diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/video | |
download | lwn-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.gz lwn-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.zip |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/video')
252 files changed, 223058 insertions, 0 deletions
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c new file mode 100644 index 000000000000..6a3cfbdc6dc9 --- /dev/null +++ b/drivers/video/68328fb.c @@ -0,0 +1,506 @@ +/* + * linux/drivers/video/68328fb.c -- Low level implementation of the + * mc68x328 LCD frame buffer device + * + * Copyright (C) 2003 Georges Menie + * + * This driver assumes an already configured controller (e.g. from config.c) + * Keep the code clean of board specific initialization. + * + * This code has not been tested with colors, colormap management functions + * are minimal (no colormap data written to the 68328 registers...) + * + * initial version of this driver: + * Copyright (C) 1998,1999 Kenneth Albanowski <kjahds@kjahds.com>, + * The Silver Hammer Group, Ltd. + * + * this version is based on : + * + * linux/drivers/video/vfb.c -- Virtual frame buffer device + * + * Copyright (C) 2002 James Simmons + * + * Copyright (C) 1997 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. + */ + +#include <linux/module.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <asm/uaccess.h> +#include <linux/fb.h> +#include <linux/init.h> + +#if defined(CONFIG_M68VZ328) +#include <asm/MC68VZ328.h> +#elif defined(CONFIG_M68EZ328) +#include <asm/MC68EZ328.h> +#elif defined(CONFIG_M68328) +#include <asm/MC68328.h> +#else +#error wrong architecture for the MC68x328 frame buffer device +#endif + +#if defined(CONFIG_FB_68328_INVERT) +#define MC68X328FB_MONO_VISUAL FB_VISUAL_MONO01 +#else +#define MC68X328FB_MONO_VISUAL FB_VISUAL_MONO10 +#endif + +static u_long videomemory; +static u_long videomemorysize; + +static struct fb_info fb_info; +static u32 mc68x328fb_pseudo_palette[17]; + +static struct fb_var_screeninfo mc68x328fb_default __initdata = { + .red = { 0, 8, 0 }, + .green = { 0, 8, 0 }, + .blue = { 0, 8, 0 }, + .activate = FB_ACTIVATE_TEST, + .height = -1, + .width = -1, + .pixclock = 20000, + .left_margin = 64, + .right_margin = 64, + .upper_margin = 32, + .lower_margin = 32, + .hsync_len = 64, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo mc68x328fb_fix __initdata = { + .id = "68328fb", + .type = FB_TYPE_PACKED_PIXELS, + .xpanstep = 1, + .ypanstep = 1, + .ywrapstep = 1, + .accel = FB_ACCEL_NONE, +}; + + /* + * Interface used by the world + */ +int mc68x328fb_init(void); +int mc68x328fb_setup(char *); + +static int mc68x328fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int mc68x328fb_set_par(struct fb_info *info); +static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int mc68x328fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +static int mc68x328fb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma); + +static struct fb_ops mc68x328fb_ops = { + .fb_check_var = mc68x328fb_check_var, + .fb_set_par = mc68x328fb_set_par, + .fb_setcolreg = mc68x328fb_setcolreg, + .fb_pan_display = mc68x328fb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + .fb_mmap = mc68x328fb_mmap, +}; + + /* + * Internal routines + */ + +static u_long get_line_length(int xres_virtual, int bpp) +{ + u_long length; + + length = xres_virtual * bpp; + length = (length + 31) & ~31; + length >>= 3; + return (length); +} + + /* + * Setting the video mode has been split into two parts. + * First part, xxxfb_check_var, must not write anything + * to hardware, it should only verify and adjust var. + * This means it doesn't alter par but it does use hardware + * data from it to check this var. + */ + +static int mc68x328fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + u_long line_length; + + /* + * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! + * as FB_VMODE_SMOOTH_XPAN is only used internally + */ + + if (var->vmode & FB_VMODE_CONUPDATE) { + var->vmode |= FB_VMODE_YWRAP; + var->xoffset = info->var.xoffset; + var->yoffset = info->var.yoffset; + } + + /* + * Some very basic checks + */ + if (!var->xres) + var->xres = 1; + if (!var->yres) + var->yres = 1; + if (var->xres > var->xres_virtual) + var->xres_virtual = var->xres; + if (var->yres > var->yres_virtual) + var->yres_virtual = var->yres; + if (var->bits_per_pixel <= 1) + var->bits_per_pixel = 1; + else if (var->bits_per_pixel <= 8) + var->bits_per_pixel = 8; + else if (var->bits_per_pixel <= 16) + var->bits_per_pixel = 16; + else if (var->bits_per_pixel <= 24) + var->bits_per_pixel = 24; + else if (var->bits_per_pixel <= 32) + var->bits_per_pixel = 32; + else + return -EINVAL; + + if (var->xres_virtual < var->xoffset + var->xres) + var->xres_virtual = var->xoffset + var->xres; + if (var->yres_virtual < var->yoffset + var->yres) + var->yres_virtual = var->yoffset + var->yres; + + /* + * Memory limit + */ + line_length = + get_line_length(var->xres_virtual, var->bits_per_pixel); + if (line_length * var->yres_virtual > videomemorysize) + return -ENOMEM; + + /* + * Now that we checked it we alter var. The reason being is that the video + * mode passed in might not work but slight changes to it might make it + * work. This way we let the user know what is acceptable. + */ + switch (var->bits_per_pixel) { + case 1: + var->red.offset = 0; + var->red.length = 1; + var->green.offset = 0; + var->green.length = 1; + var->blue.offset = 0; + var->blue.length = 1; + var->transp.offset = 0; + var->transp.length = 0; + break; + 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: /* RGBA 5551 */ + if (var->transp.length) { + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 10; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + } else { /* RGB 565 */ + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 11; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } + break; + case 24: /* RGB 888 */ + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 32: /* RGBA 8888 */ + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + 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; + + return 0; +} + +/* This routine actually sets the video mode. It's in here where we + * the hardware state info->par and fix which can be affected by the + * change in par. For this driver it doesn't do much. + */ +static int mc68x328fb_set_par(struct fb_info *info) +{ + info->fix.line_length = get_line_length(info->var.xres_virtual, + info->var.bits_per_pixel); + return 0; +} + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + if (regno >= 256) /* no. of hw registers */ + return 1; + /* + * Program hardware... do anything you want with transp + */ + + /* grayscale works only partially under directcolor */ + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = + (red * 77 + green * 151 + blue * 28) >> 8; + } + + /* Directcolor: + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * {hardwarespecific} contains width of RAMDAC + * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) + * RAMDAC[X] is programmed to (red, green, blue) + * + * Pseudocolor: + * uses offset = 0 && length = RAMDAC register width. + * var->{color}.offset is 0 + * var->{color}.length contains widht of DAC + * cmap is not used + * RAMDAC[X] is programmed to (red, green, blue) + * Truecolor: + * does not use DAC. Usually 3 are present. + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * cmap is programmed to (red << red.offset) | (green << green.offset) | + * (blue << blue.offset) | (transp << transp.offset) + * RAMDAC does not exist + */ +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + case FB_VISUAL_PSEUDOCOLOR: + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + break; + case FB_VISUAL_DIRECTCOLOR: + red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */ + green = CNVT_TOHW(green, 8); + blue = CNVT_TOHW(blue, 8); + /* hey, there is bug in transp handling... */ + transp = CNVT_TOHW(transp, 8); + break; + } +#undef CNVT_TOHW + /* Truecolor has hardware independent palette */ + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v; + + if (regno >= 16) + return 1; + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + switch (info->var.bits_per_pixel) { + case 8: + break; + case 16: + ((u32 *) (info->pseudo_palette))[regno] = v; + break; + case 24: + case 32: + ((u32 *) (info->pseudo_palette))[regno] = v; + break; + } + return 0; + } + return 0; +} + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int mc68x328fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset < 0 + || var->yoffset >= info->var.yres_virtual + || var->xoffset) + return -EINVAL; + } else { + if (var->xoffset + var->xres > info->var.xres_virtual || + var->yoffset + var->yres > info->var.yres_virtual) + return -EINVAL; + } + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; +} + + /* + * Most drivers don't need their own mmap function + */ + +static int mc68x328fb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ +#ifndef MMU + /* this is uClinux (no MMU) specific code */ + + vma->vm_flags |= VM_RESERVED; + vma->vm_start = videomemory; + + return 0; +#else + return -EINVAL; +#endif +} + +int __init mc68x328fb_setup(char *options) +{ +#if 0 + char *this_opt; +#endif + + if (!options || !*options) + return 1; +#if 0 + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + if (!strncmp(this_opt, "disable", 7)) + mc68x328fb_enable = 0; + } +#endif + return 1; +} + + /* + * Initialisation + */ + +int __init mc68x328fb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("68328fb", &option)) + return -ENODEV; + mc68x328fb_setup(option); +#endif + /* + * initialize the default mode from the LCD controller registers + */ + mc68x328fb_default.xres = LXMAX; + mc68x328fb_default.yres = LYMAX+1; + mc68x328fb_default.xres_virtual = mc68x328fb_default.xres; + mc68x328fb_default.yres_virtual = mc68x328fb_default.yres; + mc68x328fb_default.bits_per_pixel = 1 + (LPICF & 0x01); + videomemory = LSSA; + videomemorysize = (mc68x328fb_default.xres_virtual+7) / 8 * + mc68x328fb_default.yres_virtual * mc68x328fb_default.bits_per_pixel; + + fb_info.screen_base = (void *)videomemory; + fb_info.fbops = &mc68x328fb_ops; + fb_info.var = mc68x328fb_default; + fb_info.fix = mc68x328fb_fix; + fb_info.fix.smem_start = videomemory; + fb_info.fix.smem_len = videomemorysize; + fb_info.fix.line_length = + get_line_length(mc68x328fb_default.xres_virtual, mc68x328fb_default.bits_per_pixel); + fb_info.fix.visual = (mc68x328fb_default.bits_per_pixel) == 1 ? + MC68X328FB_MONO_VISUAL : FB_VISUAL_PSEUDOCOLOR; + if (fb_info.var.bits_per_pixel == 1) { + fb_info.var.red.length = fb_info.var.green.length = fb_info.var.blue.length = 1; + fb_info.var.red.offset = fb_info.var.green.offset = fb_info.var.blue.offset = 0; + } + fb_info.pseudo_palette = &mc68x328fb_pseudo_palette; + fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + + fb_alloc_cmap(&fb_info.cmap, 256, 0); + + if (register_framebuffer(&fb_info) < 0) { + return -EINVAL; + } + + printk(KERN_INFO + "fb%d: %s frame buffer device\n", fb_info.node, fb_info.fix.id); + printk(KERN_INFO + "fb%d: %dx%dx%d at 0x%08lx\n", fb_info.node, + mc68x328fb_default.xres_virtual, mc68x328fb_default.yres_virtual, + 1 << mc68x328fb_default.bits_per_pixel, videomemory); + + return 0; +} + +module_init(mc68x328fb_init); + +#ifdef MODULE + +static void __exit mc68x328fb_cleanup(void) +{ + unregister_framebuffer(&fb_info); +} + +module_exit(mc68x328fb_cleanup); + +MODULE_LICENSE("GPL"); +#endif /* MODULE */ diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig new file mode 100644 index 000000000000..2a1c5965de22 --- /dev/null +++ b/drivers/video/Kconfig @@ -0,0 +1,1497 @@ +# +# Video configuration +# + +menu "Graphics support" + +config FB + tristate "Support for frame buffer devices" + ---help--- + The frame buffer device provides an abstraction for the graphics + hardware. It represents the frame buffer of some video hardware and + allows application software to access the graphics hardware through + a well-defined interface, so the software doesn't need to know + anything about the low-level (hardware register) stuff. + + Frame buffer devices work identically across the different + architectures supported by Linux and make the implementation of + application programs easier and more portable; at this point, an X + server exists which uses the frame buffer device exclusively. + On several non-X86 architectures, the frame buffer device is the + only way to use the graphics hardware. + + The device is accessed through special device nodes, usually located + in the /dev directory, i.e. /dev/fb*. + + You need an utility program called fbset to make full use of frame + buffer devices. Please read <file:Documentation/fb/framebuffer.txt> + and the Framebuffer-HOWTO at + <http://www.tahallah.demon.co.uk/programming/prog.html> for more + information. + + Say Y here and to the driver for your graphics board below if you + are compiling a kernel for a non-x86 architecture. + + If you are compiling for the x86 architecture, you can say Y if you + want to play with it, but it is not essential. Please note that + running graphical applications that directly touch the hardware + (e.g. an accelerated X server) and that are not frame buffer + device-aware may cause unexpected results. If unsure, say N. + +config FB_CFB_FILLRECT + tristate + depends on FB + default n + ---help--- + Include the cfb_fillrect function for generic software rectangle + filling. This is used by drivers that don't provide their own + (accelerated) version. + +config FB_CFB_COPYAREA + tristate + depends on FB + default n + ---help--- + Include the cfb_copyarea function for generic software area copying. + This is used by drivers that don't provide their own (accelerated) + version. + +config FB_CFB_IMAGEBLIT + tristate + depends on FB + default n + ---help--- + Include the cfb_imageblit function for generic software image + blitting. This is used by drivers that don't provide their own + (accelerated) version. + +config FB_SOFT_CURSOR + tristate + depends on FB + default n + ---help--- + Include the soft_cursor function for generic software cursor support. + This is used by drivers that don't provide their own (accelerated) + version. + +config FB_MACMODES + tristate + depends on FB + default n + +config FB_MODE_HELPERS + bool "Enable Video Mode Handling Helpers" + depends on FB + default n + ---help--- + This enables functions for handling video modes using the + Generalized Timing Formula and the EDID parser. A few drivers rely + on this feature such as the radeonfb, rivafb, and the i810fb. If + your driver does not take advantage of this feature, choosing Y will + just increase the kernel size by about 5K. + +config FB_TILEBLITTING + bool "Enable Tile Blitting Support" + depends on FB + default n + ---help--- + This enables tile blitting. Tile blitting is a drawing technique + where the screen is divided into rectangular sections (tiles), whereas + the standard blitting divides the screen into pixels. Because the + default drawing element is a tile, drawing functions will be passed + parameters in terms of number of tiles instead of number of pixels. + For example, to draw a single character, instead of using bitmaps, + an index to an array of bitmaps will be used. To clear or move a + rectangular section of a screen, the rectangle will be described in + terms of number of tiles in the x- and y-axis. + + This is particularly important to one driver, matroxfb. If + unsure, say N. + +config FB_CIRRUS + tristate "Cirrus Logic support" + depends on FB && (ZORRO || PCI) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + ---help--- + This enables support for Cirrus Logic GD542x/543x based boards on + Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. + + If you have a PCI-based system, this enables support for these + chips: GD-543x, GD-544x, GD-5480. + + Please read the file <file:Documentation/fb/cirrusfb.txt>. + + Say N unless you have such a graphics board or plan to get one + before you next recompile the kernel. + +config FB_PM2 + tristate "Permedia2 support" + depends on FB && ((AMIGA && BROKEN) || PCI) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the Permedia2 AGP frame + buffer card from ASK, aka `Graphic Blaster Exxtreme'. There is a + product page at + <http://www.ask.com.hk/product/Permedia%202/permedia2.htm>. + +config FB_PM2_FIFO_DISCONNECT + bool "enable FIFO disconnect feature" + depends on FB_PM2 && PCI + help + Support the Permedia2 FIFO disconnect feature (see CONFIG_FB_PM2). + +config FB_ARMCLCD + tristate "ARM PrimeCell PL110 support" + depends on FB && ARM && ARM_AMBA + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This framebuffer device driver is for the ARM PrimeCell PL110 + Colour LCD controller. ARM PrimeCells provide the building + blocks for System on a Chip devices. + + If you want to compile this as a module (=code which can be + inserted into and removed from the running kernel), say M + here and read <file:Documentation/modules.txt>. The module + will be called amba-clcd. + +config FB_ACORN + bool "Acorn VIDC support" + depends on (FB = y) && ARM && (ARCH_ACORN || ARCH_CLPS7500) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the Acorn VIDC graphics + hardware found in Acorn RISC PCs and other ARM-based machines. If + unsure, say N. + +config FB_CLPS711X + bool "CLPS711X LCD support" + depends on (FB = y) && ARM && ARCH_CLPS711X + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + +config FB_SA1100 + bool "SA-1100 LCD support" + depends on (FB = y) && ARM && ARCH_SA1100 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is a framebuffer device for the SA-1100 LCD Controller. + See <http://www.linux-fbdev.org/> for information on framebuffer + devices. + + If you plan to use the LCD display with your SA-1100 system, say + Y here. + +config FB_CYBER2000 + tristate "CyberPro 2000/2010/5000 support" + depends on FB && PCI && (BROKEN || !SPARC64) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This enables support for the Integraphics CyberPro 20x0 and 5000 + VGA chips used in the Rebel.com Netwinder and other machines. + Say Y if you have a NetWinder or a graphics card containing this + device, otherwise say N. + +config FB_APOLLO + bool + depends on (FB = y) && APOLLO + default y + select FB_CFB_FILLRECT + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + +config FB_Q40 + bool + depends on (FB = y) && Q40 + default y + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + +config FB_AMIGA + tristate "Amiga native chipset support" + depends on FB && AMIGA + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the builtin graphics + chipset found in Amigas. + + To compile this driver as a module, choose M here: the + module will be called amifb. + +config FB_AMIGA_OCS + bool "Amiga OCS chipset support" + depends on FB_AMIGA + help + This enables support for the original Agnus and Denise video chips, + found in the Amiga 1000 and most A500's and A2000's. If you intend + to run Linux on any of these systems, say Y; otherwise say N. + +config FB_AMIGA_ECS + bool "Amiga ECS chipset support" + depends on FB_AMIGA + help + This enables support for the Enhanced Chip Set, found in later + A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If + you intend to run Linux on any of these systems, say Y; otherwise + say N. + +config FB_AMIGA_AGA + bool "Amiga AGA chipset support" + depends on FB_AMIGA + help + This enables support for the Advanced Graphics Architecture (also + known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T + and CD32. If you intend to run Linux on any of these systems, say Y; + otherwise say N. + +config FB_CYBER + tristate "Amiga CyberVision 64 support" + depends on FB && ZORRO && BROKEN + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This enables support for the Cybervision 64 graphics card from + Phase5. Please note that its use is not all that intuitive (i.e. if + you have any questions, be sure to ask!). Say N unless you have a + Cybervision 64 or plan to get one before you next recompile the + kernel. Please note that this driver DOES NOT support the + Cybervision 64/3D card, as they use incompatible video chips. + +config FB_VIRGE + bool "Amiga CyberVision 64/3D support " + depends on (FB = y) && ZORRO && BROKEN + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This enables support for the Cybervision 64/3D graphics card from + Phase5. Please note that its use is not all that intuitive (i.e. if + you have any questions, be sure to ask!). Say N unless you have a + Cybervision 64/3D or plan to get one before you next recompile the + kernel. Please note that this driver DOES NOT support the older + Cybervision 64 card, as they use incompatible video chips. + +config FB_RETINAZ3 + tristate "Amiga Retina Z3 support" + depends on (FB = y) && ZORRO && BROKEN + help + This enables support for the Retina Z3 graphics card. Say N unless + you have a Retina Z3 or plan to get one before you next recompile + the kernel. + +config FB_FM2 + bool "Amiga FrameMaster II/Rainbow II support" + depends on (FB = y) && ZORRO + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the Amiga FrameMaster + card from BSC (exhibited 1992 but not shipped as a CBM product). + +config FB_ATARI + bool "Atari native chipset support" + depends on (FB = y) && ATARI && BROKEN + help + This is the frame buffer device driver for the builtin graphics + chipset found in Ataris. + +config FB_OF + bool "Open Firmware frame buffer device support" + depends on (FB = y) && (PPC64 || PPC_OF) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select FB_MACMODES + help + Say Y if you want support with Open Firmware for your graphics + board. + +config FB_CONTROL + bool "Apple \"control\" display support" + depends on (FB = y) && PPC_PMAC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select FB_MACMODES + help + This driver supports a frame buffer for the graphics adapter in the + Power Macintosh 7300 and others. + +config FB_PLATINUM + bool "Apple \"platinum\" display support" + depends on (FB = y) && PPC_PMAC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select FB_MACMODES + help + This driver supports a frame buffer for the "platinum" graphics + adapter in some Power Macintoshes. + +config FB_VALKYRIE + bool "Apple \"valkyrie\" display support" + depends on (FB = y) && (MAC || PPC_PMAC) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select FB_MACMODES + help + This driver supports a frame buffer for the "valkyrie" graphics + adapter in some Power Macintoshes. + +config FB_CT65550 + bool "Chips 65550 display support" + depends on (FB = y) && PPC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the Chips & Technologies + 65550 graphics chip in PowerBooks. + +config FB_ASILIANT + bool "Chips 69000 display support" + depends on (FB = y) && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + +config FB_IMSTT + bool "IMS Twin Turbo display support" + depends on (FB = y) && PCI + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select FB_MACMODES if PPC + help + The IMS Twin Turbo is a PCI-based frame buffer card bundled with + many Macintosh and compatible computers. + +config FB_S3TRIO + bool "S3 Trio display support" + depends on (FB = y) && PPC && BROKEN + help + If you have a S3 Trio say Y. Say N for S3 Virge. + +config FB_VGA16 + tristate "VGA 16-color graphics support" + depends on FB && (X86 || PPC) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for VGA 16 color graphic + cards. Say Y if you have such a card. + + To compile this driver as a module, choose M here: the + module will be called vga16fb. + +config FB_STI + tristate "HP STI frame buffer device support" + depends on FB && PARISC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + 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 + 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" + depends on (FB = y) && MAC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select FB_MACMODES + +# bool ' Apple DAFB display support' CONFIG_FB_DAFB +config FB_HP300 + bool + depends on (FB = y) && HP300 + select FB_CFB_FILLRECT + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + default y + +config FB_TGA + tristate "TGA framebuffer support" + depends on FB && ALPHA + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for generic TGA graphic + cards. Say Y if you have one of those. + +config FB_VESA + bool "VESA VGA graphics support" + depends on (FB = y) && (X86 || X86_64) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for generic VESA 2.0 + compliant graphic cards. The older VESA 1.2 cards are not supported. + You will get a boot time penguin logo at no additional cost. Please + read <file:Documentation/fb/vesafb.txt>. If unsure, say Y. + +config VIDEO_SELECT + bool + depends on FB_VESA + default y + +config FB_HGA + tristate "Hercules mono graphics support" + depends on FB && X86 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + Say Y here if you have a Hercules mono graphics card. + + To compile this driver as a module, choose M here: the + module will be called hgafb. + + As this card technology is 15 years old, most people will answer N + here. + +config FB_HGA_ACCEL + bool "Hercules mono Acceleration functions (EXPERIMENTAL)" + depends on FB_HGA && EXPERIMENTAL + ---help--- + This will compile the Hercules mono graphics with + acceleration functions. + + +config VIDEO_SELECT + bool + depends on (FB = y) && X86 + default y + +config FB_SGIVW + tristate "SGI Visual Workstation framebuffer support" + depends on FB && X86_VISWS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + SGI Visual Workstation support for framebuffer graphics. + +config FB_GBE + bool "SGI Graphics Backend frame buffer support" + depends on (FB = y) && (SGI_IP32 || X86_VISWS) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for SGI Graphics Backend. + This chip is used in SGI O2 and Visual Workstation 320/540. + +config FB_GBE_MEM + int "Video memory size in MB" + depends on FB_GBE + default 8 + help + This is the amount of memory reserved for the framebuffer, + which can be any value between 1MB and 8MB. + +config BUS_I2C + bool + depends on (FB = y) && VISWS + default y + +config FB_SUN3 + bool "Sun3 framebuffer support" + depends on (FB = y) && (SUN3 || SUN3X) && BROKEN + +config FB_BW2 + bool "BWtwo support" + depends on (FB = y) && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the BWtwo frame buffer. + +config FB_CG3 + bool "CGthree support" + depends on (FB = y) && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3) + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the CGthree frame buffer. + +config FB_CG6 + bool "CGsix (GX,TurboGX) support" + depends on (FB = y) && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3) + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the CGsix (GX, TurboGX) + frame buffer. + +config FB_PVR2 + tristate "NEC PowerVR 2 display support" + depends on FB && SH_DREAMCAST + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + ---help--- + Say Y here if you have a PowerVR 2 card in your box. If you plan to + run linux on your Dreamcast, you will have to say Y here. + This driver may or may not work on other PowerVR 2 cards, but is + totally untested. Use at your own risk. If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called pvr2fb. + + You can pass several parameters to the driver at boot time or at + module load time. The parameters look like "video=pvr2:XXX", where + the meaning of XXX can be found at the end of the main source file + (<file:drivers/video/pvr2fb.c>). Please see the file + <file:Documentation/fb/pvr2fb.txt>. + +config FB_EPSON1355 + bool "Epson 1355 framebuffer support" + depends on (FB = y) && (SUPERH || ARCH_CEIVA) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + Build in support for the SED1355 Epson Research Embedded RAMDAC + LCD/CRT Controller (since redesignated as the S1D13505) as a + framebuffer. Product specs at + <http://www.erd.epson.com/vdc/html/products.htm>. + +config FB_NVIDIA + tristate "nVidia Framebuffer Support" + depends on FB && PCI + select I2C_ALGOBIT if FB_NVIDIA_I2C + select I2C if FB_NVIDIA_I2C + select FB_MODE_HELPERS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This driver supports graphics boards with the nVidia chips, TNT + and newer. For very old chipsets, such as the RIVA128, then use + the rivafb. + Say Y if you have such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called nvidiafb. + +config FB_NVIDIA_I2C + bool "Enable DDC Support" + depends on FB_NVIDIA && !PPC_OF + help + This enables I2C support for nVidia Chipsets. This is used + only for getting EDID information from the attached display + allowing for robust video mode handling and switching. + + Because fbdev-2.6 requires that drivers must be able to + independently validate video mode parameters, you should say Y + here. + +config FB_RIVA + tristate "nVidia Riva support" + depends on FB && PCI + select I2C_ALGOBIT if FB_RIVA_I2C + select I2C if FB_RIVA_I2C + select FB_MODE_HELPERS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This driver supports graphics boards with the nVidia Riva/Geforce + chips. + Say Y if you have such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called rivafb. + +config FB_RIVA_I2C + bool "Enable DDC Support" + depends on FB_RIVA + help + This enables I2C support for nVidia Chipsets. This is used + only for getting EDID information from the attached display + allowing for robust video mode handling and switching. + + Because fbdev-2.6 requires that drivers must be able to + independently validate video mode parameters, you should say Y + here. + +config FB_RIVA_DEBUG + bool "Lots of debug output from Riva(nVidia) driver" + depends on FB_RIVA + default n + help + Say Y here if you want the Riva driver to output all sorts + of debugging informations to provide to the maintainer when + something goes wrong. + +config FB_I810 + tristate "Intel 810/815 support (EXPERIMENTAL)" + depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64 + select AGP + select AGP_INTEL + select FB_MODE_HELPERS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + 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. + + To compile this driver as a module, choose M here: the + module will be called i810fb. + + 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_INTEL + tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)" + depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64 + select AGP + select AGP_INTEL + select FB_MODE_HELPERS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This driver supports the on-board graphics built in to the Intel + 830M/845G/852GM/855GM/865G chipsets. + Say Y if you have and plan to use such a board. + + To compile this driver as a module, choose M here: the + module will be called intelfb. + +config FB_INTEL_DEBUG + bool "Intel driver Debug Messages" + depends on FB_INTEL + ---help--- + Say Y here if you want the Intel driver to output all sorts + of debugging informations to provide to the maintainer when + something goes wrong. + +config FB_MATROX + tristate "Matrox acceleration" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select FB_TILEBLITTING + select FB_MACMODES if PPC_PMAC + ---help--- + Say Y here if you have a Matrox Millennium, Matrox Millennium II, + Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox + Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video, + Matrox G400, G450 or G550 card in your box. + + To compile this driver as a module, choose M here: the + module will be called matroxfb. + + You can pass several parameters to the driver at boot time or at + module load time. The parameters look like "video=matrox:XXX", and + are described in <file:Documentation/fb/matroxfb.txt>. + +config FB_MATROX_MILLENIUM + bool "Millennium I/II support" + depends on FB_MATROX + help + Say Y here if you have a Matrox Millennium or Matrox Millennium II + video card. If you select "Advanced lowlevel driver options" below, + you should check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp + packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can + also use font widths different from 8. + +config FB_MATROX_MYSTIQUE + bool "Mystique support" + depends on FB_MATROX + help + Say Y here if you have a Matrox Mystique or Matrox Mystique 220 + video card. If you select "Advanced lowlevel driver options" below, + you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp + packed pixel and 32 bpp packed pixel. You can also use font widths + different from 8. + +config FB_MATROX_G + bool "G100/G200/G400/G450/G550 support" + depends on FB_MATROX + ---help--- + Say Y here if you have a Matrox G100, G200, G400, G450 or G550 based + video card. If you select "Advanced lowlevel driver options", you + should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed + pixel and 32 bpp packed pixel. You can also use font widths + different from 8. + + If you need support for G400 secondary head, you must first say Y to + "I2C support" in the character devices section, and then to + "Matrox I2C support" and "G400 second head support" here in the + framebuffer section. G450/G550 secondary head and digital output + are supported without additional modules. + + The driver starts in monitor mode. You must use the matroxset tool + (available at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to + swap primary and secondary head outputs, or to change output mode. + Secondary head driver always start in 640x480 resolution and you + must use fbset to change it. + + Do not forget that second head supports only 16 and 32 bpp + packed pixels, so it is a good idea to compile them into the kernel + too. You can use only some font widths, as the driver uses generic + painting procedures (the secondary head does not use acceleration + engine). + + G450/G550 hardware can display TV picture only from secondary CRTC, + and it performs no scaling, so picture must have 525 or 625 lines. + +config FB_MATROX_I2C + tristate "Matrox I2C support" + depends on FB_MATROX && I2C + select I2C_ALGOBIT + ---help--- + This drivers creates I2C buses which are needed for accessing the + DDC (I2C) bus present on all Matroxes, an I2C bus which + interconnects Matrox optional devices, like MGA-TVO on G200 and + G400, and the secondary head DDC bus, present on G400 only. + + You can say Y or M here if you want to experiment with monitor + detection code. You must say Y or M here if you want to use either + second head of G400 or MGA-TVO on G200 or G400. + + If you compile it as module, it will create a module named + i2c-matroxfb. + +config FB_MATROX_MAVEN + tristate "G400 second head support" + depends on FB_MATROX_G && FB_MATROX_I2C + ---help--- + WARNING !!! This support does not work with G450 !!! + + Say Y or M here if you want to use a secondary head (meaning two + monitors in parallel) on G400 or MGA-TVO add-on on G200. Secondary + head is not compatible with accelerated XFree 3.3.x SVGA servers - + secondary head output is blanked while you are in X. With XFree + 3.9.17 preview you can use both heads if you use SVGA over fbdev or + the fbdev driver on first head and the fbdev driver on second head. + + If you compile it as module, two modules are created, + matroxfb_crtc2 and matroxfb_maven. Matroxfb_maven is needed for + both G200 and G400, matroxfb_crtc2 is needed only by G400. You must + also load i2c-matroxfb to get it to run. + + The driver starts in monitor mode and you must use the matroxset + tool (available at + <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to switch it to + PAL or NTSC or to swap primary and secondary head outputs. + Secondary head driver also always start in 640x480 resolution, you + must use fbset to change it. + + Also do not forget that second head supports only 16 and 32 bpp + packed pixels, so it is a good idea to compile them into the kernel + too. You can use only some font widths, as the driver uses generic + painting procedures (the secondary head does not use acceleration + engine). + +config FB_MATROX_MULTIHEAD + bool "Multihead support" + depends on FB_MATROX + ---help--- + Say Y here if you have more than one (supported) Matrox device in + your computer and you want to use all of them for different monitors + ("multihead"). If you have only one device, you should say N because + the driver compiled with Y is larger and a bit slower, especially on + ia32 (ix86). + + If you said M to "Matrox unified accelerated driver" and N here, you + will still be able to use several Matrox devices simultaneously: + insert several instances of the module matroxfb into the kernel + with insmod, supplying the parameter "dev=N" where N is 0, 1, etc. + for the different Matrox devices. This method is slightly faster but + uses 40 KB of kernel memory per Matrox card. + + There is no need for enabling 'Matrox multihead support' if you have + only one Matrox card in the box. + +config FB_RADEON_OLD + tristate "ATI Radeon display support (Old driver)" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select FB_MACMODES if PPC + help + Choose this option if you want to use an ATI Radeon graphics card as + a framebuffer device. There are both PCI and AGP versions. You + don't need to choose this to run the Radeon in plain VGA mode. + There is a product page at + <http://www.ati.com/na/pages/products/pc/radeon32/index.html>. + +config FB_RADEON + tristate "ATI Radeon display support" + depends on FB && PCI + select I2C_ALGOBIT if FB_RADEON_I2C + select I2C if FB_RADEON_I2C + select FB_MODE_HELPERS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select FB_MACMODES if PPC_OF + help + Choose this option if you want to use an ATI Radeon graphics card as + a framebuffer device. There are both PCI and AGP versions. You + don't need to choose this to run the Radeon in plain VGA mode. + + If you say Y here and want DDC/I2C support you must first say Y to + "I2C support" and "I2C bit-banging support" in the character devices + section. + + If you say M here then "I2C support" and "I2C bit-banging support" + can be build either as modules or built-in. + + There is a product page at + <http://www.ati.com/na/pages/products/pc/radeon32/index.html>. + +config FB_RADEON_I2C + bool "DDC/I2C for ATI Radeon support" + depends on FB_RADEON + default y + help + Say Y here if you want DDC/I2C support for your Radeon board. + +config FB_RADEON_DEBUG + bool "Lots of debug output from Radeon driver" + depends on FB_RADEON + default n + help + Say Y here if you want the Radeon driver to output all sorts + of debugging informations to provide to the maintainer when + something goes wrong. + +config FB_ATY128 + tristate "ATI Rage128 display support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select FB_MACMODES if PPC_PMAC + help + This driver supports graphics boards with the ATI Rage128 chips. + Say Y if you have such a graphics board and read + <file:Documentation/fb/aty128fb.txt>. + + To compile this driver as a module, choose M here: the + module will be called aty128fb. + +config FB_ATY + tristate "ATI Mach64 display support" if PCI || ATARI + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select FB_MACMODES if PPC + help + This driver supports graphics boards with the ATI Mach64 chips. + Say Y if you have such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called atyfb. + +config FB_ATY_CT + bool "Mach64 CT/VT/GT/LT (incl. 3D RAGE) support" + depends on PCI && FB_ATY + default y if SPARC64 && FB_PCI + help + Say Y here to support use of ATI's 64-bit Rage boards (or other + boards based on the Mach64 CT, VT, GT, and LT chipsets) as a + framebuffer device. The ATI product support page for these boards + is at <http://support.ati.com/products/pc/mach64/>. + +config FB_ATY_GENERIC_LCD + bool "Mach64 generic LCD support (EXPERIMENTAL)" + depends on FB_ATY_CT + help + Say Y if you have a laptop with an ATI Rage LT PRO, Rage Mobility, + Rage XC, or Rage XL chipset. + +config FB_ATY_XL_INIT + bool "Rage XL No-BIOS Init support" + depends on FB_ATY_CT + help + Say Y here to support booting a Rage XL without BIOS support. + +config FB_ATY_GX + bool "Mach64 GX support" if PCI + depends on FB_ATY + default y if ATARI + help + Say Y here to support use of the ATI Mach64 Graphics Expression + board (or other boards based on the Mach64 GX chipset) as a + framebuffer device. The ATI product support page for these boards + is at + <http://support.ati.com/products/pc/mach64/graphics_xpression.html>. + +config FB_SAVAGE + tristate "S3 Savage support" + depends on FB && PCI && EXPERIMENTAL + select I2C_ALGOBIT if FB_SAVAGE_I2C + select I2C if FB_SAVAGE_I2C + select FB_MODE_HELPERS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This driver supports notebooks and computers with S3 Savage PCI/AGP + chips. + + Say Y if you have such a graphics card. + + To compile this driver as a module, choose M here; the module + will be called savagefb. + +config FB_SAVAGE_I2C + bool "Enable DDC2 Support" + depends on FB_SAVAGE + help + This enables I2C support for S3 Savage Chipsets. This is used + only for getting EDID information from the attached display + allowing for robust video mode handling and switching. + + Because fbdev-2.6 requires that drivers must be able to + independently validate video mode parameters, you should say Y + here. + +config FB_SAVAGE_ACCEL + bool "Enable Console Acceleration" + depends on FB_SAVAGE + default n + help + This option will compile in console acceleration support. If + the resulting framebuffer console has bothersome glitches, then + choose N here. + +config FB_SIS + tristate "SiS acceleration" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the SiS 300, 315 and + 330 series VGA chipsets. Specs available at <http://www.sis.com> + + To compile this driver as a module, choose M here; the module + will be called sisfb. + +config FB_SIS_300 + bool "SiS 300 series support" + depends on FB_SIS + help + Say Y here to support use of the SiS 300/305, 540, 630 and 730. + +config FB_SIS_315 + bool "SiS 315/330 series support" + depends on FB_SIS + help + Say Y here to support use of the SiS 315 and 330 series + (315/H/PRO, 55x, 650, 651, 740, 330, 661, 741, 760). + +config FB_NEOMAGIC + tristate "NeoMagic display support" + depends on FB && PCI + select FB_MODE_HELPERS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This driver supports notebooks with NeoMagic PCI chips. + Say Y if you have such a graphics card. + + To compile this driver as a module, choose M here: the + module will be called neofb. + +config FB_KYRO + tristate "IMG Kyro support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + Say Y here if you have a STG4000 / Kyro / PowerVR 3 based + graphics board. + + To compile this driver as a module, choose M here: the + module will be called kyrofb. + +config FB_3DFX + tristate "3Dfx Banshee/Voodoo3 display support" + depends on FB && PCI + select FB_CFB_IMAGEBLIT + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_SOFT_CURSOR + help + This driver supports graphics boards with the 3Dfx Banshee/Voodoo3 + chips. Say Y if you have such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called tdfxfb. + +config FB_3DFX_ACCEL + bool "3Dfx Banshee/Voodoo3 Acceleration functions (EXPERIMENTAL)" + depends on FB_3DFX && EXPERIMENTAL + ---help--- + This will compile the 3Dfx Banshee/Voodoo3 frame buffer device + with acceleration functions. + + +config FB_VOODOO1 + tristate "3Dfx Voodoo Graphics (sst1) support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + ---help--- + Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or + Voodoo2 (cvg) based graphics card. + + To compile this driver as a module, choose M here: the + module will be called sstfb. + + WARNING: Do not use any application that uses the 3D engine + (namely glide) while using this driver. + Please read the <file:Documentation/fb/README-sstfb.txt> for supported + options and other important info support. + +config FB_TRIDENT + tristate "Trident support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + ---help--- + This driver is supposed to support graphics boards with the + Trident CyberXXXX/Image/CyberBlade chips mostly found in laptops + but also on some motherboards. For more information, read + <file:Documentation/fb/tridentfb.txt> + + Say Y if you have such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called tridentfb. + +config FB_TRIDENT_ACCEL + bool "Trident Acceleration functions (EXPERIMENTAL)" + depends on FB_TRIDENT && EXPERIMENTAL + ---help--- + This will compile the Trident frame buffer device with + acceleration functions. + + +config FB_PM3 + tristate "Permedia3 support" + depends on FB && PCI && BROKEN + help + This is the frame buffer device driver for the 3DLabs Permedia3 + chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & + similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000 + and maybe other boards. + +config FB_E1356 + tristate "Epson SED1356 framebuffer support" + depends on FB && EXPERIMENTAL && PCI && MIPS + +config PB1000_CRT + bool "Use CRT on Pb1000 (J65)" + depends on MIPS_PB1000=y && FB_E1356 + +config PB1000_NTSC + bool "Use Compsite NTSC on Pb1000 (J63)" + depends on MIPS_PB1000=y && FB_E1356 + +config PB1000_TFT + bool "Use TFT Panel on Pb1000 (J64)" + depends on MIPS_PB1000=y && FB_E1356 + +config PB1500_CRT + bool "Use CRT on Pb1500 " if MIPS_PB1500=y + depends on FB_E1356 + +config PB1500_CRT + prompt "Use CRT on Pb1100 " + depends on FB_E1356 && MIPS_PB1100=y + +config PB1500_TFT + bool "Use TFT Panel on Pb1500 " if MIPS_PB1500=y + depends on FB_E1356 + +config PB1500_TFT + prompt "Use TFT Panel on Pb1100 " + depends on FB_E1356 && MIPS_PB1100=y + +config FB_AU1100 + bool "Au1100 LCD Driver" + depends on (FB = y) && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y + +source "drivers/video/geode/Kconfig" + +config FB_SBUS + bool "SBUS and UPA framebuffers" + depends on (FB = y) && (SPARC32 || SPARC64) + help + Say Y if you want support for SBUS or UPA based frame buffer device. + +config FB_FFB + bool "Creator/Creator3D/Elite3D support" + depends on FB_SBUS && SPARC64 + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the Creator, Creator3D, + and Elite3D graphics boards. + +config FB_TCX + bool "TCX (SS4/SS5 only) support" + depends on FB_SBUS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the TCX 24/8bit frame + buffer. + +config FB_CG14 + bool "CGfourteen (SX) support" + depends on FB_SBUS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the CGfourteen frame + buffer on Desktop SPARCsystems with the SX graphics option. + +config FB_P9100 + bool "P9100 (Sparcbook 3 only) support" + depends on FB_SBUS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the P9100 card + supported on Sparcbook 3 machines. + +config FB_LEO + bool "Leo (ZX) support" + depends on FB_SBUS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the SBUS-based Sun ZX + (leo) frame buffer cards. + +config FB_PCI + bool "PCI framebuffers" + depends on (FB = y) && PCI && (SPARC64 || SPARC32) + +config FB_IGA + bool "IGA 168x display support" + depends on SPARC32 && FB_PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the framebuffer device for the INTERGRAPHICS 1680 and + successor frame buffer cards. + +config FB_HIT + tristate "HD64461 Frame Buffer support" + depends on FB && HD64461 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This is the frame buffer device driver for the Hitachi HD64461 LCD + frame buffer card. + +config FB_PMAG_AA + bool "PMAG-AA TURBOchannel framebuffer support" + depends on (FB = y) && MACH_DECSTATION && TC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + Support for the PMAG-AA TURBOchannel framebuffer card (1280x1024x1) + used mainly in the MIPS-based DECstation series. + +config FB_PMAG_BA + bool "PMAG-BA TURBOchannel framebuffer support" + depends on (FB = y) && MACH_DECSTATION && TC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + Support for the PMAG-BA TURBOchannel framebuffer card (1024x864x8) + used mainly in the MIPS-based DECstation series. + +config FB_PMAGB_B + bool "PMAGB-B TURBOchannel framebuffer support" + depends on (FB = y) && MACH_DECSTATION && TC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + Support for the PMAGB-B TURBOchannel framebuffer card used mainly + in the MIPS-based DECstation series. The card is currently only + supported in 1280x1024x8 mode. + +config FB_MAXINE + bool "Maxine (Personal DECstation) onboard framebuffer support" + depends on (FB = y) && MACH_DECSTATION && TC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + Support for the onboard framebuffer (1024x768x8) in the Personal + DECstation series (Personal DECstation 5000/20, /25, /33, /50, + Codename "Maxine"). + +config FB_TX3912 + bool "TMPTX3912/PR31700 frame buffer support" + depends on (FB = y) && NINO + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + The TX3912 is a Toshiba RISC processor based on the MIPS 3900 core + see <http://www.toshiba.com/taec/components/Generic/risc/tx3912.htm>. + + Say Y here to enable kernel support for the on-board framebuffer. + +config FB_G364 + bool + depends on MIPS_MAGNUM_4000 || OLIVETTI_M700 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + The G364 driver is the framebuffer used in MIPS Magnum 4000 and + Olivetti M700-10 systems. + +config FB_68328 + bool "Motorola 68328 native frame buffer support" + depends on FB && (M68328 || M68EZ328 || M68VZ328) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + Say Y here if you want to support the built-in frame buffer of + the Motorola 68328 CPU family. + +config FB_PXA + tristate "PXA LCD framebuffer support" + depends on FB && ARCH_PXA + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + ---help--- + Frame buffer driver for the built-in LCD controller in the Intel + PXA2x0 processor. + + This 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 vfb. If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. + + If unsure, say N. + +config FB_W100 + tristate "W100 frame buffer support" + depends on FB && PXA_SHARPSL + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + ---help--- + Frame buffer driver for the w100 as found on the Sharp SL-Cxx series. + + This 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 vfb. If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. + + If unsure, say N. + +config FB_PXA_PARAMETERS + bool "PXA LCD command line parameters" + default n + depends on FB_PXA + ---help--- + Enable the use of kernel command line or module parameters + to configure the physical properties of the LCD panel when + using the PXA LCD driver. + + This option allows you to override the panel parameters + supplied by the platform in order to support multiple + different models of flatpanel. If you will only be using a + single model of flatpanel then you can safely leave this + option disabled. + + <file:Documentation/fb/pxafb.txt> describes the available parameters. + +config FB_S1D13XXX + tristate "Epson S1D13XXX framebuffer support" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + Support for S1D13XXX framebuffer device family (currently only + working with S1D13806). Product specs at + <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm> + +config FB_VIRTUAL + tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + ---help--- + This is a `virtual' frame buffer device. It operates on a chunk of + unswappable kernel memory instead of on the memory of a graphics + board. This means you cannot see any output sent to this frame + buffer device, while it does consume precious memory. The main use + of this frame buffer device is testing and debugging the frame + buffer subsystem. Do NOT enable it for normal systems! To protect + the innocent, it has to be enabled explicitly at boot time using the + kernel option `video=vfb:'. + + To compile this driver as a module, choose M here: the + module will be called vfb. + + If unsure, say N. +if VT + source "drivers/video/console/Kconfig" +endif + +if FB || SGI_NEWPORT_CONSOLE + source "drivers/video/logo/Kconfig" +endif + +if FB && SYSFS + source "drivers/video/backlight/Kconfig" +endif + +endmenu + diff --git a/drivers/video/Makefile b/drivers/video/Makefile new file mode 100644 index 000000000000..92265b741dc3 --- /dev/null +++ b/drivers/video/Makefile @@ -0,0 +1,100 @@ +# Makefile for the Linux video drivers. +# 5 Aug 1999, James Simmons, <mailto:jsimmons@users.sf.net> +# Rewritten to use lists instead of if-statements. + +# Each configuration option enables a list of files. + +obj-$(CONFIG_VT) += console/ +obj-$(CONFIG_LOGO) += logo/ +obj-$(CONFIG_SYSFS) += backlight/ + +obj-$(CONFIG_FB) += fb.o +fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o modedb.o +fb-objs := $(fb-y) + +obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o +obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o +obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o +obj-$(CONFIG_FB_SOFT_CURSOR) += softcursor.o +obj-$(CONFIG_FB_MACMODES) += macmodes.o + +# Hardware specific drivers go first +obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o +obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o +obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o +obj-$(CONFIG_FB_CYBER) += cyberfb.o +obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o +obj-$(CONFIG_FB_PM2) += pm2fb.o +obj-$(CONFIG_FB_PM3) += pm3fb.o + +obj-$(CONFIG_FB_MATROX) += matrox/ +obj-$(CONFIG_FB_RIVA) += riva/ vgastate.o +obj-$(CONFIG_FB_NVIDIA) += nvidia/ +obj-$(CONFIG_FB_ATY) += aty/ macmodes.o +obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o +obj-$(CONFIG_FB_RADEON) += aty/ +obj-$(CONFIG_FB_SIS) += sis/ +obj-$(CONFIG_FB_KYRO) += kyro/ +obj-$(CONFIG_FB_SAVAGE) += savage/ +obj-$(CONFIG_FB_GEODE) += geode/ +obj-$(CONFIG_FB_I810) += vgastate.o +obj-$(CONFIG_FB_RADEON_OLD) += radeonfb.o +obj-$(CONFIG_FB_NEOMAGIC) += neofb.o vgastate.o +obj-$(CONFIG_FB_VIRGE) += virgefb.o +obj-$(CONFIG_FB_3DFX) += tdfxfb.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_IMSTT) += imsttfb.o +obj-$(CONFIG_FB_S3TRIO) += S3triofb.o +obj-$(CONFIG_FB_FM2) += fm2fb.o +obj-$(CONFIG_FB_TRIDENT) += tridentfb.o +obj-$(CONFIG_FB_STI) += stifb.o +obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o +obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o +obj-$(CONFIG_FB_CG3) += cg3.o sbuslib.o +obj-$(CONFIG_FB_BW2) += bw2.o sbuslib.o +obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o +obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o +obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o +obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o +obj-$(CONFIG_FB_SGIVW) += sgivwfb.o +obj-$(CONFIG_FB_ACORN) += acornfb.o +obj-$(CONFIG_FB_ATARI) += atafb.o +obj-$(CONFIG_FB_MAC) += macfb.o +obj-$(CONFIG_FB_HGA) += hgafb.o +obj-$(CONFIG_FB_IGA) += igafb.o +obj-$(CONFIG_FB_APOLLO) += dnfb.o +obj-$(CONFIG_FB_Q40) += q40fb.o +obj-$(CONFIG_FB_TGA) += tgafb.o +obj-$(CONFIG_FB_HP300) += hpfb.o +obj-$(CONFIG_FB_G364) += g364fb.o +obj-$(CONFIG_FB_SA1100) += sa1100fb.o +obj-$(CONFIG_FB_SUN3) += sun3fb.o +obj-$(CONFIG_FB_HIT) += hitfb.o +obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o +obj-$(CONFIG_FB_PVR2) += pvr2fb.o +obj-$(CONFIG_FB_VOODOO1) += sstfb.o +obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o +obj-$(CONFIG_FB_68328) += 68328fb.o +obj-$(CONFIG_FB_GBE) += gbefb.o +obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o +obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o +obj-$(CONFIG_FB_PXA) += pxafb.o +obj-$(CONFIG_FB_W100) += w100fb.o +obj-$(CONFIG_FB_AU1100) += au1100fb.o fbgen.o +obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o +obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o +obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o +obj-$(CONFIG_FB_MAXINE) += maxinefb.o +obj-$(CONFIG_FB_TX3912) += tx3912fb.o +obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o + +# Platform or fallback drivers go here +obj-$(CONFIG_FB_VESA) += vesafb.o +obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o +obj-$(CONFIG_FB_OF) += offb.o + +# the test framebuffer is last +obj-$(CONFIG_FB_VIRTUAL) += vfb.o diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c new file mode 100644 index 000000000000..455fda990ff7 --- /dev/null +++ b/drivers/video/S3triofb.c @@ -0,0 +1,789 @@ +/* + * linux/drivers/video/S3Triofb.c -- Open Firmware based frame buffer device + * + * Copyright (C) 1997 Peter De Schrijver + * + * This driver is partly based on the PowerMac console driver: + * + * Copyright (C) 1996 Paul Mackerras + * + * and on the Open Firmware based frame buffer device: + * + * Copyright (C) 1997 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. + */ + +/* + Bugs : + OF dependencies should be removed. + + This driver should be merged with the CyberVision driver. The + CyberVision is a Zorro III implementation of the S3Trio64 chip. + +*/ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/selection.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#include <linux/pci.h> + +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/s3blit.h> + + +#define mem_in8(addr) in_8((void *)(addr)) +#define mem_in16(addr) in_le16((void *)(addr)) +#define mem_in32(addr) in_le32((void *)(addr)) + +#define mem_out8(val, addr) out_8((void *)(addr), val) +#define mem_out16(val, addr) out_le16((void *)(addr), val) +#define mem_out32(val, addr) out_le32((void *)(addr), val) + +#define IO_OUT16VAL(v, r) (((v) << 8) | (r)) + +static struct display disp; +static struct fb_info fb_info; +static struct { u_char red, green, blue, pad; } palette[256]; +static char s3trio_name[16] = "S3Trio "; +static char *s3trio_base; + +static struct fb_fix_screeninfo fb_fix; +static struct fb_var_screeninfo fb_var = { 0, }; + + + /* + * Interface used by the world + */ + +static void __init s3triofb_of_init(struct device_node *dp); +static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int s3trio_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int s3trio_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int s3trio_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static void s3triofb_blank(int blank, struct fb_info *info); + + /* + * Interface to the low level console driver + */ + +int s3triofb_init(void); +static int s3triofbcon_switch(int con, struct fb_info *info); +static int s3triofbcon_updatevar(int con, struct fb_info *info); + + /* + * Text console acceleration + */ + +#ifdef FBCON_HAS_CFB8 +static struct display_switch fbcon_trio8; +#endif + + /* + * Accelerated Functions used by the low level console driver + */ + +static void Trio_WaitQueue(u_short fifo); +static void Trio_WaitBlit(void); +static void Trio_BitBLT(u_short curx, u_short cury, u_short destx, + u_short desty, u_short width, u_short height, + u_short mode); +static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height, + u_short mode, u_short color); +static void Trio_MoveCursor(u_short x, u_short y); + + + /* + * Internal routines + */ + +static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info); + +static struct fb_ops s3trio_ops = { + .owner = THIS_MODULE, + .fb_get_fix = s3trio_get_fix, + .fb_get_var = s3trio_get_var, + .fb_set_var = s3trio_set_var, + .fb_get_cmap = s3trio_get_cmap, + .fb_set_cmap = gen_set_cmap, + .fb_setcolreg = s3trio_setcolreg, + .fb_pan_display =s3trio_pan_display, + .fb_blank = s3triofb_blank, +}; + + /* + * Get the Fixed Part of the Display + */ + +static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + memcpy(fix, &fb_fix, sizeof(fb_fix)); + return 0; +} + + + /* + * Get the User Defined Part of the Display + */ + +static int s3trio_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + memcpy(var, &fb_var, sizeof(fb_var)); + return 0; +} + + + /* + * Set the User Defined Part of the Display + */ + +static int s3trio_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + if (var->xres > fb_var.xres || var->yres > fb_var.yres || + var->bits_per_pixel > fb_var.bits_per_pixel ) + /* || var->nonstd || var->vmode != FB_VMODE_NONINTERLACED) */ + return -EINVAL; + if (var->xres_virtual > fb_var.xres_virtual) { + outw(IO_OUT16VAL((var->xres_virtual /8) & 0xff, 0x13), 0x3d4); + outw(IO_OUT16VAL(((var->xres_virtual /8 ) & 0x300) >> 3, 0x51), 0x3d4); + fb_var.xres_virtual = var->xres_virtual; + fb_fix.line_length = var->xres_virtual; + } + fb_var.yres_virtual = var->yres_virtual; + memcpy(var, &fb_var, sizeof(fb_var)); + return 0; +} + + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int s3trio_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + unsigned int base; + + if (var->xoffset > (var->xres_virtual - var->xres)) + return -EINVAL; + if (var->yoffset > (var->yres_virtual - var->yres)) + return -EINVAL; + + fb_var.xoffset = var->xoffset; + fb_var.yoffset = var->yoffset; + + base = var->yoffset * fb_fix.line_length + var->xoffset; + + outw(IO_OUT16VAL((base >> 8) & 0xff, 0x0c),0x03D4); + outw(IO_OUT16VAL(base & 0xff, 0x0d),0x03D4); + outw(IO_OUT16VAL((base >> 16) & 0xf, 0x69),0x03D4); + return 0; +} + + + /* + * Get the Colormap + */ + +static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + if (con == info->currcon) /* current console? */ + return fb_get_cmap(cmap, kspc, s3trio_getcolreg, info); + else if (fb_display[con].cmap.len) /* non default colormap? */ + 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; +} + +int __init s3triofb_init(void) +{ + struct device_node *dp; + + dp = find_devices("S3Trio"); + if (dp != 0) + s3triofb_of_init(dp); + return 0; +} + +void __init s3trio_resetaccel(void){ + + +#define EC01_ENH_ENB 0x0005 +#define EC01_LAW_ENB 0x0010 +#define EC01_MMIO_ENB 0x0020 + +#define EC00_RESET 0x8000 +#define EC00_ENABLE 0x4000 +#define MF_MULT_MISC 0xE000 +#define SRC_FOREGROUND 0x0020 +#define SRC_BACKGROUND 0x0000 +#define MIX_SRC 0x0007 +#define MF_T_CLIP 0x1000 +#define MF_L_CLIP 0x2000 +#define MF_B_CLIP 0x3000 +#define MF_R_CLIP 0x4000 +#define MF_PIX_CONTROL 0xA000 +#define MFA_SRC_FOREGR_MIX 0x0000 +#define MF_PIX_CONTROL 0xA000 + + outw(EC00_RESET, 0x42e8); + inw( 0x42e8); + outw(EC00_ENABLE, 0x42e8); + inw( 0x42e8); + outw(EC01_ENH_ENB | EC01_LAW_ENB, + 0x4ae8); + outw(MF_MULT_MISC, 0xbee8); /* 16 bit I/O registers */ + + /* Now set some basic accelerator registers */ + Trio_WaitQueue(0x0400); + outw(SRC_FOREGROUND | MIX_SRC, 0xbae8); + outw(SRC_BACKGROUND | MIX_SRC, 0xb6e8);/* direct color*/ + outw(MF_T_CLIP | 0, 0xbee8 ); /* clip virtual area */ + outw(MF_L_CLIP | 0, 0xbee8 ); + outw(MF_R_CLIP | (640 - 1), 0xbee8); + outw(MF_B_CLIP | (480 - 1), 0xbee8); + Trio_WaitQueue(0x0400); + outw(0xffff, 0xaae8); /* Enable all planes */ + outw(0xffff, 0xaae8); /* Enable all planes */ + outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX, 0xbee8); +} + +int __init s3trio_init(struct device_node *dp){ + + u_char bus, dev; + unsigned int t32; + unsigned short cmd; + + pci_device_loc(dp,&bus,&dev); + pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32); + if(t32 == (PCI_DEVICE_ID_S3_TRIO << 16) + PCI_VENDOR_ID_S3) { + pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32); + pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32); + pcibios_read_config_word(bus, dev, PCI_COMMAND,&cmd); + + pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + + pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff); + pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32); + +/* This is a gross hack as OF only maps enough memory for the framebuffer and + we want to use MMIO too. We should find out which chunk of address space + we can use here */ + pcibios_write_config_dword(bus,dev,PCI_BASE_ADDRESS_0,0xc6000000); + + /* unlock s3 */ + + outb(0x01, 0x3C3); + + outb(inb(0x03CC) | 1, 0x3c2); + + outw(IO_OUT16VAL(0x48, 0x38),0x03D4); + outw(IO_OUT16VAL(0xA0, 0x39),0x03D4); + outb(0x33,0x3d4); + outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 | 0x40)) | + 0x20, 0x33), 0x3d4); + + outw(IO_OUT16VAL(0x6, 0x8), 0x3c4); + + /* switch to MMIO only mode */ + + outb(0x58, 0x3d4); + outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4); + outw(IO_OUT16VAL(8, 0x53), 0x3d4); + + /* switch off I/O accesses */ + +#if 0 + pcibios_write_config_word(bus, dev, PCI_COMMAND, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY); +#endif + return 1; + } + + return 0; +} + + + /* + * Initialisation + * We heavily rely on OF for the moment. This needs fixing. + */ + +static void __init s3triofb_of_init(struct device_node *dp) +{ + int i, *pp, len; + unsigned long address, size; + u_long *CursorBase; + + strncat(s3trio_name, dp->name, sizeof(s3trio_name)); + s3trio_name[sizeof(s3trio_name)-1] = '\0'; + strcpy(fb_fix.id, s3trio_name); + + if((pp = (int *)get_property(dp, "vendor-id", &len)) != NULL + && *pp!=PCI_VENDOR_ID_S3) { + printk("%s: can't find S3 Trio board\n", dp->full_name); + return; + } + + if((pp = (int *)get_property(dp, "device-id", &len)) != NULL + && *pp!=PCI_DEVICE_ID_S3_TRIO) { + printk("%s: can't find S3 Trio board\n", dp->full_name); + return; + } + + if ((pp = (int *)get_property(dp, "depth", &len)) != NULL + && len == sizeof(int) && *pp != 8) { + printk("%s: can't use depth = %d\n", dp->full_name, *pp); + return; + } + if ((pp = (int *)get_property(dp, "width", &len)) != NULL + && len == sizeof(int)) + fb_var.xres = fb_var.xres_virtual = *pp; + if ((pp = (int *)get_property(dp, "height", &len)) != NULL + && len == sizeof(int)) + fb_var.yres = fb_var.yres_virtual = *pp; + if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL + && len == sizeof(int)) + fb_fix.line_length = *pp; + else + fb_fix.line_length = fb_var.xres_virtual; + fb_fix.smem_len = fb_fix.line_length*fb_var.yres; + + address = 0xc6000000; + size = 64*1024*1024; + if (!request_mem_region(address, size, "S3triofb")) + return; + + s3trio_init(dp); + s3trio_base = ioremap(address, size); + fb_fix.smem_start = address; + fb_fix.type = FB_TYPE_PACKED_PIXELS; + fb_fix.type_aux = 0; + fb_fix.accel = FB_ACCEL_S3_TRIO64; + fb_fix.mmio_start = address+0x1000000; + fb_fix.mmio_len = 0x1000000; + + fb_fix.xpanstep = 1; + fb_fix.ypanstep = 1; + + s3trio_resetaccel(); + + mem_out8(0x30, s3trio_base+0x1008000 + 0x03D4); + mem_out8(0x2d, s3trio_base+0x1008000 + 0x03D4); + mem_out8(0x2e, s3trio_base+0x1008000 + 0x03D4); + + mem_out8(0x50, s3trio_base+0x1008000 + 0x03D4); + + /* disable HW cursor */ + + mem_out8(0x39, s3trio_base+0x1008000 + 0x03D4); + mem_out8(0xa0, s3trio_base+0x1008000 + 0x03D5); + + mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4); + mem_out8(0, s3trio_base+0x1008000 + 0x03D5); + + mem_out8(0x4e, s3trio_base+0x1008000 + 0x03D4); + mem_out8(0, s3trio_base+0x1008000 + 0x03D5); + + mem_out8(0x4f, s3trio_base+0x1008000 + 0x03D4); + mem_out8(0, s3trio_base+0x1008000 + 0x03D5); + + /* init HW cursor */ + + CursorBase = (u_long *)(s3trio_base + 2*1024*1024 - 0x400); + for (i = 0; i < 8; i++) { + *(CursorBase +(i*4)) = 0xffffff00; + *(CursorBase+1+(i*4)) = 0xffff0000; + *(CursorBase+2+(i*4)) = 0xffff0000; + *(CursorBase+3+(i*4)) = 0xffff0000; + } + for (i = 8; i < 64; i++) { + *(CursorBase +(i*4)) = 0xffff0000; + *(CursorBase+1+(i*4)) = 0xffff0000; + *(CursorBase+2+(i*4)) = 0xffff0000; + *(CursorBase+3+(i*4)) = 0xffff0000; + } + + + mem_out8(0x4c, s3trio_base+0x1008000 + 0x03D4); + mem_out8(((2*1024 - 1)&0xf00)>>8, s3trio_base+0x1008000 + 0x03D5); + + mem_out8(0x4d, s3trio_base+0x1008000 + 0x03D4); + mem_out8((2*1024 - 1) & 0xff, s3trio_base+0x1008000 + 0x03D5); + + mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4); + mem_in8(s3trio_base+0x1008000 + 0x03D4); + + mem_out8(0x4a, s3trio_base+0x1008000 + 0x03D4); + mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5); + mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5); + mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5); + + mem_out8(0x4b, s3trio_base+0x1008000 + 0x03D4); + mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5); + mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5); + mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5); + + mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4); + mem_out8(0, s3trio_base+0x1008000 + 0x03D5); + + /* setup default color table */ + + for(i = 0; i < 16; i++) { + int j = color_table[i]; + palette[i].red=default_red[j]; + palette[i].green=default_grn[j]; + palette[i].blue=default_blu[j]; + } + + s3trio_setcolreg(255, 56, 100, 160, 0, NULL /* not used */); + s3trio_setcolreg(254, 0, 0, 0, 0, NULL /* not used */); + memset((char *)s3trio_base, 0, 640*480); + +#if 0 + Trio_RectFill(0, 0, 90, 90, 7, 1); +#endif + + fb_fix.visual = FB_VISUAL_PSEUDOCOLOR ; + fb_var.xoffset = fb_var.yoffset = 0; + fb_var.bits_per_pixel = 8; + fb_var.grayscale = 0; + fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0; + fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8; + fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0; + fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0; + fb_var.nonstd = 0; + fb_var.activate = 0; + fb_var.height = fb_var.width = -1; + fb_var.accel_flags = FB_ACCELF_TEXT; +#warning FIXME: always obey fb_var.accel_flags + fb_var.pixclock = 1; + fb_var.left_margin = fb_var.right_margin = 0; + fb_var.upper_margin = fb_var.lower_margin = 0; + fb_var.hsync_len = fb_var.vsync_len = 0; + fb_var.sync = 0; + fb_var.vmode = FB_VMODE_NONINTERLACED; + + disp.var = fb_var; + disp.cmap.start = 0; + disp.cmap.len = 0; + disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL; + disp.visual = fb_fix.visual; + disp.type = fb_fix.type; + disp.type_aux = fb_fix.type_aux; + disp.ypanstep = 0; + disp.ywrapstep = 0; + disp.line_length = fb_fix.line_length; + disp.can_soft_blank = 1; + disp.inverse = 0; +#ifdef FBCON_HAS_CFB8 + if (fb_var.accel_flags & FB_ACCELF_TEXT) + disp.dispsw = &fbcon_trio8; + else + disp.dispsw = &fbcon_cfb8; +#else + disp.dispsw = &fbcon_dummy; +#endif + disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW; + + strcpy(fb_info.modename, "Trio64 "); + strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename)); + fb_info.currcon = -1; + fb_info.fbops = &s3trio_ops; + fb_info.screen_base = s3trio_base; +#if 0 + fb_info.fbvar_num = 1; + fb_info.fbvar = &fb_var; +#endif + fb_info.disp = &disp; + fb_info.fontname[0] = '\0'; + fb_info.changevar = NULL; + fb_info.switch_con = &s3triofbcon_switch; + fb_info.updatevar = &s3triofbcon_updatevar; +#if 0 + fb_info.setcmap = &s3triofbcon_setcmap; +#endif + + fb_info.flags = FBINFO_FLAG_DEFAULT; + if (register_framebuffer(&fb_info) < 0) + return; + + printk("fb%d: S3 Trio frame buffer device on %s\n", + fb_info.node, dp->full_name); +} + + +static int s3triofbcon_switch(int con, struct fb_info *info) +{ + /* Do we have to save the colormap? */ + if (fb_display[info->currcon].cmap.len) + fb_get_cmap(&fb_display[info->currcon].cmap, 1, s3trio_getcolreg, info); + + info->currcon = con; + /* Install new colormap */ + do_install_cmap(con,info); + return 0; +} + + /* + * Update the `var' structure (called by fbcon.c) + */ + +static int s3triofbcon_updatevar(int con, struct fb_info *info) +{ + /* Nothing */ + return 0; +} + + /* + * Blank the display. + */ + +static int s3triofb_blank(int blank, struct fb_info *info) +{ + unsigned char x; + + mem_out8(0x1, s3trio_base+0x1008000 + 0x03c4); + x = mem_in8(s3trio_base+0x1008000 + 0x03c5); + mem_out8((x & (~0x20)) | (blank << 5), s3trio_base+0x1008000 + 0x03c5); + return 0; +} + + /* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info) +{ + if (regno > 255) + return 1; + *red = (palette[regno].red << 8) | palette[regno].red; + *green = (palette[regno].green << 8) | palette[regno].green; + *blue = (palette[regno].blue << 8) | palette[regno].blue; + *transp = 0; + return 0; +} + + + /* + * Set a single color register. Return != 0 for invalid regno. + */ + +static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + if (regno > 255) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + palette[regno].red = red; + palette[regno].green = green; + palette[regno].blue = blue; + + mem_out8(regno,s3trio_base+0x1008000 + 0x3c8); + mem_out8((red & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9); + mem_out8((green & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9); + mem_out8((blue & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9); + + return 0; +} + +static void Trio_WaitQueue(u_short fifo) { + + u_short status; + + do + { + status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8); + } while (!(status & fifo)); + +} + +static void Trio_WaitBlit(void) { + + u_short status; + + do + { + status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8); + } while (status & 0x200); + +} + +static void Trio_BitBLT(u_short curx, u_short cury, u_short destx, + u_short desty, u_short width, u_short height, + u_short mode) { + + u_short blitcmd = 0xc011; + + /* Set drawing direction */ + /* -Y, X maj, -X (default) */ + + if (curx > destx) + blitcmd |= 0x0020; /* Drawing direction +X */ + else { + curx += (width - 1); + destx += (width - 1); + } + + if (cury > desty) + blitcmd |= 0x0080; /* Drawing direction +Y */ + else { + cury += (height - 1); + desty += (height - 1); + } + + Trio_WaitQueue(0x0400); + + outw(0xa000, 0xBEE8); + outw(0x60 | mode, 0xBAE8); + + outw(curx, 0x86E8); + outw(cury, 0x82E8); + + outw(destx, 0x8EE8); + outw(desty, 0x8AE8); + + outw(height - 1, 0xBEE8); + outw(width - 1, 0x96E8); + + outw(blitcmd, 0x9AE8); + +} + +static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height, + u_short mode, u_short color) { + + u_short blitcmd = 0x40b1; + + Trio_WaitQueue(0x0400); + + outw(0xa000, 0xBEE8); + outw((0x20 | mode), 0xBAE8); + outw(0xe000, 0xBEE8); + outw(color, 0xA6E8); + outw(x, 0x86E8); + outw(y, 0x82E8); + outw((height - 1), 0xBEE8); + outw((width - 1), 0x96E8); + outw(blitcmd, 0x9AE8); + +} + + +static void Trio_MoveCursor(u_short x, u_short y) { + + mem_out8(0x39, s3trio_base + 0x1008000 + 0x3d4); + mem_out8(0xa0, s3trio_base + 0x1008000 + 0x3d5); + + mem_out8(0x46, s3trio_base + 0x1008000 + 0x3d4); + mem_out8((x & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5); + mem_out8(0x47, s3trio_base + 0x1008000 + 0x3d4); + mem_out8(x & 0x00ff, s3trio_base + 0x1008000 + 0x3d5); + + mem_out8(0x48, s3trio_base + 0x1008000 + 0x3d4); + mem_out8((y & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5); + mem_out8(0x49, s3trio_base + 0x1008000 + 0x3d4); + mem_out8(y & 0x00ff, s3trio_base + 0x1008000 + 0x3d5); + +} + + + /* + * Text console acceleration + */ + +#ifdef FBCON_HAS_CFB8 +static void fbcon_trio8_bmove(struct display *p, int sy, int sx, int dy, + int dx, int height, int width) +{ + sx *= 8; dx *= 8; width *= 8; + Trio_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx, + (u_short)(dy*fontheight(p)), (u_short)width, + (u_short)(height*fontheight(p)), (u_short)S3_NEW); +} + +static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + unsigned char bg; + + sx *= 8; width *= 8; + bg = attr_bgcol_ec(p,conp); + Trio_RectFill((u_short)sx, + (u_short)(sy*fontheight(p)), + (u_short)width, + (u_short)(height*fontheight(p)), + (u_short)S3_NEW, + (u_short)bg); +} + +static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c, + int yy, int xx) +{ + Trio_WaitBlit(); + fbcon_cfb8_putc(conp, p, c, yy, xx); +} + +static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, int xx) +{ + Trio_WaitBlit(); + fbcon_cfb8_putcs(conp, p, s, count, yy, xx); +} + +static void fbcon_trio8_revc(struct display *p, int xx, int yy) +{ + Trio_WaitBlit(); + fbcon_cfb8_revc(p, xx, yy); +} + +static struct display_switch fbcon_trio8 = { + .setup = fbcon_cfb8_setup, + .bmove = fbcon_trio8_bmove, + .clear = fbcon_trio8_clear, + .putc = fbcon_trio8_putc, + .putcs = fbcon_trio8_putcs, + .revc = fbcon_trio8_revc, + .clear_margins = fbcon_cfb8_clear_margins, + .fontwidthmask = FONTWIDTH(8) +}; +#endif + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c new file mode 100644 index 000000000000..f02965f39501 --- /dev/null +++ b/drivers/video/acornfb.c @@ -0,0 +1,1472 @@ +/* + * linux/drivers/video/acornfb.c + * + * Copyright (C) 1998-2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Frame buffer code for Acorn platforms + * + * NOTE: Most of the modes with X!=640 will disappear shortly. + * NOTE: Startup setting of HS & VS polarity not supported. + * (do we need to support it if we're coming up in 640x480?) + * + * FIXME: (things broken by the "new improved" FBCON API) + * - Blanking 8bpp displays with VIDC + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/ctype.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mach-types.h> +#include <asm/pgtable.h> + +#include "acornfb.h" + +/* + * VIDC machines can't do 16 or 32BPP modes. + */ +#ifdef HAS_VIDC +#undef FBCON_HAS_CFB16 +#undef FBCON_HAS_CFB32 +#endif + +/* + * Default resolution. + * NOTE that it has to be supported in the table towards + * the end of this file. + */ +#define DEFAULT_XRES 640 +#define DEFAULT_YRES 480 +#define DEFAULT_BPP 4 + +/* + * define this to debug the video mode selection + */ +#undef DEBUG_MODE_SELECTION + +/* + * Translation from RISC OS monitor types to actual + * HSYNC and VSYNC frequency ranges. These are + * probably not right, but they're the best info I + * have. Allow 1% either way on the nominal for TVs. + */ +#define NR_MONTYPES 6 +static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = { + { /* TV */ + .hfmin = 15469, + .hfmax = 15781, + .vfmin = 49, + .vfmax = 51, + }, { /* Multi Freq */ + .hfmin = 0, + .hfmax = 99999, + .vfmin = 0, + .vfmax = 199, + }, { /* Hi-res mono */ + .hfmin = 58608, + .hfmax = 58608, + .vfmin = 64, + .vfmax = 64, + }, { /* VGA */ + .hfmin = 30000, + .hfmax = 70000, + .vfmin = 60, + .vfmax = 60, + }, { /* SVGA */ + .hfmin = 30000, + .hfmax = 70000, + .vfmin = 56, + .vfmax = 75, + }, { + .hfmin = 30000, + .hfmax = 70000, + .vfmin = 60, + .vfmax = 60, + } +}; + +static struct fb_info fb_info; +static struct acornfb_par current_par; +static struct vidc_timing current_vidc; + +extern unsigned int vram_size; /* set by setup.c */ + +#ifdef HAS_VIDC + +#define MAX_SIZE 480*1024 + +/* CTL VIDC Actual + * 24.000 0 8.000 + * 25.175 0 8.392 + * 36.000 0 12.000 + * 24.000 1 12.000 + * 25.175 1 12.588 + * 24.000 2 16.000 + * 25.175 2 16.783 + * 36.000 1 18.000 + * 24.000 3 24.000 + * 36.000 2 24.000 + * 25.175 3 25.175 + * 36.000 3 36.000 + */ +struct pixclock { + u_long min_clock; + u_long max_clock; + u_int vidc_ctl; + u_int vid_ctl; +}; + +static struct pixclock arc_clocks[] = { + /* we allow +/-1% on these */ + { 123750, 126250, VIDC_CTRL_DIV3, VID_CTL_24MHz }, /* 8.000MHz */ + { 82500, 84167, VIDC_CTRL_DIV2, VID_CTL_24MHz }, /* 12.000MHz */ + { 61875, 63125, VIDC_CTRL_DIV1_5, VID_CTL_24MHz }, /* 16.000MHz */ + { 41250, 42083, VIDC_CTRL_DIV1, VID_CTL_24MHz }, /* 24.000MHz */ +}; + +#ifdef CONFIG_ARCH_A5K +static struct pixclock a5k_clocks[] = { + { 117974, 120357, VIDC_CTRL_DIV3, VID_CTL_25MHz }, /* 8.392MHz */ + { 78649, 80238, VIDC_CTRL_DIV2, VID_CTL_25MHz }, /* 12.588MHz */ + { 58987, 60178, VIDC_CTRL_DIV1_5, VID_CTL_25MHz }, /* 16.588MHz */ + { 55000, 56111, VIDC_CTRL_DIV2, VID_CTL_36MHz }, /* 18.000MHz */ + { 39325, 40119, VIDC_CTRL_DIV1, VID_CTL_25MHz }, /* 25.175MHz */ + { 27500, 28055, VIDC_CTRL_DIV1, VID_CTL_36MHz }, /* 36.000MHz */ +}; +#endif + +static struct pixclock * +acornfb_valid_pixrate(struct fb_var_screeninfo *var) +{ + u_long pixclock = var->pixclock; + u_int i; + + if (!var->pixclock) + return NULL; + + for (i = 0; i < ARRAY_SIZE(arc_clocks); i++) + if (pixclock > arc_clocks[i].min_clock && + pixclock < arc_clocks[i].max_clock) + return arc_clocks + i; + +#ifdef CONFIG_ARCH_A5K + if (machine_is_a5k()) { + for (i = 0; i < ARRAY_SIZE(a5k_clocks); i++) + if (pixclock > a5k_clocks[i].min_clock && + pixclock < a5k_clocks[i].max_clock) + return a5k_clocks + i; + } +#endif + + return NULL; +} + +/* VIDC Rules: + * hcr : must be even (interlace, hcr/2 must be even) + * hswr : must be even + * hdsr : must be odd + * hder : must be odd + * + * vcr : must be odd + * vswr : >= 1 + * vdsr : >= 1 + * vder : >= vdsr + * if interlaced, then hcr/2 must be even + */ +static void +acornfb_set_timing(struct fb_var_screeninfo *var) +{ + struct pixclock *pclk; + struct vidc_timing vidc; + u_int horiz_correction; + u_int sync_len, display_start, display_end, cycle; + u_int is_interlaced; + u_int vid_ctl, vidc_ctl; + u_int bandwidth; + + memset(&vidc, 0, sizeof(vidc)); + + pclk = acornfb_valid_pixrate(var); + vidc_ctl = pclk->vidc_ctl; + vid_ctl = pclk->vid_ctl; + + bandwidth = var->pixclock * 8 / var->bits_per_pixel; + /* 25.175, 4bpp = 79.444ns per byte, 317.776ns per word: fifo = 2,6 */ + if (bandwidth > 143500) + vidc_ctl |= VIDC_CTRL_FIFO_3_7; + else if (bandwidth > 71750) + vidc_ctl |= VIDC_CTRL_FIFO_2_6; + else if (bandwidth > 35875) + vidc_ctl |= VIDC_CTRL_FIFO_1_5; + else + vidc_ctl |= VIDC_CTRL_FIFO_0_4; + + switch (var->bits_per_pixel) { + case 1: + horiz_correction = 19; + vidc_ctl |= VIDC_CTRL_1BPP; + break; + + case 2: + horiz_correction = 11; + vidc_ctl |= VIDC_CTRL_2BPP; + break; + + case 4: + horiz_correction = 7; + vidc_ctl |= VIDC_CTRL_4BPP; + break; + + default: + case 8: + horiz_correction = 5; + vidc_ctl |= VIDC_CTRL_8BPP; + break; + } + + if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */ + vidc_ctl |= VIDC_CTRL_CSYNC; + else { + if (!(var->sync & FB_SYNC_HOR_HIGH_ACT)) + vid_ctl |= VID_CTL_HS_NHSYNC; + + if (!(var->sync & FB_SYNC_VERT_HIGH_ACT)) + vid_ctl |= VID_CTL_VS_NVSYNC; + } + + sync_len = var->hsync_len; + display_start = sync_len + var->left_margin; + display_end = display_start + var->xres; + cycle = display_end + var->right_margin; + + /* if interlaced, then hcr/2 must be even */ + is_interlaced = (var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED; + + if (is_interlaced) { + vidc_ctl |= VIDC_CTRL_INTERLACE; + if (cycle & 2) { + cycle += 2; + var->right_margin += 2; + } + } + + vidc.h_cycle = (cycle - 2) / 2; + vidc.h_sync_width = (sync_len - 2) / 2; + vidc.h_border_start = (display_start - 1) / 2; + vidc.h_display_start = (display_start - horiz_correction) / 2; + vidc.h_display_end = (display_end - horiz_correction) / 2; + vidc.h_border_end = (display_end - 1) / 2; + vidc.h_interlace = (vidc.h_cycle + 1) / 2; + + sync_len = var->vsync_len; + display_start = sync_len + var->upper_margin; + display_end = display_start + var->yres; + cycle = display_end + var->lower_margin; + + if (is_interlaced) + cycle = (cycle - 3) / 2; + else + cycle = cycle - 1; + + vidc.v_cycle = cycle; + vidc.v_sync_width = sync_len - 1; + vidc.v_border_start = display_start - 1; + vidc.v_display_start = vidc.v_border_start; + vidc.v_display_end = display_end - 1; + vidc.v_border_end = vidc.v_display_end; + + if (machine_is_a5k()) + __raw_writeb(vid_ctl, IOEB_VID_CTL); + + if (memcmp(¤t_vidc, &vidc, sizeof(vidc))) { + current_vidc = vidc; + + vidc_writel(0xe0000000 | vidc_ctl); + vidc_writel(0x80000000 | (vidc.h_cycle << 14)); + vidc_writel(0x84000000 | (vidc.h_sync_width << 14)); + vidc_writel(0x88000000 | (vidc.h_border_start << 14)); + vidc_writel(0x8c000000 | (vidc.h_display_start << 14)); + vidc_writel(0x90000000 | (vidc.h_display_end << 14)); + vidc_writel(0x94000000 | (vidc.h_border_end << 14)); + vidc_writel(0x98000000); + vidc_writel(0x9c000000 | (vidc.h_interlace << 14)); + vidc_writel(0xa0000000 | (vidc.v_cycle << 14)); + vidc_writel(0xa4000000 | (vidc.v_sync_width << 14)); + vidc_writel(0xa8000000 | (vidc.v_border_start << 14)); + vidc_writel(0xac000000 | (vidc.v_display_start << 14)); + vidc_writel(0xb0000000 | (vidc.v_display_end << 14)); + vidc_writel(0xb4000000 | (vidc.v_border_end << 14)); + vidc_writel(0xb8000000); + vidc_writel(0xbc000000); + } +#ifdef DEBUG_MODE_SELECTION + printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres, + var->yres, var->bits_per_pixel); + printk(KERN_DEBUG " H-cycle : %d\n", vidc.h_cycle); + printk(KERN_DEBUG " H-sync-width : %d\n", vidc.h_sync_width); + printk(KERN_DEBUG " H-border-start : %d\n", vidc.h_border_start); + printk(KERN_DEBUG " H-display-start : %d\n", vidc.h_display_start); + printk(KERN_DEBUG " H-display-end : %d\n", vidc.h_display_end); + printk(KERN_DEBUG " H-border-end : %d\n", vidc.h_border_end); + printk(KERN_DEBUG " H-interlace : %d\n", vidc.h_interlace); + printk(KERN_DEBUG " V-cycle : %d\n", vidc.v_cycle); + printk(KERN_DEBUG " V-sync-width : %d\n", vidc.v_sync_width); + printk(KERN_DEBUG " V-border-start : %d\n", vidc.v_border_start); + printk(KERN_DEBUG " V-display-start : %d\n", vidc.v_display_start); + printk(KERN_DEBUG " V-display-end : %d\n", vidc.v_display_end); + printk(KERN_DEBUG " V-border-end : %d\n", vidc.v_border_end); + printk(KERN_DEBUG " VIDC Ctrl (E) : 0x%08X\n", vidc_ctl); + printk(KERN_DEBUG " IOEB Ctrl : 0x%08X\n", vid_ctl); +#endif +} + +static int +acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int trans, struct fb_info *info) +{ + union palette pal; + + if (regno >= current_par.palette_size) + return 1; + + pal.p = 0; + pal.vidc.reg = regno; + pal.vidc.red = red >> 12; + pal.vidc.green = green >> 12; + pal.vidc.blue = blue >> 12; + + current_par.palette[regno] = pal; + + vidc_writel(pal.p); + + return 0; +} +#endif + +#ifdef HAS_VIDC20 +#include <asm/arch/acornfb.h> + +#define MAX_SIZE 2*1024*1024 + +/* VIDC20 has a different set of rules from the VIDC: + * hcr : must be multiple of 4 + * hswr : must be even + * hdsr : must be even + * hder : must be even + * vcr : >= 2, (interlace, must be odd) + * vswr : >= 1 + * vdsr : >= 1 + * vder : >= vdsr + */ +static void acornfb_set_timing(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct vidc_timing vidc; + u_int vcr, fsize; + u_int ext_ctl, dat_ctl; + u_int words_per_line; + + memset(&vidc, 0, sizeof(vidc)); + + vidc.h_sync_width = var->hsync_len - 8; + vidc.h_border_start = vidc.h_sync_width + var->left_margin + 8 - 12; + vidc.h_display_start = vidc.h_border_start + 12 - 18; + vidc.h_display_end = vidc.h_display_start + var->xres; + vidc.h_border_end = vidc.h_display_end + 18 - 12; + vidc.h_cycle = vidc.h_border_end + var->right_margin + 12 - 8; + vidc.h_interlace = vidc.h_cycle / 2; + vidc.v_sync_width = var->vsync_len - 1; + vidc.v_border_start = vidc.v_sync_width + var->upper_margin; + vidc.v_display_start = vidc.v_border_start; + vidc.v_display_end = vidc.v_display_start + var->yres; + vidc.v_border_end = vidc.v_display_end; + vidc.control = acornfb_default_control(); + + vcr = var->vsync_len + var->upper_margin + var->yres + + var->lower_margin; + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + vidc.v_cycle = (vcr - 3) / 2; + vidc.control |= VIDC20_CTRL_INT; + } else + vidc.v_cycle = vcr - 2; + + switch (var->bits_per_pixel) { + case 1: vidc.control |= VIDC20_CTRL_1BPP; break; + case 2: vidc.control |= VIDC20_CTRL_2BPP; break; + case 4: vidc.control |= VIDC20_CTRL_4BPP; break; + default: + case 8: vidc.control |= VIDC20_CTRL_8BPP; break; + case 16: vidc.control |= VIDC20_CTRL_16BPP; break; + case 32: vidc.control |= VIDC20_CTRL_32BPP; break; + } + + acornfb_vidc20_find_rates(&vidc, var); + fsize = var->vsync_len + var->upper_margin + var->lower_margin - 1; + + if (memcmp(¤t_vidc, &vidc, sizeof(vidc))) { + current_vidc = vidc; + + vidc_writel(VIDC20_CTRL| vidc.control); + vidc_writel(0xd0000000 | vidc.pll_ctl); + vidc_writel(0x80000000 | vidc.h_cycle); + vidc_writel(0x81000000 | vidc.h_sync_width); + vidc_writel(0x82000000 | vidc.h_border_start); + vidc_writel(0x83000000 | vidc.h_display_start); + vidc_writel(0x84000000 | vidc.h_display_end); + vidc_writel(0x85000000 | vidc.h_border_end); + vidc_writel(0x86000000); + vidc_writel(0x87000000 | vidc.h_interlace); + vidc_writel(0x90000000 | vidc.v_cycle); + vidc_writel(0x91000000 | vidc.v_sync_width); + vidc_writel(0x92000000 | vidc.v_border_start); + vidc_writel(0x93000000 | vidc.v_display_start); + vidc_writel(0x94000000 | vidc.v_display_end); + vidc_writel(0x95000000 | vidc.v_border_end); + vidc_writel(0x96000000); + vidc_writel(0x97000000); + } + + iomd_writel(fsize, IOMD_FSIZE); + + ext_ctl = acornfb_default_econtrol(); + + if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */ + ext_ctl |= VIDC20_ECTL_HS_NCSYNC | VIDC20_ECTL_VS_NCSYNC; + else { + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + ext_ctl |= VIDC20_ECTL_HS_HSYNC; + else + ext_ctl |= VIDC20_ECTL_HS_NHSYNC; + + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + ext_ctl |= VIDC20_ECTL_VS_VSYNC; + else + ext_ctl |= VIDC20_ECTL_VS_NVSYNC; + } + + vidc_writel(VIDC20_ECTL | ext_ctl); + + words_per_line = var->xres * var->bits_per_pixel / 32; + + if (current_par.using_vram && info->fix.smem_len == 2048*1024) + words_per_line /= 2; + + /* RiscPC doesn't use the VIDC's VRAM control. */ + dat_ctl = VIDC20_DCTL_VRAM_DIS | VIDC20_DCTL_SNA | words_per_line; + + /* The data bus width is dependent on both the type + * and amount of video memory. + * DRAM 32bit low + * 1MB VRAM 32bit + * 2MB VRAM 64bit + */ + if (current_par.using_vram && current_par.vram_half_sam == 2048) + dat_ctl |= VIDC20_DCTL_BUS_D63_0; + else + dat_ctl |= VIDC20_DCTL_BUS_D31_0; + + vidc_writel(VIDC20_DCTL | dat_ctl); + +#ifdef DEBUG_MODE_SELECTION + printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres, + var->yres, var->bits_per_pixel); + printk(KERN_DEBUG " H-cycle : %d\n", vidc.h_cycle); + printk(KERN_DEBUG " H-sync-width : %d\n", vidc.h_sync_width); + printk(KERN_DEBUG " H-border-start : %d\n", vidc.h_border_start); + printk(KERN_DEBUG " H-display-start : %d\n", vidc.h_display_start); + printk(KERN_DEBUG " H-display-end : %d\n", vidc.h_display_end); + printk(KERN_DEBUG " H-border-end : %d\n", vidc.h_border_end); + printk(KERN_DEBUG " H-interlace : %d\n", vidc.h_interlace); + printk(KERN_DEBUG " V-cycle : %d\n", vidc.v_cycle); + printk(KERN_DEBUG " V-sync-width : %d\n", vidc.v_sync_width); + printk(KERN_DEBUG " V-border-start : %d\n", vidc.v_border_start); + printk(KERN_DEBUG " V-display-start : %d\n", vidc.v_display_start); + printk(KERN_DEBUG " V-display-end : %d\n", vidc.v_display_end); + printk(KERN_DEBUG " V-border-end : %d\n", vidc.v_border_end); + printk(KERN_DEBUG " Ext Ctrl (C) : 0x%08X\n", ext_ctl); + printk(KERN_DEBUG " PLL Ctrl (D) : 0x%08X\n", vidc.pll_ctl); + printk(KERN_DEBUG " Ctrl (E) : 0x%08X\n", vidc.control); + printk(KERN_DEBUG " Data Ctrl (F) : 0x%08X\n", dat_ctl); + printk(KERN_DEBUG " Fsize : 0x%08X\n", fsize); +#endif +} + +/* + * We have to take note of the VIDC20's 16-bit palette here. + * The VIDC20 looks up a 16 bit pixel as follows: + * + * bits 111111 + * 5432109876543210 + * red ++++++++ (8 bits, 7 to 0) + * green ++++++++ (8 bits, 11 to 4) + * blue ++++++++ (8 bits, 15 to 8) + * + * We use a pixel which looks like: + * + * bits 111111 + * 5432109876543210 + * red +++++ (5 bits, 4 to 0) + * green +++++ (5 bits, 9 to 5) + * blue +++++ (5 bits, 14 to 10) + */ +static int +acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int trans, struct fb_info *info) +{ + union palette pal; + + if (regno >= current_par.palette_size) + return 1; + + if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + u32 pseudo_val; + + pseudo_val = regno << info->var.red.offset; + pseudo_val |= regno << info->var.green.offset; + pseudo_val |= regno << info->var.blue.offset; + + ((u32 *)info->pseudo_palette)[regno] = pseudo_val; + } + + pal.p = 0; + pal.vidc20.red = red >> 8; + pal.vidc20.green = green >> 8; + pal.vidc20.blue = blue >> 8; + + current_par.palette[regno] = pal; + + if (info->var.bits_per_pixel == 16) { + int i; + + pal.p = 0; + vidc_writel(0x10000000); + for (i = 0; i < 256; i += 1) { + pal.vidc20.red = current_par.palette[ i & 31].vidc20.red; + pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green; + pal.vidc20.blue = current_par.palette[(i >> 2) & 31].vidc20.blue; + vidc_writel(pal.p); + /* Palette register pointer auto-increments */ + } + } else { + vidc_writel(0x10000000 | regno); + vidc_writel(pal.p); + } + + return 0; +} +#endif + +/* + * Before selecting the timing parameters, adjust + * the resolution to fit the rules. + */ +static int +acornfb_adjust_timing(struct fb_info *info, struct fb_var_screeninfo *var, u_int fontht) +{ + u_int font_line_len, sam_size, min_size, size, nr_y; + + /* xres must be even */ + var->xres = (var->xres + 1) & ~1; + + /* + * We don't allow xres_virtual to differ from xres + */ + var->xres_virtual = var->xres; + var->xoffset = 0; + + if (current_par.using_vram) + sam_size = current_par.vram_half_sam * 2; + else + sam_size = 16; + + /* + * Now, find a value for yres_virtual which allows + * us to do ywrap scrolling. The value of + * yres_virtual must be such that the end of the + * displayable frame buffer must be aligned with + * the start of a font line. + */ + font_line_len = var->xres * var->bits_per_pixel * fontht / 8; + min_size = var->xres * var->yres * var->bits_per_pixel / 8; + + /* + * If minimum screen size is greater than that we have + * available, reject it. + */ + if (min_size > info->fix.smem_len) + return -EINVAL; + + /* Find int 'y', such that y * fll == s * sam < maxsize + * y = s * sam / fll; s = maxsize / sam + */ + for (size = info->fix.smem_len; + nr_y = size / font_line_len, min_size <= size; + size -= sam_size) { + if (nr_y * font_line_len == size) + break; + } + nr_y *= fontht; + + if (var->accel_flags & FB_ACCELF_TEXT) { + if (min_size > size) { + /* + * failed, use ypan + */ + size = info->fix.smem_len; + var->yres_virtual = size / (font_line_len / fontht); + } else + var->yres_virtual = nr_y; + } else if (var->yres_virtual > nr_y) + var->yres_virtual = nr_y; + + current_par.screen_end = info->fix.smem_start + size; + + /* + * Fix yres & yoffset if needed. + */ + if (var->yres > var->yres_virtual) + var->yres = var->yres_virtual; + + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset > var->yres_virtual) + var->yoffset = var->yres_virtual; + } else { + if (var->yoffset + var->yres > var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres; + } + + /* hsync_len must be even */ + var->hsync_len = (var->hsync_len + 1) & ~1; + +#ifdef HAS_VIDC + /* left_margin must be odd */ + if ((var->left_margin & 1) == 0) { + var->left_margin -= 1; + var->right_margin += 1; + } + + /* right_margin must be odd */ + var->right_margin |= 1; +#elif defined(HAS_VIDC20) + /* left_margin must be even */ + if (var->left_margin & 1) { + var->left_margin += 1; + var->right_margin -= 1; + } + + /* right_margin must be even */ + if (var->right_margin & 1) + var->right_margin += 1; +#endif + + if (var->vsync_len < 1) + var->vsync_len = 1; + + return 0; +} + +static int +acornfb_validate_timing(struct fb_var_screeninfo *var, + struct fb_monspecs *monspecs) +{ + unsigned long hs, vs; + + /* + * hs(Hz) = 10^12 / (pixclock * xtotal) + * vs(Hz) = hs(Hz) / ytotal + * + * No need to do long long divisions or anything + * like that if you factor it correctly + */ + hs = 1953125000 / var->pixclock; + hs = hs * 512 / + (var->xres + var->left_margin + var->right_margin + var->hsync_len); + vs = hs / + (var->yres + var->upper_margin + var->lower_margin + var->vsync_len); + + return (vs >= monspecs->vfmin && vs <= monspecs->vfmax && + hs >= monspecs->hfmin && hs <= monspecs->hfmax) ? 0 : -EINVAL; +} + +static inline void +acornfb_update_dma(struct fb_info *info, struct fb_var_screeninfo *var) +{ + u_int off = var->yoffset * info->fix.line_length; + +#if defined(HAS_MEMC) + memc_write(VDMA_INIT, off >> 2); +#elif defined(HAS_IOMD) + iomd_writel(info->fix.smem_start + off, IOMD_VIDINIT); +#endif +} + +static int +acornfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + u_int fontht; + int err; + + /* + * FIXME: Find the font height + */ + fontht = 8; + + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + + switch (var->bits_per_pixel) { + case 1: case 2: case 4: case 8: + var->red.offset = 0; + var->red.length = var->bits_per_pixel; + var->green = var->red; + var->blue = var->red; + var->transp.offset = 0; + var->transp.length = 0; + break; + +#ifdef HAS_VIDC20 + case 16: + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 10; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + break; + + case 32: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 4; + break; +#endif + default: + return -EINVAL; + } + + /* + * Check to see if the pixel rate is valid. + */ + if (!acornfb_valid_pixrate(var)) + return -EINVAL; + + /* + * Validate and adjust the resolution to + * match the video generator hardware. + */ + err = acornfb_adjust_timing(info, var, fontht); + if (err) + return err; + + /* + * Validate the timing against the + * monitor hardware. + */ + return acornfb_validate_timing(var, &info->monspecs); +} + +static int acornfb_set_par(struct fb_info *info) +{ + switch (info->var.bits_per_pixel) { + case 1: + current_par.palette_size = 2; + info->fix.visual = FB_VISUAL_MONO10; + break; + case 2: + current_par.palette_size = 4; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + case 4: + current_par.palette_size = 16; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + case 8: + current_par.palette_size = VIDC_PALETTE_SIZE; +#ifdef HAS_VIDC + info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; +#else + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; +#endif + break; +#ifdef HAS_VIDC20 + case 16: + current_par.palette_size = 32; + info->fix.visual = FB_VISUAL_DIRECTCOLOR; + break; + case 32: + current_par.palette_size = VIDC_PALETTE_SIZE; + info->fix.visual = FB_VISUAL_DIRECTCOLOR; + break; +#endif + default: + BUG(); + } + + info->fix.line_length = (info->var.xres * info->var.bits_per_pixel) / 8; + +#if defined(HAS_MEMC) + { + unsigned long size = info->fix.smem_len - VDMA_XFERSIZE; + + memc_write(VDMA_START, 0); + memc_write(VDMA_END, size >> 2); + } +#elif defined(HAS_IOMD) + { + unsigned long start, size; + u_int control; + + start = info->fix.smem_start; + size = current_par.screen_end; + + if (current_par.using_vram) { + size -= current_par.vram_half_sam; + control = DMA_CR_E | (current_par.vram_half_sam / 256); + } else { + size -= 16; + control = DMA_CR_E | DMA_CR_D | 16; + } + + iomd_writel(start, IOMD_VIDSTART); + iomd_writel(size, IOMD_VIDEND); + iomd_writel(control, IOMD_VIDCR); + } +#endif + + acornfb_update_dma(info, &info->var); + acornfb_set_timing(info); + + return 0; +} + +static int +acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + u_int y_bottom = var->yoffset; + + if (!(var->vmode & FB_VMODE_YWRAP)) + y_bottom += var->yres; + + BUG_ON(y_bottom > var->yres_virtual); + + acornfb_update_dma(info, var); + + return 0; +} + +/* + * Note that we are entered with the kernel locked. + */ +static int +acornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) +{ + unsigned long off, start; + u32 len; + + off = vma->vm_pgoff << PAGE_SHIFT; + + start = info->fix.smem_start; + len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len; + start &= PAGE_MASK; + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + off += start; + vma->vm_pgoff = off >> PAGE_SHIFT; + + /* This is an IO map - tell maydump to skip this VMA */ + vma->vm_flags |= VM_IO; + + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + /* + * Don't alter the page protection flags; we want to keep the area + * cached for better performance. This does mean that we may miss + * some updates to the screen occasionally, but process switches + * should cause the caches and buffers to be flushed often enough. + */ + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + return 0; +} + +static struct fb_ops acornfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = acornfb_check_var, + .fb_set_par = acornfb_set_par, + .fb_setcolreg = acornfb_setcolreg, + .fb_pan_display = acornfb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = acornfb_mmap, + .fb_cursor = soft_cursor, +}; + +/* + * Everything after here is initialisation!!! + */ +static struct fb_videomode modedb[] __initdata = { + { /* 320x256 @ 50Hz */ + NULL, 50, 320, 256, 125000, 92, 62, 35, 19, 38, 2, + FB_SYNC_COMP_HIGH_ACT, + FB_VMODE_NONINTERLACED + }, { /* 640x250 @ 50Hz, 15.6 kHz hsync */ + NULL, 50, 640, 250, 62500, 185, 123, 38, 21, 76, 3, + 0, + FB_VMODE_NONINTERLACED + }, { /* 640x256 @ 50Hz, 15.6 kHz hsync */ + NULL, 50, 640, 256, 62500, 185, 123, 35, 18, 76, 3, + 0, + FB_VMODE_NONINTERLACED + }, { /* 640x512 @ 50Hz, 26.8 kHz hsync */ + NULL, 50, 640, 512, 41667, 113, 87, 18, 1, 56, 3, + 0, + FB_VMODE_NONINTERLACED + }, { /* 640x250 @ 70Hz, 31.5 kHz hsync */ + NULL, 70, 640, 250, 39722, 48, 16, 109, 88, 96, 2, + 0, + FB_VMODE_NONINTERLACED + }, { /* 640x256 @ 70Hz, 31.5 kHz hsync */ + NULL, 70, 640, 256, 39722, 48, 16, 106, 85, 96, 2, + 0, + FB_VMODE_NONINTERLACED + }, { /* 640x352 @ 70Hz, 31.5 kHz hsync */ + NULL, 70, 640, 352, 39722, 48, 16, 58, 37, 96, 2, + 0, + FB_VMODE_NONINTERLACED + }, { /* 640x480 @ 60Hz, 31.5 kHz hsync */ + NULL, 60, 640, 480, 39722, 48, 16, 32, 11, 96, 2, + 0, + FB_VMODE_NONINTERLACED + }, { /* 800x600 @ 56Hz, 35.2 kHz hsync */ + NULL, 56, 800, 600, 27778, 101, 23, 22, 1, 100, 2, + 0, + FB_VMODE_NONINTERLACED + }, { /* 896x352 @ 60Hz, 21.8 kHz hsync */ + NULL, 60, 896, 352, 41667, 59, 27, 9, 0, 118, 3, + 0, + FB_VMODE_NONINTERLACED + }, { /* 1024x 768 @ 60Hz, 48.4 kHz hsync */ + NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6, + 0, + FB_VMODE_NONINTERLACED + }, { /* 1280x1024 @ 60Hz, 63.8 kHz hsync */ + NULL, 60, 1280, 1024, 9090, 186, 96, 38, 1, 160, 3, + 0, + FB_VMODE_NONINTERLACED + } +}; + +static struct fb_videomode __initdata +acornfb_default_mode = { + .name = NULL, + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39722, + .left_margin = 56, + .right_margin = 16, + .upper_margin = 34, + .lower_margin = 9, + .hsync_len = 88, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED +}; + +static void __init acornfb_init_fbinfo(void) +{ + static int first = 1; + + if (!first) + return; + first = 0; + + fb_info.fbops = &acornfb_ops; + fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + fb_info.pseudo_palette = current_par.pseudo_palette; + + strcpy(fb_info.fix.id, "Acorn"); + fb_info.fix.type = FB_TYPE_PACKED_PIXELS; + fb_info.fix.type_aux = 0; + fb_info.fix.xpanstep = 0; + fb_info.fix.ypanstep = 1; + fb_info.fix.ywrapstep = 1; + fb_info.fix.line_length = 0; + fb_info.fix.accel = FB_ACCEL_NONE; + + /* + * setup initial parameters + */ + memset(&fb_info.var, 0, sizeof(fb_info.var)); + +#if defined(HAS_VIDC20) + fb_info.var.red.length = 8; + fb_info.var.transp.length = 4; +#elif defined(HAS_VIDC) + fb_info.var.red.length = 4; + fb_info.var.transp.length = 1; +#endif + fb_info.var.green = fb_info.var.red; + fb_info.var.blue = fb_info.var.red; + fb_info.var.nonstd = 0; + fb_info.var.activate = FB_ACTIVATE_NOW; + fb_info.var.height = -1; + fb_info.var.width = -1; + fb_info.var.vmode = FB_VMODE_NONINTERLACED; + fb_info.var.accel_flags = FB_ACCELF_TEXT; + + current_par.dram_size = 0; + current_par.montype = -1; + current_par.dpms = 0; +} + +/* + * setup acornfb options: + * + * mon:hmin-hmax:vmin-vmax:dpms:width:height + * Set monitor parameters: + * hmin = horizontal minimum frequency (Hz) + * hmax = horizontal maximum frequency (Hz) (optional) + * vmin = vertical minimum frequency (Hz) + * vmax = vertical maximum frequency (Hz) (optional) + * dpms = DPMS supported? (optional) + * width = width of picture in mm. (optional) + * height = height of picture in mm. (optional) + * + * montype:type + * Set RISC-OS style monitor type: + * 0 (or tv) - TV frequency + * 1 (or multi) - Multi frequency + * 2 (or hires) - Hi-res monochrome + * 3 (or vga) - VGA + * 4 (or svga) - SVGA + * auto, or option missing + * - try hardware detect + * + * dram:size + * Set the amount of DRAM to use for the frame buffer + * (even if you have VRAM). + * size can optionally be followed by 'M' or 'K' for + * MB or KB respectively. + */ +static void __init +acornfb_parse_mon(char *opt) +{ + char *p = opt; + + current_par.montype = -2; + + fb_info.monspecs.hfmin = simple_strtoul(p, &p, 0); + if (*p == '-') + fb_info.monspecs.hfmax = simple_strtoul(p + 1, &p, 0); + else + fb_info.monspecs.hfmax = fb_info.monspecs.hfmin; + + if (*p != ':') + goto bad; + + fb_info.monspecs.vfmin = simple_strtoul(p + 1, &p, 0); + if (*p == '-') + fb_info.monspecs.vfmax = simple_strtoul(p + 1, &p, 0); + else + fb_info.monspecs.vfmax = fb_info.monspecs.vfmin; + + if (*p != ':') + goto check_values; + + fb_info.monspecs.dpms = simple_strtoul(p + 1, &p, 0); + + if (*p != ':') + goto check_values; + + fb_info.var.width = simple_strtoul(p + 1, &p, 0); + + if (*p != ':') + goto check_values; + + fb_info.var.height = simple_strtoul(p + 1, NULL, 0); + +check_values: + if (fb_info.monspecs.hfmax < fb_info.monspecs.hfmin || + fb_info.monspecs.vfmax < fb_info.monspecs.vfmin) + goto bad; + return; + +bad: + printk(KERN_ERR "Acornfb: bad monitor settings: %s\n", opt); + current_par.montype = -1; +} + +static void __init +acornfb_parse_montype(char *opt) +{ + current_par.montype = -2; + + if (strncmp(opt, "tv", 2) == 0) { + opt += 2; + current_par.montype = 0; + } else if (strncmp(opt, "multi", 5) == 0) { + opt += 5; + current_par.montype = 1; + } else if (strncmp(opt, "hires", 5) == 0) { + opt += 5; + current_par.montype = 2; + } else if (strncmp(opt, "vga", 3) == 0) { + opt += 3; + current_par.montype = 3; + } else if (strncmp(opt, "svga", 4) == 0) { + opt += 4; + current_par.montype = 4; + } else if (strncmp(opt, "auto", 4) == 0) { + opt += 4; + current_par.montype = -1; + } else if (isdigit(*opt)) + current_par.montype = simple_strtoul(opt, &opt, 0); + + if (current_par.montype == -2 || + current_par.montype > NR_MONTYPES) { + printk(KERN_ERR "acornfb: unknown monitor type: %s\n", + opt); + current_par.montype = -1; + } else + if (opt && *opt) { + if (strcmp(opt, ",dpms") == 0) + current_par.dpms = 1; + else + printk(KERN_ERR + "acornfb: unknown monitor option: %s\n", + opt); + } +} + +static void __init +acornfb_parse_dram(char *opt) +{ + unsigned int size; + + size = simple_strtoul(opt, &opt, 0); + + if (opt) { + switch (*opt) { + case 'M': + case 'm': + size *= 1024; + case 'K': + case 'k': + size *= 1024; + default: + break; + } + } + + current_par.dram_size = size; +} + +static struct options { + char *name; + void (*parse)(char *opt); +} opt_table[] __initdata = { + { "mon", acornfb_parse_mon }, + { "montype", acornfb_parse_montype }, + { "dram", acornfb_parse_dram }, + { NULL, NULL } +}; + +int __init +acornfb_setup(char *options) +{ + struct options *optp; + char *opt; + + if (!options || !*options) + return 0; + + acornfb_init_fbinfo(); + + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + + for (optp = opt_table; optp->name; optp++) { + int optlen; + + optlen = strlen(optp->name); + + if (strncmp(opt, optp->name, optlen) == 0 && + opt[optlen] == ':') { + optp->parse(opt + optlen + 1); + break; + } + } + + if (!optp->name) + printk(KERN_ERR "acornfb: unknown parameter: %s\n", + opt); + } + return 0; +} + +/* + * Detect type of monitor connected + * For now, we just assume SVGA + */ +static int __init +acornfb_detect_monitortype(void) +{ + return 4; +} + +/* + * This enables the unused memory to be freed on older Acorn machines. + * We are freeing memory on behalf of the architecture initialisation + * code here. + */ +static inline void +free_unused_pages(unsigned int virtual_start, unsigned int virtual_end) +{ + int mb_freed = 0; + + /* + * Align addresses + */ + virtual_start = PAGE_ALIGN(virtual_start); + virtual_end = PAGE_ALIGN(virtual_end); + + while (virtual_start < virtual_end) { + struct page *page; + + /* + * Clear page reserved bit, + * set count to 1, and free + * the page. + */ + page = virt_to_page(virtual_start); + ClearPageReserved(page); + set_page_count(page, 1); + free_page(virtual_start); + + virtual_start += PAGE_SIZE; + mb_freed += PAGE_SIZE / 1024; + } + + printk("acornfb: freed %dK memory\n", mb_freed); +} + +static int __init acornfb_probe(struct device *dev) +{ + unsigned long size; + u_int h_sync, v_sync; + int rc, i; + char *option = NULL; + + if (fb_get_options("acornfb", &option)) + return -ENODEV; + acornfb_setup(option); + + acornfb_init_fbinfo(); + + current_par.dev = dev; + + if (current_par.montype == -1) + current_par.montype = acornfb_detect_monitortype(); + + if (current_par.montype == -1 || current_par.montype > NR_MONTYPES) + current_par.montype = 4; + + if (current_par.montype >= 0) { + fb_info.monspecs = monspecs[current_par.montype]; + fb_info.monspecs.dpms = current_par.dpms; + } + + /* + * Try to select a suitable default mode + */ + for (i = 0; i < sizeof(modedb) / sizeof(*modedb); i++) { + unsigned long hs; + + hs = modedb[i].refresh * + (modedb[i].yres + modedb[i].upper_margin + + modedb[i].lower_margin + modedb[i].vsync_len); + if (modedb[i].xres == DEFAULT_XRES && + modedb[i].yres == DEFAULT_YRES && + modedb[i].refresh >= fb_info.monspecs.vfmin && + modedb[i].refresh <= fb_info.monspecs.vfmax && + hs >= fb_info.monspecs.hfmin && + hs <= fb_info.monspecs.hfmax) { + acornfb_default_mode = modedb[i]; + break; + } + } + + fb_info.screen_base = (char *)SCREEN_BASE; + fb_info.fix.smem_start = SCREEN_START; + current_par.using_vram = 0; + + /* + * If vram_size is set, we are using VRAM in + * a Risc PC. However, if the user has specified + * an amount of DRAM then use that instead. + */ + if (vram_size && !current_par.dram_size) { + size = vram_size; + current_par.vram_half_sam = vram_size / 1024; + current_par.using_vram = 1; + } else if (current_par.dram_size) + size = current_par.dram_size; + else + size = MAX_SIZE; + + /* + * Limit maximum screen size. + */ + if (size > MAX_SIZE) + size = MAX_SIZE; + + size = PAGE_ALIGN(size); + +#if defined(HAS_VIDC20) + if (!current_par.using_vram) { + dma_addr_t handle; + void *base; + + /* + * RiscPC needs to allocate the DRAM memory + * for the framebuffer if we are not using + * VRAM. + */ + base = dma_alloc_writecombine(current_par.dev, size, &handle, + GFP_KERNEL); + if (base == NULL) { + printk(KERN_ERR "acornfb: unable to allocate screen " + "memory\n"); + return -ENOMEM; + } + + fb_info.screen_base = base; + fb_info.fix.smem_start = handle; + } +#endif +#if defined(HAS_VIDC) + /* + * Archimedes/A5000 machines use a fixed address for their + * framebuffers. Free unused pages + */ + free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE); +#endif + + fb_info.fix.smem_len = size; + current_par.palette_size = VIDC_PALETTE_SIZE; + + /* + * Lookup the timing for this resolution. If we can't + * find it, then we can't restore it if we change + * the resolution, so we disable this feature. + */ + do { + rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb, + sizeof(modedb) / sizeof(*modedb), + &acornfb_default_mode, DEFAULT_BPP); + /* + * If we found an exact match, all ok. + */ + if (rc == 1) + break; + + rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0, + &acornfb_default_mode, DEFAULT_BPP); + /* + * If we found an exact match, all ok. + */ + if (rc == 1) + break; + + rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb, + sizeof(modedb) / sizeof(*modedb), + &acornfb_default_mode, DEFAULT_BPP); + if (rc) + break; + + rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0, + &acornfb_default_mode, DEFAULT_BPP); + } while (0); + + /* + * If we didn't find an exact match, try the + * generic database. + */ + if (rc == 0) { + printk("Acornfb: no valid mode found\n"); + return -EINVAL; + } + + h_sync = 1953125000 / fb_info.var.pixclock; + h_sync = h_sync * 512 / (fb_info.var.xres + fb_info.var.left_margin + + fb_info.var.right_margin + fb_info.var.hsync_len); + v_sync = h_sync / (fb_info.var.yres + fb_info.var.upper_margin + + fb_info.var.lower_margin + fb_info.var.vsync_len); + + printk(KERN_INFO "Acornfb: %dkB %cRAM, %s, using %dx%d, " + "%d.%03dkHz, %dHz\n", + fb_info.fix.smem_len / 1024, + current_par.using_vram ? 'V' : 'D', + VIDC_NAME, fb_info.var.xres, fb_info.var.yres, + h_sync / 1000, h_sync % 1000, v_sync); + + printk(KERN_INFO "Acornfb: Monitor: %d.%03d-%d.%03dkHz, %d-%dHz%s\n", + fb_info.monspecs.hfmin / 1000, fb_info.monspecs.hfmin % 1000, + fb_info.monspecs.hfmax / 1000, fb_info.monspecs.hfmax % 1000, + fb_info.monspecs.vfmin, fb_info.monspecs.vfmax, + fb_info.monspecs.dpms ? ", DPMS" : ""); + + if (fb_set_var(&fb_info, &fb_info.var)) + printk(KERN_ERR "Acornfb: unable to set display parameters\n"); + + if (register_framebuffer(&fb_info) < 0) + return -EINVAL; + return 0; +} + +static struct device_driver acornfb_driver = { + .name = "acornfb", + .bus = &platform_bus_type, + .probe = acornfb_probe, +}; + +static int __init acornfb_init(void) +{ + return driver_register(&acornfb_driver); +} + +module_init(acornfb_init); + +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/acornfb.h b/drivers/video/acornfb.h new file mode 100644 index 000000000000..fb2a7fffe506 --- /dev/null +++ b/drivers/video/acornfb.h @@ -0,0 +1,198 @@ +/* + * linux/drivers/video/acornfb.h + * + * Copyright (C) 1998,1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Frame buffer code for Acorn platforms + */ +#if defined(HAS_VIDC20) +#include <asm/hardware/iomd.h> +#define VIDC_PALETTE_SIZE 256 +#define VIDC_NAME "VIDC20" +#elif defined(HAS_VIDC) +#include <asm/hardware/memc.h> +#define VIDC_PALETTE_SIZE 16 +#define VIDC_NAME "VIDC" +#endif + +#define EXTEND8(x) ((x)|(x)<<8) +#define EXTEND4(x) ((x)|(x)<<4|(x)<<8|(x)<<12) + +struct vidc20_palette { + u_int red:8; + u_int green:8; + u_int blue:8; + u_int ext:4; + u_int unused:4; +}; + +struct vidc_palette { + u_int red:4; + u_int green:4; + u_int blue:4; + u_int trans:1; + u_int sbz1:13; + u_int reg:4; + u_int sbz2:2; +}; + +union palette { + struct vidc20_palette vidc20; + struct vidc_palette vidc; + u_int p; +}; + +struct acornfb_par { + struct device *dev; + unsigned long screen_end; + unsigned int dram_size; + unsigned int vram_half_sam; + unsigned int palette_size; + signed int montype; + unsigned int using_vram : 1; + unsigned int dpms : 1; + + union palette palette[VIDC_PALETTE_SIZE]; + + u32 pseudo_palette[16]; +}; + +struct vidc_timing { + u_int h_cycle; + u_int h_sync_width; + u_int h_border_start; + u_int h_display_start; + u_int h_display_end; + u_int h_border_end; + u_int h_interlace; + + u_int v_cycle; + u_int v_sync_width; + u_int v_border_start; + u_int v_display_start; + u_int v_display_end; + u_int v_border_end; + + u_int control; + + /* VIDC20 only */ + u_int pll_ctl; +}; + +struct modey_params { + u_int y_res; + u_int u_margin; + u_int b_margin; + u_int vsync_len; + u_int vf; +}; + +struct modex_params { + u_int x_res; + u_int l_margin; + u_int r_margin; + u_int hsync_len; + u_int clock; + u_int hf; + const struct modey_params *modey; +}; + +#ifdef HAS_VIDC + +#define VID_CTL_VS_NVSYNC (1 << 3) +#define VID_CTL_HS_NHSYNC (1 << 2) +#define VID_CTL_24MHz (0) +#define VID_CTL_25MHz (1) +#define VID_CTL_36MHz (2) + +#define VIDC_CTRL_CSYNC (1 << 7) +#define VIDC_CTRL_INTERLACE (1 << 6) +#define VIDC_CTRL_FIFO_0_4 (0 << 4) +#define VIDC_CTRL_FIFO_1_5 (1 << 4) +#define VIDC_CTRL_FIFO_2_6 (2 << 4) +#define VIDC_CTRL_FIFO_3_7 (3 << 4) +#define VIDC_CTRL_1BPP (0 << 2) +#define VIDC_CTRL_2BPP (1 << 2) +#define VIDC_CTRL_4BPP (2 << 2) +#define VIDC_CTRL_8BPP (3 << 2) +#define VIDC_CTRL_DIV3 (0 << 0) +#define VIDC_CTRL_DIV2 (1 << 0) +#define VIDC_CTRL_DIV1_5 (2 << 0) +#define VIDC_CTRL_DIV1 (3 << 0) + +#endif + +#ifdef HAS_VIDC20 +/* + * VIDC20 registers + */ +#define VIDC20_CTRL 0xe0000000 +#define VIDC20_CTRL_PIX_VCLK (0 << 0) +#define VIDC20_CTRL_PIX_HCLK (1 << 0) +#define VIDC20_CTRL_PIX_RCLK (2 << 0) +#define VIDC20_CTRL_PIX_CK (0 << 2) +#define VIDC20_CTRL_PIX_CK2 (1 << 2) +#define VIDC20_CTRL_PIX_CK3 (2 << 2) +#define VIDC20_CTRL_PIX_CK4 (3 << 2) +#define VIDC20_CTRL_PIX_CK5 (4 << 2) +#define VIDC20_CTRL_PIX_CK6 (5 << 2) +#define VIDC20_CTRL_PIX_CK7 (6 << 2) +#define VIDC20_CTRL_PIX_CK8 (7 << 2) +#define VIDC20_CTRL_1BPP (0 << 5) +#define VIDC20_CTRL_2BPP (1 << 5) +#define VIDC20_CTRL_4BPP (2 << 5) +#define VIDC20_CTRL_8BPP (3 << 5) +#define VIDC20_CTRL_16BPP (4 << 5) +#define VIDC20_CTRL_32BPP (6 << 5) +#define VIDC20_CTRL_FIFO_NS (0 << 8) +#define VIDC20_CTRL_FIFO_4 (1 << 8) +#define VIDC20_CTRL_FIFO_8 (2 << 8) +#define VIDC20_CTRL_FIFO_12 (3 << 8) +#define VIDC20_CTRL_FIFO_16 (4 << 8) +#define VIDC20_CTRL_FIFO_20 (5 << 8) +#define VIDC20_CTRL_FIFO_24 (6 << 8) +#define VIDC20_CTRL_FIFO_28 (7 << 8) +#define VIDC20_CTRL_INT (1 << 12) +#define VIDC20_CTRL_DUP (1 << 13) +#define VIDC20_CTRL_PDOWN (1 << 14) + +#define VIDC20_ECTL 0xc0000000 +#define VIDC20_ECTL_REG(x) ((x) & 0xf3) +#define VIDC20_ECTL_ECK (1 << 2) +#define VIDC20_ECTL_REDPED (1 << 8) +#define VIDC20_ECTL_GREENPED (1 << 9) +#define VIDC20_ECTL_BLUEPED (1 << 10) +#define VIDC20_ECTL_DAC (1 << 12) +#define VIDC20_ECTL_LCDGS (1 << 13) +#define VIDC20_ECTL_HRM (1 << 14) + +#define VIDC20_ECTL_HS_MASK (3 << 16) +#define VIDC20_ECTL_HS_HSYNC (0 << 16) +#define VIDC20_ECTL_HS_NHSYNC (1 << 16) +#define VIDC20_ECTL_HS_CSYNC (2 << 16) +#define VIDC20_ECTL_HS_NCSYNC (3 << 16) + +#define VIDC20_ECTL_VS_MASK (3 << 18) +#define VIDC20_ECTL_VS_VSYNC (0 << 18) +#define VIDC20_ECTL_VS_NVSYNC (1 << 18) +#define VIDC20_ECTL_VS_CSYNC (2 << 18) +#define VIDC20_ECTL_VS_NCSYNC (3 << 18) + +#define VIDC20_DCTL 0xf0000000 +/* 0-9 = number of words in scanline */ +#define VIDC20_DCTL_SNA (1 << 12) +#define VIDC20_DCTL_HDIS (1 << 13) +#define VIDC20_DCTL_BUS_NS (0 << 16) +#define VIDC20_DCTL_BUS_D31_0 (1 << 16) +#define VIDC20_DCTL_BUS_D63_32 (2 << 16) +#define VIDC20_DCTL_BUS_D63_0 (3 << 16) +#define VIDC20_DCTL_VRAM_DIS (0 << 18) +#define VIDC20_DCTL_VRAM_PXCLK (1 << 18) +#define VIDC20_DCTL_VRAM_PXCLK2 (2 << 18) +#define VIDC20_DCTL_VRAM_PXCLK4 (3 << 18) + +#endif diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c new file mode 100644 index 000000000000..acdba0c67fb8 --- /dev/null +++ b/drivers/video/amba-clcd.c @@ -0,0 +1,533 @@ +/* + * linux/drivers/video/amba-clcd.c + * + * Copyright (C) 2001 ARM Limited, by David A Rusling + * Updated to 2.5, Deep Blue Solutions Ltd. + * + * 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. + * + * ARM PrimeCell PL110 Color LCD Controller + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/list.h> + +#include <asm/hardware/amba.h> +#include <asm/hardware/clock.h> + +#include <asm/hardware/amba_clcd.h> + +#define to_clcd(info) container_of(info, struct clcd_fb, fb) + +/* This is limited to 16 characters when displayed by X startup */ +static const char *clcd_name = "CLCD FB"; + +/* + * Unfortunately, the enable/disable functions may be called either from + * process or IRQ context, and we _need_ to delay. This is _not_ good. + */ +static inline void clcdfb_sleep(unsigned int ms) +{ + if (in_atomic()) { + mdelay(ms); + } else { + msleep(ms); + } +} + +static inline void clcdfb_set_start(struct clcd_fb *fb) +{ + unsigned long ustart = fb->fb.fix.smem_start; + unsigned long lstart; + + ustart += fb->fb.var.yoffset * fb->fb.fix.line_length; + lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2; + + writel(ustart, fb->regs + CLCD_UBAS); + writel(lstart, fb->regs + CLCD_LBAS); +} + +static void clcdfb_disable(struct clcd_fb *fb) +{ + u32 val; + + if (fb->board->disable) + fb->board->disable(fb); + + val = readl(fb->regs + CLCD_CNTL); + if (val & CNTL_LCDPWR) { + val &= ~CNTL_LCDPWR; + writel(val, fb->regs + CLCD_CNTL); + + clcdfb_sleep(20); + } + if (val & CNTL_LCDEN) { + val &= ~CNTL_LCDEN; + writel(val, fb->regs + CLCD_CNTL); + } + + /* + * Disable CLCD clock source. + */ + clk_disable(fb->clk); +} + +static void clcdfb_enable(struct clcd_fb *fb, u32 cntl) +{ + /* + * Enable the CLCD clock source. + */ + clk_enable(fb->clk); + + /* + * Bring up by first enabling.. + */ + cntl |= CNTL_LCDEN; + writel(cntl, fb->regs + CLCD_CNTL); + + clcdfb_sleep(20); + + /* + * and now apply power. + */ + cntl |= CNTL_LCDPWR; + writel(cntl, fb->regs + CLCD_CNTL); + + /* + * finally, enable the interface. + */ + if (fb->board->enable) + fb->board->enable(fb); +} + +static int +clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) +{ + int ret = 0; + + memset(&var->transp, 0, sizeof(var->transp)); + memset(&var->red, 0, sizeof(var->red)); + memset(&var->green, 0, sizeof(var->green)); + memset(&var->blue, 0, sizeof(var->blue)); + + switch (var->bits_per_pixel) { + case 1: + case 2: + case 4: + case 8: + var->red.length = 8; + var->red.offset = 0; + var->green.length = 8; + var->green.offset = 0; + var->blue.length = 8; + var->blue.offset = 0; + break; + case 16: + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + if (fb->panel->cntl & CNTL_BGR) { + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + } else { + var->red.offset = 0; + var->green.offset = 5; + var->blue.offset = 10; + } + break; + case 24: + if (fb->panel->cntl & CNTL_LCDTFT) { + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + + if (fb->panel->cntl & CNTL_BGR) { + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + } else { + var->red.offset = 0; + var->green.offset = 8; + var->blue.offset = 16; + } + break; + } + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct clcd_fb *fb = to_clcd(info); + int ret = -EINVAL; + + if (fb->board->check) + ret = fb->board->check(fb, var); + if (ret == 0) + ret = clcdfb_set_bitfields(fb, var); + + return ret; +} + +static int clcdfb_set_par(struct fb_info *info) +{ + struct clcd_fb *fb = to_clcd(info); + struct clcd_regs regs; + + fb->fb.fix.line_length = fb->fb.var.xres_virtual * + fb->fb.var.bits_per_pixel / 8; + + if (fb->fb.var.bits_per_pixel <= 8) + fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; + else + fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; + + fb->board->decode(fb, ®s); + + clcdfb_disable(fb); + + writel(regs.tim0, fb->regs + CLCD_TIM0); + writel(regs.tim1, fb->regs + CLCD_TIM1); + writel(regs.tim2, fb->regs + CLCD_TIM2); + writel(regs.tim3, fb->regs + CLCD_TIM3); + + clcdfb_set_start(fb); + + clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000); + + fb->clcd_cntl = regs.cntl; + + clcdfb_enable(fb, regs.cntl); + +#ifdef DEBUG + printk(KERN_INFO "CLCD: Registers set to\n" + KERN_INFO " %08x %08x %08x %08x\n" + KERN_INFO " %08x %08x %08x %08x\n", + readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1), + readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3), + readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS), + readl(fb->regs + CLCD_IENB), readl(fb->regs + CLCD_CNTL)); +#endif + + return 0; +} + +static inline u32 convert_bitfield(int val, struct fb_bitfield *bf) +{ + unsigned int mask = (1 << bf->length) - 1; + + return (val >> (16 - bf->length) & mask) << bf->offset; +} + +/* + * Set a single color register. The values supplied have a 16 bit + * magnitude. Return != 0 for invalid regno. + */ +static int +clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, + unsigned int blue, unsigned int transp, struct fb_info *info) +{ + struct clcd_fb *fb = to_clcd(info); + + if (regno < 16) + fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) | + convert_bitfield(blue, &fb->fb.var.blue) | + convert_bitfield(green, &fb->fb.var.green) | + convert_bitfield(red, &fb->fb.var.red); + + if (fb->fb.var.bits_per_pixel == 8 && regno < 256) { + int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3); + u32 val, mask, newval; + + newval = (red >> 11) & 0x001f; + newval |= (green >> 6) & 0x03e0; + newval |= (blue >> 1) & 0x7c00; + + /* + * 3.2.11: if we're configured for big endian + * byte order, the palette entries are swapped. + */ + if (fb->clcd_cntl & CNTL_BEBO) + regno ^= 1; + + if (regno & 1) { + newval <<= 16; + mask = 0x0000ffff; + } else { + mask = 0xffff0000; + } + + val = readl(fb->regs + hw_reg) & mask; + writel(val | newval, fb->regs + hw_reg); + } + + return regno > 255; +} + +/* + * Blank the screen if blank_mode != 0, else unblank. If blank == NULL + * then the caller blanks by setting the CLUT (Color Look Up Table) to all + * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due + * to e.g. a video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + */ +static int clcdfb_blank(int blank_mode, struct fb_info *info) +{ + struct clcd_fb *fb = to_clcd(info); + + if (blank_mode != 0) { + clcdfb_disable(fb); + } else { + clcdfb_enable(fb, fb->clcd_cntl); + } + return 0; +} + +static int clcdfb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + struct clcd_fb *fb = to_clcd(info); + unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT; + int ret = -EINVAL; + + len = info->fix.smem_len; + + if (off <= len && vma->vm_end - vma->vm_start <= len - off && + fb->board->mmap) + ret = fb->board->mmap(fb, vma); + + return ret; +} + +static struct fb_ops clcdfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = clcdfb_check_var, + .fb_set_par = clcdfb_set_par, + .fb_setcolreg = clcdfb_setcolreg, + .fb_blank = clcdfb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + .fb_mmap = clcdfb_mmap, +}; + +static int clcdfb_register(struct clcd_fb *fb) +{ + int ret; + + fb->clk = clk_get(&fb->dev->dev, "CLCDCLK"); + if (IS_ERR(fb->clk)) { + ret = PTR_ERR(fb->clk); + goto out; + } + + ret = clk_use(fb->clk); + if (ret) + goto free_clk; + + fb->fb.fix.mmio_start = fb->dev->res.start; + fb->fb.fix.mmio_len = SZ_4K; + + fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len); + if (!fb->regs) { + printk(KERN_ERR "CLCD: unable to remap registers\n"); + ret = -ENOMEM; + goto unuse_clk; + } + + fb->fb.fbops = &clcdfb_ops; + fb->fb.flags = FBINFO_FLAG_DEFAULT; + fb->fb.pseudo_palette = fb->cmap; + + strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id)); + fb->fb.fix.type = FB_TYPE_PACKED_PIXELS; + fb->fb.fix.type_aux = 0; + fb->fb.fix.xpanstep = 0; + fb->fb.fix.ypanstep = 0; + fb->fb.fix.ywrapstep = 0; + fb->fb.fix.accel = FB_ACCEL_NONE; + + fb->fb.var.xres = fb->panel->mode.xres; + fb->fb.var.yres = fb->panel->mode.yres; + fb->fb.var.xres_virtual = fb->panel->mode.xres; + fb->fb.var.yres_virtual = fb->panel->mode.yres; + fb->fb.var.bits_per_pixel = fb->panel->bpp; + fb->fb.var.grayscale = fb->panel->grayscale; + fb->fb.var.pixclock = fb->panel->mode.pixclock; + fb->fb.var.left_margin = fb->panel->mode.left_margin; + fb->fb.var.right_margin = fb->panel->mode.right_margin; + fb->fb.var.upper_margin = fb->panel->mode.upper_margin; + fb->fb.var.lower_margin = fb->panel->mode.lower_margin; + fb->fb.var.hsync_len = fb->panel->mode.hsync_len; + fb->fb.var.vsync_len = fb->panel->mode.vsync_len; + fb->fb.var.sync = fb->panel->mode.sync; + fb->fb.var.vmode = fb->panel->mode.vmode; + fb->fb.var.activate = FB_ACTIVATE_NOW; + fb->fb.var.nonstd = 0; + fb->fb.var.height = fb->panel->height; + fb->fb.var.width = fb->panel->width; + fb->fb.var.accel_flags = 0; + + fb->fb.monspecs.hfmin = 0; + fb->fb.monspecs.hfmax = 100000; + fb->fb.monspecs.vfmin = 0; + fb->fb.monspecs.vfmax = 400; + fb->fb.monspecs.dclkmin = 1000000; + fb->fb.monspecs.dclkmax = 100000000; + + /* + * Make sure that the bitfields are set appropriately. + */ + clcdfb_set_bitfields(fb, &fb->fb.var); + + /* + * Allocate colourmap. + */ + fb_alloc_cmap(&fb->fb.cmap, 256, 0); + + /* + * Ensure interrupts are disabled. + */ + writel(0, fb->regs + CLCD_IENB); + + fb_set_var(&fb->fb, &fb->fb.var); + + printk(KERN_INFO "CLCD: %s hardware, %s display\n", + fb->board->name, fb->panel->mode.name); + + ret = register_framebuffer(&fb->fb); + if (ret == 0) + goto out; + + printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret); + + iounmap(fb->regs); + unuse_clk: + clk_unuse(fb->clk); + free_clk: + clk_put(fb->clk); + out: + return ret; +} + +static int clcdfb_probe(struct amba_device *dev, void *id) +{ + struct clcd_board *board = dev->dev.platform_data; + struct clcd_fb *fb; + int ret; + + if (!board) + return -EINVAL; + + ret = amba_request_regions(dev, NULL); + if (ret) { + printk(KERN_ERR "CLCD: unable to reserve regs region\n"); + goto out; + } + + fb = (struct clcd_fb *) kmalloc(sizeof(struct clcd_fb), GFP_KERNEL); + if (!fb) { + printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n"); + ret = -ENOMEM; + goto free_region; + } + memset(fb, 0, sizeof(struct clcd_fb)); + + fb->dev = dev; + fb->board = board; + + ret = fb->board->setup(fb); + if (ret) + goto free_fb; + + ret = clcdfb_register(fb); + if (ret == 0) { + amba_set_drvdata(dev, fb); + goto out; + } + + fb->board->remove(fb); + free_fb: + kfree(fb); + free_region: + amba_release_regions(dev); + out: + return ret; +} + +static int clcdfb_remove(struct amba_device *dev) +{ + struct clcd_fb *fb = amba_get_drvdata(dev); + + amba_set_drvdata(dev, NULL); + + clcdfb_disable(fb); + unregister_framebuffer(&fb->fb); + iounmap(fb->regs); + clk_unuse(fb->clk); + clk_put(fb->clk); + + fb->board->remove(fb); + + kfree(fb); + + amba_release_regions(dev); + + return 0; +} + +static struct amba_id clcdfb_id_table[] = { + { + .id = 0x00041110, + .mask = 0x000fffff, + }, + { 0, 0 }, +}; + +static struct amba_driver clcd_driver = { + .drv = { + .name = "clcd-pl110", + }, + .probe = clcdfb_probe, + .remove = clcdfb_remove, + .id_table = clcdfb_id_table, +}; + +int __init amba_clcdfb_init(void) +{ + if (fb_get_options("ambafb", NULL)) + return -ENODEV; + + return amba_driver_register(&clcd_driver); +} + +module_init(amba_clcdfb_init); + +static void __exit amba_clcdfb_exit(void) +{ + amba_driver_unregister(&clcd_driver); +} + +module_exit(amba_clcdfb_exit); + +MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c new file mode 100644 index 000000000000..cf8bb67462dc --- /dev/null +++ b/drivers/video/amifb.c @@ -0,0 +1,3812 @@ +/* + * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device + * + * Copyright (C) 1995-2003 Geert Uytterhoeven + * + * with work by Roman Zippel + * + * + * This file is based on the Atari frame buffer device (atafb.c): + * + * Copyright (C) 1994 Martin Schaller + * Roman Hodek + * + * with work by Andreas Schwab + * Guenther Kelleter + * + * and on the original Amiga console driver (amicon.c): + * + * Copyright (C) 1993 Hamish Macdonald + * Greg Harp + * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] + * + * with work by William Rucklidge (wjr@cs.cornell.edu) + * Geert Uytterhoeven + * Jes Sorensen (jds@kom.auc.dk) + * + * + * History: + * + * - 24 Jul 96: Copper generates now vblank interrupt and + * VESA Power Saving Protocol is fully implemented + * - 14 Jul 96: Rework and hopefully last ECS bugs fixed + * - 7 Mar 96: Hardware sprite support by Roman Zippel + * - 18 Feb 96: OCS and ECS support by Roman Zippel + * Hardware functions completely rewritten + * - 2 Dec 95: AGA version 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. + */ + +#include <linux/module.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/delay.h> +#include <linux/config.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/ioport.h> + +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/amigahw.h> +#include <asm/amigaints.h> +#include <asm/setup.h> + +#include "c2p.h" + + +#define DEBUG + +#if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA) +#define CONFIG_FB_AMIGA_OCS /* define at least one fb driver, this will change later */ +#endif + +#if !defined(CONFIG_FB_AMIGA_OCS) +# define IS_OCS (0) +#elif defined(CONFIG_FB_AMIGA_ECS) || defined(CONFIG_FB_AMIGA_AGA) +# define IS_OCS (chipset == TAG_OCS) +#else +# define CONFIG_FB_AMIGA_OCS_ONLY +# define IS_OCS (1) +#endif + +#if !defined(CONFIG_FB_AMIGA_ECS) +# define IS_ECS (0) +#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_AGA) +# define IS_ECS (chipset == TAG_ECS) +#else +# define CONFIG_FB_AMIGA_ECS_ONLY +# define IS_ECS (1) +#endif + +#if !defined(CONFIG_FB_AMIGA_AGA) +# define IS_AGA (0) +#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_ECS) +# define IS_AGA (chipset == TAG_AGA) +#else +# define CONFIG_FB_AMIGA_AGA_ONLY +# define IS_AGA (1) +#endif + +#ifdef DEBUG +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + +/******************************************************************************* + + + Generic video timings + --------------------- + + Timings used by the frame buffer interface: + + +----------+---------------------------------------------+----------+-------+ + | | ^ | | | + | | |upper_margin | | | + | | | | | + +----------###############################################----------+-------+ + | # ^ # | | + | # | # | | + | # | # | | + | # | # | | + | left # | # right | hsync | + | margin # | xres # margin | len | + |<-------->#<---------------+--------------------------->#<-------->|<----->| + | # | # | | + | # | # | | + | # | # | | + | # |yres # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # # | | + +----------###############################################----------+-------+ + | | ^ | | | + | | |lower_margin | | | + | | | | | + +----------+---------------------------------------------+----------+-------+ + | | ^ | | | + | | |vsync_len | | | + | | | | | + +----------+---------------------------------------------+----------+-------+ + + + Amiga video timings + ------------------- + + The Amiga native chipsets uses another timing scheme: + + - hsstrt: Start of horizontal synchronization pulse + - hsstop: End of horizontal synchronization pulse + - htotal: Last value on the line (i.e. line length = htotal+1) + - vsstrt: Start of vertical synchronization pulse + - vsstop: End of vertical synchronization pulse + - vtotal: Last line value (i.e. number of lines = vtotal+1) + - hcenter: Start of vertical retrace for interlace + + You can specify the blanking timings independently. Currently I just set + them equal to the respective synchronization values: + + - hbstrt: Start of horizontal blank + - hbstop: End of horizontal blank + - vbstrt: Start of vertical blank + - vbstop: End of vertical blank + + Horizontal values are in color clock cycles (280 ns), vertical values are in + scanlines. + + (0, 0) is somewhere in the upper-left corner :-) + + + Amiga visible window definitions + -------------------------------- + + Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to + make corrections and/or additions. + + Within the above synchronization specifications, the visible window is + defined by the following parameters (actual register resolutions may be + different; all horizontal values are normalized with respect to the pixel + clock): + + - diwstrt_h: Horizontal start of the visible window + - diwstop_h: Horizontal stop+1(*) of the visible window + - diwstrt_v: Vertical start of the visible window + - diwstop_v: Vertical stop of the visible window + - ddfstrt: Horizontal start of display DMA + - ddfstop: Horizontal stop of display DMA + - hscroll: Horizontal display output delay + + Sprite positioning: + + - sprstrt_h: Horizontal start-4 of sprite + - sprstrt_v: Vertical start of sprite + + (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1. + + Horizontal values are in dotclock cycles (35 ns), vertical values are in + scanlines. + + (0, 0) is somewhere in the upper-left corner :-) + + + Dependencies (AGA, SHRES (35 ns dotclock)) + ------------------------------------------- + + Since there are much more parameters for the Amiga display than for the + frame buffer interface, there must be some dependencies among the Amiga + display parameters. Here's what I found out: + + - ddfstrt and ddfstop are best aligned to 64 pixels. + - the chipset needs 64+4 horizontal pixels after the DMA start before the + first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to + display the first pixel on the line too. Increase diwstrt_h for virtual + screen panning. + - the display DMA always fetches 64 pixels at a time (fmode = 3). + - ddfstop is ddfstrt+#pixels-64. + - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1 + more than htotal. + - hscroll simply adds a delay to the display output. Smooth horizontal + panning needs an extra 64 pixels on the left to prefetch the pixels that + `fall off' on the left. + - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane + DMA, so it's best to make the DMA start as late as possible. + - you really don't want to make ddfstrt < 128, since this will steal DMA + cycles from the other DMA channels (audio, floppy and Chip RAM refresh). + - I make diwstop_h and diwstop_v as large as possible. + + General dependencies + -------------------- + + - all values are SHRES pixel (35ns) + + table 1:fetchstart table 2:prefetch table 3:fetchsize + ------------------ ---------------- ----------------- + Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES + -------------#------+-----+------#------+-----+------#------+-----+------ + Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64 + Bus width 2x # 32 | 64 | 128 # 32 | 64 | 64 # 64 | 64 | 128 + Bus width 4x # 64 | 128 | 256 # 64 | 64 | 64 # 64 | 128 | 256 + + - chipset needs 4 pixels before the first pixel is output + - ddfstrt must be aligned to fetchstart (table 1) + - chipset needs also prefetch (table 2) to get first pixel data, so + ddfstrt = ((diwstrt_h-4) & -fetchstart) - prefetch + - for horizontal panning decrease diwstrt_h + - the length of a fetchline must be aligned to fetchsize (table 3) + - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit + moved to optimize use of dma (useful for OCS/ECS overscan displays) + - ddfstop is ddfstrt+ddfsize-fetchsize + - If C= didn't change anything for AGA, then at following positions the + dma bus is already used: + ddfstrt < 48 -> memory refresh + < 96 -> disk dma + < 160 -> audio dma + < 192 -> sprite 0 dma + < 416 -> sprite dma (32 per sprite) + - in accordance with the hardware reference manual a hardware stop is at + 192, but AGA (ECS?) can go below this. + + DMA priorities + -------------- + + Since there are limits on the earliest start value for display DMA and the + display of sprites, I use the following policy on horizontal panning and + the hardware cursor: + + - if you want to start display DMA too early, you lose the ability to + do smooth horizontal panning (xpanstep 1 -> 64). + - if you want to go even further, you lose the hardware cursor too. + + IMHO a hardware cursor is more important for X than horizontal scrolling, + so that's my motivation. + + + Implementation + -------------- + + ami_decode_var() converts the frame buffer values to the Amiga values. It's + just a `straightforward' implementation of the above rules. + + + Standard VGA timings + -------------------- + + xres yres left right upper lower hsync vsync + ---- ---- ---- ----- ----- ----- ----- ----- + 80x25 720 400 27 45 35 12 108 2 + 80x30 720 480 27 45 30 9 108 2 + + These were taken from a XFree86 configuration file, recalculated for a 28 MHz + dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer + generic timings. + + As a comparison, graphics/monitor.h suggests the following: + + xres yres left right upper lower hsync vsync + ---- ---- ---- ----- ----- ----- ----- ----- + + VGA 640 480 52 112 24 19 112 - 2 + + VGA70 640 400 52 112 27 21 112 - 2 - + + + Sync polarities + --------------- + + VSYNC HSYNC Vertical size Vertical total + ----- ----- ------------- -------------- + + + Reserved Reserved + + - 400 414 + - + 350 362 + - - 480 496 + + Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992 + + + Broadcast video timings + ----------------------- + + According to the CCIR and RETMA specifications, we have the following values: + + CCIR -> PAL + ----------- + + - a scanline is 64 s long, of which 52.48 s are visible. This is about + 736 visible 70 ns pixels per line. + - we have 625 scanlines, of which 575 are visible (interlaced); after + rounding this becomes 576. + + RETMA -> NTSC + ------------- + + - a scanline is 63.5 s long, of which 53.5 s are visible. This is about + 736 visible 70 ns pixels per line. + - we have 525 scanlines, of which 485 are visible (interlaced); after + rounding this becomes 484. + + Thus if you want a PAL compatible display, you have to do the following: + + - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast + timings are to be used. + - make sure upper_margin+yres+lower_margin+vsync_len = 625 for an + interlaced, 312 for a non-interlaced and 156 for a doublescanned + display. + - make sure left_margin+xres+right_margin+hsync_len = 1816 for a SHRES, + 908 for a HIRES and 454 for a LORES display. + - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90), + left_margin+2*hsync_len must be greater or equal. + - the upper visible part begins at 48 (interlaced; non-interlaced:24, + doublescanned:12), upper_margin+2*vsync_len must be greater or equal. + - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync + of 4 scanlines + + The settings for a NTSC compatible display are straightforward. + + Note that in a strict sense the PAL and NTSC standards only define the + encoding of the color part (chrominance) of the video signal and don't say + anything about horizontal/vertical synchronization nor refresh rates. + + + -- Geert -- + +*******************************************************************************/ + + + /* + * Custom Chipset Definitions + */ + +#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld) + + /* + * BPLCON0 -- Bitplane Control Register 0 + */ + +#define BPC0_HIRES (0x8000) +#define BPC0_BPU2 (0x4000) /* Bit plane used count */ +#define BPC0_BPU1 (0x2000) +#define BPC0_BPU0 (0x1000) +#define BPC0_HAM (0x0800) /* HAM mode */ +#define BPC0_DPF (0x0400) /* Double playfield */ +#define BPC0_COLOR (0x0200) /* Enable colorburst */ +#define BPC0_GAUD (0x0100) /* Genlock audio enable */ +#define BPC0_UHRES (0x0080) /* Ultrahi res enable */ +#define BPC0_SHRES (0x0040) /* Super hi res mode */ +#define BPC0_BYPASS (0x0020) /* Bypass LUT - AGA */ +#define BPC0_BPU3 (0x0010) /* AGA */ +#define BPC0_LPEN (0x0008) /* Light pen enable */ +#define BPC0_LACE (0x0004) /* Interlace */ +#define BPC0_ERSY (0x0002) /* External resync */ +#define BPC0_ECSENA (0x0001) /* ECS enable */ + + /* + * BPLCON2 -- Bitplane Control Register 2 + */ + +#define BPC2_ZDBPSEL2 (0x4000) /* Bitplane to be used for ZD - AGA */ +#define BPC2_ZDBPSEL1 (0x2000) +#define BPC2_ZDBPSEL0 (0x1000) +#define BPC2_ZDBPEN (0x0800) /* Enable ZD with ZDBPSELx - AGA */ +#define BPC2_ZDCTEN (0x0400) /* Enable ZD with palette bit #31 - AGA */ +#define BPC2_KILLEHB (0x0200) /* Kill EHB mode - AGA */ +#define BPC2_RDRAM (0x0100) /* Color table accesses read, not write - AGA */ +#define BPC2_SOGEN (0x0080) /* SOG output pin high - AGA */ +#define BPC2_PF2PRI (0x0040) /* PF2 priority over PF1 */ +#define BPC2_PF2P2 (0x0020) /* PF2 priority wrt sprites */ +#define BPC2_PF2P1 (0x0010) +#define BPC2_PF2P0 (0x0008) +#define BPC2_PF1P2 (0x0004) /* ditto PF1 */ +#define BPC2_PF1P1 (0x0002) +#define BPC2_PF1P0 (0x0001) + + /* + * BPLCON3 -- Bitplane Control Register 3 (AGA) + */ + +#define BPC3_BANK2 (0x8000) /* Bits to select color register bank */ +#define BPC3_BANK1 (0x4000) +#define BPC3_BANK0 (0x2000) +#define BPC3_PF2OF2 (0x1000) /* Bits for color table offset when PF2 */ +#define BPC3_PF2OF1 (0x0800) +#define BPC3_PF2OF0 (0x0400) +#define BPC3_LOCT (0x0200) /* Color register writes go to low bits */ +#define BPC3_SPRES1 (0x0080) /* Sprite resolution bits */ +#define BPC3_SPRES0 (0x0040) +#define BPC3_BRDRBLNK (0x0020) /* Border blanked? */ +#define BPC3_BRDRTRAN (0x0010) /* Border transparent? */ +#define BPC3_ZDCLKEN (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */ +#define BPC3_BRDRSPRT (0x0002) /* Sprites in border? */ +#define BPC3_EXTBLKEN (0x0001) /* BLANK programmable */ + + /* + * BPLCON4 -- Bitplane Control Register 4 (AGA) + */ + +#define BPC4_BPLAM7 (0x8000) /* bitplane color XOR field */ +#define BPC4_BPLAM6 (0x4000) +#define BPC4_BPLAM5 (0x2000) +#define BPC4_BPLAM4 (0x1000) +#define BPC4_BPLAM3 (0x0800) +#define BPC4_BPLAM2 (0x0400) +#define BPC4_BPLAM1 (0x0200) +#define BPC4_BPLAM0 (0x0100) +#define BPC4_ESPRM7 (0x0080) /* 4 high bits for even sprite colors */ +#define BPC4_ESPRM6 (0x0040) +#define BPC4_ESPRM5 (0x0020) +#define BPC4_ESPRM4 (0x0010) +#define BPC4_OSPRM7 (0x0008) /* 4 high bits for odd sprite colors */ +#define BPC4_OSPRM6 (0x0004) +#define BPC4_OSPRM5 (0x0002) +#define BPC4_OSPRM4 (0x0001) + + /* + * BEAMCON0 -- Beam Control Register + */ + +#define BMC0_HARDDIS (0x4000) /* Disable hardware limits */ +#define BMC0_LPENDIS (0x2000) /* Disable light pen latch */ +#define BMC0_VARVBEN (0x1000) /* Enable variable vertical blank */ +#define BMC0_LOLDIS (0x0800) /* Disable long/short line toggle */ +#define BMC0_CSCBEN (0x0400) /* Composite sync/blank */ +#define BMC0_VARVSYEN (0x0200) /* Enable variable vertical sync */ +#define BMC0_VARHSYEN (0x0100) /* Enable variable horizontal sync */ +#define BMC0_VARBEAMEN (0x0080) /* Enable variable beam counters */ +#define BMC0_DUAL (0x0040) /* Enable alternate horizontal beam counter */ +#define BMC0_PAL (0x0020) /* Set decodes for PAL */ +#define BMC0_VARCSYEN (0x0010) /* Enable variable composite sync */ +#define BMC0_BLANKEN (0x0008) /* Blank enable (no longer used on AGA) */ +#define BMC0_CSYTRUE (0x0004) /* CSY polarity */ +#define BMC0_VSYTRUE (0x0002) /* VSY polarity */ +#define BMC0_HSYTRUE (0x0001) /* HSY polarity */ + + + /* + * FMODE -- Fetch Mode Control Register (AGA) + */ + +#define FMODE_SSCAN2 (0x8000) /* Sprite scan-doubling */ +#define FMODE_BSCAN2 (0x4000) /* Use PF2 modulus every other line */ +#define FMODE_SPAGEM (0x0008) /* Sprite page mode */ +#define FMODE_SPR32 (0x0004) /* Sprite 32 bit fetch */ +#define FMODE_BPAGEM (0x0002) /* Bitplane page mode */ +#define FMODE_BPL32 (0x0001) /* Bitplane 32 bit fetch */ + + /* + * Tags used to indicate a specific Pixel Clock + * + * clk_shift is the shift value to get the timings in 35 ns units + */ + +enum { TAG_SHRES, TAG_HIRES, TAG_LORES }; + + /* + * Tags used to indicate the specific chipset + */ + +enum { TAG_OCS, TAG_ECS, TAG_AGA }; + + /* + * Tags used to indicate the memory bandwidth + */ + +enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 }; + + + /* + * Clock Definitions, Maximum Display Depth + * + * These depend on the E-Clock or the Chipset, so they are filled in + * dynamically + */ + +static u_long pixclock[3]; /* SHRES/HIRES/LORES: index = clk_shift */ +static u_short maxdepth[3]; /* SHRES/HIRES/LORES: index = clk_shift */ +static u_short maxfmode, chipset; + + + /* + * Broadcast Video Timings + * + * Horizontal values are in 35 ns (SHRES) units + * Vertical values are in interlaced scanlines + */ + +#define PAL_DIWSTRT_H (360) /* PAL Window Limits */ +#define PAL_DIWSTRT_V (48) +#define PAL_HTOTAL (1816) +#define PAL_VTOTAL (625) + +#define NTSC_DIWSTRT_H (360) /* NTSC Window Limits */ +#define NTSC_DIWSTRT_V (40) +#define NTSC_HTOTAL (1816) +#define NTSC_VTOTAL (525) + + + /* + * Various macros + */ + +#define up2(v) (((v)+1) & -2) +#define down2(v) ((v) & -2) +#define div2(v) ((v)>>1) +#define mod2(v) ((v) & 1) + +#define up4(v) (((v)+3) & -4) +#define down4(v) ((v) & -4) +#define mul4(v) ((v)<<2) +#define div4(v) ((v)>>2) +#define mod4(v) ((v) & 3) + +#define up8(v) (((v)+7) & -8) +#define down8(v) ((v) & -8) +#define div8(v) ((v)>>3) +#define mod8(v) ((v) & 7) + +#define up16(v) (((v)+15) & -16) +#define down16(v) ((v) & -16) +#define div16(v) ((v)>>4) +#define mod16(v) ((v) & 15) + +#define up32(v) (((v)+31) & -32) +#define down32(v) ((v) & -32) +#define div32(v) ((v)>>5) +#define mod32(v) ((v) & 31) + +#define up64(v) (((v)+63) & -64) +#define down64(v) ((v) & -64) +#define div64(v) ((v)>>6) +#define mod64(v) ((v) & 63) + +#define upx(x,v) (((v)+(x)-1) & -(x)) +#define downx(x,v) ((v) & -(x)) +#define modx(x,v) ((v) & ((x)-1)) + +/* if x1 is not a constant, this macro won't make real sense :-) */ +#ifdef __mc68000__ +#define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \ + "d" (x2), "d" ((long)((x1)/0x100000000ULL)), "0" ((long)(x1))); res;}) +#else +/* We know a bit about the numbers, so we can do it this way */ +#define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \ + ((((long)((unsigned long long)x1 >> 8) % x2) << 8) / x2)) +#endif + +#define highw(x) ((u_long)(x)>>16 & 0xffff) +#define loww(x) ((u_long)(x) & 0xffff) + +#define VBlankOn() custom.intena = IF_SETCLR|IF_COPER +#define VBlankOff() custom.intena = IF_COPER + + + /* + * Chip RAM we reserve for the Frame Buffer + * + * This defines the Maximum Virtual Screen Size + * (Setable per kernel options?) + */ + +#define VIDEOMEMSIZE_AGA_2M (1310720) /* AGA (2MB) : max 1280*1024*256 */ +#define VIDEOMEMSIZE_AGA_1M (786432) /* AGA (1MB) : max 1024*768*256 */ +#define VIDEOMEMSIZE_ECS_2M (655360) /* ECS (2MB) : max 1280*1024*16 */ +#define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */ +#define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */ + +#define SPRITEMEMSIZE (64*64/4) /* max 64*64*4 */ +#define DUMMYSPRITEMEMSIZE (8) +static u_long spritememory; + +#define CHIPRAM_SAFETY_LIMIT (16384) + +static u_long videomemory; + + /* + * This is the earliest allowed start of fetching display data. + * Only if you really want no hardware cursor and audio, + * set this to 128, but let it better at 192 + */ + +static u_long min_fstrt = 192; + +#define assignchunk(name, type, ptr, size) \ +{ \ + (name) = (type)(ptr); \ + ptr += size; \ +} + + + /* + * Copper Instructions + */ + +#define CMOVE(val, reg) (CUSTOM_OFS(reg)<<16 | (val)) +#define CMOVE2(val, reg) ((CUSTOM_OFS(reg)+2)<<16 | (val)) +#define CWAIT(x, y) (((y) & 0x1fe)<<23 | ((x) & 0x7f0)<<13 | 0x0001fffe) +#define CEND (0xfffffffe) + + +typedef union { + u_long l; + u_short w[2]; +} copins; + +static struct copdisplay { + copins *init; + copins *wait; + copins *list[2][2]; + copins *rebuild[2]; +} copdisplay; + +static u_short currentcop = 0; + + /* + * Hardware Cursor API Definitions + * These used to be in linux/fb.h, but were preliminary and used by + * amifb only anyway + */ + +#define FBIOGET_FCURSORINFO 0x4607 +#define FBIOGET_VCURSORINFO 0x4608 +#define FBIOPUT_VCURSORINFO 0x4609 +#define FBIOGET_CURSORSTATE 0x460A +#define FBIOPUT_CURSORSTATE 0x460B + + +struct fb_fix_cursorinfo { + __u16 crsr_width; /* width and height of the cursor in */ + __u16 crsr_height; /* pixels (zero if no cursor) */ + __u16 crsr_xsize; /* cursor size in display pixels */ + __u16 crsr_ysize; + __u16 crsr_color1; /* colormap entry for cursor color1 */ + __u16 crsr_color2; /* colormap entry for cursor color2 */ +}; + +struct fb_var_cursorinfo { + __u16 width; + __u16 height; + __u16 xspot; + __u16 yspot; + __u8 data[1]; /* field with [height][width] */ +}; + +struct fb_cursorstate { + __s16 xoffset; + __s16 yoffset; + __u16 mode; +}; + +#define FB_CURSOR_OFF 0 +#define FB_CURSOR_ON 1 +#define FB_CURSOR_FLASH 2 + + + /* + * Hardware Cursor + */ + +static int cursorrate = 20; /* Number of frames/flash toggle */ +static u_short cursorstate = -1; +static u_short cursormode = FB_CURSOR_OFF; + +static u_short *lofsprite, *shfsprite, *dummysprite; + + /* + * Current Video Mode + */ + +static struct amifb_par { + + /* General Values */ + + int xres; /* vmode */ + int yres; /* vmode */ + int vxres; /* vmode */ + int vyres; /* vmode */ + int xoffset; /* vmode */ + int yoffset; /* vmode */ + u_short bpp; /* vmode */ + u_short clk_shift; /* vmode */ + u_short line_shift; /* vmode */ + int vmode; /* vmode */ + u_short diwstrt_h; /* vmode */ + u_short diwstop_h; /* vmode */ + u_short diwstrt_v; /* vmode */ + u_short diwstop_v; /* vmode */ + u_long next_line; /* modulo for next line */ + u_long next_plane; /* modulo for next plane */ + + /* Cursor Values */ + + struct { + short crsr_x; /* movecursor */ + short crsr_y; /* movecursor */ + short spot_x; + short spot_y; + u_short height; + u_short width; + u_short fmode; + } crsr; + + /* OCS Hardware Registers */ + + u_long bplpt0; /* vmode, pan (Note: physical address) */ + u_long bplpt0wrap; /* vmode, pan (Note: physical address) */ + u_short ddfstrt; + u_short ddfstop; + u_short bpl1mod; + u_short bpl2mod; + u_short bplcon0; /* vmode */ + u_short bplcon1; /* vmode */ + u_short htotal; /* vmode */ + u_short vtotal; /* vmode */ + + /* Additional ECS Hardware Registers */ + + u_short bplcon3; /* vmode */ + u_short beamcon0; /* vmode */ + u_short hsstrt; /* vmode */ + u_short hsstop; /* vmode */ + u_short hbstrt; /* vmode */ + u_short hbstop; /* vmode */ + u_short vsstrt; /* vmode */ + u_short vsstop; /* vmode */ + u_short vbstrt; /* vmode */ + u_short vbstop; /* vmode */ + u_short hcenter; /* vmode */ + + /* Additional AGA Hardware Registers */ + + u_short fmode; /* vmode */ +} currentpar; + + +static struct fb_info fb_info = { + .fix = { + .id = "Amiga ", + .visual = FB_VISUAL_PSEUDOCOLOR, + .accel = FB_ACCEL_AMIGABLITT + } +}; + + + /* + * Saved color entry 0 so we can restore it when unblanking + */ + +static u_char red0, green0, blue0; + + +#if defined(CONFIG_FB_AMIGA_ECS) +static u_short ecs_palette[32]; +#endif + + + /* + * Latches for Display Changes during VBlank + */ + +static u_short do_vmode_full = 0; /* Change the Video Mode */ +static u_short do_vmode_pan = 0; /* Update the Video Mode */ +static short do_blank = 0; /* (Un)Blank the Screen (1) */ +static u_short do_cursor = 0; /* Move the Cursor */ + + + /* + * Various Flags + */ + +static u_short is_blanked = 0; /* Screen is Blanked */ +static u_short is_lace = 0; /* Screen is laced */ + + /* + * Predefined Video Modes + * + */ + +static struct fb_videomode ami_modedb[] __initdata = { + + /* + * AmigaOS Video Modes + * + * If you change these, make sure to update DEFMODE_* as well! + */ + + { + /* 640x200, 15 kHz, 60 Hz (NTSC) */ + "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2, + FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ + "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x256, 15 kHz, 50 Hz (PAL) */ + "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2, + FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ + "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x480, 29 kHz, 57 Hz */ + "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x960, 29 kHz, 57 Hz interlaced */ + "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, 16, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x200, 15 kHz, 72 Hz */ + "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 15 kHz, 72 Hz interlaced */ + "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, 10, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 29 kHz, 68 Hz */ + "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x800, 29 kHz, 68 Hz interlaced */ + "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, 16, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 800x300, 23 kHz, 70 Hz */ + "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 800x600, 23 kHz, 70 Hz interlaced */ + "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x200, 27 kHz, 57 Hz doublescan */ + "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4, + 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP + }, { + /* 640x400, 27 kHz, 57 Hz */ + "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x800, 27 kHz, 57 Hz interlaced */ + "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x256, 27 kHz, 47 Hz doublescan */ + "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4, + 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP + }, { + /* 640x512, 27 kHz, 47 Hz */ + "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x1024, 27 kHz, 47 Hz interlaced */ + "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, + + /* + * VGA Video Modes + */ + + { + /* 640x480, 31 kHz, 60 Hz (VGA) */ + "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 31 kHz, 70 Hz (VGA) */ + "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2, + FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, + +#if 0 + + /* + * A2024 video modes + * These modes don't work yet because there's no A2024 driver. + */ + + { + /* 1024x800, 10 Hz */ + "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 1024x800, 15 Hz */ + "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + } +#endif +}; + +#define NUM_TOTAL_MODES ARRAY_SIZE(ami_modedb) + +static char *mode_option __initdata = NULL; +static int round_down_bpp = 1; /* for mode probing */ + + /* + * Some default modes + */ + + +#define DEFMODE_PAL 2 /* "pal" for PAL OCS/ECS */ +#define DEFMODE_NTSC 0 /* "ntsc" for NTSC OCS/ECS */ +#define DEFMODE_AMBER_PAL 3 /* "pal-lace" for flicker fixed PAL (A3000) */ +#define DEFMODE_AMBER_NTSC 1 /* "ntsc-lace" for flicker fixed NTSC (A3000) */ +#define DEFMODE_AGA 19 /* "vga70" for AGA */ + + +static int amifb_ilbm = 0; /* interleaved or normal bitplanes */ +static int amifb_inverse = 0; + + + /* + * Macros for the conversion from real world values to hardware register + * values + * + * This helps us to keep our attention on the real stuff... + * + * Hardware limits for AGA: + * + * parameter min max step + * --------- --- ---- ---- + * diwstrt_h 0 2047 1 + * diwstrt_v 0 2047 1 + * diwstop_h 0 4095 1 + * diwstop_v 0 4095 1 + * + * ddfstrt 0 2032 16 + * ddfstop 0 2032 16 + * + * htotal 8 2048 8 + * hsstrt 0 2040 8 + * hsstop 0 2040 8 + * vtotal 1 4096 1 + * vsstrt 0 4095 1 + * vsstop 0 4095 1 + * hcenter 0 2040 8 + * + * hbstrt 0 2047 1 + * hbstop 0 2047 1 + * vbstrt 0 4095 1 + * vbstop 0 4095 1 + * + * Horizontal values are in 35 ns (SHRES) pixels + * Vertical values are in half scanlines + */ + +/* bplcon1 (smooth scrolling) */ + +#define hscroll2hw(hscroll) \ + (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \ + ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f)) + +/* diwstrt/diwstop/diwhigh (visible display window) */ + +#define diwstrt2hw(diwstrt_h, diwstrt_v) \ + (((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) +#define diwstop2hw(diwstop_h, diwstop_v) \ + (((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) +#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \ + (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \ + ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \ + ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007)) + +/* ddfstrt/ddfstop (display DMA) */ + +#define ddfstrt2hw(ddfstrt) div8(ddfstrt) +#define ddfstop2hw(ddfstop) div8(ddfstop) + +/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */ + +#define hsstrt2hw(hsstrt) (div8(hsstrt)) +#define hsstop2hw(hsstop) (div8(hsstop)) +#define htotal2hw(htotal) (div8(htotal)-1) +#define vsstrt2hw(vsstrt) (div2(vsstrt)) +#define vsstop2hw(vsstop) (div2(vsstop)) +#define vtotal2hw(vtotal) (div2(vtotal)-1) +#define hcenter2hw(htotal) (div8(htotal)) + +/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */ + +#define hbstrt2hw(hbstrt) (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) +#define hbstop2hw(hbstop) (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) +#define vbstrt2hw(vbstrt) (div2(vbstrt)) +#define vbstop2hw(vbstop) (div2(vbstop)) + +/* colour */ + +#define rgb2hw8_high(red, green, blue) \ + (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4)) +#define rgb2hw8_low(red, green, blue) \ + (((red & 0x0f)<<8) | ((green & 0x0f)<<4) | (blue & 0x0f)) +#define rgb2hw4(red, green, blue) \ + (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4)) +#define rgb2hw2(red, green, blue) \ + (((red & 0xc0)<<4) | (green & 0xc0) | ((blue & 0xc0)>>4)) + +/* sprpos/sprctl (sprite positioning) */ + +#define spr2hw_pos(start_v, start_h) \ + (((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff)) +#define spr2hw_ctl(start_v, start_h, stop_v) \ + (((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \ + ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \ + ((start_h)>>2&0x0001)) + +/* get current vertical position of beam */ +#define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe)) + + /* + * Copper Initialisation List + */ + +#define COPINITSIZE (sizeof(copins)*40) + +enum { + cip_bplcon0 +}; + + /* + * Long Frame/Short Frame Copper List + * Don't change the order, build_copper()/rebuild_copper() rely on this + */ + +#define COPLISTSIZE (sizeof(copins)*64) + +enum { + cop_wait, cop_bplcon0, + cop_spr0ptrh, cop_spr0ptrl, + cop_diwstrt, cop_diwstop, + cop_diwhigh, +}; + + /* + * Pixel modes for Bitplanes and Sprites + */ + +static u_short bplpixmode[3] = { + BPC0_SHRES, /* 35 ns */ + BPC0_HIRES, /* 70 ns */ + 0 /* 140 ns */ +}; + +static u_short sprpixmode[3] = { + BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns */ + BPC3_SPRES1, /* 70 ns */ + BPC3_SPRES0 /* 140 ns */ +}; + + /* + * Fetch modes for Bitplanes and Sprites + */ + +static u_short bplfetchmode[3] = { + 0, /* 1x */ + FMODE_BPL32, /* 2x */ + FMODE_BPAGEM | FMODE_BPL32 /* 4x */ +}; + +static u_short sprfetchmode[3] = { + 0, /* 1x */ + FMODE_SPR32, /* 2x */ + FMODE_SPAGEM | FMODE_SPR32 /* 4x */ +}; + + + /* + * Interface used by the world + */ + +int amifb_setup(char*); + +static int amifb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int amifb_set_par(struct fb_info *info); +static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info); +static int amifb_blank(int blank, struct fb_info *info); +static int amifb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +static void amifb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect); +static void amifb_copyarea(struct fb_info *info, + const struct fb_copyarea *region); +static void amifb_imageblit(struct fb_info *info, + const struct fb_image *image); +static int amifb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + struct fb_info *info); + + + /* + * Interface to the low level console driver + */ + +int amifb_init(void); +static void amifb_deinit(void); + + /* + * Internal routines + */ + +static int flash_cursor(void); +static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp); +static u_long chipalloc(u_long size); +static void chipfree(void); + + /* + * Hardware routines + */ + +static int ami_decode_var(struct fb_var_screeninfo *var, + struct amifb_par *par); +static int ami_encode_var(struct fb_var_screeninfo *var, + struct amifb_par *par); +static void ami_pan_var(struct fb_var_screeninfo *var); +static int ami_update_par(void); +static void ami_update_display(void); +static void ami_init_display(void); +static void ami_do_blank(void); +static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix); +static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data); +static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data); +static int ami_get_cursorstate(struct fb_cursorstate *state); +static int ami_set_cursorstate(struct fb_cursorstate *state); +static void ami_set_sprite(void); +static void ami_init_copper(void); +static void ami_reinit_copper(void); +static void ami_build_copper(void); +static void ami_rebuild_copper(void); + + +static struct fb_ops amifb_ops = { + .owner = THIS_MODULE, + .fb_check_var = amifb_check_var, + .fb_set_par = amifb_set_par, + .fb_setcolreg = amifb_setcolreg, + .fb_blank = amifb_blank, + .fb_pan_display = amifb_pan_display, + .fb_fillrect = amifb_fillrect, + .fb_copyarea = amifb_copyarea, + .fb_imageblit = amifb_imageblit, + .fb_cursor = soft_cursor, + .fb_ioctl = amifb_ioctl, +}; + +static void __init amifb_setup_mcap(char *spec) +{ + char *p; + int vmin, vmax, hmin, hmax; + + /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax> + * <V*> vertical freq. in Hz + * <H*> horizontal freq. in kHz + */ + + if (!(p = strsep(&spec, ";")) || !*p) + return; + vmin = simple_strtoul(p, NULL, 10); + if (vmin <= 0) + return; + if (!(p = strsep(&spec, ";")) || !*p) + return; + vmax = simple_strtoul(p, NULL, 10); + if (vmax <= 0 || vmax <= vmin) + return; + if (!(p = strsep(&spec, ";")) || !*p) + return; + hmin = 1000 * simple_strtoul(p, NULL, 10); + if (hmin <= 0) + return; + if (!(p = strsep(&spec, "")) || !*p) + return; + hmax = 1000 * simple_strtoul(p, NULL, 10); + if (hmax <= 0 || hmax <= hmin) + return; + + fb_info.monspecs.vfmin = vmin; + fb_info.monspecs.vfmax = vmax; + fb_info.monspecs.hfmin = hmin; + fb_info.monspecs.hfmax = hmax; +} + +int __init amifb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + if (!strcmp(this_opt, "inverse")) { + amifb_inverse = 1; + fb_invert_cmaps(); + } else if (!strcmp(this_opt, "ilbm")) + amifb_ilbm = 1; + else if (!strncmp(this_opt, "monitorcap:", 11)) + amifb_setup_mcap(this_opt+11); + else if (!strncmp(this_opt, "fstart:", 7)) + min_fstrt = simple_strtoul(this_opt+7, NULL, 0); + else + mode_option = this_opt; + } + + if (min_fstrt < 48) + min_fstrt = 48; + + return 0; +} + + +static int amifb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int err; + struct amifb_par par; + + /* Validate wanted screen parameters */ + if ((err = ami_decode_var(var, &par))) + return err; + + /* Encode (possibly rounded) screen parameters */ + ami_encode_var(var, &par); + return 0; +} + + +static int amifb_set_par(struct fb_info *info) +{ + struct amifb_par *par = (struct amifb_par *)info->par; + + do_vmode_pan = 0; + do_vmode_full = 0; + + /* Decode wanted screen parameters */ + ami_decode_var(&info->var, par); + + /* Set new videomode */ + ami_build_copper(); + + /* Set VBlank trigger */ + do_vmode_full = 1; + + /* Update fix for new screen parameters */ + if (par->bpp == 1) { + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + } else if (amifb_ilbm) { + info->fix.type = FB_TYPE_INTERLEAVED_PLANES; + info->fix.type_aux = par->next_line; + } else { + info->fix.type = FB_TYPE_PLANES; + info->fix.type_aux = 0; + } + info->fix.line_length = div8(upx(16<<maxfmode, par->vxres)); + + if (par->vmode & FB_VMODE_YWRAP) { + info->fix.ywrapstep = 1; + info->fix.xpanstep = 0; + info->fix.ypanstep = 0; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP | + FBINFO_READS_FAST; /* override SCROLL_REDRAW */ + } else { + info->fix.ywrapstep = 0; + if (par->vmode & FB_VMODE_SMOOTH_XPAN) + info->fix.xpanstep = 1; + else + info->fix.xpanstep = 16<<maxfmode; + info->fix.ypanstep = 1; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + } + return 0; +} + + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int amifb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset < 0 || + var->yoffset >= info->var.yres_virtual || var->xoffset) + return -EINVAL; + } else { + /* + * TODO: There will be problems when xpan!=1, so some columns + * on the right side will never be seen + */ + if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) || + var->yoffset+info->var.yres > info->var.yres_virtual) + return -EINVAL; + } + ami_pan_var(var); + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; +} + + +#if BITS_PER_LONG == 32 +#define BYTES_PER_LONG 4 +#define SHIFT_PER_LONG 5 +#elif BITS_PER_LONG == 64 +#define BYTES_PER_LONG 8 +#define SHIFT_PER_LONG 6 +#else +#define Please update me +#endif + + + /* + * Compose two values, using a bitmask as decision value + * This is equivalent to (a & mask) | (b & ~mask) + */ + +static inline unsigned long comp(unsigned long a, unsigned long b, + unsigned long mask) +{ + return ((a ^ b) & mask) ^ b; +} + + +static inline unsigned long xor(unsigned long a, unsigned long b, + unsigned long mask) +{ + return (a & mask) ^ b; +} + + + /* + * Unaligned forward bit copy using 32-bit or 64-bit memory accesses + */ + +static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, + int src_idx, u32 n) +{ + unsigned long first, last; + int shift = dst_idx-src_idx, left, right; + unsigned long d0, d1; + int m; + + if (!n) + return; + + shift = dst_idx-src_idx; + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + + if (!shift) { + // Same alignment for source and dest + + if (dst_idx+n <= BITS_PER_LONG) { + // Single word + if (last) + first &= last; + *dst = comp(*src, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = comp(*src, *dst, first); + dst++; + src++; + n -= BITS_PER_LONG-dst_idx; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 8) { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + n -= 8; + } + while (n--) + *dst++ = *src++; + + // Trailing bits + if (last) + *dst = comp(*src, *dst, last); + } + } else { + // Different alignment for source and dest + + right = shift & (BITS_PER_LONG-1); + left = -shift & (BITS_PER_LONG-1); + + if (dst_idx+n <= BITS_PER_LONG) { + // Single destination word + if (last) + first &= last; + if (shift > 0) { + // Single source word + *dst = comp(*src >> right, *dst, first); + } else if (src_idx+n <= BITS_PER_LONG) { + // Single source word + *dst = comp(*src << left, *dst, first); + } else { + // 2 source words + d0 = *src++; + d1 = *src; + *dst = comp(d0 << left | d1 >> right, *dst, + first); + } + } else { + // Multiple destination words + d0 = *src++; + // Leading bits + if (shift > 0) { + // Single source word + *dst = comp(d0 >> right, *dst, first); + dst++; + n -= BITS_PER_LONG-dst_idx; + } else { + // 2 source words + d1 = *src++; + *dst = comp(d0 << left | d1 >> right, *dst, + first); + d0 = d1; + dst++; + n -= BITS_PER_LONG-dst_idx; + } + + // Main chunk + m = n % BITS_PER_LONG; + n /= BITS_PER_LONG; + while (n >= 4) { + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + n -= 4; + } + while (n--) { + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + } + + // Trailing bits + if (last) { + if (m <= right) { + // Single source word + *dst = comp(d0 << left, *dst, last); + } else { + // 2 source words + d1 = *src; + *dst = comp(d0 << left | d1 >> right, + *dst, last); + } + } + } + } +} + + + /* + * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses + */ + +static void bitcpy_rev(unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, u32 n) +{ + unsigned long first, last; + int shift = dst_idx-src_idx, left, right; + unsigned long d0, d1; + int m; + + if (!n) + return; + + dst += (n-1)/BITS_PER_LONG; + src += (n-1)/BITS_PER_LONG; + if ((n-1) % BITS_PER_LONG) { + dst_idx += (n-1) % BITS_PER_LONG; + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= BITS_PER_LONG-1; + src_idx += (n-1) % BITS_PER_LONG; + src += src_idx >> SHIFT_PER_LONG; + src_idx &= BITS_PER_LONG-1; + } + + shift = dst_idx-src_idx; + first = ~0UL << (BITS_PER_LONG-1-dst_idx); + last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG))); + + if (!shift) { + // Same alignment for source and dest + + if ((unsigned long)dst_idx+1 >= n) { + // Single word + if (last) + first &= last; + *dst = comp(*src, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = comp(*src, *dst, first); + dst--; + src--; + n -= dst_idx+1; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 8) { + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + n -= 8; + } + while (n--) + *dst-- = *src--; + + // Trailing bits + if (last) + *dst = comp(*src, *dst, last); + } + } else { + // Different alignment for source and dest + + right = shift & (BITS_PER_LONG-1); + left = -shift & (BITS_PER_LONG-1); + + if ((unsigned long)dst_idx+1 >= n) { + // Single destination word + if (last) + first &= last; + if (shift < 0) { + // Single source word + *dst = comp(*src << left, *dst, first); + } else if (1+(unsigned long)src_idx >= n) { + // Single source word + *dst = comp(*src >> right, *dst, first); + } else { + // 2 source words + d0 = *src--; + d1 = *src; + *dst = comp(d0 >> right | d1 << left, *dst, + first); + } + } else { + // Multiple destination words + d0 = *src--; + // Leading bits + if (shift < 0) { + // Single source word + *dst = comp(d0 << left, *dst, first); + dst--; + n -= dst_idx+1; + } else { + // 2 source words + d1 = *src--; + *dst = comp(d0 >> right | d1 << left, *dst, + first); + d0 = d1; + dst--; + n -= dst_idx+1; + } + + // Main chunk + m = n % BITS_PER_LONG; + n /= BITS_PER_LONG; + while (n >= 4) { + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + n -= 4; + } + while (n--) { + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + } + + // Trailing bits + if (last) { + if (m <= left) { + // Single source word + *dst = comp(d0 >> right, *dst, last); + } else { + // 2 source words + d1 = *src; + *dst = comp(d0 >> right | d1 << left, + *dst, last); + } + } + } + } +} + + + /* + * Unaligned forward inverting bit copy using 32-bit or 64-bit memory + * accesses + */ + +static void bitcpy_not(unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, u32 n) +{ + unsigned long first, last; + int shift = dst_idx-src_idx, left, right; + unsigned long d0, d1; + int m; + + if (!n) + return; + + shift = dst_idx-src_idx; + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + + if (!shift) { + // Same alignment for source and dest + + if (dst_idx+n <= BITS_PER_LONG) { + // Single word + if (last) + first &= last; + *dst = comp(~*src, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = comp(~*src, *dst, first); + dst++; + src++; + n -= BITS_PER_LONG-dst_idx; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 8) { + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + n -= 8; + } + while (n--) + *dst++ = ~*src++; + + // Trailing bits + if (last) + *dst = comp(~*src, *dst, last); + } + } else { + // Different alignment for source and dest + + right = shift & (BITS_PER_LONG-1); + left = -shift & (BITS_PER_LONG-1); + + if (dst_idx+n <= BITS_PER_LONG) { + // Single destination word + if (last) + first &= last; + if (shift > 0) { + // Single source word + *dst = comp(~*src >> right, *dst, first); + } else if (src_idx+n <= BITS_PER_LONG) { + // Single source word + *dst = comp(~*src << left, *dst, first); + } else { + // 2 source words + d0 = ~*src++; + d1 = ~*src; + *dst = comp(d0 << left | d1 >> right, *dst, + first); + } + } else { + // Multiple destination words + d0 = ~*src++; + // Leading bits + if (shift > 0) { + // Single source word + *dst = comp(d0 >> right, *dst, first); + dst++; + n -= BITS_PER_LONG-dst_idx; + } else { + // 2 source words + d1 = ~*src++; + *dst = comp(d0 << left | d1 >> right, *dst, + first); + d0 = d1; + dst++; + n -= BITS_PER_LONG-dst_idx; + } + + // Main chunk + m = n % BITS_PER_LONG; + n /= BITS_PER_LONG; + while (n >= 4) { + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + n -= 4; + } + while (n--) { + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + } + + // Trailing bits + if (last) { + if (m <= right) { + // Single source word + *dst = comp(d0 << left, *dst, last); + } else { + // 2 source words + d1 = ~*src; + *dst = comp(d0 << left | d1 >> right, + *dst, last); + } + } + } + } +} + + + /* + * Unaligned 32-bit pattern fill using 32/64-bit memory accesses + */ + +static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) +{ + unsigned long val = pat; + unsigned long first, last; + + if (!n) + return; + +#if BITS_PER_LONG == 64 + val |= val << 32; +#endif + + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + + if (dst_idx+n <= BITS_PER_LONG) { + // Single word + if (last) + first &= last; + *dst = comp(val, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = comp(val, *dst, first); + dst++; + n -= BITS_PER_LONG-dst_idx; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 8) { + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + n -= 8; + } + while (n--) + *dst++ = val; + + // Trailing bits + if (last) + *dst = comp(val, *dst, last); + } +} + + + /* + * Unaligned 32-bit pattern xor using 32/64-bit memory accesses + */ + +static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) +{ + unsigned long val = pat; + unsigned long first, last; + + if (!n) + return; + +#if BITS_PER_LONG == 64 + val |= val << 32; +#endif + + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + + if (dst_idx+n <= BITS_PER_LONG) { + // Single word + if (last) + first &= last; + *dst = xor(val, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = xor(val, *dst, first); + dst++; + n -= BITS_PER_LONG-dst_idx; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 4) { + *dst++ ^= val; + *dst++ ^= val; + *dst++ ^= val; + *dst++ ^= val; + n -= 4; + } + while (n--) + *dst++ ^= val; + + // Trailing bits + if (last) + *dst = xor(val, *dst, last); + } +} + +static inline void fill_one_line(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, u32 n, + u32 color) +{ + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG-1); + bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n); + if (!--bpp) + break; + color >>= 1; + dst_idx += next_plane*8; + } +} + +static inline void xor_one_line(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, u32 n, + u32 color) +{ + while (color) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG-1); + bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n); + if (!--bpp) + break; + color >>= 1; + dst_idx += next_plane*8; + } +} + + +static void amifb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + struct amifb_par *par = (struct amifb_par *)info->par; + int dst_idx, x2, y2; + unsigned long *dst; + u32 width, height; + + if (!rect->width || !rect->height) + return; + + /* + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. + * */ + x2 = rect->dx + rect->width; + y2 = rect->dy + rect->height; + x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; + y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; + width = x2 - rect->dx; + height = y2 - rect->dy; + + dst = (unsigned long *) + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; + dst_idx += rect->dy*par->next_line*8+rect->dx; + while (height--) { + switch (rect->rop) { + case ROP_COPY: + fill_one_line(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, width, + rect->color); + break; + + case ROP_XOR: + xor_one_line(info->var.bits_per_pixel, par->next_plane, + dst, dst_idx, width, rect->color); + break; + } + dst_idx += par->next_line*8; + } +} + +static inline void copy_one_line(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, + unsigned long *src, int src_idx, u32 n) +{ + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG-1); + src += src_idx >> SHIFT_PER_LONG; + src_idx &= (BITS_PER_LONG-1); + bitcpy(dst, dst_idx, src, src_idx, n); + if (!--bpp) + break; + dst_idx += next_plane*8; + src_idx += next_plane*8; + } +} + +static inline void copy_one_line_rev(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, + unsigned long *src, int src_idx, u32 n) +{ + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG-1); + src += src_idx >> SHIFT_PER_LONG; + src_idx &= (BITS_PER_LONG-1); + bitcpy_rev(dst, dst_idx, src, src_idx, n); + if (!--bpp) + break; + dst_idx += next_plane*8; + src_idx += next_plane*8; + } +} + + +static void amifb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + struct amifb_par *par = (struct amifb_par *)info->par; + int x2, y2; + u32 dx, dy, sx, sy, width, height; + unsigned long *dst, *src; + int dst_idx, src_idx; + int rev_copy = 0; + + /* clip the destination */ + x2 = area->dx + area->width; + y2 = area->dy + area->height; + dx = area->dx > 0 ? area->dx : 0; + dy = area->dy > 0 ? area->dy : 0; + x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; + y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; + width = x2 - dx; + height = y2 - dy; + + /* update sx,sy */ + sx = area->sx + (dx - area->dx); + sy = area->sy + (dy - area->dy); + + /* the source must be completely inside the virtual screen */ + if (sx < 0 || sy < 0 || (sx + width) > info->var.xres_virtual || + (sy + height) > info->var.yres_virtual) + return; + + if (dy > sy || (dy == sy && dx > sx)) { + dy += height; + sy += height; + rev_copy = 1; + } + dst = (unsigned long *) + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); + src = dst; + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; + src_idx = dst_idx; + dst_idx += dy*par->next_line*8+dx; + src_idx += sy*par->next_line*8+sx; + if (rev_copy) { + while (height--) { + dst_idx -= par->next_line*8; + src_idx -= par->next_line*8; + copy_one_line_rev(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, src, + src_idx, width); + } + } else { + while (height--) { + copy_one_line(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, src, + src_idx, width); + dst_idx += par->next_line*8; + src_idx += par->next_line*8; + } + } +} + + +static inline void expand_one_line(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, u32 n, + const u8 *data, u32 bgcolor, u32 fgcolor) +{ + const unsigned long *src; + int src_idx; + + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG-1); + if ((bgcolor ^ fgcolor) & 1) { + src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1)); + src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8; + if (fgcolor & 1) + bitcpy(dst, dst_idx, src, src_idx, n); + else + bitcpy_not(dst, dst_idx, src, src_idx, n); + /* set or clear */ + } else + bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n); + if (!--bpp) + break; + bgcolor >>= 1; + fgcolor >>= 1; + dst_idx += next_plane*8; + } +} + + +static void amifb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct amifb_par *par = (struct amifb_par *)info->par; + int x2, y2; + unsigned long *dst; + int dst_idx; + const char *src; + u32 dx, dy, width, height, pitch; + + /* + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly like we are + * doing here. + */ + x2 = image->dx + image->width; + y2 = image->dy + image->height; + dx = image->dx; + dy = image->dy; + x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; + y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; + width = x2 - dx; + height = y2 - dy; + + if (image->depth == 1) { + dst = (unsigned long *) + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; + dst_idx += dy*par->next_line*8+dx; + src = image->data; + pitch = (image->width+7)/8; + while (height--) { + expand_one_line(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, width, + src, image->bg_color, + image->fg_color); + dst_idx += par->next_line*8; + src += pitch; + } + } else { + c2p(info->screen_base, image->data, dx, dy, width, height, + par->next_line, par->next_plane, image->width, + info->var.bits_per_pixel); + } +} + + + /* + * Amiga Frame Buffer Specific ioctls + */ + +static int amifb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + struct fb_info *info) +{ + union { + struct fb_fix_cursorinfo fix; + struct fb_var_cursorinfo var; + struct fb_cursorstate state; + } crsr; + int i; + + switch (cmd) { + case FBIOGET_FCURSORINFO: + i = ami_get_fix_cursorinfo(&crsr.fix); + if (i) + return i; + return copy_to_user((void *)arg, &crsr.fix, + sizeof(crsr.fix)) ? -EFAULT : 0; + + case FBIOGET_VCURSORINFO: + i = ami_get_var_cursorinfo(&crsr.var, + ((struct fb_var_cursorinfo *)arg)->data); + if (i) + return i; + return copy_to_user((void *)arg, &crsr.var, + sizeof(crsr.var)) ? -EFAULT : 0; + + case FBIOPUT_VCURSORINFO: + if (copy_from_user(&crsr.var, (void *)arg, + sizeof(crsr.var))) + return -EFAULT; + return ami_set_var_cursorinfo(&crsr.var, + ((struct fb_var_cursorinfo *)arg)->data); + + case FBIOGET_CURSORSTATE: + i = ami_get_cursorstate(&crsr.state); + if (i) + return i; + return copy_to_user((void *)arg, &crsr.state, + sizeof(crsr.state)) ? -EFAULT : 0; + + case FBIOPUT_CURSORSTATE: + if (copy_from_user(&crsr.state, (void *)arg, + sizeof(crsr.state))) + return -EFAULT; + return ami_set_cursorstate(&crsr.state); + } + return -EINVAL; +} + + + /* + * Allocate, Clear and Align a Block of Chip Memory + */ + +static u_long unaligned_chipptr = 0; + +static inline u_long __init chipalloc(u_long size) +{ + size += PAGE_SIZE-1; + if (!(unaligned_chipptr = (u_long)amiga_chip_alloc(size, + "amifb [RAM]"))) + panic("No Chip RAM for frame buffer"); + memset((void *)unaligned_chipptr, 0, size); + return PAGE_ALIGN(unaligned_chipptr); +} + +static inline void chipfree(void) +{ + if (unaligned_chipptr) + amiga_chip_free((void *)unaligned_chipptr); +} + + + /* + * Initialisation + */ + +int __init amifb_init(void) +{ + int tag, i, err = 0; + u_long chipptr; + u_int defmode; + +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("amifb", &option)) { + amifb_video_off(); + return -ENODEV; + } + amifb_setup(option); +#endif + if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO)) + return -ENXIO; + + /* + * We request all registers starting from bplpt[0] + */ + if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120, + "amifb [Denise/Lisa]")) + return -EBUSY; + + custom.dmacon = DMAF_ALL | DMAF_MASTER; + + switch (amiga_chipset) { +#ifdef CONFIG_FB_AMIGA_OCS + case CS_OCS: + strcat(fb_info.fix.id, "OCS"); +default_chipset: + chipset = TAG_OCS; + maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ + maxdepth[TAG_HIRES] = 4; + maxdepth[TAG_LORES] = 6; + maxfmode = TAG_FMODE_1; + defmode = amiga_vblank == 50 ? DEFMODE_PAL + : DEFMODE_NTSC; + fb_info.fix.smem_len = VIDEOMEMSIZE_OCS; + break; +#endif /* CONFIG_FB_AMIGA_OCS */ + +#ifdef CONFIG_FB_AMIGA_ECS + case CS_ECS: + strcat(fb_info.fix.id, "ECS"); + chipset = TAG_ECS; + maxdepth[TAG_SHRES] = 2; + maxdepth[TAG_HIRES] = 4; + maxdepth[TAG_LORES] = 6; + maxfmode = TAG_FMODE_1; + if (AMIGAHW_PRESENT(AMBER_FF)) + defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL + : DEFMODE_AMBER_NTSC; + else + defmode = amiga_vblank == 50 ? DEFMODE_PAL + : DEFMODE_NTSC; + if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > + VIDEOMEMSIZE_ECS_1M) + fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M; + else + fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M; + break; +#endif /* CONFIG_FB_AMIGA_ECS */ + +#ifdef CONFIG_FB_AMIGA_AGA + case CS_AGA: + strcat(fb_info.fix.id, "AGA"); + chipset = TAG_AGA; + maxdepth[TAG_SHRES] = 8; + maxdepth[TAG_HIRES] = 8; + maxdepth[TAG_LORES] = 8; + maxfmode = TAG_FMODE_4; + defmode = DEFMODE_AGA; + if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > + VIDEOMEMSIZE_AGA_1M) + fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M; + else + fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M; + break; +#endif /* CONFIG_FB_AMIGA_AGA */ + + default: +#ifdef CONFIG_FB_AMIGA_OCS + printk("Unknown graphics chipset, defaulting to OCS\n"); + strcat(fb_info.fix.id, "Unknown"); + goto default_chipset; +#else /* CONFIG_FB_AMIGA_OCS */ + err = -ENXIO; + goto amifb_error; +#endif /* CONFIG_FB_AMIGA_OCS */ + break; + } + + /* + * Calculate the Pixel Clock Values for this Machine + */ + + { + u_long tmp = DIVUL(200000000000ULL, amiga_eclock); + + pixclock[TAG_SHRES] = (tmp + 4) / 8; /* SHRES: 35 ns / 28 MHz */ + pixclock[TAG_HIRES] = (tmp + 2) / 4; /* HIRES: 70 ns / 14 MHz */ + pixclock[TAG_LORES] = (tmp + 1) / 2; /* LORES: 140 ns / 7 MHz */ + } + + /* + * Replace the Tag Values with the Real Pixel Clock Values + */ + + for (i = 0; i < NUM_TOTAL_MODES; i++) { + struct fb_videomode *mode = &ami_modedb[i]; + tag = mode->pixclock; + if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) { + mode->pixclock = pixclock[tag]; + } + } + + /* + * These monitor specs are for a typical Amiga monitor (e.g. A1960) + */ + if (fb_info.monspecs.hfmin == 0) { + fb_info.monspecs.hfmin = 15000; + fb_info.monspecs.hfmax = 38000; + fb_info.monspecs.vfmin = 49; + fb_info.monspecs.vfmax = 90; + } + + fb_info.fbops = &amifb_ops; + fb_info.par = ¤tpar; + fb_info.flags = FBINFO_DEFAULT; + + if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb, + NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { + err = -EINVAL; + goto amifb_error; + } + + round_down_bpp = 0; + chipptr = chipalloc(fb_info.fix.smem_len+ + SPRITEMEMSIZE+ + DUMMYSPRITEMEMSIZE+ + COPINITSIZE+ + 4*COPLISTSIZE); + + assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len); + assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); + assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); + assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); + assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE); + assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE); + assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE); + assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE); + + /* + * access the videomem with writethrough cache + */ + fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory); + videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start, + fb_info.fix.smem_len); + if (!videomemory) { + printk("amifb: WARNING! unable to map videomem cached writethrough\n"); + videomemory = ZTWO_VADDR(fb_info.fix.smem_start); + } + + fb_info.screen_base = (char *)videomemory; + memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); + + /* + * Enable Display DMA + */ + + custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | + DMAF_BLITTER | DMAF_SPRITE; + + /* + * Make sure the Copper has something to do + */ + + ami_init_copper(); + + if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, + "fb vertb handler", ¤tpar)) { + err = -EBUSY; + goto amifb_error; + } + + fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0); + + if (register_framebuffer(&fb_info) < 0) { + err = -EINVAL; + goto amifb_error; + } + + printk("fb%d: %s frame buffer device, using %dK of video memory\n", + fb_info.node, fb_info.fix.id, fb_info.fix.smem_len>>10); + + return 0; + +amifb_error: + amifb_deinit(); + return err; +} + +static void amifb_deinit(void) +{ + fb_dealloc_cmap(&fb_info.cmap); + chipfree(); + release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120); + custom.dmacon = DMAF_ALL | DMAF_MASTER; +} + + + /* + * Blank the display. + */ + +static int amifb_blank(int blank, struct fb_info *info) +{ + do_blank = blank ? blank : -1; + + return 0; +} + + /* + * Flash the cursor (called by VBlank interrupt) + */ + +static int flash_cursor(void) +{ + static int cursorcount = 1; + + if (cursormode == FB_CURSOR_FLASH) { + if (!--cursorcount) { + cursorstate = -cursorstate; + cursorcount = cursorrate; + if (!is_blanked) + return 1; + } + } + return 0; +} + + /* + * VBlank Display Interrupt + */ + +static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp) +{ + if (do_vmode_pan || do_vmode_full) + ami_update_display(); + + if (do_vmode_full) + ami_init_display(); + + if (do_vmode_pan) { + flash_cursor(); + ami_rebuild_copper(); + do_cursor = do_vmode_pan = 0; + } else if (do_cursor) { + flash_cursor(); + ami_set_sprite(); + do_cursor = 0; + } else { + if (flash_cursor()) + ami_set_sprite(); + } + + if (do_blank) { + ami_do_blank(); + do_blank = 0; + } + + if (do_vmode_full) { + ami_reinit_copper(); + do_vmode_full = 0; + } + return IRQ_HANDLED; +} + +/* --------------------------- Hardware routines --------------------------- */ + + /* + * Get the video params out of `var'. If a value doesn't fit, round + * it up, if it's too big, return -EINVAL. + */ + +static int ami_decode_var(struct fb_var_screeninfo *var, + struct amifb_par *par) +{ + u_short clk_shift, line_shift; + u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; + u_int htotal, vtotal; + + /* + * Find a matching Pixel Clock + */ + + for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++) + if (var->pixclock <= pixclock[clk_shift]) + break; + if (clk_shift > TAG_LORES) { + DPRINTK("pixclock too high\n"); + return -EINVAL; + } + par->clk_shift = clk_shift; + + /* + * Check the Geometry Values + */ + + if ((par->xres = var->xres) < 64) + par->xres = 64; + if ((par->yres = var->yres) < 64) + par->yres = 64; + if ((par->vxres = var->xres_virtual) < par->xres) + par->vxres = par->xres; + if ((par->vyres = var->yres_virtual) < par->yres) + par->vyres = par->yres; + + par->bpp = var->bits_per_pixel; + if (!var->nonstd) { + if (par->bpp < 1) + par->bpp = 1; + if (par->bpp > maxdepth[clk_shift]) { + if (round_down_bpp && maxdepth[clk_shift]) + par->bpp = maxdepth[clk_shift]; + else { + DPRINTK("invalid bpp\n"); + return -EINVAL; + } + } + } else if (var->nonstd == FB_NONSTD_HAM) { + if (par->bpp < 6) + par->bpp = 6; + if (par->bpp != 6) { + if (par->bpp < 8) + par->bpp = 8; + if (par->bpp != 8 || !IS_AGA) { + DPRINTK("invalid bpp for ham mode\n"); + return -EINVAL; + } + } + } else { + DPRINTK("unknown nonstd mode\n"); + return -EINVAL; + } + + /* + * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing + * checks failed and smooth scrolling is not possible + */ + + par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN; + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + line_shift = 0; + break; + case FB_VMODE_NONINTERLACED: + line_shift = 1; + break; + case FB_VMODE_DOUBLE: + if (!IS_AGA) { + DPRINTK("double mode only possible with aga\n"); + return -EINVAL; + } + line_shift = 2; + break; + default: + DPRINTK("unknown video mode\n"); + return -EINVAL; + break; + } + par->line_shift = line_shift; + + /* + * Vertical and Horizontal Timings + */ + + xres_n = par->xres<<clk_shift; + yres_n = par->yres<<line_shift; + par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift); + par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1); + + if (IS_AGA) + par->bplcon3 = sprpixmode[clk_shift]; + else + par->bplcon3 = 0; + if (var->sync & FB_SYNC_BROADCAST) { + par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift); + if (IS_AGA) + par->diwstop_h += mod4(var->hsync_len); + else + par->diwstop_h = down4(par->diwstop_h); + + par->diwstrt_h = par->diwstop_h - xres_n; + par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift); + par->diwstrt_v = par->diwstop_v - yres_n; + if (par->diwstop_h >= par->htotal+8) { + DPRINTK("invalid diwstop_h\n"); + return -EINVAL; + } + if (par->diwstop_v > par->vtotal) { + DPRINTK("invalid diwstop_v\n"); + return -EINVAL; + } + + if (!IS_OCS) { + /* Initialize sync with some reasonable values for pwrsave */ + par->hsstrt = 160; + par->hsstop = 320; + par->vsstrt = 30; + par->vsstop = 34; + } else { + par->hsstrt = 0; + par->hsstop = 0; + par->vsstrt = 0; + par->vsstop = 0; + } + if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) { + /* PAL video mode */ + if (par->htotal != PAL_HTOTAL) { + DPRINTK("htotal invalid for pal\n"); + return -EINVAL; + } + if (par->diwstrt_h < PAL_DIWSTRT_H) { + DPRINTK("diwstrt_h too low for pal\n"); + return -EINVAL; + } + if (par->diwstrt_v < PAL_DIWSTRT_V) { + DPRINTK("diwstrt_v too low for pal\n"); + return -EINVAL; + } + htotal = PAL_HTOTAL>>clk_shift; + vtotal = PAL_VTOTAL>>1; + if (!IS_OCS) { + par->beamcon0 = BMC0_PAL; + par->bplcon3 |= BPC3_BRDRBLNK; + } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || + AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { + par->beamcon0 = BMC0_PAL; + par->hsstop = 1; + } else if (amiga_vblank != 50) { + DPRINTK("pal not supported by this chipset\n"); + return -EINVAL; + } + } else { + /* NTSC video mode + * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK + * and NTSC activated, so than better let diwstop_h <= 1812 + */ + if (par->htotal != NTSC_HTOTAL) { + DPRINTK("htotal invalid for ntsc\n"); + return -EINVAL; + } + if (par->diwstrt_h < NTSC_DIWSTRT_H) { + DPRINTK("diwstrt_h too low for ntsc\n"); + return -EINVAL; + } + if (par->diwstrt_v < NTSC_DIWSTRT_V) { + DPRINTK("diwstrt_v too low for ntsc\n"); + return -EINVAL; + } + htotal = NTSC_HTOTAL>>clk_shift; + vtotal = NTSC_VTOTAL>>1; + if (!IS_OCS) { + par->beamcon0 = 0; + par->bplcon3 |= BPC3_BRDRBLNK; + } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || + AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { + par->beamcon0 = 0; + par->hsstop = 1; + } else if (amiga_vblank != 60) { + DPRINTK("ntsc not supported by this chipset\n"); + return -EINVAL; + } + } + if (IS_OCS) { + if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 || + par->diwstrt_v >= 512 || par->diwstop_v < 256) { + DPRINTK("invalid position for display on ocs\n"); + return -EINVAL; + } + } + } else if (!IS_OCS) { + /* Programmable video mode */ + par->hsstrt = var->right_margin<<clk_shift; + par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift; + par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift); + if (!IS_AGA) + par->diwstop_h = down4(par->diwstop_h) - 16; + par->diwstrt_h = par->diwstop_h - xres_n; + par->hbstop = par->diwstrt_h + 4; + par->hbstrt = par->diwstop_h + 4; + if (par->hbstrt >= par->htotal + 8) + par->hbstrt -= par->htotal; + par->hcenter = par->hsstrt + (par->htotal >> 1); + par->vsstrt = var->lower_margin<<line_shift; + par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift; + par->diwstop_v = par->vtotal; + if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + par->diwstop_v -= 2; + par->diwstrt_v = par->diwstop_v - yres_n; + par->vbstop = par->diwstrt_v - 2; + par->vbstrt = par->diwstop_v - 2; + if (par->vtotal > 2048) { + DPRINTK("vtotal too high\n"); + return -EINVAL; + } + if (par->htotal > 2048) { + DPRINTK("htotal too high\n"); + return -EINVAL; + } + par->bplcon3 |= BPC3_EXTBLKEN; + par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | + BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | + BMC0_PAL | BMC0_VARCSYEN; + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + par->beamcon0 |= BMC0_HSYTRUE; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + par->beamcon0 |= BMC0_VSYTRUE; + if (var->sync & FB_SYNC_COMP_HIGH_ACT) + par->beamcon0 |= BMC0_CSYTRUE; + htotal = par->htotal>>clk_shift; + vtotal = par->vtotal>>1; + } else { + DPRINTK("only broadcast modes possible for ocs\n"); + return -EINVAL; + } + + /* + * Checking the DMA timing + */ + + fconst = 16<<maxfmode<<clk_shift; + + /* + * smallest window start value without turn off other dma cycles + * than sprite1-7, unless you change min_fstrt + */ + + + fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64); + fstrt = downx(fconst, par->diwstrt_h-4) - fsize; + if (fstrt < min_fstrt) { + DPRINTK("fetch start too low\n"); + return -EINVAL; + } + + /* + * smallest window start value where smooth scrolling is possible + */ + + fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize; + if (fstrt < min_fstrt) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + maxfetchstop = down16(par->htotal - 80); + + fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst; + fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4))); + if (fstrt + fsize > maxfetchstop) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + fsize = upx(fconst, xres_n); + if (fstrt + fsize > maxfetchstop) { + DPRINTK("fetch stop too high\n"); + return -EINVAL; + } + + if (maxfmode + clk_shift <= 1) { + fsize = up64(xres_n + fconst - 1); + if (min_fstrt + fsize - 64 > maxfetchstop) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + fsize = up64(xres_n); + if (min_fstrt + fsize - 64 > maxfetchstop) { + DPRINTK("fetch size too high\n"); + return -EINVAL; + } + + fsize -= 64; + } else + fsize -= fconst; + + /* + * Check if there is enough time to update the bitplane pointers for ywrap + */ + + if (par->htotal-fsize-64 < par->bpp*64) + par->vmode &= ~FB_VMODE_YWRAP; + + /* + * Bitplane calculations and check the Memory Requirements + */ + + if (amifb_ilbm) { + par->next_plane = div8(upx(16<<maxfmode, par->vxres)); + par->next_line = par->bpp*par->next_plane; + if (par->next_line * par->vyres > fb_info.fix.smem_len) { + DPRINTK("too few video mem\n"); + return -EINVAL; + } + } else { + par->next_line = div8(upx(16<<maxfmode, par->vxres)); + par->next_plane = par->vyres*par->next_line; + if (par->next_plane * par->bpp > fb_info.fix.smem_len) { + DPRINTK("too few video mem\n"); + return -EINVAL; + } + } + + /* + * Hardware Register Values + */ + + par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift]; + if (!IS_OCS) + par->bplcon0 |= BPC0_ECSENA; + if (par->bpp == 8) + par->bplcon0 |= BPC0_BPU3; + else + par->bplcon0 |= par->bpp<<12; + if (var->nonstd == FB_NONSTD_HAM) + par->bplcon0 |= BPC0_HAM; + if (var->sync & FB_SYNC_EXT) + par->bplcon0 |= BPC0_ERSY; + + if (IS_AGA) + par->fmode = bplfetchmode[maxfmode]; + + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + par->bplcon0 |= BPC0_LACE; + break; + case FB_VMODE_DOUBLE: + if (IS_AGA) + par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; + break; + } + + if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (par->vmode & FB_VMODE_YWRAP) { + if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres) + par->xoffset = par->yoffset = 0; + } else { + if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) || + par->yoffset < 0 || par->yoffset > par->vyres-par->yres) + par->xoffset = par->yoffset = 0; + } + } else + par->xoffset = par->yoffset = 0; + + par->crsr.crsr_x = par->crsr.crsr_y = 0; + par->crsr.spot_x = par->crsr.spot_y = 0; + par->crsr.height = par->crsr.width = 0; + +#if 0 /* fbmon not done. uncomment for 2.5.x -brad */ + if (!fbmon_valid_timings(pixclock[clk_shift], htotal, vtotal, + &fb_info)) { + DPRINTK("mode doesn't fit for monitor\n"); + return -EINVAL; + } +#endif + + return 0; +} + + /* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static int ami_encode_var(struct fb_var_screeninfo *var, + struct amifb_par *par) +{ + u_short clk_shift, line_shift; + + memset(var, 0, sizeof(struct fb_var_screeninfo)); + + clk_shift = par->clk_shift; + line_shift = par->line_shift; + + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->vxres; + var->yres_virtual = par->vyres; + var->xoffset = par->xoffset; + var->yoffset = par->yoffset; + + var->bits_per_pixel = par->bpp; + var->grayscale = 0; + + var->red.offset = 0; + var->red.msb_right = 0; + var->red.length = par->bpp; + if (par->bplcon0 & BPC0_HAM) + var->red.length -= 2; + var->blue = var->green = var->red; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + + if (par->bplcon0 & BPC0_HAM) + var->nonstd = FB_NONSTD_HAM; + else + var->nonstd = 0; + var->activate = 0; + + var->height = -1; + var->width = -1; + + var->pixclock = pixclock[clk_shift]; + + if (IS_AGA && par->fmode & FMODE_BSCAN2) + var->vmode = FB_VMODE_DOUBLE; + else if (par->bplcon0 & BPC0_LACE) + var->vmode = FB_VMODE_INTERLACED; + else + var->vmode = FB_VMODE_NONINTERLACED; + + if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) { + var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift; + var->right_margin = par->hsstrt>>clk_shift; + var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; + var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift; + var->lower_margin = par->vsstrt>>line_shift; + var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len; + var->sync = 0; + if (par->beamcon0 & BMC0_HSYTRUE) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (par->beamcon0 & BMC0_VSYTRUE) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + if (par->beamcon0 & BMC0_CSYTRUE) + var->sync |= FB_SYNC_COMP_HIGH_ACT; + } else { + var->sync = FB_SYNC_BROADCAST; + var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h); + var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len; + var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; + var->vsync_len = 4>>line_shift; + var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len; + var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres - + var->lower_margin - var->vsync_len; + } + + if (par->bplcon0 & BPC0_ERSY) + var->sync |= FB_SYNC_EXT; + if (par->vmode & FB_VMODE_YWRAP) + var->vmode |= FB_VMODE_YWRAP; + + return 0; +} + + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + * in `var'. + */ + +static void ami_pan_var(struct fb_var_screeninfo *var) +{ + struct amifb_par *par = ¤tpar; + + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + par->vmode |= FB_VMODE_YWRAP; + else + par->vmode &= ~FB_VMODE_YWRAP; + + do_vmode_pan = 0; + ami_update_par(); + do_vmode_pan = 1; +} + + /* + * Update hardware + */ + +static int ami_update_par(void) +{ + struct amifb_par *par = ¤tpar; + short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; + + clk_shift = par->clk_shift; + + if (!(par->vmode & FB_VMODE_SMOOTH_XPAN)) + par->xoffset = upx(16<<maxfmode, par->xoffset); + + fconst = 16<<maxfmode<<clk_shift; + vshift = modx(16<<maxfmode, par->xoffset); + fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4; + fsize = (par->xres+vshift)<<clk_shift; + shift = modx(fconst, fstrt); + move = downx(2<<maxfmode, div8(par->xoffset)); + if (maxfmode + clk_shift > 1) { + fstrt = downx(fconst, fstrt) - 64; + fsize = upx(fconst, fsize); + fstop = fstrt + fsize - fconst; + } else { + mod = fstrt = downx(fconst, fstrt) - fconst; + fstop = fstrt + upx(fconst, fsize) - 64; + fsize = up64(fsize); + fstrt = fstop - fsize + 64; + if (fstrt < min_fstrt) { + fstop += min_fstrt - fstrt; + fstrt = min_fstrt; + } + move = move - div8((mod-fstrt)>>clk_shift); + } + mod = par->next_line - div8(fsize>>clk_shift); + par->ddfstrt = fstrt; + par->ddfstop = fstop; + par->bplcon1 = hscroll2hw(shift); + par->bpl2mod = mod; + if (par->bplcon0 & BPC0_LACE) + par->bpl2mod += par->next_line; + if (IS_AGA && (par->fmode & FMODE_BSCAN2)) + par->bpl1mod = -div8(fsize>>clk_shift); + else + par->bpl1mod = par->bpl2mod; + + if (par->yoffset) { + par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move; + if (par->vmode & FB_VMODE_YWRAP) { + if (par->yoffset > par->vyres-par->yres) { + par->bplpt0wrap = fb_info.fix.smem_start + move; + if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset)) + par->bplpt0wrap += par->next_line; + } + } + } else + par->bplpt0 = fb_info.fix.smem_start + move; + + if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) + par->bplpt0 += par->next_line; + + return 0; +} + + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + if (IS_AGA) { + if (regno > 255) + return 1; + } else if (currentpar.bplcon0 & BPC0_SHRES) { + if (regno > 3) + return 1; + } else { + if (regno > 31) + return 1; + } + red >>= 8; + green >>= 8; + blue >>= 8; + if (!regno) { + red0 = red; + green0 = green; + blue0 = blue; + } + + /* + * Update the corresponding Hardware Color Register, unless it's Color + * Register 0 and the screen is blanked. + * + * VBlank is switched off to protect bplcon3 or ecs_palette[] from + * being changed by ami_do_blank() during the VBlank. + */ + + if (regno || !is_blanked) { +#if defined(CONFIG_FB_AMIGA_AGA) + if (IS_AGA) { + u_short bplcon3 = currentpar.bplcon3; + VBlankOff(); + custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000); + custom.color[regno&31] = rgb2hw8_high(red, green, blue); + custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT; + custom.color[regno&31] = rgb2hw8_low(red, green, blue); + custom.bplcon3 = bplcon3; + VBlankOn(); + } else +#endif +#if defined(CONFIG_FB_AMIGA_ECS) + if (currentpar.bplcon0 & BPC0_SHRES) { + u_short color, mask; + int i; + + mask = 0x3333; + color = rgb2hw2(red, green, blue); + VBlankOff(); + for (i = regno+12; i >= (int)regno; i -= 4) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + mask <<=2; color >>= 2; + regno = down16(regno)+mul4(mod4(regno)); + for (i = regno+3; i >= (int)regno; i--) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + VBlankOn(); + } else +#endif + custom.color[regno] = rgb2hw4(red, green, blue); + } + return 0; +} + +static void ami_update_display(void) +{ + struct amifb_par *par = ¤tpar; + + custom.bplcon1 = par->bplcon1; + custom.bpl1mod = par->bpl1mod; + custom.bpl2mod = par->bpl2mod; + custom.ddfstrt = ddfstrt2hw(par->ddfstrt); + custom.ddfstop = ddfstop2hw(par->ddfstop); +} + + /* + * Change the video mode (called by VBlank interrupt) + */ + +static void ami_init_display(void) +{ + struct amifb_par *par = ¤tpar; + int i; + + custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; + custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; + if (!IS_OCS) { + custom.bplcon3 = par->bplcon3; + if (IS_AGA) + custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; + if (par->beamcon0 & BMC0_VARBEAMEN) { + custom.htotal = htotal2hw(par->htotal); + custom.hbstrt = hbstrt2hw(par->hbstrt); + custom.hbstop = hbstop2hw(par->hbstop); + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.hcenter = hcenter2hw(par->hcenter); + custom.vtotal = vtotal2hw(par->vtotal); + custom.vbstrt = vbstrt2hw(par->vbstrt); + custom.vbstop = vbstop2hw(par->vbstop); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstop2hw(par->vsstop); + } + } + if (!IS_OCS || par->hsstop) + custom.beamcon0 = par->beamcon0; + if (IS_AGA) + custom.fmode = par->fmode; + + /* + * The minimum period for audio depends on htotal + */ + + amiga_audio_min_period = div16(par->htotal); + + is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; +#if 1 + if (is_lace) { + i = custom.vposr >> 15; + } else { + custom.vposw = custom.vposr | 0x8000; + i = 1; + } +#else + i = 1; + custom.vposw = custom.vposr | 0x8000; +#endif + custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]); +} + + /* + * (Un)Blank the screen (called by VBlank interrupt) + */ + +static void ami_do_blank(void) +{ + struct amifb_par *par = ¤tpar; +#if defined(CONFIG_FB_AMIGA_AGA) + u_short bplcon3 = par->bplcon3; +#endif + u_char red, green, blue; + + if (do_blank > 0) { + custom.dmacon = DMAF_RASTER | DMAF_SPRITE; + red = green = blue = 0; + if (!IS_OCS && do_blank > 1) { + switch (do_blank) { + case FB_BLANK_VSYNC_SUSPEND: + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.vsstrt = vsstrt2hw(par->vtotal+4); + custom.vsstop = vsstop2hw(par->vtotal+4); + break; + case FB_BLANK_HSYNC_SUSPEND: + custom.hsstrt = hsstrt2hw(par->htotal+16); + custom.hsstop = hsstop2hw(par->htotal+16); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstrt2hw(par->vsstop); + break; + case FB_BLANK_POWERDOWN: + custom.hsstrt = hsstrt2hw(par->htotal+16); + custom.hsstop = hsstop2hw(par->htotal+16); + custom.vsstrt = vsstrt2hw(par->vtotal+4); + custom.vsstop = vsstop2hw(par->vtotal+4); + break; + } + if (!(par->beamcon0 & BMC0_VARBEAMEN)) { + custom.htotal = htotal2hw(par->htotal); + custom.vtotal = vtotal2hw(par->vtotal); + custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN | + BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN; + } + } + } else { + custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; + red = red0; + green = green0; + blue = blue0; + if (!IS_OCS) { + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstop2hw(par->vsstop); + custom.beamcon0 = par->beamcon0; + } + } +#if defined(CONFIG_FB_AMIGA_AGA) + if (IS_AGA) { + custom.bplcon3 = bplcon3; + custom.color[0] = rgb2hw8_high(red, green, blue); + custom.bplcon3 = bplcon3 | BPC3_LOCT; + custom.color[0] = rgb2hw8_low(red, green, blue); + custom.bplcon3 = bplcon3; + } else +#endif +#if defined(CONFIG_FB_AMIGA_ECS) + if (par->bplcon0 & BPC0_SHRES) { + u_short color, mask; + int i; + + mask = 0x3333; + color = rgb2hw2(red, green, blue); + for (i = 12; i >= 0; i -= 4) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + mask <<=2; color >>= 2; + for (i = 3; i >= 0; i--) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + } else +#endif + custom.color[0] = rgb2hw4(red, green, blue); + is_blanked = do_blank > 0 ? do_blank : 0; +} + +static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix) +{ + struct amifb_par *par = ¤tpar; + + fix->crsr_width = fix->crsr_xsize = par->crsr.width; + fix->crsr_height = fix->crsr_ysize = par->crsr.height; + fix->crsr_color1 = 17; + fix->crsr_color2 = 18; + return 0; +} + +static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data) +{ + struct amifb_par *par = ¤tpar; + register u_short *lspr, *sspr; +#ifdef __mc68000__ + register u_long datawords asm ("d2"); +#else + register u_long datawords; +#endif + register short delta; + register u_char color; + short height, width, bits, words; + int size, alloc; + + size = par->crsr.height*par->crsr.width; + alloc = var->height*var->width; + var->height = par->crsr.height; + var->width = par->crsr.width; + var->xspot = par->crsr.spot_x; + var->yspot = par->crsr.spot_y; + if (size > var->height*var->width) + return -ENAMETOOLONG; + if (!access_ok(VERIFY_WRITE, (void *)data, size)) + return -EFAULT; + delta = 1<<par->crsr.fmode; + lspr = lofsprite + (delta<<1); + if (par->bplcon0 & BPC0_LACE) + sspr = shfsprite + (delta<<1); + else + sspr = 0; + for (height = (short)var->height-1; height >= 0; height--) { + bits = 0; words = delta; datawords = 0; + for (width = (short)var->width-1; width >= 0; width--) { + if (bits == 0) { + bits = 16; --words; +#ifdef __mc68000__ + asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0" + : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta)); +#else + datawords = (*(lspr+delta) << 16) | (*lspr++); +#endif + } + --bits; +#ifdef __mc68000__ + asm volatile ( + "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; " + "swap %1 ; lslw #1,%1 ; roxlb #1,%0" + : "=d" (color), "=d" (datawords) : "1" (datawords)); +#else + color = (((datawords >> 30) & 2) + | ((datawords >> 15) & 1)); + datawords <<= 1; +#endif + put_user(color, data++); + } + if (bits > 0) { + --words; ++lspr; + } + while (--words >= 0) + ++lspr; +#ifdef __mc68000__ + asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" + : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); +#else + lspr += delta; + if (sspr) { + u_short *tmp = lspr; + lspr = sspr; + sspr = tmp; + } +#endif + } + return 0; +} + +static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data) +{ + struct amifb_par *par = ¤tpar; + register u_short *lspr, *sspr; +#ifdef __mc68000__ + register u_long datawords asm ("d2"); +#else + register u_long datawords; +#endif + register short delta; + u_short fmode; + short height, width, bits, words; + + if (!var->width) + return -EINVAL; + else if (var->width <= 16) + fmode = TAG_FMODE_1; + else if (var->width <= 32) + fmode = TAG_FMODE_2; + else if (var->width <= 64) + fmode = TAG_FMODE_4; + else + return -EINVAL; + if (fmode > maxfmode) + return -EINVAL; + if (!var->height) + return -EINVAL; + if (!access_ok(VERIFY_READ, (void *)data, var->width*var->height)) + return -EFAULT; + delta = 1<<fmode; + lofsprite = shfsprite = (u_short *)spritememory; + lspr = lofsprite + (delta<<1); + if (par->bplcon0 & BPC0_LACE) { + if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE) + return -EINVAL; + memset(lspr, 0, (var->height+4)<<fmode<<2); + shfsprite += ((var->height+5)&-2)<<fmode; + sspr = shfsprite + (delta<<1); + } else { + if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE) + return -EINVAL; + memset(lspr, 0, (var->height+2)<<fmode<<2); + sspr = 0; + } + for (height = (short)var->height-1; height >= 0; height--) { + bits = 16; words = delta; datawords = 0; + for (width = (short)var->width-1; width >= 0; width--) { + unsigned long tdata = 0; + get_user(tdata, (char *)data); + data++; +#ifdef __mc68000__ + asm volatile ( + "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; " + "lsrb #1,%2 ; roxlw #1,%0 ; swap %0" + : "=d" (datawords) + : "0" (datawords), "d" (tdata)); +#else + datawords = ((datawords << 1) & 0xfffefffe); + datawords |= tdata & 1; + datawords |= (tdata & 2) << (16-1); +#endif + if (--bits == 0) { + bits = 16; --words; +#ifdef __mc68000__ + asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta)); +#else + *(lspr+delta) = (u_short) (datawords >> 16); + *lspr++ = (u_short) (datawords & 0xffff); +#endif + } + } + if (bits < 16) { + --words; +#ifdef __mc68000__ + asm volatile ( + "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; " + "swap %2 ; lslw %4,%2 ; movew %2,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits)); +#else + *(lspr+delta) = (u_short) (datawords >> (16+bits)); + *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits); +#endif + } + while (--words >= 0) { +#ifdef __mc68000__ + asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0"); +#else + *(lspr+delta) = 0; + *lspr++ = 0; +#endif + } +#ifdef __mc68000__ + asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" + : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); +#else + lspr += delta; + if (sspr) { + u_short *tmp = lspr; + lspr = sspr; + sspr = tmp; + } +#endif + } + par->crsr.height = var->height; + par->crsr.width = var->width; + par->crsr.spot_x = var->xspot; + par->crsr.spot_y = var->yspot; + par->crsr.fmode = fmode; + if (IS_AGA) { + par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32); + par->fmode |= sprfetchmode[fmode]; + custom.fmode = par->fmode; + } + return 0; +} + +static int ami_get_cursorstate(struct fb_cursorstate *state) +{ + struct amifb_par *par = ¤tpar; + + state->xoffset = par->crsr.crsr_x; + state->yoffset = par->crsr.crsr_y; + state->mode = cursormode; + return 0; +} + +static int ami_set_cursorstate(struct fb_cursorstate *state) +{ + struct amifb_par *par = ¤tpar; + + par->crsr.crsr_x = state->xoffset; + par->crsr.crsr_y = state->yoffset; + if ((cursormode = state->mode) == FB_CURSOR_OFF) + cursorstate = -1; + do_cursor = 1; + return 0; +} + +static void ami_set_sprite(void) +{ + struct amifb_par *par = ¤tpar; + copins *copl, *cops; + u_short hs, vs, ve; + u_long pl, ps, pt; + short mx, my; + + cops = copdisplay.list[currentcop][0]; + copl = copdisplay.list[currentcop][1]; + ps = pl = ZTWO_PADDR(dummysprite); + mx = par->crsr.crsr_x-par->crsr.spot_x; + my = par->crsr.crsr_y-par->crsr.spot_y; + if (!(par->vmode & FB_VMODE_YWRAP)) { + mx -= par->xoffset; + my -= par->yoffset; + } + if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 && + mx > -(short)par->crsr.width && mx < par->xres && + my > -(short)par->crsr.height && my < par->yres) { + pl = ZTWO_PADDR(lofsprite); + hs = par->diwstrt_h + (mx<<par->clk_shift) - 4; + vs = par->diwstrt_v + (my<<par->line_shift); + ve = vs + (par->crsr.height<<par->line_shift); + if (par->bplcon0 & BPC0_LACE) { + ps = ZTWO_PADDR(shfsprite); + lofsprite[0] = spr2hw_pos(vs, hs); + shfsprite[0] = spr2hw_pos(vs+1, hs); + if (mod2(vs)) { + lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); + shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1); + pt = pl; pl = ps; ps = pt; + } else { + lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1); + shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve); + } + } else { + lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0); + lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); + } + } + copl[cop_spr0ptrh].w[1] = highw(pl); + copl[cop_spr0ptrl].w[1] = loww(pl); + if (par->bplcon0 & BPC0_LACE) { + cops[cop_spr0ptrh].w[1] = highw(ps); + cops[cop_spr0ptrl].w[1] = loww(ps); + } +} + + + /* + * Initialise the Copper Initialisation List + */ + +static void __init ami_init_copper(void) +{ + copins *cop = copdisplay.init; + u_long p; + int i; + + if (!IS_OCS) { + (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); + (cop++)->l = CMOVE(0x0181, diwstrt); + (cop++)->l = CMOVE(0x0281, diwstop); + (cop++)->l = CMOVE(0x0000, diwhigh); + } else + (cop++)->l = CMOVE(BPC0_COLOR, bplcon0); + p = ZTWO_PADDR(dummysprite); + for (i = 0; i < 8; i++) { + (cop++)->l = CMOVE(0, spr[i].pos); + (cop++)->l = CMOVE(highw(p), sprpt[i]); + (cop++)->l = CMOVE2(loww(p), sprpt[i]); + } + + (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq); + copdisplay.wait = cop; + (cop++)->l = CEND; + (cop++)->l = CMOVE(0, copjmp2); + cop->l = CEND; + + custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init); + custom.copjmp1 = 0; +} + +static void ami_reinit_copper(void) +{ + struct amifb_par *par = ¤tpar; + + copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; + copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4); +} + + /* + * Build the Copper List + */ + +static void ami_build_copper(void) +{ + struct amifb_par *par = ¤tpar; + copins *copl, *cops; + u_long p; + + currentcop = 1 - currentcop; + + copl = copdisplay.list[currentcop][1]; + + (copl++)->l = CWAIT(0, 10); + (copl++)->l = CMOVE(par->bplcon0, bplcon0); + (copl++)->l = CMOVE(0, sprpt[0]); + (copl++)->l = CMOVE2(0, sprpt[0]); + + if (par->bplcon0 & BPC0_LACE) { + cops = copdisplay.list[currentcop][0]; + + (cops++)->l = CWAIT(0, 10); + (cops++)->l = CMOVE(par->bplcon0, bplcon0); + (cops++)->l = CMOVE(0, sprpt[0]); + (cops++)->l = CMOVE2(0, sprpt[0]); + + (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt); + (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop); + (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); + (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); + if (!IS_OCS) { + (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1, + par->diwstop_h, par->diwstop_v+1), diwhigh); + (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, + par->diwstop_h, par->diwstop_v), diwhigh); +#if 0 + if (par->beamcon0 & BMC0_VARBEAMEN) { + (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt); + (copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop); + (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); + (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); + } +#endif + } + p = ZTWO_PADDR(copdisplay.list[currentcop][0]); + (copl++)->l = CMOVE(highw(p), cop2lc); + (copl++)->l = CMOVE2(loww(p), cop2lc); + p = ZTWO_PADDR(copdisplay.list[currentcop][1]); + (cops++)->l = CMOVE(highw(p), cop2lc); + (cops++)->l = CMOVE2(loww(p), cop2lc); + copdisplay.rebuild[0] = cops; + } else { + (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); + (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); + if (!IS_OCS) { + (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, + par->diwstop_h, par->diwstop_v), diwhigh); +#if 0 + if (par->beamcon0 & BMC0_VARBEAMEN) { + (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); + (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); + } +#endif + } + } + copdisplay.rebuild[1] = copl; + + ami_update_par(); + ami_rebuild_copper(); +} + + /* + * Rebuild the Copper List + * + * We only change the things that are not static + */ + +static void ami_rebuild_copper(void) +{ + struct amifb_par *par = ¤tpar; + copins *copl, *cops; + u_short line, h_end1, h_end2; + short i; + u_long p; + + if (IS_AGA && maxfmode + par->clk_shift == 0) + h_end1 = par->diwstrt_h-64; + else + h_end1 = par->htotal-32; + h_end2 = par->ddfstop+64; + + ami_set_sprite(); + + copl = copdisplay.rebuild[1]; + p = par->bplpt0; + if (par->vmode & FB_VMODE_YWRAP) { + if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) { + if (par->yoffset > par->vyres-par->yres) { + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (copl++)->l = CMOVE(highw(p), bplpt[i]); + (copl++)->l = CMOVE2(loww(p), bplpt[i]); + } + line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1; + while (line >= 512) { + (copl++)->l = CWAIT(h_end1, 510); + line -= 512; + } + if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0) + (copl++)->l = CWAIT(h_end1, line); + else + (copl++)->l = CWAIT(h_end2, line); + p = par->bplpt0wrap; + } + } else p = par->bplpt0wrap; + } + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (copl++)->l = CMOVE(highw(p), bplpt[i]); + (copl++)->l = CMOVE2(loww(p), bplpt[i]); + } + copl->l = CEND; + + if (par->bplcon0 & BPC0_LACE) { + cops = copdisplay.rebuild[0]; + p = par->bplpt0; + if (mod2(par->diwstrt_v)) + p -= par->next_line; + else + p += par->next_line; + if (par->vmode & FB_VMODE_YWRAP) { + if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) { + if (par->yoffset > par->vyres-par->yres+1) { + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (cops++)->l = CMOVE(highw(p), bplpt[i]); + (cops++)->l = CMOVE2(loww(p), bplpt[i]); + } + line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2; + while (line >= 512) { + (cops++)->l = CWAIT(h_end1, 510); + line -= 512; + } + if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0) + (cops++)->l = CWAIT(h_end1, line); + else + (cops++)->l = CWAIT(h_end2, line); + p = par->bplpt0wrap; + if (mod2(par->diwstrt_v+par->vyres-par->yoffset)) + p -= par->next_line; + else + p += par->next_line; + } + } else p = par->bplpt0wrap - par->next_line; + } + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (cops++)->l = CMOVE(highw(p), bplpt[i]); + (cops++)->l = CMOVE2(loww(p), bplpt[i]); + } + cops->l = CEND; + } +} + + +module_init(amifb_init); + +#ifdef MODULE +MODULE_LICENSE("GPL"); + +void cleanup_module(void) +{ + unregister_framebuffer(&fb_info); + amifb_deinit(); + amifb_video_off(); +} +#endif /* MODULE */ diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c new file mode 100644 index 000000000000..f4729f4df8ce --- /dev/null +++ b/drivers/video/asiliantfb.c @@ -0,0 +1,617 @@ +/* + * drivers/video/asiliantfb.c + * frame buffer driver for Asiliant 69000 chip + * Copyright (C) 2001-2003 Saito.K & Jeanne + * + * from driver/video/chipsfb.c and, + * + * drivers/video/asiliantfb.c -- frame buffer device for + * Asiliant 69030 chip (formerly Intel, formerly Chips & Technologies) + * Author: apc@agelectronics.co.uk + * Copyright (C) 2000 AG Electronics + * Note: the data sheets don't seem to be available from Asiliant. + * They are available by searching developer.intel.com, but are not otherwise + * linked to. + * + * This driver should be portable with minimal effort to the 69000 display + * chip, and to the twin-display mode of the 69030. + * Contains code from Thomas Hhenleitner <th@visuelle-maschinen.de> (thanks) + * + * Derived from the CT65550 driver chipsfb.c: + * Copyright (C) 1998 Paul Mackerras + * ...which was derived from the Powermac "chips" driver: + * Copyright (C) 1997 Fabio Riccardi. + * And from the frame buffer device for Open Firmware-initialized devices: + * Copyright (C) 1997 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. + */ + +#include <linux/config.h> +#include <linux/module.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <asm/io.h> + +/* Built in clock of the 69030 */ +static const unsigned Fref = 14318180; + +#define mmio_base (p->screen_base + 0x400000) + +#define mm_write_ind(num, val, ap, dp) do { \ + writeb((num), mmio_base + (ap)); writeb((val), mmio_base + (dp)); \ +} while (0) + +static void mm_write_xr(struct fb_info *p, u8 reg, u8 data) +{ + mm_write_ind(reg, data, 0x7ac, 0x7ad); +} +#define write_xr(num, val) mm_write_xr(p, num, val) + +static void mm_write_fr(struct fb_info *p, u8 reg, u8 data) +{ + mm_write_ind(reg, data, 0x7a0, 0x7a1); +} +#define write_fr(num, val) mm_write_fr(p, num, val) + +static void mm_write_cr(struct fb_info *p, u8 reg, u8 data) +{ + mm_write_ind(reg, data, 0x7a8, 0x7a9); +} +#define write_cr(num, val) mm_write_cr(p, num, val) + +static void mm_write_gr(struct fb_info *p, u8 reg, u8 data) +{ + mm_write_ind(reg, data, 0x79c, 0x79d); +} +#define write_gr(num, val) mm_write_gr(p, num, val) + +static void mm_write_sr(struct fb_info *p, u8 reg, u8 data) +{ + mm_write_ind(reg, data, 0x788, 0x789); +} +#define write_sr(num, val) mm_write_sr(p, num, val) + +static void mm_write_ar(struct fb_info *p, u8 reg, u8 data) +{ + readb(mmio_base + 0x7b4); + mm_write_ind(reg, data, 0x780, 0x780); +} +#define write_ar(num, val) mm_write_ar(p, num, val) + +static int asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *); +static int asiliantfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int asiliantfb_set_par(struct fb_info *info); +static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); + +static struct fb_ops asiliantfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = asiliantfb_check_var, + .fb_set_par = asiliantfb_set_par, + .fb_setcolreg = asiliantfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +/* Calculate the ratios for the dot clocks without using a single long long + * value */ +static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dclk2_div) +{ + unsigned pixclock = *ppixclock; + unsigned Ftarget = 1000000 * (1000000 / pixclock); + unsigned n; + unsigned best_error = 0xffffffff; + unsigned best_m = 0xffffffff, + best_n = 0xffffffff; + unsigned ratio; + unsigned remainder; + unsigned char divisor = 0; + + /* Calculate the frequency required. This is hard enough. */ + ratio = 1000000 / pixclock; + remainder = 1000000 % pixclock; + Ftarget = 1000000 * ratio + (1000000 * remainder) / pixclock; + + while (Ftarget < 100000000) { + divisor += 0x10; + Ftarget <<= 1; + } + + ratio = Ftarget / Fref; + remainder = Ftarget % Fref; + + /* This expresses the constraint that 150kHz <= Fref/n <= 5Mhz, + * together with 3 <= n <= 257. */ + for (n = 3; n <= 257; n++) { + unsigned m = n * ratio + (n * remainder) / Fref; + + /* 3 <= m <= 257 */ + if (m >= 3 && m <= 257) { + unsigned new_error = ((Ftarget * n) - (Fref * m)) >= 0 ? + ((Ftarget * n) - (Fref * m)) : ((Fref * m) - (Ftarget * n)); + if (new_error < best_error) { + best_n = n; + best_m = m; + best_error = new_error; + } + } + /* But if VLD = 4, then 4m <= 1028 */ + else if (m <= 1028) { + /* remember there are still only 8-bits of precision in m, so + * avoid over-optimistic error calculations */ + unsigned new_error = ((Ftarget * n) - (Fref * (m & ~3))) >= 0 ? + ((Ftarget * n) - (Fref * (m & ~3))) : ((Fref * (m & ~3)) - (Ftarget * n)); + if (new_error < best_error) { + best_n = n; + best_m = m; + best_error = new_error; + } + } + } + if (best_m > 257) + best_m >>= 2; /* divide m by 4, and leave VCO loop divide at 4 */ + else + divisor |= 4; /* or set VCO loop divide to 1 */ + *dclk2_m = best_m - 2; + *dclk2_n = best_n - 2; + *dclk2_div = divisor; + *ppixclock = pixclock; + return; +} + +static void asiliant_set_timing(struct fb_info *p) +{ + unsigned hd = p->var.xres / 8; + unsigned hs = (p->var.xres + p->var.right_margin) / 8; + unsigned he = (p->var.xres + p->var.right_margin + p->var.hsync_len) / 8; + unsigned ht = (p->var.left_margin + p->var.xres + p->var.right_margin + p->var.hsync_len) / 8; + unsigned vd = p->var.yres; + unsigned vs = p->var.yres + p->var.lower_margin; + unsigned ve = p->var.yres + p->var.lower_margin + p->var.vsync_len; + unsigned vt = p->var.upper_margin + p->var.yres + p->var.lower_margin + p->var.vsync_len; + unsigned wd = (p->var.xres_virtual * ((p->var.bits_per_pixel+7)/8)) / 8; + + if ((p->var.xres == 640) && (p->var.yres == 480) && (p->var.pixclock == 39722)) { + write_fr(0x01, 0x02); /* LCD */ + } else { + write_fr(0x01, 0x01); /* CRT */ + } + + write_cr(0x11, (ve - 1) & 0x0f); + write_cr(0x00, (ht - 5) & 0xff); + write_cr(0x01, hd - 1); + write_cr(0x02, hd); + write_cr(0x03, ((ht - 1) & 0x1f) | 0x80); + write_cr(0x04, hs); + write_cr(0x05, (((ht - 1) & 0x20) <<2) | (he & 0x1f)); + write_cr(0x3c, (ht - 1) & 0xc0); + write_cr(0x06, (vt - 2) & 0xff); + write_cr(0x30, (vt - 2) >> 8); + write_cr(0x07, 0x00); + write_cr(0x08, 0x00); + write_cr(0x09, 0x00); + write_cr(0x10, (vs - 1) & 0xff); + write_cr(0x32, ((vs - 1) >> 8) & 0xf); + write_cr(0x11, ((ve - 1) & 0x0f) | 0x80); + write_cr(0x12, (vd - 1) & 0xff); + write_cr(0x31, ((vd - 1) & 0xf00) >> 8); + write_cr(0x13, wd & 0xff); + write_cr(0x41, (wd & 0xf00) >> 8); + write_cr(0x15, (vs - 1) & 0xff); + write_cr(0x33, ((vs - 1) >> 8) & 0xf); + write_cr(0x38, ((ht - 5) & 0x100) >> 8); + write_cr(0x16, (vt - 1) & 0xff); + write_cr(0x18, 0x00); + + if (p->var.xres == 640) { + writeb(0xc7, mmio_base + 0x784); /* set misc output reg */ + } else { + writeb(0x07, mmio_base + 0x784); /* set misc output reg */ + } +} + +static int asiliantfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *p) +{ + unsigned long Ftarget, ratio, remainder; + + ratio = 1000000 / var->pixclock; + remainder = 1000000 % var->pixclock; + Ftarget = 1000000 * ratio + (1000000 * remainder) / var->pixclock; + + /* First check the constraint that the maximum post-VCO divisor is 32, + * and the maximum Fvco is 220MHz */ + if (Ftarget > 220000000 || Ftarget < 3125000) { + printk(KERN_ERR "asiliantfb dotclock must be between 3.125 and 220MHz\n"); + return -ENXIO; + } + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; + + if (var->bits_per_pixel == 24) { + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = var->blue.length = var->green.length = 8; + } else if (var->bits_per_pixel == 16) { + switch (var->red.offset) { + case 11: + var->green.length = 6; + break; + case 10: + var->green.length = 5; + break; + default: + return -EINVAL; + } + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = var->blue.length = 5; + } else if (var->bits_per_pixel == 8) { + var->red.offset = var->green.offset = var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = 8; + } + return 0; +} + +static int asiliantfb_set_par(struct fb_info *p) +{ + u8 dclk2_m; /* Holds m-2 value for register */ + u8 dclk2_n; /* Holds n-2 value for register */ + u8 dclk2_div; /* Holds divisor bitmask */ + + /* Set pixclock */ + asiliant_calc_dclk2(&p->var.pixclock, &dclk2_m, &dclk2_n, &dclk2_div); + + /* Set color depth */ + if (p->var.bits_per_pixel == 24) { + write_xr(0x81, 0x16); /* 24 bit packed color mode */ + write_xr(0x82, 0x00); /* Disable palettes */ + write_xr(0x20, 0x20); /* 24 bit blitter mode */ + } else if (p->var.bits_per_pixel == 16) { + if (p->var.red.offset == 11) + write_xr(0x81, 0x15); /* 16 bit color mode */ + else + write_xr(0x81, 0x14); /* 15 bit color mode */ + write_xr(0x82, 0x00); /* Disable palettes */ + write_xr(0x20, 0x10); /* 16 bit blitter mode */ + } else if (p->var.bits_per_pixel == 8) { + write_xr(0x0a, 0x02); /* Linear */ + write_xr(0x81, 0x12); /* 8 bit color mode */ + write_xr(0x82, 0x00); /* Graphics gamma enable */ + write_xr(0x20, 0x00); /* 8 bit blitter mode */ + } + p->fix.line_length = p->var.xres * (p->var.bits_per_pixel >> 3); + p->fix.visual = (p->var.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + write_xr(0xc4, dclk2_m); + write_xr(0xc5, dclk2_n); + write_xr(0xc7, dclk2_div); + /* Set up the CR registers */ + asiliant_set_timing(p); + return 0; +} + +static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *p) +{ + if (regno > 255) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + + /* Set hardware palete */ + writeb(regno, mmio_base + 0x790); + udelay(1); + writeb(red, mmio_base + 0x791); + writeb(green, mmio_base + 0x791); + writeb(blue, mmio_base + 0x791); + + switch(p->var.bits_per_pixel) { + case 15: + if (regno < 16) { + ((u32 *)(p->pseudo_palette))[regno] = + ((red & 0xf8) << 7) | + ((green & 0xf8) << 2) | + ((blue & 0xf8) >> 3); + } + break; + case 16: + if (regno < 16) { + ((u32 *)(p->pseudo_palette))[regno] = + ((red & 0xf8) << 8) | + ((green & 0xfc) << 3) | + ((blue & 0xf8) >> 3); + } + break; + case 24: + if (regno < 24) { + ((u32 *)(p->pseudo_palette))[regno] = + (red << 16) | + (green << 8) | + (blue); + } + break; + } + return 0; +} + +struct chips_init_reg { + unsigned char addr; + unsigned char data; +}; + +#define N_ELTS(x) (sizeof(x) / sizeof(x[0])) + +static struct chips_init_reg chips_init_sr[] = +{ + {0x00, 0x03}, /* Reset register */ + {0x01, 0x01}, /* Clocking mode */ + {0x02, 0x0f}, /* Plane mask */ + {0x04, 0x0e} /* Memory mode */ +}; + +static struct chips_init_reg chips_init_gr[] = +{ + {0x03, 0x00}, /* Data rotate */ + {0x05, 0x00}, /* Graphics mode */ + {0x06, 0x01}, /* Miscellaneous */ + {0x08, 0x00} /* Bit mask */ +}; + +static struct chips_init_reg chips_init_ar[] = +{ + {0x10, 0x01}, /* Mode control */ + {0x11, 0x00}, /* Overscan */ + {0x12, 0x0f}, /* Memory plane enable */ + {0x13, 0x00} /* Horizontal pixel panning */ +}; + +static struct chips_init_reg chips_init_cr[] = +{ + {0x0c, 0x00}, /* Start address high */ + {0x0d, 0x00}, /* Start address low */ + {0x40, 0x00}, /* Extended Start Address */ + {0x41, 0x00}, /* Extended Start Address */ + {0x14, 0x00}, /* Underline location */ + {0x17, 0xe3}, /* CRT mode control */ + {0x70, 0x00} /* Interlace control */ +}; + + +static struct chips_init_reg chips_init_fr[] = +{ + {0x01, 0x02}, + {0x03, 0x08}, + {0x08, 0xcc}, + {0x0a, 0x08}, + {0x18, 0x00}, + {0x1e, 0x80}, + {0x40, 0x83}, + {0x41, 0x00}, + {0x48, 0x13}, + {0x4d, 0x60}, + {0x4e, 0x0f}, + + {0x0b, 0x01}, + + {0x21, 0x51}, + {0x22, 0x1d}, + {0x23, 0x5f}, + {0x20, 0x4f}, + {0x34, 0x00}, + {0x24, 0x51}, + {0x25, 0x00}, + {0x27, 0x0b}, + {0x26, 0x00}, + {0x37, 0x80}, + {0x33, 0x0b}, + {0x35, 0x11}, + {0x36, 0x02}, + {0x31, 0xea}, + {0x32, 0x0c}, + {0x30, 0xdf}, + {0x10, 0x0c}, + {0x11, 0xe0}, + {0x12, 0x50}, + {0x13, 0x00}, + {0x16, 0x03}, + {0x17, 0xbd}, + {0x1a, 0x00}, +}; + + +static struct chips_init_reg chips_init_xr[] = +{ + {0xce, 0x00}, /* set default memory clock */ + {0xcc, 200 }, /* MCLK ratio M */ + {0xcd, 18 }, /* MCLK ratio N */ + {0xce, 0x90}, /* MCLK divisor = 2 */ + + {0xc4, 209 }, + {0xc5, 118 }, + {0xc7, 32 }, + {0xcf, 0x06}, + {0x09, 0x01}, /* IO Control - CRT controller extensions */ + {0x0a, 0x02}, /* Frame buffer mapping */ + {0x0b, 0x01}, /* PCI burst write */ + {0x40, 0x03}, /* Memory access control */ + {0x80, 0x82}, /* Pixel pipeline configuration 0 */ + {0x81, 0x12}, /* Pixel pipeline configuration 1 */ + {0x82, 0x08}, /* Pixel pipeline configuration 2 */ + + {0xd0, 0x0f}, + {0xd1, 0x01}, +}; + +static void __devinit chips_hw_init(struct fb_info *p) +{ + int i; + + for (i = 0; i < N_ELTS(chips_init_xr); ++i) + write_xr(chips_init_xr[i].addr, chips_init_xr[i].data); + write_xr(0x81, 0x12); + write_xr(0x82, 0x08); + write_xr(0x20, 0x00); + for (i = 0; i < N_ELTS(chips_init_sr); ++i) + write_sr(chips_init_sr[i].addr, chips_init_sr[i].data); + for (i = 0; i < N_ELTS(chips_init_gr); ++i) + write_gr(chips_init_gr[i].addr, chips_init_gr[i].data); + for (i = 0; i < N_ELTS(chips_init_ar); ++i) + write_ar(chips_init_ar[i].addr, chips_init_ar[i].data); + /* Enable video output in attribute index register */ + writeb(0x20, mmio_base + 0x780); + for (i = 0; i < N_ELTS(chips_init_cr); ++i) + write_cr(chips_init_cr[i].addr, chips_init_cr[i].data); + for (i = 0; i < N_ELTS(chips_init_fr); ++i) + write_fr(chips_init_fr[i].addr, chips_init_fr[i].data); +} + +static struct fb_fix_screeninfo asiliantfb_fix __devinitdata = { + .id = "Asiliant 69000", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .accel = FB_ACCEL_NONE, + .line_length = 640, + .smem_len = 0x200000, /* 2MB */ +}; + +static struct fb_var_screeninfo asiliantfb_var __devinitdata = { + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 480, + .bits_per_pixel = 8, + .red = { .length = 8 }, + .green = { .length = 8 }, + .blue = { .length = 8 }, + .height = -1, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, + .pixclock = 39722, + .left_margin = 48, + .right_margin = 16, + .upper_margin = 33, + .lower_margin = 10, + .hsync_len = 96, + .vsync_len = 2, +}; + +static void __devinit init_asiliant(struct fb_info *p, unsigned long addr) +{ + p->fix = asiliantfb_fix; + p->fix.smem_start = addr; + p->var = asiliantfb_var; + p->fbops = &asiliantfb_ops; + p->flags = FBINFO_DEFAULT; + + fb_alloc_cmap(&p->cmap, 256, 0); + + if (register_framebuffer(p) < 0) { + printk(KERN_ERR "C&T 69000 framebuffer failed to register\n"); + return; + } + + printk(KERN_INFO "fb%d: Asiliant 69000 frame buffer (%dK RAM detected)\n", + p->node, p->fix.smem_len / 1024); + + writeb(0xff, mmio_base + 0x78c); + chips_hw_init(p); +} + +static int __devinit +asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) +{ + unsigned long addr, size; + struct fb_info *p; + + if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) + return -ENODEV; + addr = pci_resource_start(dp, 0); + size = pci_resource_len(dp, 0); + if (addr == 0) + return -ENODEV; + if (!request_mem_region(addr, size, "asiliantfb")) + return -EBUSY; + + p = framebuffer_alloc(sizeof(u32) * 256, &dp->dev); + if (!p) { + release_mem_region(addr, size); + return -ENOMEM; + } + p->pseudo_palette = p->par; + p->par = NULL; + + p->screen_base = ioremap(addr, 0x800000); + if (p->screen_base == NULL) { + release_mem_region(addr, size); + framebuffer_release(p); + return -ENOMEM; + } + + pci_write_config_dword(dp, 4, 0x02800083); + writeb(3, p->screen_base + 0x400784); + + init_asiliant(p, addr); + + pci_set_drvdata(dp, p); + return 0; +} + +static void __devexit asiliantfb_remove(struct pci_dev *dp) +{ + struct fb_info *p = pci_get_drvdata(dp); + + unregister_framebuffer(p); + iounmap(p->screen_base); + release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0)); + pci_set_drvdata(dp, NULL); + framebuffer_release(p); +} + +static struct pci_device_id asiliantfb_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_69000, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, asiliantfb_pci_tbl); + +static struct pci_driver asiliantfb_driver = { + .name = "asiliantfb", + .id_table = asiliantfb_pci_tbl, + .probe = asiliantfb_pci_init, + .remove = __devexit_p(asiliantfb_remove), +}; + +static int __init asiliantfb_init(void) +{ + if (fb_get_options("asiliantfb", NULL)) + return -ENODEV; + + return pci_register_driver(&asiliantfb_driver); +} + +module_init(asiliantfb_init); + +static void __exit asiliantfb_exit(void) +{ + pci_unregister_driver(&asiliantfb_driver); +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c new file mode 100644 index 000000000000..15ec1295bc29 --- /dev/null +++ b/drivers/video/atafb.c @@ -0,0 +1,3098 @@ +/* + * linux/drivers/video/atafb.c -- Atari builtin chipset frame buffer device + * + * Copyright (C) 1994 Martin Schaller & Roman Hodek + * + * 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. + * + * History: + * - 03 Jan 95: Original version by Martin Schaller: The TT driver and + * all the device independent stuff + * - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch) + * and wrote the Falcon, ST(E), and External drivers + * based on the original TT driver. + * - 07 May 95: Martin: Added colormap operations for the external driver + * - 21 May 95: Martin: Added support for overscan + * Andreas: some bug fixes for this + * - Jul 95: Guenther Kelleter <guenther@pool.informatik.rwth-aachen.de>: + * Programmable Falcon video modes + * (thanks to Christian Cartus for documentation + * of VIDEL registers). + * - 27 Dec 95: Guenther: Implemented user definable video modes "user[0-7]" + * on minor 24...31. "user0" may be set on commandline by + * "R<x>;<y>;<depth>". (Makes sense only on Falcon) + * Video mode switch on Falcon now done at next VBL interrupt + * to avoid the annoying right shift of the screen. + * - 23 Sep 97: Juergen: added xres_virtual for cards like ProMST + * The external-part is legacy, therefore hardware-specific + * functions like panning/hardwarescrolling/blanking isn't + * supported. + * - 29 Sep 97: Juergen: added Romans suggestion for pan_display + * (var->xoffset was changed even if no set_screen_base avail.) + * - 05 Oct 97: Juergen: extfb (PACKED_PIXEL) is FB_PSEUDOCOLOR 'cause + * we know how to set the colors + * ext_*palette: read from ext_colors (former MV300_colors) + * write to ext_colors and RAMDAC + * + * To do: + * - For the Falcon it is not possible to set random video modes on + * SM124 and SC/TV, only the bootup resolution is supported. + * + */ + +#define ATAFB_TT +#define ATAFB_STE +#define ATAFB_EXT +#define ATAFB_FALCON + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#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/init.h> +#include <linux/interrupt.h> + +#include <asm/setup.h> +#include <asm/uaccess.h> +#include <asm/pgtable.h> +#include <asm/irq.h> +#include <asm/io.h> + +#include <asm/atarihw.h> +#include <asm/atariints.h> +#include <asm/atari_stram.h> + +#include <linux/fb.h> +#include <asm/atarikb.h> + +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-iplan2p2.h> +#include <video/fbcon-iplan2p4.h> +#include <video/fbcon-iplan2p8.h> +#include <video/fbcon-mfb.h> + + +#define SWITCH_ACIA 0x01 /* modes for switch on OverScan */ +#define SWITCH_SND6 0x40 +#define SWITCH_SND7 0x80 +#define SWITCH_NONE 0x00 + + +#define up(x, r) (((x) + (r) - 1) & ~((r)-1)) + + +static int default_par=0; /* default resolution (0=none) */ + +static unsigned long default_mem_req=0; + +static int hwscroll=-1; + +static int use_hwscroll = 1; + +static int sttt_xres=640,st_yres=400,tt_yres=480; +static int sttt_xres_virtual=640,sttt_yres_virtual=400; +static int ovsc_offset=0, ovsc_addlen=0; + +static struct atafb_par { + void *screen_base; + int yres_virtual; +#if defined ATAFB_TT || defined ATAFB_STE + union { + struct { + int mode; + int sync; + } tt, st; +#endif +#ifdef ATAFB_FALCON + struct falcon_hw { + /* Here are fields for storing a video mode, as direct + * parameters for the hardware. + */ + short sync; + short line_width; + short line_offset; + short st_shift; + short f_shift; + short vid_control; + short vid_mode; + short xoffset; + short hht, hbb, hbe, hdb, hde, hss; + short vft, vbb, vbe, vdb, vde, vss; + /* auxiliary information */ + short mono; + short ste_mode; + short bpp; + } falcon; +#endif + /* Nothing needed for external mode */ + } hw; +} current_par; + +/* Don't calculate an own resolution, and thus don't change the one found when + * booting (currently used for the Falcon to keep settings for internal video + * hardware extensions (e.g. ScreenBlaster) */ +static int DontCalcRes = 0; + +#ifdef ATAFB_FALCON +#define HHT hw.falcon.hht +#define HBB hw.falcon.hbb +#define HBE hw.falcon.hbe +#define HDB hw.falcon.hdb +#define HDE hw.falcon.hde +#define HSS hw.falcon.hss +#define VFT hw.falcon.vft +#define VBB hw.falcon.vbb +#define VBE hw.falcon.vbe +#define VDB hw.falcon.vdb +#define VDE hw.falcon.vde +#define VSS hw.falcon.vss +#define VCO_CLOCK25 0x04 +#define VCO_CSYPOS 0x10 +#define VCO_VSYPOS 0x20 +#define VCO_HSYPOS 0x40 +#define VCO_SHORTOFFS 0x100 +#define VMO_DOUBLE 0x01 +#define VMO_INTER 0x02 +#define VMO_PREMASK 0x0c +#endif + +static struct fb_info fb_info; + +static void *screen_base; /* base address of screen */ +static void *real_screen_base; /* (only for Overscan) */ + +static int screen_len; + +static int current_par_valid=0; + +static int mono_moni=0; + +static struct display disp; + + +#ifdef ATAFB_EXT +/* external video handling */ + +static unsigned external_xres; +static unsigned external_xres_virtual; +static unsigned external_yres; +/* not needed - atafb will never support panning/hardwarescroll with external + * static unsigned external_yres_virtual; +*/ + +static unsigned external_depth; +static int external_pmode; +static void *external_addr = 0; +static unsigned long external_len; +static unsigned long external_vgaiobase = 0; +static unsigned int external_bitspercol = 6; + +/* +JOE <joe@amber.dinoco.de>: +added card type for external driver, is only needed for +colormap handling. +*/ + +enum cardtype { IS_VGA, IS_MV300 }; +static enum cardtype external_card_type = IS_VGA; + +/* +The MV300 mixes the color registers. So we need an array of munged +indices in order to access the correct reg. +*/ +static int MV300_reg_1bit[2]={0,1}; +static int MV300_reg_4bit[16]={ +0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; +static int MV300_reg_8bit[256]={ +0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, +8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, +4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, +12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, +2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, +10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, +6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, +14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, +1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, +9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, +5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, +13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, +3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, +11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, +7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, +15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 }; + +static int *MV300_reg = MV300_reg_8bit; + +/* +And on the MV300 it's difficult to read out the hardware palette. So we +just keep track of the set colors in our own array here, and use that! +*/ + +static struct { unsigned char red,green,blue,pad; } ext_color[256]; +#endif /* ATAFB_EXT */ + + +static int inverse=0; + +extern int fontheight_8x8; +extern int fontwidth_8x8; +extern unsigned char fontdata_8x8[]; + +extern int fontheight_8x16; +extern int fontwidth_8x16; +extern unsigned char fontdata_8x16[]; + +/* ++roman: This structure abstracts from the underlying hardware (ST(e), + * TT, or Falcon. + * + * int (*detect)( void ) + * This function should detect the current video mode settings and + * store them in atafb_predefined[0] for later reference by the + * user. Return the index+1 of an equivalent predefined mode or 0 + * if there is no such. + * + * int (*encode_fix)( struct fb_fix_screeninfo *fix, + * struct atafb_par *par ) + * This function should fill in the 'fix' structure based on the + * values in the 'par' structure. + * + * int (*decode_var)( struct fb_var_screeninfo *var, + * struct atafb_par *par ) + * Get the video params out of 'var'. If a value doesn't fit, round + * it up, if it's too big, return EINVAL. + * Round up in the following order: bits_per_pixel, xres, yres, + * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, + * horizontal timing, vertical timing. + * + * int (*encode_var)( struct fb_var_screeninfo *var, + * struct atafb_par *par ); + * Fill the 'var' structure based on the values in 'par' and maybe + * other values read out of the hardware. + * + * void (*get_par)( struct atafb_par *par ) + * Fill the hardware's 'par' structure. + * + * void (*set_par)( struct atafb_par *par ) + * Set the hardware according to 'par'. + * + * int (*getcolreg)( unsigned regno, unsigned *red, + * unsigned *green, unsigned *blue, + * unsigned *transp, struct fb_info *info ) + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + * + * void (*set_screen_base)(void *s_base) + * Set the base address of the displayed frame buffer. Only called + * if yres_virtual > yres or xres_virtual > xres. + * + * int (*blank)( int blank_mode ) + * Blank the screen if blank_mode!=0, else unblank. If blank==NULL then + * the caller blanks by setting the CLUT to all black. Return 0 if blanking + * succeeded, !=0 if un-/blanking failed due to e.g. a video mode which + * doesn't support it. Implements VESA suspend and powerdown modes on + * hardware that supports disabling hsync/vsync: + * blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown. + */ + +static struct fb_hwswitch { + int (*detect)( void ); + int (*encode_fix)( struct fb_fix_screeninfo *fix, + struct atafb_par *par ); + int (*decode_var)( struct fb_var_screeninfo *var, + struct atafb_par *par ); + int (*encode_var)( struct fb_var_screeninfo *var, + struct atafb_par *par ); + void (*get_par)( struct atafb_par *par ); + void (*set_par)( struct atafb_par *par ); + int (*getcolreg)( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp, struct fb_info *info ); + void (*set_screen_base)(void *s_base); + int (*blank)( int blank_mode ); + int (*pan_display)( struct fb_var_screeninfo *var, + struct atafb_par *par); +} *fbhw; + +static char *autodetect_names[] = {"autodetect", NULL}; +static char *stlow_names[] = {"stlow", NULL}; +static char *stmid_names[] = {"stmid", "default5", NULL}; +static char *sthigh_names[] = {"sthigh", "default4", NULL}; +static char *ttlow_names[] = {"ttlow", NULL}; +static char *ttmid_names[]= {"ttmid", "default1", NULL}; +static char *tthigh_names[]= {"tthigh", "default2", NULL}; +static char *vga2_names[] = {"vga2", NULL}; +static char *vga4_names[] = {"vga4", NULL}; +static char *vga16_names[] = {"vga16", "default3", NULL}; +static char *vga256_names[] = {"vga256", NULL}; +static char *falh2_names[] = {"falh2", NULL}; +static char *falh16_names[] = {"falh16", NULL}; + +static char **fb_var_names[] = { + /* Writing the name arrays directly in this array (via "(char *[]){...}") + * crashes gcc 2.5.8 (sigsegv) if the inner array + * contains more than two items. I've also seen that all elements + * were identical to the last (my cross-gcc) :-(*/ + autodetect_names, + stlow_names, + stmid_names, + sthigh_names, + ttlow_names, + ttmid_names, + tthigh_names, + vga2_names, + vga4_names, + vga16_names, + vga256_names, + falh2_names, + falh16_names, + NULL + /* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */ +}; + +static struct fb_var_screeninfo atafb_predefined[] = { + /* + * yres_virtual==0 means use hw-scrolling if possible, else yres + */ + { /* autodetect */ + 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */ + {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* st low */ + 320, 200, 320, 0, 0, 0, 4, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* st mid */ + 640, 200, 640, 0, 0, 0, 2, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* st high */ + 640, 400, 640, 0, 0, 0, 1, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* tt low */ + 320, 480, 320, 0, 0, 0, 8, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* tt mid */ + 640, 480, 640, 0, 0, 0, 4, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* tt high */ + 1280, 960, 1280, 0, 0, 0, 1, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* vga2 */ + 640, 480, 640, 0, 0, 0, 1, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* vga4 */ + 640, 480, 640, 0, 0, 0, 2, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* vga16 */ + 640, 480, 640, 0, 0, 0, 4, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* vga256 */ + 640, 480, 640, 0, 0, 0, 8, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* falh2 */ + 896, 608, 896, 0, 0, 0, 1, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* falh16 */ + 896, 608, 896, 0, 0, 0, 4, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +static int num_atafb_predefined=ARRAY_SIZE(atafb_predefined); + + +static int +get_video_mode(char *vname) +{ + char ***name_list; + char **name; + int i; + name_list=fb_var_names; + for (i = 0 ; i < num_atafb_predefined ; i++) { + name=*(name_list++); + if (! name || ! *name) + break; + while (*name) { + if (! strcmp(vname, *name)) + return i+1; + name++; + } + } + return 0; +} + + + +/* ------------------- TT specific functions ---------------------- */ + +#ifdef ATAFB_TT + +static int tt_encode_fix( struct fb_fix_screeninfo *fix, + struct atafb_par *par ) + +{ + int mode; + + strcpy(fix->id,"Atari Builtin"); + fix->smem_start = (unsigned long)real_screen_base; + fix->smem_len = screen_len; + fix->type=FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux=2; + fix->visual=FB_VISUAL_PSEUDOCOLOR; + mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK; + if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) { + fix->type=FB_TYPE_PACKED_PIXELS; + fix->type_aux=0; + if (mode == TT_SHIFTER_TTHIGH) + fix->visual=FB_VISUAL_MONO01; + } + fix->xpanstep=0; + fix->ypanstep=1; + fix->ywrapstep=0; + fix->line_length = 0; + fix->accel = FB_ACCEL_ATARIBLITT; + return 0; +} + + +static int tt_decode_var( struct fb_var_screeninfo *var, + struct atafb_par *par ) +{ + int xres=var->xres; + int yres=var->yres; + int bpp=var->bits_per_pixel; + int linelen; + int yres_virtual = var->yres_virtual; + + if (mono_moni) { + if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2) + return -EINVAL; + par->hw.tt.mode=TT_SHIFTER_TTHIGH; + xres=sttt_xres*2; + yres=tt_yres*2; + bpp=1; + } else { + if (bpp > 8 || xres > sttt_xres || yres > tt_yres) + return -EINVAL; + if (bpp > 4) { + if (xres > sttt_xres/2 || yres > tt_yres) + return -EINVAL; + par->hw.tt.mode=TT_SHIFTER_TTLOW; + xres=sttt_xres/2; + yres=tt_yres; + bpp=8; + } + else if (bpp > 2) { + if (xres > sttt_xres || yres > tt_yres) + return -EINVAL; + if (xres > sttt_xres/2 || yres > st_yres/2) { + par->hw.tt.mode=TT_SHIFTER_TTMID; + xres=sttt_xres; + yres=tt_yres; + bpp=4; + } + else { + par->hw.tt.mode=TT_SHIFTER_STLOW; + xres=sttt_xres/2; + yres=st_yres/2; + bpp=4; + } + } + else if (bpp > 1) { + if (xres > sttt_xres || yres > st_yres/2) + return -EINVAL; + par->hw.tt.mode=TT_SHIFTER_STMID; + xres=sttt_xres; + yres=st_yres/2; + bpp=2; + } + else if (var->xres > sttt_xres || var->yres > st_yres) { + return -EINVAL; + } + else { + par->hw.tt.mode=TT_SHIFTER_STHIGH; + xres=sttt_xres; + yres=st_yres; + bpp=1; + } + } + if (yres_virtual <= 0) + yres_virtual = 0; + else if (yres_virtual < yres) + yres_virtual = yres; + if (var->sync & FB_SYNC_EXT) + par->hw.tt.sync=0; + else + par->hw.tt.sync=1; + linelen=xres*bpp/8; + if (yres_virtual * linelen > screen_len && screen_len) + return -EINVAL; + if (yres * linelen > screen_len && screen_len) + return -EINVAL; + if (var->yoffset + yres > yres_virtual && yres_virtual) + return -EINVAL; + par->yres_virtual = yres_virtual; + par->screen_base = screen_base + var->yoffset * linelen; + return 0; +} + +static int tt_encode_var( struct fb_var_screeninfo *var, + struct atafb_par *par ) +{ + int linelen; + memset(var, 0, sizeof(struct fb_var_screeninfo)); + var->red.offset=0; + var->red.length=4; + var->red.msb_right=0; + var->grayscale=0; + + var->pixclock=31041; + var->left_margin=120; /* these may be incorrect */ + var->right_margin=100; + var->upper_margin=8; + var->lower_margin=16; + var->hsync_len=140; + var->vsync_len=30; + + var->height=-1; + var->width=-1; + + if (par->hw.tt.sync & 1) + var->sync=0; + else + var->sync=FB_SYNC_EXT; + + switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) { + case TT_SHIFTER_STLOW: + var->xres=sttt_xres/2; + var->xres_virtual=sttt_xres_virtual/2; + var->yres=st_yres/2; + var->bits_per_pixel=4; + break; + case TT_SHIFTER_STMID: + var->xres=sttt_xres; + var->xres_virtual=sttt_xres_virtual; + var->yres=st_yres/2; + var->bits_per_pixel=2; + break; + case TT_SHIFTER_STHIGH: + var->xres=sttt_xres; + var->xres_virtual=sttt_xres_virtual; + var->yres=st_yres; + var->bits_per_pixel=1; + break; + case TT_SHIFTER_TTLOW: + var->xres=sttt_xres/2; + var->xres_virtual=sttt_xres_virtual/2; + var->yres=tt_yres; + var->bits_per_pixel=8; + break; + case TT_SHIFTER_TTMID: + var->xres=sttt_xres; + var->xres_virtual=sttt_xres_virtual; + var->yres=tt_yres; + var->bits_per_pixel=4; + break; + case TT_SHIFTER_TTHIGH: + var->red.length=0; + var->xres=sttt_xres*2; + var->xres_virtual=sttt_xres_virtual*2; + var->yres=tt_yres*2; + var->bits_per_pixel=1; + break; + } + var->blue=var->green=var->red; + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + linelen=var->xres_virtual * var->bits_per_pixel / 8; + if (! use_hwscroll) + var->yres_virtual=var->yres; + else if (screen_len) { + if (par->yres_virtual) + var->yres_virtual = par->yres_virtual; + else + /* yres_virtual==0 means use maximum */ + var->yres_virtual = screen_len / linelen; + } else { + if (hwscroll < 0) + var->yres_virtual = 2 * var->yres; + else + var->yres_virtual=var->yres+hwscroll * 16; + } + var->xoffset=0; + if (screen_base) + var->yoffset=(par->screen_base - screen_base)/linelen; + else + var->yoffset=0; + var->nonstd=0; + var->activate=0; + var->vmode=FB_VMODE_NONINTERLACED; + return 0; +} + + +static void tt_get_par( struct atafb_par *par ) +{ + unsigned long addr; + par->hw.tt.mode=shifter_tt.tt_shiftmode; + par->hw.tt.sync=shifter.syncmode; + addr = ((shifter.bas_hi & 0xff) << 16) | + ((shifter.bas_md & 0xff) << 8) | + ((shifter.bas_lo & 0xff)); + par->screen_base = phys_to_virt(addr); +} + +static void tt_set_par( struct atafb_par *par ) +{ + shifter_tt.tt_shiftmode=par->hw.tt.mode; + shifter.syncmode=par->hw.tt.sync; + /* only set screen_base if really necessary */ + if (current_par.screen_base != par->screen_base) + fbhw->set_screen_base(par->screen_base); +} + + +static int tt_getcolreg(unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp, struct fb_info *info) +{ + int t, col; + + if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) + regno += 254; + if (regno > 255) + return 1; + t = tt_palette[regno]; + col = t & 15; + col |= col << 4; + col |= col << 8; + *blue = col; + col = (t >> 4) & 15; + col |= col << 4; + col |= col << 8; + *green = col; + col = (t >> 8) & 15; + col |= col << 4; + col |= col << 8; + *red = col; + *transp = 0; + return 0; +} + + +static int tt_setcolreg(unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) + regno += 254; + if (regno > 255) + return 1; + tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) | + (blue >> 12)); + if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == + TT_SHIFTER_STHIGH && regno == 254) + tt_palette[0] = 0; + return 0; +} + + +static int tt_detect( void ) + +{ struct atafb_par par; + + /* Determine the connected monitor: The DMA sound must be + * disabled before reading the MFP GPIP, because the Sound + * Done Signal and the Monochrome Detect are XORed together! + * + * Even on a TT, we should look if there is a DMA sound. It was + * announced that the Eagle is TT compatible, but only the PCM is + * missing... + */ + if (ATARIHW_PRESENT(PCM_8BIT)) { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + udelay(20); /* wait a while for things to settle down */ + } + mono_moni = (mfp.par_dt_reg & 0x80) == 0; + + tt_get_par(&par); + tt_encode_var(&atafb_predefined[0], &par); + + return 1; +} + +#endif /* ATAFB_TT */ + +/* ------------------- Falcon specific functions ---------------------- */ + +#ifdef ATAFB_FALCON + +static int mon_type; /* Falcon connected monitor */ +static int f030_bus_width; /* Falcon ram bus width (for vid_control) */ +#define F_MON_SM 0 +#define F_MON_SC 1 +#define F_MON_VGA 2 +#define F_MON_TV 3 + +static struct pixel_clock { + unsigned long f; /* f/[Hz] */ + unsigned long t; /* t/[ps] (=1/f) */ + int right, hsync, left; /* standard timing in clock cycles, not pixel */ + /* hsync initialized in falcon_detect() */ + int sync_mask; /* or-mask for hw.falcon.sync to set this clock */ + int control_mask; /* ditto, for hw.falcon.vid_control */ +} +f25 = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25}, +f32 = {32000000, 31250, 18, 0, 42, 0x0, 0}, +fext = { 0, 0, 18, 0, 42, 0x1, 0}; + +/* VIDEL-prescale values [mon_type][pixel_length from VCO] */ +static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}}; + +/* Default hsync timing [mon_type] in picoseconds */ +static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000}; + +#ifdef FBCON_HAS_CFB16 +static u16 fbcon_cfb16_cmap[16]; +#endif + +static inline int hxx_prescale(struct falcon_hw *hw) +{ + return hw->ste_mode ? 16 : + vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3]; +} + +static int falcon_encode_fix( struct fb_fix_screeninfo *fix, + struct atafb_par *par ) +{ + strcpy(fix->id, "Atari Builtin"); + fix->smem_start = (unsigned long)real_screen_base; + fix->smem_len = screen_len; + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux = 2; + fix->visual = FB_VISUAL_PSEUDOCOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + if (par->hw.falcon.mono) { + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + /* no smooth scrolling with longword aligned video mem */ + fix->xpanstep = 32; + } + else if (par->hw.falcon.f_shift & 0x100) { + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + /* Is this ok or should it be DIRECTCOLOR? */ + fix->visual = FB_VISUAL_TRUECOLOR; + fix->xpanstep = 2; + } + fix->line_length = 0; + fix->accel = FB_ACCEL_ATARIBLITT; + return 0; +} + + +static int falcon_decode_var( struct fb_var_screeninfo *var, + struct atafb_par *par ) +{ + int bpp = var->bits_per_pixel; + int xres = var->xres; + int yres = var->yres; + int xres_virtual = var->xres_virtual; + int yres_virtual = var->yres_virtual; + int left_margin, right_margin, hsync_len; + int upper_margin, lower_margin, vsync_len; + int linelen; + int interlace = 0, doubleline = 0; + struct pixel_clock *pclock; + int plen; /* width of pixel in clock cycles */ + int xstretch; + int prescale; + int longoffset = 0; + int hfreq, vfreq; + +/* + Get the video params out of 'var'. If a value doesn't fit, round + it up, if it's too big, return EINVAL. + Round up in the following order: bits_per_pixel, xres, yres, + xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, + horizontal timing, vertical timing. + + There is a maximum of screen resolution determined by pixelclock + and minimum frame rate -- (X+hmarg.)*(Y+vmarg.)*vfmin <= pixelclock. + In interlace mode this is " * " *vfmin <= pixelclock. + Additional constraints: hfreq. + Frequency range for multisync monitors is given via command line. + For TV and SM124 both frequencies are fixed. + + X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0) + Y % 16 == 0 to fit 8x16 font + Y % 8 == 0 if Y<400 + + Currently interlace and doubleline mode in var are ignored. + On SM124 and TV only the standard resolutions can be used. +*/ + + /* Reject uninitialized mode */ + if (!xres || !yres || !bpp) + return -EINVAL; + + if (mon_type == F_MON_SM && bpp != 1) { + return -EINVAL; + } + else if (bpp <= 1) { + bpp = 1; + par->hw.falcon.f_shift = 0x400; + par->hw.falcon.st_shift = 0x200; + } + else if (bpp <= 2) { + bpp = 2; + par->hw.falcon.f_shift = 0x000; + par->hw.falcon.st_shift = 0x100; + } + else if (bpp <= 4) { + bpp = 4; + par->hw.falcon.f_shift = 0x000; + par->hw.falcon.st_shift = 0x000; + } + else if (bpp <= 8) { + bpp = 8; + par->hw.falcon.f_shift = 0x010; + } + else if (bpp <= 16) { + bpp = 16; /* packed pixel mode */ + par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */ + } + else + return -EINVAL; + par->hw.falcon.bpp = bpp; + + if (mon_type == F_MON_SM || DontCalcRes) { + /* Skip all calculations. VGA/TV/SC1224 only supported. */ + struct fb_var_screeninfo *myvar = &atafb_predefined[0]; + + if (bpp > myvar->bits_per_pixel || + var->xres > myvar->xres || + var->yres > myvar->yres) + return -EINVAL; + fbhw->get_par(par); /* Current par will be new par */ + goto set_screen_base; /* Don't forget this */ + } + + /* Only some fixed resolutions < 640x400 */ + if (xres <= 320) + xres = 320; + else if (xres <= 640 && bpp != 16) + xres = 640; + if (yres <= 200) + yres = 200; + else if (yres <= 240) + yres = 240; + else if (yres <= 400) + yres = 400; + + /* 2 planes must use STE compatibility mode */ + par->hw.falcon.ste_mode = bpp==2; + par->hw.falcon.mono = bpp==1; + + /* Total and visible scanline length must be a multiple of one longword, + * this and the console fontwidth yields the alignment for xres and + * xres_virtual. + * TODO: this way "odd" fontheights are not supported + * + * Special case in STE mode: blank and graphic positions don't align, + * avoid trash at right margin + */ + if (par->hw.falcon.ste_mode) + xres = (xres + 63) & ~63; + else if (bpp == 1) + xres = (xres + 31) & ~31; + else + xres = (xres + 15) & ~15; + if (yres >= 400) + yres = (yres + 15) & ~15; + else + yres = (yres + 7) & ~7; + + if (xres_virtual < xres) + xres_virtual = xres; + else if (bpp == 1) + xres_virtual = (xres_virtual + 31) & ~31; + else + xres_virtual = (xres_virtual + 15) & ~15; + + if (yres_virtual <= 0) + yres_virtual = 0; + else if (yres_virtual < yres) + yres_virtual = yres; + + /* backward bug-compatibility */ + if (var->pixclock > 1) + var->pixclock -= 1; + + par->hw.falcon.line_width = bpp * xres / 16; + par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16; + + /* single or double pixel width */ + xstretch = (xres < 640) ? 2 : 1; + +#if 0 /* SM124 supports only 640x400, this is rejected above */ + if (mon_type == F_MON_SM) { + if (xres != 640 && yres != 400) + return -EINVAL; + plen = 1; + pclock = &f32; + /* SM124-mode is special */ + par->hw.falcon.ste_mode = 1; + par->hw.falcon.f_shift = 0x000; + par->hw.falcon.st_shift = 0x200; + left_margin = hsync_len = 128 / plen; + right_margin = 0; + /* TODO set all margins */ + } + else +#endif + if (mon_type == F_MON_SC || mon_type == F_MON_TV) { + plen = 2 * xstretch; + if (var->pixclock > f32.t * plen) + return -EINVAL; + pclock = &f32; + if (yres > 240) + interlace = 1; + if (var->pixclock == 0) { + /* set some minimal margins which center the screen */ + left_margin = 32; + right_margin = 18; + hsync_len = pclock->hsync / plen; + upper_margin = 31; + lower_margin = 14; + vsync_len = interlace ? 3 : 4; + } else { + left_margin = var->left_margin; + right_margin = var->right_margin; + hsync_len = var->hsync_len; + upper_margin = var->upper_margin; + lower_margin = var->lower_margin; + vsync_len = var->vsync_len; + if (var->vmode & FB_VMODE_INTERLACED) { + upper_margin = (upper_margin + 1) / 2; + lower_margin = (lower_margin + 1) / 2; + vsync_len = (vsync_len + 1) / 2; + } else if (var->vmode & FB_VMODE_DOUBLE) { + upper_margin *= 2; + lower_margin *= 2; + vsync_len *= 2; + } + } + } + else + { /* F_MON_VGA */ + if (bpp == 16) + xstretch = 2; /* Double pixel width only for hicolor */ + /* Default values are used for vert./hor. timing if no pixelclock given. */ + if (var->pixclock == 0) { + int linesize; + + /* Choose master pixelclock depending on hor. timing */ + plen = 1 * xstretch; + if ((plen * xres + f25.right+f25.hsync+f25.left) * + fb_info.monspecs.hfmin < f25.f) + pclock = &f25; + else if ((plen * xres + f32.right+f32.hsync+f32.left) * + fb_info.monspecs.hfmin < f32.f) + pclock = &f32; + else if ((plen * xres + fext.right+fext.hsync+fext.left) * + fb_info.monspecs.hfmin < fext.f + && fext.f) + pclock = &fext; + else + return -EINVAL; + + left_margin = pclock->left / plen; + right_margin = pclock->right / plen; + hsync_len = pclock->hsync / plen; + linesize = left_margin + xres + right_margin + hsync_len; + upper_margin = 31; + lower_margin = 11; + vsync_len = 3; + } + else { + /* Choose largest pixelclock <= wanted clock */ + int i; + unsigned long pcl = ULONG_MAX; + pclock = 0; + for (i=1; i <= 4; i *= 2) { + if (f25.t*i >= var->pixclock && f25.t*i < pcl) { + pcl = f25.t * i; + pclock = &f25; + } + if (f32.t*i >= var->pixclock && f32.t*i < pcl) { + pcl = f32.t * i; + pclock = &f32; + } + if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) { + pcl = fext.t * i; + pclock = &fext; + } + } + if (!pclock) + return -EINVAL; + plen = pcl / pclock->t; + + left_margin = var->left_margin; + right_margin = var->right_margin; + hsync_len = var->hsync_len; + upper_margin = var->upper_margin; + lower_margin = var->lower_margin; + vsync_len = var->vsync_len; + /* Internal unit is [single lines per (half-)frame] */ + if (var->vmode & FB_VMODE_INTERLACED) { + /* # lines in half frame */ + /* External unit is [lines per full frame] */ + upper_margin = (upper_margin + 1) / 2; + lower_margin = (lower_margin + 1) / 2; + vsync_len = (vsync_len + 1) / 2; + } + else if (var->vmode & FB_VMODE_DOUBLE) { + /* External unit is [double lines per frame] */ + upper_margin *= 2; + lower_margin *= 2; + vsync_len *= 2; + } + } + if (pclock == &fext) + longoffset = 1; /* VIDEL doesn't synchronize on short offset */ + } + /* Is video bus bandwidth (32MB/s) too low for this resolution? */ + /* this is definitely wrong if bus clock != 32MHz */ + if (pclock->f / plen / 8 * bpp > 32000000L) + return -EINVAL; + + if (vsync_len < 1) + vsync_len = 1; + + /* include sync lengths in right/lower margin for all calculations */ + right_margin += hsync_len; + lower_margin += vsync_len; + + /* ! In all calculations of margins we use # of lines in half frame + * (which is a full frame in non-interlace mode), so we can switch + * between interlace and non-interlace without messing around + * with these. + */ + again: + /* Set base_offset 128 and video bus width */ + par->hw.falcon.vid_control = mon_type | f030_bus_width; + if (!longoffset) + par->hw.falcon.vid_control |= VCO_SHORTOFFS; /* base_offset 64 */ + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + par->hw.falcon.vid_control |= VCO_HSYPOS; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + par->hw.falcon.vid_control |= VCO_VSYPOS; + /* Pixelclock */ + par->hw.falcon.vid_control |= pclock->control_mask; + /* External or internal clock */ + par->hw.falcon.sync = pclock->sync_mask | 0x2; + /* Pixellength and prescale */ + par->hw.falcon.vid_mode = (2/plen) << 2; + if (doubleline) + par->hw.falcon.vid_mode |= VMO_DOUBLE; + if (interlace) + par->hw.falcon.vid_mode |= VMO_INTER; + + /********************* + Horizontal timing: unit = [master clock cycles] + unit of hxx-registers: [master clock cycles * prescale] + Hxx-registers are 9 bit wide + + 1 line = ((hht + 2) * 2 * prescale) clock cycles + + graphic output = hdb & 0x200 ? + ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff: + ( hht + 2 - hdb + hde) * prescale - hdboff + hdeoff + (this must be a multiple of plen*128/bpp, on VGA pixels + to the right may be cut off with a bigger right margin) + + start of graphics relative to start of 1st halfline = hdb & 0x200 ? + (hdb - hht - 2) * prescale + hdboff : + hdb * prescale + hdboff + + end of graphics relative to start of 1st halfline = + (hde + hht + 2) * prescale + hdeoff + *********************/ + /* Calculate VIDEL registers */ + { + int hdb_off, hde_off, base_off; + int gstart, gend1, gend2, align; + + prescale = hxx_prescale(&par->hw.falcon); + base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128; + + /* Offsets depend on video mode */ + /* Offsets are in clock cycles, divide by prescale to + * calculate hd[be]-registers + */ + if (par->hw.falcon.f_shift & 0x100) { + align = 1; + hde_off = 0; + hdb_off = (base_off + 16 * plen) + prescale; + } + else { + align = 128 / bpp; + hde_off = ((128 / bpp + 2) * plen); + if (par->hw.falcon.ste_mode) + hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale; + else + hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale; + } + + gstart = (prescale/2 + plen * left_margin) / prescale; + /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */ + gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale; + /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */ + gend2 = gstart + xres * plen / prescale; + par->HHT = plen * (left_margin + xres + right_margin) / + (2 * prescale) - 2; +/* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/ + + par->HDB = gstart - hdb_off/prescale; + par->HBE = gstart; + if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200; + par->HDE = gend1 - par->HHT - 2 - hde_off/prescale; + par->HBB = gend2 - par->HHT - 2; +#if 0 + /* One more Videl constraint: data fetch of two lines must not overlap */ + if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) { + /* if this happens increase margins, decrease hfreq. */ + } +#endif + if (hde_off % prescale) + par->HBB++; /* compensate for non matching hde and hbb */ + par->HSS = par->HHT + 2 - plen * hsync_len / prescale; + if (par->HSS < par->HBB) + par->HSS = par->HBB; + } + + /* check hor. frequency */ + hfreq = pclock->f / ((par->HHT+2)*prescale*2); + if (hfreq > fb_info.monspecs.hfmax && mon_type!=F_MON_VGA) { + /* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */ + /* Too high -> enlarge margin */ + left_margin += 1; + right_margin += 1; + goto again; + } + if (hfreq > fb_info.monspecs.hfmax || hfreq < fb_info.monspecs.hfmin) + return -EINVAL; + + /* Vxx-registers */ + /* All Vxx must be odd in non-interlace, since frame starts in the middle + * of the first displayed line! + * One frame consists of VFT+1 half lines. VFT+1 must be even in + * non-interlace, odd in interlace mode for synchronisation. + * Vxx-registers are 11 bit wide + */ + par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */ + par->VDB = par->VBE; + par->VDE = yres; + if (!interlace) par->VDE <<= 1; + if (doubleline) par->VDE <<= 1; /* VDE now half lines per (half-)frame */ + par->VDE += par->VDB; + par->VBB = par->VDE; + par->VFT = par->VBB + (lower_margin * 2 - 1) - 1; + par->VSS = par->VFT+1 - (vsync_len * 2 - 1); + /* vbb,vss,vft must be even in interlace mode */ + if (interlace) { + par->VBB++; + par->VSS++; + par->VFT++; + } + + /* V-frequency check, hope I didn't create any loop here. */ + /* Interlace and doubleline are mutually exclusive. */ + vfreq = (hfreq * 2) / (par->VFT + 1); + if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) { + /* Too high -> try again with doubleline */ + doubleline = 1; + goto again; + } + else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) { + /* Too low -> try again with interlace */ + interlace = 1; + goto again; + } + else if (vfreq < fb_info.monspecs.vfmin && doubleline) { + /* Doubleline too low -> clear doubleline and enlarge margins */ + int lines; + doubleline = 0; + for (lines=0; + (hfreq*2)/(par->VFT+1+4*lines-2*yres)>fb_info.monspecs.vfmax; + lines++) + ; + upper_margin += lines; + lower_margin += lines; + goto again; + } + else if (vfreq > fb_info.monspecs.vfmax && doubleline) { + /* Doubleline too high -> enlarge margins */ + int lines; + for (lines=0; + (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax; + lines+=2) + ; + upper_margin += lines; + lower_margin += lines; + goto again; + } + else if (vfreq > fb_info.monspecs.vfmax && interlace) { + /* Interlace, too high -> enlarge margins */ + int lines; + for (lines=0; + (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax; + lines++) + ; + upper_margin += lines; + lower_margin += lines; + goto again; + } + else if (vfreq < fb_info.monspecs.vfmin || + vfreq > fb_info.monspecs.vfmax) + return -EINVAL; + + set_screen_base: + linelen = xres_virtual * bpp / 8; + if (yres_virtual * linelen > screen_len && screen_len) + return -EINVAL; + if (yres * linelen > screen_len && screen_len) + return -EINVAL; + if (var->yoffset + yres > yres_virtual && yres_virtual) + return -EINVAL; + par->yres_virtual = yres_virtual; + par->screen_base = screen_base + var->yoffset * linelen; + par->hw.falcon.xoffset = 0; + + return 0; +} + +static int falcon_encode_var( struct fb_var_screeninfo *var, + struct atafb_par *par ) +{ +/* !!! only for VGA !!! */ + int linelen; + int prescale, plen; + int hdb_off, hde_off, base_off; + struct falcon_hw *hw = &par->hw.falcon; + + memset(var, 0, sizeof(struct fb_var_screeninfo)); + /* possible frequencies: 25.175 or 32MHz */ + var->pixclock = hw->sync & 0x1 ? fext.t : + hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t; + + var->height=-1; + var->width=-1; + + var->sync=0; + if (hw->vid_control & VCO_HSYPOS) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (hw->vid_control & VCO_VSYPOS) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + + var->vmode = FB_VMODE_NONINTERLACED; + if (hw->vid_mode & VMO_INTER) + var->vmode |= FB_VMODE_INTERLACED; + if (hw->vid_mode & VMO_DOUBLE) + var->vmode |= FB_VMODE_DOUBLE; + + /* visible y resolution: + * Graphics display starts at line VDB and ends at line + * VDE. If interlace mode off unit of VC-registers is + * half lines, else lines. + */ + var->yres = hw->vde - hw->vdb; + if (!(var->vmode & FB_VMODE_INTERLACED)) + var->yres >>= 1; + if (var->vmode & FB_VMODE_DOUBLE) + var->yres >>= 1; + + /* to get bpp, we must examine f_shift and st_shift. + * f_shift is valid if any of bits no. 10, 8 or 4 + * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e. + * if bit 10 set then bit 8 and bit 4 don't care... + * If all these bits are 0 get display depth from st_shift + * (as for ST and STE) + */ + if (hw->f_shift & 0x400) /* 2 colors */ + var->bits_per_pixel = 1; + else if (hw->f_shift & 0x100) /* hicolor */ + var->bits_per_pixel = 16; + else if (hw->f_shift & 0x010) /* 8 bitplanes */ + var->bits_per_pixel = 8; + else if (hw->st_shift == 0) + var->bits_per_pixel = 4; + else if (hw->st_shift == 0x100) + var->bits_per_pixel = 2; + else /* if (hw->st_shift == 0x200) */ + var->bits_per_pixel = 1; + + var->xres = hw->line_width * 16 / var->bits_per_pixel; + var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel; + if (hw->xoffset) + var->xres_virtual += 16; + + if (var->bits_per_pixel == 16) { + var->red.offset=11; + var->red.length=5; + var->red.msb_right=0; + var->green.offset=5; + var->green.length=6; + var->green.msb_right=0; + var->blue.offset=0; + var->blue.length=5; + var->blue.msb_right=0; + } + else { + var->red.offset=0; + var->red.length = hw->ste_mode ? 4 : 6; + var->red.msb_right=0; + var->grayscale=0; + var->blue=var->green=var->red; + } + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + + linelen = var->xres_virtual * var->bits_per_pixel / 8; + if (screen_len) { + if (par->yres_virtual) + var->yres_virtual = par->yres_virtual; + else + /* yres_virtual==0 means use maximum */ + var->yres_virtual = screen_len / linelen; + } + else { + if (hwscroll < 0) + var->yres_virtual = 2 * var->yres; + else + var->yres_virtual=var->yres+hwscroll * 16; + } + var->xoffset=0; /* TODO change this */ + + /* hdX-offsets */ + prescale = hxx_prescale(hw); + plen = 4 >> (hw->vid_mode >> 2 & 0x3); + base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128; + if (hw->f_shift & 0x100) { + hde_off = 0; + hdb_off = (base_off + 16 * plen) + prescale; + } + else { + hde_off = ((128 / var->bits_per_pixel + 2) * plen); + if (hw->ste_mode) + hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen) + + prescale; + else + hdb_off = (base_off + (128 / var->bits_per_pixel + 18) * plen) + + prescale; + } + + /* Right margin includes hsync */ + var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) - + (hw->hdb & 0x200 ? 2+hw->hht : 0)); + if (hw->ste_mode || mon_type!=F_MON_VGA) + var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off; + else + /* can't use this in ste_mode, because hbb is +1 off */ + var->right_margin = prescale * (hw->hht + 2 - hw->hbb); + var->hsync_len = prescale * (hw->hht + 2 - hw->hss); + + /* Lower margin includes vsync */ + var->upper_margin = hw->vdb / 2 ; /* round down to full lines */ + var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */ + var->vsync_len = (hw->vft+1 - hw->vss + 1) / 2; /* round up */ + if (var->vmode & FB_VMODE_INTERLACED) { + var->upper_margin *= 2; + var->lower_margin *= 2; + var->vsync_len *= 2; + } + else if (var->vmode & FB_VMODE_DOUBLE) { + var->upper_margin = (var->upper_margin + 1) / 2; + var->lower_margin = (var->lower_margin + 1) / 2; + var->vsync_len = (var->vsync_len + 1) / 2; + } + + var->pixclock *= plen; + var->left_margin /= plen; + var->right_margin /= plen; + var->hsync_len /= plen; + + var->right_margin -= var->hsync_len; + var->lower_margin -= var->vsync_len; + + if (screen_base) + var->yoffset=(par->screen_base - screen_base)/linelen; + else + var->yoffset=0; + var->nonstd=0; /* what is this for? */ + var->activate=0; + return 0; +} + + +static int f_change_mode = 0; +static struct falcon_hw f_new_mode; +static int f_pan_display = 0; + +static void falcon_get_par( struct atafb_par *par ) +{ + unsigned long addr; + struct falcon_hw *hw = &par->hw.falcon; + + hw->line_width = shifter_f030.scn_width; + hw->line_offset = shifter_f030.off_next; + hw->st_shift = videl.st_shift & 0x300; + hw->f_shift = videl.f_shift; + hw->vid_control = videl.control; + hw->vid_mode = videl.mode; + hw->sync = shifter.syncmode & 0x1; + hw->xoffset = videl.xoffset & 0xf; + hw->hht = videl.hht; + hw->hbb = videl.hbb; + hw->hbe = videl.hbe; + hw->hdb = videl.hdb; + hw->hde = videl.hde; + hw->hss = videl.hss; + hw->vft = videl.vft; + hw->vbb = videl.vbb; + hw->vbe = videl.vbe; + hw->vdb = videl.vdb; + hw->vde = videl.vde; + hw->vss = videl.vss; + + addr = (shifter.bas_hi & 0xff) << 16 | + (shifter.bas_md & 0xff) << 8 | + (shifter.bas_lo & 0xff); + par->screen_base = phys_to_virt(addr); + + /* derived parameters */ + hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100; + hw->mono = (hw->f_shift & 0x400) || + ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200); +} + +static void falcon_set_par( struct atafb_par *par ) +{ + f_change_mode = 0; + + /* only set screen_base if really necessary */ + if (current_par.screen_base != par->screen_base) + fbhw->set_screen_base(par->screen_base); + + /* Don't touch any other registers if we keep the default resolution */ + if (DontCalcRes) + return; + + /* Tell vbl-handler to change video mode. + * We change modes only on next VBL, to avoid desynchronisation + * (a shift to the right and wrap around by a random number of pixels + * in all monochrome modes). + * This seems to work on my Falcon. + */ + f_new_mode = par->hw.falcon; + f_change_mode = 1; +} + + +static irqreturn_t falcon_vbl_switcher( int irq, void *dummy, struct pt_regs *fp ) +{ + struct falcon_hw *hw = &f_new_mode; + + if (f_change_mode) { + f_change_mode = 0; + + if (hw->sync & 0x1) { + /* Enable external pixelclock. This code only for ScreenWonder */ + *(volatile unsigned short*)0xffff9202 = 0xffbf; + } + else { + /* Turn off external clocks. Read sets all output bits to 1. */ + *(volatile unsigned short*)0xffff9202; + } + shifter.syncmode = hw->sync; + + videl.hht = hw->hht; + videl.hbb = hw->hbb; + videl.hbe = hw->hbe; + videl.hdb = hw->hdb; + videl.hde = hw->hde; + videl.hss = hw->hss; + videl.vft = hw->vft; + videl.vbb = hw->vbb; + videl.vbe = hw->vbe; + videl.vdb = hw->vdb; + videl.vde = hw->vde; + videl.vss = hw->vss; + + videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */ + if (hw->ste_mode) { + videl.st_shift = hw->st_shift; /* write enables STE palette */ + } + else { + /* IMPORTANT: + * set st_shift 0, so we can tell the screen-depth if f_shift==0. + * Writing 0 to f_shift enables 4 plane Falcon mode but + * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible + * with Falcon palette. + */ + videl.st_shift = 0; + /* now back to Falcon palette mode */ + videl.f_shift = hw->f_shift; + } + /* writing to st_shift changed scn_width and vid_mode */ + videl.xoffset = hw->xoffset; + shifter_f030.scn_width = hw->line_width; + shifter_f030.off_next = hw->line_offset; + videl.control = hw->vid_control; + videl.mode = hw->vid_mode; + } + if (f_pan_display) { + f_pan_display = 0; + videl.xoffset = current_par.hw.falcon.xoffset; + shifter_f030.off_next = current_par.hw.falcon.line_offset; + } + return IRQ_HANDLED; +} + + +static int falcon_pan_display( struct fb_var_screeninfo *var, + struct atafb_par *par ) +{ + int xoffset; + int bpp = fb_display[fb_info.currcon].var.bits_per_pixel; + + if (bpp == 1) + var->xoffset = up(var->xoffset, 32); + if (bpp != 16) + par->hw.falcon.xoffset = var->xoffset & 15; + else { + par->hw.falcon.xoffset = 0; + var->xoffset = up(var->xoffset, 2); + } + par->hw.falcon.line_offset = bpp * + (fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16; + if (par->hw.falcon.xoffset) + par->hw.falcon.line_offset -= bpp; + xoffset = var->xoffset - par->hw.falcon.xoffset; + + par->screen_base = screen_base + + (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + xoffset) * bpp / 8; + if (fbhw->set_screen_base) + fbhw->set_screen_base (par->screen_base); + else + return -EINVAL; /* shouldn't happen */ + f_pan_display = 1; + return 0; +} + + +static int falcon_getcolreg( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp, struct fb_info *info ) +{ unsigned long col; + + if (regno > 255) + return 1; + /* This works in STE-mode (with 4bit/color) since f030_col-registers + * hold up to 6bit/color. + * Even with hicolor r/g/b=5/6/5 bit! + */ + col = f030_col[regno]; + *red = (col >> 16) & 0xff00; + *green = (col >> 8) & 0xff00; + *blue = (col << 8) & 0xff00; + *transp = 0; + return 0; +} + + +static int falcon_setcolreg( unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp, struct fb_info *info ) +{ + if (regno > 255) + return 1; + f030_col[regno] = (((red & 0xfc00) << 16) | + ((green & 0xfc00) << 8) | + ((blue & 0xfc00) >> 8)); + if (regno < 16) { + shifter_tt.color_reg[regno] = + (((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) | + (((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) | + ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12); +#ifdef FBCON_HAS_CFB16 + fbcon_cfb16_cmap[regno] = ((red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11)); +#endif + } + return 0; +} + + +static int falcon_blank( int blank_mode ) +{ +/* ++guenther: we can switch off graphics by changing VDB and VDE, + * so VIDEL doesn't hog the bus while saving. + * (this may affect usleep()). + */ + int vdb, vss, hbe, hss; + + if (mon_type == F_MON_SM) /* this doesn't work on SM124 */ + return 1; + + vdb = current_par.VDB; + vss = current_par.VSS; + hbe = current_par.HBE; + hss = current_par.HSS; + + if (blank_mode >= 1) { + /* disable graphics output (this speeds up the CPU) ... */ + vdb = current_par.VFT + 1; + /* ... and blank all lines */ + hbe = current_par.HHT + 2; + } + /* use VESA suspend modes on VGA monitors */ + if (mon_type == F_MON_VGA) { + if (blank_mode == 2 || blank_mode == 4) + vss = current_par.VFT + 1; + if (blank_mode == 3 || blank_mode == 4) + hss = current_par.HHT + 2; + } + + videl.vdb = vdb; + videl.vss = vss; + videl.hbe = hbe; + videl.hss = hss; + + return 0; +} + + +static int falcon_detect( void ) +{ + struct atafb_par par; + unsigned char fhw; + + /* Determine connected monitor and set monitor parameters */ + fhw = *(unsigned char*)0xffff8006; + mon_type = fhw >> 6 & 0x3; + /* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */ + f030_bus_width = fhw << 6 & 0x80; + switch (mon_type) { + case F_MON_SM: + fb_info.monspecs.vfmin = 70; + fb_info.monspecs.vfmax = 72; + fb_info.monspecs.hfmin = 35713; + fb_info.monspecs.hfmax = 35715; + break; + case F_MON_SC: + case F_MON_TV: + /* PAL...NTSC */ + fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */ + fb_info.monspecs.vfmax = 60; + fb_info.monspecs.hfmin = 15620; + fb_info.monspecs.hfmax = 15755; + break; + } + /* initialize hsync-len */ + f25.hsync = h_syncs[mon_type] / f25.t; + f32.hsync = h_syncs[mon_type] / f32.t; + if (fext.t) + fext.hsync = h_syncs[mon_type] / fext.t; + + falcon_get_par(&par); + falcon_encode_var(&atafb_predefined[0], &par); + + /* Detected mode is always the "autodetect" slot */ + return 1; +} + +#endif /* ATAFB_FALCON */ + +/* ------------------- ST(E) specific functions ---------------------- */ + +#ifdef ATAFB_STE + +static int stste_encode_fix( struct fb_fix_screeninfo *fix, + struct atafb_par *par ) + +{ + int mode; + + strcpy(fix->id,"Atari Builtin"); + fix->smem_start = (unsigned long)real_screen_base; + fix->smem_len = screen_len; + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux = 2; + fix->visual = FB_VISUAL_PSEUDOCOLOR; + mode = par->hw.st.mode & 3; + if (mode == ST_HIGH) { + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->visual = FB_VISUAL_MONO10; + } + if (ATARIHW_PRESENT(EXTD_SHIFTER)) { + fix->xpanstep = 16; + fix->ypanstep = 1; + } else { + fix->xpanstep = 0; + fix->ypanstep = 0; + } + fix->ywrapstep = 0; + fix->line_length = 0; + fix->accel = FB_ACCEL_ATARIBLITT; + return 0; +} + + +static int stste_decode_var( struct fb_var_screeninfo *var, + struct atafb_par *par ) +{ + int xres=var->xres; + int yres=var->yres; + int bpp=var->bits_per_pixel; + int linelen; + int yres_virtual = var->yres_virtual; + + if (mono_moni) { + if (bpp > 1 || xres > sttt_xres || yres > st_yres) + return -EINVAL; + par->hw.st.mode=ST_HIGH; + xres=sttt_xres; + yres=st_yres; + bpp=1; + } else { + if (bpp > 4 || xres > sttt_xres || yres > st_yres) + return -EINVAL; + if (bpp > 2) { + if (xres > sttt_xres/2 || yres > st_yres/2) + return -EINVAL; + par->hw.st.mode=ST_LOW; + xres=sttt_xres/2; + yres=st_yres/2; + bpp=4; + } + else if (bpp > 1) { + if (xres > sttt_xres || yres > st_yres/2) + return -EINVAL; + par->hw.st.mode=ST_MID; + xres=sttt_xres; + yres=st_yres/2; + bpp=2; + } + else + return -EINVAL; + } + if (yres_virtual <= 0) + yres_virtual = 0; + else if (yres_virtual < yres) + yres_virtual = yres; + if (var->sync & FB_SYNC_EXT) + par->hw.st.sync=(par->hw.st.sync & ~1) | 1; + else + par->hw.st.sync=(par->hw.st.sync & ~1); + linelen=xres*bpp/8; + if (yres_virtual * linelen > screen_len && screen_len) + return -EINVAL; + if (yres * linelen > screen_len && screen_len) + return -EINVAL; + if (var->yoffset + yres > yres_virtual && yres_virtual) + return -EINVAL; + par->yres_virtual = yres_virtual; + par->screen_base=screen_base+ var->yoffset*linelen; + return 0; +} + +static int stste_encode_var( struct fb_var_screeninfo *var, + struct atafb_par *par ) +{ + int linelen; + memset(var, 0, sizeof(struct fb_var_screeninfo)); + var->red.offset=0; + var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3; + var->red.msb_right=0; + var->grayscale=0; + + var->pixclock=31041; + var->left_margin=120; /* these are incorrect */ + var->right_margin=100; + var->upper_margin=8; + var->lower_margin=16; + var->hsync_len=140; + var->vsync_len=30; + + var->height=-1; + var->width=-1; + + if (!(par->hw.st.sync & 1)) + var->sync=0; + else + var->sync=FB_SYNC_EXT; + + switch (par->hw.st.mode & 3) { + case ST_LOW: + var->xres=sttt_xres/2; + var->yres=st_yres/2; + var->bits_per_pixel=4; + break; + case ST_MID: + var->xres=sttt_xres; + var->yres=st_yres/2; + var->bits_per_pixel=2; + break; + case ST_HIGH: + var->xres=sttt_xres; + var->yres=st_yres; + var->bits_per_pixel=1; + break; + } + var->blue=var->green=var->red; + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + var->xres_virtual=sttt_xres_virtual; + linelen=var->xres_virtual * var->bits_per_pixel / 8; + ovsc_addlen=linelen*(sttt_yres_virtual - st_yres); + + if (! use_hwscroll) + var->yres_virtual=var->yres; + else if (screen_len) { + if (par->yres_virtual) + var->yres_virtual = par->yres_virtual; + else + /* yres_virtual==0 means use maximum */ + var->yres_virtual = screen_len / linelen; + } + else { + if (hwscroll < 0) + var->yres_virtual = 2 * var->yres; + else + var->yres_virtual=var->yres+hwscroll * 16; + } + var->xoffset=0; + if (screen_base) + var->yoffset=(par->screen_base - screen_base)/linelen; + else + var->yoffset=0; + var->nonstd=0; + var->activate=0; + var->vmode=FB_VMODE_NONINTERLACED; + return 0; +} + + +static void stste_get_par( struct atafb_par *par ) +{ + unsigned long addr; + par->hw.st.mode=shifter_tt.st_shiftmode; + par->hw.st.sync=shifter.syncmode; + addr = ((shifter.bas_hi & 0xff) << 16) | + ((shifter.bas_md & 0xff) << 8); + if (ATARIHW_PRESENT(EXTD_SHIFTER)) + addr |= (shifter.bas_lo & 0xff); + par->screen_base = phys_to_virt(addr); +} + +static void stste_set_par( struct atafb_par *par ) +{ + shifter_tt.st_shiftmode=par->hw.st.mode; + shifter.syncmode=par->hw.st.sync; + /* only set screen_base if really necessary */ + if (current_par.screen_base != par->screen_base) + fbhw->set_screen_base(par->screen_base); +} + + +static int stste_getcolreg(unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp, struct fb_info *info) +{ + unsigned col, t; + + if (regno > 15) + return 1; + col = shifter_tt.color_reg[regno]; + if (ATARIHW_PRESENT(EXTD_SHIFTER)) { + t = ((col >> 7) & 0xe) | ((col >> 11) & 1); + t |= t << 4; + *red = t | (t << 8); + t = ((col >> 3) & 0xe) | ((col >> 7) & 1); + t |= t << 4; + *green = t | (t << 8); + t = ((col << 1) & 0xe) | ((col >> 3) & 1); + t |= t << 4; + *blue = t | (t << 8); + } + else { + t = (col >> 7) & 0xe; + t |= t << 4; + *red = t | (t << 8); + t = (col >> 3) & 0xe; + t |= t << 4; + *green = t | (t << 8); + t = (col << 1) & 0xe; + t |= t << 4; + *blue = t | (t << 8); + } + *transp = 0; + return 0; +} + + +static int stste_setcolreg(unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + if (regno > 15) + return 1; + red >>= 12; + blue >>= 12; + green >>= 12; + if (ATARIHW_PRESENT(EXTD_SHIFTER)) + shifter_tt.color_reg[regno] = + (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) | + (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) | + ((blue & 0xe) >> 1) | ((blue & 1) << 3); + else + shifter_tt.color_reg[regno] = + ((red & 0xe) << 7) | + ((green & 0xe) << 3) | + ((blue & 0xe) >> 1); + return 0; +} + + +static int stste_detect( void ) + +{ struct atafb_par par; + + /* Determine the connected monitor: The DMA sound must be + * disabled before reading the MFP GPIP, because the Sound + * Done Signal and the Monochrome Detect are XORed together! + */ + if (ATARIHW_PRESENT(PCM_8BIT)) { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + udelay(20); /* wait a while for things to settle down */ + } + mono_moni = (mfp.par_dt_reg & 0x80) == 0; + + stste_get_par(&par); + stste_encode_var(&atafb_predefined[0], &par); + + if (!ATARIHW_PRESENT(EXTD_SHIFTER)) + use_hwscroll = 0; + return 1; +} + +static void stste_set_screen_base(void *s_base) +{ + unsigned long addr; + addr= virt_to_phys(s_base); + /* Setup Screen Memory */ + shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16); + shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8); + if (ATARIHW_PRESENT(EXTD_SHIFTER)) + shifter.bas_lo=(unsigned char) (addr & 0x0000ff); +} + +#endif /* ATAFB_STE */ + +/* Switching the screen size should be done during vsync, otherwise + * the margins may get messed up. This is a well known problem of + * the ST's video system. + * + * Unfortunately there is hardly any way to find the vsync, as the + * vertical blank interrupt is no longer in time on machines with + * overscan type modifications. + * + * We can, however, use Timer B to safely detect the black shoulder, + * but then we've got to guess an appropriate delay to find the vsync. + * This might not work on every machine. + * + * martin_rogge @ ki.maus.de, 8th Aug 1995 + */ + +#define LINE_DELAY (mono_moni ? 30 : 70) +#define SYNC_DELAY (mono_moni ? 1500 : 2000) + +/* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */ +static void st_ovsc_switch(void) +{ + unsigned long flags; + register unsigned char old, new; + + if (!(atari_switches & ATARI_SWITCH_OVSC_MASK)) + return; + local_irq_save(flags); + + mfp.tim_ct_b = 0x10; + mfp.active_edge |= 8; + mfp.tim_ct_b = 0; + mfp.tim_dt_b = 0xf0; + mfp.tim_ct_b = 8; + while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */ + ; + new = mfp.tim_dt_b; + do { + udelay(LINE_DELAY); + old = new; + new = mfp.tim_dt_b; + } while (old != new); + mfp.tim_ct_b = 0x10; + udelay(SYNC_DELAY); + + if (atari_switches & ATARI_SWITCH_OVSC_IKBD) + acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE; + if (atari_switches & ATARI_SWITCH_OVSC_MIDI) + acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; + if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) { + sound_ym.rd_data_reg_sel = 14; + sound_ym.wd_data = sound_ym.rd_data_reg_sel | + ((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) | + ((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0); + } + local_irq_restore(flags); +} + +/* ------------------- External Video ---------------------- */ + +#ifdef ATAFB_EXT + +static int ext_encode_fix( struct fb_fix_screeninfo *fix, + struct atafb_par *par ) + +{ + strcpy(fix->id,"Unknown Extern"); + fix->smem_start = (unsigned long)external_addr; + fix->smem_len = PAGE_ALIGN(external_len); + if (external_depth == 1) { + fix->type = FB_TYPE_PACKED_PIXELS; + /* The letters 'n' and 'i' in the "atavideo=external:" stand + * for "normal" and "inverted", rsp., in the monochrome case */ + fix->visual = + (external_pmode == FB_TYPE_INTERLEAVED_PLANES || + external_pmode == FB_TYPE_PACKED_PIXELS) ? + FB_VISUAL_MONO10 : + FB_VISUAL_MONO01; + } + else { + /* Use STATIC if we don't know how to access color registers */ + int visual = external_vgaiobase ? + FB_VISUAL_PSEUDOCOLOR : + FB_VISUAL_STATIC_PSEUDOCOLOR; + switch (external_pmode) { + case -1: /* truecolor */ + fix->type=FB_TYPE_PACKED_PIXELS; + fix->visual=FB_VISUAL_TRUECOLOR; + break; + case FB_TYPE_PACKED_PIXELS: + fix->type=FB_TYPE_PACKED_PIXELS; + fix->visual=visual; + break; + case FB_TYPE_PLANES: + fix->type=FB_TYPE_PLANES; + fix->visual=visual; + break; + case FB_TYPE_INTERLEAVED_PLANES: + fix->type=FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux=2; + fix->visual=visual; + break; + } + } + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = 0; + return 0; +} + + +static int ext_decode_var( struct fb_var_screeninfo *var, + struct atafb_par *par ) +{ + struct fb_var_screeninfo *myvar = &atafb_predefined[0]; + + if (var->bits_per_pixel > myvar->bits_per_pixel || + var->xres > myvar->xres || + var->xres_virtual > myvar->xres_virtual || + var->yres > myvar->yres || + var->xoffset > 0 || + var->yoffset > 0) + return -EINVAL; + return 0; +} + + +static int ext_encode_var( struct fb_var_screeninfo *var, + struct atafb_par *par ) +{ + memset(var, 0, sizeof(struct fb_var_screeninfo)); + var->red.offset=0; + var->red.length=(external_pmode == -1) ? external_depth/3 : + (external_vgaiobase ? external_bitspercol : 0); + var->red.msb_right=0; + var->grayscale=0; + + var->pixclock=31041; + var->left_margin=120; /* these are surely incorrect */ + var->right_margin=100; + var->upper_margin=8; + var->lower_margin=16; + var->hsync_len=140; + var->vsync_len=30; + + var->height=-1; + var->width=-1; + + var->sync=0; + + var->xres = external_xres; + var->yres = external_yres; + var->xres_virtual = external_xres_virtual; + var->bits_per_pixel = external_depth; + + var->blue=var->green=var->red; + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + var->yres_virtual=var->yres; + var->xoffset=0; + var->yoffset=0; + var->nonstd=0; + var->activate=0; + var->vmode=FB_VMODE_NONINTERLACED; + return 0; +} + + +static void ext_get_par( struct atafb_par *par ) +{ + par->screen_base = external_addr; +} + +static void ext_set_par( struct atafb_par *par ) +{ +} + +#define OUTB(port,val) \ + *((unsigned volatile char *) ((port)+external_vgaiobase))=(val) +#define INB(port) \ + (*((unsigned volatile char *) ((port)+external_vgaiobase))) +#define DACDelay \ + do { \ + unsigned char tmp=INB(0x3da); \ + tmp=INB(0x3da); \ + } while (0) + +static int ext_getcolreg( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp, struct fb_info *info ) +{ + if (! external_vgaiobase) + return 1; + + *red = ext_color[regno].red; + *green = ext_color[regno].green; + *blue = ext_color[regno].blue; + *transp=0; + return 0; +} + +static int ext_setcolreg( unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp, struct fb_info *info ) + +{ unsigned char colmask = (1 << external_bitspercol) - 1; + + if (! external_vgaiobase) + return 1; + + ext_color[regno].red = red; + ext_color[regno].green = green; + ext_color[regno].blue = blue; + + switch (external_card_type) { + case IS_VGA: + OUTB(0x3c8, regno); + DACDelay; + OUTB(0x3c9, red & colmask); + DACDelay; + OUTB(0x3c9, green & colmask); + DACDelay; + OUTB(0x3c9, blue & colmask); + DACDelay; + return 0; + + case IS_MV300: + OUTB((MV300_reg[regno] << 2)+1, red); + OUTB((MV300_reg[regno] << 2)+1, green); + OUTB((MV300_reg[regno] << 2)+1, blue); + return 0; + + default: + return 1; + } +} + + +static int ext_detect( void ) + +{ + struct fb_var_screeninfo *myvar = &atafb_predefined[0]; + struct atafb_par dummy_par; + + myvar->xres = external_xres; + myvar->xres_virtual = external_xres_virtual; + myvar->yres = external_yres; + myvar->bits_per_pixel = external_depth; + ext_encode_var(myvar, &dummy_par); + return 1; +} + +#endif /* ATAFB_EXT */ + +/* ------ This is the same for most hardware types -------- */ + +static void set_screen_base(void *s_base) +{ + unsigned long addr; + addr= virt_to_phys(s_base); + /* Setup Screen Memory */ + shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16); + shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8); + shifter.bas_lo=(unsigned char) (addr & 0x0000ff); +} + + +static int pan_display( struct fb_var_screeninfo *var, + struct atafb_par *par ) +{ + if (!fbhw->set_screen_base || + (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset)) + return -EINVAL; + var->xoffset = up(var->xoffset, 16); + par->screen_base = screen_base + + (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + var->xoffset) + * fb_display[fb_info.currcon].var.bits_per_pixel / 8; + fbhw->set_screen_base (par->screen_base); + return 0; +} + + +/* ------------ Interfaces to hardware functions ------------ */ + + +#ifdef ATAFB_TT +static struct fb_hwswitch tt_switch = { + tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var, + tt_get_par, tt_set_par, tt_getcolreg, + set_screen_base, NULL, pan_display +}; +#endif + +#ifdef ATAFB_FALCON +static struct fb_hwswitch falcon_switch = { + falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var, + falcon_get_par, falcon_set_par, falcon_getcolreg, + set_screen_base, falcon_blank, falcon_pan_display +}; +#endif + +#ifdef ATAFB_STE +static struct fb_hwswitch st_switch = { + stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var, + stste_get_par, stste_set_par, stste_getcolreg, + stste_set_screen_base, NULL, pan_display +}; +#endif + +#ifdef ATAFB_EXT +static struct fb_hwswitch ext_switch = { + ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var, + ext_get_par, ext_set_par, ext_getcolreg, NULL, NULL, NULL +}; +#endif + + + +static void atafb_get_par( struct atafb_par *par ) +{ + if (current_par_valid) { + *par=current_par; + } + else + fbhw->get_par(par); +} + + +static void atafb_set_par( struct atafb_par *par ) +{ + fbhw->set_par(par); + current_par=*par; + current_par_valid=1; +} + + + +/* =========================================================== */ +/* ============== Hardware Independent Functions ============= */ +/* =========================================================== */ + + +/* used for hardware scrolling */ + +static int +fb_update_var(int con, struct fb_info *info) +{ + int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual* + fb_display[con].var.bits_per_pixel>>3; + + current_par.screen_base=screen_base + off; + + if (fbhw->set_screen_base) + fbhw->set_screen_base(current_par.screen_base); + return 0; +} + +static int +do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +{ + int err,activate; + struct atafb_par par; + if ((err=fbhw->decode_var(var, &par))) + return err; + activate=var->activate; + if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) + atafb_set_par(&par); + fbhw->encode_var(var, &par); + var->activate=activate; + return 0; +} + +static int +atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) +{ + struct atafb_par par; + if (con == -1) + atafb_get_par(&par); + else { + int err; + if ((err=fbhw->decode_var(&fb_display[con].var,&par))) + return err; + } + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + return fbhw->encode_fix(fix, &par); +} + +static int +atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) +{ + struct atafb_par par; + if (con == -1) { + atafb_get_par(&par); + fbhw->encode_var(var, &par); + } + else + *var=fb_display[con].var; + return 0; +} + +static void +atafb_set_disp(int con, struct fb_info *info) +{ + struct fb_fix_screeninfo fix; + struct fb_var_screeninfo var; + struct display *display; + + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + atafb_get_fix(&fix, con, info); + atafb_get_var(&var, con, info); + if (con == -1) + con=0; + info->screen_base = (void *)fix.smem_start; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + if (fix.visual != FB_VISUAL_PSEUDOCOLOR && + fix.visual != FB_VISUAL_DIRECTCOLOR) + display->can_soft_blank = 0; + else + display->can_soft_blank = 1; + display->inverse = + (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse); + switch (fix.type) { + case FB_TYPE_INTERLEAVED_PLANES: + switch (var.bits_per_pixel) { +#ifdef FBCON_HAS_IPLAN2P2 + case 2: + display->dispsw = &fbcon_iplan2p2; + break; +#endif +#ifdef FBCON_HAS_IPLAN2P4 + case 4: + display->dispsw = &fbcon_iplan2p4; + break; +#endif +#ifdef FBCON_HAS_IPLAN2P8 + case 8: + display->dispsw = &fbcon_iplan2p8; + break; +#endif + } + break; + case FB_TYPE_PACKED_PIXELS: + switch (var.bits_per_pixel) { +#ifdef FBCON_HAS_MFB + case 1: + display->dispsw = &fbcon_mfb; + break; +#endif +#ifdef FBCON_HAS_CFB8 + case 8: + display->dispsw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + display->dispsw = &fbcon_cfb16; + display->dispsw_data = fbcon_cfb16_cmap; + break; +#endif + } + break; + } +} + +static int +atafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) +{ + int err,oldxres,oldyres,oldbpp,oldxres_virtual, + oldyres_virtual,oldyoffset; + if ((err=do_fb_set_var(var, con==info->currcon))) + return err; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres=fb_display[con].var.xres; + oldyres=fb_display[con].var.yres; + oldxres_virtual=fb_display[con].var.xres_virtual; + oldyres_virtual=fb_display[con].var.yres_virtual; + oldbpp=fb_display[con].var.bits_per_pixel; + oldyoffset=fb_display[con].var.yoffset; + fb_display[con].var=*var; + if (oldxres != var->xres || oldyres != var->yres + || oldxres_virtual != var->xres_virtual + || oldyres_virtual != var->yres_virtual + || oldbpp != var->bits_per_pixel + || oldyoffset != var->yoffset) { + atafb_set_disp(con, info); + (*fb_info.changevar)(con); + fb_alloc_cmap(&fb_display[con].cmap, 0, 0); + do_install_cmap(con, info); + } + } + var->activate=0; + return 0; +} + + + +static int +atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) +{ + if (con == info->currcon) /* current console ? */ + return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info); + else + if (fb_display[con].cmap.len) /* non default colormap ? */ + 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; +} + +static int +atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info) +{ + int xoffset = var->xoffset; + int yoffset = var->yoffset; + int err; + + if ( xoffset < 0 || xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual + || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual) + return -EINVAL; + + if (con == info->currcon) { + if (fbhw->pan_display) { + if ((err = fbhw->pan_display(var, ¤t_par))) + return err; + } + else + return -EINVAL; + } + fb_display[con].var.xoffset = var->xoffset; + fb_display[con].var.yoffset = var->yoffset; + return 0; +} + +static int +atafb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, int con, struct fb_info *info) +{ + switch (cmd) { +#ifdef FBCMD_GET_CURRENTPAR + case FBCMD_GET_CURRENTPAR: + if (copy_to_user((void *)arg, (void *)¤t_par, + sizeof(struct atafb_par))) + return -EFAULT; + return 0; +#endif +#ifdef FBCMD_SET_CURRENTPAR + case FBCMD_SET_CURRENTPAR: + if (copy_from_user((void *)¤t_par, (void *)arg, + sizeof(struct atafb_par))) + return -EFAULT; + atafb_set_par(¤t_par); + return 0; +#endif + } + return -EINVAL; +} + +/* (un)blank/poweroff + * 0 = unblank + * 1 = blank + * 2 = suspend vsync + * 3 = suspend hsync + * 4 = off + */ +static int +atafb_blank(int blank, struct fb_info *info) +{ + unsigned short black[16]; + struct fb_cmap cmap; + if (fbhw->blank && !fbhw->blank(blank)) + return 1; + if (blank) { + memset(black, 0, 16*sizeof(unsigned short)); + cmap.red=black; + cmap.green=black; + cmap.blue=black; + cmap.transp=NULL; + cmap.start=0; + cmap.len=16; + fb_set_cmap(&cmap, 1, info); + } + else + do_install_cmap(info->currcon, info); + return 0; +} + +static struct fb_ops atafb_ops = { + .owner = THIS_MODULE, + .fb_get_fix = atafb_get_fix, + .fb_get_var = atafb_get_var, + .fb_set_var = atafb_set_var, + .fb_get_cmap = atafb_get_cmap, + .fb_set_cmap = gen_set_cmap, + .fb_pan_display =atafb_pan_display, + .fb_blank = atafb_blank, + .fb_ioctl = atafb_ioctl, +}; + +static void +check_default_par( int detected_mode ) +{ + char default_name[10]; + int i; + struct fb_var_screeninfo var; + unsigned long min_mem; + + /* First try the user supplied mode */ + if (default_par) { + var=atafb_predefined[default_par-1]; + var.activate = FB_ACTIVATE_TEST; + if (do_fb_set_var(&var,1)) + default_par=0; /* failed */ + } + /* Next is the autodetected one */ + if (! default_par) { + var=atafb_predefined[detected_mode-1]; /* autodetect */ + var.activate = FB_ACTIVATE_TEST; + if (!do_fb_set_var(&var,1)) + default_par=detected_mode; + } + /* If that also failed, try some default modes... */ + if (! default_par) { + /* try default1, default2... */ + for (i=1 ; i < 10 ; i++) { + sprintf(default_name,"default%d",i); + default_par=get_video_mode(default_name); + if (! default_par) + panic("can't set default video mode"); + var=atafb_predefined[default_par-1]; + var.activate = FB_ACTIVATE_TEST; + if (! do_fb_set_var(&var,1)) + break; /* ok */ + } + } + min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8; + if (default_mem_req < min_mem) + default_mem_req=min_mem; +} + +static int +atafb_switch(int con, struct fb_info *info) +{ + /* Do we have to save the colormap ? */ + if (fb_display[info->currcon].cmap.len) + fb_get_cmap(&fb_display[info->currcon].cmap, 1, fbhw->getcolreg, + info); + do_fb_set_var(&fb_display[con].var,1); + info->currcon=con; + /* Install new colormap */ + do_install_cmap(con, info); + return 0; +} + +int __init atafb_init(void) +{ + int pad; + int detected_mode; + unsigned long mem_req; + + if (!MACH_IS_ATARI) + return -ENXIO; + + do { +#ifdef ATAFB_EXT + if (external_addr) { + fbhw = &ext_switch; + atafb_ops.fb_setcolreg = &ext_setcolreg; + break; + } +#endif +#ifdef ATAFB_TT + if (ATARIHW_PRESENT(TT_SHIFTER)) { + fbhw = &tt_switch; + atafb_ops.fb_setcolreg = &tt_setcolreg; + break; + } +#endif +#ifdef ATAFB_FALCON + if (ATARIHW_PRESENT(VIDEL_SHIFTER)) { + fbhw = &falcon_switch; + atafb_ops.fb_setcolreg = &falcon_setcolreg; + request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, + "framebuffer/modeswitch", falcon_vbl_switcher); + break; + } +#endif +#ifdef ATAFB_STE + if (ATARIHW_PRESENT(STND_SHIFTER) || + ATARIHW_PRESENT(EXTD_SHIFTER)) { + fbhw = &st_switch; + atafb_ops.fb_setcolreg = &stste_setcolreg; + break; + } + fbhw = &st_switch; + atafb_ops.fb_setcolreg = &stste_setcolreg; + printk("Cannot determine video hardware; defaulting to ST(e)\n"); +#else /* ATAFB_STE */ + /* no default driver included */ + /* Nobody will ever see this message :-) */ + panic("Cannot initialize video hardware"); +#endif + } while (0); + + /* Multisync monitor capabilities */ + /* Atari-TOS defaults if no boot option present */ + if (fb_info.monspecs.hfmin == 0) { + fb_info.monspecs.hfmin = 31000; + fb_info.monspecs.hfmax = 32000; + fb_info.monspecs.vfmin = 58; + fb_info.monspecs.vfmax = 62; + } + + detected_mode = fbhw->detect(); + check_default_par(detected_mode); +#ifdef ATAFB_EXT + if (!external_addr) { +#endif /* ATAFB_EXT */ + mem_req = default_mem_req + ovsc_offset + ovsc_addlen; + mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE; + screen_base = atari_stram_alloc(mem_req, "atafb"); + if (!screen_base) + panic("Cannot allocate screen memory"); + memset(screen_base, 0, mem_req); + pad = -(unsigned long)screen_base & (PAGE_SIZE-1); + screen_base+=pad; + real_screen_base=screen_base+ovsc_offset; + screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK; + st_ovsc_switch(); + if (CPU_IS_040_OR_060) { + /* On a '040+, the cache mode of video RAM must be set to + * write-through also for internal video hardware! */ + cache_push(virt_to_phys(screen_base), screen_len); + kernel_set_cachemode(screen_base, screen_len, + IOMAP_WRITETHROUGH); + } +#ifdef ATAFB_EXT + } + else { + /* Map the video memory (physical address given) to somewhere + * in the kernel address space. + */ + external_addr = + ioremap_writethrough((unsigned long)external_addr, + external_len); + if (external_vgaiobase) + external_vgaiobase = + (unsigned long)ioremap(external_vgaiobase, 0x10000); + screen_base = + real_screen_base = external_addr; + screen_len = external_len & PAGE_MASK; + memset (screen_base, 0, external_len); + } +#endif /* ATAFB_EXT */ + + strcpy(fb_info.modename, "Atari Builtin "); + fb_info.changevar = NULL; + fb_info.fbops = &atafb_ops; + fb_info.disp = &disp; + fb_info.currcon = -1; + fb_info.switch_con = &atafb_switch; + fb_info.updatevar = &fb_update_var; + fb_info.flags = FBINFO_FLAG_DEFAULT; + do_fb_set_var(&atafb_predefined[default_par-1], 1); + strcat(fb_info.modename, fb_var_names[default_par-1][0]); + + atafb_get_var(&disp.var, -1, &fb_info); + atafb_set_disp(-1, &fb_info); + do_install_cmap(0, &fb_info); + + if (register_framebuffer(&fb_info) < 0) + return -EINVAL; + + printk("Determined %dx%d, depth %d\n", + disp.var.xres, disp.var.yres, disp.var.bits_per_pixel); + if ((disp.var.xres != disp.var.xres_virtual) || + (disp.var.yres != disp.var.yres_virtual)) + printk(" virtual %dx%d\n", + disp.var.xres_virtual, disp.var.yres_virtual); + printk("fb%d: %s frame buffer device, using %dK of video memory\n", + fb_info.node, fb_info.modename, screen_len>>10); + + /* TODO: This driver cannot be unloaded yet */ + return 0; +} + + +#ifdef ATAFB_EXT +static void __init atafb_setup_ext(char *spec) +{ + int xres, xres_virtual, yres, depth, planes; + unsigned long addr, len; + char *p; + + /* Format is: <xres>;<yres>;<depth>;<plane organ.>; + * <screen mem addr> + * [;<screen mem length>[;<vgaiobase>[;<bits-per-col>[;<colorreg-type> + * [;<xres-virtual>]]]]] + * + * 09/23/97 Juergen + * <xres_virtual>: hardware's x-resolution (f.e. ProMST) + * + * Even xres_virtual is available, we neither support panning nor hw-scrolling! + */ + if (!(p = strsep(&spec, ";")) || !*p) + return; + xres_virtual = xres = simple_strtoul(p, NULL, 10); + if (xres <= 0) + return; + + if (!(p = strsep(&spec, ";")) || !*p) + return; + yres = simple_strtoul(p, NULL, 10); + if (yres <= 0) + return; + + if (!(p = strsep(&spec, ";")) || !*p) + return; + depth = simple_strtoul(p, NULL, 10); + if (depth != 1 && depth != 2 && depth != 4 && depth != 8 && + depth != 16 && depth != 24) + return; + + if (!(p = strsep(&spec, ";")) || !*p) + return; + if (*p == 'i') + planes = FB_TYPE_INTERLEAVED_PLANES; + else if (*p == 'p') + planes = FB_TYPE_PACKED_PIXELS; + else if (*p == 'n') + planes = FB_TYPE_PLANES; + else if (*p == 't') + planes = -1; /* true color */ + else + return; + + + if (!(p = strsep(&spec, ";")) || !*p) + return; + addr = simple_strtoul(p, NULL, 0); + + if (!(p = strsep(&spec, ";")) || !*p) + len = xres*yres*depth/8; + else + len = simple_strtoul(p, NULL, 0); + + if ((p = strsep(&spec, ";")) && *p) { + external_vgaiobase=simple_strtoul(p, NULL, 0); + } + + if ((p = strsep(&spec, ";")) && *p) { + external_bitspercol = simple_strtoul(p, NULL, 0); + if (external_bitspercol > 8) + external_bitspercol = 8; + else if (external_bitspercol < 1) + external_bitspercol = 1; + } + + if ((p = strsep(&spec, ";")) && *p) { + if (!strcmp(p, "vga")) + external_card_type = IS_VGA; + if (!strcmp(p, "mv300")) + external_card_type = IS_MV300; + } + + if ((p = strsep(&spec, ";")) && *p) { + xres_virtual = simple_strtoul(p, NULL, 10); + if (xres_virtual < xres) + xres_virtual = xres; + if (xres_virtual*yres*depth/8 > len) + len=xres_virtual*yres*depth/8; + } + + external_xres = xres; + external_xres_virtual = xres_virtual; + external_yres = yres; + external_depth = depth; + external_pmode = planes; + external_addr = (void *)addr; + external_len = len; + + if (external_card_type == IS_MV300) + switch (external_depth) { + case 1: + MV300_reg = MV300_reg_1bit; + break; + case 4: + MV300_reg = MV300_reg_4bit; + break; + case 8: + MV300_reg = MV300_reg_8bit; + break; + } +} +#endif /* ATAFB_EXT */ + + +static void __init atafb_setup_int(char *spec) +{ + /* Format to config extended internal video hardware like OverScan: + "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>" + Explanation: + <xres>: x-resolution + <yres>: y-resolution + The following are only needed if you have an overscan which + needs a black border: + <xres_max>: max. length of a line in pixels your OverScan hardware would allow + <yres_max>: max. number of lines your OverScan hardware would allow + <offset>: Offset from physical beginning to visible beginning + of screen in bytes + */ + int xres; + char *p; + + if (!(p = strsep(&spec, ";")) || !*p) + return; + xres = simple_strtoul(p, NULL, 10); + if (!(p = strsep(&spec, ";")) || !*p) + return; + sttt_xres=xres; + tt_yres=st_yres=simple_strtoul(p, NULL, 10); + if ((p=strsep(&spec, ";")) && *p) { + sttt_xres_virtual=simple_strtoul(p, NULL, 10); + } + if ((p=strsep(&spec, ";")) && *p) { + sttt_yres_virtual=simple_strtoul(p, NULL, 0); + } + if ((p=strsep(&spec, ";")) && *p) { + ovsc_offset=simple_strtoul(p, NULL, 0); + } + + if (ovsc_offset || (sttt_yres_virtual != st_yres)) + use_hwscroll=0; +} + + +#ifdef ATAFB_FALCON +static void __init atafb_setup_mcap(char *spec) +{ + char *p; + int vmin, vmax, hmin, hmax; + + /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax> + * <V*> vertical freq. in Hz + * <H*> horizontal freq. in kHz + */ + if (!(p = strsep(&spec, ";")) || !*p) + return; + vmin = simple_strtoul(p, NULL, 10); + if (vmin <= 0) + return; + if (!(p = strsep(&spec, ";")) || !*p) + return; + vmax = simple_strtoul(p, NULL, 10); + if (vmax <= 0 || vmax <= vmin) + return; + if (!(p = strsep(&spec, ";")) || !*p) + return; + hmin = 1000 * simple_strtoul(p, NULL, 10); + if (hmin <= 0) + return; + if (!(p = strsep(&spec, "")) || !*p) + return; + hmax = 1000 * simple_strtoul(p, NULL, 10); + if (hmax <= 0 || hmax <= hmin) + return; + + fb_info.monspecs.vfmin = vmin; + fb_info.monspecs.vfmax = vmax; + fb_info.monspecs.hfmin = hmin; + fb_info.monspecs.hfmax = hmax; +} +#endif /* ATAFB_FALCON */ + + +static void __init atafb_setup_user(char *spec) +{ + /* Format of user defined video mode is: <xres>;<yres>;<depth> + */ + char *p; + int xres, yres, depth, temp; + + if (!(p = strsep(&spec, ";")) || !*p) + return; + xres = simple_strtoul(p, NULL, 10); + if (!(p = strsep(&spec, ";")) || !*p) + return; + yres = simple_strtoul(p, NULL, 10); + if (!(p = strsep(&spec, "")) || !*p) + return; + depth = simple_strtoul(p, NULL, 10); + if ((temp=get_video_mode("user0"))) { + default_par=temp; + atafb_predefined[default_par-1].xres = xres; + atafb_predefined[default_par-1].yres = yres; + atafb_predefined[default_par-1].bits_per_pixel = depth; + } +} + +int __init atafb_setup( char *options ) +{ + char *this_opt; + int temp; + + fb_info.fontname[0] = '\0'; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) continue; + if ((temp=get_video_mode(this_opt))) + default_par=temp; + else if (! strcmp(this_opt, "inverse")) + inverse=1; + else if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt+5); + else if (! strncmp(this_opt, "hwscroll_",9)) { + hwscroll=simple_strtoul(this_opt+9, NULL, 10); + if (hwscroll < 0) + hwscroll = 0; + if (hwscroll > 200) + hwscroll = 200; + } +#ifdef ATAFB_EXT + else if (!strcmp(this_opt,"mv300")) { + external_bitspercol = 8; + external_card_type = IS_MV300; + } + else if (!strncmp(this_opt,"external:",9)) + atafb_setup_ext(this_opt+9); +#endif + else if (!strncmp(this_opt,"internal:",9)) + atafb_setup_int(this_opt+9); +#ifdef ATAFB_FALCON + else if (!strncmp(this_opt, "eclock:", 7)) { + fext.f = simple_strtoul(this_opt+7, NULL, 10); + /* external pixelclock in kHz --> ps */ + fext.t = 1000000000/fext.f; + fext.f *= 1000; + } + else if (!strncmp(this_opt, "monitorcap:", 11)) + atafb_setup_mcap(this_opt+11); +#endif + else if (!strcmp(this_opt, "keep")) + DontCalcRes = 1; + else if (!strncmp(this_opt, "R", 1)) + atafb_setup_user(this_opt+1); + } + return 0; +} + +#ifdef MODULE +MODULE_LICENSE("GPL"); + +int init_module(void) +{ + return atafb_init(); +} +#endif /* MODULE */ diff --git a/drivers/video/aty/Makefile b/drivers/video/aty/Makefile new file mode 100644 index 000000000000..9dec96249ffb --- /dev/null +++ b/drivers/video/aty/Makefile @@ -0,0 +1,15 @@ +obj-$(CONFIG_FB_ATY) += atyfb.o +obj-$(CONFIG_FB_ATY128) += aty128fb.o +obj-$(CONFIG_FB_RADEON) += radeonfb.o + +atyfb-y := atyfb_base.o mach64_accel.o mach64_cursor.o +atyfb-$(CONFIG_FB_ATY_GX) += mach64_gx.o +atyfb-$(CONFIG_FB_ATY_CT) += mach64_ct.o +atyfb-$(CONFIG_FB_ATY_XL_INIT) += xlinit.o + +atyfb-objs := $(atyfb-y) + +radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o +radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o +radeonfb-objs := $(radeonfb-y) + diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h new file mode 100644 index 000000000000..13321c689cf6 --- /dev/null +++ b/drivers/video/aty/ati_ids.h @@ -0,0 +1,211 @@ +/* + * ATI PCI IDs from XFree86, kept here to make sync'ing with + * XFree much simpler. Currently, this list is only used by + * radeonfb + */ + +#define PCI_CHIP_RV380_3150 0x3150 +#define PCI_CHIP_RV380_3151 0x3151 +#define PCI_CHIP_RV380_3152 0x3152 +#define PCI_CHIP_RV380_3153 0x3153 +#define PCI_CHIP_RV380_3154 0x3154 +#define PCI_CHIP_RV380_3156 0x3156 +#define PCI_CHIP_RV380_3E50 0x3E50 +#define PCI_CHIP_RV380_3E51 0x3E51 +#define PCI_CHIP_RV380_3E52 0x3E52 +#define PCI_CHIP_RV380_3E53 0x3E53 +#define PCI_CHIP_RV380_3E54 0x3E54 +#define PCI_CHIP_RV380_3E56 0x3E56 +#define PCI_CHIP_RS100_4136 0x4136 +#define PCI_CHIP_RS200_4137 0x4137 +#define PCI_CHIP_R300_AD 0x4144 +#define PCI_CHIP_R300_AE 0x4145 +#define PCI_CHIP_R300_AF 0x4146 +#define PCI_CHIP_R300_AG 0x4147 +#define PCI_CHIP_R350_AH 0x4148 +#define PCI_CHIP_R350_AI 0x4149 +#define PCI_CHIP_R350_AJ 0x414A +#define PCI_CHIP_R350_AK 0x414B +#define PCI_CHIP_RV350_AP 0x4150 +#define PCI_CHIP_RV350_AQ 0x4151 +#define PCI_CHIP_RV360_AR 0x4152 +#define PCI_CHIP_RV350_AS 0x4153 +#define PCI_CHIP_RV350_AT 0x4154 +#define PCI_CHIP_RV350_AV 0x4156 +#define PCI_CHIP_MACH32 0x4158 +#define PCI_CHIP_RS250_4237 0x4237 +#define PCI_CHIP_R200_BB 0x4242 +#define PCI_CHIP_R200_BC 0x4243 +#define PCI_CHIP_RS100_4336 0x4336 +#define PCI_CHIP_RS200_4337 0x4337 +#define PCI_CHIP_MACH64CT 0x4354 +#define PCI_CHIP_MACH64CX 0x4358 +#define PCI_CHIP_RS250_4437 0x4437 +#define PCI_CHIP_MACH64ET 0x4554 +#define PCI_CHIP_MACH64GB 0x4742 +#define PCI_CHIP_MACH64GD 0x4744 +#define PCI_CHIP_MACH64GI 0x4749 +#define PCI_CHIP_MACH64GL 0x474C +#define PCI_CHIP_MACH64GM 0x474D +#define PCI_CHIP_MACH64GN 0x474E +#define PCI_CHIP_MACH64GO 0x474F +#define PCI_CHIP_MACH64GP 0x4750 +#define PCI_CHIP_MACH64GQ 0x4751 +#define PCI_CHIP_MACH64GR 0x4752 +#define PCI_CHIP_MACH64GS 0x4753 +#define PCI_CHIP_MACH64GT 0x4754 +#define PCI_CHIP_MACH64GU 0x4755 +#define PCI_CHIP_MACH64GV 0x4756 +#define PCI_CHIP_MACH64GW 0x4757 +#define PCI_CHIP_MACH64GX 0x4758 +#define PCI_CHIP_MACH64GY 0x4759 +#define PCI_CHIP_MACH64GZ 0x475A +#define PCI_CHIP_RV250_Id 0x4964 +#define PCI_CHIP_RV250_Ie 0x4965 +#define PCI_CHIP_RV250_If 0x4966 +#define PCI_CHIP_RV250_Ig 0x4967 +#define PCI_CHIP_R420_JH 0x4A48 +#define PCI_CHIP_R420_JI 0x4A49 +#define PCI_CHIP_R420_JJ 0x4A4A +#define PCI_CHIP_R420_JK 0x4A4B +#define PCI_CHIP_R420_JL 0x4A4C +#define PCI_CHIP_R420_JM 0x4A4D +#define PCI_CHIP_R420_JN 0x4A4E +#define PCI_CHIP_R420_JP 0x4A50 +#define PCI_CHIP_MACH64LB 0x4C42 +#define PCI_CHIP_MACH64LD 0x4C44 +#define PCI_CHIP_RAGE128LE 0x4C45 +#define PCI_CHIP_RAGE128LF 0x4C46 +#define PCI_CHIP_MACH64LG 0x4C47 +#define PCI_CHIP_MACH64LI 0x4C49 +#define PCI_CHIP_MACH64LM 0x4C4D +#define PCI_CHIP_MACH64LN 0x4C4E +#define PCI_CHIP_MACH64LP 0x4C50 +#define PCI_CHIP_MACH64LQ 0x4C51 +#define PCI_CHIP_MACH64LR 0x4C52 +#define PCI_CHIP_MACH64LS 0x4C53 +#define PCI_CHIP_MACH64LT 0x4C54 +#define PCI_CHIP_RADEON_LW 0x4C57 +#define PCI_CHIP_RADEON_LX 0x4C58 +#define PCI_CHIP_RADEON_LY 0x4C59 +#define PCI_CHIP_RADEON_LZ 0x4C5A +#define PCI_CHIP_RV250_Ld 0x4C64 +#define PCI_CHIP_RV250_Le 0x4C65 +#define PCI_CHIP_RV250_Lf 0x4C66 +#define PCI_CHIP_RV250_Lg 0x4C67 +#define PCI_CHIP_RV250_Ln 0x4C6E +#define PCI_CHIP_RAGE128MF 0x4D46 +#define PCI_CHIP_RAGE128ML 0x4D4C +#define PCI_CHIP_R300_ND 0x4E44 +#define PCI_CHIP_R300_NE 0x4E45 +#define PCI_CHIP_R300_NF 0x4E46 +#define PCI_CHIP_R300_NG 0x4E47 +#define PCI_CHIP_R350_NH 0x4E48 +#define PCI_CHIP_R350_NI 0x4E49 +#define PCI_CHIP_R360_NJ 0x4E4A +#define PCI_CHIP_R350_NK 0x4E4B +#define PCI_CHIP_RV350_NP 0x4E50 +#define PCI_CHIP_RV350_NQ 0x4E51 +#define PCI_CHIP_RV350_NR 0x4E52 +#define PCI_CHIP_RV350_NS 0x4E53 +#define PCI_CHIP_RV350_NT 0x4E54 +#define PCI_CHIP_RV350_NV 0x4E56 +#define PCI_CHIP_RAGE128PA 0x5041 +#define PCI_CHIP_RAGE128PB 0x5042 +#define PCI_CHIP_RAGE128PC 0x5043 +#define PCI_CHIP_RAGE128PD 0x5044 +#define PCI_CHIP_RAGE128PE 0x5045 +#define PCI_CHIP_RAGE128PF 0x5046 +#define PCI_CHIP_RAGE128PG 0x5047 +#define PCI_CHIP_RAGE128PH 0x5048 +#define PCI_CHIP_RAGE128PI 0x5049 +#define PCI_CHIP_RAGE128PJ 0x504A +#define PCI_CHIP_RAGE128PK 0x504B +#define PCI_CHIP_RAGE128PL 0x504C +#define PCI_CHIP_RAGE128PM 0x504D +#define PCI_CHIP_RAGE128PN 0x504E +#define PCI_CHIP_RAGE128PO 0x504F +#define PCI_CHIP_RAGE128PP 0x5050 +#define PCI_CHIP_RAGE128PQ 0x5051 +#define PCI_CHIP_RAGE128PR 0x5052 +#define PCI_CHIP_RAGE128PS 0x5053 +#define PCI_CHIP_RAGE128PT 0x5054 +#define PCI_CHIP_RAGE128PU 0x5055 +#define PCI_CHIP_RAGE128PV 0x5056 +#define PCI_CHIP_RAGE128PW 0x5057 +#define PCI_CHIP_RAGE128PX 0x5058 +#define PCI_CHIP_RADEON_QD 0x5144 +#define PCI_CHIP_RADEON_QE 0x5145 +#define PCI_CHIP_RADEON_QF 0x5146 +#define PCI_CHIP_RADEON_QG 0x5147 +#define PCI_CHIP_R200_QH 0x5148 +#define PCI_CHIP_R200_QI 0x5149 +#define PCI_CHIP_R200_QJ 0x514A +#define PCI_CHIP_R200_QK 0x514B +#define PCI_CHIP_R200_QL 0x514C +#define PCI_CHIP_R200_QM 0x514D +#define PCI_CHIP_R200_QN 0x514E +#define PCI_CHIP_R200_QO 0x514F +#define PCI_CHIP_RV200_QW 0x5157 +#define PCI_CHIP_RV200_QX 0x5158 +#define PCI_CHIP_RV100_QY 0x5159 +#define PCI_CHIP_RV100_QZ 0x515A +#define PCI_CHIP_RAGE128RE 0x5245 +#define PCI_CHIP_RAGE128RF 0x5246 +#define PCI_CHIP_RAGE128RG 0x5247 +#define PCI_CHIP_RAGE128RK 0x524B +#define PCI_CHIP_RAGE128RL 0x524C +#define PCI_CHIP_RAGE128SE 0x5345 +#define PCI_CHIP_RAGE128SF 0x5346 +#define PCI_CHIP_RAGE128SG 0x5347 +#define PCI_CHIP_RAGE128SH 0x5348 +#define PCI_CHIP_RAGE128SK 0x534B +#define PCI_CHIP_RAGE128SL 0x534C +#define PCI_CHIP_RAGE128SM 0x534D +#define PCI_CHIP_RAGE128SN 0x534E +#define PCI_CHIP_RAGE128TF 0x5446 +#define PCI_CHIP_RAGE128TL 0x544C +#define PCI_CHIP_RAGE128TR 0x5452 +#define PCI_CHIP_RAGE128TS 0x5453 +#define PCI_CHIP_RAGE128TT 0x5454 +#define PCI_CHIP_RAGE128TU 0x5455 +#define PCI_CHIP_RV370_5460 0x5460 +#define PCI_CHIP_RV370_5461 0x5461 +#define PCI_CHIP_RV370_5462 0x5462 +#define PCI_CHIP_RV370_5463 0x5463 +#define PCI_CHIP_RV370_5464 0x5464 +#define PCI_CHIP_RV370_5465 0x5465 +#define PCI_CHIP_RV370_5466 0x5466 +#define PCI_CHIP_RV370_5467 0x5467 +#define PCI_CHIP_R423_UH 0x5548 +#define PCI_CHIP_R423_UI 0x5549 +#define PCI_CHIP_R423_UJ 0x554A +#define PCI_CHIP_R423_UK 0x554B +#define PCI_CHIP_R423_UQ 0x5551 +#define PCI_CHIP_R423_UR 0x5552 +#define PCI_CHIP_R423_UT 0x5554 +#define PCI_CHIP_MACH64VT 0x5654 +#define PCI_CHIP_MACH64VU 0x5655 +#define PCI_CHIP_MACH64VV 0x5656 +#define PCI_CHIP_RS300_5834 0x5834 +#define PCI_CHIP_RS300_5835 0x5835 +#define PCI_CHIP_RS300_5836 0x5836 +#define PCI_CHIP_RS300_5837 0x5837 +#define PCI_CHIP_RV370_5B60 0x5B60 +#define PCI_CHIP_RV370_5B61 0x5B61 +#define PCI_CHIP_RV370_5B62 0x5B62 +#define PCI_CHIP_RV370_5B63 0x5B63 +#define PCI_CHIP_RV370_5B64 0x5B64 +#define PCI_CHIP_RV370_5B65 0x5B65 +#define PCI_CHIP_RV370_5B66 0x5B66 +#define PCI_CHIP_RV370_5B67 0x5B67 +#define PCI_CHIP_RV280_5960 0x5960 +#define PCI_CHIP_RV280_5961 0x5961 +#define PCI_CHIP_RV280_5962 0x5962 +#define PCI_CHIP_RV280_5964 0x5964 +#define PCI_CHIP_RV280_5C61 0x5C61 +#define PCI_CHIP_RV280_5C63 0x5C63 +#define PCI_CHIP_R423_5D57 0x5D57 +#define PCI_CHIP_RS350_7834 0x7834 +#define PCI_CHIP_RS350_7835 0x7835 + diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c new file mode 100644 index 000000000000..8a4ba3bb9872 --- /dev/null +++ b/drivers/video/aty/aty128fb.c @@ -0,0 +1,2485 @@ +/* $Id: aty128fb.c,v 1.1.1.1.36.1 1999/12/11 09:03:05 Exp $ + * linux/drivers/video/aty128fb.c -- Frame buffer device for ATI Rage128 + * + * Copyright (C) 1999-2003, Brad Douglas <brad@neruo.com> + * Copyright (C) 1999, Anthony Tong <atong@uiuc.edu> + * + * Ani Joshi / Jeff Garzik + * - Code cleanup + * + * Michel Danzer <michdaen@iiic.ethz.ch> + * - 15/16 bit cleanup + * - fix panning + * + * Benjamin Herrenschmidt + * - pmac-specific PM stuff + * - various fixes & cleanups + * + * Andreas Hundt <andi@convergence.de> + * - FB_ACTIVATE fixes + * + * Paul Mackerras <paulus@samba.org> + * - Convert to new framebuffer API, + * fix colormap setting at 16 bits/pixel (565) + * + * Paul Mundt + * - PCI hotplug + * + * Jon Smirl <jonsmirl@yahoo.com> + * - PCI ID update + * - replace ROM BIOS search + * + * Based off of Geert's atyfb.c and vfb.c. + * + * TODO: + * - monitor sensing (DDC) + * - virtual display + * - other platform support (only ppc/x86 supported) + * - hardware cursor support + * + * Please cc: your patches to brad@neruo.com. + */ + +/* + * A special note of gratitude to ATI's devrel for providing documentation, + * example code and hardware. Thanks Nitya. -atong and brad + */ + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/moduleparam.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <asm/uaccess.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/ioport.h> +#include <linux/console.h> +#include <asm/io.h> + +#ifdef CONFIG_PPC_PMAC +#include <asm/pmac_feature.h> +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#include "../macmodes.h" +#endif + +#ifdef CONFIG_PMAC_BACKLIGHT +#include <asm/backlight.h> +#endif + +#ifdef CONFIG_BOOTX_TEXT +#include <asm/btext.h> +#endif /* CONFIG_BOOTX_TEXT */ + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include <video/aty128.h> + +/* Debug flag */ +#undef DEBUG + +#ifdef DEBUG +#define DBG(fmt, args...) printk(KERN_DEBUG "aty128fb: %s " fmt, __FUNCTION__, ##args); +#else +#define DBG(fmt, args...) +#endif + +#ifndef CONFIG_PPC_PMAC +/* default mode */ +static struct fb_var_screeninfo default_var __initdata = { + /* 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 +}; + +#else /* CONFIG_PPC_PMAC */ +/* default to 1024x768 at 75Hz on PPC - this will work + * on the iMac, the usual 640x480 @ 60Hz doesn't. */ +static struct fb_var_screeninfo default_var = { + /* 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, 160, 32, 28, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED +}; +#endif /* CONFIG_PPC_PMAC */ + +/* default modedb mode */ +/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ +static struct fb_videomode defaultmode __initdata = { + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39722, + .left_margin = 48, + .right_margin = 16, + .upper_margin = 33, + .lower_margin = 10, + .hsync_len = 96, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED +}; + +/* Chip generations */ +enum { + rage_128, + rage_128_pci, + rage_128_pro, + rage_128_pro_pci, + rage_M3, + rage_M3_pci, + rage_M4, + rage_128_ultra, +}; + +/* Must match above enum */ +static const char *r128_family[] __devinitdata = { + "AGP", + "PCI", + "PRO AGP", + "PRO PCI", + "M3 AGP", + "M3 PCI", + "M4 AGP", + "Ultra AGP", +}; + +/* + * PCI driver prototypes + */ +static int aty128_probe(struct pci_dev *pdev, + const struct pci_device_id *ent); +static void aty128_remove(struct pci_dev *pdev); +static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state); +static int aty128_pci_resume(struct pci_dev *pdev); +static int aty128_do_resume(struct pci_dev *pdev); + +/* supported Rage128 chipsets */ +static struct pci_device_id aty128_pci_tbl[] = { + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_MF, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_ML, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PB, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PD, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PF, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PG, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PJ, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PK, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PN, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PQ, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PS, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PU, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PV, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PW, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RG, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SF, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SG, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SK, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SN, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TF, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TS, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TU, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, aty128_pci_tbl); + +static struct pci_driver aty128fb_driver = { + .name = "aty128fb", + .id_table = aty128_pci_tbl, + .probe = aty128_probe, + .remove = __devexit_p(aty128_remove), + .suspend = aty128_pci_suspend, + .resume = aty128_pci_resume, +}; + +/* packed BIOS settings */ +#ifndef CONFIG_PPC +typedef struct { + u8 clock_chip_type; + u8 struct_size; + u8 accelerator_entry; + u8 VGA_entry; + u16 VGA_table_offset; + u16 POST_table_offset; + u16 XCLK; + u16 MCLK; + u8 num_PLL_blocks; + u8 size_PLL_blocks; + u16 PCLK_ref_freq; + u16 PCLK_ref_divider; + u32 PCLK_min_freq; + u32 PCLK_max_freq; + u16 MCLK_ref_freq; + u16 MCLK_ref_divider; + u32 MCLK_min_freq; + u32 MCLK_max_freq; + u16 XCLK_ref_freq; + u16 XCLK_ref_divider; + u32 XCLK_min_freq; + u32 XCLK_max_freq; +} __attribute__ ((packed)) PLL_BLOCK; +#endif /* !CONFIG_PPC */ + +/* onboard memory information */ +struct aty128_meminfo { + u8 ML; + u8 MB; + u8 Trcd; + u8 Trp; + u8 Twr; + u8 CL; + u8 Tr2w; + u8 LoopLatency; + u8 DspOn; + u8 Rloop; + const char *name; +}; + +/* various memory configurations */ +static const struct aty128_meminfo sdr_128 = + { 4, 4, 3, 3, 1, 3, 1, 16, 30, 16, "128-bit SDR SGRAM (1:1)" }; +static const struct aty128_meminfo sdr_64 = + { 4, 8, 3, 3, 1, 3, 1, 17, 46, 17, "64-bit SDR SGRAM (1:1)" }; +static const struct aty128_meminfo sdr_sgram = + { 4, 4, 1, 2, 1, 2, 1, 16, 24, 16, "64-bit SDR SGRAM (2:1)" }; +static const struct aty128_meminfo ddr_sgram = + { 4, 4, 3, 3, 2, 3, 1, 16, 31, 16, "64-bit DDR SGRAM" }; + +static struct fb_fix_screeninfo aty128fb_fix __initdata = { + .id = "ATY Rage128", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .xpanstep = 8, + .ypanstep = 1, + .mmio_len = 0x2000, + .accel = FB_ACCEL_ATI_RAGE128, +}; + +static char *mode_option __initdata = NULL; + +#ifdef CONFIG_PPC_PMAC +static int default_vmode __initdata = VMODE_1024_768_60; +static int default_cmode __initdata = CMODE_8; +#endif + +#ifdef CONFIG_PMAC_PBOOK +static int default_crt_on __initdata = 0; +static int default_lcd_on __initdata = 1; +#endif + +#ifdef CONFIG_MTRR +static int mtrr = 1; +#endif + +/* PLL constants */ +struct aty128_constants { + u32 ref_clk; + u32 ppll_min; + u32 ppll_max; + u32 ref_divider; + u32 xclk; + u32 fifo_width; + u32 fifo_depth; +}; + +struct aty128_crtc { + u32 gen_cntl; + u32 h_total, h_sync_strt_wid; + u32 v_total, v_sync_strt_wid; + u32 pitch; + u32 offset, offset_cntl; + u32 xoffset, yoffset; + u32 vxres, vyres; + u32 depth, bpp; +}; + +struct aty128_pll { + u32 post_divider; + u32 feedback_divider; + u32 vclk; +}; + +struct aty128_ddafifo { + u32 dda_config; + u32 dda_on_off; +}; + +/* register values for a specific mode */ +struct aty128fb_par { + struct aty128_crtc crtc; + struct aty128_pll pll; + struct aty128_ddafifo fifo_reg; + u32 accel_flags; + struct aty128_constants constants; /* PLL and others */ + void __iomem *regbase; /* remapped mmio */ + u32 vram_size; /* onboard video ram */ + int chip_gen; + const struct aty128_meminfo *mem; /* onboard mem info */ +#ifdef CONFIG_MTRR + struct { int vram; int vram_valid; } mtrr; +#endif + int blitter_may_be_busy; + int fifo_slots; /* free slots in FIFO (64 max) */ + + int pm_reg; + int crt_on, lcd_on; + struct pci_dev *pdev; + struct fb_info *next; + int asleep; + int lock_blank; + + u8 red[32]; /* see aty128fb_setcolreg */ + u8 green[64]; + u8 blue[32]; + u32 pseudo_palette[16]; /* used for TRUECOLOR */ +}; + + +#define round_div(n, d) ((n+(d/2))/d) + +static int aty128fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int aty128fb_set_par(struct fb_info *info); +static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int aty128fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fb); +static int aty128fb_blank(int blank, struct fb_info *fb); +static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, struct fb_info *info); +static int aty128fb_sync(struct fb_info *info); + + /* + * Internal routines + */ + +static int aty128_encode_var(struct fb_var_screeninfo *var, + const struct aty128fb_par *par); +static int aty128_decode_var(struct fb_var_screeninfo *var, + struct aty128fb_par *par); +#if 0 +static void __init aty128_get_pllinfo(struct aty128fb_par *par, + void __iomem *bios); +static void __init __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par); +#endif +static void aty128_timings(struct aty128fb_par *par); +static void aty128_init_engine(struct aty128fb_par *par); +static void aty128_reset_engine(const struct aty128fb_par *par); +static void aty128_flush_pixel_cache(const struct aty128fb_par *par); +static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par); +static void wait_for_fifo(u16 entries, struct aty128fb_par *par); +static void wait_for_idle(struct aty128fb_par *par); +static u32 depth_to_dst(u32 depth); + +#define BIOS_IN8(v) (readb(bios + (v))) +#define BIOS_IN16(v) (readb(bios + (v)) | \ + (readb(bios + (v) + 1) << 8)) +#define BIOS_IN32(v) (readb(bios + (v)) | \ + (readb(bios + (v) + 1) << 8) | \ + (readb(bios + (v) + 2) << 16) | \ + (readb(bios + (v) + 3) << 24)) + + +static struct fb_ops aty128fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = aty128fb_check_var, + .fb_set_par = aty128fb_set_par, + .fb_setcolreg = aty128fb_setcolreg, + .fb_pan_display = aty128fb_pan_display, + .fb_blank = aty128fb_blank, + .fb_ioctl = aty128fb_ioctl, + .fb_sync = aty128fb_sync, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +#ifdef CONFIG_PMAC_BACKLIGHT +static int aty128_set_backlight_enable(int on, int level, void* data); +static int aty128_set_backlight_level(int level, void* data); + +static struct backlight_controller aty128_backlight_controller = { + aty128_set_backlight_enable, + aty128_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ + + /* + * Functions to read from/write to the mmio registers + * - endian conversions may possibly be avoided by + * using the other register aperture. TODO. + */ +static inline u32 _aty_ld_le32(volatile unsigned int regindex, + const struct aty128fb_par *par) +{ + return readl (par->regbase + regindex); +} + +static inline void _aty_st_le32(volatile unsigned int regindex, u32 val, + const struct aty128fb_par *par) +{ + writel (val, par->regbase + regindex); +} + +static inline u8 _aty_ld_8(unsigned int regindex, + const struct aty128fb_par *par) +{ + return readb (par->regbase + regindex); +} + +static inline void _aty_st_8(unsigned int regindex, u8 val, + const struct aty128fb_par *par) +{ + writeb (val, par->regbase + regindex); +} + +#define aty_ld_le32(regindex) _aty_ld_le32(regindex, par) +#define aty_st_le32(regindex, val) _aty_st_le32(regindex, val, par) +#define aty_ld_8(regindex) _aty_ld_8(regindex, par) +#define aty_st_8(regindex, val) _aty_st_8(regindex, val, par) + + /* + * Functions to read from/write to the pll registers + */ + +#define aty_ld_pll(pll_index) _aty_ld_pll(pll_index, par) +#define aty_st_pll(pll_index, val) _aty_st_pll(pll_index, val, par) + + +static u32 _aty_ld_pll(unsigned int pll_index, + const struct aty128fb_par *par) +{ + aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F); + return aty_ld_le32(CLOCK_CNTL_DATA); +} + + +static void _aty_st_pll(unsigned int pll_index, u32 val, + const struct aty128fb_par *par) +{ + aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x3F) | PLL_WR_EN); + aty_st_le32(CLOCK_CNTL_DATA, val); +} + + +/* return true when the PLL has completed an atomic update */ +static int aty_pll_readupdate(const struct aty128fb_par *par) +{ + return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); +} + + +static void aty_pll_wait_readupdate(const struct aty128fb_par *par) +{ + unsigned long timeout = jiffies + HZ/100; // should be more than enough + int reset = 1; + + while (time_before(jiffies, timeout)) + if (aty_pll_readupdate(par)) { + reset = 0; + break; + } + + if (reset) /* reset engine?? */ + printk(KERN_DEBUG "aty128fb: PLL write timeout!\n"); +} + + +/* tell PLL to update */ +static void aty_pll_writeupdate(const struct aty128fb_par *par) +{ + aty_pll_wait_readupdate(par); + + aty_st_pll(PPLL_REF_DIV, + aty_ld_pll(PPLL_REF_DIV) | PPLL_ATOMIC_UPDATE_W); +} + + +/* write to the scratch register to test r/w functionality */ +static int __init register_test(const struct aty128fb_par *par) +{ + u32 val; + int flag = 0; + + val = aty_ld_le32(BIOS_0_SCRATCH); + + aty_st_le32(BIOS_0_SCRATCH, 0x55555555); + if (aty_ld_le32(BIOS_0_SCRATCH) == 0x55555555) { + aty_st_le32(BIOS_0_SCRATCH, 0xAAAAAAAA); + + if (aty_ld_le32(BIOS_0_SCRATCH) == 0xAAAAAAAA) + flag = 1; + } + + aty_st_le32(BIOS_0_SCRATCH, val); // restore value + return flag; +} + + +/* + * Accelerator engine functions + */ +static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par) +{ + int i; + + for (;;) { + for (i = 0; i < 2000000; i++) { + par->fifo_slots = aty_ld_le32(GUI_STAT) & 0x0fff; + if (par->fifo_slots >= entries) + return; + } + aty128_reset_engine(par); + } +} + + +static void wait_for_idle(struct aty128fb_par *par) +{ + int i; + + do_wait_for_fifo(64, par); + + for (;;) { + for (i = 0; i < 2000000; i++) { + if (!(aty_ld_le32(GUI_STAT) & (1 << 31))) { + aty128_flush_pixel_cache(par); + par->blitter_may_be_busy = 0; + return; + } + } + aty128_reset_engine(par); + } +} + + +static void wait_for_fifo(u16 entries, struct aty128fb_par *par) +{ + if (par->fifo_slots < entries) + do_wait_for_fifo(64, par); + par->fifo_slots -= entries; +} + + +static void aty128_flush_pixel_cache(const struct aty128fb_par *par) +{ + int i; + u32 tmp; + + tmp = aty_ld_le32(PC_NGUI_CTLSTAT); + tmp &= ~(0x00ff); + tmp |= 0x00ff; + aty_st_le32(PC_NGUI_CTLSTAT, tmp); + + for (i = 0; i < 2000000; i++) + if (!(aty_ld_le32(PC_NGUI_CTLSTAT) & PC_BUSY)) + break; +} + + +static void aty128_reset_engine(const struct aty128fb_par *par) +{ + u32 gen_reset_cntl, clock_cntl_index, mclk_cntl; + + aty128_flush_pixel_cache(par); + + clock_cntl_index = aty_ld_le32(CLOCK_CNTL_INDEX); + mclk_cntl = aty_ld_pll(MCLK_CNTL); + + aty_st_pll(MCLK_CNTL, mclk_cntl | 0x00030000); + + gen_reset_cntl = aty_ld_le32(GEN_RESET_CNTL); + aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl | SOFT_RESET_GUI); + aty_ld_le32(GEN_RESET_CNTL); + aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl & ~(SOFT_RESET_GUI)); + aty_ld_le32(GEN_RESET_CNTL); + + aty_st_pll(MCLK_CNTL, mclk_cntl); + aty_st_le32(CLOCK_CNTL_INDEX, clock_cntl_index); + aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl); + + /* use old pio mode */ + aty_st_le32(PM4_BUFFER_CNTL, PM4_BUFFER_CNTL_NONPM4); + + DBG("engine reset"); +} + + +static void aty128_init_engine(struct aty128fb_par *par) +{ + u32 pitch_value; + + wait_for_idle(par); + + /* 3D scaler not spoken here */ + wait_for_fifo(1, par); + aty_st_le32(SCALE_3D_CNTL, 0x00000000); + + aty128_reset_engine(par); + + pitch_value = par->crtc.pitch; + if (par->crtc.bpp == 24) { + pitch_value = pitch_value * 3; + } + + wait_for_fifo(4, par); + /* setup engine offset registers */ + aty_st_le32(DEFAULT_OFFSET, 0x00000000); + + /* setup engine pitch registers */ + aty_st_le32(DEFAULT_PITCH, pitch_value); + + /* set the default scissor register to max dimensions */ + aty_st_le32(DEFAULT_SC_BOTTOM_RIGHT, (0x1FFF << 16) | 0x1FFF); + + /* set the drawing controls registers */ + aty_st_le32(DP_GUI_MASTER_CNTL, + GMC_SRC_PITCH_OFFSET_DEFAULT | + GMC_DST_PITCH_OFFSET_DEFAULT | + GMC_SRC_CLIP_DEFAULT | + GMC_DST_CLIP_DEFAULT | + GMC_BRUSH_SOLIDCOLOR | + (depth_to_dst(par->crtc.depth) << 8) | + GMC_SRC_DSTCOLOR | + GMC_BYTE_ORDER_MSB_TO_LSB | + GMC_DP_CONVERSION_TEMP_6500 | + ROP3_PATCOPY | + GMC_DP_SRC_RECT | + GMC_3D_FCN_EN_CLR | + GMC_DST_CLR_CMP_FCN_CLEAR | + GMC_AUX_CLIP_CLEAR | + GMC_WRITE_MASK_SET); + + wait_for_fifo(8, par); + /* clear the line drawing registers */ + aty_st_le32(DST_BRES_ERR, 0); + aty_st_le32(DST_BRES_INC, 0); + aty_st_le32(DST_BRES_DEC, 0); + + /* set brush color registers */ + aty_st_le32(DP_BRUSH_FRGD_CLR, 0xFFFFFFFF); /* white */ + aty_st_le32(DP_BRUSH_BKGD_CLR, 0x00000000); /* black */ + + /* set source color registers */ + aty_st_le32(DP_SRC_FRGD_CLR, 0xFFFFFFFF); /* white */ + aty_st_le32(DP_SRC_BKGD_CLR, 0x00000000); /* black */ + + /* default write mask */ + aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF); + + /* Wait for all the writes to be completed before returning */ + wait_for_idle(par); +} + + +/* convert depth values to their register representation */ +static u32 depth_to_dst(u32 depth) +{ + if (depth <= 8) + return DST_8BPP; + else if (depth <= 15) + return DST_15BPP; + else if (depth == 16) + return DST_16BPP; + else if (depth <= 24) + return DST_24BPP; + else if (depth <= 32) + return DST_32BPP; + + return -EINVAL; +} + +/* + * PLL informations retreival + */ + + +#ifndef __sparc__ +static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev) +{ + u16 dptr; + u8 rom_type; + void __iomem *bios; + size_t rom_size; + + /* Fix from ATI for problem with Rage128 hardware not leaving ROM enabled */ + unsigned int temp; + temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG); + temp &= 0x00ffffffu; + temp |= 0x04 << 24; + aty_st_le32(RAGE128_MPP_TB_CONFIG, temp); + temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG); + + bios = pci_map_rom(dev, &rom_size); + + if (!bios) { + printk(KERN_ERR "aty128fb: ROM failed to map\n"); + return NULL; + } + + /* Very simple test to make sure it appeared */ + if (BIOS_IN16(0) != 0xaa55) { + printk(KERN_ERR "aty128fb: Invalid ROM signature %x should be 0xaa55\n", + BIOS_IN16(0)); + goto failed; + } + + /* Look for the PCI data to check the ROM type */ + dptr = BIOS_IN16(0x18); + + /* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM + * for now, until I've verified this works everywhere. The goal here is more + * to phase out Open Firmware images. + * + * Currently, we only look at the first PCI data, we could iteratre and deal with + * them all, and we should use fb_bios_start relative to start of image and not + * relative start of ROM, but so far, I never found a dual-image ATI card + * + * typedef struct { + * u32 signature; + 0x00 + * u16 vendor; + 0x04 + * u16 device; + 0x06 + * u16 reserved_1; + 0x08 + * u16 dlen; + 0x0a + * u8 drevision; + 0x0c + * u8 class_hi; + 0x0d + * u16 class_lo; + 0x0e + * u16 ilen; + 0x10 + * u16 irevision; + 0x12 + * u8 type; + 0x14 + * u8 indicator; + 0x15 + * u16 reserved_2; + 0x16 + * } pci_data_t; + */ + if (BIOS_IN32(dptr) != (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) { + printk(KERN_WARNING "aty128fb: PCI DATA signature in ROM incorrect: %08x\n", + BIOS_IN32(dptr)); + goto anyway; + } + rom_type = BIOS_IN8(dptr + 0x14); + switch(rom_type) { + case 0: + printk(KERN_INFO "aty128fb: Found Intel x86 BIOS ROM Image\n"); + break; + case 1: + printk(KERN_INFO "aty128fb: Found Open Firmware ROM Image\n"); + goto failed; + case 2: + printk(KERN_INFO "aty128fb: Found HP PA-RISC ROM Image\n"); + goto failed; + default: + printk(KERN_INFO "aty128fb: Found unknown type %d ROM Image\n", rom_type); + goto failed; + } + anyway: + return bios; + + failed: + pci_unmap_rom(dev, bios); + return NULL; +} + +static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios) +{ + unsigned int bios_hdr; + unsigned int bios_pll; + + bios_hdr = BIOS_IN16(0x48); + bios_pll = BIOS_IN16(bios_hdr + 0x30); + + par->constants.ppll_max = BIOS_IN32(bios_pll + 0x16); + par->constants.ppll_min = BIOS_IN32(bios_pll + 0x12); + par->constants.xclk = BIOS_IN16(bios_pll + 0x08); + par->constants.ref_divider = BIOS_IN16(bios_pll + 0x10); + par->constants.ref_clk = BIOS_IN16(bios_pll + 0x0e); + + DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d ref clock %d\n", + par->constants.ppll_max, par->constants.ppll_min, + par->constants.xclk, par->constants.ref_divider, + par->constants.ref_clk); + +} + +#ifdef CONFIG_X86 +static void __iomem * __devinit aty128_find_mem_vbios(struct aty128fb_par *par) +{ + /* I simplified this code as we used to miss the signatures in + * a lot of case. It's now closer to XFree, we just don't check + * for signatures at all... Something better will have to be done + * if we end up having conflicts + */ + u32 segstart; + unsigned char __iomem *rom_base = NULL; + + for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { + rom_base = ioremap(segstart, 0x10000); + if (rom_base == NULL) + return NULL; + if (readb(rom_base) == 0x55 && readb(rom_base + 1) == 0xaa) + break; + iounmap(rom_base); + rom_base = NULL; + } + return rom_base; +} +#endif +#endif /* ndef(__sparc__) */ + +/* fill in known card constants if pll_block is not available */ +static void __init aty128_timings(struct aty128fb_par *par) +{ +#ifdef CONFIG_PPC_OF + /* instead of a table lookup, assume OF has properly + * setup the PLL registers and use their values + * to set the XCLK values and reference divider values */ + + u32 x_mpll_ref_fb_div; + u32 xclk_cntl; + u32 Nx, M; + unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 }; +#endif + + if (!par->constants.ref_clk) + par->constants.ref_clk = 2950; + +#ifdef CONFIG_PPC_OF + x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV); + xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7; + Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8; + M = x_mpll_ref_fb_div & 0x0000ff; + + par->constants.xclk = round_div((2 * Nx * par->constants.ref_clk), + (M * PostDivSet[xclk_cntl])); + + par->constants.ref_divider = + aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; +#endif + + if (!par->constants.ref_divider) { + par->constants.ref_divider = 0x3b; + + aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e); + aty_pll_writeupdate(par); + } + aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider); + aty_pll_writeupdate(par); + + /* from documentation */ + if (!par->constants.ppll_min) + par->constants.ppll_min = 12500; + if (!par->constants.ppll_max) + par->constants.ppll_max = 25000; /* 23000 on some cards? */ + if (!par->constants.xclk) + par->constants.xclk = 0x1d4d; /* same as mclk */ + + par->constants.fifo_width = 128; + par->constants.fifo_depth = 32; + + switch (aty_ld_le32(MEM_CNTL) & 0x3) { + case 0: + par->mem = &sdr_128; + break; + case 1: + par->mem = &sdr_sgram; + break; + case 2: + par->mem = &ddr_sgram; + break; + default: + par->mem = &sdr_sgram; + } +} + + + +/* + * CRTC programming + */ + +/* Program the CRTC registers */ +static void aty128_set_crtc(const struct aty128_crtc *crtc, + const struct aty128fb_par *par) +{ + aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl); + aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total); + aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid); + aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_total); + aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid); + aty_st_le32(CRTC_PITCH, crtc->pitch); + aty_st_le32(CRTC_OFFSET, crtc->offset); + aty_st_le32(CRTC_OFFSET_CNTL, crtc->offset_cntl); + /* Disable ATOMIC updating. Is this the right place? */ + aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~(0x00030000)); +} + + +static int aty128_var_to_crtc(const struct fb_var_screeninfo *var, + struct aty128_crtc *crtc, + const struct aty128fb_par *par) +{ + u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp, dst; + u32 left, right, upper, lower, hslen, vslen, sync, vmode; + u32 h_total, h_disp, h_sync_strt, h_sync_wid, h_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; + u32 depth, bytpp; + u8 mode_bytpp[7] = { 0, 0, 1, 2, 2, 3, 4 }; + + /* input */ + xres = var->xres; + yres = var->yres; + vxres = var->xres_virtual; + vyres = var->yres_virtual; + xoffset = var->xoffset; + yoffset = var->yoffset; + bpp = var->bits_per_pixel; + left = var->left_margin; + right = var->right_margin; + upper = var->upper_margin; + lower = var->lower_margin; + hslen = var->hsync_len; + vslen = var->vsync_len; + sync = var->sync; + vmode = var->vmode; + + if (bpp != 16) + depth = bpp; + else + depth = (var->green.length == 6) ? 16 : 15; + + /* check for mode eligibility + * accept only non interlaced modes */ + if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + return -EINVAL; + + /* convert (and round up) and validate */ + xres = (xres + 7) & ~7; + xoffset = (xoffset + 7) & ~7; + + if (vxres < xres + xoffset) + vxres = xres + xoffset; + + if (vyres < yres + yoffset) + vyres = yres + yoffset; + + /* convert depth into ATI register depth */ + dst = depth_to_dst(depth); + + if (dst == -EINVAL) { + printk(KERN_ERR "aty128fb: Invalid depth or RGBA\n"); + return -EINVAL; + } + + /* convert register depth to bytes per pixel */ + bytpp = mode_bytpp[dst]; + + /* make sure there is enough video ram for the mode */ + if ((u32)(vxres * vyres * bytpp) > par->vram_size) { + printk(KERN_ERR "aty128fb: Not enough memory for mode\n"); + return -EINVAL; + } + + h_disp = (xres >> 3) - 1; + h_total = (((xres + right + hslen + left) >> 3) - 1) & 0xFFFFL; + + v_disp = yres - 1; + v_total = (yres + upper + vslen + lower - 1) & 0xFFFFL; + + /* check to make sure h_total and v_total are in range */ + if (((h_total >> 3) - 1) > 0x1ff || (v_total - 1) > 0x7FF) { + printk(KERN_ERR "aty128fb: invalid width ranges\n"); + return -EINVAL; + } + + h_sync_wid = (hslen + 7) >> 3; + if (h_sync_wid == 0) + h_sync_wid = 1; + else if (h_sync_wid > 0x3f) /* 0x3f = max hwidth */ + h_sync_wid = 0x3f; + + h_sync_strt = (h_disp << 3) + right; + + v_sync_wid = vslen; + if (v_sync_wid == 0) + v_sync_wid = 1; + else if (v_sync_wid > 0x1f) /* 0x1f = max vwidth */ + v_sync_wid = 0x1f; + + v_sync_strt = v_disp + lower; + + h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + + c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; + + crtc->gen_cntl = 0x3000000L | c_sync | (dst << 8); + + crtc->h_total = h_total | (h_disp << 16); + crtc->v_total = v_total | (v_disp << 16); + + crtc->h_sync_strt_wid = h_sync_strt | (h_sync_wid << 16) | + (h_sync_pol << 23); + crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) | + (v_sync_pol << 23); + + crtc->pitch = vxres >> 3; + + crtc->offset = 0; + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) + crtc->offset_cntl = 0x00010000; + else + crtc->offset_cntl = 0; + + crtc->vxres = vxres; + crtc->vyres = vyres; + crtc->xoffset = xoffset; + crtc->yoffset = yoffset; + crtc->depth = depth; + crtc->bpp = bpp; + + return 0; +} + + +static int aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var) +{ + + /* fill in pixel info */ + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.offset = 0; + var->blue.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + switch (pix_width) { + case CRTC_PIX_WIDTH_8BPP: + var->bits_per_pixel = 8; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.length = 8; + break; + case CRTC_PIX_WIDTH_15BPP: + var->bits_per_pixel = 16; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.length = 5; + break; + case CRTC_PIX_WIDTH_16BPP: + var->bits_per_pixel = 16; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.length = 5; + break; + case CRTC_PIX_WIDTH_24BPP: + var->bits_per_pixel = 24; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.length = 8; + break; + case CRTC_PIX_WIDTH_32BPP: + var->bits_per_pixel = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + default: + printk(KERN_ERR "aty128fb: Invalid pixel width\n"); + return -EINVAL; + } + + return 0; +} + + +static int aty128_crtc_to_var(const struct aty128_crtc *crtc, + struct fb_var_screeninfo *var) +{ + u32 xres, yres, left, right, upper, lower, hslen, vslen, sync; + u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; + u32 pix_width; + + /* fun with masking */ + h_total = crtc->h_total & 0x1ff; + h_disp = (crtc->h_total >> 16) & 0xff; + h_sync_strt = (crtc->h_sync_strt_wid >> 3) & 0x1ff; + h_sync_dly = crtc->h_sync_strt_wid & 0x7; + h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x3f; + h_sync_pol = (crtc->h_sync_strt_wid >> 23) & 0x1; + v_total = crtc->v_total & 0x7ff; + v_disp = (crtc->v_total >> 16) & 0x7ff; + v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; + v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f; + v_sync_pol = (crtc->v_sync_strt_wid >> 23) & 0x1; + c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; + pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; + + /* do conversions */ + xres = (h_disp + 1) << 3; + yres = v_disp + 1; + left = ((h_total - h_sync_strt - h_sync_wid) << 3) - h_sync_dly; + right = ((h_sync_strt - h_disp) << 3) + h_sync_dly; + hslen = h_sync_wid << 3; + upper = v_total - v_sync_strt - v_sync_wid; + lower = v_sync_strt - v_disp; + vslen = v_sync_wid; + sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | + (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | + (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); + + aty128_pix_width_to_var(pix_width, var); + + var->xres = xres; + var->yres = yres; + var->xres_virtual = crtc->vxres; + var->yres_virtual = crtc->vyres; + var->xoffset = crtc->xoffset; + var->yoffset = crtc->yoffset; + var->left_margin = left; + var->right_margin = right; + var->upper_margin = upper; + var->lower_margin = lower; + var->hsync_len = hslen; + var->vsync_len = vslen; + var->sync = sync; + var->vmode = FB_VMODE_NONINTERLACED; + + return 0; +} + +#ifdef CONFIG_PMAC_PBOOK +static void aty128_set_crt_enable(struct aty128fb_par *par, int on) +{ + if (on) { + aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | CRT_CRTC_ON); + aty_st_le32(DAC_CNTL, (aty_ld_le32(DAC_CNTL) | DAC_PALETTE2_SNOOP_EN)); + } else + aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & ~CRT_CRTC_ON); +} + +static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) +{ + u32 reg; + + if (on) { + reg = aty_ld_le32(LVDS_GEN_CNTL); + reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION; + reg &= ~LVDS_DISPLAY_DIS; + aty_st_le32(LVDS_GEN_CNTL, reg); +#ifdef CONFIG_PMAC_BACKLIGHT + aty128_set_backlight_enable(get_backlight_enable(), + get_backlight_level(), par); +#endif + } else { +#ifdef CONFIG_PMAC_BACKLIGHT + aty128_set_backlight_enable(0, 0, par); +#endif + reg = aty_ld_le32(LVDS_GEN_CNTL); + reg |= LVDS_DISPLAY_DIS; + aty_st_le32(LVDS_GEN_CNTL, reg); + mdelay(100); + reg &= ~(LVDS_ON /*| LVDS_EN*/); + aty_st_le32(LVDS_GEN_CNTL, reg); + } +} +#endif /* CONFIG_PMAC_PBOOK */ + +static void aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par) +{ + u32 div3; + + unsigned char post_conv[] = /* register values for post dividers */ + { 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 }; + + /* select PPLL_DIV_3 */ + aty_st_le32(CLOCK_CNTL_INDEX, aty_ld_le32(CLOCK_CNTL_INDEX) | (3 << 8)); + + /* reset PLL */ + aty_st_pll(PPLL_CNTL, + aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN); + + /* write the reference divider */ + aty_pll_wait_readupdate(par); + aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider & 0x3ff); + aty_pll_writeupdate(par); + + div3 = aty_ld_pll(PPLL_DIV_3); + div3 &= ~PPLL_FB3_DIV_MASK; + div3 |= pll->feedback_divider; + div3 &= ~PPLL_POST3_DIV_MASK; + div3 |= post_conv[pll->post_divider] << 16; + + /* write feedback and post dividers */ + aty_pll_wait_readupdate(par); + aty_st_pll(PPLL_DIV_3, div3); + aty_pll_writeupdate(par); + + aty_pll_wait_readupdate(par); + aty_st_pll(HTOTAL_CNTL, 0); /* no horiz crtc adjustment */ + aty_pll_writeupdate(par); + + /* clear the reset, just in case */ + aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET); +} + + +static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, + const struct aty128fb_par *par) +{ + const struct aty128_constants c = par->constants; + unsigned char post_dividers[] = {1,2,4,8,3,6,12}; + u32 output_freq; + u32 vclk; /* in .01 MHz */ + int i; + u32 n, d; + + vclk = 100000000 / period_in_ps; /* convert units to 10 kHz */ + + /* adjust pixel clock if necessary */ + if (vclk > c.ppll_max) + vclk = c.ppll_max; + if (vclk * 12 < c.ppll_min) + vclk = c.ppll_min/12; + + /* now, find an acceptable divider */ + for (i = 0; i < sizeof(post_dividers); i++) { + output_freq = post_dividers[i] * vclk; + if (output_freq >= c.ppll_min && output_freq <= c.ppll_max) + break; + } + + /* calculate feedback divider */ + n = c.ref_divider * output_freq; + d = c.ref_clk; + + pll->post_divider = post_dividers[i]; + pll->feedback_divider = round_div(n, d); + pll->vclk = vclk; + + DBG("post %d feedback %d vlck %d output %d ref_divider %d " + "vclk_per: %d\n", pll->post_divider, + pll->feedback_divider, vclk, output_freq, + c.ref_divider, period_in_ps); + + return 0; +} + + +static int aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var) +{ + var->pixclock = 100000000 / pll->vclk; + + return 0; +} + + +static void aty128_set_fifo(const struct aty128_ddafifo *dsp, + const struct aty128fb_par *par) +{ + aty_st_le32(DDA_CONFIG, dsp->dda_config); + aty_st_le32(DDA_ON_OFF, dsp->dda_on_off); +} + + +static int aty128_ddafifo(struct aty128_ddafifo *dsp, + const struct aty128_pll *pll, + u32 depth, + const struct aty128fb_par *par) +{ + const struct aty128_meminfo *m = par->mem; + u32 xclk = par->constants.xclk; + u32 fifo_width = par->constants.fifo_width; + u32 fifo_depth = par->constants.fifo_depth; + s32 x, b, p, ron, roff; + u32 n, d, bpp; + + /* round up to multiple of 8 */ + bpp = (depth+7) & ~7; + + n = xclk * fifo_width; + d = pll->vclk * bpp; + x = round_div(n, d); + + ron = 4 * m->MB + + 3 * ((m->Trcd - 2 > 0) ? m->Trcd - 2 : 0) + + 2 * m->Trp + + m->Twr + + m->CL + + m->Tr2w + + x; + + DBG("x %x\n", x); + + b = 0; + while (x) { + x >>= 1; + b++; + } + p = b + 1; + + ron <<= (11 - p); + + n <<= (11 - p); + x = round_div(n, d); + roff = x * (fifo_depth - 4); + + if ((ron + m->Rloop) >= roff) { + printk(KERN_ERR "aty128fb: Mode out of range!\n"); + return -EINVAL; + } + + DBG("p: %x rloop: %x x: %x ron: %x roff: %x\n", + p, m->Rloop, x, ron, roff); + + dsp->dda_config = p << 16 | m->Rloop << 20 | x; + dsp->dda_on_off = ron << 16 | roff; + + return 0; +} + + +/* + * This actually sets the video mode. + */ +static int 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); + + /* clear all registers that may interfere with mode setting */ + aty_st_le32(OVR_CLR, 0); + aty_st_le32(OVR_WID_LEFT_RIGHT, 0); + aty_st_le32(OVR_WID_TOP_BOTTOM, 0); + aty_st_le32(OV0_SCALE_CNTL, 0); + aty_st_le32(MPP_TB_CONFIG, 0); + aty_st_le32(MPP_GP_CONFIG, 0); + aty_st_le32(SUBPIC_CNTL, 0); + aty_st_le32(VIPH_CONTROL, 0); + aty_st_le32(I2C_CNTL_1, 0); /* turn off i2c */ + aty_st_le32(GEN_INT_CNTL, 0); /* turn off interrupts */ + aty_st_le32(CAP0_TRIG_CNTL, 0); + aty_st_le32(CAP1_TRIG_CNTL, 0); + + aty_st_8(CRTC_EXT_CNTL + 1, 4); /* turn video off */ + + aty128_set_crtc(&par->crtc, par); + aty128_set_pll(&par->pll, par); + aty128_set_fifo(&par->fifo_reg, par); + + config = aty_ld_le32(CONFIG_CNTL) & ~3; + +#if defined(__BIG_ENDIAN) + if (par->crtc.bpp == 32) + config |= 2; /* make aperture do 32 bit swapping */ + else if (par->crtc.bpp == 16) + config |= 1; /* make aperture do 16 bit swapping */ +#endif + + aty_st_le32(CONFIG_CNTL, config); + aty_st_8(CRTC_EXT_CNTL + 1, 0); /* turn the video back on */ + + info->fix.line_length = (par->crtc.vxres * par->crtc.bpp) >> 3; + info->fix.visual = par->crtc.bpp == 8 ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_DIRECTCOLOR; + +#ifdef CONFIG_PMAC_PBOOK + if (par->chip_gen == rage_M3) { + aty128_set_crt_enable(par, par->crt_on); + aty128_set_lcd_enable(par, par->lcd_on); + } +#endif + if (par->accel_flags & FB_ACCELF_TEXT) + aty128_init_engine(par); + +#ifdef CONFIG_BOOTX_TEXT + btext_update_display(info->fix.smem_start, + (((par->crtc.h_total>>16) & 0xff)+1)*8, + ((par->crtc.v_total>>16) & 0x7ff)+1, + par->crtc.bpp, + par->crtc.vxres*par->crtc.bpp/8); +#endif /* CONFIG_BOOTX_TEXT */ + + return 0; +} + +/* + * encode/decode the User Defined Part of the Display + */ + +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, &crtc, par))) + return err; + + if ((err = aty128_var_to_pll(var->pixclock, &pll, par))) + return err; + + 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; +} + + +static int aty128_encode_var(struct fb_var_screeninfo *var, + const struct aty128fb_par *par) +{ + int err; + + if ((err = aty128_crtc_to_var(&par->crtc, var))) + return err; + + if ((err = aty128_pll_to_var(&par->pll, var))) + return err; + + var->nonstd = 0; + var->activate = 0; + + var->height = -1; + var->width = -1; + var->accel_flags = par->accel_flags; + + return 0; +} + + +static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct aty128fb_par par; + int err; + + par = *(struct aty128fb_par *)info->par; + if ((err = aty128_decode_var(var, &par)) != 0) + return err; + aty128_encode_var(var, &par); + return 0; +} + + +/* + * Pan or Wrap the Display + */ +static int aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb) +{ + struct aty128fb_par *par = fb->par; + u32 xoffset, yoffset; + u32 offset; + u32 xres, yres; + + xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3; + yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1; + + xoffset = (var->xoffset +7) & ~7; + yoffset = var->yoffset; + + if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres) + return -EINVAL; + + par->crtc.xoffset = xoffset; + par->crtc.yoffset = yoffset; + + offset = ((yoffset * par->crtc.vxres + xoffset)*(par->crtc.bpp >> 3)) & ~7; + + if (par->crtc.bpp == 24) + offset += 8 * (offset % 3); /* Must be multiple of 8 and 3 */ + + aty_st_le32(CRTC_OFFSET, offset); + + return 0; +} + + +/* + * Helper function to store a single palette register + */ +static void aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue, + struct aty128fb_par *par) +{ + if (par->chip_gen == rage_M3) { +#if 0 + /* Note: For now, on M3, we set palette on both heads, which may + * be useless. Can someone with a M3 check this ? + * + * This code would still be useful if using the second CRTC to + * do mirroring + */ + + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); + aty_st_8(PALETTE_INDEX, regno); + aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue); +#endif + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); + } + + aty_st_8(PALETTE_INDEX, regno); + aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue); +} + +static int aty128fb_sync(struct fb_info *info) +{ + struct aty128fb_par *par = info->par; + + if (par->blitter_may_be_busy) + wait_for_idle(par); + return 0; +} + +#ifndef MODULE +static int __init aty128fb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { +#ifdef CONFIG_PMAC_PBOOK + if (!strncmp(this_opt, "lcd:", 4)) { + default_lcd_on = simple_strtoul(this_opt+4, NULL, 0); + continue; + } else if (!strncmp(this_opt, "crt:", 4)) { + default_crt_on = simple_strtoul(this_opt+4, NULL, 0); + continue; + } +#endif +#ifdef CONFIG_MTRR + if(!strncmp(this_opt, "nomtrr", 6)) { + mtrr = 0; + continue; + } +#endif +#ifdef CONFIG_PPC_PMAC + /* vmode and cmode deprecated */ + if (!strncmp(this_opt, "vmode:", 6)) { + unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + default_vmode = vmode; + continue; + } else if (!strncmp(this_opt, "cmode:", 6)) { + unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); + switch (cmode) { + case 0: + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + case 24: + case 32: + default_cmode = CMODE_32; + break; + } + continue; + } +#endif /* CONFIG_PPC_PMAC */ + mode_option = this_opt; + } + return 0; +} +#endif /* MODULE */ + + +/* + * Initialisation + */ + +#ifdef CONFIG_PPC_PMAC +static void aty128_early_resume(void *data) +{ + struct aty128fb_par *par = data; + + if (try_acquire_console_sem()) + return; + aty128_do_resume(par->pdev); + release_console_sem(); +} +#endif /* CONFIG_PPC_PMAC */ + +static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct aty128fb_par *par = info->par; + struct fb_var_screeninfo var; + char video_card[DEVICE_NAME_SIZE]; + u8 chip_rev; + u32 dac; + + if (!par->vram_size) /* may have already been probed */ + par->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF; + + /* Get the chip revision */ + chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F; + + strcpy(video_card, "Rage128 XX "); + video_card[8] = ent->device >> 8; + video_card[9] = ent->device & 0xFF; + + /* range check to make sure */ + if (ent->driver_data < (sizeof(r128_family)/sizeof(char *))) + strncat(video_card, r128_family[ent->driver_data], sizeof(video_card)); + + printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); + + if (par->vram_size % (1024 * 1024) == 0) + printk("%dM %s\n", par->vram_size / (1024*1024), par->mem->name); + else + printk("%dk %s\n", par->vram_size / 1024, par->mem->name); + + par->chip_gen = ent->driver_data; + + /* fill in info */ + info->fbops = &aty128fb_ops; + info->flags = FBINFO_FLAG_DEFAULT; + +#ifdef CONFIG_PMAC_PBOOK + par->lcd_on = default_lcd_on; + par->crt_on = default_crt_on; +#endif + + var = default_var; +#ifdef CONFIG_PPC_PMAC + if (_machine == _MACH_Pmac) { + /* Indicate sleep capability */ + if (par->chip_gen == rage_M3) { + pmac_call_feature(PMAC_FTR_DEVICE_CAN_WAKE, NULL, 0, 1); + pmac_set_early_video_resume(aty128_early_resume, par); + } + + /* Find default mode */ + if (mode_option) { + if (!mac_find_mode(&var, info, mode_option, 8)) + var = default_var; + } else { + if (default_vmode <= 0 || default_vmode > VMODE_MAX) + default_vmode = VMODE_1024_768_60; + + /* iMacs need that resolution + * PowerMac2,1 first r128 iMacs + * PowerMac2,2 summer 2000 iMacs + * PowerMac4,1 january 2001 iMacs "flower power" + */ + if (machine_is_compatible("PowerMac2,1") || + machine_is_compatible("PowerMac2,2") || + machine_is_compatible("PowerMac4,1")) + default_vmode = VMODE_1024_768_75; + + /* iBook SE */ + if (machine_is_compatible("PowerBook2,2")) + default_vmode = VMODE_800_600_60; + + /* PowerBook Firewire (Pismo), iBook Dual USB */ + if (machine_is_compatible("PowerBook3,1") || + machine_is_compatible("PowerBook4,1")) + default_vmode = VMODE_1024_768_60; + + /* PowerBook Titanium */ + if (machine_is_compatible("PowerBook3,2")) + default_vmode = VMODE_1152_768_60; + + if (default_cmode > 16) + default_cmode = CMODE_32; + else if (default_cmode > 8) + default_cmode = CMODE_16; + else + default_cmode = CMODE_8; + + if (mac_vmode_to_var(default_vmode, default_cmode, &var)) + var = default_var; + } + } else +#endif /* CONFIG_PPC_PMAC */ + { + if (mode_option) + if (fb_find_mode(&var, info, mode_option, NULL, + 0, &defaultmode, 8) == 0) + var = default_var; + } + + var.accel_flags &= ~FB_ACCELF_TEXT; +// var.accel_flags |= FB_ACCELF_TEXT;/* FIXME Will add accel later */ + + if (aty128fb_check_var(&var, info)) { + printk(KERN_ERR "aty128fb: Cannot set default mode.\n"); + return 0; + } + + /* setup the DAC the way we like it */ + dac = aty_ld_le32(DAC_CNTL); + dac |= (DAC_8BIT_EN | DAC_RANGE_CNTL); + dac |= DAC_MASK; + if (par->chip_gen == rage_M3) + dac |= DAC_PALETTE2_SNOOP_EN; + aty_st_le32(DAC_CNTL, dac); + + /* turn off bus mastering, just in case */ + aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_MASTER_DIS); + + info->var = var; + fb_alloc_cmap(&info->cmap, 256, 0); + + var.activate = FB_ACTIVATE_NOW; + + aty128_init_engine(par); + + if (register_framebuffer(info) < 0) + return 0; + +#ifdef CONFIG_PMAC_BACKLIGHT + /* Could be extended to Rage128Pro LVDS output too */ + if (par->chip_gen == rage_M3) + register_backlight_controller(&aty128_backlight_controller, par, "ati"); +#endif /* CONFIG_PMAC_BACKLIGHT */ + + par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); + par->pdev = pdev; + par->asleep = 0; + par->lock_blank = 0; + + printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", + info->node, info->fix.id, video_card); + + return 1; /* success! */ +} + +#ifdef CONFIG_PCI +/* register a card ++ajoshi */ +static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + unsigned long fb_addr, reg_addr; + struct aty128fb_par *par; + struct fb_info *info; + int err; +#ifndef __sparc__ + void __iomem *bios = NULL; +#endif + + /* Enable device in PCI config */ + if ((err = pci_enable_device(pdev))) { + printk(KERN_ERR "aty128fb: Cannot enable PCI device: %d\n", + err); + return -ENODEV; + } + + fb_addr = pci_resource_start(pdev, 0); + if (!request_mem_region(fb_addr, pci_resource_len(pdev, 0), + "aty128fb FB")) { + printk(KERN_ERR "aty128fb: cannot reserve frame " + "buffer memory\n"); + return -ENODEV; + } + + reg_addr = pci_resource_start(pdev, 2); + if (!request_mem_region(reg_addr, pci_resource_len(pdev, 2), + "aty128fb MMIO")) { + printk(KERN_ERR "aty128fb: cannot reserve MMIO region\n"); + goto err_free_fb; + } + + /* We have the resources. Now virtualize them */ + info = framebuffer_alloc(sizeof(struct aty128fb_par), &pdev->dev); + if (info == NULL) { + printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n"); + goto err_free_mmio; + } + par = info->par; + + info->pseudo_palette = par->pseudo_palette; + info->fix = aty128fb_fix; + + /* Virtualize mmio region */ + info->fix.mmio_start = reg_addr; + par->regbase = ioremap(reg_addr, pci_resource_len(pdev, 2)); + if (!par->regbase) + goto err_free_info; + + /* Grab memory size from the card */ + // How does this relate to the resource length from the PCI hardware? + par->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF; + + /* Virtualize the framebuffer */ + info->screen_base = ioremap(fb_addr, par->vram_size); + if (!info->screen_base) + goto err_unmap_out; + + /* Set up info->fix */ + info->fix = aty128fb_fix; + info->fix.smem_start = fb_addr; + info->fix.smem_len = par->vram_size; + info->fix.mmio_start = reg_addr; + + /* If we can't test scratch registers, something is seriously wrong */ + if (!register_test(par)) { + printk(KERN_ERR "aty128fb: Can't write to video register!\n"); + goto err_out; + } + +#ifndef __sparc__ + bios = aty128_map_ROM(par, pdev); +#ifdef CONFIG_X86 + if (bios == NULL) + bios = aty128_find_mem_vbios(par); +#endif + if (bios == NULL) + printk(KERN_INFO "aty128fb: BIOS not located, guessing timings.\n"); + else { + printk(KERN_INFO "aty128fb: Rage128 BIOS located\n"); + aty128_get_pllinfo(par, bios); + pci_unmap_rom(pdev, bios); + } +#endif /* __sparc__ */ + + aty128_timings(par); + pci_set_drvdata(pdev, info); + + if (!aty128_init(pdev, ent)) + goto err_out; + +#ifdef CONFIG_MTRR + if (mtrr) { + par->mtrr.vram = mtrr_add(info->fix.smem_start, + par->vram_size, MTRR_TYPE_WRCOMB, 1); + par->mtrr.vram_valid = 1; + /* let there be speed */ + printk(KERN_INFO "aty128fb: Rage128 MTRR set to ON\n"); + } +#endif /* CONFIG_MTRR */ + return 0; + +err_out: + iounmap(info->screen_base); +err_unmap_out: + iounmap(par->regbase); +err_free_info: + framebuffer_release(info); +err_free_mmio: + release_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); +err_free_fb: + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + return -ENODEV; +} + +static void __devexit aty128_remove(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct aty128fb_par *par; + + if (!info) + return; + + par = info->par; + + unregister_framebuffer(info); +#ifdef CONFIG_MTRR + if (par->mtrr.vram_valid) + mtrr_del(par->mtrr.vram, info->fix.smem_start, + par->vram_size); +#endif /* CONFIG_MTRR */ + iounmap(par->regbase); + iounmap(info->screen_base); + + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + release_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + framebuffer_release(info); +} +#endif /* CONFIG_PCI */ + + + + /* + * Blank the display. + */ +static int aty128fb_blank(int blank, struct fb_info *fb) +{ + struct aty128fb_par *par = fb->par; + u8 state = 0; + + if (par->lock_blank || par->asleep) + return 0; + +#ifdef CONFIG_PMAC_BACKLIGHT + if ((_machine == _MACH_Pmac) && blank) + set_backlight_enable(0); +#endif /* CONFIG_PMAC_BACKLIGHT */ + + if (blank & FB_BLANK_VSYNC_SUSPEND) + state |= 2; + if (blank & FB_BLANK_HSYNC_SUSPEND) + state |= 1; + if (blank & FB_BLANK_POWERDOWN) + state |= 4; + + aty_st_8(CRTC_EXT_CNTL+1, state); + +#ifdef CONFIG_PMAC_PBOOK + if (par->chip_gen == rage_M3) { + aty128_set_crt_enable(par, par->crt_on && !blank); + aty128_set_lcd_enable(par, par->lcd_on && !blank); + } +#endif +#ifdef CONFIG_PMAC_BACKLIGHT + if ((_machine == _MACH_Pmac) && !blank) + set_backlight_enable(1); +#endif /* CONFIG_PMAC_BACKLIGHT */ + return 0; +} + +/* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ +static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct aty128fb_par *par = info->par; + + if (regno > 255 + || (par->crtc.depth == 16 && regno > 63) + || (par->crtc.depth == 15 && regno > 31)) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + if (regno < 16) { + int i; + u32 *pal = info->pseudo_palette; + + switch (par->crtc.depth) { + case 15: + pal[regno] = (regno << 10) | (regno << 5) | regno; + break; + case 16: + pal[regno] = (regno << 11) | (regno << 6) | regno; + break; + case 24: + pal[regno] = (regno << 16) | (regno << 8) | regno; + break; + case 32: + i = (regno << 8) | regno; + pal[regno] = (i << 16) | i; + break; + } + } + + 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. + * Thus the R and B values go in one slot but the G value + * goes in a different slot, and we have to avoid disturbing + * the other fields in the slots we touch. + */ + par->green[regno] = green; + 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; + } else if (par->crtc.bpp == 16) + regno <<= 3; + aty128_st_pal(regno, red, green, blue, par); + + return 0; +} + +#define ATY_MIRROR_LCD_ON 0x00000001 +#define ATY_MIRROR_CRT_ON 0x00000002 + +/* out param: u32* backlight value: 0 to 15 */ +#define FBIO_ATY128_GET_MIRROR _IOR('@', 1, __u32) +/* in param: u32* backlight value: 0 to 15 */ +#define FBIO_ATY128_SET_MIRROR _IOW('@', 2, __u32) + +static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, struct fb_info *info) +{ +#ifdef CONFIG_PMAC_PBOOK + struct aty128fb_par *par = info->par; + u32 value; + int rc; + + switch (cmd) { + case FBIO_ATY128_SET_MIRROR: + if (par->chip_gen != rage_M3) + return -EINVAL; + rc = get_user(value, (__u32 __user *)arg); + if (rc) + return rc; + par->lcd_on = (value & 0x01) != 0; + par->crt_on = (value & 0x02) != 0; + if (!par->crt_on && !par->lcd_on) + par->lcd_on = 1; + aty128_set_crt_enable(par, par->crt_on); + aty128_set_lcd_enable(par, par->lcd_on); + return 0; + case FBIO_ATY128_GET_MIRROR: + if (par->chip_gen != rage_M3) + return -EINVAL; + value = (par->crt_on << 1) | par->lcd_on; + return put_user(value, (__u32 __user *)arg); + } +#endif + return -EINVAL; +} + +#ifdef CONFIG_PMAC_BACKLIGHT +static int backlight_conv[] = { + 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, + 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 +}; + +/* We turn off the LCD completely instead of just dimming the backlight. + * This provides greater power saving and the display is useless without + * backlight anyway + */ +#define BACKLIGHT_LVDS_OFF +/* That one prevents proper CRT output with LCD off */ +#undef BACKLIGHT_DAC_OFF + +static int aty128_set_backlight_enable(int on, int level, void *data) +{ + struct aty128fb_par *par = data; + unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); + + if (!par->lcd_on) + on = 0; + reg |= LVDS_BL_MOD_EN | LVDS_BLON; + if (on && level > BACKLIGHT_OFF) { + reg |= LVDS_DIGION; + if (!(reg & LVDS_ON)) { + reg &= ~LVDS_BLON; + aty_st_le32(LVDS_GEN_CNTL, reg); + (void)aty_ld_le32(LVDS_GEN_CNTL); + mdelay(10); + reg |= LVDS_BLON; + aty_st_le32(LVDS_GEN_CNTL, reg); + } + reg &= ~LVDS_BL_MOD_LEVEL_MASK; + reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT); +#ifdef BACKLIGHT_LVDS_OFF + reg |= LVDS_ON | LVDS_EN; + reg &= ~LVDS_DISPLAY_DIS; +#endif + aty_st_le32(LVDS_GEN_CNTL, reg); +#ifdef BACKLIGHT_DAC_OFF + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN)); +#endif + } else { + reg &= ~LVDS_BL_MOD_LEVEL_MASK; + reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT); +#ifdef BACKLIGHT_LVDS_OFF + reg |= LVDS_DISPLAY_DIS; + aty_st_le32(LVDS_GEN_CNTL, reg); + (void)aty_ld_le32(LVDS_GEN_CNTL); + udelay(10); + reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION); +#endif + aty_st_le32(LVDS_GEN_CNTL, reg); +#ifdef BACKLIGHT_DAC_OFF + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN); +#endif + } + + return 0; +} + +static int aty128_set_backlight_level(int level, void* data) +{ + return aty128_set_backlight_enable(1, level, data); +} +#endif /* CONFIG_PMAC_BACKLIGHT */ + +#if 0 + /* + * Accelerated functions + */ + +static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty, + u_int width, u_int height, + struct fb_info_aty128 *par) +{ + u32 save_dp_datatype, save_dp_cntl, dstval; + + if (!width || !height) + return; + + dstval = depth_to_dst(par->current_par.crtc.depth); + if (dstval == DST_24BPP) { + srcx *= 3; + dstx *= 3; + width *= 3; + } else if (dstval == -EINVAL) { + printk("aty128fb: invalid depth or RGBA\n"); + return; + } + + wait_for_fifo(2, par); + save_dp_datatype = aty_ld_le32(DP_DATATYPE); + save_dp_cntl = aty_ld_le32(DP_CNTL); + + wait_for_fifo(6, par); + aty_st_le32(SRC_Y_X, (srcy << 16) | srcx); + aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT); + aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM); + aty_st_le32(DP_DATATYPE, save_dp_datatype | dstval | SRC_DSTCOLOR); + + aty_st_le32(DST_Y_X, (dsty << 16) | dstx); + aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); + + par->blitter_may_be_busy = 1; + + wait_for_fifo(2, par); + aty_st_le32(DP_DATATYPE, save_dp_datatype); + aty_st_le32(DP_CNTL, save_dp_cntl); +} + + + /* + * Text mode accelerated functions + */ + +static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + sx *= fontwidth(p); + sy *= fontheight(p); + dx *= fontwidth(p); + dy *= fontheight(p); + width *= fontwidth(p); + height *= fontheight(p); + + aty128_rectcopy(sx, sy, dx, dy, width, height, + (struct fb_info_aty128 *)p->fb_info); +} +#endif /* 0 */ + +static void 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; + + /* Set the chip into the appropriate suspend mode (we use D2, + * D3 would require a complete re-initialisation of the chip, + * including PCI config registers, clocks, AGP configuration, ...) + */ + if (suspend) { + /* Make sure CRTC2 is reset. Remove that the day we decide to + * actually use CRTC2 and replace it with real code for disabling + * the CRTC2 output during sleep + */ + aty_st_le32(CRTC2_GEN_CNTL, aty_ld_le32(CRTC2_GEN_CNTL) & + ~(CRTC2_EN)); + + /* Set the power management mode to be PCI based */ + /* Use this magic value for now */ + pmgt = 0x0c005407; + aty_st_pll(POWER_MANAGEMENT, pmgt); + (void)aty_ld_pll(POWER_MANAGEMENT); + aty_st_le32(BUS_CNTL1, 0x00000010); + aty_st_le32(MEM_POWER_MISC, 0x0c830000); + mdelay(100); + pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); + /* Switch PCI power management to D2 */ + pci_write_config_word(pdev, par->pm_reg+PCI_PM_CTRL, + (pwr_command & ~PCI_PM_CTRL_STATE_MASK) | 2); + 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(pdev, par->pm_reg+PCI_PM_CTRL, 0); + pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); + mdelay(100); + } +} + +static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct aty128fb_par *par = info->par; + u8 agp; + + /* We don't do anything but D2, for now we return 0, but + * we may want to change that. How do we know if the BIOS + * can properly take care of D3 ? Also, with swsusp, we + * know we'll be rebooted, ... + */ +#ifdef CONFIG_PPC_PMAC + /* HACK ALERT ! Once I find a proper way to say to each driver + * individually what will happen with it's PCI slot, I'll change + * that. On laptops, the AGP slot is just unclocked, so D2 is + * expected, while on desktops, the card is powered off + */ + if (state >= 3) + state = 2; +#endif /* CONFIG_PPC_PMAC */ + + if (state != 2 || state == pdev->dev.power.power_state) + return 0; + + printk(KERN_DEBUG "aty128fb: suspending...\n"); + + acquire_console_sem(); + + fb_set_suspend(info, 1); + + /* Make sure engine is reset */ + wait_for_idle(par); + aty128_reset_engine(par); + wait_for_idle(par); + + /* Blank display and LCD */ + aty128fb_blank(VESA_POWERDOWN, info); + + /* Sleep */ + par->asleep = 1; + par->lock_blank = 1; + + /* Disable AGP. The AGP host should have done it, but since ordering + * isn't always properly guaranteed in this specific case, let's make + * sure it's disabled on card side now. Ultimately, when merging fbdev + * and dri into some common infrastructure, this will be handled + * more nicely. The host bridge side will (or will not) be dealt with + * by the bridge AGP driver, we don't attempt to touch it here. + */ + agp = pci_find_capability(pdev, PCI_CAP_ID_AGP); + if (agp) { + u32 cmd; + + pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd); + if (cmd & PCI_AGP_COMMAND_AGP) { + printk(KERN_INFO "aty128fb: AGP was enabled, " + "disabling ...\n"); + cmd &= ~PCI_AGP_COMMAND_AGP; + pci_write_config_dword(pdev, agp + PCI_AGP_COMMAND, + cmd); + } + } + + /* We need a way to make sure the fbdev layer will _not_ touch the + * framebuffer before we put the chip to suspend state. On 2.4, I + * used dummy fb ops, 2.5 need proper support for this at the + * fbdev level + */ + if (state == 2) + aty128_set_suspend(par, 1); + + release_console_sem(); + + pdev->dev.power.power_state = state; + + return 0; +} + +static int aty128_do_resume(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct aty128fb_par *par = info->par; + + if (pdev->dev.power.power_state == 0) + return 0; + + /* Wakeup chip */ + if (pdev->dev.power.power_state == 2) + aty128_set_suspend(par, 0); + par->asleep = 0; + + /* Restore display & engine */ + aty128_reset_engine(par); + wait_for_idle(par); + aty128fb_set_par(info); + fb_pan_display(info, &info->var); + fb_set_cmap(&info->cmap, info); + + /* Refresh */ + fb_set_suspend(info, 0); + + /* Unblank */ + par->lock_blank = 0; + aty128fb_blank(0, info); + + pdev->dev.power.power_state = PMSG_ON; + + printk(KERN_DEBUG "aty128fb: resumed !\n"); + + return 0; +} + +static int aty128_pci_resume(struct pci_dev *pdev) +{ + int rc; + + acquire_console_sem(); + rc = aty128_do_resume(pdev); + release_console_sem(); + + return rc; +} + + +static int __init aty128fb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("aty128fb", &option)) + return -ENODEV; + aty128fb_setup(option); +#endif + + return pci_register_driver(&aty128fb_driver); +} + +static void __exit aty128fb_exit(void) +{ + pci_unregister_driver(&aty128fb_driver); +} + +module_init(aty128fb_init); + +module_exit(aty128fb_exit); + +MODULE_AUTHOR("(c)1999-2003 Brad Douglas <brad@neruo.com>"); +MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards"); +MODULE_LICENSE("GPL"); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); +#ifdef CONFIG_MTRR +module_param_named(nomtrr, mtrr, invbool, 0); +MODULE_PARM_DESC(nomtrr, "bool: Disable MTRR support (0 or 1=disabled) (default=0)"); +#endif + diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h new file mode 100644 index 000000000000..09de173c1164 --- /dev/null +++ b/drivers/video/aty/atyfb.h @@ -0,0 +1,359 @@ +/* + * ATI Frame Buffer Device Driver Core Definitions + */ + +#include <linux/config.h> +#include <linux/spinlock.h> +#include <linux/wait.h> + /* + * Elements of the hardware specific atyfb_par structure + */ + +struct crtc { + u32 vxres; + u32 vyres; + u32 xoffset; + u32 yoffset; + u32 bpp; + u32 h_tot_disp; + u32 h_sync_strt_wid; + u32 v_tot_disp; + u32 v_sync_strt_wid; + u32 vline_crnt_vline; + u32 off_pitch; + u32 gen_cntl; + u32 dp_pix_width; /* acceleration */ + u32 dp_chain_mask; /* acceleration */ +#ifdef CONFIG_FB_ATY_GENERIC_LCD + u32 horz_stretching; + u32 vert_stretching; + u32 ext_vert_stretch; + u32 shadow_h_tot_disp; + u32 shadow_h_sync_strt_wid; + u32 shadow_v_tot_disp; + u32 shadow_v_sync_strt_wid; + u32 lcd_gen_cntl; + u32 lcd_config_panel; + u32 lcd_index; +#endif +}; + +struct aty_interrupt { + wait_queue_head_t wait; + unsigned int count; + int pan_display; +}; + +struct pll_info { + int pll_max; + int pll_min; + int sclk, mclk, mclk_pm, xclk; + int ref_div; + int ref_clk; +}; + +typedef struct { + u16 unknown1; + u16 PCLK_min_freq; + u16 PCLK_max_freq; + u16 unknown2; + u16 ref_freq; + u16 ref_divider; + u16 unknown3; + u16 MCLK_pwd; + u16 MCLK_max_freq; + u16 XCLK_max_freq; + u16 SCLK_freq; +} __attribute__ ((packed)) PLL_BLOCK_MACH64; + +struct pll_514 { + u8 m; + u8 n; +}; + +struct pll_18818 { + u32 program_bits; + u32 locationAddr; + u32 period_in_ps; + u32 post_divider; +}; + +struct pll_ct { + u8 pll_ref_div; + u8 pll_gen_cntl; + u8 mclk_fb_div; + u8 mclk_fb_mult; /* 2 ro 4 */ + u8 sclk_fb_div; + u8 pll_vclk_cntl; + u8 vclk_post_div; + u8 vclk_fb_div; + u8 pll_ext_cntl; + u8 ext_vpll_cntl; + u8 spll_cntl2; + u32 dsp_config; /* Mach64 GTB DSP */ + u32 dsp_on_off; /* Mach64 GTB DSP */ + u32 dsp_loop_latency; + u32 fifo_size; + u32 xclkpagefaultdelay; + u32 xclkmaxrasdelay; + u8 xclk_ref_div; + u8 xclk_post_div; + u8 mclk_post_div_real; + u8 xclk_post_div_real; + u8 vclk_post_div_real; + u8 features; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + u32 xres; /* use for LCD stretching/scaling */ +#endif +}; + +/* + for pll_ct.features +*/ +#define DONT_USE_SPLL 0x1 +#define DONT_USE_XDLL 0x2 +#define USE_CPUCLK 0x4 +#define POWERDOWN_PLL 0x8 + +union aty_pll { + struct pll_ct ct; + struct pll_514 ibm514; + struct pll_18818 ics2595; +}; + + /* + * The hardware parameters for each card + */ + +struct atyfb_par { + struct aty_cmap_regs __iomem *aty_cmap_regs; + struct { u8 red, green, blue; } palette[256]; + const struct aty_dac_ops *dac_ops; + const struct aty_pll_ops *pll_ops; + void __iomem *ati_regbase; + unsigned long clk_wr_offset; /* meaning overloaded, clock id by CT */ + struct crtc crtc; + union aty_pll pll; + struct pll_info pll_limits; + u32 features; + u32 ref_clk_per; + u32 pll_per; + u32 mclk_per; + u32 xclk_per; + u8 bus_type; + u8 ram_type; + u8 mem_refresh_rate; + u16 pci_id; + u32 accel_flags; + int blitter_may_be_busy; + int asleep; + int lock_blank; + unsigned long res_start; + unsigned long res_size; +#ifdef __sparc__ + struct pci_mmap_map *mmap_map; + u8 mmaped; +#endif + int open; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + unsigned long bios_base_phys; + unsigned long bios_base; + unsigned long lcd_table; + u16 lcd_width; + u16 lcd_height; + u32 lcd_pixclock; + u16 lcd_refreshrate; + u16 lcd_htotal; + u16 lcd_hdisp; + u16 lcd_hsync_dly; + u16 lcd_hsync_len; + u16 lcd_vtotal; + u16 lcd_vdisp; + u16 lcd_vsync_len; + u16 lcd_right_margin; + u16 lcd_lower_margin; + u16 lcd_hblank_len; + u16 lcd_vblank_len; +#endif + unsigned long aux_start; /* auxiliary aperture */ + unsigned long aux_size; + struct aty_interrupt vblank; + unsigned long irq_flags; + unsigned int irq; + spinlock_t int_lock; +#ifdef CONFIG_MTRR + int mtrr_aper; + int mtrr_reg; +#endif +}; + + /* + * ATI Mach64 features + */ + +#define M64_HAS(feature) ((par)->features & (M64F_##feature)) + +#define M64F_RESET_3D 0x00000001 +#define M64F_MAGIC_FIFO 0x00000002 +#define M64F_GTB_DSP 0x00000004 +#define M64F_FIFO_32 0x00000008 +#define M64F_SDRAM_MAGIC_PLL 0x00000010 +#define M64F_MAGIC_POSTDIV 0x00000020 +#define M64F_INTEGRATED 0x00000040 +#define M64F_CT_BUS 0x00000080 +#define M64F_VT_BUS 0x00000100 +#define M64F_MOBIL_BUS 0x00000200 +#define M64F_GX 0x00000400 +#define M64F_CT 0x00000800 +#define M64F_VT 0x00001000 +#define M64F_GT 0x00002000 +#define M64F_MAGIC_VRAM_SIZE 0x00004000 +#define M64F_G3_PB_1_1 0x00008000 +#define M64F_G3_PB_1024x768 0x00010000 +#define M64F_EXTRA_BRIGHT 0x00020000 +#define M64F_LT_LCD_REGS 0x00040000 +#define M64F_XL_DLL 0x00080000 +#define M64F_MFB_FORCE_4 0x00100000 +#define M64F_HW_TRIPLE 0x00200000 + /* + * Register access + */ + +static inline u32 aty_ld_le32(int regindex, const struct atyfb_par *par) +{ + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; + +#ifdef CONFIG_ATARI + return in_le32((volatile u32 *)(par->ati_regbase + regindex)); +#else + return readl(par->ati_regbase + regindex); +#endif +} + +static inline void aty_st_le32(int regindex, u32 val, const struct atyfb_par *par) +{ + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; + +#ifdef CONFIG_ATARI + out_le32((volatile u32 *)(par->ati_regbase + regindex), val); +#else + writel(val, par->ati_regbase + regindex); +#endif +} + +static inline void aty_st_le16(int regindex, u16 val, + const struct atyfb_par *par) +{ + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; +#ifdef CONFIG_ATARI + out_le16((volatile u16 *)(par->ati_regbase + regindex), val); +#else + writel(val, par->ati_regbase + regindex); +#endif +} + +static inline u8 aty_ld_8(int regindex, const struct atyfb_par *par) +{ + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; +#ifdef CONFIG_ATARI + return in_8(par->ati_regbase + regindex); +#else + return readb(par->ati_regbase + regindex); +#endif +} + +static inline void aty_st_8(int regindex, u8 val, const struct atyfb_par *par) +{ + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; + +#ifdef CONFIG_ATARI + out_8(par->ati_regbase + regindex, val); +#else + writeb(val, par->ati_regbase + regindex); +#endif +} + +#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) +extern void aty_st_lcd(int index, u32 val, const struct atyfb_par *par); +extern u32 aty_ld_lcd(int index, const struct atyfb_par *par); +#endif + + /* + * DAC operations + */ + +struct aty_dac_ops { + int (*set_dac) (const struct fb_info * info, + const union aty_pll * pll, u32 bpp, u32 accel); +}; + +extern const struct aty_dac_ops aty_dac_ibm514; /* IBM RGB514 */ +extern const struct aty_dac_ops aty_dac_ati68860b; /* ATI 68860-B */ +extern const struct aty_dac_ops aty_dac_att21c498; /* AT&T 21C498 */ +extern const struct aty_dac_ops aty_dac_unsupported; /* unsupported */ +extern const struct aty_dac_ops aty_dac_ct; /* Integrated */ + + + /* + * Clock operations + */ + +struct aty_pll_ops { + int (*var_to_pll) (const struct fb_info * info, u32 vclk_per, u32 bpp, union aty_pll * pll); + u32 (*pll_to_var) (const struct fb_info * info, const union aty_pll * pll); + void (*set_pll) (const struct fb_info * info, const union aty_pll * pll); + void (*get_pll) (const struct fb_info *info, union aty_pll * pll); + int (*init_pll) (const struct fb_info * info, union aty_pll * pll); +}; + +extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */ +extern const struct aty_pll_ops aty_pll_stg1703; /* STG 1703 */ +extern const struct aty_pll_ops aty_pll_ch8398; /* Chrontel 8398 */ +extern const struct aty_pll_ops aty_pll_att20c408; /* AT&T 20C408 */ +extern const struct aty_pll_ops aty_pll_ibm514; /* IBM RGB514 */ +extern const struct aty_pll_ops aty_pll_unsupported; /* unsupported */ +extern const struct aty_pll_ops aty_pll_ct; /* Integrated */ + + +extern void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll); +extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par); + + + /* + * Hardware cursor support + */ + +extern int aty_init_cursor(struct fb_info *info); + + /* + * Hardware acceleration + */ + +static inline void wait_for_fifo(u16 entries, const struct atyfb_par *par) +{ + while ((aty_ld_le32(FIFO_STAT, par) & 0xffff) > + ((u32) (0x8000 >> entries))); +} + +static inline void wait_for_idle(struct atyfb_par *par) +{ + wait_for_fifo(16, par); + while ((aty_ld_le32(GUI_STAT, par) & 1) != 0); + par->blitter_may_be_busy = 0; +} + +extern void aty_reset_engine(const struct atyfb_par *par); +extern void aty_init_engine(struct atyfb_par *par, struct fb_info *info); +extern int atyfb_xl_init(struct fb_info *info); +extern void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par); +extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par); diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c new file mode 100644 index 000000000000..8c42538dc8c1 --- /dev/null +++ b/drivers/video/aty/atyfb_base.c @@ -0,0 +1,3720 @@ +/* + * ATI Frame Buffer Device Driver Core + * + * Copyright (C) 2004 Alex Kern <alex.kern@gmx.de> + * Copyright (C) 1997-2001 Geert Uytterhoeven + * Copyright (C) 1998 Bernd Harries + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * + * This driver supports the following ATI graphics chips: + * - ATI Mach64 + * + * To do: add support for + * - ATI Rage128 (from aty128fb.c) + * - ATI Radeon (from radeonfb.c) + * + * This driver is partly based on the PowerMac console driver: + * + * Copyright (C) 1996 Paul Mackerras + * + * and on the PowerMac ATI/mach64 display driver: + * + * Copyright (C) 1997 Michael AK Tesch + * + * with work by Jon Howell + * Harry AC Eaton + * Anthony Tong <atong@uiuc.edu> + * + * Generic LCD support written by Daniel Mantione, ported from 2.4.20 by Alex Kern + * Many Thanks to Ville Syrjl for patches and fixing nasting 16 bit color bug. + * + * 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. + * + * Many thanks to Nitya from ATI devrel for support and patience ! + */ + +/****************************************************************************** + + TODO: + + - cursor support on all cards and all ramdacs. + - cursor parameters controlable via ioctl()s. + - guess PLL and MCLK based on the original PLL register values initialized + by Open Firmware (if they are initialized). BIOS is done + + (Anyone with Mac to help with this?) + +******************************************************************************/ + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/console.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/wait.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#include <video/mach64.h> +#include "atyfb.h" +#include "ati_ids.h" + +#ifdef __powerpc__ +#include <asm/prom.h> +#include "../macmodes.h" +#endif +#ifdef __sparc__ +#include <asm/pbm.h> +#include <asm/fbio.h> +#endif + +#ifdef CONFIG_ADB_PMU +#include <linux/adb.h> +#include <linux/pmu.h> +#endif +#ifdef CONFIG_BOOTX_TEXT +#include <asm/btext.h> +#endif +#ifdef CONFIG_PMAC_BACKLIGHT +#include <asm/backlight.h> +#endif +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +/* + * Debug flags. + */ +#undef DEBUG +/*#define DEBUG*/ + +/* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */ +/* - must be large enough to catch all GUI-Regs */ +/* - must be aligned to a PAGE boundary */ +#define GUI_RESERVE (1 * PAGE_SIZE) + +/* FIXME: remove the FAIL definition */ +#define FAIL(msg) do { printk(KERN_CRIT "atyfb: " msg "\n"); return -EINVAL; } while (0) +#define FAIL_MAX(msg, x, _max_) do { if(x > _max_) { printk(KERN_CRIT "atyfb: " msg " %x(%x)\n", x, _max_); return -EINVAL; } } while (0) + +#ifdef DEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "atyfb: " fmt, ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#define PRINTKI(fmt, args...) printk(KERN_INFO "atyfb: " fmt, ## args) +#define PRINTKE(fmt, args...) printk(KERN_ERR "atyfb: " fmt, ## args) + +#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) +static const u32 lt_lcd_regs[] = { + CONFIG_PANEL_LG, + LCD_GEN_CNTL_LG, + DSTN_CONTROL_LG, + HFB_PITCH_ADDR_LG, + HORZ_STRETCHING_LG, + VERT_STRETCHING_LG, + 0, /* EXT_VERT_STRETCH */ + LT_GIO_LG, + POWER_MANAGEMENT_LG +}; + +void aty_st_lcd(int index, u32 val, const struct atyfb_par *par) +{ + if (M64_HAS(LT_LCD_REGS)) { + aty_st_le32(lt_lcd_regs[index], val, par); + } else { + unsigned long temp; + + /* write addr byte */ + temp = aty_ld_le32(LCD_INDEX, par); + aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par); + /* write the register value */ + aty_st_le32(LCD_DATA, val, par); + } +} + +u32 aty_ld_lcd(int index, const struct atyfb_par *par) +{ + if (M64_HAS(LT_LCD_REGS)) { + return aty_ld_le32(lt_lcd_regs[index], par); + } else { + unsigned long temp; + + /* write addr byte */ + temp = aty_ld_le32(LCD_INDEX, par); + aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par); + /* read the register value */ + return aty_ld_le32(LCD_DATA, par); + } +} +#endif /* defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) */ + +#ifdef CONFIG_FB_ATY_GENERIC_LCD +/* + * ATIReduceRatio -- + * + * Reduce a fraction by factoring out the largest common divider of the + * fraction's numerator and denominator. + */ +static void ATIReduceRatio(int *Numerator, int *Denominator) +{ + int Multiplier, Divider, Remainder; + + Multiplier = *Numerator; + Divider = *Denominator; + + while ((Remainder = Multiplier % Divider)) + { + Multiplier = Divider; + Divider = Remainder; + } + + *Numerator /= Divider; + *Denominator /= Divider; +} +#endif + /* + * The Hardware parameters for each card + */ + +struct aty_cmap_regs { + u8 windex; + u8 lut; + u8 mask; + u8 rindex; + u8 cntl; +}; + +struct pci_mmap_map { + unsigned long voff; + unsigned long poff; + unsigned long size; + unsigned long prot_flag; + unsigned long prot_mask; +}; + +static struct fb_fix_screeninfo atyfb_fix __devinitdata = { + .id = "ATY Mach64", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .xpanstep = 8, + .ypanstep = 1, +}; + + /* + * Frame buffer device API + */ + +static int atyfb_open(struct fb_info *info, int user); +static int atyfb_release(struct fb_info *info, int user); +static int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); +static int atyfb_set_par(struct fb_info *info); +static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int atyfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); +static int atyfb_blank(int blank, struct fb_info *info); +static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, struct fb_info *info); +extern void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +extern void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); +extern void atyfb_imageblit(struct fb_info *info, const struct fb_image *image); +#ifdef __sparc__ +static int atyfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma); +#endif +static int atyfb_sync(struct fb_info *info); + + /* + * Internal routines + */ + +static int aty_init(struct fb_info *info, const char *name); +#ifdef CONFIG_ATARI +static int store_video_par(char *videopar, unsigned char m64_num); +#endif + +static struct crtc saved_crtc; +static union aty_pll saved_pll; +static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc); + +static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc); +static int aty_var_to_crtc(const struct fb_info *info, const struct fb_var_screeninfo *var, struct crtc *crtc); +static int aty_crtc_to_var(const struct crtc *crtc, struct fb_var_screeninfo *var); +static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info); +#ifdef CONFIG_PPC +static int read_aty_sense(const struct atyfb_par *par); +#endif + + + /* + * Interface used by the world + */ + +static 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 +}; + +static struct fb_videomode defmode = { + /* 640x480 @ 60 Hz, 31.5 kHz hsync */ + NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, + 0, FB_VMODE_NONINTERLACED +}; + +static struct fb_ops atyfb_ops = { + .owner = THIS_MODULE, + .fb_open = atyfb_open, + .fb_release = atyfb_release, + .fb_check_var = atyfb_check_var, + .fb_set_par = atyfb_set_par, + .fb_setcolreg = atyfb_setcolreg, + .fb_pan_display = atyfb_pan_display, + .fb_blank = atyfb_blank, + .fb_ioctl = atyfb_ioctl, + .fb_fillrect = atyfb_fillrect, + .fb_copyarea = atyfb_copyarea, + .fb_imageblit = atyfb_imageblit, + .fb_cursor = soft_cursor, +#ifdef __sparc__ + .fb_mmap = atyfb_mmap, +#endif + .fb_sync = atyfb_sync, +}; + +static int noaccel; +#ifdef CONFIG_MTRR +static int nomtrr; +#endif +static int vram; +static int pll; +static int mclk; +static int xclk; +static int comp_sync __initdata = -1; +static char *mode; + +#ifdef CONFIG_PPC +static int default_vmode __initdata = VMODE_CHOOSE; +static int default_cmode __initdata = CMODE_CHOOSE; + +module_param_named(vmode, default_vmode, int, 0); +MODULE_PARM_DESC(vmode, "int: video mode for mac"); +module_param_named(cmode, default_cmode, int, 0); +MODULE_PARM_DESC(cmode, "int: color mode for mac"); +#endif + +#ifdef CONFIG_ATARI +static unsigned int mach64_count __initdata = 0; +static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, }; +static unsigned long phys_size[FB_MAX] __initdata = { 0, }; +static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, }; +#endif + +/* top -> down is an evolution of mach64 chipset, any corrections? */ +#define ATI_CHIP_88800GX (M64F_GX) +#define ATI_CHIP_88800CX (M64F_GX) + +#define ATI_CHIP_264CT (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO) +#define ATI_CHIP_264ET (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO) + +#define ATI_CHIP_264VT (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO) +#define ATI_CHIP_264GT (M64F_GT | M64F_INTEGRATED | M64F_MAGIC_FIFO | M64F_EXTRA_BRIGHT) + +#define ATI_CHIP_264VTB (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP) +#define ATI_CHIP_264VT3 (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL) +#define ATI_CHIP_264VT4 (M64F_VT | M64F_INTEGRATED | M64F_GTB_DSP) + +#define ATI_CHIP_264LT (M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP) + +/* make sets shorter */ +#define ATI_MODERN_SET (M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_EXTRA_BRIGHT) + +#define ATI_CHIP_264GTB (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL) +/*#define ATI_CHIP_264GTDVD ?*/ +#define ATI_CHIP_264LTG (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL) + +#define ATI_CHIP_264GT2C (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE) +#define ATI_CHIP_264GTPRO (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D) +#define ATI_CHIP_264LTPRO (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D) + +#define ATI_CHIP_264XL (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4) +#define ATI_CHIP_MOBILITY (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_MOBIL_BUS) + +static struct { + u16 pci_id; + const char *name; + int pll, mclk, xclk; + u32 features; +} aty_chips[] __devinitdata = { +#ifdef CONFIG_FB_ATY_GX + /* Mach64 GX */ + { PCI_CHIP_MACH64GX, "ATI888GX00 (Mach64 GX)", 135, 50, 50, ATI_CHIP_88800GX }, + { PCI_CHIP_MACH64CX, "ATI888CX00 (Mach64 CX)", 135, 50, 50, ATI_CHIP_88800CX }, +#endif /* CONFIG_FB_ATY_GX */ + +#ifdef CONFIG_FB_ATY_CT + { PCI_CHIP_MACH64CT, "ATI264CT (Mach64 CT)", 135, 60, 60, ATI_CHIP_264CT }, + { PCI_CHIP_MACH64ET, "ATI264ET (Mach64 ET)", 135, 60, 60, ATI_CHIP_264ET }, + { PCI_CHIP_MACH64VT, "ATI264VT? (Mach64 VT)", 170, 67, 67, ATI_CHIP_264VT }, + { PCI_CHIP_MACH64GT, "3D RAGE (Mach64 GT)", 135, 63, 63, ATI_CHIP_264GT }, + /* FIXME { ...ATI_264GU, maybe ATI_CHIP_264GTDVD }, */ + { PCI_CHIP_MACH64GU, "3D RAGE II+ (Mach64 GTB)", 200, 67, 67, ATI_CHIP_264GTB }, + { PCI_CHIP_MACH64VU, "ATI264VTB (Mach64 VU)", 200, 67, 67, ATI_CHIP_264VT3 }, + + { PCI_CHIP_MACH64LT, "3D RAGE LT (Mach64 LT)", 135, 63, 63, ATI_CHIP_264LT }, + /* FIXME chipset maybe ATI_CHIP_264LTPRO ? */ + { PCI_CHIP_MACH64LG, "3D RAGE LT-G (Mach64 LG)", 230, 63, 63, ATI_CHIP_264LTG | M64F_LT_LCD_REGS | M64F_G3_PB_1024x768 }, + + { PCI_CHIP_MACH64VV, "ATI264VT4 (Mach64 VV)", 230, 83, 83, ATI_CHIP_264VT4 }, + + { PCI_CHIP_MACH64GV, "3D RAGE IIC (Mach64 GV, PCI)", 230, 83, 83, ATI_CHIP_264GT2C }, + { PCI_CHIP_MACH64GW, "3D RAGE IIC (Mach64 GW, AGP)", 230, 83, 83, ATI_CHIP_264GT2C }, + { PCI_CHIP_MACH64GY, "3D RAGE IIC (Mach64 GY, PCI)", 230, 83, 83, ATI_CHIP_264GT2C }, + { PCI_CHIP_MACH64GZ, "3D RAGE IIC (Mach64 GZ, AGP)", 230, 83, 83, ATI_CHIP_264GT2C }, + + { PCI_CHIP_MACH64GB, "3D RAGE PRO (Mach64 GB, BGA, AGP)", 230, 100, 100, ATI_CHIP_264GTPRO }, + { PCI_CHIP_MACH64GD, "3D RAGE PRO (Mach64 GD, BGA, AGP 1x)", 230, 100, 100, ATI_CHIP_264GTPRO }, + { PCI_CHIP_MACH64GI, "3D RAGE PRO (Mach64 GI, BGA, PCI)", 230, 100, 100, ATI_CHIP_264GTPRO | M64F_MAGIC_VRAM_SIZE }, + { PCI_CHIP_MACH64GP, "3D RAGE PRO (Mach64 GP, PQFP, PCI)", 230, 100, 100, ATI_CHIP_264GTPRO }, + { PCI_CHIP_MACH64GQ, "3D RAGE PRO (Mach64 GQ, PQFP, PCI, limited 3D)", 230, 100, 100, ATI_CHIP_264GTPRO }, + + { PCI_CHIP_MACH64LB, "3D RAGE LT PRO (Mach64 LB, AGP)", 236, 75, 100, ATI_CHIP_264LTPRO }, + { PCI_CHIP_MACH64LD, "3D RAGE LT PRO (Mach64 LD, AGP)", 230, 100, 100, ATI_CHIP_264LTPRO }, + { PCI_CHIP_MACH64LI, "3D RAGE LT PRO (Mach64 LI, PCI)", 230, 100, 100, ATI_CHIP_264LTPRO | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 }, + { PCI_CHIP_MACH64LP, "3D RAGE LT PRO (Mach64 LP, PCI)", 230, 100, 100, ATI_CHIP_264LTPRO }, + { PCI_CHIP_MACH64LQ, "3D RAGE LT PRO (Mach64 LQ, PCI)", 230, 100, 100, ATI_CHIP_264LTPRO }, + + { PCI_CHIP_MACH64GM, "3D RAGE XL (Mach64 GM, AGP)", 230, 83, 63, ATI_CHIP_264XL }, + { PCI_CHIP_MACH64GN, "3D RAGE XL (Mach64 GN, AGP)", 230, 83, 63, ATI_CHIP_264XL }, + { PCI_CHIP_MACH64GO, "3D RAGE XL (Mach64 GO, PCI-66/BGA)", 230, 83, 63, ATI_CHIP_264XL }, + { PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33MHz)", 230, 83, 63, ATI_CHIP_264XL }, + { PCI_CHIP_MACH64GL, "3D RAGE XL (Mach64 GL, PCI)", 230, 83, 63, ATI_CHIP_264XL }, + { PCI_CHIP_MACH64GS, "3D RAGE XL (Mach64 GS, PCI)", 230, 83, 63, ATI_CHIP_264XL }, + + { PCI_CHIP_MACH64LM, "3D RAGE Mobility P/M (Mach64 LM, AGP 2x)", 230, 83, 125, ATI_CHIP_MOBILITY }, + { PCI_CHIP_MACH64LN, "3D RAGE Mobility L (Mach64 LN, AGP 2x)", 230, 83, 125, ATI_CHIP_MOBILITY }, + { PCI_CHIP_MACH64LR, "3D RAGE Mobility P/M (Mach64 LR, PCI)", 230, 83, 125, ATI_CHIP_MOBILITY }, + { PCI_CHIP_MACH64LS, "3D RAGE Mobility L (Mach64 LS, PCI)", 230, 83, 125, ATI_CHIP_MOBILITY }, +#endif /* CONFIG_FB_ATY_CT */ +}; + +/* can not fail */ +static int __devinit correct_chipset(struct atyfb_par *par) +{ + u8 rev; + u16 type; + u32 chip_id; + const char *name; + int i; + + for (i = sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >= 0; i--) + if (par->pci_id == aty_chips[i].pci_id) + break; + + name = aty_chips[i].name; + par->pll_limits.pll_max = aty_chips[i].pll; + par->pll_limits.mclk = aty_chips[i].mclk; + par->pll_limits.xclk = aty_chips[i].xclk; + par->features = aty_chips[i].features; + + chip_id = aty_ld_le32(CONFIG_CHIP_ID, par); + type = chip_id & CFG_CHIP_TYPE; + rev = (chip_id & CFG_CHIP_REV) >> 24; + + switch(par->pci_id) { +#ifdef CONFIG_FB_ATY_GX + case PCI_CHIP_MACH64GX: + if(type != 0x00d7) + return -ENODEV; + break; + case PCI_CHIP_MACH64CX: + if(type != 0x0057) + return -ENODEV; + break; +#endif +#ifdef CONFIG_FB_ATY_CT + case PCI_CHIP_MACH64VT: + rev &= 0xc7; + if(rev == 0x00) { + name = "ATI264VTA3 (Mach64 VT)"; + par->pll_limits.pll_max = 170; + par->pll_limits.mclk = 67; + par->pll_limits.xclk = 67; + par->features = ATI_CHIP_264VT; + } else if(rev == 0x40) { + name = "ATI264VTA4 (Mach64 VT)"; + par->pll_limits.pll_max = 200; + par->pll_limits.mclk = 67; + par->pll_limits.xclk = 67; + par->features = ATI_CHIP_264VT | M64F_MAGIC_POSTDIV; + } else { + name = "ATI264VTB (Mach64 VT)"; + par->pll_limits.pll_max = 200; + par->pll_limits.mclk = 67; + par->pll_limits.xclk = 67; + par->features = ATI_CHIP_264VTB; + } + break; + case PCI_CHIP_MACH64GT: + rev &= 0x07; + if(rev == 0x01) { + par->pll_limits.pll_max = 170; + par->pll_limits.mclk = 67; + par->pll_limits.xclk = 67; + par->features = ATI_CHIP_264GTB; + } else if(rev == 0x02) { + par->pll_limits.pll_max = 200; + par->pll_limits.mclk = 67; + par->pll_limits.xclk = 67; + par->features = ATI_CHIP_264GTB; + } + break; +#endif + } + + PRINTKI("%s [0x%04x rev 0x%02x]\n", name, type, rev); + return 0; +} + +static char ram_dram[] __devinitdata = "DRAM"; +static char ram_resv[] __devinitdata = "RESV"; +#ifdef CONFIG_FB_ATY_GX +static char ram_vram[] __devinitdata = "VRAM"; +#endif /* CONFIG_FB_ATY_GX */ +#ifdef CONFIG_FB_ATY_CT +static char ram_edo[] __devinitdata = "EDO"; +static char ram_sdram[] __devinitdata = "SDRAM (1:1)"; +static char ram_sgram[] __devinitdata = "SGRAM (1:1)"; +static char ram_sdram32[] __devinitdata = "SDRAM (2:1) (32-bit)"; +static char ram_off[] __devinitdata = "OFF"; +#endif /* CONFIG_FB_ATY_CT */ + + +static u32 pseudo_palette[17]; + +#ifdef CONFIG_FB_ATY_GX +static char *aty_gx_ram[8] __devinitdata = { + ram_dram, ram_vram, ram_vram, ram_dram, + ram_dram, ram_vram, ram_vram, ram_resv +}; +#endif /* CONFIG_FB_ATY_GX */ + +#ifdef CONFIG_FB_ATY_CT +static char *aty_ct_ram[8] __devinitdata = { + ram_off, ram_dram, ram_edo, ram_edo, + ram_sdram, ram_sgram, ram_sdram32, ram_resv +}; +#endif /* CONFIG_FB_ATY_CT */ + +static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var, struct atyfb_par *par) +{ + u32 pixclock = var->pixclock; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + u32 lcd_on_off; + par->pll.ct.xres = 0; + if (par->lcd_table != 0) { + lcd_on_off = aty_ld_lcd(LCD_GEN_CNTL, par); + if(lcd_on_off & LCD_ON) { + par->pll.ct.xres = var->xres; + pixclock = par->lcd_pixclock; + } + } +#endif + return pixclock; +} + +#if defined(CONFIG_PPC) + +/* + * Apple monitor sense + */ + +static int __init read_aty_sense(const struct atyfb_par *par) +{ + int sense, i; + + aty_st_le32(GP_IO, 0x31003100, par); /* drive outputs high */ + __delay(200); + aty_st_le32(GP_IO, 0, par); /* turn off outputs */ + __delay(2000); + i = aty_ld_le32(GP_IO, par); /* get primary sense value */ + sense = ((i & 0x3000) >> 3) | (i & 0x100); + + /* drive each sense line low in turn and collect the other 2 */ + aty_st_le32(GP_IO, 0x20000000, par); /* drive A low */ + __delay(2000); + i = aty_ld_le32(GP_IO, par); + sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4); + aty_st_le32(GP_IO, 0x20002000, par); /* drive A high again */ + __delay(200); + + aty_st_le32(GP_IO, 0x10000000, par); /* drive B low */ + __delay(2000); + i = aty_ld_le32(GP_IO, par); + sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6); + aty_st_le32(GP_IO, 0x10001000, par); /* drive B high again */ + __delay(200); + + aty_st_le32(GP_IO, 0x01000000, par); /* drive C low */ + __delay(2000); + sense |= (aty_ld_le32(GP_IO, par) & 0x3000) >> 12; + aty_st_le32(GP_IO, 0, par); /* turn off outputs */ + return sense; +} + +#endif /* defined(CONFIG_PPC) */ + +/* ------------------------------------------------------------------------- */ + +/* + * CRTC programming + */ + +static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc) +{ +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table != 0) { + if(!M64_HAS(LT_LCD_REGS)) { + crtc->lcd_index = aty_ld_le32(LCD_INDEX, par); + aty_st_le32(LCD_INDEX, crtc->lcd_index, par); + } + crtc->lcd_config_panel = aty_ld_lcd(CONFIG_PANEL, par); + crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par); + + + /* switch to non shadow registers */ + aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl & + ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par); + + /* save stretching */ + crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par); + crtc->vert_stretching = aty_ld_lcd(VERT_STRETCHING, par); + if (!M64_HAS(LT_LCD_REGS)) + crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par); + } +#endif + crtc->h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par); + crtc->h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par); + crtc->v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par); + crtc->v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par); + crtc->vline_crnt_vline = aty_ld_le32(CRTC_VLINE_CRNT_VLINE, par); + crtc->off_pitch = aty_ld_le32(CRTC_OFF_PITCH, par); + crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par); + +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table != 0) { + /* switch to shadow registers */ + aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) | + SHADOW_EN | SHADOW_RW_EN, par); + + crtc->shadow_h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par); + crtc->shadow_h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par); + crtc->shadow_v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par); + crtc->shadow_v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par); + + aty_st_le32(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par); + } +#endif /* CONFIG_FB_ATY_GENERIC_LCD */ +} + +static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc) +{ +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table != 0) { + /* stop CRTC */ + aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~(CRTC_EXT_DISP_EN | CRTC_EN), par); + + /* update non-shadow registers first */ + aty_st_lcd(CONFIG_PANEL, crtc->lcd_config_panel, par); + aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl & + ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par); + + /* temporarily disable stretching */ + aty_st_lcd(HORZ_STRETCHING, + crtc->horz_stretching & + ~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN), par); + aty_st_lcd(VERT_STRETCHING, + crtc->vert_stretching & + ~(VERT_STRETCH_RATIO1 | VERT_STRETCH_RATIO2 | + VERT_STRETCH_USE0 | VERT_STRETCH_EN), par); + } +#endif + /* turn off CRT */ + aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~CRTC_EN, par); + + DPRINTK("setting up CRTC\n"); + DPRINTK("set primary CRT to %ix%i %c%c composite %c\n", + ((((crtc->h_tot_disp>>16) & 0xff) + 1)<<3), (((crtc->v_tot_disp>>16) & 0x7ff) + 1), + (crtc->h_sync_strt_wid & 0x200000)?'N':'P', (crtc->v_sync_strt_wid & 0x200000)?'N':'P', + (crtc->gen_cntl & CRTC_CSYNC_EN)?'P':'N'); + + DPRINTK("CRTC_H_TOTAL_DISP: %x\n",crtc->h_tot_disp); + DPRINTK("CRTC_H_SYNC_STRT_WID: %x\n",crtc->h_sync_strt_wid); + DPRINTK("CRTC_V_TOTAL_DISP: %x\n",crtc->v_tot_disp); + DPRINTK("CRTC_V_SYNC_STRT_WID: %x\n",crtc->v_sync_strt_wid); + DPRINTK("CRTC_OFF_PITCH: %x\n", crtc->off_pitch); + DPRINTK("CRTC_VLINE_CRNT_VLINE: %x\n", crtc->vline_crnt_vline); + DPRINTK("CRTC_GEN_CNTL: %x\n",crtc->gen_cntl); + + aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, par); + aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, par); + aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, par); + aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, par); + aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, par); + aty_st_le32(CRTC_VLINE_CRNT_VLINE, crtc->vline_crnt_vline, par); + + aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, par); +#if 0 + FIXME + if (par->accel_flags & FB_ACCELF_TEXT) + aty_init_engine(par, info); +#endif +#ifdef CONFIG_FB_ATY_GENERIC_LCD + /* after setting the CRTC registers we should set the LCD registers. */ + if (par->lcd_table != 0) { + /* switch to shadow registers */ + aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) | + (SHADOW_EN | SHADOW_RW_EN), par); + + DPRINTK("set secondary CRT to %ix%i %c%c\n", + ((((crtc->shadow_h_tot_disp>>16) & 0xff) + 1)<<3), (((crtc->shadow_v_tot_disp>>16) & 0x7ff) + 1), + (crtc->shadow_h_sync_strt_wid & 0x200000)?'N':'P', (crtc->shadow_v_sync_strt_wid & 0x200000)?'N':'P'); + + DPRINTK("SHADOW CRTC_H_TOTAL_DISP: %x\n", crtc->shadow_h_tot_disp); + DPRINTK("SHADOW CRTC_H_SYNC_STRT_WID: %x\n", crtc->shadow_h_sync_strt_wid); + DPRINTK("SHADOW CRTC_V_TOTAL_DISP: %x\n", crtc->shadow_v_tot_disp); + DPRINTK("SHADOW CRTC_V_SYNC_STRT_WID: %x\n", crtc->shadow_v_sync_strt_wid); + + aty_st_le32(CRTC_H_TOTAL_DISP, crtc->shadow_h_tot_disp, par); + aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->shadow_h_sync_strt_wid, par); + aty_st_le32(CRTC_V_TOTAL_DISP, crtc->shadow_v_tot_disp, par); + aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->shadow_v_sync_strt_wid, par); + + /* restore CRTC selection & shadow state and enable stretching */ + DPRINTK("LCD_GEN_CNTL: %x\n", crtc->lcd_gen_cntl); + DPRINTK("HORZ_STRETCHING: %x\n", crtc->horz_stretching); + DPRINTK("VERT_STRETCHING: %x\n", crtc->vert_stretching); + if(!M64_HAS(LT_LCD_REGS)) + DPRINTK("EXT_VERT_STRETCH: %x\n", crtc->ext_vert_stretch); + + aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par); + aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching, par); + aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching, par); + if(!M64_HAS(LT_LCD_REGS)) { + aty_st_lcd(EXT_VERT_STRETCH, crtc->ext_vert_stretch, par); + aty_ld_le32(LCD_INDEX, par); + aty_st_le32(LCD_INDEX, crtc->lcd_index, par); + } + } +#endif /* CONFIG_FB_ATY_GENERIC_LCD */ +} + +static int aty_var_to_crtc(const struct fb_info *info, + const struct fb_var_screeninfo *var, struct crtc *crtc) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; + u32 sync, vmode, vdisplay; + u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync; + u32 pix_width, dp_pix_width, dp_chain_mask; + + /* input */ + xres = var->xres; + yres = var->yres; + vxres = var->xres_virtual; + vyres = var->yres_virtual; + xoffset = var->xoffset; + yoffset = var->yoffset; + bpp = var->bits_per_pixel; + if (bpp == 16) + bpp = (var->green.length == 5) ? 15 : 16; + sync = var->sync; + vmode = var->vmode; + + /* convert (and round up) and validate */ + if (vxres < xres + xoffset) + vxres = xres + xoffset; + h_disp = xres; + + if (vyres < yres + yoffset) + vyres = yres + yoffset; + v_disp = yres; + + if (bpp <= 8) { + bpp = 8; + pix_width = CRTC_PIX_WIDTH_8BPP; + dp_pix_width = + HOST_8BPP | SRC_8BPP | DST_8BPP | + BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = DP_CHAIN_8BPP; + } else if (bpp <= 15) { + bpp = 16; + pix_width = CRTC_PIX_WIDTH_15BPP; + dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP | + BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = DP_CHAIN_15BPP; + } else if (bpp <= 16) { + bpp = 16; + pix_width = CRTC_PIX_WIDTH_16BPP; + dp_pix_width = HOST_16BPP | SRC_16BPP | DST_16BPP | + BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = DP_CHAIN_16BPP; + } else if (bpp <= 24 && M64_HAS(INTEGRATED)) { + bpp = 24; + pix_width = CRTC_PIX_WIDTH_24BPP; + dp_pix_width = + HOST_8BPP | SRC_8BPP | DST_8BPP | + BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = DP_CHAIN_24BPP; + } else if (bpp <= 32) { + bpp = 32; + pix_width = CRTC_PIX_WIDTH_32BPP; + dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP | + BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = DP_CHAIN_32BPP; + } else + FAIL("invalid bpp"); + + if (vxres * vyres * bpp / 8 > info->fix.smem_len) + FAIL("not enough video RAM"); + + h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + + if((xres > 1600) || (yres > 1200)) { + FAIL("MACH64 chips are designed for max 1600x1200\n" + "select anoter resolution."); + } + h_sync_strt = h_disp + var->right_margin; + h_sync_end = h_sync_strt + var->hsync_len; + h_sync_dly = var->right_margin & 7; + h_total = h_sync_end + h_sync_dly + var->left_margin; + + v_sync_strt = v_disp + var->lower_margin; + v_sync_end = v_sync_strt + var->vsync_len; + v_total = v_sync_end + var->upper_margin; + +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table != 0) { + if(!M64_HAS(LT_LCD_REGS)) { + u32 lcd_index = aty_ld_le32(LCD_INDEX, par); + crtc->lcd_index = lcd_index & + ~(LCD_INDEX_MASK | LCD_DISPLAY_DIS | LCD_SRC_SEL | CRTC2_DISPLAY_DIS); + aty_st_le32(LCD_INDEX, lcd_index, par); + } + + if (!M64_HAS(MOBIL_BUS)) + crtc->lcd_index |= CRTC2_DISPLAY_DIS; + + crtc->lcd_config_panel = aty_ld_lcd(CONFIG_PANEL, par) | 0x4000; + crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par) & ~CRTC_RW_SELECT; + + crtc->lcd_gen_cntl &= + ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | TVCLK_PM_EN | + /*VCLK_DAC_PM_EN | USE_SHADOWED_VEND |*/ + USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN); + crtc->lcd_gen_cntl |= DONT_SHADOW_VPAR | LOCK_8DOT; + + if((crtc->lcd_gen_cntl & LCD_ON) && + ((xres > par->lcd_width) || (yres > par->lcd_height))) { + /* We cannot display the mode on the LCD. If the CRT is enabled + we can turn off the LCD. + If the CRT is off, it isn't a good idea to switch it on; we don't + know if one is connected. So it's better to fail then. + */ + if (crtc->lcd_gen_cntl & CRT_ON) { + PRINTKI("Disable lcd panel, because video mode does not fit.\n"); + crtc->lcd_gen_cntl &= ~LCD_ON; + /*aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);*/ + } else { + FAIL("Video mode exceeds size of lcd panel.\nConnect this computer to a conventional monitor if you really need this mode."); + } + } + } + + if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON)) { + int VScan = 1; + /* bpp -> bytespp, 1,4 -> 0; 8 -> 2; 15,16 -> 1; 24 -> 6; 32 -> 5 + const u8 DFP_h_sync_dly_LT[] = { 0, 2, 1, 6, 5 }; + const u8 ADD_to_strt_wid_and_dly_LT_DAC[] = { 0, 5, 6, 9, 9, 12, 12 }; */ + + vmode &= ~(FB_VMODE_DOUBLE | FB_VMODE_INTERLACED); + + /* This is horror! When we simulate, say 640x480 on an 800x600 + lcd monitor, the CRTC should be programmed 800x600 values for + the non visible part, but 640x480 for the visible part. + This code has been tested on a laptop with it's 1400x1050 lcd + monitor and a conventional monitor both switched on. + Tested modes: 1280x1024, 1152x864, 1024x768, 800x600, + works with little glitches also with DOUBLESCAN modes + */ + if (yres < par->lcd_height) { + VScan = par->lcd_height / yres; + if(VScan > 1) { + VScan = 2; + vmode |= FB_VMODE_DOUBLE; + } + } + + h_sync_strt = h_disp + par->lcd_right_margin; + h_sync_end = h_sync_strt + par->lcd_hsync_len; + h_sync_dly = /*DFP_h_sync_dly[ ( bpp + 1 ) / 3 ]; */par->lcd_hsync_dly; + h_total = h_disp + par->lcd_hblank_len; + + v_sync_strt = v_disp + par->lcd_lower_margin / VScan; + v_sync_end = v_sync_strt + par->lcd_vsync_len / VScan; + v_total = v_disp + par->lcd_vblank_len / VScan; + } +#endif /* CONFIG_FB_ATY_GENERIC_LCD */ + + h_disp = (h_disp >> 3) - 1; + h_sync_strt = (h_sync_strt >> 3) - 1; + h_sync_end = (h_sync_end >> 3) - 1; + h_total = (h_total >> 3) - 1; + h_sync_wid = h_sync_end - h_sync_strt; + + FAIL_MAX("h_disp too large", h_disp, 0xff); + FAIL_MAX("h_sync_strt too large", h_sync_strt, 0x1ff); + /*FAIL_MAX("h_sync_wid too large", h_sync_wid, 0x1f);*/ + if(h_sync_wid > 0x1f) + h_sync_wid = 0x1f; + FAIL_MAX("h_total too large", h_total, 0x1ff); + + if (vmode & FB_VMODE_DOUBLE) { + v_disp <<= 1; + v_sync_strt <<= 1; + v_sync_end <<= 1; + v_total <<= 1; + } + + vdisplay = yres; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON)) + vdisplay = par->lcd_height; +#endif + + if(vdisplay < 400) { + h_sync_pol = 1; + v_sync_pol = 0; + } else if(vdisplay < 480) { + h_sync_pol = 0; + v_sync_pol = 1; + } else if(vdisplay < 768) { + h_sync_pol = 0; + v_sync_pol = 0; + } else { + h_sync_pol = 1; + v_sync_pol = 1; + } + + v_disp--; + v_sync_strt--; + v_sync_end--; + v_total--; + v_sync_wid = v_sync_end - v_sync_strt; + + FAIL_MAX("v_disp too large", v_disp, 0x7ff); + FAIL_MAX("v_sync_stsrt too large", v_sync_strt, 0x7ff); + /*FAIL_MAX("v_sync_wid too large", v_sync_wid, 0x1f);*/ + if(v_sync_wid > 0x1f) + v_sync_wid = 0x1f; + FAIL_MAX("v_total too large", v_total, 0x7ff); + + c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0; + + /* output */ + crtc->vxres = vxres; + crtc->vyres = vyres; + crtc->xoffset = xoffset; + crtc->yoffset = yoffset; + crtc->bpp = bpp; + crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); + crtc->vline_crnt_vline = 0; + + crtc->h_tot_disp = h_total | (h_disp<<16); + crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) | + ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) | (h_sync_pol<<21); + crtc->v_tot_disp = v_total | (v_disp<<16); + crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21); + + /* crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_PRESERVED_MASK; */ + crtc->gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | pix_width | c_sync; + crtc->gen_cntl |= CRTC_VGA_LINEAR; + + /* Enable doublescan mode if requested */ + if (vmode & FB_VMODE_DOUBLE) + crtc->gen_cntl |= CRTC_DBL_SCAN_EN; + /* Enable interlaced mode if requested */ + if (vmode & FB_VMODE_INTERLACED) + crtc->gen_cntl |= CRTC_INTERLACE_EN; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table != 0) { + vdisplay = yres; + if(vmode & FB_VMODE_DOUBLE) + vdisplay <<= 1; + if(vmode & FB_VMODE_INTERLACED) { + vdisplay >>= 1; + + /* The prefered mode for the lcd is not interlaced, so disable it if + it was enabled. For doublescan there is no problem, because we can + compensate for it in the hardware stretching (we stretch half as much) + */ + vmode &= ~FB_VMODE_INTERLACED; + /*crtc->gen_cntl &= ~CRTC_INTERLACE_EN;*/ + } + crtc->gen_cntl &= ~(CRTC2_EN | CRTC2_PIX_WIDTH); + crtc->lcd_gen_cntl &= ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | + /*TVCLK_PM_EN | VCLK_DAC_PM_EN |*/ + USE_SHADOWED_VEND | USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN); + crtc->lcd_gen_cntl |= (DONT_SHADOW_VPAR/* | LOCK_8DOT*/); + + /* MOBILITY M1 tested, FIXME: LT */ + crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par); + if (!M64_HAS(LT_LCD_REGS)) + crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par) & + ~(AUTO_VERT_RATIO | VERT_STRETCH_MODE | VERT_STRETCH_RATIO3); + + crtc->horz_stretching &= + ~(HORZ_STRETCH_RATIO | HORZ_STRETCH_LOOP | AUTO_HORZ_RATIO | + HORZ_STRETCH_MODE | HORZ_STRETCH_EN); + if (xres < par->lcd_width) { + do { + /* + * The horizontal blender misbehaves when HDisplay is less than a + * a certain threshold (440 for a 1024-wide panel). It doesn't + * stretch such modes enough. Use pixel replication instead of + * blending to stretch modes that can be made to exactly fit the + * panel width. The undocumented "NoLCDBlend" option allows the + * pixel-replicated mode to be slightly wider or narrower than the + * panel width. It also causes a mode that is exactly half as wide + * as the panel to be pixel-replicated, rather than blended. + */ + int HDisplay = xres & ~7; + int nStretch = par->lcd_width / HDisplay; + int Remainder = par->lcd_width % HDisplay; + + if ((!Remainder && ((nStretch > 2))) || + (((HDisplay * 16) / par->lcd_width) < 7)) { + static const char StretchLoops[] = {10, 12, 13, 15, 16}; + int horz_stretch_loop = -1, BestRemainder; + int Numerator = HDisplay, Denominator = par->lcd_width; + int Index = 5; + ATIReduceRatio(&Numerator, &Denominator); + + BestRemainder = (Numerator * 16) / Denominator; + while (--Index >= 0) { + Remainder = ((Denominator - Numerator) * StretchLoops[Index]) % + Denominator; + if (Remainder < BestRemainder) { + horz_stretch_loop = Index; + if (!(BestRemainder = Remainder)) + break; + } + } + + if ((horz_stretch_loop >= 0) && !BestRemainder) { + int horz_stretch_ratio = 0, Accumulator = 0; + int reuse_previous = 1; + + Index = StretchLoops[horz_stretch_loop]; + + while (--Index >= 0) { + if (Accumulator > 0) + horz_stretch_ratio |= reuse_previous; + else + Accumulator += Denominator; + Accumulator -= Numerator; + reuse_previous <<= 1; + } + + crtc->horz_stretching |= (HORZ_STRETCH_EN | + ((horz_stretch_loop & HORZ_STRETCH_LOOP) << 16) | + (horz_stretch_ratio & HORZ_STRETCH_RATIO)); + break; /* Out of the do { ... } while (0) */ + } + } + + crtc->horz_stretching |= (HORZ_STRETCH_MODE | HORZ_STRETCH_EN | + (((HDisplay * (HORZ_STRETCH_BLEND + 1)) / par->lcd_width) & HORZ_STRETCH_BLEND)); + } while (0); + } + + if (vdisplay < par->lcd_height) { + crtc->vert_stretching = (VERT_STRETCH_USE0 | VERT_STRETCH_EN | + (((vdisplay * (VERT_STRETCH_RATIO0 + 1)) / par->lcd_height) & VERT_STRETCH_RATIO0)); + + if (!M64_HAS(LT_LCD_REGS) && + xres <= (M64_HAS(MOBIL_BUS)?1024:800)) + crtc->ext_vert_stretch |= VERT_STRETCH_MODE; + } else { + /* + * Don't use vertical blending if the mode is too wide or not + * vertically stretched. + */ + crtc->vert_stretching = 0; + } + /* copy to shadow crtc */ + crtc->shadow_h_tot_disp = crtc->h_tot_disp; + crtc->shadow_h_sync_strt_wid = crtc->h_sync_strt_wid; + crtc->shadow_v_tot_disp = crtc->v_tot_disp; + crtc->shadow_v_sync_strt_wid = crtc->v_sync_strt_wid; + } +#endif /* CONFIG_FB_ATY_GENERIC_LCD */ + + if (M64_HAS(MAGIC_FIFO)) { + /* Not VTB/GTB */ + /* FIXME: magic FIFO values */ + crtc->gen_cntl |= (aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC2_PIX_WIDTH); + } + crtc->dp_pix_width = dp_pix_width; + crtc->dp_chain_mask = dp_chain_mask; + + return 0; +} + +static int aty_crtc_to_var(const struct crtc *crtc, struct fb_var_screeninfo *var) +{ + u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync; + u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, + h_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; + u32 pix_width; + u32 double_scan, interlace; + + /* input */ + h_total = crtc->h_tot_disp & 0x1ff; + h_disp = (crtc->h_tot_disp >> 16) & 0xff; + h_sync_strt = (crtc->h_sync_strt_wid & 0xff) | ((crtc->h_sync_strt_wid >> 4) & 0x100); + h_sync_dly = (crtc->h_sync_strt_wid >> 8) & 0x7; + h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x1f; + h_sync_pol = (crtc->h_sync_strt_wid >> 21) & 0x1; + v_total = crtc->v_tot_disp & 0x7ff; + v_disp = (crtc->v_tot_disp >> 16) & 0x7ff; + v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; + v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f; + v_sync_pol = (crtc->v_sync_strt_wid >> 21) & 0x1; + c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; + pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; + double_scan = crtc->gen_cntl & CRTC_DBL_SCAN_EN; + interlace = crtc->gen_cntl & CRTC_INTERLACE_EN; + + /* convert */ + xres = (h_disp + 1) * 8; + yres = v_disp + 1; + left = (h_total - h_sync_strt - h_sync_wid) * 8 - h_sync_dly; + right = (h_sync_strt - h_disp) * 8 + h_sync_dly; + hslen = h_sync_wid * 8; + upper = v_total - v_sync_strt - v_sync_wid; + lower = v_sync_strt - v_disp; + vslen = v_sync_wid; + sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | + (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | + (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); + + switch (pix_width) { +#if 0 + case CRTC_PIX_WIDTH_4BPP: + bpp = 4; + 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; +#endif + case CRTC_PIX_WIDTH_8BPP: + bpp = 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 CRTC_PIX_WIDTH_15BPP: /* RGB 555 */ + bpp = 16; + 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 = 0; + var->transp.length = 0; + break; + case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */ + bpp = 16; + 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 CRTC_PIX_WIDTH_24BPP: /* RGB 888 */ + bpp = 24; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */ + bpp = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + default: + FAIL("Invalid pixel width"); + } + + /* output */ + var->xres = xres; + var->yres = yres; + var->xres_virtual = crtc->vxres; + var->yres_virtual = crtc->vyres; + var->bits_per_pixel = bpp; + var->left_margin = left; + var->right_margin = right; + var->upper_margin = upper; + var->lower_margin = lower; + var->hsync_len = hslen; + var->vsync_len = vslen; + var->sync = sync; + var->vmode = FB_VMODE_NONINTERLACED; + /* In double scan mode, the vertical parameters are doubled, so we need to + half them to get the right values. + In interlaced mode the values are already correct, so no correction is + necessary. + */ + if (interlace) + var->vmode = FB_VMODE_INTERLACED; + + if (double_scan) { + var->vmode = FB_VMODE_DOUBLE; + var->yres>>=1; + var->upper_margin>>=1; + var->lower_margin>>=1; + var->vsync_len>>=1; + } + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static int atyfb_set_par(struct fb_info *info) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + struct fb_var_screeninfo *var = &info->var; + u32 tmp, pixclock; + int err; +#ifdef DEBUG + struct fb_var_screeninfo debug; + u32 pixclock_in_ps; +#endif + if (par->asleep) + return 0; + + if ((err = aty_var_to_crtc(info, var, &par->crtc))) + return err; + + pixclock = atyfb_get_pixclock(var, par); + + if (pixclock == 0) { + FAIL("Invalid pixclock"); + } else { + if((err = par->pll_ops->var_to_pll(info, pixclock, var->bits_per_pixel, &par->pll))) + return err; + } + + par->accel_flags = var->accel_flags; /* hack */ + + if (par->blitter_may_be_busy) + wait_for_idle(par); + + aty_set_crtc(par, &par->crtc); + par->dac_ops->set_dac(info, &par->pll, var->bits_per_pixel, par->accel_flags); + par->pll_ops->set_pll(info, &par->pll); + +#ifdef DEBUG + if(par->pll_ops && par->pll_ops->pll_to_var) + pixclock_in_ps = par->pll_ops->pll_to_var(info, &(par->pll)); + else + pixclock_in_ps = 0; + + if(0 == pixclock_in_ps) { + PRINTKE("ALERT ops->pll_to_var get 0\n"); + pixclock_in_ps = pixclock; + } + + memset(&debug, 0, sizeof(debug)); + if(!aty_crtc_to_var(&(par->crtc), &debug)) { + u32 hSync, vRefresh; + u32 h_disp, h_sync_strt, h_sync_end, h_total; + u32 v_disp, v_sync_strt, v_sync_end, v_total; + + h_disp = debug.xres; + h_sync_strt = h_disp + debug.right_margin; + h_sync_end = h_sync_strt + debug.hsync_len; + h_total = h_sync_end + debug.left_margin; + v_disp = debug.yres; + v_sync_strt = v_disp + debug.lower_margin; + v_sync_end = v_sync_strt + debug.vsync_len; + v_total = v_sync_end + debug.upper_margin; + + hSync = 1000000000 / (pixclock_in_ps * h_total); + vRefresh = (hSync * 1000) / v_total; + if (par->crtc.gen_cntl & CRTC_INTERLACE_EN) + vRefresh *= 2; + if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN) + vRefresh /= 2; + + DPRINTK("atyfb_set_par\n"); + DPRINTK(" Set Visible Mode to %ix%i-%i\n", var->xres, var->yres, var->bits_per_pixel); + DPRINTK(" Virtual resolution %ix%i, pixclock_in_ps %i (calculated %i)\n", + var->xres_virtual, var->yres_virtual, pixclock, pixclock_in_ps); + DPRINTK(" Dot clock: %i MHz\n", 1000000 / pixclock_in_ps); + DPRINTK(" Horizontal sync: %i kHz\n", hSync); + DPRINTK(" Vertical refresh: %i Hz\n", vRefresh); + DPRINTK(" x style: %i.%03i %i %i %i %i %i %i %i %i\n", + 1000000 / pixclock_in_ps, 1000000 % pixclock_in_ps, + h_disp, h_sync_strt, h_sync_end, h_total, + v_disp, v_sync_strt, v_sync_end, v_total); + DPRINTK(" fb style: %i %i %i %i %i %i %i %i %i\n", + pixclock_in_ps, + debug.left_margin, h_disp, debug.right_margin, debug.hsync_len, + debug.upper_margin, v_disp, debug.lower_margin, debug.vsync_len); + } +#endif /* DEBUG */ + + if (!M64_HAS(INTEGRATED)) { + /* Don't forget MEM_CNTL */ + tmp = aty_ld_le32(MEM_CNTL, par) & 0xf0ffffff; + switch (var->bits_per_pixel) { + case 8: + tmp |= 0x02000000; + break; + case 16: + tmp |= 0x03000000; + break; + case 32: + tmp |= 0x06000000; + break; + } + aty_st_le32(MEM_CNTL, tmp, par); + } else { + tmp = aty_ld_le32(MEM_CNTL, par) & 0xf00fffff; + if (!M64_HAS(MAGIC_POSTDIV)) + tmp |= par->mem_refresh_rate << 20; + switch (var->bits_per_pixel) { + case 8: + case 24: + tmp |= 0x00000000; + break; + case 16: + tmp |= 0x04000000; + break; + case 32: + tmp |= 0x08000000; + break; + } + if (M64_HAS(CT_BUS)) { + aty_st_le32(DAC_CNTL, 0x87010184, par); + aty_st_le32(BUS_CNTL, 0x680000f9, par); + } else if (M64_HAS(VT_BUS)) { + aty_st_le32(DAC_CNTL, 0x87010184, par); + aty_st_le32(BUS_CNTL, 0x680000f9, par); + } else if (M64_HAS(MOBIL_BUS)) { + aty_st_le32(DAC_CNTL, 0x80010102, par); + aty_st_le32(BUS_CNTL, 0x7b33a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par); + } else { + /* GT */ + aty_st_le32(DAC_CNTL, 0x86010102, par); + aty_st_le32(BUS_CNTL, 0x7b23a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par); + aty_st_le32(EXT_MEM_CNTL, aty_ld_le32(EXT_MEM_CNTL, par) | 0x5000001, par); + } + aty_st_le32(MEM_CNTL, tmp, par); + } + aty_st_8(DAC_MASK, 0xff, par); + + info->fix.line_length = var->xres_virtual * var->bits_per_pixel/8; + info->fix.visual = var->bits_per_pixel <= 8 ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + + /* Initialize the graphics engine */ + if (par->accel_flags & FB_ACCELF_TEXT) + aty_init_engine(par, info); + +#ifdef CONFIG_BOOTX_TEXT + btext_update_display(info->fix.smem_start, + (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8, + ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1, + var->bits_per_pixel, + par->crtc.vxres * var->bits_per_pixel / 8); +#endif /* CONFIG_BOOTX_TEXT */ +#if 0 + /* switch to accelerator mode */ + if (!(par->crtc.gen_cntl & CRTC_EXT_DISP_EN)) + aty_st_le32(CRTC_GEN_CNTL, par->crtc.gen_cntl | CRTC_EXT_DISP_EN, par); +#endif +#ifdef DEBUG +{ + /* dump non shadow CRTC, pll, LCD registers */ + int i; u32 base; + + /* CRTC registers */ + base = 0x2000; + printk("debug atyfb: Mach64 non-shadow register values:"); + for (i = 0; i < 256; i = i+4) { + if(i%16 == 0) printk("\ndebug atyfb: 0x%04X: ", base + i); + printk(" %08X", aty_ld_le32(i, par)); + } + printk("\n\n"); + +#ifdef CONFIG_FB_ATY_CT + /* PLL registers */ + base = 0x00; + printk("debug atyfb: Mach64 PLL register values:"); + for (i = 0; i < 64; i++) { + if(i%16 == 0) printk("\ndebug atyfb: 0x%02X: ", base + i); + if(i%4 == 0) printk(" "); + printk("%02X", aty_ld_pll_ct(i, par)); + } + printk("\n\n"); +#endif /* CONFIG_FB_ATY_CT */ + +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table != 0) { + /* LCD registers */ + base = 0x00; + printk("debug atyfb: LCD register values:"); + if(M64_HAS(LT_LCD_REGS)) { + for(i = 0; i <= POWER_MANAGEMENT; i++) { + if(i == EXT_VERT_STRETCH) + continue; + printk("\ndebug atyfb: 0x%04X: ", lt_lcd_regs[i]); + printk(" %08X", aty_ld_lcd(i, par)); + } + + } else { + for (i = 0; i < 64; i++) { + if(i%4 == 0) printk("\ndebug atyfb: 0x%02X: ", base + i); + printk(" %08X", aty_ld_lcd(i, par)); + } + } + printk("\n\n"); + } +#endif /* CONFIG_FB_ATY_GENERIC_LCD */ +} +#endif /* DEBUG */ + return 0; +} + +static int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + int err; + struct crtc crtc; + union aty_pll pll; + u32 pixclock; + + memcpy(&pll, &(par->pll), sizeof(pll)); + + if((err = aty_var_to_crtc(info, var, &crtc))) + return err; + + pixclock = atyfb_get_pixclock(var, par); + + if (pixclock == 0) { + FAIL("Invalid pixclock"); + } else { + if((err = par->pll_ops->var_to_pll(info, pixclock, var->bits_per_pixel, &pll))) + return err; + } + + if (var->accel_flags & FB_ACCELF_TEXT) + info->var.accel_flags = FB_ACCELF_TEXT; + else + info->var.accel_flags = 0; + +#if 0 /* fbmon is not done. uncomment for 2.5.x -brad */ + if (!fbmon_valid_timings(pixclock, htotal, vtotal, info)) + return -EINVAL; +#endif + aty_crtc_to_var(&crtc, var); + var->pixclock = par->pll_ops->pll_to_var(info, &pll); + return 0; +} + +static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info) +{ + u32 xoffset = info->var.xoffset; + u32 yoffset = info->var.yoffset; + u32 vxres = par->crtc.vxres; + u32 bpp = info->var.bits_per_pixel; + + par->crtc.off_pitch = ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19); +} + + + /* + * Open/Release the frame buffer device + */ + +static int atyfb_open(struct fb_info *info, int user) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + + if (user) { + par->open++; +#ifdef __sparc__ + par->mmaped = 0; +#endif + } + return (0); +} + +static irqreturn_t aty_irq(int irq, void *dev_id, struct pt_regs *fp) +{ + struct atyfb_par *par = dev_id; + int handled = 0; + u32 int_cntl; + + spin_lock(&par->int_lock); + + int_cntl = aty_ld_le32(CRTC_INT_CNTL, par); + + if (int_cntl & CRTC_VBLANK_INT) { + /* clear interrupt */ + aty_st_le32(CRTC_INT_CNTL, (int_cntl & CRTC_INT_EN_MASK) | CRTC_VBLANK_INT_AK, par); + par->vblank.count++; + if (par->vblank.pan_display) { + par->vblank.pan_display = 0; + aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par); + } + wake_up_interruptible(&par->vblank.wait); + handled = 1; + } + + spin_unlock(&par->int_lock); + + return IRQ_RETVAL(handled); +} + +static int aty_enable_irq(struct atyfb_par *par, int reenable) +{ + u32 int_cntl; + + if (!test_and_set_bit(0, &par->irq_flags)) { + if (request_irq(par->irq, aty_irq, SA_SHIRQ, "atyfb", par)) { + clear_bit(0, &par->irq_flags); + return -EINVAL; + } + spin_lock_irq(&par->int_lock); + int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK; + /* clear interrupt */ + aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_AK, par); + /* enable interrupt */ + aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par); + spin_unlock_irq(&par->int_lock); + } else if (reenable) { + spin_lock_irq(&par->int_lock); + int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK; + if (!(int_cntl & CRTC_VBLANK_INT_EN)) { + printk("atyfb: someone disabled IRQ [%08x]\n", int_cntl); + /* re-enable interrupt */ + aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par ); + } + spin_unlock_irq(&par->int_lock); + } + + return 0; +} + +static int aty_disable_irq(struct atyfb_par *par) +{ + u32 int_cntl; + + if (test_and_clear_bit(0, &par->irq_flags)) { + if (par->vblank.pan_display) { + par->vblank.pan_display = 0; + aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par); + } + spin_lock_irq(&par->int_lock); + int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK; + /* disable interrupt */ + aty_st_le32(CRTC_INT_CNTL, int_cntl & ~CRTC_VBLANK_INT_EN, par ); + spin_unlock_irq(&par->int_lock); + free_irq(par->irq, par); + } + + return 0; +} + +static int atyfb_release(struct fb_info *info, int user) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + if (user) { + par->open--; + mdelay(1); + wait_for_idle(par); + if (!par->open) { +#ifdef __sparc__ + int was_mmaped = par->mmaped; + + par->mmaped = 0; + + if (was_mmaped) { + struct fb_var_screeninfo var; + + /* Now reset the default display config, we have no + * idea what the program(s) which mmap'd the chip did + * to the configuration, nor whether it restored it + * correctly. + */ + var = default_var; + if (noaccel) + var.accel_flags &= ~FB_ACCELF_TEXT; + else + var.accel_flags |= FB_ACCELF_TEXT; + if (var.yres == var.yres_virtual) { + u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2)); + var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual; + if (var.yres_virtual < var.yres) + var.yres_virtual = var.yres; + } + } +#endif + aty_disable_irq(par); + } + } + return (0); +} + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int atyfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 xres, yres, xoffset, yoffset; + + xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8; + yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1; + if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN) + yres >>= 1; + xoffset = (var->xoffset + 7) & ~7; + yoffset = var->yoffset; + if (xoffset + xres > par->crtc.vxres || yoffset + yres > par->crtc.vyres) + return -EINVAL; + info->var.xoffset = xoffset; + info->var.yoffset = yoffset; + if (par->asleep) + return 0; + + set_off_pitch(par, info); + if ((var->activate & FB_ACTIVATE_VBL) && !aty_enable_irq(par, 0)) { + par->vblank.pan_display = 1; + } else { + par->vblank.pan_display = 0; + aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par); + } + + return 0; +} + +static int aty_waitforvblank(struct atyfb_par *par, u32 crtc) +{ + struct aty_interrupt *vbl; + unsigned int count; + int ret; + + switch (crtc) { + case 0: + vbl = &par->vblank; + break; + default: + return -ENODEV; + } + + ret = aty_enable_irq(par, 0); + if (ret) + return ret; + + count = vbl->count; + ret = wait_event_interruptible_timeout(vbl->wait, count != vbl->count, HZ/10); + if (ret < 0) { + return ret; + } + if (ret == 0) { + aty_enable_irq(par, 1); + return -ETIMEDOUT; + } + + return 0; +} + + +#ifdef DEBUG +#define ATYIO_CLKR 0x41545900 /* ATY\00 */ +#define ATYIO_CLKW 0x41545901 /* ATY\01 */ + +struct atyclk { + u32 ref_clk_per; + u8 pll_ref_div; + u8 mclk_fb_div; + u8 mclk_post_div; /* 1,2,3,4,8 */ + u8 mclk_fb_mult; /* 2 or 4 */ + u8 xclk_post_div; /* 1,2,3,4,8 */ + u8 vclk_fb_div; + u8 vclk_post_div; /* 1,2,3,4,6,8,12 */ + u32 dsp_xclks_per_row; /* 0-16383 */ + u32 dsp_loop_latency; /* 0-15 */ + u32 dsp_precision; /* 0-7 */ + u32 dsp_on; /* 0-2047 */ + u32 dsp_off; /* 0-2047 */ +}; + +#define ATYIO_FEATR 0x41545902 /* ATY\02 */ +#define ATYIO_FEATW 0x41545903 /* ATY\03 */ +#endif + +#ifndef FBIO_WAITFORVSYNC +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) +#endif + +static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, struct fb_info *info) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; +#ifdef __sparc__ + struct fbtype fbtyp; +#endif + + switch (cmd) { +#ifdef __sparc__ + case FBIOGTYPE: + fbtyp.fb_type = FBTYPE_PCI_GENERIC; + fbtyp.fb_width = par->crtc.vxres; + fbtyp.fb_height = par->crtc.vyres; + fbtyp.fb_depth = info->var.bits_per_pixel; + fbtyp.fb_cmsize = info->cmap.len; + fbtyp.fb_size = info->fix.smem_len; + if (copy_to_user((struct fbtype __user *) arg, &fbtyp, sizeof(fbtyp))) + return -EFAULT; + break; +#endif /* __sparc__ */ + + case FBIO_WAITFORVSYNC: + { + u32 crtc; + + if (get_user(crtc, (__u32 __user *) arg)) + return -EFAULT; + + return aty_waitforvblank(par, crtc); + } + break; + +#if defined(DEBUG) && defined(CONFIG_FB_ATY_CT) + case ATYIO_CLKR: + if (M64_HAS(INTEGRATED)) { + struct atyclk clk; + union aty_pll *pll = &(par->pll); + u32 dsp_config = pll->ct.dsp_config; + u32 dsp_on_off = pll->ct.dsp_on_off; + clk.ref_clk_per = par->ref_clk_per; + clk.pll_ref_div = pll->ct.pll_ref_div; + clk.mclk_fb_div = pll->ct.mclk_fb_div; + clk.mclk_post_div = pll->ct.mclk_post_div_real; + clk.mclk_fb_mult = pll->ct.mclk_fb_mult; + clk.xclk_post_div = pll->ct.xclk_post_div_real; + clk.vclk_fb_div = pll->ct.vclk_fb_div; + clk.vclk_post_div = pll->ct.vclk_post_div_real; + clk.dsp_xclks_per_row = dsp_config & 0x3fff; + clk.dsp_loop_latency = (dsp_config >> 16) & 0xf; + clk.dsp_precision = (dsp_config >> 20) & 7; + clk.dsp_off = dsp_on_off & 0x7ff; + clk.dsp_on = (dsp_on_off >> 16) & 0x7ff; + if (copy_to_user((struct atyclk __user *) arg, &clk, + sizeof(clk))) + return -EFAULT; + } else + return -EINVAL; + break; + case ATYIO_CLKW: + if (M64_HAS(INTEGRATED)) { + struct atyclk clk; + union aty_pll *pll = &(par->pll); + if (copy_from_user(&clk, (struct atyclk __user *) arg, sizeof(clk))) + return -EFAULT; + par->ref_clk_per = clk.ref_clk_per; + pll->ct.pll_ref_div = clk.pll_ref_div; + pll->ct.mclk_fb_div = clk.mclk_fb_div; + pll->ct.mclk_post_div_real = clk.mclk_post_div; + pll->ct.mclk_fb_mult = clk.mclk_fb_mult; + pll->ct.xclk_post_div_real = clk.xclk_post_div; + pll->ct.vclk_fb_div = clk.vclk_fb_div; + pll->ct.vclk_post_div_real = clk.vclk_post_div; + pll->ct.dsp_config = (clk.dsp_xclks_per_row & 0x3fff) | + ((clk.dsp_loop_latency & 0xf)<<16)| ((clk.dsp_precision & 7)<<20); + pll->ct.dsp_on_off = (clk.dsp_off & 0x7ff) | ((clk.dsp_on & 0x7ff)<<16); + /*aty_calc_pll_ct(info, &pll->ct);*/ + aty_set_pll_ct(info, pll); + } else + return -EINVAL; + break; + case ATYIO_FEATR: + if (get_user(par->features, (u32 __user *) arg)) + return -EFAULT; + break; + case ATYIO_FEATW: + if (put_user(par->features, (u32 __user *) arg)) + return -EFAULT; + break; +#endif /* DEBUG && CONFIG_FB_ATY_CT */ + default: + return -EINVAL; + } + return 0; +} + +static int atyfb_sync(struct fb_info *info) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + + if (par->blitter_may_be_busy) + wait_for_idle(par); + return 0; +} + +#ifdef __sparc__ +static int atyfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + unsigned int size, page, map_size = 0; + unsigned long map_offset = 0; + unsigned long off; + int i; + + if (!par->mmap_map) + return -ENXIO; + + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + + off = vma->vm_pgoff << PAGE_SHIFT; + size = vma->vm_end - vma->vm_start; + + /* To stop the swapper from even considering these pages. */ + vma->vm_flags |= (VM_IO | VM_RESERVED); + + if (((vma->vm_pgoff == 0) && (size == info->fix.smem_len)) || + ((off == info->fix.smem_len) && (size == PAGE_SIZE))) + off += 0x8000000000000000UL; + + vma->vm_pgoff = off >> PAGE_SHIFT; /* propagate off changes */ + + /* Each page, see which map applies */ + for (page = 0; page < size;) { + map_size = 0; + for (i = 0; par->mmap_map[i].size; i++) { + unsigned long start = par->mmap_map[i].voff; + unsigned long end = start + par->mmap_map[i].size; + unsigned long offset = off + page; + + if (start > offset) + continue; + if (offset >= end) + continue; + + map_size = par->mmap_map[i].size - (offset - start); + map_offset = + par->mmap_map[i].poff + (offset - start); + break; + } + if (!map_size) { + page += PAGE_SIZE; + continue; + } + if (page + map_size > size) + map_size = size - page; + + pgprot_val(vma->vm_page_prot) &= + ~(par->mmap_map[i].prot_mask); + pgprot_val(vma->vm_page_prot) |= par->mmap_map[i].prot_flag; + + if (remap_pfn_range(vma, vma->vm_start + page, + map_offset >> PAGE_SHIFT, map_size, vma->vm_page_prot)) + return -EAGAIN; + + page += map_size; + } + + if (!map_size) + return -EINVAL; + + if (!par->mmaped) + par->mmaped = 1; + return 0; +} + +static struct { + u32 yoffset; + u8 r[2][256]; + u8 g[2][256]; + u8 b[2][256]; +} atyfb_save; + +static void atyfb_save_palette(struct atyfb_par *par, int enter) +{ + int i, tmp; + + for (i = 0; i < 256; i++) { + tmp = aty_ld_8(DAC_CNTL, par) & 0xfc; + if (M64_HAS(EXTRA_BRIGHT)) + tmp |= 0x2; + aty_st_8(DAC_CNTL, tmp, par); + aty_st_8(DAC_MASK, 0xff, par); + + writeb(i, &par->aty_cmap_regs->rindex); + atyfb_save.r[enter][i] = readb(&par->aty_cmap_regs->lut); + atyfb_save.g[enter][i] = readb(&par->aty_cmap_regs->lut); + atyfb_save.b[enter][i] = readb(&par->aty_cmap_regs->lut); + writeb(i, &par->aty_cmap_regs->windex); + writeb(atyfb_save.r[1 - enter][i], + &par->aty_cmap_regs->lut); + writeb(atyfb_save.g[1 - enter][i], + &par->aty_cmap_regs->lut); + writeb(atyfb_save.b[1 - enter][i], + &par->aty_cmap_regs->lut); + } +} + +static void atyfb_palette(int enter) +{ + struct atyfb_par *par; + struct fb_info *info; + int i; + + for (i = 0; i < FB_MAX; i++) { + info = registered_fb[i]; + if (info && info->fbops == &atyfb_ops) { + par = (struct atyfb_par *) info->par; + + atyfb_save_palette(par, enter); + if (enter) { + atyfb_save.yoffset = info->var.yoffset; + info->var.yoffset = 0; + set_off_pitch(par, info); + } else { + info->var.yoffset = atyfb_save.yoffset; + set_off_pitch(par, info); + } + aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par); + break; + } + } +} +#endif /* __sparc__ */ + + + +#if defined(CONFIG_PM) && defined(CONFIG_PCI) + +/* Power management routines. Those are used for PowerBook sleep. + */ +static int aty_power_mgmt(int sleep, struct atyfb_par *par) +{ + u32 pm; + int timeout; + + pm = aty_ld_lcd(POWER_MANAGEMENT, par); + pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; + aty_st_lcd(POWER_MANAGEMENT, pm, par); + pm = aty_ld_lcd(POWER_MANAGEMENT, par); + + timeout = 2000; + if (sleep) { + /* Sleep */ + pm &= ~PWR_MGT_ON; + aty_st_lcd(POWER_MANAGEMENT, pm, par); + pm = aty_ld_lcd(POWER_MANAGEMENT, par); + udelay(10); + pm &= ~(PWR_BLON | AUTO_PWR_UP); + pm |= SUSPEND_NOW; + aty_st_lcd(POWER_MANAGEMENT, pm, par); + pm = aty_ld_lcd(POWER_MANAGEMENT, par); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_lcd(POWER_MANAGEMENT, pm, par); + do { + pm = aty_ld_lcd(POWER_MANAGEMENT, par); + mdelay(1); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); + } else { + /* Wakeup */ + pm &= ~PWR_MGT_ON; + aty_st_lcd(POWER_MANAGEMENT, pm, par); + pm = aty_ld_lcd(POWER_MANAGEMENT, par); + udelay(10); + pm &= ~SUSPEND_NOW; + pm |= (PWR_BLON | AUTO_PWR_UP); + aty_st_lcd(POWER_MANAGEMENT, pm, par); + pm = aty_ld_lcd(POWER_MANAGEMENT, par); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_lcd(POWER_MANAGEMENT, pm, par); + do { + pm = aty_ld_lcd(POWER_MANAGEMENT, par); + mdelay(1); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != 0); + } + mdelay(500); + + return timeout ? 0 : -EIO; +} + +static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct atyfb_par *par = (struct atyfb_par *) info->par; + +#ifdef CONFIG_PPC_PMAC + /* HACK ALERT ! Once I find a proper way to say to each driver + * individually what will happen with it's PCI slot, I'll change + * that. On laptops, the AGP slot is just unclocked, so D2 is + * expected, while on desktops, the card is powered off + */ + if (state >= 3) + state = 2; +#endif /* CONFIG_PPC_PMAC */ + + if (state != 2 || state == pdev->dev.power.power_state) + return 0; + + acquire_console_sem(); + + fb_set_suspend(info, 1); + + /* Idle & reset engine */ + wait_for_idle(par); + aty_reset_engine(par); + + /* Blank display and LCD */ + atyfb_blank(FB_BLANK_POWERDOWN, info); + + par->asleep = 1; + par->lock_blank = 1; + + /* Set chip to "suspend" mode */ + if (aty_power_mgmt(1, par)) { + par->asleep = 0; + par->lock_blank = 0; + atyfb_blank(FB_BLANK_UNBLANK, info); + fb_set_suspend(info, 0); + release_console_sem(); + return -EIO; + } + + release_console_sem(); + + pdev->dev.power.power_state = state; + + return 0; +} + +static int atyfb_pci_resume(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct atyfb_par *par = (struct atyfb_par *) info->par; + + if (pdev->dev.power.power_state == 0) + return 0; + + acquire_console_sem(); + + if (pdev->dev.power.power_state == 2) + aty_power_mgmt(0, par); + par->asleep = 0; + + /* Restore display */ + atyfb_set_par(info); + + /* Refresh */ + fb_set_suspend(info, 0); + + /* Unblank */ + par->lock_blank = 0; + atyfb_blank(FB_BLANK_UNBLANK, info); + + release_console_sem(); + + pdev->dev.power.power_state = PMSG_ON; + + return 0; +} + +#endif /* defined(CONFIG_PM) && defined(CONFIG_PCI) */ + +#ifdef CONFIG_PMAC_BACKLIGHT + + /* + * LCD backlight control + */ + +static int backlight_conv[] = { + 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d, + 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff +}; + +static int aty_set_backlight_enable(int on, int level, void *data) +{ + struct fb_info *info = (struct fb_info *) data; + struct atyfb_par *par = (struct atyfb_par *) info->par; + unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par); + + reg |= (BLMOD_EN | BIASMOD_EN); + if (on && level > BACKLIGHT_OFF) { + reg &= ~BIAS_MOD_LEVEL_MASK; + reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT); + } else { + reg &= ~BIAS_MOD_LEVEL_MASK; + reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT); + } + aty_st_lcd(LCD_MISC_CNTL, reg, par); + return 0; +} + +static int aty_set_backlight_level(int level, void *data) +{ + return aty_set_backlight_enable(1, level, data); +} + +static struct backlight_controller aty_backlight_controller = { + aty_set_backlight_enable, + aty_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ + +static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk) +{ + const int ragepro_tbl[] = { + 44, 50, 55, 66, 75, 80, 100 + }; + const int ragexl_tbl[] = { + 50, 66, 75, 83, 90, 95, 100, 105, + 110, 115, 120, 125, 133, 143, 166 + }; + const int *refresh_tbl; + int i, size; + + if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) { + refresh_tbl = ragexl_tbl; + size = sizeof(ragexl_tbl)/sizeof(int); + } else { + refresh_tbl = ragepro_tbl; + size = sizeof(ragepro_tbl)/sizeof(int); + } + + for (i=0; i < size; i++) { + if (xclk < refresh_tbl[i]) + break; + } + par->mem_refresh_rate = i; +} + + /* + * Initialisation + */ + +static struct fb_info *fb_list = NULL; + +static int __init aty_init(struct fb_info *info, const char *name) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + const char *ramname = NULL, *xtal; + int gtb_memsize; + struct fb_var_screeninfo var; + u8 pll_ref_div; + u32 i; +#if defined(CONFIG_PPC) + int sense; +#endif + + init_waitqueue_head(&par->vblank.wait); + spin_lock_init(&par->int_lock); + + par->aty_cmap_regs = + (struct aty_cmap_regs __iomem *) (par->ati_regbase + 0xc0); + +#ifdef CONFIG_PPC_PMAC + /* The Apple iBook1 uses non-standard memory frequencies. We detect it + * and set the frequency manually. */ + if (machine_is_compatible("PowerBook2,1")) { + par->pll_limits.mclk = 70; + par->pll_limits.xclk = 53; + } +#endif + if (pll) + par->pll_limits.pll_max = pll; + if (mclk) + par->pll_limits.mclk = mclk; + if (xclk) + par->pll_limits.xclk = xclk; + + aty_calc_mem_refresh(par, par->pll_limits.xclk); + par->pll_per = 1000000/par->pll_limits.pll_max; + par->mclk_per = 1000000/par->pll_limits.mclk; + par->xclk_per = 1000000/par->pll_limits.xclk; + + par->ref_clk_per = 1000000000000ULL / 14318180; + xtal = "14.31818"; + +#ifdef CONFIG_FB_ATY_GX + if (!M64_HAS(INTEGRATED)) { + u32 stat0; + u8 dac_type, dac_subtype, clk_type; + stat0 = aty_ld_le32(CONFIG_STAT0, par); + par->bus_type = (stat0 >> 0) & 0x07; + par->ram_type = (stat0 >> 3) & 0x07; + ramname = aty_gx_ram[par->ram_type]; + /* FIXME: clockchip/RAMDAC probing? */ + dac_type = (aty_ld_le32(DAC_CNTL, par) >> 16) & 0x07; +#ifdef CONFIG_ATARI + clk_type = CLK_ATI18818_1; + dac_type = (stat0 >> 9) & 0x07; + if (dac_type == 0x07) + dac_subtype = DAC_ATT20C408; + else + dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, par) & 0xF0) | dac_type; +#else + dac_type = DAC_IBMRGB514; + dac_subtype = DAC_IBMRGB514; + clk_type = CLK_IBMRGB514; +#endif + switch (dac_subtype) { + case DAC_IBMRGB514: + par->dac_ops = &aty_dac_ibm514; + break; + case DAC_ATI68860_B: + case DAC_ATI68860_C: + par->dac_ops = &aty_dac_ati68860b; + break; + case DAC_ATT20C408: + case DAC_ATT21C498: + par->dac_ops = &aty_dac_att21c498; + break; + default: + PRINTKI("aty_init: DAC type not implemented yet!\n"); + par->dac_ops = &aty_dac_unsupported; + break; + } + switch (clk_type) { + case CLK_ATI18818_1: + par->pll_ops = &aty_pll_ati18818_1; + break; + case CLK_STG1703: + par->pll_ops = &aty_pll_stg1703; + break; + case CLK_CH8398: + par->pll_ops = &aty_pll_ch8398; + break; + case CLK_ATT20C408: + par->pll_ops = &aty_pll_att20c408; + break; + case CLK_IBMRGB514: + par->pll_ops = &aty_pll_ibm514; + break; + default: + PRINTKI("aty_init: CLK type not implemented yet!"); + par->pll_ops = &aty_pll_unsupported; + break; + } + } +#endif /* CONFIG_FB_ATY_GX */ +#ifdef CONFIG_FB_ATY_CT + if (M64_HAS(INTEGRATED)) { + par->dac_ops = &aty_dac_ct; + par->pll_ops = &aty_pll_ct; + par->bus_type = PCI; +#ifdef CONFIG_FB_ATY_XL_INIT + if (IS_XL(par->pci_id)) + atyfb_xl_init(info); +#endif + par->ram_type = (aty_ld_le32(CONFIG_STAT0, par) & 0x07); + ramname = aty_ct_ram[par->ram_type]; + /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */ + if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM) + par->pll_limits.mclk = 63; + } + + if (M64_HAS(GTB_DSP) + && (pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par))) { + int diff1, diff2; + diff1 = 510 * 14 / pll_ref_div - par->pll_limits.pll_max; + diff2 = 510 * 29 / pll_ref_div - par->pll_limits.pll_max; + if (diff1 < 0) + diff1 = -diff1; + if (diff2 < 0) + diff2 = -diff2; + if (diff2 < diff1) { + par->ref_clk_per = 1000000000000ULL / 29498928; + xtal = "29.498928"; + } + } +#endif /* CONFIG_FB_ATY_CT */ + + /* save previous video mode */ + aty_get_crtc(par, &saved_crtc); + if(par->pll_ops->get_pll) + par->pll_ops->get_pll(info, &saved_pll); + + i = aty_ld_le32(MEM_CNTL, par); + gtb_memsize = M64_HAS(GTB_DSP); + if (gtb_memsize) + switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */ + case MEM_SIZE_512K: + info->fix.smem_len = 0x80000; + break; + case MEM_SIZE_1M: + info->fix.smem_len = 0x100000; + break; + case MEM_SIZE_2M_GTB: + info->fix.smem_len = 0x200000; + break; + case MEM_SIZE_4M_GTB: + info->fix.smem_len = 0x400000; + break; + case MEM_SIZE_6M_GTB: + info->fix.smem_len = 0x600000; + break; + case MEM_SIZE_8M_GTB: + info->fix.smem_len = 0x800000; + break; + default: + info->fix.smem_len = 0x80000; + } else + switch (i & MEM_SIZE_ALIAS) { + case MEM_SIZE_512K: + info->fix.smem_len = 0x80000; + break; + case MEM_SIZE_1M: + info->fix.smem_len = 0x100000; + break; + case MEM_SIZE_2M: + info->fix.smem_len = 0x200000; + break; + case MEM_SIZE_4M: + info->fix.smem_len = 0x400000; + break; + case MEM_SIZE_6M: + info->fix.smem_len = 0x600000; + break; + case MEM_SIZE_8M: + info->fix.smem_len = 0x800000; + break; + default: + info->fix.smem_len = 0x80000; + } + + if (M64_HAS(MAGIC_VRAM_SIZE)) { + if (aty_ld_le32(CONFIG_STAT1, par) & 0x40000000) + info->fix.smem_len += 0x400000; + } + + if (vram) { + info->fix.smem_len = vram * 1024; + i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS); + if (info->fix.smem_len <= 0x80000) + i |= MEM_SIZE_512K; + else if (info->fix.smem_len <= 0x100000) + i |= MEM_SIZE_1M; + else if (info->fix.smem_len <= 0x200000) + i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M; + else if (info->fix.smem_len <= 0x400000) + i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M; + else if (info->fix.smem_len <= 0x600000) + i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M; + else + i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M; + aty_st_le32(MEM_CNTL, i, par); + } + + /* + * Reg Block 0 (CT-compatible block) is at mmio_start + * Reg Block 1 (multimedia extensions) is at mmio_start - 0x400 + */ + if (M64_HAS(GX)) { + info->fix.mmio_len = 0x400; + info->fix.accel = FB_ACCEL_ATI_MACH64GX; + } else if (M64_HAS(CT)) { + info->fix.mmio_len = 0x400; + info->fix.accel = FB_ACCEL_ATI_MACH64CT; + } else if (M64_HAS(VT)) { + info->fix.mmio_start -= 0x400; + info->fix.mmio_len = 0x800; + info->fix.accel = FB_ACCEL_ATI_MACH64VT; + } else {/* GT */ + info->fix.mmio_start -= 0x400; + info->fix.mmio_len = 0x800; + info->fix.accel = FB_ACCEL_ATI_MACH64GT; + } + + PRINTKI("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK, %d MHz XCLK\n", + info->fix.smem_len == 0x80000 ? 512 : (info->fix.smem_len >> 20), + info->fix.smem_len == 0x80000 ? 'K' : 'M', ramname, xtal, par->pll_limits.pll_max, + par->pll_limits.mclk, par->pll_limits.xclk); + +#if defined(DEBUG) && defined(CONFIG_ATY_CT) + if (M64_HAS(INTEGRATED)) { + int i; + printk("debug atyfb: BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL " + "DSP_CONFIG DSP_ON_OFF CLOCK_CNTL\n" + "debug atyfb: %08x %08x %08x %08x %08x %08x %08x %08x\n" + "debug atyfb: PLL", + aty_ld_le32(BUS_CNTL, par), aty_ld_le32(DAC_CNTL, par), + aty_ld_le32(MEM_CNTL, par), aty_ld_le32(EXT_MEM_CNTL, par), + aty_ld_le32(CRTC_GEN_CNTL, par), aty_ld_le32(DSP_CONFIG, par), + aty_ld_le32(DSP_ON_OFF, par), aty_ld_le32(CLOCK_CNTL, par)); + for (i = 0; i < 40; i++) + printk(" %02x", aty_ld_pll_ct(i, par)); + printk("\n"); + } +#endif + if(par->pll_ops->init_pll) + par->pll_ops->init_pll(info, &par->pll); + + /* + * Last page of 8 MB (4 MB on ISA) aperture is MMIO + * FIXME: we should use the auxiliary aperture instead so we can access + * the full 8 MB of video RAM on 8 MB boards + */ + + if (!par->aux_start && + (info->fix.smem_len == 0x800000 || (par->bus_type == ISA && info->fix.smem_len == 0x400000))) + info->fix.smem_len -= GUI_RESERVE; + + /* + * Disable register access through the linear aperture + * if the auxiliary aperture is used so we can access + * the full 8 MB of video RAM on 8 MB boards. + */ + if (par->aux_start) + aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par); + +#ifdef CONFIG_MTRR + par->mtrr_aper = -1; + par->mtrr_reg = -1; + if (!nomtrr) { + /* Cover the whole resource. */ + par->mtrr_aper = mtrr_add(par->res_start, par->res_size, MTRR_TYPE_WRCOMB, 1); + if (par->mtrr_aper >= 0 && !par->aux_start) { + /* Make a hole for mmio. */ + par->mtrr_reg = mtrr_add(par->res_start + 0x800000 - GUI_RESERVE, + GUI_RESERVE, MTRR_TYPE_UNCACHABLE, 1); + if (par->mtrr_reg < 0) { + mtrr_del(par->mtrr_aper, 0, 0); + par->mtrr_aper = -1; + } + } + } +#endif + + info->fbops = &atyfb_ops; + info->pseudo_palette = pseudo_palette; + info->flags = FBINFO_FLAG_DEFAULT; + +#ifdef CONFIG_PMAC_BACKLIGHT + if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) { + /* these bits let the 101 powerbook wake up from sleep -- paulus */ + aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par) + | (USE_F32KHZ | TRISTATE_MEM_EN), par); + } else if (M64_HAS(MOBIL_BUS)) + register_backlight_controller(&aty_backlight_controller, info, "ati"); +#endif /* CONFIG_PMAC_BACKLIGHT */ + + memset(&var, 0, sizeof(var)); +#ifdef CONFIG_PPC + if (_machine == _MACH_Pmac) { + /* + * FIXME: The NVRAM stuff should be put in a Mac-specific file, as it + * applies to all Mac video cards + */ + if (mode) { + if (!mac_find_mode(&var, info, mode, 8)) + var = default_var; + } else { + if (default_vmode == VMODE_CHOOSE) { + if (M64_HAS(G3_PB_1024x768)) + /* G3 PowerBook with 1024x768 LCD */ + default_vmode = VMODE_1024_768_60; + else if (machine_is_compatible("iMac")) + default_vmode = VMODE_1024_768_75; + else if (machine_is_compatible + ("PowerBook2,1")) + /* iBook with 800x600 LCD */ + default_vmode = VMODE_800_600_60; + else + default_vmode = VMODE_640_480_67; + sense = read_aty_sense(par); + PRINTKI("monitor sense=%x, mode %d\n", + sense, mac_map_monitor_sense(sense)); + } + if (default_vmode <= 0 || default_vmode > VMODE_MAX) + default_vmode = VMODE_640_480_60; + if (default_cmode < CMODE_8 || default_cmode > CMODE_32) + default_cmode = CMODE_8; + if (mac_vmode_to_var(default_vmode, default_cmode, &var)) + var = default_var; + } + } else +#endif /* !CONFIG_PPC */ + if ( +#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) + /* On Sparc, unless the user gave a specific mode + * specification, use the PROM probed values in + * default_var. + */ + !mode || +#endif + !fb_find_mode(&var, info, mode, NULL, 0, &defmode, 8)) + var = default_var; + + if (noaccel) + var.accel_flags &= ~FB_ACCELF_TEXT; + else + var.accel_flags |= FB_ACCELF_TEXT; + + if (comp_sync != -1) { + if (!comp_sync) + var.sync &= ~FB_SYNC_COMP_HIGH_ACT; + else + var.sync |= FB_SYNC_COMP_HIGH_ACT; + } + + if (var.yres == var.yres_virtual) { + u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2)); + var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual; + if (var.yres_virtual < var.yres) + var.yres_virtual = var.yres; + } + + if (atyfb_check_var(&var, info)) { + PRINTKE("can't set default video mode\n"); + goto aty_init_exit; + } + +#ifdef __sparc__ + atyfb_save_palette(par, 0); +#endif + +#ifdef CONFIG_FB_ATY_CT + if (!noaccel && M64_HAS(INTEGRATED)) + aty_init_cursor(info); +#endif /* CONFIG_FB_ATY_CT */ + info->var = var; + + fb_alloc_cmap(&info->cmap, 256, 0); + + if (register_framebuffer(info) < 0) + goto aty_init_exit; + + fb_list = info; + + PRINTKI("fb%d: %s frame buffer device on %s\n", + info->node, info->fix.id, name); + return 0; + +aty_init_exit: + /* restore video mode */ + aty_set_crtc(par, &saved_crtc); + par->pll_ops->set_pll(info, &saved_pll); + +#ifdef CONFIG_MTRR + if (par->mtrr_reg >= 0) { + mtrr_del(par->mtrr_reg, 0, 0); + par->mtrr_reg = -1; + } + if (par->mtrr_aper >= 0) { + mtrr_del(par->mtrr_aper, 0, 0); + par->mtrr_aper = -1; + } +#endif + return -1; +} + +#ifdef CONFIG_ATARI +static int __init store_video_par(char *video_str, unsigned char m64_num) +{ + char *p; + unsigned long vmembase, size, guiregbase; + + PRINTKI("store_video_par() '%s' \n", video_str); + + if (!(p = strsep(&video_str, ";")) || !*p) + goto mach64_invalid; + vmembase = simple_strtoul(p, NULL, 0); + if (!(p = strsep(&video_str, ";")) || !*p) + goto mach64_invalid; + size = simple_strtoul(p, NULL, 0); + if (!(p = strsep(&video_str, ";")) || !*p) + goto mach64_invalid; + guiregbase = simple_strtoul(p, NULL, 0); + + phys_vmembase[m64_num] = vmembase; + phys_size[m64_num] = size; + phys_guiregbase[m64_num] = guiregbase; + PRINTKI("stored them all: $%08lX $%08lX $%08lX \n", vmembase, size, + guiregbase); + return 0; + + mach64_invalid: + phys_vmembase[m64_num] = 0; + return -1; +} +#endif /* CONFIG_ATARI */ + + /* + * Blank the display. + */ + +static int atyfb_blank(int blank, struct fb_info *info) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u8 gen_cntl; + + if (par->lock_blank || par->asleep) + return 0; + +#ifdef CONFIG_PMAC_BACKLIGHT + if ((_machine == _MACH_Pmac) && blank) + set_backlight_enable(0); +#elif defined(CONFIG_FB_ATY_GENERIC_LCD) + if (par->lcd_table && blank && + (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { + u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par); + pm &= ~PWR_BLON; + aty_st_lcd(POWER_MANAGEMENT, pm, par); + } +#endif + + gen_cntl = aty_ld_8(CRTC_GEN_CNTL, par); + switch (blank) { + case FB_BLANK_UNBLANK: + gen_cntl &= ~(0x4c); + break; + case FB_BLANK_NORMAL: + gen_cntl |= 0x40; + break; + case FB_BLANK_VSYNC_SUSPEND: + gen_cntl |= 0x8; + break; + case FB_BLANK_HSYNC_SUSPEND: + gen_cntl |= 0x4; + break; + case FB_BLANK_POWERDOWN: + gen_cntl |= 0x4c; + break; + } + aty_st_8(CRTC_GEN_CNTL, gen_cntl, par); + +#ifdef CONFIG_PMAC_BACKLIGHT + if ((_machine == _MACH_Pmac) && !blank) + set_backlight_enable(1); +#elif defined(CONFIG_FB_ATY_GENERIC_LCD) + if (par->lcd_table && !blank && + (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { + u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par); + pm |= PWR_BLON; + aty_st_lcd(POWER_MANAGEMENT, pm, par); + } +#endif + + return 0; +} + +static void aty_st_pal(u_int regno, u_int red, u_int green, u_int blue, + const struct atyfb_par *par) +{ +#ifdef CONFIG_ATARI + out_8(&par->aty_cmap_regs->windex, regno); + out_8(&par->aty_cmap_regs->lut, red); + out_8(&par->aty_cmap_regs->lut, green); + out_8(&par->aty_cmap_regs->lut, blue); +#else + writeb(regno, &par->aty_cmap_regs->windex); + writeb(red, &par->aty_cmap_regs->lut); + writeb(green, &par->aty_cmap_regs->lut); + writeb(blue, &par->aty_cmap_regs->lut); +#endif +} + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + * !! 4 & 8 = PSEUDO, > 8 = DIRECTCOLOR + */ + +static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + int i, depth; + u32 *pal = info->pseudo_palette; + + depth = info->var.bits_per_pixel; + if (depth == 16) + depth = (info->var.green.length == 5) ? 15 : 16; + + if (par->asleep) + return 0; + + if (regno > 255 || + (depth == 16 && regno > 63) || + (depth == 15 && regno > 31)) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + par->palette[regno].red = red; + par->palette[regno].green = green; + par->palette[regno].blue = blue; + + if (regno < 16) { + switch (depth) { + case 15: + pal[regno] = (regno << 10) | (regno << 5) | regno; + break; + case 16: + pal[regno] = (regno << 11) | (regno << 5) | regno; + break; + case 24: + pal[regno] = (regno << 16) | (regno << 8) | regno; + break; + case 32: + i = (regno << 8) | regno; + pal[regno] = (i << 16) | i; + break; + } + } + + i = aty_ld_8(DAC_CNTL, par) & 0xfc; + if (M64_HAS(EXTRA_BRIGHT)) + i |= 0x2; /* DAC_CNTL | 0x2 turns off the extra brightness for gt */ + aty_st_8(DAC_CNTL, i, par); + aty_st_8(DAC_MASK, 0xff, par); + + if (M64_HAS(INTEGRATED)) { + if (depth == 16) { + if (regno < 32) + aty_st_pal(regno << 3, red, + par->palette[regno<<1].green, + blue, par); + red = par->palette[regno>>1].red; + blue = par->palette[regno>>1].blue; + regno <<= 2; + } else if (depth == 15) { + regno <<= 3; + for(i = 0; i < 8; i++) { + aty_st_pal(regno + i, red, green, blue, par); + } + } + } + aty_st_pal(regno, red, green, blue, par); + + return 0; +} + +#ifdef CONFIG_PCI + +#ifdef __sparc__ + +extern void (*prom_palette) (int); + +static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, + struct fb_info *info, unsigned long addr) +{ + extern int con_is_present(void); + + struct atyfb_par *par = info->par; + struct pcidev_cookie *pcp; + char prop[128]; + int node, len, i, j, ret; + u32 mem, chip_id; + + /* Do not attach when we have a serial console. */ + if (!con_is_present()) + return -ENXIO; + + /* + * Map memory-mapped registers. + */ + par->ati_regbase = (void *)addr + 0x7ffc00UL; + info->fix.mmio_start = addr + 0x7ffc00UL; + + /* + * Map in big-endian aperture. + */ + info->screen_base = (char *) (addr + 0x800000UL); + info->fix.smem_start = addr + 0x800000UL; + + /* + * Figure mmap addresses from PCI config space. + * Split Framebuffer in big- and little-endian halfs. + */ + for (i = 0; i < 6 && pdev->resource[i].start; i++) + /* nothing */ ; + j = i + 4; + + par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC); + if (!par->mmap_map) { + PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n"); + return -ENOMEM; + } + memset(par->mmap_map, 0, j * sizeof(*par->mmap_map)); + + for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) { + struct resource *rp = &pdev->resource[i]; + int io, breg = PCI_BASE_ADDRESS_0 + (i << 2); + unsigned long base; + u32 size, pbase; + + base = rp->start; + + io = (rp->flags & IORESOURCE_IO); + + size = rp->end - base + 1; + + pci_read_config_dword(pdev, breg, &pbase); + + if (io) + size &= ~1; + + /* + * Map the framebuffer a second time, this time without + * the braindead _PAGE_IE setting. This is used by the + * fixed Xserver, but we need to maintain the old mapping + * to stay compatible with older ones... + */ + if (base == addr) { + par->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK; + par->mmap_map[j].poff = base & PAGE_MASK; + par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK; + par->mmap_map[j].prot_mask = _PAGE_CACHE; + par->mmap_map[j].prot_flag = _PAGE_E; + j++; + } + + /* + * Here comes the old framebuffer mapping with _PAGE_IE + * set for the big endian half of the framebuffer... + */ + if (base == addr) { + par->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK; + par->mmap_map[j].poff = (base + 0x800000) & PAGE_MASK; + par->mmap_map[j].size = 0x800000; + par->mmap_map[j].prot_mask = _PAGE_CACHE; + par->mmap_map[j].prot_flag = _PAGE_E | _PAGE_IE; + size -= 0x800000; + j++; + } + + par->mmap_map[j].voff = pbase & PAGE_MASK; + par->mmap_map[j].poff = base & PAGE_MASK; + par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK; + par->mmap_map[j].prot_mask = _PAGE_CACHE; + par->mmap_map[j].prot_flag = _PAGE_E; + j++; + } + + if((ret = correct_chipset(par))) + return ret; + + if (IS_XL(pdev->device)) { + /* + * Fix PROMs idea of MEM_CNTL settings... + */ + mem = aty_ld_le32(MEM_CNTL, par); + chip_id = aty_ld_le32(CONFIG_CHIP_ID, par); + if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && !((chip_id >> 24) & 1)) { + switch (mem & 0x0f) { + case 3: + mem = (mem & ~(0x0f)) | 2; + break; + case 7: + mem = (mem & ~(0x0f)) | 3; + break; + case 9: + mem = (mem & ~(0x0f)) | 4; + break; + case 11: + mem = (mem & ~(0x0f)) | 5; + break; + default: + break; + } + if ((aty_ld_le32(CONFIG_STAT0, par) & 7) >= SDRAM) + mem &= ~(0x00700000); + } + mem &= ~(0xcf80e000); /* Turn off all undocumented bits. */ + aty_st_le32(MEM_CNTL, mem, par); + } + + /* + * If this is the console device, we will set default video + * settings to what the PROM left us with. + */ + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "aliases"); + if (node) { + len = prom_getproperty(node, "screen", prop, sizeof(prop)); + if (len > 0) { + prop[len] = '\0'; + node = prom_finddevice(prop); + } else + node = 0; + } + + pcp = pdev->sysdata; + if (node == pcp->prom_node) { + struct fb_var_screeninfo *var = &default_var; + unsigned int N, P, Q, M, T, R; + u32 v_total, h_total; + struct crtc crtc; + u8 pll_regs[16]; + u8 clock_cntl; + + crtc.vxres = prom_getintdefault(node, "width", 1024); + crtc.vyres = prom_getintdefault(node, "height", 768); + var->bits_per_pixel = prom_getintdefault(node, "depth", 8); + var->xoffset = var->yoffset = 0; + crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par); + crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par); + crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par); + crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par); + crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par); + aty_crtc_to_var(&crtc, var); + + h_total = var->xres + var->right_margin + var->hsync_len + var->left_margin; + v_total = var->yres + var->lower_margin + var->vsync_len + var->upper_margin; + + /* + * Read the PLL to figure actual Refresh Rate. + */ + clock_cntl = aty_ld_8(CLOCK_CNTL, par); + /* DPRINTK("CLOCK_CNTL %02x\n", clock_cntl); */ + for (i = 0; i < 16; i++) + pll_regs[i] = aty_ld_pll_ct(i, par); + + /* + * PLL Reference Divider M: + */ + M = pll_regs[2]; + + /* + * PLL Feedback Divider N (Dependant on CLOCK_CNTL): + */ + N = pll_regs[7 + (clock_cntl & 3)]; + + /* + * PLL Post Divider P (Dependant on CLOCK_CNTL): + */ + P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1)); + + /* + * PLL Divider Q: + */ + Q = N / P; + + /* + * Target Frequency: + * + * T * M + * Q = ------- + * 2 * R + * + * where R is XTALIN (= 14318 or 29498 kHz). + */ + if (IS_XL(pdev->device)) + R = 29498; + else + R = 14318; + + T = 2 * Q * R / M; + + default_var.pixclock = 1000000000 / T; + } + + return 0; +} + +#else /* __sparc__ */ + +#ifdef __i386__ +#ifdef CONFIG_FB_ATY_GENERIC_LCD +static void aty_init_lcd(struct atyfb_par *par, u32 bios_base) +{ + u32 driv_inf_tab, sig; + u16 lcd_ofs; + + /* To support an LCD panel, we should know it's dimensions and + * it's desired pixel clock. + * There are two ways to do it: + * - Check the startup video mode and calculate the panel + * size from it. This is unreliable. + * - Read it from the driver information table in the video BIOS. + */ + /* Address of driver information table is at offset 0x78. */ + driv_inf_tab = bios_base + *((u16 *)(bios_base+0x78)); + + /* Check for the driver information table signature. */ + sig = (*(u32 *)driv_inf_tab); + if ((sig == 0x54504c24) || /* Rage LT pro */ + (sig == 0x544d5224) || /* Rage mobility */ + (sig == 0x54435824) || /* Rage XC */ + (sig == 0x544c5824)) { /* Rage XL */ + PRINTKI("BIOS contains driver information table.\n"); + lcd_ofs = (*(u16 *)(driv_inf_tab + 10)); + par->lcd_table = 0; + if (lcd_ofs != 0) { + par->lcd_table = bios_base + lcd_ofs; + } + } + + if (par->lcd_table != 0) { + char model[24]; + char strbuf[16]; + char refresh_rates_buf[100]; + int id, tech, f, i, m, default_refresh_rate; + char *txtcolour; + char *txtmonitor; + char *txtdual; + char *txtformat; + u16 width, height, panel_type, refresh_rates; + u16 *lcdmodeptr; + u32 format; + u8 lcd_refresh_rates[16] = {50,56,60,67,70,72,75,76,85,90,100,120,140,150,160,200}; + /* The most important information is the panel size at + * offset 25 and 27, but there's some other nice information + * which we print to the screen. + */ + id = *(u8 *)par->lcd_table; + strncpy(model,(char *)par->lcd_table+1,24); + model[23]=0; + + width = par->lcd_width = *(u16 *)(par->lcd_table+25); + height = par->lcd_height = *(u16 *)(par->lcd_table+27); + panel_type = *(u16 *)(par->lcd_table+29); + if (panel_type & 1) + txtcolour = "colour"; + else + txtcolour = "monochrome"; + if (panel_type & 2) + txtdual = "dual (split) "; + else + txtdual = ""; + tech = (panel_type>>2) & 63; + switch (tech) { + case 0: + txtmonitor = "passive matrix"; + break; + case 1: + txtmonitor = "active matrix"; + break; + case 2: + txtmonitor = "active addressed STN"; + break; + case 3: + txtmonitor = "EL"; + break; + case 4: + txtmonitor = "plasma"; + break; + default: + txtmonitor = "unknown"; + } + format = *(u32 *)(par->lcd_table+57); + if (tech == 0 || tech == 2) { + switch (format & 7) { + case 0: + txtformat = "12 bit interface"; + break; + case 1: + txtformat = "16 bit interface"; + break; + case 2: + txtformat = "24 bit interface"; + break; + default: + txtformat = "unkown format"; + } + } else { + switch (format & 7) { + case 0: + txtformat = "8 colours"; + break; + case 1: + txtformat = "512 colours"; + break; + case 2: + txtformat = "4096 colours"; + break; + case 4: + txtformat = "262144 colours (LT mode)"; + break; + case 5: + txtformat = "16777216 colours"; + break; + case 6: + txtformat = "262144 colours (FDPI-2 mode)"; + break; + default: + txtformat = "unkown format"; + } + } + PRINTKI("%s%s %s monitor detected: %s\n", + txtdual ,txtcolour, txtmonitor, model); + PRINTKI(" id=%d, %dx%d pixels, %s\n", + id, width, height, txtformat); + refresh_rates_buf[0] = 0; + refresh_rates = *(u16 *)(par->lcd_table+62); + m = 1; + f = 0; + for (i=0;i<16;i++) { + if (refresh_rates & m) { + if (f == 0) { + sprintf(strbuf, "%d", lcd_refresh_rates[i]); + f++; + } else { + sprintf(strbuf, ",%d", lcd_refresh_rates[i]); + } + strcat(refresh_rates_buf,strbuf); + } + m = m << 1; + } + default_refresh_rate = (*(u8 *)(par->lcd_table+61) & 0xf0) >> 4; + PRINTKI(" supports refresh rates [%s], default %d Hz\n", + refresh_rates_buf, lcd_refresh_rates[default_refresh_rate]); + par->lcd_refreshrate = lcd_refresh_rates[default_refresh_rate]; + /* We now need to determine the crtc parameters for the + * lcd monitor. This is tricky, because they are not stored + * individually in the BIOS. Instead, the BIOS contains a + * table of display modes that work for this monitor. + * + * The idea is that we search for a mode of the same dimensions + * as the dimensions of the lcd monitor. Say our lcd monitor + * is 800x600 pixels, we search for a 800x600 monitor. + * The CRTC parameters we find here are the ones that we need + * to use to simulate other resolutions on the lcd screen. + */ + lcdmodeptr = (u16 *)(par->lcd_table + 64); + while (*lcdmodeptr != 0) { + u32 modeptr; + u16 mwidth, mheight, lcd_hsync_start, lcd_vsync_start; + modeptr = bios_base + *lcdmodeptr; + + mwidth = *((u16 *)(modeptr+0)); + mheight = *((u16 *)(modeptr+2)); + + if (mwidth == width && mheight == height) { + par->lcd_pixclock = 100000000 / *((u16 *)(modeptr+9)); + par->lcd_htotal = *((u16 *)(modeptr+17)) & 511; + par->lcd_hdisp = *((u16 *)(modeptr+19)) & 511; + lcd_hsync_start = *((u16 *)(modeptr+21)) & 511; + par->lcd_hsync_dly = (*((u16 *)(modeptr+21)) >> 9) & 7; + par->lcd_hsync_len = *((u8 *)(modeptr+23)) & 63; + + par->lcd_vtotal = *((u16 *)(modeptr+24)) & 2047; + par->lcd_vdisp = *((u16 *)(modeptr+26)) & 2047; + lcd_vsync_start = *((u16 *)(modeptr+28)) & 2047; + par->lcd_vsync_len = (*((u16 *)(modeptr+28)) >> 11) & 31; + + par->lcd_htotal = (par->lcd_htotal + 1) * 8; + par->lcd_hdisp = (par->lcd_hdisp + 1) * 8; + lcd_hsync_start = (lcd_hsync_start + 1) * 8; + par->lcd_hsync_len = par->lcd_hsync_len * 8; + + par->lcd_vtotal++; + par->lcd_vdisp++; + lcd_vsync_start++; + + par->lcd_right_margin = lcd_hsync_start - par->lcd_hdisp; + par->lcd_lower_margin = lcd_vsync_start - par->lcd_vdisp; + par->lcd_hblank_len = par->lcd_htotal - par->lcd_hdisp; + par->lcd_vblank_len = par->lcd_vtotal - par->lcd_vdisp; + break; + } + + lcdmodeptr++; + } + if (*lcdmodeptr == 0) { + PRINTKE("LCD monitor CRTC parameters not found!!!\n"); + /* To do: Switch to CRT if possible. */ + } else { + PRINTKI(" LCD CRTC parameters: %d.%d %d %d %d %d %d %d %d %d\n", + 1000000 / par->lcd_pixclock, 1000000 % par->lcd_pixclock, + par->lcd_hdisp, + par->lcd_hdisp + par->lcd_right_margin, + par->lcd_hdisp + par->lcd_right_margin + + par->lcd_hsync_dly + par->lcd_hsync_len, + par->lcd_htotal, + par->lcd_vdisp, + par->lcd_vdisp + par->lcd_lower_margin, + par->lcd_vdisp + par->lcd_lower_margin + par->lcd_vsync_len, + par->lcd_vtotal); + PRINTKI(" : %d %d %d %d %d %d %d %d %d\n", + par->lcd_pixclock, + par->lcd_hblank_len - (par->lcd_right_margin + + par->lcd_hsync_dly + par->lcd_hsync_len), + par->lcd_hdisp, + par->lcd_right_margin, + par->lcd_hsync_len, + par->lcd_vblank_len - (par->lcd_lower_margin + par->lcd_vsync_len), + par->lcd_vdisp, + par->lcd_lower_margin, + par->lcd_vsync_len); + } + } +} +#endif /* CONFIG_FB_ATY_GENERIC_LCD */ + +static int __devinit init_from_bios(struct atyfb_par *par) +{ + u32 bios_base, rom_addr; + int ret; + + rom_addr = 0xc0000 + ((aty_ld_le32(SCRATCH_REG1, par) & 0x7f) << 11); + bios_base = (unsigned long)ioremap(rom_addr, 0x10000); + + /* The BIOS starts with 0xaa55. */ + if (*((u16 *)bios_base) == 0xaa55) { + + u8 *bios_ptr; + u16 rom_table_offset, freq_table_offset; + PLL_BLOCK_MACH64 pll_block; + + PRINTKI("Mach64 BIOS is located at %x, mapped at %x.\n", rom_addr, bios_base); + + /* check for frequncy table */ + bios_ptr = (u8*)bios_base; + rom_table_offset = (u16)(bios_ptr[0x48] | (bios_ptr[0x49] << 8)); + freq_table_offset = bios_ptr[rom_table_offset + 16] | (bios_ptr[rom_table_offset + 17] << 8); + memcpy(&pll_block, bios_ptr + freq_table_offset, sizeof(PLL_BLOCK_MACH64)); + + PRINTKI("BIOS frequency table:\n"); + PRINTKI("PCLK_min_freq %d, PCLK_max_freq %d, ref_freq %d, ref_divider %d\n", + pll_block.PCLK_min_freq, pll_block.PCLK_max_freq, + pll_block.ref_freq, pll_block.ref_divider); + PRINTKI("MCLK_pwd %d, MCLK_max_freq %d, XCLK_max_freq %d, SCLK_freq %d\n", + pll_block.MCLK_pwd, pll_block.MCLK_max_freq, + pll_block.XCLK_max_freq, pll_block.SCLK_freq); + + par->pll_limits.pll_min = pll_block.PCLK_min_freq/100; + par->pll_limits.pll_max = pll_block.PCLK_max_freq/100; + par->pll_limits.ref_clk = pll_block.ref_freq/100; + par->pll_limits.ref_div = pll_block.ref_divider; + par->pll_limits.sclk = pll_block.SCLK_freq/100; + par->pll_limits.mclk = pll_block.MCLK_max_freq/100; + par->pll_limits.mclk_pm = pll_block.MCLK_pwd/100; + par->pll_limits.xclk = pll_block.XCLK_max_freq/100; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + aty_init_lcd(par, bios_base); +#endif + ret = 0; + } else { + PRINTKE("no BIOS frequency table found, use parameters\n"); + ret = -ENXIO; + } + iounmap((void* __iomem )bios_base); + + return ret; +} +#endif /* __i386__ */ + +static int __devinit atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info, unsigned long addr) +{ + struct atyfb_par *par = info->par; + u16 tmp; + unsigned long raddr; + struct resource *rrp; + int ret = 0; + + raddr = addr + 0x7ff000UL; + rrp = &pdev->resource[2]; + if ((rrp->flags & IORESOURCE_MEM) && request_mem_region(rrp->start, rrp->end - rrp->start + 1, "atyfb")) { + par->aux_start = rrp->start; + par->aux_size = rrp->end - rrp->start + 1; + raddr = rrp->start; + PRINTKI("using auxiliary register aperture\n"); + } + + info->fix.mmio_start = raddr; + par->ati_regbase = ioremap(info->fix.mmio_start, 0x1000); + if (par->ati_regbase == 0) + return -ENOMEM; + + info->fix.mmio_start += par->aux_start ? 0x400 : 0xc00; + par->ati_regbase += par->aux_start ? 0x400 : 0xc00; + + /* + * Enable memory-space accesses using config-space + * command register. + */ + pci_read_config_word(pdev, PCI_COMMAND, &tmp); + if (!(tmp & PCI_COMMAND_MEMORY)) { + tmp |= PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, tmp); + } +#ifdef __BIG_ENDIAN + /* Use the big-endian aperture */ + addr += 0x800000; +#endif + + /* Map in frame buffer */ + info->fix.smem_start = addr; + info->screen_base = ioremap(addr, 0x800000); + if (info->screen_base == NULL) { + ret = -ENOMEM; + goto atyfb_setup_generic_fail; + } + + if((ret = correct_chipset(par))) + goto atyfb_setup_generic_fail; +#ifdef __i386__ + if((ret = init_from_bios(par))) + goto atyfb_setup_generic_fail; +#endif + if (!(aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_EXT_DISP_EN)) + par->clk_wr_offset = (inb(R_GENMO) & 0x0CU) >> 2; + else + par->clk_wr_offset = aty_ld_8(CLOCK_CNTL, par) & 0x03U; + + /* according to ATI, we should use clock 3 for acelerated mode */ + par->clk_wr_offset = 3; + + return 0; + +atyfb_setup_generic_fail: + iounmap(par->ati_regbase); + par->ati_regbase = NULL; + return ret; +} + +#endif /* !__sparc__ */ + +static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + unsigned long addr, res_start, res_size; + struct fb_info *info; + struct resource *rp; + struct atyfb_par *par; + int i, rc = -ENOMEM; + + for (i = sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >= 0; i--) + if (pdev->device == aty_chips[i].pci_id) + break; + + if (i < 0) + return -ENODEV; + + /* Enable device in PCI config */ + if (pci_enable_device(pdev)) { + PRINTKE("Cannot enable PCI device\n"); + return -ENXIO; + } + + /* Find which resource to use */ + rp = &pdev->resource[0]; + if (rp->flags & IORESOURCE_IO) + rp = &pdev->resource[1]; + addr = rp->start; + if (!addr) + return -ENXIO; + + /* Reserve space */ + res_start = rp->start; + res_size = rp->end - rp->start + 1; + if (!request_mem_region (res_start, res_size, "atyfb")) + return -EBUSY; + + /* Allocate framebuffer */ + info = framebuffer_alloc(sizeof(struct atyfb_par), &pdev->dev); + if (!info) { + PRINTKE("atyfb_pci_probe() can't alloc fb_info\n"); + return -ENOMEM; + } + par = info->par; + info->fix = atyfb_fix; + info->device = &pdev->dev; + par->pci_id = aty_chips[i].pci_id; + par->res_start = res_start; + par->res_size = res_size; + par->irq = pdev->irq; + + /* Setup "info" structure */ +#ifdef __sparc__ + rc = atyfb_setup_sparc(pdev, info, addr); +#else + rc = atyfb_setup_generic(pdev, info, addr); +#endif + if (rc) + goto err_release_mem; + + pci_set_drvdata(pdev, info); + + /* Init chip & register framebuffer */ + if (aty_init(info, "PCI")) + goto err_release_io; + +#ifdef __sparc__ + if (!prom_palette) + prom_palette = atyfb_palette; + + /* + * Add /dev/fb mmap values. + */ + par->mmap_map[0].voff = 0x8000000000000000UL; + par->mmap_map[0].poff = (unsigned long) info->screen_base & PAGE_MASK; + par->mmap_map[0].size = info->fix.smem_len; + par->mmap_map[0].prot_mask = _PAGE_CACHE; + par->mmap_map[0].prot_flag = _PAGE_E; + par->mmap_map[1].voff = par->mmap_map[0].voff + info->fix.smem_len; + par->mmap_map[1].poff = (long)par->ati_regbase & PAGE_MASK; + par->mmap_map[1].size = PAGE_SIZE; + par->mmap_map[1].prot_mask = _PAGE_CACHE; + par->mmap_map[1].prot_flag = _PAGE_E; +#endif /* __sparc__ */ + + return 0; + +err_release_io: +#ifdef __sparc__ + kfree(par->mmap_map); +#else + if (par->ati_regbase) + iounmap(par->ati_regbase); + if (info->screen_base) + iounmap(info->screen_base); +#endif +err_release_mem: + if (par->aux_start) + release_mem_region(par->aux_start, par->aux_size); + + release_mem_region(par->res_start, par->res_size); + framebuffer_release(info); + + return rc; +} + +#endif /* CONFIG_PCI */ + +#ifdef CONFIG_ATARI + +static int __devinit atyfb_atari_probe(void) +{ + struct aty_par *par; + struct fb_info *info; + int m64_num; + u32 clock_r; + + for (m64_num = 0; m64_num < mach64_count; m64_num++) { + if (!phys_vmembase[m64_num] || !phys_size[m64_num] || + !phys_guiregbase[m64_num]) { + PRINTKI("phys_*[%d] parameters not set => returning early. \n", m64_num); + continue; + } + + info = framebuffer_alloc(sizeof(struct atyfb_par), NULL); + if (!info) { + PRINTKE("atyfb_atari_probe() can't alloc fb_info\n"); + return -ENOMEM; + } + par = info->par; + + info->fix = atyfb_fix; + + par->irq = (unsigned int) -1; /* something invalid */ + + /* + * Map the video memory (physical address given) to somewhere in the + * kernel address space. + */ + info->screen_base = ioremap(phys_vmembase[m64_num], phys_size[m64_num]); + info->fix.smem_start = (unsigned long)info->screen_base; /* Fake! */ + par->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000) + + 0xFC00ul; + info->fix.mmio_start = (unsigned long)par->ati_regbase; /* Fake! */ + + aty_st_le32(CLOCK_CNTL, 0x12345678, par); + clock_r = aty_ld_le32(CLOCK_CNTL, par); + + switch (clock_r & 0x003F) { + case 0x12: + par->clk_wr_offset = 3; /* */ + break; + case 0x34: + par->clk_wr_offset = 2; /* Medusa ST-IO ISA Adapter etc. */ + break; + case 0x16: + par->clk_wr_offset = 1; /* */ + break; + case 0x38: + par->clk_wr_offset = 0; /* Panther 1 ISA Adapter (Gerald) */ + break; + } + + if (aty_init(info, "ISA bus")) { + framebuffer_release(info); + /* This is insufficient! kernel_map has added two large chunks!! */ + return -ENXIO; + } + } +} + +#endif /* CONFIG_ATARI */ + +static void __devexit atyfb_remove(struct fb_info *info) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + + /* restore video mode */ + aty_set_crtc(par, &saved_crtc); + par->pll_ops->set_pll(info, &saved_pll); + + unregister_framebuffer(info); + +#ifdef CONFIG_MTRR + if (par->mtrr_reg >= 0) { + mtrr_del(par->mtrr_reg, 0, 0); + par->mtrr_reg = -1; + } + if (par->mtrr_aper >= 0) { + mtrr_del(par->mtrr_aper, 0, 0); + par->mtrr_aper = -1; + } +#endif +#ifndef __sparc__ + if (par->ati_regbase) + iounmap(par->ati_regbase); + if (info->screen_base) + iounmap(info->screen_base); +#ifdef __BIG_ENDIAN + if (info->sprite.addr) + iounmap(info->sprite.addr); +#endif +#endif +#ifdef __sparc__ + kfree(par->mmap_map); +#endif + if (par->aux_start) + release_mem_region(par->aux_start, par->aux_size); + + if (par->res_start) + release_mem_region(par->res_start, par->res_size); + + framebuffer_release(info); +} + +#ifdef CONFIG_PCI + +static void __devexit atyfb_pci_remove(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + + atyfb_remove(info); +} + +/* + * This driver uses its own matching table. That will be more difficult + * to fix, so for now, we just match against any ATI ID and let the + * probe() function find out what's up. That also mean we don't have + * a module ID table though. + */ +static struct pci_device_id atyfb_pci_tbl[] = { + { PCI_VENDOR_ID_ATI, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0 }, + { 0, } +}; + +static struct pci_driver atyfb_driver = { + .name = "atyfb", + .id_table = atyfb_pci_tbl, + .probe = atyfb_pci_probe, + .remove = __devexit_p(atyfb_pci_remove), +#ifdef CONFIG_PM + .suspend = atyfb_pci_suspend, + .resume = atyfb_pci_resume, +#endif /* CONFIG_PM */ +}; + +#endif /* CONFIG_PCI */ + +#ifndef MODULE +static int __init atyfb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "noaccel", 7)) { + noaccel = 1; +#ifdef CONFIG_MTRR + } else if (!strncmp(this_opt, "nomtrr", 6)) { + nomtrr = 1; +#endif + } else if (!strncmp(this_opt, "vram:", 5)) + vram = simple_strtoul(this_opt + 5, NULL, 0); + else if (!strncmp(this_opt, "pll:", 4)) + pll = simple_strtoul(this_opt + 4, NULL, 0); + else if (!strncmp(this_opt, "mclk:", 5)) + mclk = simple_strtoul(this_opt + 5, NULL, 0); + else if (!strncmp(this_opt, "xclk:", 5)) + xclk = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "comp_sync:", 10)) + comp_sync = simple_strtoul(this_opt+10, NULL, 0); +#ifdef CONFIG_PPC + else if (!strncmp(this_opt, "vmode:", 6)) { + unsigned int vmode = + simple_strtoul(this_opt + 6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + default_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + unsigned int cmode = + simple_strtoul(this_opt + 6, NULL, 0); + switch (cmode) { + case 0: + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + case 24: + case 32: + default_cmode = CMODE_32; + break; + } + } +#endif +#ifdef CONFIG_ATARI + /* + * Why do we need this silly Mach64 argument? + * We are already here because of mach64= so its redundant. + */ + else if (MACH_IS_ATARI + && (!strncmp(this_opt, "Mach64:", 7))) { + static unsigned char m64_num; + static char mach64_str[80]; + strlcpy(mach64_str, this_opt + 7, sizeof(mach64_str)); + if (!store_video_par(mach64_str, m64_num)) { + m64_num++; + mach64_count = m64_num; + } + } +#endif + else + mode = this_opt; + } + return 0; +} +#endif /* MODULE */ + +static int __init atyfb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("atyfb", &option)) + return -ENODEV; + atyfb_setup(option); +#endif + +#ifdef CONFIG_PCI + pci_register_driver(&atyfb_driver); +#endif +#ifdef CONFIG_ATARI + atyfb_atari_probe(); +#endif + return 0; +} + +static void __exit atyfb_exit(void) +{ +#ifdef CONFIG_PCI + pci_unregister_driver(&atyfb_driver); +#endif +} + +module_init(atyfb_init); +module_exit(atyfb_exit); + +MODULE_DESCRIPTION("FBDev driver for ATI Mach64 cards"); +MODULE_LICENSE("GPL"); +module_param(noaccel, bool, 0); +MODULE_PARM_DESC(noaccel, "bool: disable acceleration"); +module_param(vram, int, 0); +MODULE_PARM_DESC(vram, "int: override size of video ram"); +module_param(pll, int, 0); +MODULE_PARM_DESC(pll, "int: override video clock"); +module_param(mclk, int, 0); +MODULE_PARM_DESC(mclk, "int: override memory clock"); +module_param(xclk, int, 0); +MODULE_PARM_DESC(xclk, "int: override accelerated engine clock"); +module_param(comp_sync, int, 0); +MODULE_PARM_DESC(comp_sync, + "Set composite sync signal to low (0) or high (1)"); +module_param(mode, charp, 0); +MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); +#ifdef CONFIG_MTRR +module_param(nomtrr, bool, 0); +MODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers"); +#endif diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c new file mode 100644 index 000000000000..c98f4a442134 --- /dev/null +++ b/drivers/video/aty/mach64_accel.c @@ -0,0 +1,433 @@ + +/* + * ATI Mach64 Hardware Acceleration + */ + +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <video/mach64.h> +#include "atyfb.h" + + /* + * Generic Mach64 routines + */ + +/* this is for DMA GUI engine! work in progress */ +typedef struct { + u32 frame_buf_offset; + u32 system_mem_addr; + u32 command; + u32 reserved; +} BM_DESCRIPTOR_ENTRY; + +#define LAST_DESCRIPTOR (1 << 31) +#define SYSTEM_TO_FRAME_BUFFER 0 + +static u32 rotation24bpp(u32 dx, u32 direction) +{ + u32 rotation; + if (direction & DST_X_LEFT_TO_RIGHT) { + rotation = (dx / 4) % 6; + } else { + rotation = ((dx + 2) / 4) % 6; + } + + return ((rotation << 8) | DST_24_ROTATION_ENABLE); +} + +void aty_reset_engine(const struct atyfb_par *par) +{ + /* reset engine */ + aty_st_le32(GEN_TEST_CNTL, + aty_ld_le32(GEN_TEST_CNTL, par) & ~GUI_ENGINE_ENABLE, par); + /* enable engine */ + aty_st_le32(GEN_TEST_CNTL, + aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE, par); + /* ensure engine is not locked up by clearing any FIFO or */ + /* HOST errors */ + aty_st_le32(BUS_CNTL, + aty_ld_le32(BUS_CNTL, par) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK, par); +} + +static void reset_GTC_3D_engine(const struct atyfb_par *par) +{ + aty_st_le32(SCALE_3D_CNTL, 0xc0, par); + mdelay(GTC_3D_RESET_DELAY); + aty_st_le32(SETUP_CNTL, 0x00, par); + mdelay(GTC_3D_RESET_DELAY); + aty_st_le32(SCALE_3D_CNTL, 0x00, par); + mdelay(GTC_3D_RESET_DELAY); +} + +void aty_init_engine(struct atyfb_par *par, struct fb_info *info) +{ + u32 pitch_value; + + /* determine modal information from global mode structure */ + pitch_value = info->var.xres_virtual; + + if (info->var.bits_per_pixel == 24) { + /* In 24 bpp, the engine is in 8 bpp - this requires that all */ + /* horizontal coordinates and widths must be adjusted */ + pitch_value *= 3; + } + + /* On GTC (RagePro), we need to reset the 3D engine before */ + if (M64_HAS(RESET_3D)) + reset_GTC_3D_engine(par); + + /* Reset engine, enable, and clear any engine errors */ + aty_reset_engine(par); + /* Ensure that vga page pointers are set to zero - the upper */ + /* page pointers are set to 1 to handle overflows in the */ + /* lower page */ + aty_st_le32(MEM_VGA_WP_SEL, 0x00010000, par); + aty_st_le32(MEM_VGA_RP_SEL, 0x00010000, par); + + /* ---- Setup standard engine context ---- */ + + /* All GUI registers here are FIFOed - therefore, wait for */ + /* the appropriate number of empty FIFO entries */ + wait_for_fifo(14, par); + + /* enable all registers to be loaded for context loads */ + aty_st_le32(CONTEXT_MASK, 0xFFFFFFFF, par); + + /* set destination pitch to modal pitch, set offset to zero */ + aty_st_le32(DST_OFF_PITCH, (pitch_value / 8) << 22, par); + + /* zero these registers (set them to a known state) */ + aty_st_le32(DST_Y_X, 0, par); + aty_st_le32(DST_HEIGHT, 0, par); + aty_st_le32(DST_BRES_ERR, 0, par); + aty_st_le32(DST_BRES_INC, 0, par); + aty_st_le32(DST_BRES_DEC, 0, par); + + /* set destination drawing attributes */ + aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | + DST_X_LEFT_TO_RIGHT, par); + + /* set source pitch to modal pitch, set offset to zero */ + aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, par); + + /* set these registers to a known state */ + aty_st_le32(SRC_Y_X, 0, par); + aty_st_le32(SRC_HEIGHT1_WIDTH1, 1, par); + aty_st_le32(SRC_Y_X_START, 0, par); + aty_st_le32(SRC_HEIGHT2_WIDTH2, 1, par); + + /* set source pixel retrieving attributes */ + aty_st_le32(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT, par); + + /* set host attributes */ + wait_for_fifo(13, par); + aty_st_le32(HOST_CNTL, 0, par); + + /* set pattern attributes */ + aty_st_le32(PAT_REG0, 0, par); + aty_st_le32(PAT_REG1, 0, par); + aty_st_le32(PAT_CNTL, 0, par); + + /* set scissors to modal size */ + aty_st_le32(SC_LEFT, 0, par); + aty_st_le32(SC_TOP, 0, par); + aty_st_le32(SC_BOTTOM, par->crtc.vyres - 1, par); + aty_st_le32(SC_RIGHT, pitch_value - 1, par); + + /* set background color to minimum value (usually BLACK) */ + aty_st_le32(DP_BKGD_CLR, 0, par); + + /* set foreground color to maximum value (usually WHITE) */ + aty_st_le32(DP_FRGD_CLR, 0xFFFFFFFF, par); + + /* set write mask to effect all pixel bits */ + aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par); + + /* set foreground mix to overpaint and background mix to */ + /* no-effect */ + aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, par); + + /* set primary source pixel channel to foreground color */ + /* register */ + aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, par); + + /* set compare functionality to false (no-effect on */ + /* destination) */ + wait_for_fifo(3, par); + aty_st_le32(CLR_CMP_CLR, 0, par); + aty_st_le32(CLR_CMP_MASK, 0xFFFFFFFF, par); + aty_st_le32(CLR_CMP_CNTL, 0, par); + + /* set pixel depth */ + wait_for_fifo(2, par); + aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par); + aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, par); + + wait_for_fifo(5, par); + aty_st_le32(SCALE_3D_CNTL, 0, par); + aty_st_le32(Z_CNTL, 0, par); + aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, par) & ~0x20, + par); + aty_st_le32(GUI_TRAJ_CNTL, 0x100023, par); + + /* insure engine is idle before leaving */ + wait_for_idle(par); +} + + /* + * Accelerated functions + */ + +static inline void draw_rect(s16 x, s16 y, u16 width, u16 height, + struct atyfb_par *par) +{ + /* perform rectangle fill */ + wait_for_fifo(2, par); + aty_st_le32(DST_Y_X, (x << 16) | y, par); + aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | height, par); + par->blitter_may_be_busy = 1; +} + +void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 dy = area->dy, sy = area->sy, direction = DST_LAST_PEL; + u32 sx = area->sx, dx = area->dx, width = area->width, rotation = 0; + + if (par->asleep) + return; + if (!area->width || !area->height) + return; + if (!par->accel_flags) { + if (par->blitter_may_be_busy) + wait_for_idle(par); + cfb_copyarea(info, area); + return; + } + + if (info->var.bits_per_pixel == 24) { + /* In 24 bpp, the engine is in 8 bpp - this requires that all */ + /* horizontal coordinates and widths must be adjusted */ + sx *= 3; + dx *= 3; + width *= 3; + } + + if (area->sy < area->dy) { + dy += area->height - 1; + sy += area->height - 1; + } else + direction |= DST_Y_TOP_TO_BOTTOM; + + if (sx < dx) { + dx += width - 1; + sx += width - 1; + } else + direction |= DST_X_LEFT_TO_RIGHT; + + if (info->var.bits_per_pixel == 24) { + rotation = rotation24bpp(dx, direction); + } + + wait_for_fifo(4, par); + aty_st_le32(DP_SRC, FRGD_SRC_BLIT, par); + aty_st_le32(SRC_Y_X, (sx << 16) | sy, par); + aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | area->height, par); + aty_st_le32(DST_CNTL, direction | rotation, par); + draw_rect(dx, dy, width, area->height, par); +} + +void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 color = rect->color, dx = rect->dx, width = rect->width, rotation = 0; + + if (par->asleep) + return; + if (!rect->width || !rect->height) + return; + if (!par->accel_flags) { + if (par->blitter_may_be_busy) + wait_for_idle(par); + cfb_fillrect(info, rect); + return; + } + + color |= (rect->color << 8); + color |= (rect->color << 16); + + if (info->var.bits_per_pixel == 24) { + /* In 24 bpp, the engine is in 8 bpp - this requires that all */ + /* horizontal coordinates and widths must be adjusted */ + dx *= 3; + width *= 3; + rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT); + } + + wait_for_fifo(3, par); + aty_st_le32(DP_FRGD_CLR, color, par); + aty_st_le32(DP_SRC, + BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE, + par); + aty_st_le32(DST_CNTL, + DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | + DST_X_LEFT_TO_RIGHT | rotation, par); + draw_rect(dx, rect->dy, width, rect->height, par); +} + +void atyfb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 src_bytes, dx = image->dx, dy = image->dy, width = image->width; + u32 pix_width_save, pix_width, host_cntl, rotation = 0, src, mix; + + if (par->asleep) + return; + if (!image->width || !image->height) + return; + if (!par->accel_flags || + (image->depth != 1 && info->var.bits_per_pixel != image->depth)) { + if (par->blitter_may_be_busy) + wait_for_idle(par); + + cfb_imageblit(info, image); + return; + } + + wait_for_idle(par); + pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par); + host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN; + + switch (image->depth) { + case 1: + pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK); + pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_1BPP); + break; + case 4: + pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK); + pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_4BPP); + break; + case 8: + pix_width &= ~HOST_MASK; + pix_width |= HOST_8BPP; + break; + case 15: + pix_width &= ~HOST_MASK; + pix_width |= HOST_15BPP; + break; + case 16: + pix_width &= ~HOST_MASK; + pix_width |= HOST_16BPP; + break; + case 24: + pix_width &= ~HOST_MASK; + pix_width |= HOST_24BPP; + break; + case 32: + pix_width &= ~HOST_MASK; + pix_width |= HOST_32BPP; + break; + } + + if (info->var.bits_per_pixel == 24) { + /* In 24 bpp, the engine is in 8 bpp - this requires that all */ + /* horizontal coordinates and widths must be adjusted */ + dx *= 3; + width *= 3; + + rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT); + + pix_width &= ~DST_MASK; + pix_width |= DST_8BPP; + + /* + * since Rage 3D IIc we have DP_HOST_TRIPLE_EN bit + * this hwaccelerated triple has an issue with not aligned data + */ + if (M64_HAS(HW_TRIPLE) && image->width % 8 == 0) + pix_width |= DP_HOST_TRIPLE_EN; + } + + if (image->depth == 1) { + u32 fg, bg; + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + fg = ((u32*)(info->pseudo_palette))[image->fg_color]; + bg = ((u32*)(info->pseudo_palette))[image->bg_color]; + } else { + fg = image->fg_color; + bg = image->bg_color; + } + + wait_for_fifo(2, par); + aty_st_le32(DP_BKGD_CLR, bg, par); + aty_st_le32(DP_FRGD_CLR, fg, par); + src = MONO_SRC_HOST | FRGD_SRC_FRGD_CLR | BKGD_SRC_BKGD_CLR; + mix = FRGD_MIX_S | BKGD_MIX_S; + } else { + src = MONO_SRC_ONE | FRGD_SRC_HOST; + mix = FRGD_MIX_D_XOR_S | BKGD_MIX_D; + } + + wait_for_fifo(6, par); + aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par); + aty_st_le32(DP_PIX_WIDTH, pix_width, par); + aty_st_le32(DP_MIX, mix, par); + aty_st_le32(DP_SRC, src, par); + aty_st_le32(HOST_CNTL, host_cntl, par); + aty_st_le32(DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT | rotation, par); + + draw_rect(dx, dy, width, image->height, par); + src_bytes = (((image->width * image->depth) + 7) / 8) * image->height; + + /* manual triple each pixel */ + if (info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) { + int inbit, outbit, mult24, byte_id_in_dword, width; + u8 *pbitmapin = (u8*)image->data, *pbitmapout; + u32 hostdword; + + for (width = image->width, inbit = 7, mult24 = 0; src_bytes; ) { + for (hostdword = 0, pbitmapout = (u8*)&hostdword, byte_id_in_dword = 0; + byte_id_in_dword < 4 && src_bytes; + byte_id_in_dword++, pbitmapout++) { + for (outbit = 7; outbit >= 0; outbit--) { + *pbitmapout |= (((*pbitmapin >> inbit) & 1) << outbit); + mult24++; + /* next bit */ + if (mult24 == 3) { + mult24 = 0; + inbit--; + width--; + } + + /* next byte */ + if (inbit < 0 || width == 0) { + src_bytes--; + pbitmapin++; + inbit = 7; + + if (width == 0) { + width = image->width; + outbit = 0; + } + } + } + } + wait_for_fifo(1, par); + aty_st_le32(HOST_DATA0, hostdword, par); + } + } else { + u32 *pbitmap, dwords = (src_bytes + 3) / 4; + for (pbitmap = (u32*)(image->data); dwords; dwords--, pbitmap++) { + wait_for_fifo(1, par); + aty_st_le32(HOST_DATA0, le32_to_cpup(pbitmap), par); + } + } + + wait_for_idle(par); + + /* restore pix_width */ + wait_for_fifo(1, par); + aty_st_le32(DP_PIX_WIDTH, pix_width_save, par); +} diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c new file mode 100644 index 000000000000..9bdb2aab01aa --- /dev/null +++ b/drivers/video/aty/mach64_ct.c @@ -0,0 +1,619 @@ + +/* + * ATI Mach64 CT/VT/GT/LT Support + */ + +#include <linux/fb.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <video/mach64.h> +#include "atyfb.h" + +#undef DEBUG + +static int aty_valid_pll_ct (const struct fb_info *info, u32 vclk_per, struct pll_ct *pll); +static int aty_dsp_gt (const struct fb_info *info, u32 bpp, struct pll_ct *pll); +static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll); +static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll); + +u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par) +{ + u8 res; + + /* write addr byte */ + aty_st_8(CLOCK_CNTL_ADDR, (offset << 2) & PLL_ADDR, par); + /* read the register value */ + res = aty_ld_8(CLOCK_CNTL_DATA, par); + return res; +} + +void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par) +{ + /* write addr byte */ + aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) | PLL_WR_EN, par); + /* write the register value */ + aty_st_8(CLOCK_CNTL_DATA, val & PLL_DATA, par); + aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) & ~PLL_WR_EN, par); +} + +/* + * by Daniel Mantione + * <daniel.mantione@freepascal.org> + * + * + * ATI Mach64 CT clock synthesis description. + * + * All clocks on the Mach64 can be calculated using the same principle: + * + * XTALIN * x * FB_DIV + * CLK = ---------------------- + * PLL_REF_DIV * POST_DIV + * + * XTALIN is a fixed speed clock. Common speeds are 14.31 MHz and 29.50 MHz. + * PLL_REF_DIV can be set by the user, but is the same for all clocks. + * FB_DIV can be set by the user for each clock individually, it should be set + * between 128 and 255, the chip will generate a bad clock signal for too low + * values. + * x depends on the type of clock; usually it is 2, but for the MCLK it can also + * be set to 4. + * POST_DIV can be set by the user for each clock individually, Possible values + * are 1,2,4,8 and for some clocks other values are available too. + * CLK is of course the clock speed that is generated. + * + * The Mach64 has these clocks: + * + * MCLK The clock rate of the chip + * XCLK The clock rate of the on-chip memory + * VCLK0 First pixel clock of first CRT controller + * VCLK1 Second pixel clock of first CRT controller + * VCLK2 Third pixel clock of first CRT controller + * VCLK3 Fourth pixel clock of first CRT controller + * VCLK Selected pixel clock, one of VCLK0, VCLK1, VCLK2, VCLK3 + * V2CLK Pixel clock of the second CRT controller. + * SCLK Multi-purpose clock + * + * - MCLK and XCLK use the same FB_DIV + * - VCLK0 .. VCLK3 use the same FB_DIV + * - V2CLK is needed when the second CRTC is used (can be used for dualhead); + * i.e. CRT monitor connected to laptop has different resolution than built + * in LCD monitor. + * - SCLK is not available on all cards; it is know to exist on the Rage LT-PRO, + * Rage XL and Rage Mobility. It is know not to exist on the Mach64 VT. + * - V2CLK is not available on all cards, most likely only the Rage LT-PRO, + * the Rage XL and the Rage Mobility + * + * SCLK can be used to: + * - Clock the chip instead of MCLK + * - Replace XTALIN with a user defined frequency + * - Generate the pixel clock for the LCD monitor (instead of VCLK) + */ + + /* + * It can be quite hard to calculate XCLK and MCLK if they don't run at the + * same frequency. Luckily, until now all cards that need asynchrone clock + * speeds seem to have SCLK. + * So this driver uses SCLK to clock the chip and XCLK to clock the memory. + */ + +/* ------------------------------------------------------------------------- */ + +/* + * PLL programming (Mach64 CT family) + * + * + * This procedure sets the display fifo. The display fifo is a buffer that + * contains data read from the video memory that waits to be processed by + * the CRT controller. + * + * On the more modern Mach64 variants, the chip doesn't calculate the + * interval after which the display fifo has to be reloaded from memory + * automatically, the driver has to do it instead. + */ + +#define Maximum_DSP_PRECISION 7 +static u8 postdividers[] = {1,2,4,8,3}; + +static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll) +{ + u32 dsp_off, dsp_on, dsp_xclks; + u32 multiplier, divider, ras_multiplier, ras_divider, tmp; + u8 vshift, xshift; + s8 dsp_precision; + + multiplier = ((u32)pll->mclk_fb_div) * pll->vclk_post_div_real; + divider = ((u32)pll->vclk_fb_div) * pll->xclk_ref_div; + + ras_multiplier = pll->xclkmaxrasdelay; + ras_divider = 1; + + if (bpp>=8) + divider = divider * (bpp >> 2); + + vshift = (6 - 2) - pll->xclk_post_div; /* FIFO is 64 bits wide in accelerator mode ... */ + + if (bpp == 0) + vshift--; /* ... but only 32 bits in VGA mode. */ + +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (pll->xres != 0) { + struct atyfb_par *par = (struct atyfb_par *) info->par; + + multiplier = multiplier * par->lcd_width; + divider = divider * pll->xres & ~7; + + ras_multiplier = ras_multiplier * par->lcd_width; + ras_divider = ras_divider * pll->xres & ~7; + } +#endif + /* If we don't do this, 32 bits for multiplier & divider won't be + enough in certain situations! */ + while (((multiplier | divider) & 1) == 0) { + multiplier = multiplier >> 1; + divider = divider >> 1; + } + + /* Determine DSP precision first */ + tmp = ((multiplier * pll->fifo_size) << vshift) / divider; + + for (dsp_precision = -5; tmp; dsp_precision++) + tmp >>= 1; + if (dsp_precision < 0) + dsp_precision = 0; + else if (dsp_precision > Maximum_DSP_PRECISION) + dsp_precision = Maximum_DSP_PRECISION; + + xshift = 6 - dsp_precision; + vshift += xshift; + + /* Move on to dsp_off */ + dsp_off = ((multiplier * (pll->fifo_size - 1)) << vshift) / divider - + (1 << (vshift - xshift)); + +/* if (bpp == 0) + dsp_on = ((multiplier * 20 << vshift) + divider) / divider; + else */ + { + dsp_on = ((multiplier << vshift) + divider) / divider; + tmp = ((ras_multiplier << xshift) + ras_divider) / ras_divider; + if (dsp_on < tmp) + dsp_on = tmp; + dsp_on = dsp_on + (tmp * 2) + (pll->xclkpagefaultdelay << xshift); + } + + /* Calculate rounding factor and apply it to dsp_on */ + tmp = ((1 << (Maximum_DSP_PRECISION - dsp_precision)) - 1) >> 1; + dsp_on = ((dsp_on + tmp) / (tmp + 1)) * (tmp + 1); + + if (dsp_on >= ((dsp_off / (tmp + 1)) * (tmp + 1))) { + dsp_on = dsp_off - (multiplier << vshift) / divider; + dsp_on = (dsp_on / (tmp + 1)) * (tmp + 1); + } + + /* Last but not least: dsp_xclks */ + dsp_xclks = ((multiplier << (vshift + 5)) + divider) / divider; + + /* Get register values. */ + pll->dsp_on_off = (dsp_on << 16) + dsp_off; + pll->dsp_config = (dsp_precision << 20) | (pll->dsp_loop_latency << 16) | dsp_xclks; +#ifdef DEBUG + printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n", + __FUNCTION__, pll->dsp_config, pll->dsp_on_off); +#endif + return 0; +} + +static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll_ct *pll) +{ + u32 q; + struct atyfb_par *par = (struct atyfb_par *) info->par; +#ifdef DEBUG + int pllvclk; +#endif + + /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */ + q = par->ref_clk_per * pll->pll_ref_div * 4 / vclk_per; + if (q < 16*8 || q > 255*8) { + printk(KERN_CRIT "atyfb: vclk out of range\n"); + return -EINVAL; + } else { + pll->vclk_post_div = (q < 128*8); + pll->vclk_post_div += (q < 64*8); + pll->vclk_post_div += (q < 32*8); + } + pll->vclk_post_div_real = postdividers[pll->vclk_post_div]; + // pll->vclk_post_div <<= 6; + pll->vclk_fb_div = q * pll->vclk_post_div_real / 8; +#ifdef DEBUG + pllvclk = (1000000 * 2 * pll->vclk_fb_div) / + (par->ref_clk_per * pll->pll_ref_div); + printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n", + __FUNCTION__, pllvclk, pllvclk / pll->vclk_post_div_real); +#endif + pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */ + return 0; +} + +static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + int err; + + if ((err = aty_valid_pll_ct(info, vclk_per, &pll->ct))) + return err; + if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct))) + return err; + /*aty_calc_pll_ct(info, &pll->ct);*/ + return 0; +} + +static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 ret; + ret = par->ref_clk_per * pll->ct.pll_ref_div * pll->ct.vclk_post_div_real / pll->ct.vclk_fb_div / 2; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if(pll->ct.xres > 0) { + ret *= par->lcd_width; + ret /= pll->ct.xres; + } +#endif +#ifdef DEBUG + printk("atyfb(%s): calculated 0x%08X(%i)\n", __FUNCTION__, ret, ret); +#endif + return ret; +} + +void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 crtc_gen_cntl, lcd_gen_cntrl; + u8 tmp, tmp2; + + lcd_gen_cntrl = 0; +#ifdef DEBUG + printk("atyfb(%s): about to program:\n" + "pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n", + __FUNCTION__, + pll->ct.pll_ext_cntl, pll->ct.pll_gen_cntl, pll->ct.pll_vclk_cntl); + + printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n", + __FUNCTION__, + par->clk_wr_offset, pll->ct.vclk_fb_div, + pll->ct.pll_ref_div, pll->ct.vclk_post_div, pll->ct.vclk_post_div_real); +#endif +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table != 0) { + /* turn off LCD */ + lcd_gen_cntrl = aty_ld_lcd(LCD_GEN_CNTL, par); + aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl & ~LCD_ON, par); + } +#endif + aty_st_8(CLOCK_CNTL, par->clk_wr_offset | CLOCK_STROBE, par); + + /* Temporarily switch to accelerator mode */ + crtc_gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par); + if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) + aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN, par); + + /* Reset VCLK generator */ + aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par); + + /* Set post-divider */ + tmp2 = par->clk_wr_offset << 1; + tmp = aty_ld_pll_ct(VCLK_POST_DIV, par); + tmp &= ~(0x03U << tmp2); + tmp |= ((pll->ct.vclk_post_div & 0x03U) << tmp2); + aty_st_pll_ct(VCLK_POST_DIV, tmp, par); + + /* Set extended post-divider */ + tmp = aty_ld_pll_ct(PLL_EXT_CNTL, par); + tmp &= ~(0x10U << par->clk_wr_offset); + tmp &= 0xF0U; + tmp |= pll->ct.pll_ext_cntl; + aty_st_pll_ct(PLL_EXT_CNTL, tmp, par); + + /* Set feedback divider */ + tmp = VCLK0_FB_DIV + par->clk_wr_offset; + aty_st_pll_ct(tmp, (pll->ct.vclk_fb_div & 0xFFU), par); + + aty_st_pll_ct(PLL_GEN_CNTL, (pll->ct.pll_gen_cntl & (~(PLL_OVERRIDE | PLL_MCLK_RST))) | OSC_EN, par); + + /* End VCLK generator reset */ + aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl & ~(PLL_VCLK_RST), par); + mdelay(5); + + aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par); + aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par); + mdelay(1); + + /* Restore mode register */ + if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) + aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl, par); + + if (M64_HAS(GTB_DSP)) { + u8 dll_cntl; + + if (M64_HAS(XL_DLL)) + dll_cntl = 0x80; + else if (par->ram_type >= SDRAM) + dll_cntl = 0xa6; + else + dll_cntl = 0xa0; + aty_st_pll_ct(DLL_CNTL, dll_cntl, par); + aty_st_pll_ct(VFC_CNTL, 0x1b, par); + aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, par); + aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, par); + + mdelay(10); + aty_st_pll_ct(DLL_CNTL, dll_cntl, par); + mdelay(10); + aty_st_pll_ct(DLL_CNTL, dll_cntl | 0x40, par); + mdelay(10); + aty_st_pll_ct(DLL_CNTL, dll_cntl & ~0x40, par); + } +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table != 0) { + /* restore LCD */ + aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl, par); + } +#endif +} + +static void __init aty_get_pll_ct(const struct fb_info *info, + union aty_pll *pll) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u8 tmp, clock; + + clock = aty_ld_8(CLOCK_CNTL, par) & 0x03U; + tmp = clock << 1; + pll->ct.vclk_post_div = (aty_ld_pll_ct(VCLK_POST_DIV, par) >> tmp) & 0x03U; + + pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par) & 0x0FU; + pll->ct.vclk_fb_div = aty_ld_pll_ct(VCLK0_FB_DIV + clock, par) & 0xFFU; + pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par); + pll->ct.mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par); + + pll->ct.pll_gen_cntl = aty_ld_pll_ct(PLL_GEN_CNTL, par); + pll->ct.pll_vclk_cntl = aty_ld_pll_ct(PLL_VCLK_CNTL, par); + + if (M64_HAS(GTB_DSP)) { + pll->ct.dsp_config = aty_ld_le32(DSP_CONFIG, par); + pll->ct.dsp_on_off = aty_ld_le32(DSP_ON_OFF, par); + } +} + +static int __init aty_init_pll_ct(const struct fb_info *info, + union aty_pll *pll) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u8 mpost_div, xpost_div, sclk_post_div_real, sclk_fb_div, spll_cntl2; + u32 q, i, memcntl, trp; + u32 dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off; +#ifdef DEBUG + int pllmclk, pllsclk; +#endif + pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par); + pll->ct.xclk_post_div = pll->ct.pll_ext_cntl & 0x07; + pll->ct.xclk_ref_div = 1; + switch (pll->ct.xclk_post_div) { + case 0: case 1: case 2: case 3: + break; + + case 4: + pll->ct.xclk_ref_div = 3; + pll->ct.xclk_post_div = 0; + break; + + default: + printk(KERN_CRIT "atyfb: Unsupported xclk source: %d.\n", pll->ct.xclk_post_div); + return -EINVAL; + } + pll->ct.mclk_fb_mult = 2; + if(pll->ct.pll_ext_cntl & PLL_MFB_TIMES_4_2B) { + pll->ct.mclk_fb_mult = 4; + pll->ct.xclk_post_div -= 1; + } + +#ifdef DEBUG + printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n", + __FUNCTION__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div); +#endif + + memcntl = aty_ld_le32(MEM_CNTL, par); + trp = (memcntl & 0x300) >> 8; + + pll->ct.xclkpagefaultdelay = ((memcntl & 0xc00) >> 10) + ((memcntl & 0x1000) >> 12) + trp + 2; + pll->ct.xclkmaxrasdelay = ((memcntl & 0x70000) >> 16) + trp + 2; + + if (M64_HAS(FIFO_32)) { + pll->ct.fifo_size = 32; + } else { + pll->ct.fifo_size = 24; + pll->ct.xclkpagefaultdelay += 2; + pll->ct.xclkmaxrasdelay += 3; + } + + switch (par->ram_type) { + case DRAM: + if (info->fix.smem_len<=ONE_MB) { + pll->ct.dsp_loop_latency = 10; + } else { + pll->ct.dsp_loop_latency = 8; + pll->ct.xclkpagefaultdelay += 2; + } + break; + case EDO: + case PSEUDO_EDO: + if (info->fix.smem_len<=ONE_MB) { + pll->ct.dsp_loop_latency = 9; + } else { + pll->ct.dsp_loop_latency = 8; + pll->ct.xclkpagefaultdelay += 1; + } + break; + case SDRAM: + if (info->fix.smem_len<=ONE_MB) { + pll->ct.dsp_loop_latency = 11; + } else { + pll->ct.dsp_loop_latency = 10; + pll->ct.xclkpagefaultdelay += 1; + } + break; + case SGRAM: + pll->ct.dsp_loop_latency = 8; + pll->ct.xclkpagefaultdelay += 3; + break; + default: + pll->ct.dsp_loop_latency = 11; + pll->ct.xclkpagefaultdelay += 3; + break; + } + + if (pll->ct.xclkmaxrasdelay <= pll->ct.xclkpagefaultdelay) + pll->ct.xclkmaxrasdelay = pll->ct.xclkpagefaultdelay + 1; + + /* Allow BIOS to override */ + dsp_config = aty_ld_le32(DSP_CONFIG, par); + dsp_on_off = aty_ld_le32(DSP_ON_OFF, par); + vga_dsp_config = aty_ld_le32(VGA_DSP_CONFIG, par); + vga_dsp_on_off = aty_ld_le32(VGA_DSP_ON_OFF, par); + + if (dsp_config) + pll->ct.dsp_loop_latency = (dsp_config & DSP_LOOP_LATENCY) >> 16; +#if 0 + FIXME: is it relevant for us? + if ((!dsp_on_off && !M64_HAS(RESET_3D)) || + ((dsp_on_off == vga_dsp_on_off) && + (!dsp_config || !((dsp_config ^ vga_dsp_config) & DSP_XCLKS_PER_QW)))) { + vga_dsp_on_off &= VGA_DSP_OFF; + vga_dsp_config &= VGA_DSP_XCLKS_PER_QW; + if (ATIDivide(vga_dsp_on_off, vga_dsp_config, 5, 1) > 24) + pll->ct.fifo_size = 32; + else + pll->ct.fifo_size = 24; + } +#endif + /* Exit if the user does not want us to tamper with the clock + rates of her chip. */ + if (par->mclk_per == 0) { + u8 mclk_fb_div, pll_ext_cntl; + pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par); + pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par); + pll->ct.xclk_post_div_real = postdividers[pll_ext_cntl & 0x07]; + mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par); + if (pll_ext_cntl & PLL_MFB_TIMES_4_2B) + mclk_fb_div <<= 1; + pll->ct.mclk_fb_div = mclk_fb_div; + return 0; + } + + pll->ct.pll_ref_div = par->pll_per * 2 * 255 / par->ref_clk_per; + + /* FIXME: use the VTB/GTB /3 post divider if it's better suited */ + q = par->ref_clk_per * pll->ct.pll_ref_div * 8 / + (pll->ct.mclk_fb_mult * par->xclk_per); + + if (q < 16*8 || q > 255*8) { + printk(KERN_CRIT "atxfb: xclk out of range\n"); + return -EINVAL; + } else { + xpost_div = (q < 128*8); + xpost_div += (q < 64*8); + xpost_div += (q < 32*8); + } + pll->ct.xclk_post_div_real = postdividers[xpost_div]; + pll->ct.mclk_fb_div = q * pll->ct.xclk_post_div_real / 8; + +#ifdef DEBUG + pllmclk = (1000000 * pll->ct.mclk_fb_mult * pll->ct.mclk_fb_div) / + (par->ref_clk_per * pll->ct.pll_ref_div); + printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n", + __FUNCTION__, pllmclk, pllmclk / pll->ct.xclk_post_div_real); +#endif + + if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM)) + pll->ct.pll_gen_cntl = OSC_EN; + else + pll->ct.pll_gen_cntl = OSC_EN | DLL_PWDN /* | FORCE_DCLK_TRI_STATE */; + + if (M64_HAS(MAGIC_POSTDIV)) + pll->ct.pll_ext_cntl = 0; + else + pll->ct.pll_ext_cntl = xpost_div; + + if (pll->ct.mclk_fb_mult == 4) + pll->ct.pll_ext_cntl |= PLL_MFB_TIMES_4_2B; + + if (par->mclk_per == par->xclk_per) { + pll->ct.pll_gen_cntl |= (xpost_div << 4); /* mclk == xclk */ + } else { + /* + * The chip clock is not equal to the memory clock. + * Therefore we will use sclk to clock the chip. + */ + pll->ct.pll_gen_cntl |= (6 << 4); /* mclk == sclk */ + + q = par->ref_clk_per * pll->ct.pll_ref_div * 4 / par->mclk_per; + if (q < 16*8 || q > 255*8) { + printk(KERN_CRIT "atyfb: mclk out of range\n"); + return -EINVAL; + } else { + mpost_div = (q < 128*8); + mpost_div += (q < 64*8); + mpost_div += (q < 32*8); + } + sclk_post_div_real = postdividers[mpost_div]; + sclk_fb_div = q * sclk_post_div_real / 8; + spll_cntl2 = mpost_div << 4; +#ifdef DEBUG + pllsclk = (1000000 * 2 * sclk_fb_div) / + (par->ref_clk_per * pll->ct.pll_ref_div); + printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n", + __FUNCTION__, pllsclk, pllsclk / sclk_post_div_real); +#endif + /* + * This disables the sclk, crashes the computer as reported: + * aty_st_pll_ct(SPLL_CNTL2, 3, info); + * + * So it seems the sclk must be enabled before it is used; + * so PLL_GEN_CNTL must be programmed *after* the sclk. + */ + aty_st_pll_ct(SCLK_FB_DIV, sclk_fb_div, par); + aty_st_pll_ct(SPLL_CNTL2, spll_cntl2, par); + /* + * The sclk has been started. However, I believe the first clock + * ticks it generates are not very stable. Hope this primitive loop + * helps for Rage Mobilities that sometimes crash when + * we switch to sclk. (Daniel Mantione, 13-05-2003) + */ + for (i=0;i<=0x1ffff;i++); + } + + aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par); + aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par); + aty_st_pll_ct(MCLK_FB_DIV, pll->ct.mclk_fb_div, par); + aty_st_pll_ct(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par); + /* Disable the extra precision pixel clock controls since we do not use them. */ + aty_st_pll_ct(EXT_VPLL_CNTL, aty_ld_pll_ct(EXT_VPLL_CNTL, par) & + ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC), par); + + return 0; +} + +static int dummy(void) +{ + return 0; +} + +const struct aty_dac_ops aty_dac_ct = { + .set_dac = (void *) dummy, +}; + +const struct aty_pll_ops aty_pll_ct = { + .var_to_pll = aty_var_to_pll_ct, + .pll_to_var = aty_pll_to_var_ct, + .set_pll = aty_set_pll_ct, + .get_pll = aty_get_pll_ct, + .init_pll = aty_init_pll_ct +}; diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c new file mode 100644 index 000000000000..ad8b7496f853 --- /dev/null +++ b/drivers/video/aty/mach64_cursor.c @@ -0,0 +1,226 @@ +/* + * ATI Mach64 CT/VT/GT/LT Cursor Support + */ + +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/string.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#ifdef __sparc__ +#include <asm/pbm.h> +#include <asm/fbio.h> +#endif + +#include <video/mach64.h> +#include "atyfb.h" + +/* + * The hardware cursor definition requires 2 bits per pixel. The + * Cursor size reguardless of the visible cursor size is 64 pixels + * by 64 lines. The total memory required to define the cursor is + * 16 bytes / line for 64 lines or 1024 bytes of data. The data + * must be in a contigiuos format. The 2 bit cursor code values are + * as follows: + * + * 00 - pixel colour = CURSOR_CLR_0 + * 01 - pixel colour = CURSOR_CLR_1 + * 10 - pixel colour = transparent (current display pixel) + * 11 - pixel colour = 1's complement of current display pixel + * + * Cursor Offset 64 pixels Actual Displayed Area + * \_________________________/ + * | | | | + * |<--------------->| | | + * | CURS_HORZ_OFFSET| | | + * | |_______| | 64 Lines + * | ^ | | + * | | | | + * | CURS_VERT_OFFSET| | + * | | | | + * |____________________|____| | + * + * + * The Screen position of the top left corner of the displayed + * cursor is specificed by CURS_HORZ_VERT_POSN. Care must be taken + * when the cursor hot spot is not the top left corner and the + * physical cursor position becomes negative. It will be be displayed + * if either the horizontal or vertical cursor position is negative + * + * If x becomes negative the cursor manager must adjust the CURS_HORZ_OFFSET + * to a larger number and saturate CUR_HORZ_POSN to zero. + * + * if Y becomes negative, CUR_VERT_OFFSET must be adjusted to a larger number, + * CUR_OFFSET must be adjusted to a point to the appropraite line in the cursor + * definitation and CUR_VERT_POSN must be saturated to zero. + */ + + /* + * Hardware Cursor support. + */ +static const u8 cursor_bits_lookup[16] = { + 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, + 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 +}; + +static const u8 cursor_mask_lookup[16] = { + 0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02, + 0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00 +}; + +static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u16 xoff, yoff; + int x, y, h; + +#ifdef __sparc__ + if (par->mmaped) + return -EPERM; +#endif + if (par->asleep) + return -EPERM; + + /* Hide cursor */ + wait_for_fifo(1, par); + aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) & ~HWCURSOR_ENABLE, par); + + /* set position */ + if (cursor->set & FB_CUR_SETPOS) { + x = cursor->image.dx - cursor->hot.x - info->var.xoffset; + if (x < 0) { + xoff = -x; + x = 0; + } else { + xoff = 0; + } + + y = cursor->image.dy - cursor->hot.y - info->var.yoffset; + if (y < 0) { + yoff = -y; + y = 0; + } else { + yoff = 0; + } + + h = cursor->image.height; + + /* + * In doublescan mode, the cursor location + * and heigh also needs to be doubled. + */ + if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN) { + y<<=1; + h<<=1; + } + wait_for_fifo(4, par); + aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1), par); + aty_st_le32(CUR_HORZ_VERT_OFF, + ((u32) (64 - h + yoff) << 16) | xoff, par); + aty_st_le32(CUR_HORZ_VERT_POSN, ((u32) y << 16) | x, par); + } + + /* Set color map */ + if (cursor->set & FB_CUR_SETCMAP) { + u32 fg_idx, bg_idx, fg, bg; + + fg_idx = cursor->image.fg_color; + bg_idx = cursor->image.bg_color; + + fg = (info->cmap.red[fg_idx] << 24) | + (info->cmap.green[fg_idx] << 16) | + (info->cmap.blue[fg_idx] << 8) | 15; + + bg = (info->cmap.red[bg_idx] << 24) | + (info->cmap.green[bg_idx] << 16) | + (info->cmap.blue[bg_idx] << 8); + + wait_for_fifo(2, par); + aty_st_le32(CUR_CLR0, bg, par); + aty_st_le32(CUR_CLR1, fg, par); + } + + if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { + u8 *src = (u8 *)cursor->image.data; + u8 *msk = (u8 *)cursor->mask; + u8 __iomem *dst = (u8 __iomem *)info->sprite.addr; + unsigned int width = (cursor->image.width + 7) >> 3; + unsigned int height = cursor->image.height; + unsigned int align = info->sprite.scan_align; + + unsigned int i, j, offset; + u8 m, b; + + // Clear cursor image with 1010101010... + fb_memset(dst, 0xaa, 1024); + + offset = align - width*2; + + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + b = *src++; + m = *msk++; + switch (cursor->rop) { + case ROP_XOR: + // Upper 4 bits of mask data + fb_writeb(cursor_mask_lookup[m >> 4 ] | + cursor_bits_lookup[(b ^ m) >> 4], dst++); + // Lower 4 bits of mask + fb_writeb(cursor_mask_lookup[m & 0x0f ] | + cursor_bits_lookup[(b ^ m) & 0x0f], dst++); + break; + case ROP_COPY: + // Upper 4 bits of mask data + fb_writeb(cursor_mask_lookup[m >> 4 ] | + cursor_bits_lookup[(b & m) >> 4], dst++); + // Lower 4 bits of mask + fb_writeb(cursor_mask_lookup[m & 0x0f ] | + cursor_bits_lookup[(b & m) & 0x0f], dst++); + break; + } + } + dst += offset; + } + } + + if (cursor->enable) { + wait_for_fifo(1, par); + aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) + | HWCURSOR_ENABLE, par); + } + return 0; +} + +int __init aty_init_cursor(struct fb_info *info) +{ + unsigned long addr; + + info->fix.smem_len -= PAGE_SIZE; + +#ifdef __sparc__ + addr = (unsigned long) info->screen_base - 0x800000 + info->fix.smem_len; + info->sprite.addr = (u8 *) addr; +#else +#ifdef __BIG_ENDIAN + addr = info->fix.smem_start - 0x800000 + info->fix.smem_len; + info->sprite.addr = (u8 *) ioremap(addr, 1024); +#else + addr = (unsigned long) info->screen_base + info->fix.smem_len; + info->sprite.addr = (u8 *) addr; +#endif +#endif + if (!info->sprite.addr) + return -ENXIO; + info->sprite.size = PAGE_SIZE; + info->sprite.scan_align = 16; /* Scratch pad 64 bytes wide */ + info->sprite.buf_align = 16; /* and 64 lines tall. */ + info->sprite.flags = FB_PIXMAP_IO; + + info->fbops->fb_cursor = atyfb_cursor; + + return 0; +} + diff --git a/drivers/video/aty/mach64_gx.c b/drivers/video/aty/mach64_gx.c new file mode 100644 index 000000000000..01fdff79483b --- /dev/null +++ b/drivers/video/aty/mach64_gx.c @@ -0,0 +1,912 @@ + +/* + * ATI Mach64 GX Support + */ + +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/sched.h> + +#include <asm/io.h> + +#include <video/mach64.h> +#include "atyfb.h" + +/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */ + +#define REF_FREQ_2595 1432 /* 14.33 MHz (exact 14.31818) */ +#define REF_DIV_2595 46 /* really 43 on ICS 2595 !!! */ + /* ohne Prescaler */ +#define MAX_FREQ_2595 15938 /* 159.38 MHz (really 170.486) */ +#define MIN_FREQ_2595 8000 /* 80.00 MHz ( 85.565) */ + /* mit Prescaler 2, 4, 8 */ +#define ABS_MIN_FREQ_2595 1000 /* 10.00 MHz (really 10.697) */ +#define N_ADJ_2595 257 + +#define STOP_BITS_2595 0x1800 + + +#define MIN_N_408 2 + +#define MIN_N_1703 6 + +#define MIN_M 2 +#define MAX_M 30 +#define MIN_N 35 +#define MAX_N 255-8 + + + /* + * Support Functions + */ + +static void aty_dac_waste4(const struct atyfb_par *par) +{ + (void) aty_ld_8(DAC_REGS, par); + + (void) aty_ld_8(DAC_REGS + 2, par); + (void) aty_ld_8(DAC_REGS + 2, par); + (void) aty_ld_8(DAC_REGS + 2, par); + (void) aty_ld_8(DAC_REGS + 2, par); +} + +static void aty_StrobeClock(const struct atyfb_par *par) +{ + u8 tmp; + + udelay(26); + + tmp = aty_ld_8(CLOCK_CNTL, par); + aty_st_8(CLOCK_CNTL + par->clk_wr_offset, tmp | CLOCK_STROBE, par); + return; +} + + + /* + * IBM RGB514 DAC and Clock Chip + */ + +static void aty_st_514(int offset, u8 val, const struct atyfb_par *par) +{ + aty_st_8(DAC_CNTL, 1, par); + /* right addr byte */ + aty_st_8(DAC_W_INDEX, offset & 0xff, par); + /* left addr byte */ + aty_st_8(DAC_DATA, (offset >> 8) & 0xff, par); + aty_st_8(DAC_MASK, val, par); + aty_st_8(DAC_CNTL, 0, par); +} + +static int aty_set_dac_514(const struct fb_info *info, + const union aty_pll *pll, u32 bpp, u32 accel) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + static struct { + u8 pixel_dly; + u8 misc2_cntl; + u8 pixel_rep; + u8 pixel_cntl_index; + u8 pixel_cntl_v1; + } tab[3] = { + { + 0, 0x41, 0x03, 0x71, 0x45}, /* 8 bpp */ + { + 0, 0x45, 0x04, 0x0c, 0x01}, /* 555 */ + { + 0, 0x45, 0x06, 0x0e, 0x00}, /* XRGB */ + }; + int i; + + switch (bpp) { + case 8: + default: + i = 0; + break; + case 16: + i = 1; + break; + case 32: + i = 2; + break; + } + aty_st_514(0x90, 0x00, par); /* VRAM Mask Low */ + aty_st_514(0x04, tab[i].pixel_dly, par); /* Horizontal Sync Control */ + aty_st_514(0x05, 0x00, par); /* Power Management */ + aty_st_514(0x02, 0x01, par); /* Misc Clock Control */ + aty_st_514(0x71, tab[i].misc2_cntl, par); /* Misc Control 2 */ + aty_st_514(0x0a, tab[i].pixel_rep, par); /* Pixel Format */ + aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, par); + /* Misc Control 2 / 16 BPP Control / 32 BPP Control */ + return 0; +} + +static int aty_var_to_pll_514(const struct fb_info *info, u32 vclk_per, + u32 bpp, union aty_pll *pll) +{ + /* + * FIXME: use real calculations instead of using fixed values from the old + * driver + */ + static struct { + u32 limit; /* pixlock rounding limit (arbitrary) */ + u8 m; /* (df<<6) | vco_div_count */ + u8 n; /* ref_div_count */ + } RGB514_clocks[7] = { + { + 8000, (3 << 6) | 20, 9}, /* 7395 ps / 135.2273 MHz */ + { + 10000, (1 << 6) | 19, 3}, /* 9977 ps / 100.2273 MHz */ + { + 13000, (1 << 6) | 2, 3}, /* 12509 ps / 79.9432 MHz */ + { + 14000, (2 << 6) | 8, 7}, /* 13394 ps / 74.6591 MHz */ + { + 16000, (1 << 6) | 44, 6}, /* 15378 ps / 65.0284 MHz */ + { + 25000, (1 << 6) | 15, 5}, /* 17460 ps / 57.2727 MHz */ + { + 50000, (0 << 6) | 53, 7}, /* 33145 ps / 30.1705 MHz */ + }; + int i; + + for (i = 0; i < sizeof(RGB514_clocks) / sizeof(*RGB514_clocks); + i++) + if (vclk_per <= RGB514_clocks[i].limit) { + pll->ibm514.m = RGB514_clocks[i].m; + pll->ibm514.n = RGB514_clocks[i].n; + return 0; + } + return -EINVAL; +} + +static u32 aty_pll_514_to_var(const struct fb_info *info, + const union aty_pll *pll) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u8 df, vco_div_count, ref_div_count; + + df = pll->ibm514.m >> 6; + vco_div_count = pll->ibm514.m & 0x3f; + ref_div_count = pll->ibm514.n; + + return ((par->ref_clk_per * ref_div_count) << (3 - df))/ + (vco_div_count + 65); +} + +static void aty_set_pll_514(const struct fb_info *info, + const union aty_pll *pll) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + + aty_st_514(0x06, 0x02, par); /* DAC Operation */ + aty_st_514(0x10, 0x01, par); /* PLL Control 1 */ + aty_st_514(0x70, 0x01, par); /* Misc Control 1 */ + aty_st_514(0x8f, 0x1f, par); /* PLL Ref. Divider Input */ + aty_st_514(0x03, 0x00, par); /* Sync Control */ + aty_st_514(0x05, 0x00, par); /* Power Management */ + aty_st_514(0x20, pll->ibm514.m, par); /* F0 / M0 */ + aty_st_514(0x21, pll->ibm514.n, par); /* F1 / N0 */ +} + +const struct aty_dac_ops aty_dac_ibm514 = { + .set_dac = aty_set_dac_514, +}; + +const struct aty_pll_ops aty_pll_ibm514 = { + .var_to_pll = aty_var_to_pll_514, + .pll_to_var = aty_pll_514_to_var, + .set_pll = aty_set_pll_514, +}; + + + /* + * ATI 68860-B DAC + */ + +static int aty_set_dac_ATI68860_B(const struct fb_info *info, + const union aty_pll *pll, u32 bpp, + u32 accel) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 gModeReg, devSetupRegA, temp, mask; + + gModeReg = 0; + devSetupRegA = 0; + + switch (bpp) { + case 8: + gModeReg = 0x83; + devSetupRegA = + 0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */ ; + break; + case 15: + gModeReg = 0xA0; + devSetupRegA = 0x60; + break; + case 16: + gModeReg = 0xA1; + devSetupRegA = 0x60; + break; + case 24: + gModeReg = 0xC0; + devSetupRegA = 0x60; + break; + case 32: + gModeReg = 0xE3; + devSetupRegA = 0x60; + break; + } + + if (!accel) { + gModeReg = 0x80; + devSetupRegA = 0x61; + } + + temp = aty_ld_8(DAC_CNTL, par); + aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, + par); + + aty_st_8(DAC_REGS + 2, 0x1D, par); + aty_st_8(DAC_REGS + 3, gModeReg, par); + aty_st_8(DAC_REGS, 0x02, par); + + temp = aty_ld_8(DAC_CNTL, par); + aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par); + + if (info->fix.smem_len < ONE_MB) + mask = 0x04; + else if (info->fix.smem_len == ONE_MB) + mask = 0x08; + else + mask = 0x0C; + + /* The following assumes that the BIOS has correctly set R7 of the + * Device Setup Register A at boot time. + */ +#define A860_DELAY_L 0x80 + + temp = aty_ld_8(DAC_REGS, par); + aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L), + par); + temp = aty_ld_8(DAC_CNTL, par); + aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)), + par); + + aty_st_le32(BUS_CNTL, 0x890e20f1, par); + aty_st_le32(DAC_CNTL, 0x47052100, par); + return 0; +} + +const struct aty_dac_ops aty_dac_ati68860b = { + .set_dac = aty_set_dac_ATI68860_B, +}; + + + /* + * AT&T 21C498 DAC + */ + +static int aty_set_dac_ATT21C498(const struct fb_info *info, + const union aty_pll *pll, u32 bpp, + u32 accel) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 dotClock; + int muxmode = 0; + int DACMask = 0; + + dotClock = 100000000 / pll->ics2595.period_in_ps; + + switch (bpp) { + case 8: + if (dotClock > 8000) { + DACMask = 0x24; + muxmode = 1; + } else + DACMask = 0x04; + break; + case 15: + DACMask = 0x16; + break; + case 16: + DACMask = 0x36; + break; + case 24: + DACMask = 0xE6; + break; + case 32: + DACMask = 0xE6; + break; + } + + if (1 /* info->mach64DAC8Bit */ ) + DACMask |= 0x02; + + aty_dac_waste4(par); + aty_st_8(DAC_REGS + 2, DACMask, par); + + aty_st_le32(BUS_CNTL, 0x890e20f1, par); + aty_st_le32(DAC_CNTL, 0x00072000, par); + return muxmode; +} + +const struct aty_dac_ops aty_dac_att21c498 = { + .set_dac = aty_set_dac_ATT21C498, +}; + + + /* + * ATI 18818 / ICS 2595 Clock Chip + */ + +static int aty_var_to_pll_18818(const struct fb_info *info, u32 vclk_per, + u32 bpp, union aty_pll *pll) +{ + u32 MHz100; /* in 0.01 MHz */ + u32 program_bits; + u32 post_divider; + + /* Calculate the programming word */ + MHz100 = 100000000 / vclk_per; + + program_bits = -1; + post_divider = 1; + + if (MHz100 > MAX_FREQ_2595) { + MHz100 = MAX_FREQ_2595; + return -EINVAL; + } else if (MHz100 < ABS_MIN_FREQ_2595) { + program_bits = 0; /* MHz100 = 257 */ + return -EINVAL; + } else { + while (MHz100 < MIN_FREQ_2595) { + MHz100 *= 2; + post_divider *= 2; + } + } + MHz100 *= 1000; + MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595; + + MHz100 += 500; /* + 0.5 round */ + MHz100 /= 1000; + + if (program_bits == -1) { + program_bits = MHz100 - N_ADJ_2595; + switch (post_divider) { + case 1: + program_bits |= 0x0600; + break; + case 2: + program_bits |= 0x0400; + break; + case 4: + program_bits |= 0x0200; + break; + case 8: + default: + break; + } + } + + program_bits |= STOP_BITS_2595; + + pll->ics2595.program_bits = program_bits; + pll->ics2595.locationAddr = 0; + pll->ics2595.post_divider = post_divider; + pll->ics2595.period_in_ps = vclk_per; + + return 0; +} + +static u32 aty_pll_18818_to_var(const struct fb_info *info, + const union aty_pll *pll) +{ + return (pll->ics2595.period_in_ps); /* default for now */ +} + +static void aty_ICS2595_put1bit(u8 data, const struct atyfb_par *par) +{ + u8 tmp; + + data &= 0x01; + tmp = aty_ld_8(CLOCK_CNTL, par); + aty_st_8(CLOCK_CNTL + par->clk_wr_offset, + (tmp & ~0x04) | (data << 2), par); + + tmp = aty_ld_8(CLOCK_CNTL, par); + aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (0 << 3), + par); + + aty_StrobeClock(par); + + tmp = aty_ld_8(CLOCK_CNTL, par); + aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (1 << 3), + par); + + aty_StrobeClock(par); + return; +} + +static void aty_set_pll18818(const struct fb_info *info, + const union aty_pll *pll) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 program_bits; + u32 locationAddr; + + u32 i; + + u8 old_clock_cntl; + u8 old_crtc_ext_disp; + + old_clock_cntl = aty_ld_8(CLOCK_CNTL, par); + aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par); + + old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par); + aty_st_8(CRTC_GEN_CNTL + 3, + old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par); + + mdelay(15); /* delay for 50 (15) ms */ + + program_bits = pll->ics2595.program_bits; + locationAddr = pll->ics2595.locationAddr; + + /* Program the clock chip */ + aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par); /* Strobe = 0 */ + aty_StrobeClock(par); + aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 1, par); /* Strobe = 0 */ + aty_StrobeClock(par); + + aty_ICS2595_put1bit(1, par); /* Send start bits */ + aty_ICS2595_put1bit(0, par); /* Start bit */ + aty_ICS2595_put1bit(0, par); /* Read / ~Write */ + + for (i = 0; i < 5; i++) { /* Location 0..4 */ + aty_ICS2595_put1bit(locationAddr & 1, par); + locationAddr >>= 1; + } + + for (i = 0; i < 8 + 1 + 2 + 2; i++) { + aty_ICS2595_put1bit(program_bits & 1, par); + program_bits >>= 1; + } + + mdelay(1); /* delay for 1 ms */ + + (void) aty_ld_8(DAC_REGS, par); /* Clear DAC Counter */ + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par); + aty_st_8(CLOCK_CNTL + par->clk_wr_offset, + old_clock_cntl | CLOCK_STROBE, par); + + mdelay(50); /* delay for 50 (15) ms */ + aty_st_8(CLOCK_CNTL + par->clk_wr_offset, + ((pll->ics2595.locationAddr & 0x0F) | CLOCK_STROBE), par); + return; +} + +const struct aty_pll_ops aty_pll_ati18818_1 = { + .var_to_pll = aty_var_to_pll_18818, + .pll_to_var = aty_pll_18818_to_var, + .set_pll = aty_set_pll18818, +}; + + + /* + * STG 1703 Clock Chip + */ + +static int aty_var_to_pll_1703(const struct fb_info *info, u32 vclk_per, + u32 bpp, union aty_pll *pll) +{ + u32 mhz100; /* in 0.01 MHz */ + u32 program_bits; + /* u32 post_divider; */ + u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; + u32 temp, tempB; + u16 remainder, preRemainder; + short divider = 0, tempA; + + /* Calculate the programming word */ + mhz100 = 100000000 / vclk_per; + mach64MinFreq = MIN_FREQ_2595; + mach64MaxFreq = MAX_FREQ_2595; + mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ + + /* Calculate program word */ + if (mhz100 == 0) + program_bits = 0xE0; + else { + if (mhz100 < mach64MinFreq) + mhz100 = mach64MinFreq; + if (mhz100 > mach64MaxFreq) + mhz100 = mach64MaxFreq; + + divider = 0; + while (mhz100 < (mach64MinFreq << 3)) { + mhz100 <<= 1; + divider += 0x20; + } + + temp = (unsigned int) (mhz100); + temp = (unsigned int) (temp * (MIN_N_1703 + 2)); + temp -= (short) (mach64RefFreq << 1); + + tempA = MIN_N_1703; + preRemainder = 0xffff; + + do { + tempB = temp; + remainder = tempB % mach64RefFreq; + tempB = tempB / mach64RefFreq; + + if ((tempB & 0xffff) <= 127 + && (remainder <= preRemainder)) { + preRemainder = remainder; + divider &= ~0x1f; + divider |= tempA; + divider = + (divider & 0x00ff) + + ((tempB & 0xff) << 8); + } + + temp += mhz100; + tempA++; + } while (tempA <= (MIN_N_1703 << 1)); + + program_bits = divider; + } + + pll->ics2595.program_bits = program_bits; + pll->ics2595.locationAddr = 0; + pll->ics2595.post_divider = divider; /* fuer nix */ + pll->ics2595.period_in_ps = vclk_per; + + return 0; +} + +static u32 aty_pll_1703_to_var(const struct fb_info *info, + const union aty_pll *pll) +{ + return (pll->ics2595.period_in_ps); /* default for now */ +} + +static void aty_set_pll_1703(const struct fb_info *info, + const union aty_pll *pll) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 program_bits; + u32 locationAddr; + + char old_crtc_ext_disp; + + old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par); + aty_st_8(CRTC_GEN_CNTL + 3, + old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par); + + program_bits = pll->ics2595.program_bits; + locationAddr = pll->ics2595.locationAddr; + + /* Program clock */ + aty_dac_waste4(par); + + (void) aty_ld_8(DAC_REGS + 2, par); + aty_st_8(DAC_REGS + 2, (locationAddr << 1) + 0x20, par); + aty_st_8(DAC_REGS + 2, 0, par); + aty_st_8(DAC_REGS + 2, (program_bits & 0xFF00) >> 8, par); + aty_st_8(DAC_REGS + 2, (program_bits & 0xFF), par); + + (void) aty_ld_8(DAC_REGS, par); /* Clear DAC Counter */ + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par); + return; +} + +const struct aty_pll_ops aty_pll_stg1703 = { + .var_to_pll = aty_var_to_pll_1703, + .pll_to_var = aty_pll_1703_to_var, + .set_pll = aty_set_pll_1703, +}; + + + /* + * Chrontel 8398 Clock Chip + */ + +static int aty_var_to_pll_8398(const struct fb_info *info, u32 vclk_per, + u32 bpp, union aty_pll *pll) +{ + u32 tempA, tempB, fOut, longMHz100, diff, preDiff; + + u32 mhz100; /* in 0.01 MHz */ + u32 program_bits; + /* u32 post_divider; */ + u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; + u16 m, n, k = 0, save_m, save_n, twoToKth; + + /* Calculate the programming word */ + mhz100 = 100000000 / vclk_per; + mach64MinFreq = MIN_FREQ_2595; + mach64MaxFreq = MAX_FREQ_2595; + mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ + + save_m = 0; + save_n = 0; + + /* Calculate program word */ + if (mhz100 == 0) + program_bits = 0xE0; + else { + if (mhz100 < mach64MinFreq) + mhz100 = mach64MinFreq; + if (mhz100 > mach64MaxFreq) + mhz100 = mach64MaxFreq; + + longMHz100 = mhz100 * 256 / 100; /* 8 bit scale this */ + + while (mhz100 < (mach64MinFreq << 3)) { + mhz100 <<= 1; + k++; + } + + twoToKth = 1 << k; + diff = 0; + preDiff = 0xFFFFFFFF; + + for (m = MIN_M; m <= MAX_M; m++) { + for (n = MIN_N; n <= MAX_N; n++) { + tempA = 938356; /* 14.31818 * 65536 */ + tempA *= (n + 8); /* 43..256 */ + tempB = twoToKth * 256; + tempB *= (m + 2); /* 4..32 */ + fOut = tempA / tempB; /* 8 bit scale */ + + if (longMHz100 > fOut) + diff = longMHz100 - fOut; + else + diff = fOut - longMHz100; + + if (diff < preDiff) { + save_m = m; + save_n = n; + preDiff = diff; + } + } + } + + program_bits = (k << 6) + (save_m) + (save_n << 8); + } + + pll->ics2595.program_bits = program_bits; + pll->ics2595.locationAddr = 0; + pll->ics2595.post_divider = 0; + pll->ics2595.period_in_ps = vclk_per; + + return 0; +} + +static u32 aty_pll_8398_to_var(const struct fb_info *info, + const union aty_pll *pll) +{ + return (pll->ics2595.period_in_ps); /* default for now */ +} + +static void aty_set_pll_8398(const struct fb_info *info, + const union aty_pll *pll) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 program_bits; + u32 locationAddr; + + char old_crtc_ext_disp; + char tmp; + + old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par); + aty_st_8(CRTC_GEN_CNTL + 3, + old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par); + + program_bits = pll->ics2595.program_bits; + locationAddr = pll->ics2595.locationAddr; + + /* Program clock */ + tmp = aty_ld_8(DAC_CNTL, par); + aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par); + + aty_st_8(DAC_REGS, locationAddr, par); + aty_st_8(DAC_REGS + 1, (program_bits & 0xff00) >> 8, par); + aty_st_8(DAC_REGS + 1, (program_bits & 0xff), par); + + tmp = aty_ld_8(DAC_CNTL, par); + aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, + par); + + (void) aty_ld_8(DAC_REGS, par); /* Clear DAC Counter */ + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par); + + return; +} + +const struct aty_pll_ops aty_pll_ch8398 = { + .var_to_pll = aty_var_to_pll_8398, + .pll_to_var = aty_pll_8398_to_var, + .set_pll = aty_set_pll_8398, +}; + + + /* + * AT&T 20C408 Clock Chip + */ + +static int aty_var_to_pll_408(const struct fb_info *info, u32 vclk_per, + u32 bpp, union aty_pll *pll) +{ + u32 mhz100; /* in 0.01 MHz */ + u32 program_bits; + /* u32 post_divider; */ + u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; + u32 temp, tempB; + u16 remainder, preRemainder; + short divider = 0, tempA; + + /* Calculate the programming word */ + mhz100 = 100000000 / vclk_per; + mach64MinFreq = MIN_FREQ_2595; + mach64MaxFreq = MAX_FREQ_2595; + mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ + + /* Calculate program word */ + if (mhz100 == 0) + program_bits = 0xFF; + else { + if (mhz100 < mach64MinFreq) + mhz100 = mach64MinFreq; + if (mhz100 > mach64MaxFreq) + mhz100 = mach64MaxFreq; + + while (mhz100 < (mach64MinFreq << 3)) { + mhz100 <<= 1; + divider += 0x40; + } + + temp = (unsigned int) mhz100; + temp = (unsigned int) (temp * (MIN_N_408 + 2)); + temp -= ((short) (mach64RefFreq << 1)); + + tempA = MIN_N_408; + preRemainder = 0xFFFF; + + do { + tempB = temp; + remainder = tempB % mach64RefFreq; + tempB = tempB / mach64RefFreq; + if (((tempB & 0xFFFF) <= 255) + && (remainder <= preRemainder)) { + preRemainder = remainder; + divider &= ~0x3f; + divider |= tempA; + divider = + (divider & 0x00FF) + + ((tempB & 0xFF) << 8); + } + temp += mhz100; + tempA++; + } while (tempA <= 32); + + program_bits = divider; + } + + pll->ics2595.program_bits = program_bits; + pll->ics2595.locationAddr = 0; + pll->ics2595.post_divider = divider; /* fuer nix */ + pll->ics2595.period_in_ps = vclk_per; + + return 0; +} + +static u32 aty_pll_408_to_var(const struct fb_info *info, + const union aty_pll *pll) +{ + return (pll->ics2595.period_in_ps); /* default for now */ +} + +static void aty_set_pll_408(const struct fb_info *info, + const union aty_pll *pll) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + u32 program_bits; + u32 locationAddr; + + u8 tmpA, tmpB, tmpC; + char old_crtc_ext_disp; + + old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par); + aty_st_8(CRTC_GEN_CNTL + 3, + old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par); + + program_bits = pll->ics2595.program_bits; + locationAddr = pll->ics2595.locationAddr; + + /* Program clock */ + aty_dac_waste4(par); + tmpB = aty_ld_8(DAC_REGS + 2, par) | 1; + aty_dac_waste4(par); + aty_st_8(DAC_REGS + 2, tmpB, par); + + tmpA = tmpB; + tmpC = tmpA; + tmpA |= 8; + tmpB = 1; + + aty_st_8(DAC_REGS, tmpB, par); + aty_st_8(DAC_REGS + 2, tmpA, par); + + udelay(400); /* delay for 400 us */ + + locationAddr = (locationAddr << 2) + 0x40; + tmpB = locationAddr; + tmpA = program_bits >> 8; + + aty_st_8(DAC_REGS, tmpB, par); + aty_st_8(DAC_REGS + 2, tmpA, par); + + tmpB = locationAddr + 1; + tmpA = (u8) program_bits; + + aty_st_8(DAC_REGS, tmpB, par); + aty_st_8(DAC_REGS + 2, tmpA, par); + + tmpB = locationAddr + 2; + tmpA = 0x77; + + aty_st_8(DAC_REGS, tmpB, par); + aty_st_8(DAC_REGS + 2, tmpA, par); + + udelay(400); /* delay for 400 us */ + tmpA = tmpC & (~(1 | 8)); + tmpB = 1; + + aty_st_8(DAC_REGS, tmpB, par); + aty_st_8(DAC_REGS + 2, tmpA, par); + + (void) aty_ld_8(DAC_REGS, par); /* Clear DAC Counter */ + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par); + return; +} + +const struct aty_pll_ops aty_pll_att20c408 = { + .var_to_pll = aty_var_to_pll_408, + .pll_to_var = aty_pll_408_to_var, + .set_pll = aty_set_pll_408, +}; + + + /* + * Unsupported DAC and Clock Chip + */ + +static int aty_set_dac_unsupported(const struct fb_info *info, + const union aty_pll *pll, u32 bpp, + u32 accel) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + + aty_st_le32(BUS_CNTL, 0x890e20f1, par); + aty_st_le32(DAC_CNTL, 0x47052100, par); + /* new in 2.2.3p1 from Geert. ???????? */ + aty_st_le32(BUS_CNTL, 0x590e10ff, par); + aty_st_le32(DAC_CNTL, 0x47012100, par); + return 0; +} + +static int dummy(void) +{ + return 0; +} + +const struct aty_dac_ops aty_dac_unsupported = { + .set_dac = aty_set_dac_unsupported, +}; + +const struct aty_pll_ops aty_pll_unsupported = { + .var_to_pll = (void *) dummy, + .pll_to_var = (void *) dummy, + .set_pll = (void *) dummy, +}; diff --git a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c new file mode 100644 index 000000000000..3ca27cb13caa --- /dev/null +++ b/drivers/video/aty/radeon_accel.c @@ -0,0 +1,316 @@ +#include "radeonfb.h" + +/* the accelerated functions here are patterned after the + * "ACCEL_MMIO" ifdef branches in XFree86 + * --dte + */ + +static void radeon_fixup_offset(struct radeonfb_info *rinfo) +{ + u32 local_base; + + /* *** Ugly workaround *** */ + /* + * On some platforms, the video memory is mapped at 0 in radeon chip space + * (like PPCs) by the firmware. X will always move it up so that it's seen + * by the chip to be at the same address as the PCI BAR. + * That means that when switching back from X, there is a mismatch between + * the offsets programmed into the engine. This means that potentially, + * accel operations done before radeonfb has a chance to re-init the engine + * will have incorrect offsets, and potentially trash system memory ! + * + * The correct fix is for fbcon to never call any accel op before the engine + * has properly been re-initialized (by a call to set_var), but this is a + * complex fix. This workaround in the meantime, called before every accel + * operation, makes sure the offsets are in sync. + */ + + radeon_fifo_wait (1); + local_base = INREG(MC_FB_LOCATION) << 16; + if (local_base == rinfo->fb_local_base) + return; + + rinfo->fb_local_base = local_base; + + radeon_fifo_wait (3); + OUTREG(DEFAULT_PITCH_OFFSET, (rinfo->pitch << 0x16) | + (rinfo->fb_local_base >> 10)); + OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10)); + OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10)); +} + +static void radeonfb_prim_fillrect(struct radeonfb_info *rinfo, + const struct fb_fillrect *region) +{ + radeon_fifo_wait(4); + + OUTREG(DP_GUI_MASTER_CNTL, + rinfo->dp_gui_master_cntl /* contains, like GMC_DST_32BPP */ + | GMC_BRUSH_SOLID_COLOR + | ROP3_P); + if (radeon_get_dstbpp(rinfo->depth) != DST_8BPP) + OUTREG(DP_BRUSH_FRGD_CLR, rinfo->pseudo_palette[region->color]); + else + OUTREG(DP_BRUSH_FRGD_CLR, region->color); + OUTREG(DP_WRITE_MSK, 0xffffffff); + OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM)); + + radeon_fifo_wait(2); + OUTREG(DST_Y_X, (region->dy << 16) | region->dx); + OUTREG(DST_WIDTH_HEIGHT, (region->width << 16) | region->height); +} + +void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region) +{ + struct radeonfb_info *rinfo = info->par; + struct fb_fillrect modded; + int vxres, vyres; + + if (info->state != FBINFO_STATE_RUNNING) + return; + if (info->flags & FBINFO_HWACCEL_DISABLED) { + cfb_fillrect(info, region); + return; + } + + radeon_fixup_offset(rinfo); + + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + + memcpy(&modded, region, sizeof(struct fb_fillrect)); + + if(!modded.width || !modded.height || + modded.dx >= vxres || modded.dy >= vyres) + return; + + if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx; + if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy; + + radeonfb_prim_fillrect(rinfo, &modded); +} + +static void radeonfb_prim_copyarea(struct radeonfb_info *rinfo, + const struct fb_copyarea *area) +{ + int xdir, ydir; + u32 sx, sy, dx, dy, w, h; + + w = area->width; h = area->height; + dx = area->dx; dy = area->dy; + sx = area->sx; sy = area->sy; + xdir = sx - dx; + ydir = sy - dy; + + if ( xdir < 0 ) { sx += w-1; dx += w-1; } + if ( ydir < 0 ) { sy += h-1; dy += h-1; } + + radeon_fifo_wait(3); + OUTREG(DP_GUI_MASTER_CNTL, + rinfo->dp_gui_master_cntl /* i.e. GMC_DST_32BPP */ + | GMC_BRUSH_NONE + | GMC_SRC_DSTCOLOR + | ROP3_S + | DP_SRC_SOURCE_MEMORY ); + OUTREG(DP_WRITE_MSK, 0xffffffff); + OUTREG(DP_CNTL, (xdir>=0 ? DST_X_LEFT_TO_RIGHT : 0) + | (ydir>=0 ? DST_Y_TOP_TO_BOTTOM : 0)); + + radeon_fifo_wait(3); + OUTREG(SRC_Y_X, (sy << 16) | sx); + OUTREG(DST_Y_X, (dy << 16) | dx); + OUTREG(DST_HEIGHT_WIDTH, (h << 16) | w); +} + + +void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct radeonfb_info *rinfo = info->par; + struct fb_copyarea modded; + u32 vxres, vyres; + modded.sx = area->sx; + modded.sy = area->sy; + modded.dx = area->dx; + modded.dy = area->dy; + modded.width = area->width; + modded.height = area->height; + + if (info->state != FBINFO_STATE_RUNNING) + return; + if (info->flags & FBINFO_HWACCEL_DISABLED) { + cfb_copyarea(info, area); + return; + } + + radeon_fixup_offset(rinfo); + + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + + if(!modded.width || !modded.height || + modded.sx >= vxres || modded.sy >= vyres || + modded.dx >= vxres || modded.dy >= vyres) + return; + + if(modded.sx + modded.width > vxres) modded.width = vxres - modded.sx; + if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx; + if(modded.sy + modded.height > vyres) modded.height = vyres - modded.sy; + if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy; + + radeonfb_prim_copyarea(rinfo, &modded); +} + +void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct radeonfb_info *rinfo = info->par; + + if (info->state != FBINFO_STATE_RUNNING) + return; + radeon_engine_idle(); + + cfb_imageblit(info, image); +} + +int radeonfb_sync(struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; + + if (info->state != FBINFO_STATE_RUNNING) + return 0; + radeon_engine_idle(); + + return 0; +} + +void radeonfb_engine_reset(struct radeonfb_info *rinfo) +{ + u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset; + u32 host_path_cntl; + + radeon_engine_flush (rinfo); + + clock_cntl_index = INREG(CLOCK_CNTL_INDEX); + mclk_cntl = INPLL(MCLK_CNTL); + + OUTPLL(MCLK_CNTL, (mclk_cntl | + FORCEON_MCLKA | + FORCEON_MCLKB | + FORCEON_YCLKA | + FORCEON_YCLKB | + FORCEON_MC | + FORCEON_AIC)); + + host_path_cntl = INREG(HOST_PATH_CNTL); + rbbm_soft_reset = INREG(RBBM_SOFT_RESET); + + if (rinfo->family == CHIP_FAMILY_R300 || + rinfo->family == CHIP_FAMILY_R350 || + rinfo->family == CHIP_FAMILY_RV350) { + u32 tmp; + + OUTREG(RBBM_SOFT_RESET, (rbbm_soft_reset | + SOFT_RESET_CP | + SOFT_RESET_HI | + SOFT_RESET_E2)); + INREG(RBBM_SOFT_RESET); + OUTREG(RBBM_SOFT_RESET, 0); + tmp = INREG(RB2D_DSTCACHE_MODE); + OUTREG(RB2D_DSTCACHE_MODE, tmp | (1 << 17)); /* FIXME */ + } else { + OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset | + SOFT_RESET_CP | + SOFT_RESET_HI | + SOFT_RESET_SE | + SOFT_RESET_RE | + SOFT_RESET_PP | + SOFT_RESET_E2 | + SOFT_RESET_RB); + INREG(RBBM_SOFT_RESET); + OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset & (u32) + ~(SOFT_RESET_CP | + SOFT_RESET_HI | + SOFT_RESET_SE | + SOFT_RESET_RE | + SOFT_RESET_PP | + SOFT_RESET_E2 | + SOFT_RESET_RB)); + INREG(RBBM_SOFT_RESET); + } + + OUTREG(HOST_PATH_CNTL, host_path_cntl | HDP_SOFT_RESET); + INREG(HOST_PATH_CNTL); + OUTREG(HOST_PATH_CNTL, host_path_cntl); + + if (rinfo->family != CHIP_FAMILY_R300 || + rinfo->family != CHIP_FAMILY_R350 || + rinfo->family != CHIP_FAMILY_RV350) + OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset); + + OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index); + OUTPLL(MCLK_CNTL, mclk_cntl); +} + +void radeonfb_engine_init (struct radeonfb_info *rinfo) +{ + unsigned long temp; + + /* disable 3D engine */ + OUTREG(RB3D_CNTL, 0); + + radeonfb_engine_reset(rinfo); + + radeon_fifo_wait (1); + if ((rinfo->family != CHIP_FAMILY_R300) && + (rinfo->family != CHIP_FAMILY_R350) && + (rinfo->family != CHIP_FAMILY_RV350)) + OUTREG(RB2D_DSTCACHE_MODE, 0); + + radeon_fifo_wait (3); + /* We re-read MC_FB_LOCATION from card as it can have been + * modified by XFree drivers (ouch !) + */ + rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16; + + OUTREG(DEFAULT_PITCH_OFFSET, (rinfo->pitch << 0x16) | + (rinfo->fb_local_base >> 10)); + OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10)); + OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10)); + + radeon_fifo_wait (1); +#if defined(__BIG_ENDIAN) + OUTREGP(DP_DATATYPE, HOST_BIG_ENDIAN_EN, ~HOST_BIG_ENDIAN_EN); +#else + OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN); +#endif + radeon_fifo_wait (2); + OUTREG(DEFAULT_SC_TOP_LEFT, 0); + OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX | + DEFAULT_SC_BOTTOM_MAX)); + + temp = radeon_get_dstbpp(rinfo->depth); + rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS); + + radeon_fifo_wait (1); + OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl | + GMC_BRUSH_SOLID_COLOR | + GMC_SRC_DATATYPE_COLOR)); + + radeon_fifo_wait (7); + + /* clear line drawing regs */ + OUTREG(DST_LINE_START, 0); + OUTREG(DST_LINE_END, 0); + + /* set brush color regs */ + OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff); + OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000); + + /* set source color regs */ + OUTREG(DP_SRC_FRGD_CLR, 0xffffffff); + OUTREG(DP_SRC_BKGD_CLR, 0x00000000); + + /* default write mask */ + OUTREG(DP_WRITE_MSK, 0xffffffff); + + radeon_engine_idle (); +} diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c new file mode 100644 index 000000000000..e8eb124754b1 --- /dev/null +++ b/drivers/video/aty/radeon_base.c @@ -0,0 +1,2587 @@ +/* + * drivers/video/aty/radeon_base.c + * + * framebuffer driver for ATI Radeon chipset video boards + * + * Copyright 2003 Ben. Herrenschmidt <benh@kernel.crashing.org> + * Copyright 2000 Ani Joshi <ajoshi@kernel.crashing.org> + * + * i2c bits from Luca Tettamanti <kronos@kronoz.cjb.net> + * + * Special thanks to ATI DevRel team for their hardware donations. + * + * ...Insert GPL boilerplate here... + * + * Significant portions of this driver apdated from XFree86 Radeon + * driver which has the following copyright notice: + * + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * XFree86 driver authors: + * + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * Alan Hourihane <alanh@fairlite.demon.co.uk> + * + */ + + +#define RADEON_VERSION "0.2.0" + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/moduleparam.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/delay.h> +#include <linux/time.h> +#include <linux/fb.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/vmalloc.h> +#include <linux/device.h> +#include <linux/i2c.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_PPC_OF + +#include <asm/pci-bridge.h> +#include "../macmodes.h" + +#ifdef CONFIG_PMAC_BACKLIGHT +#include <asm/backlight.h> +#endif + +#ifdef CONFIG_BOOTX_TEXT +#include <asm/btext.h> +#endif + +#endif /* CONFIG_PPC_OF */ + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include <video/radeon.h> +#include <linux/radeonfb.h> + +#include "../edid.h" // MOVE THAT TO include/video +#include "ati_ids.h" +#include "radeonfb.h" + +#define MAX_MAPPED_VRAM (2048*2048*4) +#define MIN_MAPPED_VRAM (1024*768*1) + +#define CHIP_DEF(id, family, flags) \ + { PCI_VENDOR_ID_ATI, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (flags) | (CHIP_FAMILY_##family) } + +static struct pci_device_id radeonfb_pci_table[] = { + /* Mobility M6 */ + CHIP_DEF(PCI_CHIP_RADEON_LY, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RADEON_LZ, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + /* Radeon VE/7000 */ + CHIP_DEF(PCI_CHIP_RV100_QY, RV100, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV100_QZ, RV100, CHIP_HAS_CRTC2), + /* Radeon IGP320M (U1) */ + CHIP_DEF(PCI_CHIP_RS100_4336, RS100, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), + /* Radeon IGP320 (A3) */ + CHIP_DEF(PCI_CHIP_RS100_4136, RS100, CHIP_HAS_CRTC2 | CHIP_IS_IGP), + /* IGP330M/340M/350M (U2) */ + CHIP_DEF(PCI_CHIP_RS200_4337, RS200, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), + /* IGP330/340/350 (A4) */ + CHIP_DEF(PCI_CHIP_RS200_4137, RS200, CHIP_HAS_CRTC2 | CHIP_IS_IGP), + /* Mobility 7000 IGP */ + CHIP_DEF(PCI_CHIP_RS250_4437, RS200, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), + /* 7000 IGP (A4+) */ + CHIP_DEF(PCI_CHIP_RS250_4237, RS200, CHIP_HAS_CRTC2 | CHIP_IS_IGP), + /* 8500 AIW */ + CHIP_DEF(PCI_CHIP_R200_BB, R200, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R200_BC, R200, CHIP_HAS_CRTC2), + /* 8700/8800 */ + CHIP_DEF(PCI_CHIP_R200_QH, R200, CHIP_HAS_CRTC2), + /* 8500 */ + CHIP_DEF(PCI_CHIP_R200_QL, R200, CHIP_HAS_CRTC2), + /* 9100 */ + CHIP_DEF(PCI_CHIP_R200_QM, R200, CHIP_HAS_CRTC2), + /* Mobility M7 */ + CHIP_DEF(PCI_CHIP_RADEON_LW, RV200, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RADEON_LX, RV200, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + /* 7500 */ + CHIP_DEF(PCI_CHIP_RV200_QW, RV200, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV200_QX, RV200, CHIP_HAS_CRTC2), + /* Mobility M9 */ + CHIP_DEF(PCI_CHIP_RV250_Ld, RV250, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV250_Le, RV250, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV250_Lf, RV250, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV250_Lg, RV250, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + /* 9000/Pro */ + CHIP_DEF(PCI_CHIP_RV250_If, RV250, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV250_Ig, RV250, CHIP_HAS_CRTC2), + /* Mobility 9100 IGP (U3) */ + CHIP_DEF(PCI_CHIP_RS300_5835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RS350_7835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), + /* 9100 IGP (A5) */ + CHIP_DEF(PCI_CHIP_RS300_5834, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP), + CHIP_DEF(PCI_CHIP_RS350_7834, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP), + /* Mobility 9200 (M9+) */ + CHIP_DEF(PCI_CHIP_RV280_5C61, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV280_5C63, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + /* 9200 */ + CHIP_DEF(PCI_CHIP_RV280_5960, RV280, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV280_5961, RV280, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV280_5962, RV280, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV280_5964, RV280, CHIP_HAS_CRTC2), + /* 9500 */ + CHIP_DEF(PCI_CHIP_R300_AD, R300, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R300_AE, R300, CHIP_HAS_CRTC2), + /* 9600TX / FireGL Z1 */ + CHIP_DEF(PCI_CHIP_R300_AF, R300, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R300_AG, R300, CHIP_HAS_CRTC2), + /* 9700/9500/Pro/FireGL X1 */ + CHIP_DEF(PCI_CHIP_R300_ND, R300, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R300_NE, R300, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R300_NF, R300, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R300_NG, R300, CHIP_HAS_CRTC2), + /* Mobility M10/M11 */ + CHIP_DEF(PCI_CHIP_RV350_NP, RV350, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV350_NQ, RV350, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV350_NR, RV350, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV350_NS, RV350, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV350_NT, RV350, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV350_NV, RV350, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + /* 9600/FireGL T2 */ + CHIP_DEF(PCI_CHIP_RV350_AP, RV350, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV350_AQ, RV350, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV360_AR, RV350, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV350_AS, RV350, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV350_AT, RV350, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV350_AV, RV350, CHIP_HAS_CRTC2), + /* 9800/Pro/FileGL X2 */ + CHIP_DEF(PCI_CHIP_R350_AH, R350, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R350_AI, R350, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R350_AJ, R350, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R350_AK, R350, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R350_NH, R350, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R350_NI, R350, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R360_NJ, R350, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R350_NK, R350, CHIP_HAS_CRTC2), + /* Newer stuff */ + CHIP_DEF(PCI_CHIP_RV380_3E50, RV380, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV380_3E54, RV380, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV380_3150, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV380_3154, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV370_5B60, RV380, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV370_5B62, RV380, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV370_5B64, RV380, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV370_5B65, RV380, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RV370_5460, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV370_5464, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_R420_JH, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R420_JI, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R420_JJ, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R420_JK, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R420_JL, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R420_JM, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R420_JN, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_R420_JP, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R423_UH, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R423_UI, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R423_UJ, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R423_UK, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R423_UQ, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R423_UR, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R423_UT, R420, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_R423_5D57, R420, CHIP_HAS_CRTC2), + /* Original Radeon/7200 */ + CHIP_DEF(PCI_CHIP_RADEON_QD, RADEON, 0), + CHIP_DEF(PCI_CHIP_RADEON_QE, RADEON, 0), + CHIP_DEF(PCI_CHIP_RADEON_QF, RADEON, 0), + CHIP_DEF(PCI_CHIP_RADEON_QG, RADEON, 0), + { 0, } +}; +MODULE_DEVICE_TABLE(pci, radeonfb_pci_table); + + +typedef struct { + u16 reg; + u32 val; +} reg_val; + + +/* these common regs are cleared before mode setting so they do not + * interfere with anything + */ +static reg_val common_regs[] = { + { OVR_CLR, 0 }, + { OVR_WID_LEFT_RIGHT, 0 }, + { OVR_WID_TOP_BOTTOM, 0 }, + { OV0_SCALE_CNTL, 0 }, + { SUBPIC_CNTL, 0 }, + { VIPH_CONTROL, 0 }, + { I2C_CNTL_1, 0 }, + { GEN_INT_CNTL, 0 }, + { CAP0_TRIG_CNTL, 0 }, + { CAP1_TRIG_CNTL, 0 }, +}; + +/* + * globals + */ + +static char *mode_option; +static char *monitor_layout; +static int noaccel = 0; +static int default_dynclk = -2; +static int nomodeset = 0; +static int ignore_edid = 0; +static int mirror = 0; +static int panel_yres = 0; +static int force_dfp = 0; +static int force_measure_pll = 0; +#ifdef CONFIG_MTRR +static int nomtrr = 0; +#endif + +/* + * prototypes + */ + + +#ifdef CONFIG_PPC_OF + +#ifdef CONFIG_PMAC_BACKLIGHT +static int radeon_set_backlight_enable(int on, int level, void *data); +static int radeon_set_backlight_level(int level, void *data); +static struct backlight_controller radeon_backlight_controller = { + radeon_set_backlight_enable, + radeon_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ + +#endif /* CONFIG_PPC_OF */ + +static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) +{ + if (!rinfo->bios_seg) + return; + pci_unmap_rom(dev, rinfo->bios_seg); +} + +static int __devinit radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) +{ + void __iomem *rom; + u16 dptr; + u8 rom_type; + size_t rom_size; + + /* If this is a primary card, there is a shadow copy of the + * ROM somewhere in the first meg. We will just ignore the copy + * and use the ROM directly. + */ + + /* Fix from ATI for problem with Radeon hardware not leaving ROM enabled */ + unsigned int temp; + temp = INREG(MPP_TB_CONFIG); + temp &= 0x00ffffffu; + temp |= 0x04 << 24; + OUTREG(MPP_TB_CONFIG, temp); + temp = INREG(MPP_TB_CONFIG); + + rom = pci_map_rom(dev, &rom_size); + if (!rom) { + printk(KERN_ERR "radeonfb (%s): ROM failed to map\n", + pci_name(rinfo->pdev)); + return -ENOMEM; + } + + rinfo->bios_seg = rom; + + /* Very simple test to make sure it appeared */ + if (BIOS_IN16(0) != 0xaa55) { + printk(KERN_ERR "radeonfb (%s): Invalid ROM signature %x should be" + "0xaa55\n", pci_name(rinfo->pdev), BIOS_IN16(0)); + goto failed; + } + /* Look for the PCI data to check the ROM type */ + dptr = BIOS_IN16(0x18); + + /* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM + * for now, until I've verified this works everywhere. The goal here is more + * to phase out Open Firmware images. + * + * Currently, we only look at the first PCI data, we could iteratre and deal with + * them all, and we should use fb_bios_start relative to start of image and not + * relative start of ROM, but so far, I never found a dual-image ATI card + * + * typedef struct { + * u32 signature; + 0x00 + * u16 vendor; + 0x04 + * u16 device; + 0x06 + * u16 reserved_1; + 0x08 + * u16 dlen; + 0x0a + * u8 drevision; + 0x0c + * u8 class_hi; + 0x0d + * u16 class_lo; + 0x0e + * u16 ilen; + 0x10 + * u16 irevision; + 0x12 + * u8 type; + 0x14 + * u8 indicator; + 0x15 + * u16 reserved_2; + 0x16 + * } pci_data_t; + */ + if (BIOS_IN32(dptr) != (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) { + printk(KERN_WARNING "radeonfb (%s): PCI DATA signature in ROM" + "incorrect: %08x\n", pci_name(rinfo->pdev), BIOS_IN32(dptr)); + goto anyway; + } + rom_type = BIOS_IN8(dptr + 0x14); + switch(rom_type) { + case 0: + printk(KERN_INFO "radeonfb: Found Intel x86 BIOS ROM Image\n"); + break; + case 1: + printk(KERN_INFO "radeonfb: Found Open Firmware ROM Image\n"); + goto failed; + case 2: + printk(KERN_INFO "radeonfb: Found HP PA-RISC ROM Image\n"); + goto failed; + default: + printk(KERN_INFO "radeonfb: Found unknown type %d ROM Image\n", rom_type); + goto failed; + } + anyway: + /* Locate the flat panel infos, do some sanity checking !!! */ + rinfo->fp_bios_start = BIOS_IN16(0x48); + return 0; + + failed: + rinfo->bios_seg = NULL; + radeon_unmap_ROM(rinfo, dev); + return -ENXIO; +} + +#ifdef CONFIG_X86 +static int __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo) +{ + /* I simplified this code as we used to miss the signatures in + * a lot of case. It's now closer to XFree, we just don't check + * for signatures at all... Something better will have to be done + * if we end up having conflicts + */ + u32 segstart; + void __iomem *rom_base = NULL; + + for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { + rom_base = ioremap(segstart, 0x10000); + if (rom_base == NULL) + return -ENOMEM; + if (readb(rom_base) == 0x55 && readb(rom_base + 1) == 0xaa) + break; + iounmap(rom_base); + rom_base = NULL; + } + if (rom_base == NULL) + return -ENXIO; + + /* Locate the flat panel infos, do some sanity checking !!! */ + rinfo->bios_seg = rom_base; + rinfo->fp_bios_start = BIOS_IN16(0x48); + + return 0; +} +#endif + +#ifdef CONFIG_PPC_OF +/* + * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device + * tree. Hopefully, ATI OF driver is kind enough to fill these + */ +static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo) +{ + struct device_node *dp = rinfo->of_node; + u32 *val; + + if (dp == NULL) + return -ENODEV; + val = (u32 *) get_property(dp, "ATY,RefCLK", NULL); + if (!val || !*val) { + printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n"); + return -EINVAL; + } + + rinfo->pll.ref_clk = (*val) / 10; + + val = (u32 *) get_property(dp, "ATY,SCLK", NULL); + if (val && *val) + rinfo->pll.sclk = (*val) / 10; + + val = (u32 *) get_property(dp, "ATY,MCLK", NULL); + if (val && *val) + rinfo->pll.mclk = (*val) / 10; + + return 0; +} +#endif /* CONFIG_PPC_OF */ + +/* + * Read PLL infos from chip registers + */ +static int __devinit radeon_probe_pll_params(struct radeonfb_info *rinfo) +{ + unsigned char ppll_div_sel; + unsigned Ns, Nm, M; + unsigned sclk, mclk, tmp, ref_div; + int hTotal, vTotal, num, denom, m, n; + unsigned long long hz, vclk; + long xtal; + struct timeval start_tv, stop_tv; + long total_secs, total_usecs; + int i; + + /* Ugh, we cut interrupts, bad bad bad, but we want some precision + * here, so... --BenH + */ + + /* Flush PCI buffers ? */ + tmp = INREG(DEVICE_ID); + + local_irq_disable(); + + for(i=0; i<1000000; i++) + if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) + break; + + do_gettimeofday(&start_tv); + + for(i=0; i<1000000; i++) + if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) != 0) + break; + + for(i=0; i<1000000; i++) + if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) + break; + + do_gettimeofday(&stop_tv); + + local_irq_enable(); + + total_secs = stop_tv.tv_sec - start_tv.tv_sec; + if (total_secs > 10) + return -1; + total_usecs = stop_tv.tv_usec - start_tv.tv_usec; + total_usecs += total_secs * 1000000; + if (total_usecs < 0) + total_usecs = -total_usecs; + hz = 1000000/total_usecs; + + hTotal = ((INREG(CRTC_H_TOTAL_DISP) & 0x1ff) + 1) * 8; + vTotal = ((INREG(CRTC_V_TOTAL_DISP) & 0x3ff) + 1); + vclk = (long long)hTotal * (long long)vTotal * hz; + + switch((INPLL(PPLL_REF_DIV) & 0x30000) >> 16) { + case 0: + default: + num = 1; + denom = 1; + break; + case 1: + n = ((INPLL(M_SPLL_REF_FB_DIV) >> 16) & 0xff); + m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff); + num = 2*n; + denom = 2*m; + break; + case 2: + n = ((INPLL(M_SPLL_REF_FB_DIV) >> 8) & 0xff); + m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff); + num = 2*n; + denom = 2*m; + break; + } + + ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3; + radeon_pll_errata_after_index(rinfo); + + n = (INPLL(PPLL_DIV_0 + ppll_div_sel) & 0x7ff); + m = (INPLL(PPLL_REF_DIV) & 0x3ff); + + num *= n; + denom *= m; + + switch ((INPLL(PPLL_DIV_0 + ppll_div_sel) >> 16) & 0x7) { + case 1: + denom *= 2; + break; + case 2: + denom *= 4; + break; + case 3: + denom *= 8; + break; + case 4: + denom *= 3; + break; + case 6: + denom *= 6; + break; + case 7: + denom *= 12; + break; + } + + vclk *= denom; + do_div(vclk, 1000 * num); + xtal = vclk; + + if ((xtal > 26900) && (xtal < 27100)) + xtal = 2700; + else if ((xtal > 14200) && (xtal < 14400)) + xtal = 1432; + else if ((xtal > 29400) && (xtal < 29600)) + xtal = 2950; + else { + printk(KERN_WARNING "xtal calculation failed: %ld\n", xtal); + return -1; + } + + tmp = INPLL(M_SPLL_REF_FB_DIV); + ref_div = INPLL(PPLL_REF_DIV) & 0x3ff; + + Ns = (tmp & 0xff0000) >> 16; + Nm = (tmp & 0xff00) >> 8; + M = (tmp & 0xff); + sclk = round_div((2 * Ns * xtal), (2 * M)); + mclk = round_div((2 * Nm * xtal), (2 * M)); + + /* we're done, hopefully these are sane values */ + rinfo->pll.ref_clk = xtal; + rinfo->pll.ref_div = ref_div; + rinfo->pll.sclk = sclk; + rinfo->pll.mclk = mclk; + + return 0; +} + +/* + * Retreive PLL infos by different means (BIOS, Open Firmware, register probing...) + */ +static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo) +{ + /* + * In the case nothing works, these are defaults; they are mostly + * incomplete, however. It does provide ppll_max and _min values + * even for most other methods, however. + */ + switch (rinfo->chipset) { + case PCI_DEVICE_ID_ATI_RADEON_QW: + case PCI_DEVICE_ID_ATI_RADEON_QX: + rinfo->pll.ppll_max = 35000; + rinfo->pll.ppll_min = 12000; + rinfo->pll.mclk = 23000; + rinfo->pll.sclk = 23000; + rinfo->pll.ref_clk = 2700; + break; + case PCI_DEVICE_ID_ATI_RADEON_QL: + case PCI_DEVICE_ID_ATI_RADEON_QN: + case PCI_DEVICE_ID_ATI_RADEON_QO: + case PCI_DEVICE_ID_ATI_RADEON_Ql: + case PCI_DEVICE_ID_ATI_RADEON_BB: + rinfo->pll.ppll_max = 35000; + rinfo->pll.ppll_min = 12000; + rinfo->pll.mclk = 27500; + rinfo->pll.sclk = 27500; + rinfo->pll.ref_clk = 2700; + break; + case PCI_DEVICE_ID_ATI_RADEON_Id: + case PCI_DEVICE_ID_ATI_RADEON_Ie: + case PCI_DEVICE_ID_ATI_RADEON_If: + case PCI_DEVICE_ID_ATI_RADEON_Ig: + rinfo->pll.ppll_max = 35000; + rinfo->pll.ppll_min = 12000; + rinfo->pll.mclk = 25000; + rinfo->pll.sclk = 25000; + rinfo->pll.ref_clk = 2700; + break; + case PCI_DEVICE_ID_ATI_RADEON_ND: + case PCI_DEVICE_ID_ATI_RADEON_NE: + case PCI_DEVICE_ID_ATI_RADEON_NF: + case PCI_DEVICE_ID_ATI_RADEON_NG: + rinfo->pll.ppll_max = 40000; + rinfo->pll.ppll_min = 20000; + rinfo->pll.mclk = 27000; + rinfo->pll.sclk = 27000; + rinfo->pll.ref_clk = 2700; + break; + case PCI_DEVICE_ID_ATI_RADEON_QD: + case PCI_DEVICE_ID_ATI_RADEON_QE: + case PCI_DEVICE_ID_ATI_RADEON_QF: + case PCI_DEVICE_ID_ATI_RADEON_QG: + default: + rinfo->pll.ppll_max = 35000; + rinfo->pll.ppll_min = 12000; + rinfo->pll.mclk = 16600; + rinfo->pll.sclk = 16600; + rinfo->pll.ref_clk = 2700; + break; + } + rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; + + +#ifdef CONFIG_PPC_OF + /* + * Retreive PLL infos from Open Firmware first + */ + if (!force_measure_pll && radeon_read_xtal_OF(rinfo) == 0) { + printk(KERN_INFO "radeonfb: Retreived PLL infos from Open Firmware\n"); + goto found; + } +#endif /* CONFIG_PPC_OF */ + + /* + * Check out if we have an X86 which gave us some PLL informations + * and if yes, retreive them + */ + if (!force_measure_pll && rinfo->bios_seg) { + u16 pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30); + + rinfo->pll.sclk = BIOS_IN16(pll_info_block + 0x08); + rinfo->pll.mclk = BIOS_IN16(pll_info_block + 0x0a); + rinfo->pll.ref_clk = BIOS_IN16(pll_info_block + 0x0e); + rinfo->pll.ref_div = BIOS_IN16(pll_info_block + 0x10); + rinfo->pll.ppll_min = BIOS_IN32(pll_info_block + 0x12); + rinfo->pll.ppll_max = BIOS_IN32(pll_info_block + 0x16); + + printk(KERN_INFO "radeonfb: Retreived PLL infos from BIOS\n"); + goto found; + } + + /* + * We didn't get PLL parameters from either OF or BIOS, we try to + * probe them + */ + if (radeon_probe_pll_params(rinfo) == 0) { + printk(KERN_INFO "radeonfb: Retreived PLL infos from registers\n"); + goto found; + } + + /* + * Fall back to already-set defaults... + */ + printk(KERN_INFO "radeonfb: Used default PLL infos\n"); + +found: + /* + * Some methods fail to retreive SCLK and MCLK values, we apply default + * settings in this case (200Mhz). If that really happne often, we could + * fetch from registers instead... + */ + if (rinfo->pll.mclk == 0) + rinfo->pll.mclk = 20000; + if (rinfo->pll.sclk == 0) + rinfo->pll.sclk = 20000; + + printk("radeonfb: Reference=%d.%02d MHz (RefDiv=%d) Memory=%d.%02d Mhz, System=%d.%02d MHz\n", + rinfo->pll.ref_clk / 100, rinfo->pll.ref_clk % 100, + rinfo->pll.ref_div, + rinfo->pll.mclk / 100, rinfo->pll.mclk % 100, + rinfo->pll.sclk / 100, rinfo->pll.sclk % 100); + printk("radeonfb: PLL min %d max %d\n", rinfo->pll.ppll_min, rinfo->pll.ppll_max); +} + +static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; + struct fb_var_screeninfo v; + int nom, den; + unsigned int pitch; + + if (radeon_match_mode(rinfo, &v, var)) + return -EINVAL; + + switch (v.bits_per_pixel) { + case 0 ... 8: + v.bits_per_pixel = 8; + break; + case 9 ... 16: + v.bits_per_pixel = 16; + break; + case 17 ... 24: +#if 0 /* Doesn't seem to work */ + v.bits_per_pixel = 24; + break; +#endif + return -EINVAL; + case 25 ... 32: + v.bits_per_pixel = 32; + break; + default: + return -EINVAL; + } + + switch (var_to_depth(&v)) { + case 8: + nom = den = 1; + v.red.offset = v.green.offset = v.blue.offset = 0; + v.red.length = v.green.length = v.blue.length = 8; + v.transp.offset = v.transp.length = 0; + break; + case 15: + nom = 2; + den = 1; + v.red.offset = 10; + v.green.offset = 5; + v.blue.offset = 0; + v.red.length = v.green.length = v.blue.length = 5; + v.transp.offset = v.transp.length = 0; + break; + case 16: + nom = 2; + den = 1; + v.red.offset = 11; + v.green.offset = 5; + v.blue.offset = 0; + v.red.length = 5; + v.green.length = 6; + v.blue.length = 5; + v.transp.offset = v.transp.length = 0; + break; + case 24: + nom = 4; + den = 1; + v.red.offset = 16; + v.green.offset = 8; + v.blue.offset = 0; + v.red.length = v.blue.length = v.green.length = 8; + v.transp.offset = v.transp.length = 0; + break; + case 32: + nom = 4; + den = 1; + v.red.offset = 16; + v.green.offset = 8; + v.blue.offset = 0; + v.red.length = v.blue.length = v.green.length = 8; + v.transp.offset = 24; + v.transp.length = 8; + break; + default: + printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + + if (v.yres_virtual < v.yres) + v.yres_virtual = v.yres; + if (v.xres_virtual < v.xres) + v.xres_virtual = v.xres; + + + /* XXX I'm adjusting xres_virtual to the pitch, that may help XFree + * with some panels, though I don't quite like this solution + */ + if (rinfo->info->flags & FBINFO_HWACCEL_DISABLED) { + v.xres_virtual = v.xres_virtual & ~7ul; + } else { + pitch = ((v.xres_virtual * ((v.bits_per_pixel + 1) / 8) + 0x3f) + & ~(0x3f)) >> 6; + v.xres_virtual = (pitch << 6) / ((v.bits_per_pixel + 1) / 8); + } + + if (((v.xres_virtual * v.yres_virtual * nom) / den) > rinfo->mapped_vram) + return -EINVAL; + + if (v.xres_virtual < v.xres) + v.xres = v.xres_virtual; + + if (v.xoffset < 0) + v.xoffset = 0; + if (v.yoffset < 0) + v.yoffset = 0; + + if (v.xoffset > v.xres_virtual - v.xres) + v.xoffset = v.xres_virtual - v.xres - 1; + + if (v.yoffset > v.yres_virtual - v.yres) + v.yoffset = v.yres_virtual - v.yres - 1; + + v.red.msb_right = v.green.msb_right = v.blue.msb_right = + v.transp.offset = v.transp.length = + v.transp.msb_right = 0; + + memcpy(var, &v, sizeof(v)); + + return 0; +} + + +static int radeonfb_pan_display (struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; + + if ((var->xoffset + var->xres > var->xres_virtual) + || (var->yoffset + var->yres > var->yres_virtual)) + return -EINVAL; + + if (rinfo->asleep) + return 0; + + radeon_fifo_wait(2); + OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset) + * var->bits_per_pixel / 8) & ~7); + return 0; +} + + +static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; + unsigned int tmp; + u32 value = 0; + int rc; + + switch (cmd) { + /* + * TODO: set mirror accordingly for non-Mobility chipsets with 2 CRTC's + * and do something better using 2nd CRTC instead of just hackish + * routing to second output + */ + case FBIO_RADEON_SET_MIRROR: + if (!rinfo->is_mobility) + return -EINVAL; + + rc = get_user(value, (__u32 __user *)arg); + + if (rc) + return rc; + + radeon_fifo_wait(2); + if (value & 0x01) { + tmp = INREG(LVDS_GEN_CNTL); + + tmp |= (LVDS_ON | LVDS_BLON); + } else { + tmp = INREG(LVDS_GEN_CNTL); + + tmp &= ~(LVDS_ON | LVDS_BLON); + } + + OUTREG(LVDS_GEN_CNTL, tmp); + + if (value & 0x02) { + tmp = INREG(CRTC_EXT_CNTL); + tmp |= CRTC_CRT_ON; + + mirror = 1; + } else { + tmp = INREG(CRTC_EXT_CNTL); + tmp &= ~CRTC_CRT_ON; + + mirror = 0; + } + + OUTREG(CRTC_EXT_CNTL, tmp); + + return 0; + case FBIO_RADEON_GET_MIRROR: + if (!rinfo->is_mobility) + return -EINVAL; + + tmp = INREG(LVDS_GEN_CNTL); + if ((LVDS_ON | LVDS_BLON) & tmp) + value |= 0x01; + + tmp = INREG(CRTC_EXT_CNTL); + if (CRTC_CRT_ON & tmp) + value |= 0x02; + + return put_user(value, (__u32 __user *)arg); + default: + return -EINVAL; + } + + return -EINVAL; +} + + +int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch) +{ + u32 val; + u32 tmp_pix_clks; + int unblank = 0; + + if (rinfo->lock_blank) + return 0; + + radeon_engine_idle(); + + val = INREG(CRTC_EXT_CNTL); + val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS | + CRTC_VSYNC_DIS); + switch (blank) { + case FB_BLANK_VSYNC_SUSPEND: + val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS); + break; + case FB_BLANK_HSYNC_SUSPEND: + val |= (CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS); + break; + case FB_BLANK_POWERDOWN: + val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | + CRTC_HSYNC_DIS); + break; + case FB_BLANK_NORMAL: + val |= CRTC_DISPLAY_DIS; + break; + case FB_BLANK_UNBLANK: + default: + unblank = 1; + } + OUTREG(CRTC_EXT_CNTL, val); + + + switch (rinfo->mon1_type) { + case MT_DFP: + if (unblank) + OUTREGP(FP_GEN_CNTL, (FP_FPON | FP_TMDS_EN), + ~(FP_FPON | FP_TMDS_EN)); + else { + if (mode_switch || blank == FB_BLANK_NORMAL) + break; + OUTREGP(FP_GEN_CNTL, 0, ~(FP_FPON | FP_TMDS_EN)); + } + break; + case MT_LCD: + del_timer_sync(&rinfo->lvds_timer); + val = INREG(LVDS_GEN_CNTL); + if (unblank) { + u32 target_val = (val & ~LVDS_DISPLAY_DIS) | LVDS_BLON | LVDS_ON + | LVDS_EN | (rinfo->init_state.lvds_gen_cntl + & (LVDS_DIGON | LVDS_BL_MOD_EN)); + if ((val ^ target_val) == LVDS_DISPLAY_DIS) + OUTREG(LVDS_GEN_CNTL, target_val); + else if ((val ^ target_val) != 0) { + OUTREG(LVDS_GEN_CNTL, target_val + & ~(LVDS_ON | LVDS_BL_MOD_EN)); + rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; + rinfo->init_state.lvds_gen_cntl |= + target_val & LVDS_STATE_MASK; + if (mode_switch) { + radeon_msleep(rinfo->panel_info.pwr_delay); + OUTREG(LVDS_GEN_CNTL, target_val); + } + else { + rinfo->pending_lvds_gen_cntl = target_val; + mod_timer(&rinfo->lvds_timer, + jiffies + + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); + } + } + } else { + val |= LVDS_DISPLAY_DIS; + OUTREG(LVDS_GEN_CNTL, val); + + /* We don't do a full switch-off on a simple mode switch */ + if (mode_switch || blank == FB_BLANK_NORMAL) + break; + + /* Asic bug, when turning off LVDS_ON, we have to make sure + * RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off + */ + tmp_pix_clks = INPLL(PIXCLKS_CNTL); + if (rinfo->is_mobility || rinfo->is_IGP) + OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb); + val &= ~(LVDS_BL_MOD_EN); + OUTREG(LVDS_GEN_CNTL, val); + udelay(100); + val &= ~(LVDS_ON | LVDS_EN); + OUTREG(LVDS_GEN_CNTL, val); + val &= ~LVDS_DIGON; + rinfo->pending_lvds_gen_cntl = val; + mod_timer(&rinfo->lvds_timer, + jiffies + + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); + rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; + rinfo->init_state.lvds_gen_cntl |= val & LVDS_STATE_MASK; + if (rinfo->is_mobility || rinfo->is_IGP) + OUTPLL(PIXCLKS_CNTL, tmp_pix_clks); + } + break; + case MT_CRT: + // todo: powerdown DAC + default: + break; + } + + /* let fbcon do a soft blank for us */ + return (blank == FB_BLANK_NORMAL) ? -EINVAL : 0; +} + +static int radeonfb_blank (int blank, struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; + + if (rinfo->asleep) + return 0; + + return radeon_screen_blank(rinfo, blank, 0); +} + +static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; + u32 pindex; + unsigned int i; + + if (regno > 255) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + rinfo->palette[regno].red = red; + rinfo->palette[regno].green = green; + rinfo->palette[regno].blue = blue; + + /* default */ + pindex = regno; + + if (!rinfo->asleep) { + u32 dac_cntl2, vclk_cntl = 0; + + radeon_fifo_wait(9); + if (rinfo->is_mobility) { + vclk_cntl = INPLL(VCLK_ECP_CNTL); + OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb); + } + + /* Make sure we are on first palette */ + if (rinfo->has_CRTC2) { + dac_cntl2 = INREG(DAC_CNTL2); + dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL; + OUTREG(DAC_CNTL2, dac_cntl2); + } + + if (rinfo->bpp == 16) { + pindex = regno * 8; + + if (rinfo->depth == 16 && regno > 63) + return 1; + if (rinfo->depth == 15 && regno > 31) + return 1; + + /* For 565, the green component is mixed one order below */ + if (rinfo->depth == 16) { + OUTREG(PALETTE_INDEX, pindex>>1); + OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) | + (green << 8) | (rinfo->palette[regno>>1].blue)); + green = rinfo->palette[regno<<1].green; + } + } + + if (rinfo->depth != 16 || regno < 32) { + OUTREG(PALETTE_INDEX, pindex); + OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue); + } + if (rinfo->is_mobility) + OUTPLL(VCLK_ECP_CNTL, vclk_cntl); + } + if (regno < 16) { + u32 *pal = info->pseudo_palette; + switch (rinfo->depth) { + case 15: + pal[regno] = (regno << 10) | (regno << 5) | regno; + break; + case 16: + pal[regno] = (regno << 11) | (regno << 5) | regno; + break; + case 24: + pal[regno] = (regno << 16) | (regno << 8) | regno; + break; + case 32: + i = (regno << 8) | regno; + pal[regno] = (i << 16) | i; + break; + } + } + return 0; +} + + +static void radeon_save_state (struct radeonfb_info *rinfo, + struct radeon_regs *save) +{ + /* CRTC regs */ + save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL); + save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL); + save->crtc_more_cntl = INREG(CRTC_MORE_CNTL); + save->dac_cntl = INREG(DAC_CNTL); + save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP); + save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID); + save->crtc_v_total_disp = INREG(CRTC_V_TOTAL_DISP); + save->crtc_v_sync_strt_wid = INREG(CRTC_V_SYNC_STRT_WID); + save->crtc_pitch = INREG(CRTC_PITCH); + save->surface_cntl = INREG(SURFACE_CNTL); + + /* FP regs */ + save->fp_crtc_h_total_disp = INREG(FP_CRTC_H_TOTAL_DISP); + save->fp_crtc_v_total_disp = INREG(FP_CRTC_V_TOTAL_DISP); + save->fp_gen_cntl = INREG(FP_GEN_CNTL); + save->fp_h_sync_strt_wid = INREG(FP_H_SYNC_STRT_WID); + save->fp_horz_stretch = INREG(FP_HORZ_STRETCH); + save->fp_v_sync_strt_wid = INREG(FP_V_SYNC_STRT_WID); + save->fp_vert_stretch = INREG(FP_VERT_STRETCH); + save->lvds_gen_cntl = INREG(LVDS_GEN_CNTL); + save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL); + save->tmds_crc = INREG(TMDS_CRC); + save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL); + save->vclk_ecp_cntl = INPLL(VCLK_ECP_CNTL); + + /* PLL regs */ + save->clk_cntl_index = INREG(CLOCK_CNTL_INDEX) & ~0x3f; + radeon_pll_errata_after_index(rinfo); + save->ppll_div_3 = INPLL(PPLL_DIV_3); + save->ppll_ref_div = INPLL(PPLL_REF_DIV); +} + + +static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *mode) +{ + int i; + + radeon_fifo_wait(20); + + /* Workaround from XFree */ + if (rinfo->is_mobility) { + /* A temporal workaround for the occational blanking on certain laptop + * panels. This appears to related to the PLL divider registers + * (fail to lock?). It occurs even when all dividers are the same + * with their old settings. In this case we really don't need to + * fiddle with PLL registers. By doing this we can avoid the blanking + * problem with some panels. + */ + if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) && + (mode->ppll_div_3 == (INPLL(PPLL_DIV_3) & + (PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK)))) { + /* We still have to force a switch to selected PPLL div thanks to + * an XFree86 driver bug which will switch it away in some cases + * even when using UseFDev */ + OUTREGP(CLOCK_CNTL_INDEX, + mode->clk_cntl_index & PPLL_DIV_SEL_MASK, + ~PPLL_DIV_SEL_MASK); + radeon_pll_errata_after_index(rinfo); + radeon_pll_errata_after_data(rinfo); + return; + } + } + + /* Swich VCKL clock input to CPUCLK so it stays fed while PPLL updates*/ + OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_CPUCLK, ~VCLK_SRC_SEL_MASK); + + /* Reset PPLL & enable atomic update */ + OUTPLLP(PPLL_CNTL, + PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN, + ~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN)); + + /* Switch to selected PPLL divider */ + OUTREGP(CLOCK_CNTL_INDEX, + mode->clk_cntl_index & PPLL_DIV_SEL_MASK, + ~PPLL_DIV_SEL_MASK); + radeon_pll_errata_after_index(rinfo); + radeon_pll_errata_after_data(rinfo); + + /* Set PPLL ref. div */ + if (rinfo->family == CHIP_FAMILY_R300 || + rinfo->family == CHIP_FAMILY_RS300 || + rinfo->family == CHIP_FAMILY_R350 || + rinfo->family == CHIP_FAMILY_RV350) { + if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { + /* When restoring console mode, use saved PPLL_REF_DIV + * setting. + */ + OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, 0); + } else { + /* R300 uses ref_div_acc field as real ref divider */ + OUTPLLP(PPLL_REF_DIV, + (mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), + ~R300_PPLL_REF_DIV_ACC_MASK); + } + } else + OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK); + + /* Set PPLL divider 3 & post divider*/ + OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK); + OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK); + + /* Write update */ + while (INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R) + ; + OUTPLLP(PPLL_REF_DIV, PPLL_ATOMIC_UPDATE_W, ~PPLL_ATOMIC_UPDATE_W); + + /* Wait read update complete */ + /* FIXME: Certain revisions of R300 can't recover here. Not sure of + the cause yet, but this workaround will mask the problem for now. + Other chips usually will pass at the very first test, so the + workaround shouldn't have any effect on them. */ + for (i = 0; (i < 10000 && INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); i++) + ; + + OUTPLL(HTOTAL_CNTL, 0); + + /* Clear reset & atomic update */ + OUTPLLP(PPLL_CNTL, 0, + ~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN)); + + /* We may want some locking ... oh well */ + radeon_msleep(5); + + /* Switch back VCLK source to PPLL */ + OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK); +} + +/* + * Timer function for delayed LVDS panel power up/down + */ +static void radeon_lvds_timer_func(unsigned long data) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *)data; + + radeon_engine_idle(); + + OUTREG(LVDS_GEN_CNTL, rinfo->pending_lvds_gen_cntl); +} + +/* + * Apply a video mode. This will apply the whole register set, including + * the PLL registers, to the card + */ +void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, + int regs_only) +{ + int i; + int primary_mon = PRIMARY_MONITOR(rinfo); + + if (nomodeset) + return; + + if (!regs_only) + radeon_screen_blank(rinfo, FB_BLANK_NORMAL, 0); + + radeon_fifo_wait(31); + for (i=0; i<10; i++) + OUTREG(common_regs[i].reg, common_regs[i].val); + + /* Apply surface registers */ + for (i=0; i<8; i++) { + OUTREG(SURFACE0_LOWER_BOUND + 0x10*i, mode->surf_lower_bound[i]); + OUTREG(SURFACE0_UPPER_BOUND + 0x10*i, mode->surf_upper_bound[i]); + OUTREG(SURFACE0_INFO + 0x10*i, mode->surf_info[i]); + } + + OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl); + OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl, + ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS)); + OUTREG(CRTC_MORE_CNTL, mode->crtc_more_cntl); + OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING); + OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp); + OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid); + OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp); + OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid); + OUTREG(CRTC_OFFSET, 0); + OUTREG(CRTC_OFFSET_CNTL, 0); + OUTREG(CRTC_PITCH, mode->crtc_pitch); + OUTREG(SURFACE_CNTL, mode->surface_cntl); + + radeon_write_pll_regs(rinfo, mode); + + if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { + radeon_fifo_wait(10); + OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp); + OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp); + OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid); + OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid); + OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch); + OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch); + OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl); + OUTREG(TMDS_CRC, mode->tmds_crc); + OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl); + } + + if (!regs_only) + radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 0); + + radeon_fifo_wait(2); + OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl); + + return; +} + +/* + * Calculate the PLL values for a given mode + */ +static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *regs, + unsigned long freq) +{ + const struct { + int divider; + int bitvalue; + } *post_div, + post_divs[] = { + { 1, 0 }, + { 2, 1 }, + { 4, 2 }, + { 8, 3 }, + { 3, 4 }, + { 16, 5 }, + { 6, 6 }, + { 12, 7 }, + { 0, 0 }, + }; + int fb_div, pll_output_freq = 0; + int uses_dvo = 0; + + /* Check if the DVO port is enabled and sourced from the primary CRTC. I'm + * not sure which model starts having FP2_GEN_CNTL, I assume anything more + * recent than an r(v)100... + */ +#if 1 + /* XXX I had reports of flicker happening with the cinema display + * on TMDS1 that seem to be fixed if I also forbit odd dividers in + * this case. This could just be a bandwidth calculation issue, I + * haven't implemented the bandwidth code yet, but in the meantime, + * forcing uses_dvo to 1 fixes it and shouln't have bad side effects, + * I haven't seen a case were were absolutely needed an odd PLL + * divider. I'll find a better fix once I have more infos on the + * real cause of the problem. + */ + while (rinfo->has_CRTC2) { + u32 fp2_gen_cntl = INREG(FP2_GEN_CNTL); + u32 disp_output_cntl; + int source; + + /* FP2 path not enabled */ + if ((fp2_gen_cntl & FP2_ON) == 0) + break; + /* Not all chip revs have the same format for this register, + * extract the source selection + */ + if (rinfo->family == CHIP_FAMILY_R200 || + rinfo->family == CHIP_FAMILY_R300 || + rinfo->family == CHIP_FAMILY_R350 || + rinfo->family == CHIP_FAMILY_RV350) { + source = (fp2_gen_cntl >> 10) & 0x3; + /* sourced from transform unit, check for transform unit + * own source + */ + if (source == 3) { + disp_output_cntl = INREG(DISP_OUTPUT_CNTL); + source = (disp_output_cntl >> 12) & 0x3; + } + } else + source = (fp2_gen_cntl >> 13) & 0x1; + /* sourced from CRTC2 -> exit */ + if (source == 1) + break; + + /* so we end up on CRTC1, let's set uses_dvo to 1 now */ + uses_dvo = 1; + break; + } +#else + uses_dvo = 1; +#endif + if (freq > rinfo->pll.ppll_max) + freq = rinfo->pll.ppll_max; + if (freq*12 < rinfo->pll.ppll_min) + freq = rinfo->pll.ppll_min / 12; + RTRACE("freq = %lu, PLL min = %u, PLL max = %u\n", + freq, rinfo->pll.ppll_min, rinfo->pll.ppll_max); + + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + pll_output_freq = post_div->divider * freq; + /* If we output to the DVO port (external TMDS), we don't allow an + * odd PLL divider as those aren't supported on this path + */ + if (uses_dvo && (post_div->divider & 1)) + continue; + if (pll_output_freq >= rinfo->pll.ppll_min && + pll_output_freq <= rinfo->pll.ppll_max) + break; + } + + /* If we fall through the bottom, try the "default value" + given by the terminal post_div->bitvalue */ + if ( !post_div->divider ) { + post_div = &post_divs[post_div->bitvalue]; + pll_output_freq = post_div->divider * freq; + } + RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n", + rinfo->pll.ref_div, rinfo->pll.ref_clk, + pll_output_freq); + + /* If we fall through the bottom, try the "default value" + given by the terminal post_div->bitvalue */ + if ( !post_div->divider ) { + post_div = &post_divs[post_div->bitvalue]; + pll_output_freq = post_div->divider * freq; + } + RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n", + rinfo->pll.ref_div, rinfo->pll.ref_clk, + pll_output_freq); + + fb_div = round_div(rinfo->pll.ref_div*pll_output_freq, + rinfo->pll.ref_clk); + regs->ppll_ref_div = rinfo->pll.ref_div; + regs->ppll_div_3 = fb_div | (post_div->bitvalue << 16); + + RTRACE("post div = 0x%x\n", post_div->bitvalue); + RTRACE("fb_div = 0x%x\n", fb_div); + RTRACE("ppll_div_3 = 0x%x\n", regs->ppll_div_3); +} + +static int radeonfb_set_par(struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; + struct fb_var_screeninfo *mode = &info->var; + struct radeon_regs *newmode; + int hTotal, vTotal, hSyncStart, hSyncEnd, + hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync; + u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5}; + u8 hsync_fudge_fp[] = {2, 2, 0, 0, 5, 5}; + u32 sync, h_sync_pol, v_sync_pol, dotClock, pixClock; + int i, freq; + int format = 0; + int nopllcalc = 0; + int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid; + int primary_mon = PRIMARY_MONITOR(rinfo); + int depth = var_to_depth(mode); + int use_rmx = 0; + + newmode = kmalloc(sizeof(struct radeon_regs), GFP_KERNEL); + if (!newmode) + return -ENOMEM; + + /* We always want engine to be idle on a mode switch, even + * if we won't actually change the mode + */ + radeon_engine_idle(); + + hSyncStart = mode->xres + mode->right_margin; + hSyncEnd = hSyncStart + mode->hsync_len; + hTotal = hSyncEnd + mode->left_margin; + + vSyncStart = mode->yres + mode->lower_margin; + vSyncEnd = vSyncStart + mode->vsync_len; + vTotal = vSyncEnd + mode->upper_margin; + pixClock = mode->pixclock; + + sync = mode->sync; + h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + + if (primary_mon == MT_DFP || primary_mon == MT_LCD) { + if (rinfo->panel_info.xres < mode->xres) + mode->xres = rinfo->panel_info.xres; + if (rinfo->panel_info.yres < mode->yres) + mode->yres = rinfo->panel_info.yres; + + hTotal = mode->xres + rinfo->panel_info.hblank; + hSyncStart = mode->xres + rinfo->panel_info.hOver_plus; + hSyncEnd = hSyncStart + rinfo->panel_info.hSync_width; + + vTotal = mode->yres + rinfo->panel_info.vblank; + vSyncStart = mode->yres + rinfo->panel_info.vOver_plus; + vSyncEnd = vSyncStart + rinfo->panel_info.vSync_width; + + h_sync_pol = !rinfo->panel_info.hAct_high; + v_sync_pol = !rinfo->panel_info.vAct_high; + + pixClock = 100000000 / rinfo->panel_info.clock; + + if (rinfo->panel_info.use_bios_dividers) { + nopllcalc = 1; + newmode->ppll_div_3 = rinfo->panel_info.fbk_divider | + (rinfo->panel_info.post_divider << 16); + newmode->ppll_ref_div = rinfo->panel_info.ref_divider; + } + } + dotClock = 1000000000 / pixClock; + freq = dotClock / 10; /* x100 */ + + RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n", + hSyncStart, hSyncEnd, hTotal); + RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n", + vSyncStart, vSyncEnd, vTotal); + + hsync_wid = (hSyncEnd - hSyncStart) / 8; + vsync_wid = vSyncEnd - vSyncStart; + if (hsync_wid == 0) + hsync_wid = 1; + else if (hsync_wid > 0x3f) /* max */ + hsync_wid = 0x3f; + + if (vsync_wid == 0) + vsync_wid = 1; + else if (vsync_wid > 0x1f) /* max */ + vsync_wid = 0x1f; + + hSyncPol = mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + vSyncPol = mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + + cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; + + format = radeon_get_dstbpp(depth); + bytpp = mode->bits_per_pixel >> 3; + + if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) + hsync_fudge = hsync_fudge_fp[format-1]; + else + hsync_fudge = hsync_adj_tab[format-1]; + + hsync_start = hSyncStart - 8 + hsync_fudge; + + newmode->crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | + (format << 8); + + /* Clear auto-center etc... */ + newmode->crtc_more_cntl = rinfo->init_state.crtc_more_cntl; + newmode->crtc_more_cntl &= 0xfffffff0; + + if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { + newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN; + if (mirror) + newmode->crtc_ext_cntl |= CRTC_CRT_ON; + + newmode->crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN | + CRTC_INTERLACE_EN); + } else { + newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN | + CRTC_CRT_ON; + } + + newmode->dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN | + DAC_8BIT_EN; + + newmode->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) | + (((mode->xres / 8) - 1) << 16)); + + newmode->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) | + (hsync_wid << 16) | (h_sync_pol << 23)); + + newmode->crtc_v_total_disp = ((vTotal - 1) & 0xffff) | + ((mode->yres - 1) << 16); + + newmode->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) | + (vsync_wid << 16) | (v_sync_pol << 23)); + + if (!(info->flags & FBINFO_HWACCEL_DISABLED)) { + /* We first calculate the engine pitch */ + rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f) + & ~(0x3f)) >> 6; + + /* Then, re-multiply it to get the CRTC pitch */ + newmode->crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8); + } else + newmode->crtc_pitch = (mode->xres_virtual >> 3); + + newmode->crtc_pitch |= (newmode->crtc_pitch << 16); + + /* + * 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; + +#if defined(__BIG_ENDIAN) + + /* 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 + + /* Clear surface registers */ + for (i=0; i<8; i++) { + newmode->surf_lower_bound[i] = 0; + newmode->surf_upper_bound[i] = 0x1f; + newmode->surf_info[i] = 0; + } + + RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", + newmode->crtc_h_total_disp, newmode->crtc_h_sync_strt_wid); + RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", + newmode->crtc_v_total_disp, newmode->crtc_v_sync_strt_wid); + + rinfo->bpp = mode->bits_per_pixel; + rinfo->depth = depth; + + RTRACE("pixclock = %lu\n", (unsigned long)pixClock); + RTRACE("freq = %lu\n", (unsigned long)freq); + + /* We use PPLL_DIV_3 */ + newmode->clk_cntl_index = 0x300; + + /* Calculate PPLL value if necessary */ + if (!nopllcalc) + radeon_calc_pll_regs(rinfo, newmode, freq); + + newmode->vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl; + + if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { + unsigned int hRatio, vRatio; + + if (mode->xres > rinfo->panel_info.xres) + mode->xres = rinfo->panel_info.xres; + if (mode->yres > rinfo->panel_info.yres) + mode->yres = rinfo->panel_info.yres; + + newmode->fp_horz_stretch = (((rinfo->panel_info.xres / 8) - 1) + << HORZ_PANEL_SHIFT); + newmode->fp_vert_stretch = ((rinfo->panel_info.yres - 1) + << VERT_PANEL_SHIFT); + + if (mode->xres != rinfo->panel_info.xres) { + hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX, + rinfo->panel_info.xres); + newmode->fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) | + (newmode->fp_horz_stretch & + (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH | + HORZ_AUTO_RATIO_INC))); + newmode->fp_horz_stretch |= (HORZ_STRETCH_BLEND | + HORZ_STRETCH_ENABLE); + use_rmx = 1; + } + newmode->fp_horz_stretch &= ~HORZ_AUTO_RATIO; + + if (mode->yres != rinfo->panel_info.yres) { + vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX, + rinfo->panel_info.yres); + newmode->fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) | + (newmode->fp_vert_stretch & + (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED))); + newmode->fp_vert_stretch |= (VERT_STRETCH_BLEND | + VERT_STRETCH_ENABLE); + use_rmx = 1; + } + newmode->fp_vert_stretch &= ~VERT_AUTO_RATIO_EN; + + newmode->fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32) + ~(FP_SEL_CRTC2 | + FP_RMX_HVSYNC_CONTROL_EN | + FP_DFP_SYNC_SEL | + FP_CRT_SYNC_SEL | + FP_CRTC_LOCK_8DOT | + FP_USE_SHADOW_EN | + FP_CRTC_USE_SHADOW_VEND | + FP_CRT_SYNC_ALT)); + + newmode->fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR | + FP_CRTC_DONT_SHADOW_HEND | + FP_PANEL_FORMAT); + + if (IS_R300_VARIANT(rinfo) || + (rinfo->family == CHIP_FAMILY_R200)) { + newmode->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; + if (use_rmx) + newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX; + else + newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1; + } else + newmode->fp_gen_cntl |= FP_SEL_CRTC1; + + newmode->lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl; + newmode->lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl; + newmode->tmds_crc = rinfo->init_state.tmds_crc; + newmode->tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl; + + if (primary_mon == MT_LCD) { + newmode->lvds_gen_cntl |= (LVDS_ON | LVDS_BLON); + newmode->fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN); + } else { + /* DFP */ + newmode->fp_gen_cntl |= (FP_FPON | FP_TMDS_EN); + newmode->tmds_transmitter_cntl &= ~(TMDS_PLLRST); + /* TMDS_PLL_EN bit is reversed on RV (and mobility) chips */ + if (IS_R300_VARIANT(rinfo) || + (rinfo->family == CHIP_FAMILY_R200) || !rinfo->has_CRTC2) + newmode->tmds_transmitter_cntl &= ~TMDS_PLL_EN; + else + newmode->tmds_transmitter_cntl |= TMDS_PLL_EN; + newmode->crtc_ext_cntl &= ~CRTC_CRT_ON; + } + + newmode->fp_crtc_h_total_disp = (((rinfo->panel_info.hblank / 8) & 0x3ff) | + (((mode->xres / 8) - 1) << 16)); + newmode->fp_crtc_v_total_disp = (rinfo->panel_info.vblank & 0xffff) | + ((mode->yres - 1) << 16); + newmode->fp_h_sync_strt_wid = ((rinfo->panel_info.hOver_plus & 0x1fff) | + (hsync_wid << 16) | (h_sync_pol << 23)); + newmode->fp_v_sync_strt_wid = ((rinfo->panel_info.vOver_plus & 0xfff) | + (vsync_wid << 16) | (v_sync_pol << 23)); + } + + /* do it! */ + if (!rinfo->asleep) { + memcpy(&rinfo->state, newmode, sizeof(*newmode)); + radeon_write_mode (rinfo, newmode, 0); + /* (re)initialize the engine */ + if (!(info->flags & FBINFO_HWACCEL_DISABLED)) + radeonfb_engine_init (rinfo); + } + /* Update fix */ + if (!(info->flags & FBINFO_HWACCEL_DISABLED)) + info->fix.line_length = rinfo->pitch*64; + else + info->fix.line_length = mode->xres_virtual + * ((mode->bits_per_pixel + 1) / 8); + info->fix.visual = rinfo->depth == 8 ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_DIRECTCOLOR; + +#ifdef CONFIG_BOOTX_TEXT + /* Update debug text engine */ + btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres, + rinfo->depth, info->fix.line_length); +#endif + + kfree(newmode); + return 0; +} + + +static struct fb_ops radeonfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = radeonfb_check_var, + .fb_set_par = radeonfb_set_par, + .fb_setcolreg = radeonfb_setcolreg, + .fb_pan_display = radeonfb_pan_display, + .fb_blank = radeonfb_blank, + .fb_ioctl = radeonfb_ioctl, + .fb_sync = radeonfb_sync, + .fb_fillrect = radeonfb_fillrect, + .fb_copyarea = radeonfb_copyarea, + .fb_imageblit = radeonfb_imageblit, + .fb_cursor = soft_cursor, +}; + + +static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo) +{ + struct fb_info *info = rinfo->info; + + info->par = rinfo; + info->pseudo_palette = rinfo->pseudo_palette; + info->flags = FBINFO_DEFAULT + | FBINFO_HWACCEL_COPYAREA + | FBINFO_HWACCEL_FILLRECT + | FBINFO_HWACCEL_XPAN + | FBINFO_HWACCEL_YPAN; + info->fbops = &radeonfb_ops; + info->screen_base = rinfo->fb_base; + info->screen_size = rinfo->mapped_vram; + /* Fill fix common fields */ + strlcpy(info->fix.id, rinfo->name, sizeof(info->fix.id)); + info->fix.smem_start = rinfo->fb_base_phys; + info->fix.smem_len = rinfo->video_ram; + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.xpanstep = 8; + info->fix.ypanstep = 1; + info->fix.ywrapstep = 0; + info->fix.type_aux = 0; + info->fix.mmio_start = rinfo->mmio_base_phys; + info->fix.mmio_len = RADEON_REGSIZE; + info->fix.accel = FB_ACCEL_ATI_RADEON; + + fb_alloc_cmap(&info->cmap, 256, 0); + + if (noaccel) + info->flags |= FBINFO_HWACCEL_DISABLED; + + return 0; +} + + +#ifdef CONFIG_PMAC_BACKLIGHT + +/* TODO: Dbl check these tables, we don't go up to full ON backlight + * in these, possibly because we noticed MacOS doesn't, but I'd prefer + * having some more official numbers from ATI + */ +static int backlight_conv_m6[] = { + 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, + 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 +}; +static int backlight_conv_m7[] = { + 0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81, + 0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9 +}; + +#define BACKLIGHT_LVDS_OFF +#undef BACKLIGHT_DAC_OFF + +/* We turn off the LCD completely instead of just dimming the backlight. + * This provides some greater power saving and the display is useless + * without backlight anyway. + */ +static int radeon_set_backlight_enable(int on, int level, void *data) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *)data; + u32 lvds_gen_cntl, tmpPixclksCntl; + int* conv_table; + + if (rinfo->mon1_type != MT_LCD) + return 0; + + /* Pardon me for that hack... maybe some day we can figure + * out in what direction backlight should work on a given + * panel ? + */ + if ((rinfo->family == CHIP_FAMILY_RV200 || + rinfo->family == CHIP_FAMILY_RV250 || + rinfo->family == CHIP_FAMILY_RV280 || + rinfo->family == CHIP_FAMILY_RV350) && + !machine_is_compatible("PowerBook4,3") && + !machine_is_compatible("PowerBook6,3") && + !machine_is_compatible("PowerBook6,5")) + conv_table = backlight_conv_m7; + else + conv_table = backlight_conv_m6; + + del_timer_sync(&rinfo->lvds_timer); + radeon_engine_idle(); + + lvds_gen_cntl = INREG(LVDS_GEN_CNTL); + if (on && (level > BACKLIGHT_OFF)) { + lvds_gen_cntl &= ~LVDS_DISPLAY_DIS; + if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) { + lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON); + lvds_gen_cntl |= LVDS_BLON | LVDS_EN; + OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); + lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; + lvds_gen_cntl |= (conv_table[level] << + LVDS_BL_MOD_LEVEL_SHIFT); + lvds_gen_cntl |= LVDS_ON; + lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN); + rinfo->pending_lvds_gen_cntl = lvds_gen_cntl; + mod_timer(&rinfo->lvds_timer, + jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); + } else { + lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; + lvds_gen_cntl |= (conv_table[level] << + LVDS_BL_MOD_LEVEL_SHIFT); + OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); + } + rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; + rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl + & LVDS_STATE_MASK; + } else { + /* Asic bug, when turning off LVDS_ON, we have to make sure + RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off + */ + tmpPixclksCntl = INPLL(PIXCLKS_CNTL); + if (rinfo->is_mobility || rinfo->is_IGP) + OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb); + lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN); + lvds_gen_cntl |= (conv_table[0] << + LVDS_BL_MOD_LEVEL_SHIFT); + lvds_gen_cntl |= LVDS_DISPLAY_DIS; + OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); + udelay(100); + lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN); + OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); + lvds_gen_cntl &= ~(LVDS_DIGON); + rinfo->pending_lvds_gen_cntl = lvds_gen_cntl; + mod_timer(&rinfo->lvds_timer, + jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); + if (rinfo->is_mobility || rinfo->is_IGP) + OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl); + } + rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; + rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK); + + return 0; +} + + +static int radeon_set_backlight_level(int level, void *data) +{ + return radeon_set_backlight_enable(1, level, data); +} +#endif /* CONFIG_PMAC_BACKLIGHT */ + + +/* + * This reconfigure the card's internal memory map. In theory, we'd like + * to setup the card's memory at the same address as it's PCI bus address, + * and the AGP aperture right after that so that system RAM on 32 bits + * machines at least, is directly accessible. However, doing so would + * conflict with the current XFree drivers... + * Ultimately, I hope XFree, GATOS and ATI binary drivers will all agree + * on the proper way to set this up and duplicate this here. In the meantime, + * I put the card's memory at 0 in card space and AGP at some random high + * local (0xe0000000 for now) that will be changed by XFree/DRI anyway + */ +#ifdef CONFIG_PPC_OF +#undef SET_MC_FB_FROM_APERTURE +static void fixup_memory_mappings(struct radeonfb_info *rinfo) +{ + u32 save_crtc_gen_cntl, save_crtc2_gen_cntl = 0; + u32 save_crtc_ext_cntl; + u32 aper_base, aper_size; + u32 agp_base; + + /* First, we disable display to avoid interfering */ + if (rinfo->has_CRTC2) { + save_crtc2_gen_cntl = INREG(CRTC2_GEN_CNTL); + OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl | CRTC2_DISP_REQ_EN_B); + } + save_crtc_gen_cntl = INREG(CRTC_GEN_CNTL); + save_crtc_ext_cntl = INREG(CRTC_EXT_CNTL); + + OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl | CRTC_DISPLAY_DIS); + OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl | CRTC_DISP_REQ_EN_B); + mdelay(100); + + aper_base = INREG(CONFIG_APER_0_BASE); + aper_size = INREG(CONFIG_APER_SIZE); + +#ifdef SET_MC_FB_FROM_APERTURE + /* Set framebuffer to be at the same address as set in PCI BAR */ + OUTREG(MC_FB_LOCATION, + ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16)); + rinfo->fb_local_base = aper_base; +#else + OUTREG(MC_FB_LOCATION, 0x7fff0000); + rinfo->fb_local_base = 0; +#endif + agp_base = aper_base + aper_size; + if (agp_base & 0xf0000000) + agp_base = (aper_base | 0x0fffffff) + 1; + + /* Set AGP to be just after the framebuffer on a 256Mb boundary. This + * assumes the FB isn't mapped to 0xf0000000 or above, but this is + * always the case on PPCs afaik. + */ +#ifdef SET_MC_FB_FROM_APERTURE + OUTREG(MC_AGP_LOCATION, 0xffff0000 | (agp_base >> 16)); +#else + OUTREG(MC_AGP_LOCATION, 0xffffe000); +#endif + + /* Fixup the display base addresses & engine offsets while we + * are at it as well + */ +#ifdef SET_MC_FB_FROM_APERTURE + OUTREG(DISPLAY_BASE_ADDR, aper_base); + if (rinfo->has_CRTC2) + OUTREG(CRTC2_DISPLAY_BASE_ADDR, aper_base); + OUTREG(OV0_BASE_ADDR, aper_base); +#else + OUTREG(DISPLAY_BASE_ADDR, 0); + if (rinfo->has_CRTC2) + OUTREG(CRTC2_DISPLAY_BASE_ADDR, 0); + OUTREG(OV0_BASE_ADDR, 0); +#endif + mdelay(100); + + /* Restore display settings */ + OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl); + OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl); + if (rinfo->has_CRTC2) + OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl); + + RTRACE("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n", + aper_base, + ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16), + 0xffff0000 | (agp_base >> 16)); +} +#endif /* CONFIG_PPC_OF */ + + +static void radeon_identify_vram(struct radeonfb_info *rinfo) +{ + u32 tmp; + + /* framebuffer size */ + if ((rinfo->family == CHIP_FAMILY_RS100) || + (rinfo->family == CHIP_FAMILY_RS200) || + (rinfo->family == CHIP_FAMILY_RS300)) { + u32 tom = INREG(NB_TOM); + tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024); + + radeon_fifo_wait(6); + OUTREG(MC_FB_LOCATION, tom); + OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16); + OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16); + OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16); + + /* This is supposed to fix the crtc2 noise problem. */ + OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000); + + if ((rinfo->family == CHIP_FAMILY_RS100) || + (rinfo->family == CHIP_FAMILY_RS200)) { + /* This is to workaround the asic bug for RMX, some versions + of BIOS dosen't have this register initialized correctly. + */ + OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN, + ~CRTC_H_CUTOFF_ACTIVE_EN); + } + } else { + tmp = INREG(CONFIG_MEMSIZE); + } + + /* mem size is bits [28:0], mask off the rest */ + rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK; + + /* + * Hack to get around some busted production M6's + * reporting no ram + */ + if (rinfo->video_ram == 0) { + switch (rinfo->pdev->device) { + case PCI_CHIP_RADEON_LY: + case PCI_CHIP_RADEON_LZ: + rinfo->video_ram = 8192 * 1024; + break; + default: + break; + } + } + + + /* + * Now try to identify VRAM type + */ + if (rinfo->is_IGP || (rinfo->family >= CHIP_FAMILY_R300) || + (INREG(MEM_SDRAM_MODE_REG) & (1<<30))) + rinfo->vram_ddr = 1; + else + rinfo->vram_ddr = 0; + + tmp = INREG(MEM_CNTL); + if (IS_R300_VARIANT(rinfo)) { + tmp &= R300_MEM_NUM_CHANNELS_MASK; + switch (tmp) { + case 0: rinfo->vram_width = 64; break; + case 1: rinfo->vram_width = 128; break; + case 2: rinfo->vram_width = 256; break; + default: rinfo->vram_width = 128; break; + } + } else if ((rinfo->family == CHIP_FAMILY_RV100) || + (rinfo->family == CHIP_FAMILY_RS100) || + (rinfo->family == CHIP_FAMILY_RS200)){ + if (tmp & RV100_MEM_HALF_MODE) + rinfo->vram_width = 32; + else + rinfo->vram_width = 64; + } else { + if (tmp & MEM_NUM_CHANNELS_MASK) + rinfo->vram_width = 128; + else + rinfo->vram_width = 64; + } + + /* This may not be correct, as some cards can have half of channel disabled + * ToDo: identify these cases + */ + + RTRACE("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n", + pci_name(rinfo->pdev), + rinfo->video_ram / 1024, + rinfo->vram_ddr ? "DDR" : "SDRAM", + rinfo->vram_width); +} + +/* + * Sysfs + */ + +static ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u8 *edid) +{ + if (off > EDID_LENGTH) + return 0; + + if (off + count > EDID_LENGTH) + count = EDID_LENGTH - off; + + memcpy(buf, edid + off, count); + + return count; +} + + +static ssize_t radeon_show_edid1(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct pci_dev *pdev = to_pci_dev(dev); + struct fb_info *info = pci_get_drvdata(pdev); + struct radeonfb_info *rinfo = info->par; + + return radeon_show_one_edid(buf, off, count, rinfo->mon1_EDID); +} + + +static ssize_t radeon_show_edid2(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct pci_dev *pdev = to_pci_dev(dev); + struct fb_info *info = pci_get_drvdata(pdev); + struct radeonfb_info *rinfo = info->par; + + return radeon_show_one_edid(buf, off, count, rinfo->mon2_EDID); +} + +static struct bin_attribute edid1_attr = { + .attr = { + .name = "edid1", + .owner = THIS_MODULE, + .mode = 0444, + }, + .size = EDID_LENGTH, + .read = radeon_show_edid1, +}; + +static struct bin_attribute edid2_attr = { + .attr = { + .name = "edid2", + .owner = THIS_MODULE, + .mode = 0444, + }, + .size = EDID_LENGTH, + .read = radeon_show_edid2, +}; + + +static int radeonfb_pci_register (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct fb_info *info; + struct radeonfb_info *rinfo; + int ret; + + RTRACE("radeonfb_pci_register BEGIN\n"); + + /* Enable device in PCI config */ + ret = pci_enable_device(pdev); + if (ret < 0) { + printk(KERN_ERR "radeonfb (%s): Cannot enable PCI device\n", + pci_name(pdev)); + goto err_out; + } + + info = framebuffer_alloc(sizeof(struct radeonfb_info), &pdev->dev); + if (!info) { + printk (KERN_ERR "radeonfb (%s): could not allocate memory\n", + pci_name(pdev)); + ret = -ENOMEM; + goto err_disable; + } + rinfo = info->par; + rinfo->info = info; + rinfo->pdev = pdev; + + spin_lock_init(&rinfo->reg_lock); + init_timer(&rinfo->lvds_timer); + rinfo->lvds_timer.function = radeon_lvds_timer_func; + rinfo->lvds_timer.data = (unsigned long)rinfo; + + strcpy(rinfo->name, "ATI Radeon XX "); + rinfo->name[11] = ent->device >> 8; + rinfo->name[12] = ent->device & 0xFF; + rinfo->family = ent->driver_data & CHIP_FAMILY_MASK; + rinfo->chipset = pdev->device; + rinfo->has_CRTC2 = (ent->driver_data & CHIP_HAS_CRTC2) != 0; + rinfo->is_mobility = (ent->driver_data & CHIP_IS_MOBILITY) != 0; + rinfo->is_IGP = (ent->driver_data & CHIP_IS_IGP) != 0; + + /* Set base addrs */ + rinfo->fb_base_phys = pci_resource_start (pdev, 0); + rinfo->mmio_base_phys = pci_resource_start (pdev, 2); + + /* request the mem regions */ + ret = pci_request_regions(pdev, "radeonfb"); + if (ret < 0) { + printk( KERN_ERR "radeonfb (%s): cannot reserve PCI regions." + " Someone already got them?\n", pci_name(rinfo->pdev)); + goto err_release_fb; + } + + /* map the regions */ + rinfo->mmio_base = ioremap(rinfo->mmio_base_phys, RADEON_REGSIZE); + if (!rinfo->mmio_base) { + printk(KERN_ERR "radeonfb (%s): cannot map MMIO\n", pci_name(rinfo->pdev)); + ret = -EIO; + goto err_release_pci; + } + + rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16; + + /* + * Check for errata + */ + rinfo->errata = 0; + if (rinfo->family == CHIP_FAMILY_R300 && + (INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) + == CFG_ATI_REV_A11) + rinfo->errata |= CHIP_ERRATA_R300_CG; + + if (rinfo->family == CHIP_FAMILY_RV200 || + rinfo->family == CHIP_FAMILY_RS200) + rinfo->errata |= CHIP_ERRATA_PLL_DUMMYREADS; + + if (rinfo->family == CHIP_FAMILY_RV100 || + rinfo->family == CHIP_FAMILY_RS100 || + rinfo->family == CHIP_FAMILY_RS200) + rinfo->errata |= CHIP_ERRATA_PLL_DELAY; + +#ifdef CONFIG_PPC_OF + /* On PPC, we obtain the OF device-node pointer to the firmware + * data for this chip + */ + rinfo->of_node = pci_device_to_OF_node(pdev); + if (rinfo->of_node == NULL) + printk(KERN_WARNING "radeonfb (%s): Cannot match card to OF node !\n", + pci_name(rinfo->pdev)); + + /* On PPC, the firmware sets up a memory mapping that tends + * to cause lockups when enabling the engine. We reconfigure + * the card internal memory mappings properly + */ + fixup_memory_mappings(rinfo); +#endif /* CONFIG_PPC_OF */ + + /* Get VRAM size and type */ + radeon_identify_vram(rinfo); + + rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM, rinfo->video_ram); + + do { + rinfo->fb_base = ioremap (rinfo->fb_base_phys, + rinfo->mapped_vram); + } while ( rinfo->fb_base == 0 && + ((rinfo->mapped_vram /=2) >= MIN_MAPPED_VRAM) ); + + if (rinfo->fb_base) + memset_io(rinfo->fb_base, 0, rinfo->mapped_vram); + else { + printk (KERN_ERR "radeonfb (%s): cannot map FB\n", pci_name(rinfo->pdev)); + ret = -EIO; + goto err_unmap_rom; + } + + RTRACE("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev), + rinfo->mapped_vram/1024); + + /* + * Map the BIOS ROM if any and retreive PLL parameters from + * the BIOS. We skip that on mobility chips as the real panel + * values we need aren't in the ROM but in the BIOS image in + * memory. This is definitely not the best meacnism though, + * we really need the arch code to tell us which is the "primary" + * video adapter to use the memory image (or better, the arch + * should provide us a copy of the BIOS image to shield us from + * archs who would store that elsewhere and/or could initialize + * more than one adapter during boot). + */ + if (!rinfo->is_mobility) + radeon_map_ROM(rinfo, pdev); + + /* + * On x86, the primary display on laptop may have it's BIOS + * ROM elsewhere, try to locate it at the legacy memory hole. + * We probably need to make sure this is the primary display, + * but that is difficult without some arch support. + */ +#ifdef CONFIG_X86 + if (rinfo->bios_seg == NULL) + radeon_find_mem_vbios(rinfo); +#endif + + /* If both above failed, try the BIOS ROM again for mobility + * chips + */ + if (rinfo->bios_seg == NULL && rinfo->is_mobility) + radeon_map_ROM(rinfo, pdev); + + /* Get informations about the board's PLL */ + radeon_get_pllinfo(rinfo); + +#ifdef CONFIG_FB_RADEON_I2C + /* Register I2C bus */ + radeon_create_i2c_busses(rinfo); +#endif + + /* set all the vital stuff */ + radeon_set_fbinfo (rinfo); + + /* Probe screen types */ + radeon_probe_screens(rinfo, monitor_layout, ignore_edid); + + /* Build mode list, check out panel native model */ + radeon_check_modes(rinfo, mode_option); + + /* Register some sysfs stuff (should be done better) */ + if (rinfo->mon1_EDID) + sysfs_create_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr); + if (rinfo->mon2_EDID) + sysfs_create_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr); + + /* save current mode regs before we switch into the new one + * so we can restore this upon __exit + */ + radeon_save_state (rinfo, &rinfo->init_state); + memcpy(&rinfo->state, &rinfo->init_state, sizeof(struct radeon_regs)); + + /* Setup Power Management capabilities */ + if (default_dynclk < -1) { + /* -2 is special: means ON on mobility chips and do not + * change on others + */ + radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1); + } else + radeonfb_pm_init(rinfo, default_dynclk); + + pci_set_drvdata(pdev, info); + + /* Register with fbdev layer */ + ret = register_framebuffer(info); + if (ret < 0) { + printk (KERN_ERR "radeonfb (%s): could not register framebuffer\n", + pci_name(rinfo->pdev)); + goto err_unmap_fb; + } + +#ifdef CONFIG_MTRR + rinfo->mtrr_hdl = nomtrr ? -1 : mtrr_add(rinfo->fb_base_phys, + rinfo->video_ram, + MTRR_TYPE_WRCOMB, 1); +#endif + +#ifdef CONFIG_PMAC_BACKLIGHT + if (rinfo->mon1_type == MT_LCD) { + register_backlight_controller(&radeon_backlight_controller, + rinfo, "ati"); + register_backlight_controller(&radeon_backlight_controller, + rinfo, "mnca"); + } +#endif + + printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name); + + if (rinfo->bios_seg) + radeon_unmap_ROM(rinfo, pdev); + RTRACE("radeonfb_pci_register END\n"); + + return 0; +err_unmap_fb: + iounmap(rinfo->fb_base); +err_unmap_rom: + kfree(rinfo->mon1_EDID); + kfree(rinfo->mon2_EDID); + if (rinfo->mon1_modedb) + fb_destroy_modedb(rinfo->mon1_modedb); + fb_dealloc_cmap(&info->cmap); +#ifdef CONFIG_FB_RADEON_I2C + radeon_delete_i2c_busses(rinfo); +#endif + if (rinfo->bios_seg) + radeon_unmap_ROM(rinfo, pdev); + iounmap(rinfo->mmio_base); +err_release_pci: + pci_release_regions(pdev); +err_release_fb: + framebuffer_release(info); +err_disable: + pci_disable_device(pdev); +err_out: + return ret; +} + + + +static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct radeonfb_info *rinfo = info->par; + + if (!rinfo) + return; + + radeonfb_pm_exit(rinfo); + +#if 0 + /* restore original state + * + * Doesn't quite work yet, I suspect if we come from a legacy + * VGA mode (or worse, text mode), we need to do some VGA black + * magic here that I know nothing about. --BenH + */ + radeon_write_mode (rinfo, &rinfo->init_state, 1); + #endif + + del_timer_sync(&rinfo->lvds_timer); + +#ifdef CONFIG_MTRR + if (rinfo->mtrr_hdl >= 0) + mtrr_del(rinfo->mtrr_hdl, 0, 0); +#endif + + unregister_framebuffer(info); + + iounmap(rinfo->mmio_base); + iounmap(rinfo->fb_base); + + pci_release_regions(pdev); + + kfree(rinfo->mon1_EDID); + kfree(rinfo->mon2_EDID); + if (rinfo->mon1_modedb) + fb_destroy_modedb(rinfo->mon1_modedb); +#ifdef CONFIG_FB_RADEON_I2C + radeon_delete_i2c_busses(rinfo); +#endif + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + pci_disable_device(pdev); +} + + +static struct pci_driver radeonfb_driver = { + .name = "radeonfb", + .id_table = radeonfb_pci_table, + .probe = radeonfb_pci_register, + .remove = __devexit_p(radeonfb_pci_unregister), +#ifdef CONFIG_PM + .suspend = radeonfb_pci_suspend, + .resume = radeonfb_pci_resume, +#endif /* CONFIG_PM */ +}; + +#ifndef MODULE +static int __init radeonfb_setup (char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep (&options, ",")) != NULL) { + if (!*this_opt) + continue; + + if (!strncmp(this_opt, "noaccel", 7)) { + noaccel = 1; + } else if (!strncmp(this_opt, "mirror", 6)) { + mirror = 1; + } else if (!strncmp(this_opt, "force_dfp", 9)) { + force_dfp = 1; + } else if (!strncmp(this_opt, "panel_yres:", 11)) { + panel_yres = simple_strtoul((this_opt+11), NULL, 0); +#ifdef CONFIG_MTRR + } else if (!strncmp(this_opt, "nomtrr", 6)) { + nomtrr = 1; +#endif + } else if (!strncmp(this_opt, "nomodeset", 9)) { + nomodeset = 1; + } else if (!strncmp(this_opt, "force_measure_pll", 17)) { + force_measure_pll = 1; + } else if (!strncmp(this_opt, "ignore_edid", 11)) { + ignore_edid = 1; + } else + mode_option = this_opt; + } + return 0; +} +#endif /* MODULE */ + +static int __init radeonfb_init (void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("radeonfb", &option)) + return -ENODEV; + radeonfb_setup(option); +#endif + return pci_register_driver (&radeonfb_driver); +} + + +static void __exit radeonfb_exit (void) +{ + pci_unregister_driver (&radeonfb_driver); +} + +module_init(radeonfb_init); +module_exit(radeonfb_exit); + +MODULE_AUTHOR("Ani Joshi"); +MODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset"); +MODULE_LICENSE("GPL"); +module_param(noaccel, bool, 0); +module_param(default_dynclk, int, 0); +MODULE_PARM_DESC(default_dynclk, "int: -2=enable on mobility only,-1=do not change,0=off,1=on"); +MODULE_PARM_DESC(noaccel, "bool: disable acceleration"); +module_param(nomodeset, bool, 0); +MODULE_PARM_DESC(nomodeset, "bool: disable actual setting of video mode"); +module_param(mirror, bool, 0); +MODULE_PARM_DESC(mirror, "bool: mirror the display to both monitors"); +module_param(force_dfp, bool, 0); +MODULE_PARM_DESC(force_dfp, "bool: force display to dfp"); +module_param(ignore_edid, bool, 0); +MODULE_PARM_DESC(ignore_edid, "bool: Ignore EDID data when doing DDC probe"); +module_param(monitor_layout, charp, 0); +MODULE_PARM_DESC(monitor_layout, "Specify monitor mapping (like XFree86)"); +module_param(force_measure_pll, bool, 0); +MODULE_PARM_DESC(force_measure_pll, "Force measurement of PLL (debug)"); +#ifdef CONFIG_MTRR +module_param(nomtrr, bool, 0); +MODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers"); +#endif +module_param(panel_yres, int, 0); +MODULE_PARM_DESC(panel_yres, "int: set panel yres"); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c new file mode 100644 index 000000000000..762244164c81 --- /dev/null +++ b/drivers/video/aty/radeon_i2c.c @@ -0,0 +1,265 @@ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/fb.h> + + +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/i2c-algo-bit.h> + +#include <asm/io.h> + +#include <video/radeon.h> +#include "radeonfb.h" +#include "../edid.h" + +#define RADEON_DDC 0x50 + +static void radeon_gpio_setscl(void* data, int state) +{ + struct radeon_i2c_chan *chan = data; + struct radeonfb_info *rinfo = chan->rinfo; + u32 val; + + val = INREG(chan->ddc_reg) & ~(VGA_DDC_CLK_OUT_EN); + if (!state) + val |= VGA_DDC_CLK_OUT_EN; + + OUTREG(chan->ddc_reg, val); + (void)INREG(chan->ddc_reg); +} + +static void radeon_gpio_setsda(void* data, int state) +{ + struct radeon_i2c_chan *chan = data; + struct radeonfb_info *rinfo = chan->rinfo; + u32 val; + + val = INREG(chan->ddc_reg) & ~(VGA_DDC_DATA_OUT_EN); + if (!state) + val |= VGA_DDC_DATA_OUT_EN; + + OUTREG(chan->ddc_reg, val); + (void)INREG(chan->ddc_reg); +} + +static int radeon_gpio_getscl(void* data) +{ + struct radeon_i2c_chan *chan = data; + struct radeonfb_info *rinfo = chan->rinfo; + u32 val; + + val = INREG(chan->ddc_reg); + + return (val & VGA_DDC_CLK_INPUT) ? 1 : 0; +} + +static int radeon_gpio_getsda(void* data) +{ + struct radeon_i2c_chan *chan = data; + struct radeonfb_info *rinfo = chan->rinfo; + u32 val; + + val = INREG(chan->ddc_reg); + + return (val & VGA_DDC_DATA_INPUT) ? 1 : 0; +} + +static int radeon_setup_i2c_bus(struct radeon_i2c_chan *chan, const char *name) +{ + int rc; + + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_ALGO_ATI; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->rinfo->pdev->dev; + chan->algo.setsda = radeon_gpio_setsda; + chan->algo.setscl = radeon_gpio_setscl; + chan->algo.getsda = radeon_gpio_getsda; + chan->algo.getscl = radeon_gpio_getscl; + chan->algo.udelay = 40; + chan->algo.timeout = 20; + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + /* Raise SCL and SDA */ + radeon_gpio_setsda(chan, 1); + radeon_gpio_setscl(chan, 1); + udelay(20); + + rc = i2c_bit_add_bus(&chan->adapter); + if (rc == 0) + dev_dbg(&chan->rinfo->pdev->dev, "I2C bus %s registered.\n", name); + else + dev_warn(&chan->rinfo->pdev->dev, "Failed to register I2C bus %s.\n", name); + return rc; +} + +void radeon_create_i2c_busses(struct radeonfb_info *rinfo) +{ + rinfo->i2c[0].rinfo = rinfo; + rinfo->i2c[0].ddc_reg = GPIO_MONID; + radeon_setup_i2c_bus(&rinfo->i2c[0], "monid"); + + rinfo->i2c[1].rinfo = rinfo; + rinfo->i2c[1].ddc_reg = GPIO_DVI_DDC; + radeon_setup_i2c_bus(&rinfo->i2c[1], "dvi"); + + rinfo->i2c[2].rinfo = rinfo; + rinfo->i2c[2].ddc_reg = GPIO_VGA_DDC; + radeon_setup_i2c_bus(&rinfo->i2c[2], "vga"); + + rinfo->i2c[3].rinfo = rinfo; + rinfo->i2c[3].ddc_reg = GPIO_CRT2_DDC; + radeon_setup_i2c_bus(&rinfo->i2c[3], "crt2"); +} + +void radeon_delete_i2c_busses(struct radeonfb_info *rinfo) +{ + if (rinfo->i2c[0].rinfo) + i2c_bit_del_bus(&rinfo->i2c[0].adapter); + rinfo->i2c[0].rinfo = NULL; + + if (rinfo->i2c[1].rinfo) + i2c_bit_del_bus(&rinfo->i2c[1].adapter); + rinfo->i2c[1].rinfo = NULL; + + if (rinfo->i2c[2].rinfo) + i2c_bit_del_bus(&rinfo->i2c[2].adapter); + rinfo->i2c[2].rinfo = NULL; + + if (rinfo->i2c[3].rinfo) + i2c_bit_del_bus(&rinfo->i2c[3].adapter); + rinfo->i2c[3].rinfo = NULL; +} + + +static u8 *radeon_do_probe_i2c_edid(struct radeon_i2c_chan *chan) +{ + u8 start = 0x0; + struct i2c_msg msgs[] = { + { + .addr = RADEON_DDC, + .len = 1, + .buf = &start, + }, { + .addr = RADEON_DDC, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + }, + }; + u8 *buf; + + buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!buf) { + dev_warn(&chan->rinfo->pdev->dev, "Out of memory!\n"); + return NULL; + } + msgs[1].buf = buf; + + if (i2c_transfer(&chan->adapter, msgs, 2) == 2) + return buf; + dev_dbg(&chan->rinfo->pdev->dev, "Unable to read EDID block.\n"); + kfree(buf); + return NULL; +} + + +int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid) +{ + u32 reg = rinfo->i2c[conn-1].ddc_reg; + u8 *edid = NULL; + int i, j; + + OUTREG(reg, INREG(reg) & + ~(VGA_DDC_DATA_OUTPUT | VGA_DDC_CLK_OUTPUT)); + + OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN)); + (void)INREG(reg); + + for (i = 0; i < 3; i++) { + /* For some old monitors we need the + * following process to initialize/stop DDC + */ + OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN)); + (void)INREG(reg); + msleep(13); + + OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN)); + (void)INREG(reg); + for (j = 0; j < 5; j++) { + msleep(10); + if (INREG(reg) & VGA_DDC_CLK_INPUT) + break; + } + if (j == 5) + continue; + + OUTREG(reg, INREG(reg) | VGA_DDC_DATA_OUT_EN); + (void)INREG(reg); + msleep(15); + OUTREG(reg, INREG(reg) | VGA_DDC_CLK_OUT_EN); + (void)INREG(reg); + msleep(15); + OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN)); + (void)INREG(reg); + msleep(15); + + /* Do the real work */ + edid = radeon_do_probe_i2c_edid(&rinfo->i2c[conn-1]); + + OUTREG(reg, INREG(reg) | + (VGA_DDC_DATA_OUT_EN | VGA_DDC_CLK_OUT_EN)); + (void)INREG(reg); + msleep(15); + + OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN)); + (void)INREG(reg); + for (j = 0; j < 10; j++) { + msleep(10); + if (INREG(reg) & VGA_DDC_CLK_INPUT) + break; + } + + OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN)); + (void)INREG(reg); + msleep(15); + OUTREG(reg, INREG(reg) | + (VGA_DDC_DATA_OUT_EN | VGA_DDC_CLK_OUT_EN)); + (void)INREG(reg); + if (edid) + break; + } + /* Release the DDC lines when done or the Apple Cinema HD display + * will switch off + */ + OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN | VGA_DDC_DATA_OUT_EN)); + (void)INREG(reg); + + if (out_edid) + *out_edid = edid; + if (!edid) { + RTRACE("radeonfb: I2C (port %d) ... not found\n", conn); + return MT_NONE; + } + if (edid[0x14] & 0x80) { + /* Fix detection using BIOS tables */ + if (rinfo->is_mobility /*&& conn == ddc_dvi*/ && + (INREG(LVDS_GEN_CNTL) & LVDS_ON)) { + RTRACE("radeonfb: I2C (port %d) ... found LVDS panel\n", conn); + return MT_LCD; + } else { + RTRACE("radeonfb: I2C (port %d) ... found TMDS panel\n", conn); + return MT_DFP; + } + } + RTRACE("radeonfb: I2C (port %d) ... found CRT display\n", conn); + return MT_CRT; +} + diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c new file mode 100644 index 000000000000..ea7c86306918 --- /dev/null +++ b/drivers/video/aty/radeon_monitor.c @@ -0,0 +1,1010 @@ +#include "radeonfb.h" +#include "../edid.h" + +static struct fb_var_screeninfo radeonfb_default_var = { + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 480, + .bits_per_pixel = 8, + .red = { .length = 8 }, + .green = { .length = 8 }, + .blue = { .length = 8 }, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .pixclock = 39721, + .left_margin = 40, + .right_margin = 24, + .upper_margin = 32, + .lower_margin = 11, + .hsync_len = 96, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED +}; + +static char *radeon_get_mon_name(int type) +{ + char *pret = NULL; + + switch (type) { + case MT_NONE: + pret = "no"; + break; + case MT_CRT: + pret = "CRT"; + break; + case MT_DFP: + pret = "DFP"; + break; + case MT_LCD: + pret = "LCD"; + break; + case MT_CTV: + pret = "CTV"; + break; + case MT_STV: + pret = "STV"; + break; + } + + return pret; +} + + +#ifdef CONFIG_PPC_OF +/* + * Try to find monitor informations & EDID data out of the Open Firmware + * device-tree. This also contains some "hacks" to work around a few machine + * models with broken OF probing by hard-coding known EDIDs for some Mac + * laptops internal LVDS panel. (XXX: not done yet) + */ +static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_EDID, + int hdno) +{ + static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", + "EDID1", "EDID2", NULL }; + u8 *pedid = NULL; + u8 *pmt = NULL; + u8 *tmp; + int i, mt = MT_NONE; + + RTRACE("analyzing OF properties...\n"); + pmt = (u8 *)get_property(dp, "display-type", NULL); + if (!pmt) + return MT_NONE; + RTRACE("display-type: %s\n", pmt); + /* OF says "LCD" for DFP as well, we discriminate from the caller of this + * function + */ + if (!strcmp(pmt, "LCD") || !strcmp(pmt, "DFP")) + mt = MT_DFP; + else if (!strcmp(pmt, "CRT")) + mt = MT_CRT; + else { + if (strcmp(pmt, "NONE") != 0) + printk(KERN_WARNING "radeonfb: Unknown OF display-type: %s\n", + pmt); + return MT_NONE; + } + + for (i = 0; propnames[i] != NULL; ++i) { + pedid = (u8 *)get_property(dp, propnames[i], NULL); + if (pedid != NULL) + break; + } + /* We didn't find the EDID in the leaf node, some cards will actually + * put EDID1/EDID2 in the parent, look for these (typically M6 tipb). + * single-head cards have hdno == -1 and skip this step + */ + if (pedid == NULL && dp->parent && (hdno != -1)) + pedid = get_property(dp->parent, (hdno == 0) ? "EDID1" : "EDID2", NULL); + if (pedid == NULL && dp->parent && (hdno == 0)) + pedid = get_property(dp->parent, "EDID", NULL); + if (pedid == NULL) + return mt; + + tmp = (u8 *)kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!tmp) + return mt; + memcpy(tmp, pedid, EDID_LENGTH); + *out_EDID = tmp; + return mt; +} + +static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_no, + u8 **out_EDID) +{ + struct device_node *dp; + + RTRACE("radeon_probe_OF_head\n"); + + dp = rinfo->of_node; + while (dp == NULL) + return MT_NONE; + + if (rinfo->has_CRTC2) { + char *pname; + int len, second = 0; + + dp = dp->child; + do { + if (!dp) + return MT_NONE; + pname = (char *)get_property(dp, "name", NULL); + if (!pname) + return MT_NONE; + len = strlen(pname); + RTRACE("head: %s (letter: %c, head_no: %d)\n", + pname, pname[len-1], head_no); + if (pname[len-1] == 'A' && head_no == 0) { + int mt = radeon_parse_montype_prop(dp, out_EDID, 0); + /* Maybe check for LVDS_GEN_CNTL here ? I need to check out + * what OF does when booting with lid closed + */ + if (mt == MT_DFP && rinfo->is_mobility) + mt = MT_LCD; + return mt; + } else if (pname[len-1] == 'B' && head_no == 1) + return radeon_parse_montype_prop(dp, out_EDID, 1); + second = 1; + dp = dp->sibling; + } while(!second); + } else { + if (head_no > 0) + return MT_NONE; + return radeon_parse_montype_prop(dp, out_EDID, -1); + } + return MT_NONE; +} +#endif /* CONFIG_PPC_OF */ + + +static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) +{ + unsigned long tmp, tmp0; + char stmp[30]; + int i; + + if (!rinfo->bios_seg) + return 0; + + if (!(tmp = BIOS_IN16(rinfo->fp_bios_start + 0x40))) { + printk(KERN_ERR "radeonfb: Failed to detect DFP panel info using BIOS\n"); + rinfo->panel_info.pwr_delay = 200; + return 0; + } + + for(i=0; i<24; i++) + stmp[i] = BIOS_IN8(tmp+i+1); + stmp[24] = 0; + printk("radeonfb: panel ID string: %s\n", stmp); + rinfo->panel_info.xres = BIOS_IN16(tmp + 25); + rinfo->panel_info.yres = BIOS_IN16(tmp + 27); + printk("radeonfb: detected LVDS panel size from BIOS: %dx%d\n", + rinfo->panel_info.xres, rinfo->panel_info.yres); + + rinfo->panel_info.pwr_delay = BIOS_IN16(tmp + 44); + RTRACE("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay); + if (rinfo->panel_info.pwr_delay > 2000 || rinfo->panel_info.pwr_delay <= 0) + rinfo->panel_info.pwr_delay = 2000; + + /* + * Some panels only work properly with some divider combinations + */ + rinfo->panel_info.ref_divider = BIOS_IN16(tmp + 46); + rinfo->panel_info.post_divider = BIOS_IN8(tmp + 48); + rinfo->panel_info.fbk_divider = BIOS_IN16(tmp + 49); + if (rinfo->panel_info.ref_divider != 0 && + rinfo->panel_info.fbk_divider > 3) { + rinfo->panel_info.use_bios_dividers = 1; + printk(KERN_INFO "radeondb: BIOS provided dividers will be used\n"); + RTRACE("ref_divider = %x\n", rinfo->panel_info.ref_divider); + RTRACE("post_divider = %x\n", rinfo->panel_info.post_divider); + RTRACE("fbk_divider = %x\n", rinfo->panel_info.fbk_divider); + } + RTRACE("Scanning BIOS table ...\n"); + for(i=0; i<32; i++) { + tmp0 = BIOS_IN16(tmp+64+i*2); + if (tmp0 == 0) + break; + RTRACE(" %d x %d\n", BIOS_IN16(tmp0), BIOS_IN16(tmp0+2)); + if ((BIOS_IN16(tmp0) == rinfo->panel_info.xres) && + (BIOS_IN16(tmp0+2) == rinfo->panel_info.yres)) { + rinfo->panel_info.hblank = (BIOS_IN16(tmp0+17) - BIOS_IN16(tmp0+19)) * 8; + rinfo->panel_info.hOver_plus = ((BIOS_IN16(tmp0+21) - + BIOS_IN16(tmp0+19) -1) * 8) & 0x7fff; + rinfo->panel_info.hSync_width = BIOS_IN8(tmp0+23) * 8; + rinfo->panel_info.vblank = BIOS_IN16(tmp0+24) - BIOS_IN16(tmp0+26); + rinfo->panel_info.vOver_plus = (BIOS_IN16(tmp0+28) & 0x7ff) - BIOS_IN16(tmp0+26); + rinfo->panel_info.vSync_width = (BIOS_IN16(tmp0+28) & 0xf800) >> 11; + rinfo->panel_info.clock = BIOS_IN16(tmp0+9); + /* Assume high active syncs for now until ATI tells me more... maybe we + * can probe register values here ? + */ + rinfo->panel_info.hAct_high = 1; + rinfo->panel_info.vAct_high = 1; + /* Mark panel infos valid */ + rinfo->panel_info.valid = 1; + + RTRACE("Found panel in BIOS table:\n"); + RTRACE(" hblank: %d\n", rinfo->panel_info.hblank); + RTRACE(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus); + RTRACE(" hSync_width: %d\n", rinfo->panel_info.hSync_width); + RTRACE(" vblank: %d\n", rinfo->panel_info.vblank); + RTRACE(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus); + RTRACE(" vSync_width: %d\n", rinfo->panel_info.vSync_width); + RTRACE(" clock: %d\n", rinfo->panel_info.clock); + + return 1; + } + } + RTRACE("Didn't find panel in BIOS table !\n"); + + return 0; +} + +/* Try to extract the connector informations from the BIOS. This + * doesn't quite work yet, but it's output is still useful for + * debugging + */ +static void __devinit radeon_parse_connector_info(struct radeonfb_info *rinfo) +{ + int offset, chips, connectors, tmp, i, conn, type; + + static char* __conn_type_table[16] = { + "NONE", "Proprietary", "CRT", "DVI-I", "DVI-D", "Unknown", "Unknown", + "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", + "Unknown", "Unknown", "Unknown" + }; + + if (!rinfo->bios_seg) + return; + + offset = BIOS_IN16(rinfo->fp_bios_start + 0x50); + if (offset == 0) { + printk(KERN_WARNING "radeonfb: No connector info table detected\n"); + return; + } + + /* Don't do much more at this point but displaying the data if + * DEBUG is enabled + */ + chips = BIOS_IN8(offset++) >> 4; + RTRACE("%d chips in connector info\n", chips); + for (i = 0; i < chips; i++) { + tmp = BIOS_IN8(offset++); + connectors = tmp & 0x0f; + RTRACE(" - chip %d has %d connectors\n", tmp >> 4, connectors); + for (conn = 0; ; conn++) { + tmp = BIOS_IN16(offset); + if (tmp == 0) + break; + offset += 2; + type = (tmp >> 12) & 0x0f; + RTRACE(" * connector %d of type %d (%s) : %04x\n", + conn, type, __conn_type_table[type], tmp); + } + } +} + + +/* + * Probe physical connection of a CRT. This code comes from XFree + * as well and currently is only implemented for the CRT DAC, the + * code for the TVDAC is commented out in XFree as "non working" + */ +static int __devinit radeon_crt_is_connected(struct radeonfb_info *rinfo, int is_crt_dac) +{ + int connected = 0; + + /* the monitor either wasn't connected or it is a non-DDC CRT. + * try to probe it + */ + if (is_crt_dac) { + unsigned long ulOrigVCLK_ECP_CNTL; + unsigned long ulOrigDAC_CNTL; + unsigned long ulOrigDAC_EXT_CNTL; + unsigned long ulOrigCRTC_EXT_CNTL; + unsigned long ulData; + unsigned long ulMask; + + ulOrigVCLK_ECP_CNTL = INPLL(VCLK_ECP_CNTL); + + ulData = ulOrigVCLK_ECP_CNTL; + ulData &= ~(PIXCLK_ALWAYS_ONb + | PIXCLK_DAC_ALWAYS_ONb); + ulMask = ~(PIXCLK_ALWAYS_ONb + | PIXCLK_DAC_ALWAYS_ONb); + OUTPLLP(VCLK_ECP_CNTL, ulData, ulMask); + + ulOrigCRTC_EXT_CNTL = INREG(CRTC_EXT_CNTL); + ulData = ulOrigCRTC_EXT_CNTL; + ulData |= CRTC_CRT_ON; + OUTREG(CRTC_EXT_CNTL, ulData); + + ulOrigDAC_EXT_CNTL = INREG(DAC_EXT_CNTL); + ulData = ulOrigDAC_EXT_CNTL; + ulData &= ~DAC_FORCE_DATA_MASK; + ulData |= (DAC_FORCE_BLANK_OFF_EN + |DAC_FORCE_DATA_EN + |DAC_FORCE_DATA_SEL_MASK); + if ((rinfo->family == CHIP_FAMILY_RV250) || + (rinfo->family == CHIP_FAMILY_RV280)) + ulData |= (0x01b6 << DAC_FORCE_DATA_SHIFT); + else + ulData |= (0x01ac << DAC_FORCE_DATA_SHIFT); + + OUTREG(DAC_EXT_CNTL, ulData); + + ulOrigDAC_CNTL = INREG(DAC_CNTL); + ulData = ulOrigDAC_CNTL; + ulData |= DAC_CMP_EN; + ulData &= ~(DAC_RANGE_CNTL_MASK + | DAC_PDWN); + ulData |= 0x2; + OUTREG(DAC_CNTL, ulData); + + mdelay(1); + + ulData = INREG(DAC_CNTL); + connected = (DAC_CMP_OUTPUT & ulData) ? 1 : 0; + + ulData = ulOrigVCLK_ECP_CNTL; + ulMask = 0xFFFFFFFFL; + OUTPLLP(VCLK_ECP_CNTL, ulData, ulMask); + + OUTREG(DAC_CNTL, ulOrigDAC_CNTL ); + OUTREG(DAC_EXT_CNTL, ulOrigDAC_EXT_CNTL ); + OUTREG(CRTC_EXT_CNTL, ulOrigCRTC_EXT_CNTL); + } + + return connected ? MT_CRT : MT_NONE; +} + +/* + * Parse the "monitor_layout" string if any. This code is mostly + * copied from XFree's radeon driver + */ +static int __devinit radeon_parse_monitor_layout(struct radeonfb_info *rinfo, + const char *monitor_layout) +{ + char s1[5], s2[5]; + int i = 0, second = 0; + const char *s; + + if (!monitor_layout) + return 0; + + s = monitor_layout; + do { + switch(*s) { + case ',': + s1[i] = '\0'; + i = 0; + second = 1; + break; + case ' ': + case '\0': + break; + default: + if (i > 4) + break; + if (second) + s2[i] = *s; + else + s1[i] = *s; + i++; + } + } while (*s++); + if (second) + s2[i] = 0; + else { + s1[i] = 0; + s2[0] = 0; + } + if (strcmp(s1, "CRT") == 0) + rinfo->mon1_type = MT_CRT; + else if (strcmp(s1, "TMDS") == 0) + rinfo->mon1_type = MT_DFP; + else if (strcmp(s1, "LVDS") == 0) + rinfo->mon1_type = MT_LCD; + + if (strcmp(s2, "CRT") == 0) + rinfo->mon2_type = MT_CRT; + else if (strcmp(s2, "TMDS") == 0) + rinfo->mon2_type = MT_DFP; + else if (strcmp(s2, "LVDS") == 0) + rinfo->mon2_type = MT_LCD; + + return 1; +} + +/* + * Probe display on both primary and secondary card's connector (if any) + * by various available techniques (i2c, OF device tree, BIOS, ...) and + * try to retreive EDID. The algorithm here comes from XFree's radeon + * driver + */ +void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, + const char *monitor_layout, int ignore_edid) +{ +#ifdef CONFIG_FB_RADEON_I2C + int ddc_crt2_used = 0; +#endif + int tmp, i; + + radeon_parse_connector_info(rinfo); + + if (radeon_parse_monitor_layout(rinfo, monitor_layout)) { + + /* + * If user specified a monitor_layout option, use it instead + * of auto-detecting. Maybe we should only use this argument + * on the first radeon card probed or provide a way to specify + * a layout for each card ? + */ + + RTRACE("Using specified monitor layout: %s", monitor_layout); +#ifdef CONFIG_FB_RADEON_I2C + if (!ignore_edid) { + if (rinfo->mon1_type != MT_NONE) + if (!radeon_probe_i2c_connector(rinfo, ddc_dvi, &rinfo->mon1_EDID)) { + radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon1_EDID); + ddc_crt2_used = 1; + } + if (rinfo->mon2_type != MT_NONE) + if (!radeon_probe_i2c_connector(rinfo, ddc_vga, &rinfo->mon2_EDID) && + !ddc_crt2_used) + radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon2_EDID); + } +#endif /* CONFIG_FB_RADEON_I2C */ + if (rinfo->mon1_type == MT_NONE) { + if (rinfo->mon2_type != MT_NONE) { + rinfo->mon1_type = rinfo->mon2_type; + rinfo->mon1_EDID = rinfo->mon2_EDID; + } else { + rinfo->mon1_type = MT_CRT; + printk(KERN_INFO "radeonfb: No valid monitor, assuming CRT on first port\n"); + } + rinfo->mon2_type = MT_NONE; + rinfo->mon2_EDID = NULL; + } + } else { + /* + * Auto-detecting display type (well... trying to ...) + */ + + RTRACE("Starting monitor auto detection...\n"); + +#if DEBUG && defined(CONFIG_FB_RADEON_I2C) + { + u8 *EDIDs[4] = { NULL, NULL, NULL, NULL }; + int mon_types[4] = {MT_NONE, MT_NONE, MT_NONE, MT_NONE}; + int i; + + for (i = 0; i < 4; i++) + mon_types[i] = radeon_probe_i2c_connector(rinfo, + i+1, &EDIDs[i]); + } +#endif /* DEBUG */ + /* + * Old single head cards + */ + if (!rinfo->has_CRTC2) { +#ifdef CONFIG_PPC_OF + if (rinfo->mon1_type == MT_NONE) + rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0, + &rinfo->mon1_EDID); +#endif /* CONFIG_PPC_OF */ +#ifdef CONFIG_FB_RADEON_I2C + if (rinfo->mon1_type == MT_NONE) + rinfo->mon1_type = + radeon_probe_i2c_connector(rinfo, ddc_dvi, + &rinfo->mon1_EDID); + if (rinfo->mon1_type == MT_NONE) + rinfo->mon1_type = + radeon_probe_i2c_connector(rinfo, ddc_vga, + &rinfo->mon1_EDID); + if (rinfo->mon1_type == MT_NONE) + rinfo->mon1_type = + radeon_probe_i2c_connector(rinfo, ddc_crt2, + &rinfo->mon1_EDID); +#endif /* CONFIG_FB_RADEON_I2C */ + if (rinfo->mon1_type == MT_NONE) + rinfo->mon1_type = MT_CRT; + goto bail; + } + + /* + * Check for cards with reversed DACs or TMDS controllers using BIOS + */ + if (rinfo->bios_seg && + (tmp = BIOS_IN16(rinfo->fp_bios_start + 0x50))) { + for (i = 1; i < 4; i++) { + unsigned int tmp0; + + if (!BIOS_IN8(tmp + i*2) && i > 1) + break; + tmp0 = BIOS_IN16(tmp + i*2); + if ((!(tmp0 & 0x01)) && (((tmp0 >> 8) & 0x0f) == ddc_dvi)) { + rinfo->reversed_DAC = 1; + printk(KERN_INFO "radeonfb: Reversed DACs detected\n"); + } + if ((((tmp0 >> 8) & 0x0f) == ddc_dvi) && ((tmp0 >> 4) & 0x01)) { + rinfo->reversed_TMDS = 1; + printk(KERN_INFO "radeonfb: Reversed TMDS detected\n"); + } + } + } + + /* + * Probe primary head (DVI or laptop internal panel) + */ +#ifdef CONFIG_PPC_OF + if (rinfo->mon1_type == MT_NONE) + rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0, + &rinfo->mon1_EDID); +#endif /* CONFIG_PPC_OF */ +#ifdef CONFIG_FB_RADEON_I2C + if (rinfo->mon1_type == MT_NONE) + rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi, + &rinfo->mon1_EDID); + if (rinfo->mon1_type == MT_NONE) { + rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_crt2, + &rinfo->mon1_EDID); + if (rinfo->mon1_type != MT_NONE) + ddc_crt2_used = 1; + } +#endif /* CONFIG_FB_RADEON_I2C */ + if (rinfo->mon1_type == MT_NONE && rinfo->is_mobility && + ((rinfo->bios_seg && (INREG(BIOS_4_SCRATCH) & 4)) + || (INREG(LVDS_GEN_CNTL) & LVDS_ON))) { + rinfo->mon1_type = MT_LCD; + printk("Non-DDC laptop panel detected\n"); + } + if (rinfo->mon1_type == MT_NONE) + rinfo->mon1_type = radeon_crt_is_connected(rinfo, rinfo->reversed_DAC); + + /* + * Probe secondary head (mostly VGA, can be DVI) + */ +#ifdef CONFIG_PPC_OF + if (rinfo->mon2_type == MT_NONE) + rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1, + &rinfo->mon2_EDID); +#endif /* CONFIG_PPC_OF */ +#ifdef CONFIG_FB_RADEON_I2C + if (rinfo->mon2_type == MT_NONE) + rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_vga, + &rinfo->mon2_EDID); + if (rinfo->mon2_type == MT_NONE && !ddc_crt2_used) + rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_crt2, + &rinfo->mon2_EDID); +#endif /* CONFIG_FB_RADEON_I2C */ + if (rinfo->mon2_type == MT_NONE) + rinfo->mon2_type = radeon_crt_is_connected(rinfo, !rinfo->reversed_DAC); + + /* + * If we only detected port 2, we swap them, if none detected, + * assume CRT (maybe fallback to old BIOS_SCRATCH stuff ? or look + * at FP registers ?) + */ + if (rinfo->mon1_type == MT_NONE) { + if (rinfo->mon2_type != MT_NONE) { + rinfo->mon1_type = rinfo->mon2_type; + rinfo->mon1_EDID = rinfo->mon2_EDID; + } else + rinfo->mon1_type = MT_CRT; + rinfo->mon2_type = MT_NONE; + rinfo->mon2_EDID = NULL; + } + + /* + * Deal with reversed TMDS + */ + if (rinfo->reversed_TMDS) { + /* Always keep internal TMDS as primary head */ + if (rinfo->mon1_type == MT_DFP || rinfo->mon2_type == MT_DFP) { + int tmp_type = rinfo->mon1_type; + u8 *tmp_EDID = rinfo->mon1_EDID; + rinfo->mon1_type = rinfo->mon2_type; + rinfo->mon1_EDID = rinfo->mon2_EDID; + rinfo->mon2_type = tmp_type; + rinfo->mon2_EDID = tmp_EDID; + if (rinfo->mon1_type == MT_CRT || rinfo->mon2_type == MT_CRT) + rinfo->reversed_DAC ^= 1; + } + } + } + if (ignore_edid) { + kfree(rinfo->mon1_EDID); + rinfo->mon1_EDID = NULL; + kfree(rinfo->mon2_EDID); + rinfo->mon2_EDID = NULL; + } + + bail: + printk(KERN_INFO "radeonfb: Monitor 1 type %s found\n", + radeon_get_mon_name(rinfo->mon1_type)); + if (rinfo->mon1_EDID) + printk(KERN_INFO "radeonfb: EDID probed\n"); + if (!rinfo->has_CRTC2) + return; + printk(KERN_INFO "radeonfb: Monitor 2 type %s found\n", + radeon_get_mon_name(rinfo->mon2_type)); + if (rinfo->mon2_EDID) + printk(KERN_INFO "radeonfb: EDID probed\n"); +} + + +/* + * This functions applyes any arch/model/machine specific fixups + * to the panel info. It may eventually alter EDID block as + * well or whatever is specific to a given model and not probed + * properly by the default code + */ +static void radeon_fixup_panel_info(struct radeonfb_info *rinfo) +{ +#ifdef CONFIG_PPC_OF + /* + * LCD Flat panels should use fixed dividers, we enfore that on + * PPC only for now... + */ + if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type == MT_LCD + && rinfo->is_mobility) { + int ppll_div_sel; + u32 ppll_divn; + ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3; + radeon_pll_errata_after_index(rinfo); + ppll_divn = INPLL(PPLL_DIV_0 + ppll_div_sel); + rinfo->panel_info.ref_divider = rinfo->pll.ref_div; + rinfo->panel_info.fbk_divider = ppll_divn & 0x7ff; + rinfo->panel_info.post_divider = (ppll_divn >> 16) & 0x7; + rinfo->panel_info.use_bios_dividers = 1; + + printk(KERN_DEBUG "radeonfb: Using Firmware dividers 0x%08x " + "from PPLL %d\n", + rinfo->panel_info.fbk_divider | + (rinfo->panel_info.post_divider << 16), + ppll_div_sel); + } +#endif /* CONFIG_PPC_OF */ +} + + +/* + * Fill up panel infos from a mode definition, either returned by the EDID + * or from the default mode when we can't do any better + */ +static void radeon_var_to_panel_info(struct radeonfb_info *rinfo, struct fb_var_screeninfo *var) +{ + rinfo->panel_info.xres = var->xres; + rinfo->panel_info.yres = var->yres; + rinfo->panel_info.clock = 100000000 / var->pixclock; + rinfo->panel_info.hOver_plus = var->right_margin; + rinfo->panel_info.hSync_width = var->hsync_len; + rinfo->panel_info.hblank = var->left_margin + + (var->right_margin + var->hsync_len); + rinfo->panel_info.vOver_plus = var->lower_margin; + rinfo->panel_info.vSync_width = var->vsync_len; + rinfo->panel_info.vblank = var->upper_margin + + (var->lower_margin + var->vsync_len); + rinfo->panel_info.hAct_high = + (var->sync & FB_SYNC_HOR_HIGH_ACT) != 0; + rinfo->panel_info.vAct_high = + (var->sync & FB_SYNC_VERT_HIGH_ACT) != 0; + rinfo->panel_info.valid = 1; + /* We use a default of 200ms for the panel power delay, + * I need to have a real schedule() instead of mdelay's in the panel code. + * we might be possible to figure out a better power delay either from + * MacOS OF tree or from the EDID block (proprietary extensions ?) + */ + rinfo->panel_info.pwr_delay = 200; +} + +static void radeon_videomode_to_var(struct fb_var_screeninfo *var, + const struct fb_videomode *mode) +{ + var->xres = mode->xres; + var->yres = mode->yres; + var->xres_virtual = mode->xres; + var->yres_virtual = mode->yres; + var->xoffset = 0; + var->yoffset = 0; + var->pixclock = mode->pixclock; + var->left_margin = mode->left_margin; + var->right_margin = mode->right_margin; + var->upper_margin = mode->upper_margin; + var->lower_margin = mode->lower_margin; + var->hsync_len = mode->hsync_len; + var->vsync_len = mode->vsync_len; + var->sync = mode->sync; + var->vmode = mode->vmode; +} + +/* + * Build the modedb for head 1 (head 2 will come later), check panel infos + * from either BIOS or EDID, and pick up the default mode + */ +void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option) +{ + struct fb_info * info = rinfo->info; + int has_default_mode = 0; + + /* + * Fill default var first + */ + info->var = radeonfb_default_var; + INIT_LIST_HEAD(&info->modelist); + + /* + * First check out what BIOS has to say + */ + if (rinfo->mon1_type == MT_LCD) + radeon_get_panel_info_BIOS(rinfo); + + /* + * Parse EDID detailed timings and deduce panel infos if any. Right now + * we only deal with first entry returned by parse_EDID, we may do better + * some day... + */ + if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type != MT_CRT + && rinfo->mon1_EDID) { + struct fb_var_screeninfo var; + RTRACE("Parsing EDID data for panel info\n"); + if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) { + if (var.xres >= rinfo->panel_info.xres && + var.yres >= rinfo->panel_info.yres) + radeon_var_to_panel_info(rinfo, &var); + } + } + + /* + * Do any additional platform/arch fixups to the panel infos + */ + radeon_fixup_panel_info(rinfo); + + /* + * If we have some valid panel infos, we setup the default mode based on + * those + */ + if (rinfo->mon1_type != MT_CRT && rinfo->panel_info.valid) { + struct fb_var_screeninfo *var = &info->var; + + RTRACE("Setting up default mode based on panel info\n"); + var->xres = rinfo->panel_info.xres; + var->yres = rinfo->panel_info.yres; + var->xres_virtual = rinfo->panel_info.xres; + var->yres_virtual = rinfo->panel_info.yres; + var->xoffset = var->yoffset = 0; + var->bits_per_pixel = 8; + var->pixclock = 100000000 / rinfo->panel_info.clock; + var->left_margin = (rinfo->panel_info.hblank - rinfo->panel_info.hOver_plus + - rinfo->panel_info.hSync_width); + var->right_margin = rinfo->panel_info.hOver_plus; + var->upper_margin = (rinfo->panel_info.vblank - rinfo->panel_info.vOver_plus + - rinfo->panel_info.vSync_width); + var->lower_margin = rinfo->panel_info.vOver_plus; + var->hsync_len = rinfo->panel_info.hSync_width; + var->vsync_len = rinfo->panel_info.vSync_width; + var->sync = 0; + if (rinfo->panel_info.hAct_high) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (rinfo->panel_info.vAct_high) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + var->vmode = 0; + has_default_mode = 1; + } + + /* + * Now build modedb from EDID + */ + if (rinfo->mon1_EDID) { + fb_edid_to_monspecs(rinfo->mon1_EDID, &info->monspecs); + fb_videomode_to_modelist(info->monspecs.modedb, + info->monspecs.modedb_len, + &info->modelist); + rinfo->mon1_modedb = info->monspecs.modedb; + rinfo->mon1_dbsize = info->monspecs.modedb_len; + } + + + /* + * Finally, if we don't have panel infos we need to figure some (or + * we try to read it from card), we try to pick a default mode + * and create some panel infos. Whatever... + */ + if (rinfo->mon1_type != MT_CRT && !rinfo->panel_info.valid) { + struct fb_videomode *modedb; + int dbsize; + char modename[32]; + + RTRACE("Guessing panel info...\n"); + if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0) { + u32 tmp = INREG(FP_HORZ_STRETCH) & HORZ_PANEL_SIZE; + rinfo->panel_info.xres = ((tmp >> HORZ_PANEL_SHIFT) + 1) * 8; + tmp = INREG(FP_VERT_STRETCH) & VERT_PANEL_SIZE; + rinfo->panel_info.yres = (tmp >> VERT_PANEL_SHIFT) + 1; + } + if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0) { + printk(KERN_WARNING "radeonfb: Can't find panel size, going back to CRT\n"); + rinfo->mon1_type = MT_CRT; + goto pickup_default; + } + printk(KERN_WARNING "radeonfb: Assuming panel size %dx%d\n", + rinfo->panel_info.xres, rinfo->panel_info.yres); + modedb = rinfo->mon1_modedb; + dbsize = rinfo->mon1_dbsize; + snprintf(modename, 31, "%dx%d", rinfo->panel_info.xres, rinfo->panel_info.yres); + if (fb_find_mode(&info->var, info, modename, + modedb, dbsize, NULL, 8) == 0) { + printk(KERN_WARNING "radeonfb: Can't find mode for panel size, going back to CRT\n"); + rinfo->mon1_type = MT_CRT; + goto pickup_default; + } + has_default_mode = 1; + radeon_var_to_panel_info(rinfo, &info->var); + } + + pickup_default: + /* + * Apply passed-in mode option if any + */ + if (mode_option) { + if (fb_find_mode(&info->var, info, mode_option, + info->monspecs.modedb, + info->monspecs.modedb_len, NULL, 8) != 0) + has_default_mode = 1; + } + + /* + * Still no mode, let's pick up a default from the db + */ + if (!has_default_mode && info->monspecs.modedb != NULL) { + struct fb_monspecs *specs = &info->monspecs; + struct fb_videomode *modedb = NULL; + + /* get preferred timing */ + if (specs->misc & FB_MISC_1ST_DETAIL) { + int i; + + for (i = 0; i < specs->modedb_len; i++) { + if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { + modedb = &specs->modedb[i]; + break; + } + } + } else { + /* otherwise, get first mode in database */ + modedb = &specs->modedb[0]; + } + if (modedb != NULL) { + info->var.bits_per_pixel = 8; + radeon_videomode_to_var(&info->var, modedb); + has_default_mode = 1; + } + } + if (1) { + struct fb_videomode mode; + /* Make sure that whatever mode got selected is actually in the + * modelist or the kernel may die + */ + fb_var_to_videomode(&mode, &info->var); + fb_add_videomode(&mode, &info->modelist); + } +} + +/* + * The code below is used to pick up a mode in check_var and + * set_var. It should be made generic + */ + +/* + * This is used when looking for modes. We assign a "distance" value + * to a mode in the modedb depending how "close" it is from what we + * are looking for. + * Currently, we don't compare that much, we could do better but + * the current fbcon doesn't quite mind ;) + */ +static int radeon_compare_modes(const struct fb_var_screeninfo *var, + const struct fb_videomode *mode) +{ + int distance = 0; + + distance = mode->yres - var->yres; + distance += (mode->xres - var->xres)/2; + return distance; +} + +/* + * This function is called by check_var, it gets the passed in mode parameter, and + * outputs a valid mode matching the passed-in one as closely as possible. + * We need something better ultimately. Things like fbcon basically pass us out + * current mode with xres/yres hacked, while things like XFree will actually + * produce a full timing that we should respect as much as possible. + * + * This is why I added the FB_ACTIVATE_FIND that is used by fbcon. Without this, + * we do a simple spec match, that's all. With it, we actually look for a mode in + * either our monitor modedb or the vesa one if none + * + */ +int radeon_match_mode(struct radeonfb_info *rinfo, + struct fb_var_screeninfo *dest, + const struct fb_var_screeninfo *src) +{ + const struct fb_videomode *db = vesa_modes; + int i, dbsize = 34; + int has_rmx, native_db = 0; + int distance = INT_MAX; + const struct fb_videomode *candidate = NULL; + + /* Start with a copy of the requested mode */ + memcpy(dest, src, sizeof(struct fb_var_screeninfo)); + + /* Check if we have a modedb built from EDID */ + if (rinfo->mon1_modedb) { + db = rinfo->mon1_modedb; + dbsize = rinfo->mon1_dbsize; + native_db = 1; + } + + /* Check if we have a scaler allowing any fancy mode */ + has_rmx = rinfo->mon1_type == MT_LCD || rinfo->mon1_type == MT_DFP; + + /* If we have a scaler and are passed FB_ACTIVATE_TEST or + * FB_ACTIVATE_NOW, just do basic checking and return if the + * mode match + */ + if ((src->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST || + (src->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + /* We don't have an RMX, validate timings. If we don't have + * monspecs, we should be paranoid and not let use go above + * 640x480-60, but I assume userland knows what it's doing here + * (though I may be proven wrong...) + */ + if (has_rmx == 0 && rinfo->mon1_modedb) + if (fb_validate_mode((struct fb_var_screeninfo *)src, rinfo->info)) + return -EINVAL; + return 0; + } + + /* Now look for a mode in the database */ + while (db) { + for (i = 0; i < dbsize; i++) { + int d; + + if (db[i].yres < src->yres) + continue; + if (db[i].xres < src->xres) + continue; + d = radeon_compare_modes(src, &db[i]); + /* If the new mode is at least as good as the previous one, + * then it's our new candidate + */ + if (d < distance) { + candidate = &db[i]; + distance = d; + } + } + db = NULL; + /* If we have a scaler, we allow any mode from the database */ + if (native_db && has_rmx) { + db = vesa_modes; + dbsize = 34; + native_db = 0; + } + } + + /* If we have found a match, return it */ + if (candidate != NULL) { + radeon_videomode_to_var(dest, candidate); + return 0; + } + + /* If we haven't and don't have a scaler, fail */ + if (!has_rmx) + return -EINVAL; + + return 0; +} diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c new file mode 100644 index 000000000000..23c677e5093f --- /dev/null +++ b/drivers/video/aty/radeon_pm.c @@ -0,0 +1,2801 @@ +/* + * drivers/video/aty/radeon_pm.c + * + * Copyright 2003,2004 Ben. Herrenschmidt <benh@kernel.crashing.org> + * Copyright 2004 Paul Mackerras <paulus@samba.org> + * + * This is the power management code for ATI radeon chipsets. It contains + * some dynamic clock PM enable/disable code similar to what X.org does, + * some D2-state (APM-style) sleep/wakeup code for use on some PowerMacs, + * and the necessary bits to re-initialize from scratch a few chips found + * on PowerMacs as well. The later could be extended to more platforms + * provided the memory controller configuration code be made more generic, + * and you can get the proper mode register commands for your RAMs. + * Those things may be found in the BIOS image... + */ + +#include "radeonfb.h" + +#include <linux/console.h> +#include <linux/agp_backend.h> + +#ifdef CONFIG_PPC_PMAC +#include <asm/processor.h> +#include <asm/prom.h> +#include <asm/pmac_feature.h> +#endif + +#include "ati_ids.h" + +static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo) +{ + u32 tmp; + + /* RV100 */ + if ((rinfo->family == CHIP_FAMILY_RV100) && (!rinfo->is_mobility)) { + if (rinfo->has_CRTC2) { + tmp = INPLL(pllSCLK_CNTL); + tmp &= ~SCLK_CNTL__DYN_STOP_LAT_MASK; + tmp |= SCLK_CNTL__CP_MAX_DYN_STOP_LAT | SCLK_CNTL__FORCEON_MASK; + OUTPLL(pllSCLK_CNTL, tmp); + } + tmp = INPLL(pllMCLK_CNTL); + tmp |= (MCLK_CNTL__FORCE_MCLKA | + MCLK_CNTL__FORCE_MCLKB | + MCLK_CNTL__FORCE_YCLKA | + MCLK_CNTL__FORCE_YCLKB | + MCLK_CNTL__FORCE_AIC | + MCLK_CNTL__FORCE_MC); + OUTPLL(pllMCLK_CNTL, tmp); + return; + } + /* R100 */ + if (!rinfo->has_CRTC2) { + tmp = INPLL(pllSCLK_CNTL); + tmp |= (SCLK_CNTL__FORCE_CP | SCLK_CNTL__FORCE_HDP | + SCLK_CNTL__FORCE_DISP1 | SCLK_CNTL__FORCE_TOP | + SCLK_CNTL__FORCE_E2 | SCLK_CNTL__FORCE_SE | + SCLK_CNTL__FORCE_IDCT | SCLK_CNTL__FORCE_VIP | + SCLK_CNTL__FORCE_RE | SCLK_CNTL__FORCE_PB | + SCLK_CNTL__FORCE_TAM | SCLK_CNTL__FORCE_TDM | + SCLK_CNTL__FORCE_RB); + OUTPLL(pllSCLK_CNTL, tmp); + return; + } + /* RV350 (M10) */ + if (rinfo->family == CHIP_FAMILY_RV350) { + /* for RV350/M10, no delays are required. */ + tmp = INPLL(pllSCLK_CNTL2); + tmp |= (SCLK_CNTL2__R300_FORCE_TCL | + SCLK_CNTL2__R300_FORCE_GA | + SCLK_CNTL2__R300_FORCE_CBA); + OUTPLL(pllSCLK_CNTL2, tmp); + + tmp = INPLL(pllSCLK_CNTL); + tmp |= (SCLK_CNTL__FORCE_DISP2 | SCLK_CNTL__FORCE_CP | + SCLK_CNTL__FORCE_HDP | SCLK_CNTL__FORCE_DISP1 | + SCLK_CNTL__FORCE_TOP | SCLK_CNTL__FORCE_E2 | + SCLK_CNTL__R300_FORCE_VAP | SCLK_CNTL__FORCE_IDCT | + SCLK_CNTL__FORCE_VIP | SCLK_CNTL__R300_FORCE_SR | + SCLK_CNTL__R300_FORCE_PX | SCLK_CNTL__R300_FORCE_TX | + SCLK_CNTL__R300_FORCE_US | SCLK_CNTL__FORCE_TV_SCLK | + SCLK_CNTL__R300_FORCE_SU | SCLK_CNTL__FORCE_OV0); + OUTPLL(pllSCLK_CNTL, tmp); + + tmp = INPLL(pllSCLK_MORE_CNTL); + tmp |= (SCLK_MORE_CNTL__FORCE_DISPREGS | SCLK_MORE_CNTL__FORCE_MC_GUI | + SCLK_MORE_CNTL__FORCE_MC_HOST); + OUTPLL(pllSCLK_MORE_CNTL, tmp); + + tmp = INPLL(pllMCLK_CNTL); + tmp |= (MCLK_CNTL__FORCE_MCLKA | + MCLK_CNTL__FORCE_MCLKB | + MCLK_CNTL__FORCE_YCLKA | + MCLK_CNTL__FORCE_YCLKB | + MCLK_CNTL__FORCE_MC); + OUTPLL(pllMCLK_CNTL, tmp); + + tmp = INPLL(pllVCLK_ECP_CNTL); + tmp &= ~(VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb | + VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb | + VCLK_ECP_CNTL__R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF); + OUTPLL(pllVCLK_ECP_CNTL, tmp); + + tmp = INPLL(pllPIXCLKS_CNTL); + tmp &= ~(PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb | + PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb | + PIXCLKS_CNTL__DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | + PIXCLKS_CNTL__R300_DVOCLK_ALWAYS_ONb | + PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb | + PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb | + PIXCLKS_CNTL__R300_PIXCLK_DVO_ALWAYS_ONb | + PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb | + PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb | + PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb | + PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb | + PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb | + PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb | + PIXCLKS_CNTL__R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF); + OUTPLL(pllPIXCLKS_CNTL, tmp); + + return; + } + + /* Default */ + + /* Force Core Clocks */ + tmp = INPLL(pllSCLK_CNTL); + tmp |= (SCLK_CNTL__FORCE_CP | SCLK_CNTL__FORCE_E2); + + /* XFree doesn't do that case, but we had this code from Apple and it + * seem necessary for proper suspend/resume operations + */ + if (rinfo->is_mobility) { + tmp |= SCLK_CNTL__FORCE_HDP| + SCLK_CNTL__FORCE_DISP1| + SCLK_CNTL__FORCE_DISP2| + SCLK_CNTL__FORCE_TOP| + SCLK_CNTL__FORCE_SE| + SCLK_CNTL__FORCE_IDCT| + SCLK_CNTL__FORCE_VIP| + SCLK_CNTL__FORCE_PB| + SCLK_CNTL__FORCE_RE| + SCLK_CNTL__FORCE_TAM| + SCLK_CNTL__FORCE_TDM| + SCLK_CNTL__FORCE_RB| + SCLK_CNTL__FORCE_TV_SCLK| + SCLK_CNTL__FORCE_SUBPIC| + SCLK_CNTL__FORCE_OV0; + } + else if (rinfo->family == CHIP_FAMILY_R300 || + rinfo->family == CHIP_FAMILY_R350) { + tmp |= SCLK_CNTL__FORCE_HDP | + SCLK_CNTL__FORCE_DISP1 | + SCLK_CNTL__FORCE_DISP2 | + SCLK_CNTL__FORCE_TOP | + SCLK_CNTL__FORCE_IDCT | + SCLK_CNTL__FORCE_VIP; + } + OUTPLL(pllSCLK_CNTL, tmp); + radeon_msleep(16); + + if (rinfo->family == CHIP_FAMILY_R300 || rinfo->family == CHIP_FAMILY_R350) { + tmp = INPLL(pllSCLK_CNTL2); + tmp |= SCLK_CNTL2__R300_FORCE_TCL | + SCLK_CNTL2__R300_FORCE_GA | + SCLK_CNTL2__R300_FORCE_CBA; + OUTPLL(pllSCLK_CNTL2, tmp); + radeon_msleep(16); + } + + tmp = INPLL(pllCLK_PIN_CNTL); + tmp &= ~CLK_PIN_CNTL__SCLK_DYN_START_CNTL; + OUTPLL(pllCLK_PIN_CNTL, tmp); + radeon_msleep(15); + + if (rinfo->is_IGP) { + /* Weird ... X is _un_ forcing clocks here, I think it's + * doing backward. Imitate it for now... + */ + tmp = INPLL(pllMCLK_CNTL); + tmp &= ~(MCLK_CNTL__FORCE_MCLKA | + MCLK_CNTL__FORCE_YCLKA); + OUTPLL(pllMCLK_CNTL, tmp); + radeon_msleep(16); + } + /* Hrm... same shit, X doesn't do that but I have to */ + else if (rinfo->is_mobility) { + tmp = INPLL(pllMCLK_CNTL); + tmp |= (MCLK_CNTL__FORCE_MCLKA | + MCLK_CNTL__FORCE_MCLKB | + MCLK_CNTL__FORCE_YCLKA | + MCLK_CNTL__FORCE_YCLKB); + OUTPLL(pllMCLK_CNTL, tmp); + radeon_msleep(16); + + tmp = INPLL(pllMCLK_MISC); + tmp &= ~(MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT| + MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT| + MCLK_MISC__MC_MCLK_DYN_ENABLE| + MCLK_MISC__IO_MCLK_DYN_ENABLE); + OUTPLL(pllMCLK_MISC, tmp); + radeon_msleep(15); + } + + if (rinfo->is_mobility) { + tmp = INPLL(pllSCLK_MORE_CNTL); + tmp |= SCLK_MORE_CNTL__FORCE_DISPREGS| + SCLK_MORE_CNTL__FORCE_MC_GUI| + SCLK_MORE_CNTL__FORCE_MC_HOST; + OUTPLL(pllSCLK_MORE_CNTL, tmp); + radeon_msleep(16); + } + + tmp = INPLL(pllPIXCLKS_CNTL); + tmp &= ~(PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb | + PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb| + PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb | + PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb| + PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb| + PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb| + PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb); + OUTPLL(pllPIXCLKS_CNTL, tmp); + radeon_msleep(16); + + tmp = INPLL( pllVCLK_ECP_CNTL); + tmp &= ~(VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb | + VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb); + OUTPLL( pllVCLK_ECP_CNTL, tmp); + radeon_msleep(16); +} + +static void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo) +{ + u32 tmp; + + /* R100 */ + if (!rinfo->has_CRTC2) { + tmp = INPLL(pllSCLK_CNTL); + + if ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) > CFG_ATI_REV_A13) + tmp &= ~(SCLK_CNTL__FORCE_CP | SCLK_CNTL__FORCE_RB); + tmp &= ~(SCLK_CNTL__FORCE_HDP | SCLK_CNTL__FORCE_DISP1 | + SCLK_CNTL__FORCE_TOP | SCLK_CNTL__FORCE_SE | + SCLK_CNTL__FORCE_IDCT | SCLK_CNTL__FORCE_RE | + SCLK_CNTL__FORCE_PB | SCLK_CNTL__FORCE_TAM | + SCLK_CNTL__FORCE_TDM); + OUTPLL(pllSCLK_CNTL, tmp); + return; + } + + /* M10 */ + if (rinfo->family == CHIP_FAMILY_RV350) { + tmp = INPLL(pllSCLK_CNTL2); + tmp &= ~(SCLK_CNTL2__R300_FORCE_TCL | + SCLK_CNTL2__R300_FORCE_GA | + SCLK_CNTL2__R300_FORCE_CBA); + tmp |= (SCLK_CNTL2__R300_TCL_MAX_DYN_STOP_LAT | + SCLK_CNTL2__R300_GA_MAX_DYN_STOP_LAT | + SCLK_CNTL2__R300_CBA_MAX_DYN_STOP_LAT); + OUTPLL(pllSCLK_CNTL2, tmp); + + tmp = INPLL(pllSCLK_CNTL); + tmp &= ~(SCLK_CNTL__FORCE_DISP2 | SCLK_CNTL__FORCE_CP | + SCLK_CNTL__FORCE_HDP | SCLK_CNTL__FORCE_DISP1 | + SCLK_CNTL__FORCE_TOP | SCLK_CNTL__FORCE_E2 | + SCLK_CNTL__R300_FORCE_VAP | SCLK_CNTL__FORCE_IDCT | + SCLK_CNTL__FORCE_VIP | SCLK_CNTL__R300_FORCE_SR | + SCLK_CNTL__R300_FORCE_PX | SCLK_CNTL__R300_FORCE_TX | + SCLK_CNTL__R300_FORCE_US | SCLK_CNTL__FORCE_TV_SCLK | + SCLK_CNTL__R300_FORCE_SU | SCLK_CNTL__FORCE_OV0); + tmp |= SCLK_CNTL__DYN_STOP_LAT_MASK; + OUTPLL(pllSCLK_CNTL, tmp); + + tmp = INPLL(pllSCLK_MORE_CNTL); + tmp &= ~SCLK_MORE_CNTL__FORCEON; + tmp |= SCLK_MORE_CNTL__DISPREGS_MAX_DYN_STOP_LAT | + SCLK_MORE_CNTL__MC_GUI_MAX_DYN_STOP_LAT | + SCLK_MORE_CNTL__MC_HOST_MAX_DYN_STOP_LAT; + OUTPLL(pllSCLK_MORE_CNTL, tmp); + + tmp = INPLL(pllVCLK_ECP_CNTL); + tmp |= (VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb | + VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb); + OUTPLL(pllVCLK_ECP_CNTL, tmp); + + tmp = INPLL(pllPIXCLKS_CNTL); + tmp |= (PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb | + PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb | + PIXCLKS_CNTL__DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | + PIXCLKS_CNTL__R300_DVOCLK_ALWAYS_ONb | + PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb | + PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb | + PIXCLKS_CNTL__R300_PIXCLK_DVO_ALWAYS_ONb | + PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb | + PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb | + PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb | + PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb | + PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb | + PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb); + OUTPLL(pllPIXCLKS_CNTL, tmp); + + tmp = INPLL(pllMCLK_MISC); + tmp |= (MCLK_MISC__MC_MCLK_DYN_ENABLE | + MCLK_MISC__IO_MCLK_DYN_ENABLE); + OUTPLL(pllMCLK_MISC, tmp); + + tmp = INPLL(pllMCLK_CNTL); + tmp |= (MCLK_CNTL__FORCE_MCLKA | MCLK_CNTL__FORCE_MCLKB); + tmp &= ~(MCLK_CNTL__FORCE_YCLKA | + MCLK_CNTL__FORCE_YCLKB | + MCLK_CNTL__FORCE_MC); + + /* Some releases of vbios have set DISABLE_MC_MCLKA + * and DISABLE_MC_MCLKB bits in the vbios table. Setting these + * bits will cause H/W hang when reading video memory with dynamic + * clocking enabled. + */ + if ((tmp & MCLK_CNTL__R300_DISABLE_MC_MCLKA) && + (tmp & MCLK_CNTL__R300_DISABLE_MC_MCLKB)) { + /* If both bits are set, then check the active channels */ + tmp = INPLL(pllMCLK_CNTL); + if (rinfo->vram_width == 64) { + if (INREG(MEM_CNTL) & R300_MEM_USE_CD_CH_ONLY) + tmp &= ~MCLK_CNTL__R300_DISABLE_MC_MCLKB; + else + tmp &= ~MCLK_CNTL__R300_DISABLE_MC_MCLKA; + } else { + tmp &= ~(MCLK_CNTL__R300_DISABLE_MC_MCLKA | + MCLK_CNTL__R300_DISABLE_MC_MCLKB); + } + } + OUTPLL(pllMCLK_CNTL, tmp); + return; + } + + /* R300 */ + if (rinfo->family == CHIP_FAMILY_R300 || rinfo->family == CHIP_FAMILY_R350) { + tmp = INPLL(pllSCLK_CNTL); + tmp &= ~(SCLK_CNTL__R300_FORCE_VAP); + tmp |= SCLK_CNTL__FORCE_CP; + OUTPLL(pllSCLK_CNTL, tmp); + radeon_msleep(15); + + tmp = INPLL(pllSCLK_CNTL2); + tmp &= ~(SCLK_CNTL2__R300_FORCE_TCL | + SCLK_CNTL2__R300_FORCE_GA | + SCLK_CNTL2__R300_FORCE_CBA); + OUTPLL(pllSCLK_CNTL2, tmp); + } + + /* Others */ + + tmp = INPLL( pllCLK_PWRMGT_CNTL); + tmp &= ~(CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK| + CLK_PWRMGT_CNTL__DISP_DYN_STOP_LAT_MASK| + CLK_PWRMGT_CNTL__DYN_STOP_MODE_MASK); + tmp |= CLK_PWRMGT_CNTL__ENGINE_DYNCLK_MODE_MASK | + (0x01 << CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT__SHIFT); + OUTPLL( pllCLK_PWRMGT_CNTL, tmp); + radeon_msleep(15); + + tmp = INPLL(pllCLK_PIN_CNTL); + tmp |= CLK_PIN_CNTL__SCLK_DYN_START_CNTL; + OUTPLL(pllCLK_PIN_CNTL, tmp); + radeon_msleep(15); + + /* When DRI is enabled, setting DYN_STOP_LAT to zero can cause some R200 + * to lockup randomly, leave them as set by BIOS. + */ + tmp = INPLL(pllSCLK_CNTL); + tmp &= ~SCLK_CNTL__FORCEON_MASK; + + /*RAGE_6::A11 A12 A12N1 A13, RV250::A11 A12, R300*/ + if ((rinfo->family == CHIP_FAMILY_RV250 && + ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) < CFG_ATI_REV_A13)) || + ((rinfo->family == CHIP_FAMILY_RV100) && + ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) <= CFG_ATI_REV_A13))) { + tmp |= SCLK_CNTL__FORCE_CP; + tmp |= SCLK_CNTL__FORCE_VIP; + } + OUTPLL(pllSCLK_CNTL, tmp); + radeon_msleep(15); + + if ((rinfo->family == CHIP_FAMILY_RV200) || + (rinfo->family == CHIP_FAMILY_RV250) || + (rinfo->family == CHIP_FAMILY_RV280)) { + tmp = INPLL(pllSCLK_MORE_CNTL); + tmp &= ~SCLK_MORE_CNTL__FORCEON; + + /* RV200::A11 A12 RV250::A11 A12 */ + if (((rinfo->family == CHIP_FAMILY_RV200) || + (rinfo->family == CHIP_FAMILY_RV250)) && + ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) < CFG_ATI_REV_A13)) + tmp |= SCLK_MORE_CNTL__FORCEON; + + OUTPLL(pllSCLK_MORE_CNTL, tmp); + radeon_msleep(15); + } + + + /* RV200::A11 A12, RV250::A11 A12 */ + if (((rinfo->family == CHIP_FAMILY_RV200) || + (rinfo->family == CHIP_FAMILY_RV250)) && + ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) < CFG_ATI_REV_A13)) { + tmp = INPLL(pllPLL_PWRMGT_CNTL); + tmp |= PLL_PWRMGT_CNTL__TCL_BYPASS_DISABLE; + OUTPLL(pllPLL_PWRMGT_CNTL, tmp); + radeon_msleep(15); + } + + tmp = INPLL(pllPIXCLKS_CNTL); + tmp |= PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb | + PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb| + PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb| + PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb| + PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb| + PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb| + PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb; + OUTPLL(pllPIXCLKS_CNTL, tmp); + radeon_msleep(15); + + tmp = INPLL(pllVCLK_ECP_CNTL); + tmp |= VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb | + VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb; + OUTPLL(pllVCLK_ECP_CNTL, tmp); + + /* X doesn't do that ... hrm, we do on mobility && Macs */ +#ifdef CONFIG_PPC_OF + if (rinfo->is_mobility) { + tmp = INPLL(pllMCLK_CNTL); + tmp &= ~(MCLK_CNTL__FORCE_MCLKA | + MCLK_CNTL__FORCE_MCLKB | + MCLK_CNTL__FORCE_YCLKA | + MCLK_CNTL__FORCE_YCLKB); + OUTPLL(pllMCLK_CNTL, tmp); + radeon_msleep(15); + + tmp = INPLL(pllMCLK_MISC); + tmp |= MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT| + MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT| + MCLK_MISC__MC_MCLK_DYN_ENABLE| + MCLK_MISC__IO_MCLK_DYN_ENABLE; + OUTPLL(pllMCLK_MISC, tmp); + radeon_msleep(15); + } +#endif /* CONFIG_PPC_OF */ +} + +#ifdef CONFIG_PM + +static void OUTMC( struct radeonfb_info *rinfo, u8 indx, u32 value) +{ + OUTREG( MC_IND_INDEX, indx | MC_IND_INDEX__MC_IND_WR_EN); + OUTREG( MC_IND_DATA, value); +} + +static u32 INMC(struct radeonfb_info *rinfo, u8 indx) +{ + OUTREG( MC_IND_INDEX, indx); + return INREG( MC_IND_DATA); +} + +static void radeon_pm_save_regs(struct radeonfb_info *rinfo, int saving_for_d3) +{ + rinfo->save_regs[0] = INPLL(PLL_PWRMGT_CNTL); + rinfo->save_regs[1] = INPLL(CLK_PWRMGT_CNTL); + rinfo->save_regs[2] = INPLL(MCLK_CNTL); + rinfo->save_regs[3] = INPLL(SCLK_CNTL); + rinfo->save_regs[4] = INPLL(CLK_PIN_CNTL); + rinfo->save_regs[5] = INPLL(VCLK_ECP_CNTL); + rinfo->save_regs[6] = INPLL(PIXCLKS_CNTL); + rinfo->save_regs[7] = INPLL(MCLK_MISC); + rinfo->save_regs[8] = INPLL(P2PLL_CNTL); + + rinfo->save_regs[9] = INREG(DISP_MISC_CNTL); + rinfo->save_regs[10] = INREG(DISP_PWR_MAN); + rinfo->save_regs[11] = INREG(LVDS_GEN_CNTL); + rinfo->save_regs[13] = INREG(TV_DAC_CNTL); + rinfo->save_regs[14] = INREG(BUS_CNTL1); + rinfo->save_regs[15] = INREG(CRTC_OFFSET_CNTL); + rinfo->save_regs[16] = INREG(AGP_CNTL); + rinfo->save_regs[17] = (INREG(CRTC_GEN_CNTL) & 0xfdffffff) | 0x04000000; + rinfo->save_regs[18] = (INREG(CRTC2_GEN_CNTL) & 0xfdffffff) | 0x04000000; + rinfo->save_regs[19] = INREG(GPIOPAD_A); + rinfo->save_regs[20] = INREG(GPIOPAD_EN); + rinfo->save_regs[21] = INREG(GPIOPAD_MASK); + rinfo->save_regs[22] = INREG(ZV_LCDPAD_A); + rinfo->save_regs[23] = INREG(ZV_LCDPAD_EN); + rinfo->save_regs[24] = INREG(ZV_LCDPAD_MASK); + rinfo->save_regs[25] = INREG(GPIO_VGA_DDC); + rinfo->save_regs[26] = INREG(GPIO_DVI_DDC); + rinfo->save_regs[27] = INREG(GPIO_MONID); + rinfo->save_regs[28] = INREG(GPIO_CRT2_DDC); + + rinfo->save_regs[29] = INREG(SURFACE_CNTL); + rinfo->save_regs[30] = INREG(MC_FB_LOCATION); + rinfo->save_regs[31] = INREG(DISPLAY_BASE_ADDR); + rinfo->save_regs[32] = INREG(MC_AGP_LOCATION); + rinfo->save_regs[33] = INREG(CRTC2_DISPLAY_BASE_ADDR); + + rinfo->save_regs[34] = INPLL(SCLK_MORE_CNTL); + rinfo->save_regs[35] = INREG(MEM_SDRAM_MODE_REG); + rinfo->save_regs[36] = INREG(BUS_CNTL); + rinfo->save_regs[39] = INREG(RBBM_CNTL); + rinfo->save_regs[40] = INREG(DAC_CNTL); + rinfo->save_regs[41] = INREG(HOST_PATH_CNTL); + rinfo->save_regs[37] = INREG(MPP_TB_CONFIG); + rinfo->save_regs[38] = INREG(FCP_CNTL); + + if (rinfo->is_mobility) { + rinfo->save_regs[12] = INREG(LVDS_PLL_CNTL); + rinfo->save_regs[43] = INPLL(pllSSPLL_CNTL); + rinfo->save_regs[44] = INPLL(pllSSPLL_REF_DIV); + rinfo->save_regs[45] = INPLL(pllSSPLL_DIV_0); + rinfo->save_regs[90] = INPLL(pllSS_INT_CNTL); + rinfo->save_regs[91] = INPLL(pllSS_TST_CNTL); + rinfo->save_regs[81] = INREG(LVDS_GEN_CNTL); + } + + if (rinfo->family >= CHIP_FAMILY_RV200) { + rinfo->save_regs[42] = INREG(MEM_REFRESH_CNTL); + rinfo->save_regs[46] = INREG(MC_CNTL); + rinfo->save_regs[47] = INREG(MC_INIT_GFX_LAT_TIMER); + rinfo->save_regs[48] = INREG(MC_INIT_MISC_LAT_TIMER); + rinfo->save_regs[49] = INREG(MC_TIMING_CNTL); + rinfo->save_regs[50] = INREG(MC_READ_CNTL_AB); + rinfo->save_regs[51] = INREG(MC_IOPAD_CNTL); + rinfo->save_regs[52] = INREG(MC_CHIP_IO_OE_CNTL_AB); + rinfo->save_regs[53] = INREG(MC_DEBUG); + } + rinfo->save_regs[54] = INREG(PAMAC0_DLY_CNTL); + rinfo->save_regs[55] = INREG(PAMAC1_DLY_CNTL); + rinfo->save_regs[56] = INREG(PAD_CTLR_MISC); + rinfo->save_regs[57] = INREG(FW_CNTL); + + if (rinfo->family >= CHIP_FAMILY_R300) { + rinfo->save_regs[58] = INMC(rinfo, ixR300_MC_MC_INIT_WR_LAT_TIMER); + rinfo->save_regs[59] = INMC(rinfo, ixR300_MC_IMP_CNTL); + rinfo->save_regs[60] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_C0); + rinfo->save_regs[61] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_C1); + rinfo->save_regs[62] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_D0); + rinfo->save_regs[63] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_D1); + rinfo->save_regs[64] = INMC(rinfo, ixR300_MC_BIST_CNTL_3); + rinfo->save_regs[65] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_A0); + rinfo->save_regs[66] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_A1); + rinfo->save_regs[67] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_B0); + rinfo->save_regs[68] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_B1); + rinfo->save_regs[69] = INMC(rinfo, ixR300_MC_DEBUG_CNTL); + rinfo->save_regs[70] = INMC(rinfo, ixR300_MC_DLL_CNTL); + rinfo->save_regs[71] = INMC(rinfo, ixR300_MC_IMP_CNTL_0); + rinfo->save_regs[72] = INMC(rinfo, ixR300_MC_ELPIDA_CNTL); + rinfo->save_regs[96] = INMC(rinfo, ixR300_MC_READ_CNTL_CD); + } else { + rinfo->save_regs[59] = INMC(rinfo, ixMC_IMP_CNTL); + rinfo->save_regs[65] = INMC(rinfo, ixMC_CHP_IO_CNTL_A0); + rinfo->save_regs[66] = INMC(rinfo, ixMC_CHP_IO_CNTL_A1); + rinfo->save_regs[67] = INMC(rinfo, ixMC_CHP_IO_CNTL_B0); + rinfo->save_regs[68] = INMC(rinfo, ixMC_CHP_IO_CNTL_B1); + rinfo->save_regs[71] = INMC(rinfo, ixMC_IMP_CNTL_0); + } + + rinfo->save_regs[73] = INPLL(pllMPLL_CNTL); + rinfo->save_regs[74] = INPLL(pllSPLL_CNTL); + rinfo->save_regs[75] = INPLL(pllMPLL_AUX_CNTL); + rinfo->save_regs[76] = INPLL(pllSPLL_AUX_CNTL); + rinfo->save_regs[77] = INPLL(pllM_SPLL_REF_FB_DIV); + rinfo->save_regs[78] = INPLL(pllAGP_PLL_CNTL); + rinfo->save_regs[79] = INREG(PAMAC2_DLY_CNTL); + + rinfo->save_regs[80] = INREG(OV0_BASE_ADDR); + rinfo->save_regs[82] = INREG(FP_GEN_CNTL); + rinfo->save_regs[83] = INREG(FP2_GEN_CNTL); + rinfo->save_regs[84] = INREG(TMDS_CNTL); + rinfo->save_regs[85] = INREG(TMDS_TRANSMITTER_CNTL); + rinfo->save_regs[86] = INREG(DISP_OUTPUT_CNTL); + rinfo->save_regs[87] = INREG(DISP_HW_DEBUG); + rinfo->save_regs[88] = INREG(TV_MASTER_CNTL); + rinfo->save_regs[89] = INPLL(pllP2PLL_REF_DIV); + rinfo->save_regs[92] = INPLL(pllPPLL_DIV_0); + rinfo->save_regs[93] = INPLL(pllPPLL_CNTL); + rinfo->save_regs[94] = INREG(GRPH_BUFFER_CNTL); + rinfo->save_regs[95] = INREG(GRPH2_BUFFER_CNTL); + rinfo->save_regs[96] = INREG(HDP_DEBUG); + rinfo->save_regs[97] = INPLL(pllMDLL_CKO); + rinfo->save_regs[98] = INPLL(pllMDLL_RDCKA); + rinfo->save_regs[99] = INPLL(pllMDLL_RDCKB); +} + +static void radeon_pm_restore_regs(struct radeonfb_info *rinfo) +{ + OUTPLL(P2PLL_CNTL, rinfo->save_regs[8] & 0xFFFFFFFE); /* First */ + + OUTPLL(PLL_PWRMGT_CNTL, rinfo->save_regs[0]); + OUTPLL(CLK_PWRMGT_CNTL, rinfo->save_regs[1]); + OUTPLL(MCLK_CNTL, rinfo->save_regs[2]); + OUTPLL(SCLK_CNTL, rinfo->save_regs[3]); + OUTPLL(CLK_PIN_CNTL, rinfo->save_regs[4]); + OUTPLL(VCLK_ECP_CNTL, rinfo->save_regs[5]); + OUTPLL(PIXCLKS_CNTL, rinfo->save_regs[6]); + OUTPLL(MCLK_MISC, rinfo->save_regs[7]); + if (rinfo->family == CHIP_FAMILY_RV350) + OUTPLL(SCLK_MORE_CNTL, rinfo->save_regs[34]); + + OUTREG(SURFACE_CNTL, rinfo->save_regs[29]); + OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]); + OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]); + OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]); + OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]); + OUTREG(CONFIG_MEMSIZE, rinfo->video_ram); + + OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]); + OUTREG(DISP_PWR_MAN, rinfo->save_regs[10]); + OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11]); + OUTREG(LVDS_PLL_CNTL,rinfo->save_regs[12]); + OUTREG(TV_DAC_CNTL, rinfo->save_regs[13]); + OUTREG(BUS_CNTL1, rinfo->save_regs[14]); + OUTREG(CRTC_OFFSET_CNTL, rinfo->save_regs[15]); + OUTREG(AGP_CNTL, rinfo->save_regs[16]); + OUTREG(CRTC_GEN_CNTL, rinfo->save_regs[17]); + OUTREG(CRTC2_GEN_CNTL, rinfo->save_regs[18]); + OUTPLL(P2PLL_CNTL, rinfo->save_regs[8]); + + OUTREG(GPIOPAD_A, rinfo->save_regs[19]); + OUTREG(GPIOPAD_EN, rinfo->save_regs[20]); + OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]); + OUTREG(ZV_LCDPAD_A, rinfo->save_regs[22]); + OUTREG(ZV_LCDPAD_EN, rinfo->save_regs[23]); + OUTREG(ZV_LCDPAD_MASK, rinfo->save_regs[24]); + OUTREG(GPIO_VGA_DDC, rinfo->save_regs[25]); + OUTREG(GPIO_DVI_DDC, rinfo->save_regs[26]); + OUTREG(GPIO_MONID, rinfo->save_regs[27]); + OUTREG(GPIO_CRT2_DDC, rinfo->save_regs[28]); +} + +static void radeon_pm_disable_iopad(struct radeonfb_info *rinfo) +{ + OUTREG(GPIOPAD_MASK, 0x0001ffff); + OUTREG(GPIOPAD_EN, 0x00000400); + OUTREG(GPIOPAD_A, 0x00000000); + OUTREG(ZV_LCDPAD_MASK, 0x00000000); + OUTREG(ZV_LCDPAD_EN, 0x00000000); + OUTREG(ZV_LCDPAD_A, 0x00000000); + OUTREG(GPIO_VGA_DDC, 0x00030000); + OUTREG(GPIO_DVI_DDC, 0x00000000); + OUTREG(GPIO_MONID, 0x00030000); + OUTREG(GPIO_CRT2_DDC, 0x00000000); +} + +static void radeon_pm_program_v2clk(struct radeonfb_info *rinfo) +{ + /* Set v2clk to 65MHz */ + if (rinfo->family <= CHIP_FAMILY_RV280) { + OUTPLL(pllPIXCLKS_CNTL, + __INPLL(rinfo, pllPIXCLKS_CNTL) + & ~PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK); + + OUTPLL(pllP2PLL_REF_DIV, 0x0000000c); + OUTPLL(pllP2PLL_CNTL, 0x0000bf00); + } else { + OUTPLL(pllP2PLL_REF_DIV, 0x0000000c); + INPLL(pllP2PLL_REF_DIV); + OUTPLL(pllP2PLL_CNTL, 0x0000a700); + } + + OUTPLL(pllP2PLL_DIV_0, 0x00020074 | P2PLL_DIV_0__P2PLL_ATOMIC_UPDATE_W); + + OUTPLL(pllP2PLL_CNTL, INPLL(pllP2PLL_CNTL) & ~P2PLL_CNTL__P2PLL_SLEEP); + mdelay(1); + + OUTPLL(pllP2PLL_CNTL, INPLL(pllP2PLL_CNTL) & ~P2PLL_CNTL__P2PLL_RESET); + mdelay( 1); + + OUTPLL(pllPIXCLKS_CNTL, + (INPLL(pllPIXCLKS_CNTL) & ~PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK) + | (0x03 << PIXCLKS_CNTL__PIX2CLK_SRC_SEL__SHIFT)); + mdelay( 1); +} + +static void radeon_pm_low_current(struct radeonfb_info *rinfo) +{ + u32 reg; + + reg = INREG(BUS_CNTL1); + if (rinfo->family <= CHIP_FAMILY_RV280) { + reg &= ~BUS_CNTL1_MOBILE_PLATFORM_SEL_MASK; + reg |= BUS_CNTL1_AGPCLK_VALID | (1<<BUS_CNTL1_MOBILE_PLATFORM_SEL_SHIFT); + } else { + reg |= 0x4080; + } + OUTREG(BUS_CNTL1, reg); + + reg = INPLL(PLL_PWRMGT_CNTL); + reg |= PLL_PWRMGT_CNTL_SPLL_TURNOFF | PLL_PWRMGT_CNTL_PPLL_TURNOFF | + PLL_PWRMGT_CNTL_P2PLL_TURNOFF | PLL_PWRMGT_CNTL_TVPLL_TURNOFF; + reg &= ~PLL_PWRMGT_CNTL_SU_MCLK_USE_BCLK; + reg &= ~PLL_PWRMGT_CNTL_MOBILE_SU; + OUTPLL(PLL_PWRMGT_CNTL, reg); + + reg = INREG(TV_DAC_CNTL); + reg &= ~(TV_DAC_CNTL_BGADJ_MASK |TV_DAC_CNTL_DACADJ_MASK); + reg |=TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD | TV_DAC_CNTL_GDACPD | + TV_DAC_CNTL_BDACPD | + (8<<TV_DAC_CNTL_BGADJ__SHIFT) | (8<<TV_DAC_CNTL_DACADJ__SHIFT); + OUTREG(TV_DAC_CNTL, reg); + + reg = INREG(TMDS_TRANSMITTER_CNTL); + reg &= ~(TMDS_PLL_EN | TMDS_PLLRST); + OUTREG(TMDS_TRANSMITTER_CNTL, reg); + + reg = INREG(DAC_CNTL); + reg &= ~DAC_CMP_EN; + OUTREG(DAC_CNTL, reg); + + reg = INREG(DAC_CNTL2); + reg &= ~DAC2_CMP_EN; + OUTREG(DAC_CNTL2, reg); + + reg = INREG(TV_DAC_CNTL); + reg &= ~TV_DAC_CNTL_DETECT; + OUTREG(TV_DAC_CNTL, reg); +} + +static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo) +{ + + u32 sclk_cntl, mclk_cntl, sclk_more_cntl; + + u32 pll_pwrmgt_cntl; + u32 clk_pwrmgt_cntl; + u32 clk_pin_cntl; + u32 vclk_ecp_cntl; + u32 pixclks_cntl; + u32 disp_mis_cntl; + u32 disp_pwr_man; + u32 tmp; + + /* Force Core Clocks */ + sclk_cntl = INPLL( pllSCLK_CNTL); + sclk_cntl |= SCLK_CNTL__IDCT_MAX_DYN_STOP_LAT| + SCLK_CNTL__VIP_MAX_DYN_STOP_LAT| + SCLK_CNTL__RE_MAX_DYN_STOP_LAT| + SCLK_CNTL__PB_MAX_DYN_STOP_LAT| + SCLK_CNTL__TAM_MAX_DYN_STOP_LAT| + SCLK_CNTL__TDM_MAX_DYN_STOP_LAT| + SCLK_CNTL__RB_MAX_DYN_STOP_LAT| + + SCLK_CNTL__FORCE_DISP2| + SCLK_CNTL__FORCE_CP| + SCLK_CNTL__FORCE_HDP| + SCLK_CNTL__FORCE_DISP1| + SCLK_CNTL__FORCE_TOP| + SCLK_CNTL__FORCE_E2| + SCLK_CNTL__FORCE_SE| + SCLK_CNTL__FORCE_IDCT| + SCLK_CNTL__FORCE_VIP| + + SCLK_CNTL__FORCE_PB| + SCLK_CNTL__FORCE_TAM| + SCLK_CNTL__FORCE_TDM| + SCLK_CNTL__FORCE_RB| + SCLK_CNTL__FORCE_TV_SCLK| + SCLK_CNTL__FORCE_SUBPIC| + SCLK_CNTL__FORCE_OV0; + if (rinfo->family <= CHIP_FAMILY_RV280) + sclk_cntl |= SCLK_CNTL__FORCE_RE; + else + sclk_cntl |= SCLK_CNTL__SE_MAX_DYN_STOP_LAT | + SCLK_CNTL__E2_MAX_DYN_STOP_LAT | + SCLK_CNTL__TV_MAX_DYN_STOP_LAT | + SCLK_CNTL__HDP_MAX_DYN_STOP_LAT | + SCLK_CNTL__CP_MAX_DYN_STOP_LAT; + + OUTPLL( pllSCLK_CNTL, sclk_cntl); + + sclk_more_cntl = INPLL(pllSCLK_MORE_CNTL); + sclk_more_cntl |= SCLK_MORE_CNTL__FORCE_DISPREGS | + SCLK_MORE_CNTL__FORCE_MC_GUI | + SCLK_MORE_CNTL__FORCE_MC_HOST; + + OUTPLL(pllSCLK_MORE_CNTL, sclk_more_cntl); + + + mclk_cntl = INPLL( pllMCLK_CNTL); + mclk_cntl &= ~( MCLK_CNTL__FORCE_MCLKA | + MCLK_CNTL__FORCE_MCLKB | + MCLK_CNTL__FORCE_YCLKA | + MCLK_CNTL__FORCE_YCLKB | + MCLK_CNTL__FORCE_MC + ); + OUTPLL( pllMCLK_CNTL, mclk_cntl); + + /* Force Display clocks */ + vclk_ecp_cntl = INPLL( pllVCLK_ECP_CNTL); + vclk_ecp_cntl &= ~(VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb + | VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb); + vclk_ecp_cntl |= VCLK_ECP_CNTL__ECP_FORCE_ON; + OUTPLL( pllVCLK_ECP_CNTL, vclk_ecp_cntl); + + + pixclks_cntl = INPLL( pllPIXCLKS_CNTL); + pixclks_cntl &= ~( PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb | + PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb| + PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb | + PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb| + PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb| + PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb| + PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb); + + OUTPLL( pllPIXCLKS_CNTL, pixclks_cntl); + + /* Switch off LVDS interface */ + OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & + ~(LVDS_BLON | LVDS_EN | LVDS_ON | LVDS_DIGON)); + + /* Enable System power management */ + pll_pwrmgt_cntl = INPLL( pllPLL_PWRMGT_CNTL); + + pll_pwrmgt_cntl |= PLL_PWRMGT_CNTL__SPLL_TURNOFF | + PLL_PWRMGT_CNTL__MPLL_TURNOFF| + PLL_PWRMGT_CNTL__PPLL_TURNOFF| + PLL_PWRMGT_CNTL__P2PLL_TURNOFF| + PLL_PWRMGT_CNTL__TVPLL_TURNOFF; + + OUTPLL( pllPLL_PWRMGT_CNTL, pll_pwrmgt_cntl); + + clk_pwrmgt_cntl = INPLL( pllCLK_PWRMGT_CNTL); + + clk_pwrmgt_cntl &= ~( CLK_PWRMGT_CNTL__MPLL_PWRMGT_OFF| + CLK_PWRMGT_CNTL__SPLL_PWRMGT_OFF| + CLK_PWRMGT_CNTL__PPLL_PWRMGT_OFF| + CLK_PWRMGT_CNTL__P2PLL_PWRMGT_OFF| + CLK_PWRMGT_CNTL__MCLK_TURNOFF| + CLK_PWRMGT_CNTL__SCLK_TURNOFF| + CLK_PWRMGT_CNTL__PCLK_TURNOFF| + CLK_PWRMGT_CNTL__P2CLK_TURNOFF| + CLK_PWRMGT_CNTL__TVPLL_PWRMGT_OFF| + CLK_PWRMGT_CNTL__GLOBAL_PMAN_EN| + CLK_PWRMGT_CNTL__ENGINE_DYNCLK_MODE| + CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK| + CLK_PWRMGT_CNTL__CG_NO1_DEBUG_MASK + ); + + clk_pwrmgt_cntl |= CLK_PWRMGT_CNTL__GLOBAL_PMAN_EN + | CLK_PWRMGT_CNTL__DISP_PM; + + OUTPLL( pllCLK_PWRMGT_CNTL, clk_pwrmgt_cntl); + + clk_pin_cntl = INPLL( pllCLK_PIN_CNTL); + + clk_pin_cntl &= ~CLK_PIN_CNTL__ACCESS_REGS_IN_SUSPEND; + + /* because both INPLL and OUTPLL take the same lock, that's why. */ + tmp = INPLL( pllMCLK_MISC) | MCLK_MISC__EN_MCLK_TRISTATE_IN_SUSPEND; + OUTPLL( pllMCLK_MISC, tmp); + + /* AGP PLL control */ + if (rinfo->family <= CHIP_FAMILY_RV280) { + OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) | BUS_CNTL1__AGPCLK_VALID); + + OUTREG(BUS_CNTL1, + (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK) + | (2<<BUS_CNTL1__MOBILE_PLATFORM_SEL__SHIFT)); // 440BX + } else { + OUTREG(BUS_CNTL1, INREG(BUS_CNTL1)); + OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & ~0x4000) | 0x8000); + } + + OUTREG(CRTC_OFFSET_CNTL, (INREG(CRTC_OFFSET_CNTL) + & ~CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN)); + + clk_pin_cntl &= ~CLK_PIN_CNTL__CG_CLK_TO_OUTPIN; + clk_pin_cntl |= CLK_PIN_CNTL__XTALIN_ALWAYS_ONb; + OUTPLL( pllCLK_PIN_CNTL, clk_pin_cntl); + + /* Solano2M */ + OUTREG(AGP_CNTL, + (INREG(AGP_CNTL) & ~(AGP_CNTL__MAX_IDLE_CLK_MASK)) + | (0x20<<AGP_CNTL__MAX_IDLE_CLK__SHIFT)); + + /* ACPI mode */ + /* because both INPLL and OUTPLL take the same lock, that's why. */ + tmp = INPLL( pllPLL_PWRMGT_CNTL) & ~PLL_PWRMGT_CNTL__PM_MODE_SEL; + OUTPLL( pllPLL_PWRMGT_CNTL, tmp); + + + disp_mis_cntl = INREG(DISP_MISC_CNTL); + + disp_mis_cntl &= ~( DISP_MISC_CNTL__SOFT_RESET_GRPH_PP | + DISP_MISC_CNTL__SOFT_RESET_SUBPIC_PP | + DISP_MISC_CNTL__SOFT_RESET_OV0_PP | + DISP_MISC_CNTL__SOFT_RESET_GRPH_SCLK| + DISP_MISC_CNTL__SOFT_RESET_SUBPIC_SCLK| + DISP_MISC_CNTL__SOFT_RESET_OV0_SCLK| + DISP_MISC_CNTL__SOFT_RESET_GRPH2_PP| + DISP_MISC_CNTL__SOFT_RESET_GRPH2_SCLK| + DISP_MISC_CNTL__SOFT_RESET_LVDS| + DISP_MISC_CNTL__SOFT_RESET_TMDS| + DISP_MISC_CNTL__SOFT_RESET_DIG_TMDS| + DISP_MISC_CNTL__SOFT_RESET_TV); + + OUTREG(DISP_MISC_CNTL, disp_mis_cntl); + + disp_pwr_man = INREG(DISP_PWR_MAN); + + disp_pwr_man &= ~( DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN | + DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN | + DISP_PWR_MAN__DISP_PWR_MAN_DPMS_MASK| + DISP_PWR_MAN__DISP_D3_RST| + DISP_PWR_MAN__DISP_D3_REG_RST + ); + + disp_pwr_man |= DISP_PWR_MAN__DISP_D3_GRPH_RST| + DISP_PWR_MAN__DISP_D3_SUBPIC_RST| + DISP_PWR_MAN__DISP_D3_OV0_RST| + DISP_PWR_MAN__DISP_D1D2_GRPH_RST| + DISP_PWR_MAN__DISP_D1D2_SUBPIC_RST| + DISP_PWR_MAN__DISP_D1D2_OV0_RST| + DISP_PWR_MAN__DIG_TMDS_ENABLE_RST| + DISP_PWR_MAN__TV_ENABLE_RST| +// DISP_PWR_MAN__AUTO_PWRUP_EN| + 0; + + OUTREG(DISP_PWR_MAN, disp_pwr_man); + + clk_pwrmgt_cntl = INPLL( pllCLK_PWRMGT_CNTL); + pll_pwrmgt_cntl = INPLL( pllPLL_PWRMGT_CNTL) ; + clk_pin_cntl = INPLL( pllCLK_PIN_CNTL); + disp_pwr_man = INREG(DISP_PWR_MAN); + + + /* D2 */ + clk_pwrmgt_cntl |= CLK_PWRMGT_CNTL__DISP_PM; + pll_pwrmgt_cntl |= PLL_PWRMGT_CNTL__MOBILE_SU | PLL_PWRMGT_CNTL__SU_SCLK_USE_BCLK; + clk_pin_cntl |= CLK_PIN_CNTL__XTALIN_ALWAYS_ONb; + disp_pwr_man &= ~(DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN_MASK + | DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN_MASK); + + OUTPLL( pllCLK_PWRMGT_CNTL, clk_pwrmgt_cntl); + OUTPLL( pllPLL_PWRMGT_CNTL, pll_pwrmgt_cntl); + OUTPLL( pllCLK_PIN_CNTL, clk_pin_cntl); + OUTREG(DISP_PWR_MAN, disp_pwr_man); + + /* disable display request & disable display */ + OUTREG( CRTC_GEN_CNTL, (INREG( CRTC_GEN_CNTL) & ~CRTC_GEN_CNTL__CRTC_EN) + | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B); + OUTREG( CRTC2_GEN_CNTL, (INREG( CRTC2_GEN_CNTL) & ~CRTC2_GEN_CNTL__CRTC2_EN) + | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B); + + mdelay(17); + +} + +static void radeon_pm_yclk_mclk_sync(struct radeonfb_info *rinfo) +{ + u32 mc_chp_io_cntl_a1, mc_chp_io_cntl_b1; + + mc_chp_io_cntl_a1 = INMC( rinfo, ixMC_CHP_IO_CNTL_A1) + & ~MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA_MASK; + mc_chp_io_cntl_b1 = INMC( rinfo, ixMC_CHP_IO_CNTL_B1) + & ~MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB_MASK; + + OUTMC( rinfo, ixMC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1 + | (1<<MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA__SHIFT)); + OUTMC( rinfo, ixMC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1 + | (1<<MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB__SHIFT)); + + OUTMC( rinfo, ixMC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1); + OUTMC( rinfo, ixMC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1); + + mdelay( 1); +} + +static void radeon_pm_yclk_mclk_sync_m10(struct radeonfb_info *rinfo) +{ + u32 mc_chp_io_cntl_a1, mc_chp_io_cntl_b1; + + mc_chp_io_cntl_a1 = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_A1) + & ~MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA_MASK; + mc_chp_io_cntl_b1 = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_B1) + & ~MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB_MASK; + + OUTMC( rinfo, ixR300_MC_CHP_IO_CNTL_A1, + mc_chp_io_cntl_a1 | (1<<MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA__SHIFT)); + OUTMC( rinfo, ixR300_MC_CHP_IO_CNTL_B1, + mc_chp_io_cntl_b1 | (1<<MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB__SHIFT)); + + OUTMC( rinfo, ixR300_MC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1); + OUTMC( rinfo, ixR300_MC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1); + + mdelay( 1); +} + +static void radeon_pm_program_mode_reg(struct radeonfb_info *rinfo, u16 value, + u8 delay_required) +{ + u32 mem_sdram_mode; + + mem_sdram_mode = INREG( MEM_SDRAM_MODE_REG); + + mem_sdram_mode &= ~MEM_SDRAM_MODE_REG__MEM_MODE_REG_MASK; + mem_sdram_mode |= (value<<MEM_SDRAM_MODE_REG__MEM_MODE_REG__SHIFT) + | MEM_SDRAM_MODE_REG__MEM_CFG_TYPE; + OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode); + if (delay_required >= 2) + mdelay(1); + + mem_sdram_mode |= MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET; + OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode); + if (delay_required >= 2) + mdelay(1); + + mem_sdram_mode &= ~MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET; + OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode); + if (delay_required >= 2) + mdelay(1); + + if (delay_required) { + do { + if (delay_required >= 2) + mdelay(1); + } while ((INREG(MC_STATUS) + & (MC_STATUS__MEM_PWRUP_COMPL_A | + MC_STATUS__MEM_PWRUP_COMPL_B)) == 0); + } +} + +static void radeon_pm_m10_program_mode_wait(struct radeonfb_info *rinfo) +{ + int cnt; + + for (cnt = 0; cnt < 100; ++cnt) { + mdelay(1); + if (INREG(MC_STATUS) & (MC_STATUS__MEM_PWRUP_COMPL_A + | MC_STATUS__MEM_PWRUP_COMPL_B)) + break; + } +} + + +static void radeon_pm_enable_dll(struct radeonfb_info *rinfo) +{ +#define DLL_RESET_DELAY 5 +#define DLL_SLEEP_DELAY 1 + + u32 cko = INPLL(pllMDLL_CKO) | MDLL_CKO__MCKOA_SLEEP + | MDLL_CKO__MCKOA_RESET; + u32 cka = INPLL(pllMDLL_RDCKA) | MDLL_RDCKA__MRDCKA0_SLEEP + | MDLL_RDCKA__MRDCKA1_SLEEP | MDLL_RDCKA__MRDCKA0_RESET + | MDLL_RDCKA__MRDCKA1_RESET; + u32 ckb = INPLL(pllMDLL_RDCKB) | MDLL_RDCKB__MRDCKB0_SLEEP + | MDLL_RDCKB__MRDCKB1_SLEEP | MDLL_RDCKB__MRDCKB0_RESET + | MDLL_RDCKB__MRDCKB1_RESET; + + /* Setting up the DLL range for write */ + OUTPLL(pllMDLL_CKO, cko); + OUTPLL(pllMDLL_RDCKA, cka); + OUTPLL(pllMDLL_RDCKB, ckb); + + mdelay(DLL_RESET_DELAY*2); + + cko &= ~(MDLL_CKO__MCKOA_SLEEP | MDLL_CKO__MCKOB_SLEEP); + OUTPLL(pllMDLL_CKO, cko); + mdelay(DLL_SLEEP_DELAY); + cko &= ~(MDLL_CKO__MCKOA_RESET | MDLL_CKO__MCKOB_RESET); + OUTPLL(pllMDLL_CKO, cko); + mdelay(DLL_RESET_DELAY); + + cka &= ~(MDLL_RDCKA__MRDCKA0_SLEEP | MDLL_RDCKA__MRDCKA1_SLEEP); + OUTPLL(pllMDLL_RDCKA, cka); + mdelay(DLL_SLEEP_DELAY); + cka &= ~(MDLL_RDCKA__MRDCKA0_RESET | MDLL_RDCKA__MRDCKA1_RESET); + OUTPLL(pllMDLL_RDCKA, cka); + mdelay(DLL_RESET_DELAY); + + ckb &= ~(MDLL_RDCKB__MRDCKB0_SLEEP | MDLL_RDCKB__MRDCKB1_SLEEP); + OUTPLL(pllMDLL_RDCKB, ckb); + mdelay(DLL_SLEEP_DELAY); + ckb &= ~(MDLL_RDCKB__MRDCKB0_RESET | MDLL_RDCKB__MRDCKB1_RESET); + OUTPLL(pllMDLL_RDCKB, ckb); + mdelay(DLL_RESET_DELAY); + + +#undef DLL_RESET_DELAY +#undef DLL_SLEEP_DELAY +} + +static void radeon_pm_enable_dll_m10(struct radeonfb_info *rinfo) +{ + u32 dll_value; + u32 dll_sleep_mask = 0; + u32 dll_reset_mask = 0; + u32 mc; + +#define DLL_RESET_DELAY 5 +#define DLL_SLEEP_DELAY 1 + + OUTMC(rinfo, ixR300_MC_DLL_CNTL, rinfo->save_regs[70]); + mc = INREG(MC_CNTL); + /* Check which channels are enabled */ + switch (mc & 0x3) { + case 1: + if (mc & 0x4) + break; + case 2: + dll_sleep_mask |= MDLL_R300_RDCK__MRDCKB_SLEEP; + dll_reset_mask |= MDLL_R300_RDCK__MRDCKB_RESET; + case 0: + dll_sleep_mask |= MDLL_R300_RDCK__MRDCKA_SLEEP; + dll_reset_mask |= MDLL_R300_RDCK__MRDCKA_RESET; + } + switch (mc & 0x3) { + case 1: + if (!(mc & 0x4)) + break; + case 2: + dll_sleep_mask |= MDLL_R300_RDCK__MRDCKD_SLEEP; + dll_reset_mask |= MDLL_R300_RDCK__MRDCKD_RESET; + dll_sleep_mask |= MDLL_R300_RDCK__MRDCKC_SLEEP; + dll_reset_mask |= MDLL_R300_RDCK__MRDCKC_RESET; + } + + dll_value = INPLL(pllMDLL_RDCKA); + + /* Power Up */ + dll_value &= ~(dll_sleep_mask); + OUTPLL(pllMDLL_RDCKA, dll_value); + mdelay( DLL_SLEEP_DELAY); + + dll_value &= ~(dll_reset_mask); + OUTPLL(pllMDLL_RDCKA, dll_value); + mdelay( DLL_RESET_DELAY); + +#undef DLL_RESET_DELAY +#undef DLL_SLEEP_DELAY +} + + +static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo) +{ + u32 crtcGenCntl, crtcGenCntl2, memRefreshCntl, crtc_more_cntl, + fp_gen_cntl, fp2_gen_cntl; + + crtcGenCntl = INREG( CRTC_GEN_CNTL); + crtcGenCntl2 = INREG( CRTC2_GEN_CNTL); + + crtc_more_cntl = INREG( CRTC_MORE_CNTL); + fp_gen_cntl = INREG( FP_GEN_CNTL); + fp2_gen_cntl = INREG( FP2_GEN_CNTL); + + + OUTREG( CRTC_MORE_CNTL, 0); + OUTREG( FP_GEN_CNTL, 0); + OUTREG( FP2_GEN_CNTL,0); + + OUTREG( CRTC_GEN_CNTL, (crtcGenCntl | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B) ); + OUTREG( CRTC2_GEN_CNTL, (crtcGenCntl2 | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B) ); + + /* This is the code for the Aluminium PowerBooks M10 */ + if (rinfo->family == CHIP_FAMILY_RV350) { + u32 sdram_mode_reg = rinfo->save_regs[35]; + static u32 default_mrtable[] = + { 0x21320032, + 0x21321000, 0xa1321000, 0x21321000, 0xffffffff, + 0x21320032, 0xa1320032, 0x21320032, 0xffffffff, + 0x21321002, 0xa1321002, 0x21321002, 0xffffffff, + 0x21320132, 0xa1320132, 0x21320132, 0xffffffff, + 0x21320032, 0xa1320032, 0x21320032, 0xffffffff, + 0x31320032 }; + + u32 *mrtable = default_mrtable; + int i, mrtable_size = ARRAY_SIZE(default_mrtable); + + mdelay(30); + + /* Disable refresh */ + memRefreshCntl = INREG( MEM_REFRESH_CNTL) + & ~MEM_REFRESH_CNTL__MEM_REFRESH_DIS; + OUTREG( MEM_REFRESH_CNTL, memRefreshCntl + | MEM_REFRESH_CNTL__MEM_REFRESH_DIS); + + /* Configure and enable M & SPLLs */ + radeon_pm_enable_dll_m10(rinfo); + radeon_pm_yclk_mclk_sync_m10(rinfo); + +#ifdef CONFIG_PPC_OF + if (rinfo->of_node != NULL) { + int size; + + mrtable = (u32 *)get_property(rinfo->of_node, "ATY,MRT", &size); + if (mrtable) + mrtable_size = size >> 2; + else + mrtable = default_mrtable; + } +#endif /* CONFIG_PPC_OF */ + + /* Program the SDRAM */ + sdram_mode_reg = mrtable[0]; + OUTREG(MEM_SDRAM_MODE_REG, sdram_mode_reg); + for (i = 0; i < mrtable_size; i++) { + if (mrtable[i] == 0xffffffffu) + radeon_pm_m10_program_mode_wait(rinfo); + else { + sdram_mode_reg &= ~(MEM_SDRAM_MODE_REG__MEM_MODE_REG_MASK + | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE + | MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET); + sdram_mode_reg |= mrtable[i]; + + OUTREG(MEM_SDRAM_MODE_REG, sdram_mode_reg); + mdelay(1); + } + } + + /* Restore memory refresh */ + OUTREG(MEM_REFRESH_CNTL, memRefreshCntl); + mdelay(30); + + } + /* Here come the desktop RV200 "QW" card */ + else if (!rinfo->is_mobility && rinfo->family == CHIP_FAMILY_RV200) { + /* Disable refresh */ + memRefreshCntl = INREG( MEM_REFRESH_CNTL) + & ~MEM_REFRESH_CNTL__MEM_REFRESH_DIS; + OUTREG(MEM_REFRESH_CNTL, memRefreshCntl + | MEM_REFRESH_CNTL__MEM_REFRESH_DIS); + mdelay(30); + + /* Reset memory */ + OUTREG(MEM_SDRAM_MODE_REG, + INREG( MEM_SDRAM_MODE_REG) & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); + + radeon_pm_program_mode_reg(rinfo, 0x2002, 2); + radeon_pm_program_mode_reg(rinfo, 0x0132, 2); + radeon_pm_program_mode_reg(rinfo, 0x0032, 2); + + OUTREG(MEM_SDRAM_MODE_REG, + INREG(MEM_SDRAM_MODE_REG) | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); + + OUTREG( MEM_REFRESH_CNTL, memRefreshCntl); + + } + /* The M6 */ + else if (rinfo->is_mobility && rinfo->family == CHIP_FAMILY_RV100) { + /* Disable refresh */ + memRefreshCntl = INREG(EXT_MEM_CNTL) & ~(1 << 20); + OUTREG( EXT_MEM_CNTL, memRefreshCntl | (1 << 20)); + + /* Reset memory */ + OUTREG( MEM_SDRAM_MODE_REG, + INREG( MEM_SDRAM_MODE_REG) + & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); + + /* DLL */ + radeon_pm_enable_dll(rinfo); + + /* MLCK / YCLK sync */ + radeon_pm_yclk_mclk_sync(rinfo); + + /* Program Mode Register */ + radeon_pm_program_mode_reg(rinfo, 0x2000, 1); + radeon_pm_program_mode_reg(rinfo, 0x2001, 1); + radeon_pm_program_mode_reg(rinfo, 0x2002, 1); + radeon_pm_program_mode_reg(rinfo, 0x0132, 1); + radeon_pm_program_mode_reg(rinfo, 0x0032, 1); + + /* Complete & re-enable refresh */ + OUTREG( MEM_SDRAM_MODE_REG, + INREG( MEM_SDRAM_MODE_REG) | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); + + OUTREG(EXT_MEM_CNTL, memRefreshCntl); + } + /* And finally, the M7..M9 models, including M9+ (RV280) */ + else if (rinfo->is_mobility) { + + /* Disable refresh */ + memRefreshCntl = INREG( MEM_REFRESH_CNTL) + & ~MEM_REFRESH_CNTL__MEM_REFRESH_DIS; + OUTREG( MEM_REFRESH_CNTL, memRefreshCntl + | MEM_REFRESH_CNTL__MEM_REFRESH_DIS); + + /* Reset memory */ + OUTREG( MEM_SDRAM_MODE_REG, + INREG( MEM_SDRAM_MODE_REG) + & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); + + /* DLL */ + radeon_pm_enable_dll(rinfo); + + /* MLCK / YCLK sync */ + radeon_pm_yclk_mclk_sync(rinfo); + + /* M6, M7 and M9 so far ... */ + if (rinfo->family <= CHIP_FAMILY_RV250) { + radeon_pm_program_mode_reg(rinfo, 0x2000, 1); + radeon_pm_program_mode_reg(rinfo, 0x2001, 1); + radeon_pm_program_mode_reg(rinfo, 0x2002, 1); + radeon_pm_program_mode_reg(rinfo, 0x0132, 1); + radeon_pm_program_mode_reg(rinfo, 0x0032, 1); + } + /* M9+ (iBook G4) */ + else if (rinfo->family == CHIP_FAMILY_RV280) { + radeon_pm_program_mode_reg(rinfo, 0x2000, 1); + radeon_pm_program_mode_reg(rinfo, 0x0132, 1); + radeon_pm_program_mode_reg(rinfo, 0x0032, 1); + } + + /* Complete & re-enable refresh */ + OUTREG( MEM_SDRAM_MODE_REG, + INREG( MEM_SDRAM_MODE_REG) | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); + + OUTREG( MEM_REFRESH_CNTL, memRefreshCntl); + } + + OUTREG( CRTC_GEN_CNTL, crtcGenCntl); + OUTREG( CRTC2_GEN_CNTL, crtcGenCntl2); + OUTREG( FP_GEN_CNTL, fp_gen_cntl); + OUTREG( FP2_GEN_CNTL, fp2_gen_cntl); + + OUTREG( CRTC_MORE_CNTL, crtc_more_cntl); + + mdelay( 15); +} + +#ifdef CONFIG_PPC_OF + +static void radeon_pm_reset_pad_ctlr_strength(struct radeonfb_info *rinfo) +{ + u32 tmp, tmp2; + int i,j; + + /* Reset the PAD_CTLR_STRENGTH & wait for it to be stable */ + INREG(PAD_CTLR_STRENGTH); + OUTREG(PAD_CTLR_STRENGTH, INREG(PAD_CTLR_STRENGTH) & ~PAD_MANUAL_OVERRIDE); + tmp = INREG(PAD_CTLR_STRENGTH); + for (i = j = 0; i < 65; ++i) { + mdelay(1); + tmp2 = INREG(PAD_CTLR_STRENGTH); + if (tmp != tmp2) { + tmp = tmp2; + i = 0; + j++; + if (j > 10) { + printk(KERN_WARNING "radeon: PAD_CTLR_STRENGTH doesn't " + "stabilize !\n"); + break; + } + } + } +} + +static void radeon_pm_all_ppls_off(struct radeonfb_info *rinfo) +{ + u32 tmp; + + tmp = INPLL(pllPPLL_CNTL); + OUTPLL(pllPPLL_CNTL, tmp | 0x3); + tmp = INPLL(pllP2PLL_CNTL); + OUTPLL(pllP2PLL_CNTL, tmp | 0x3); + tmp = INPLL(pllSPLL_CNTL); + OUTPLL(pllSPLL_CNTL, tmp | 0x3); + tmp = INPLL(pllMPLL_CNTL); + OUTPLL(pllMPLL_CNTL, tmp | 0x3); +} + +static void radeon_pm_start_mclk_sclk(struct radeonfb_info *rinfo) +{ + u32 tmp; + + /* Switch SPLL to PCI source */ + tmp = INPLL(pllSCLK_CNTL); + OUTPLL(pllSCLK_CNTL, tmp & ~SCLK_CNTL__SCLK_SRC_SEL_MASK); + + /* Reconfigure SPLL charge pump, VCO gain, duty cycle */ + tmp = INPLL(pllSPLL_CNTL); + OUTREG8(CLOCK_CNTL_INDEX, pllSPLL_CNTL + PLL_WR_EN); + radeon_pll_errata_after_index(rinfo); + OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff); + radeon_pll_errata_after_data(rinfo); + + /* Set SPLL feedback divider */ + tmp = INPLL(pllM_SPLL_REF_FB_DIV); + tmp = (tmp & 0xff00fffful) | (rinfo->save_regs[77] & 0x00ff0000ul); + OUTPLL(pllM_SPLL_REF_FB_DIV, tmp); + + /* Power up SPLL */ + tmp = INPLL(pllSPLL_CNTL); + OUTPLL(pllSPLL_CNTL, tmp & ~1); + (void)INPLL(pllSPLL_CNTL); + + mdelay(10); + + /* Release SPLL reset */ + tmp = INPLL(pllSPLL_CNTL); + OUTPLL(pllSPLL_CNTL, tmp & ~0x2); + (void)INPLL(pllSPLL_CNTL); + + mdelay(10); + + /* Select SCLK source */ + tmp = INPLL(pllSCLK_CNTL); + tmp &= ~SCLK_CNTL__SCLK_SRC_SEL_MASK; + tmp |= rinfo->save_regs[3] & SCLK_CNTL__SCLK_SRC_SEL_MASK; + OUTPLL(pllSCLK_CNTL, tmp); + (void)INPLL(pllSCLK_CNTL); + + mdelay(10); + + /* Reconfigure MPLL charge pump, VCO gain, duty cycle */ + tmp = INPLL(pllMPLL_CNTL); + OUTREG8(CLOCK_CNTL_INDEX, pllMPLL_CNTL + PLL_WR_EN); + radeon_pll_errata_after_index(rinfo); + OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff); + radeon_pll_errata_after_data(rinfo); + + /* Set MPLL feedback divider */ + tmp = INPLL(pllM_SPLL_REF_FB_DIV); + tmp = (tmp & 0xffff00fful) | (rinfo->save_regs[77] & 0x0000ff00ul); + + OUTPLL(pllM_SPLL_REF_FB_DIV, tmp); + /* Power up MPLL */ + tmp = INPLL(pllMPLL_CNTL); + OUTPLL(pllMPLL_CNTL, tmp & ~0x2); + (void)INPLL(pllMPLL_CNTL); + + mdelay(10); + + /* Un-reset MPLL */ + tmp = INPLL(pllMPLL_CNTL); + OUTPLL(pllMPLL_CNTL, tmp & ~0x1); + (void)INPLL(pllMPLL_CNTL); + + mdelay(10); + + /* Select source for MCLK */ + tmp = INPLL(pllMCLK_CNTL); + tmp |= rinfo->save_regs[2] & 0xffff; + OUTPLL(pllMCLK_CNTL, tmp); + (void)INPLL(pllMCLK_CNTL); + + mdelay(10); +} + +static void radeon_pm_m10_disable_spread_spectrum(struct radeonfb_info *rinfo) +{ + u32 r2ec; + + /* GACK ! I though we didn't have a DDA on Radeon's anymore + * here we rewrite with the same value, ... I suppose we clear + * some bits that are already clear ? Or maybe this 0x2ec + * register is something new ? + */ + mdelay(20); + r2ec = INREG(VGA_DDA_ON_OFF); + OUTREG(VGA_DDA_ON_OFF, r2ec); + mdelay(1); + + /* Spread spectrum PLLL off */ + OUTPLL(pllSSPLL_CNTL, 0xbf03); + + /* Spread spectrum disabled */ + OUTPLL(pllSS_INT_CNTL, rinfo->save_regs[90] & ~3); + + /* The trace shows read & rewrite of LVDS_PLL_CNTL here with same + * value, not sure what for... + */ + + r2ec |= 0x3f0; + OUTREG(VGA_DDA_ON_OFF, r2ec); + mdelay(1); +} + +static void radeon_pm_m10_enable_lvds_spread_spectrum(struct radeonfb_info *rinfo) +{ + u32 r2ec, tmp; + + /* GACK (bis) ! I though we didn't have a DDA on Radeon's anymore + * here we rewrite with the same value, ... I suppose we clear/set + * some bits that are already clear/set ? + */ + r2ec = INREG(VGA_DDA_ON_OFF); + OUTREG(VGA_DDA_ON_OFF, r2ec); + mdelay(1); + + /* Enable spread spectrum */ + OUTPLL(pllSSPLL_CNTL, rinfo->save_regs[43] | 3); + mdelay(3); + + OUTPLL(pllSSPLL_REF_DIV, rinfo->save_regs[44]); + OUTPLL(pllSSPLL_DIV_0, rinfo->save_regs[45]); + tmp = INPLL(pllSSPLL_CNTL); + OUTPLL(pllSSPLL_CNTL, tmp & ~0x2); + mdelay(6); + tmp = INPLL(pllSSPLL_CNTL); + OUTPLL(pllSSPLL_CNTL, tmp & ~0x1); + mdelay(5); + + OUTPLL(pllSS_INT_CNTL, rinfo->save_regs[90]); + + r2ec |= 8; + OUTREG(VGA_DDA_ON_OFF, r2ec); + mdelay(20); + + /* Enable LVDS interface */ + tmp = INREG(LVDS_GEN_CNTL); + OUTREG(LVDS_GEN_CNTL, tmp | LVDS_EN); + + /* Enable LVDS_PLL */ + tmp = INREG(LVDS_PLL_CNTL); + tmp &= ~0x30000; + tmp |= 0x10000; + OUTREG(LVDS_PLL_CNTL, tmp); + + OUTPLL(pllSCLK_MORE_CNTL, rinfo->save_regs[34]); + OUTPLL(pllSS_TST_CNTL, rinfo->save_regs[91]); + + /* The trace reads that one here, waiting for something to settle down ? */ + INREG(RBBM_STATUS); + + /* Ugh ? SS_TST_DEC is supposed to be a read register in the + * R300 register spec at least... + */ + tmp = INPLL(pllSS_TST_CNTL); + tmp |= 0x00400000; + OUTPLL(pllSS_TST_CNTL, tmp); +} + +static void radeon_pm_restore_pixel_pll(struct radeonfb_info *rinfo) +{ + u32 tmp; + + OUTREG8(CLOCK_CNTL_INDEX, pllHTOTAL_CNTL + PLL_WR_EN); + radeon_pll_errata_after_index(rinfo); + OUTREG8(CLOCK_CNTL_DATA, 0); + radeon_pll_errata_after_data(rinfo); + + tmp = INPLL(pllVCLK_ECP_CNTL); + OUTPLL(pllVCLK_ECP_CNTL, tmp | 0x80); + mdelay(5); + + tmp = INPLL(pllPPLL_REF_DIV); + tmp = (tmp & ~PPLL_REF_DIV_MASK) | rinfo->pll.ref_div; + OUTPLL(pllPPLL_REF_DIV, tmp); + INPLL(pllPPLL_REF_DIV); + + /* Reconfigure SPLL charge pump, VCO gain, duty cycle, + * probably useless since we already did it ... + */ + tmp = INPLL(pllPPLL_CNTL); + OUTREG8(CLOCK_CNTL_INDEX, pllSPLL_CNTL + PLL_WR_EN); + radeon_pll_errata_after_index(rinfo); + OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff); + radeon_pll_errata_after_data(rinfo); + + /* Restore our "reference" PPLL divider set by firmware + * according to proper spread spectrum calculations + */ + OUTPLL(pllPPLL_DIV_0, rinfo->save_regs[92]); + + tmp = INPLL(pllPPLL_CNTL); + OUTPLL(pllPPLL_CNTL, tmp & ~0x2); + mdelay(5); + + tmp = INPLL(pllPPLL_CNTL); + OUTPLL(pllPPLL_CNTL, tmp & ~0x1); + mdelay(5); + + tmp = INPLL(pllVCLK_ECP_CNTL); + OUTPLL(pllVCLK_ECP_CNTL, tmp | 3); + mdelay(5); + + tmp = INPLL(pllVCLK_ECP_CNTL); + OUTPLL(pllVCLK_ECP_CNTL, tmp | 3); + mdelay(5); + + /* Switch pixel clock to firmware default div 0 */ + OUTREG8(CLOCK_CNTL_INDEX+1, 0); + radeon_pll_errata_after_index(rinfo); + radeon_pll_errata_after_data(rinfo); +} + +static void radeon_pm_m10_reconfigure_mc(struct radeonfb_info *rinfo) +{ + OUTREG(MC_CNTL, rinfo->save_regs[46]); + OUTREG(MC_INIT_GFX_LAT_TIMER, rinfo->save_regs[47]); + OUTREG(MC_INIT_MISC_LAT_TIMER, rinfo->save_regs[48]); + OUTREG(MEM_SDRAM_MODE_REG, + rinfo->save_regs[35] & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); + OUTREG(MC_TIMING_CNTL, rinfo->save_regs[49]); + OUTREG(MEM_REFRESH_CNTL, rinfo->save_regs[42]); + OUTREG(MC_READ_CNTL_AB, rinfo->save_regs[50]); + OUTREG(MC_CHIP_IO_OE_CNTL_AB, rinfo->save_regs[52]); + OUTREG(MC_IOPAD_CNTL, rinfo->save_regs[51]); + OUTREG(MC_DEBUG, rinfo->save_regs[53]); + + OUTMC(rinfo, ixR300_MC_MC_INIT_WR_LAT_TIMER, rinfo->save_regs[58]); + OUTMC(rinfo, ixR300_MC_IMP_CNTL, rinfo->save_regs[59]); + OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_C0, rinfo->save_regs[60]); + OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_C1, rinfo->save_regs[61]); + OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_D0, rinfo->save_regs[62]); + OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_D1, rinfo->save_regs[63]); + OUTMC(rinfo, ixR300_MC_BIST_CNTL_3, rinfo->save_regs[64]); + OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_A0, rinfo->save_regs[65]); + OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_A1, rinfo->save_regs[66]); + OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_B0, rinfo->save_regs[67]); + OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_B1, rinfo->save_regs[68]); + OUTMC(rinfo, ixR300_MC_DEBUG_CNTL, rinfo->save_regs[69]); + OUTMC(rinfo, ixR300_MC_DLL_CNTL, rinfo->save_regs[70]); + OUTMC(rinfo, ixR300_MC_IMP_CNTL_0, rinfo->save_regs[71]); + OUTMC(rinfo, ixR300_MC_ELPIDA_CNTL, rinfo->save_regs[72]); + OUTMC(rinfo, ixR300_MC_READ_CNTL_CD, rinfo->save_regs[96]); + OUTREG(MC_IND_INDEX, 0); +} + +static void radeon_reinitialize_M10(struct radeonfb_info *rinfo) +{ + u32 tmp, i; + + /* Restore a bunch of registers first */ + OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]); + OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]); + OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]); + OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]); + OUTREG(OV0_BASE_ADDR, rinfo->save_regs[80]); + OUTREG(CONFIG_MEMSIZE, rinfo->video_ram); + OUTREG(BUS_CNTL, rinfo->save_regs[36]); + OUTREG(BUS_CNTL1, rinfo->save_regs[14]); + OUTREG(MPP_TB_CONFIG, rinfo->save_regs[37]); + OUTREG(FCP_CNTL, rinfo->save_regs[38]); + OUTREG(RBBM_CNTL, rinfo->save_regs[39]); + OUTREG(DAC_CNTL, rinfo->save_regs[40]); + OUTREG(DAC_MACRO_CNTL, (INREG(DAC_MACRO_CNTL) & ~0x6) | 8); + OUTREG(DAC_MACRO_CNTL, (INREG(DAC_MACRO_CNTL) & ~0x6) | 8); + + /* Hrm... */ + OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | DAC2_EXPAND_MODE); + + /* Reset the PAD CTLR */ + radeon_pm_reset_pad_ctlr_strength(rinfo); + + /* Some PLLs are Read & written identically in the trace here... + * I suppose it's actually to switch them all off & reset, + * let's assume off is what we want. I'm just doing that for all major PLLs now. + */ + radeon_pm_all_ppls_off(rinfo); + + /* Clear tiling, reset swappers */ + INREG(SURFACE_CNTL); + OUTREG(SURFACE_CNTL, 0); + + /* Some black magic with TV_DAC_CNTL, we should restore those from backups + * rather than hard coding... + */ + tmp = INREG(TV_DAC_CNTL) & ~TV_DAC_CNTL_BGADJ_MASK; + tmp |= 8 << TV_DAC_CNTL_BGADJ__SHIFT; + OUTREG(TV_DAC_CNTL, tmp); + + tmp = INREG(TV_DAC_CNTL) & ~TV_DAC_CNTL_DACADJ_MASK; + tmp |= 7 << TV_DAC_CNTL_DACADJ__SHIFT; + OUTREG(TV_DAC_CNTL, tmp); + + /* More registers restored */ + OUTREG(AGP_CNTL, rinfo->save_regs[16]); + OUTREG(HOST_PATH_CNTL, rinfo->save_regs[41]); + OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]); + + /* Hrmmm ... What is that ? */ + tmp = rinfo->save_regs[1] + & ~(CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK | + CLK_PWRMGT_CNTL__MC_BUSY); + OUTPLL(pllCLK_PWRMGT_CNTL, tmp); + + OUTREG(PAD_CTLR_MISC, rinfo->save_regs[56]); + OUTREG(FW_CNTL, rinfo->save_regs[57]); + OUTREG(HDP_DEBUG, rinfo->save_regs[96]); + OUTREG(PAMAC0_DLY_CNTL, rinfo->save_regs[54]); + OUTREG(PAMAC1_DLY_CNTL, rinfo->save_regs[55]); + OUTREG(PAMAC2_DLY_CNTL, rinfo->save_regs[79]); + + /* Restore Memory Controller configuration */ + radeon_pm_m10_reconfigure_mc(rinfo); + + /* Make sure CRTC's dont touch memory */ + OUTREG(CRTC_GEN_CNTL, INREG(CRTC_GEN_CNTL) + | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B); + OUTREG(CRTC2_GEN_CNTL, INREG(CRTC2_GEN_CNTL) + | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B); + mdelay(30); + + /* Disable SDRAM refresh */ + OUTREG(MEM_REFRESH_CNTL, INREG(MEM_REFRESH_CNTL) + | MEM_REFRESH_CNTL__MEM_REFRESH_DIS); + + /* Restore XTALIN routing (CLK_PIN_CNTL) */ + OUTPLL(pllCLK_PIN_CNTL, rinfo->save_regs[4]); + + /* Switch MCLK, YCLK and SCLK PLLs to PCI source & force them ON */ + tmp = rinfo->save_regs[2] & 0xff000000; + tmp |= MCLK_CNTL__FORCE_MCLKA | + MCLK_CNTL__FORCE_MCLKB | + MCLK_CNTL__FORCE_YCLKA | + MCLK_CNTL__FORCE_YCLKB | + MCLK_CNTL__FORCE_MC; + OUTPLL(pllMCLK_CNTL, tmp); + + /* Force all clocks on in SCLK */ + tmp = INPLL(pllSCLK_CNTL); + tmp |= SCLK_CNTL__FORCE_DISP2| + SCLK_CNTL__FORCE_CP| + SCLK_CNTL__FORCE_HDP| + SCLK_CNTL__FORCE_DISP1| + SCLK_CNTL__FORCE_TOP| + SCLK_CNTL__FORCE_E2| + SCLK_CNTL__FORCE_SE| + SCLK_CNTL__FORCE_IDCT| + SCLK_CNTL__FORCE_VIP| + SCLK_CNTL__FORCE_PB| + SCLK_CNTL__FORCE_TAM| + SCLK_CNTL__FORCE_TDM| + SCLK_CNTL__FORCE_RB| + SCLK_CNTL__FORCE_TV_SCLK| + SCLK_CNTL__FORCE_SUBPIC| + SCLK_CNTL__FORCE_OV0; + tmp |= SCLK_CNTL__CP_MAX_DYN_STOP_LAT | + SCLK_CNTL__HDP_MAX_DYN_STOP_LAT | + SCLK_CNTL__TV_MAX_DYN_STOP_LAT | + SCLK_CNTL__E2_MAX_DYN_STOP_LAT | + SCLK_CNTL__SE_MAX_DYN_STOP_LAT | + SCLK_CNTL__IDCT_MAX_DYN_STOP_LAT| + SCLK_CNTL__VIP_MAX_DYN_STOP_LAT | + SCLK_CNTL__RE_MAX_DYN_STOP_LAT | + SCLK_CNTL__PB_MAX_DYN_STOP_LAT | + SCLK_CNTL__TAM_MAX_DYN_STOP_LAT | + SCLK_CNTL__TDM_MAX_DYN_STOP_LAT | + SCLK_CNTL__RB_MAX_DYN_STOP_LAT; + OUTPLL(pllSCLK_CNTL, tmp); + + OUTPLL(pllVCLK_ECP_CNTL, 0); + OUTPLL(pllPIXCLKS_CNTL, 0); + OUTPLL(pllMCLK_MISC, + MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT | + MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT); + + mdelay(5); + + /* Restore the M_SPLL_REF_FB_DIV, MPLL_AUX_CNTL and SPLL_AUX_CNTL values */ + OUTPLL(pllM_SPLL_REF_FB_DIV, rinfo->save_regs[77]); + OUTPLL(pllMPLL_AUX_CNTL, rinfo->save_regs[75]); + OUTPLL(pllSPLL_AUX_CNTL, rinfo->save_regs[76]); + + /* Now restore the major PLLs settings, keeping them off & reset though */ + OUTPLL(pllPPLL_CNTL, rinfo->save_regs[93] | 0x3); + OUTPLL(pllP2PLL_CNTL, rinfo->save_regs[8] | 0x3); + OUTPLL(pllMPLL_CNTL, rinfo->save_regs[73] | 0x03); + OUTPLL(pllSPLL_CNTL, rinfo->save_regs[74] | 0x03); + + /* Restore MC DLL state and switch it off/reset too */ + OUTMC(rinfo, ixR300_MC_DLL_CNTL, rinfo->save_regs[70]); + + /* Switch MDLL off & reset */ + OUTPLL(pllMDLL_RDCKA, rinfo->save_regs[98] | 0xff); + mdelay(5); + + /* Setup some black magic bits in PLL_PWRMGT_CNTL. Hrm... we saved + * 0xa1100007... and MacOS writes 0xa1000007 .. + */ + OUTPLL(pllPLL_PWRMGT_CNTL, rinfo->save_regs[0]); + + /* Restore more stuffs */ + OUTPLL(pllHTOTAL_CNTL, 0); + OUTPLL(pllHTOTAL2_CNTL, 0); + + /* More PLL initial configuration */ + tmp = INPLL(pllSCLK_CNTL2); /* What for ? */ + OUTPLL(pllSCLK_CNTL2, tmp); + + tmp = INPLL(pllSCLK_MORE_CNTL); + tmp |= SCLK_MORE_CNTL__FORCE_DISPREGS | /* a guess */ + SCLK_MORE_CNTL__FORCE_MC_GUI | + SCLK_MORE_CNTL__FORCE_MC_HOST; + OUTPLL(pllSCLK_MORE_CNTL, tmp); + + /* Now we actually start MCLK and SCLK */ + radeon_pm_start_mclk_sclk(rinfo); + + /* Full reset sdrams, this also re-inits the MDLL */ + radeon_pm_full_reset_sdram(rinfo); + + /* Fill palettes */ + OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | 0x20); + for (i=0; i<256; i++) + OUTREG(PALETTE_30_DATA, 0x15555555); + OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) & ~20); + udelay(20); + for (i=0; i<256; i++) + OUTREG(PALETTE_30_DATA, 0x15555555); + + OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) & ~0x20); + mdelay(3); + + /* Restore TMDS */ + OUTREG(FP_GEN_CNTL, rinfo->save_regs[82]); + OUTREG(FP2_GEN_CNTL, rinfo->save_regs[83]); + + /* Set LVDS registers but keep interface & pll down */ + OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11] & + ~(LVDS_EN | LVDS_ON | LVDS_DIGON | LVDS_BLON | LVDS_BL_MOD_EN)); + OUTREG(LVDS_PLL_CNTL, (rinfo->save_regs[12] & ~0xf0000) | 0x20000); + + OUTREG(DISP_OUTPUT_CNTL, rinfo->save_regs[86]); + + /* Restore GPIOPAD state */ + OUTREG(GPIOPAD_A, rinfo->save_regs[19]); + OUTREG(GPIOPAD_EN, rinfo->save_regs[20]); + OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]); + + /* write some stuff to the framebuffer... */ + for (i = 0; i < 0x8000; ++i) + writeb(0, rinfo->fb_base + i); + + mdelay(40); + OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) | LVDS_DIGON | LVDS_ON); + mdelay(40); + + /* Restore a few more things */ + OUTREG(GRPH_BUFFER_CNTL, rinfo->save_regs[94]); + OUTREG(GRPH2_BUFFER_CNTL, rinfo->save_regs[95]); + + /* Take care of spread spectrum & PPLLs now */ + radeon_pm_m10_disable_spread_spectrum(rinfo); + radeon_pm_restore_pixel_pll(rinfo); + + /* GRRRR... I can't figure out the proper LVDS power sequence, and the + * code I have for blank/unblank doesn't quite work on some laptop models + * it seems ... Hrm. What I have here works most of the time ... + */ + radeon_pm_m10_enable_lvds_spread_spectrum(rinfo); +} + +static void radeon_pm_m9p_reconfigure_mc(struct radeonfb_info *rinfo) +{ + OUTREG(MC_CNTL, rinfo->save_regs[46]); + OUTREG(MC_INIT_GFX_LAT_TIMER, rinfo->save_regs[47]); + OUTREG(MC_INIT_MISC_LAT_TIMER, rinfo->save_regs[48]); + OUTREG(MEM_SDRAM_MODE_REG, + rinfo->save_regs[35] & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); + OUTREG(MC_TIMING_CNTL, rinfo->save_regs[49]); + OUTREG(MC_READ_CNTL_AB, rinfo->save_regs[50]); + OUTREG(MEM_REFRESH_CNTL, rinfo->save_regs[42]); + OUTREG(MC_IOPAD_CNTL, rinfo->save_regs[51]); + OUTREG(MC_DEBUG, rinfo->save_regs[53]); + OUTREG(MC_CHIP_IO_OE_CNTL_AB, rinfo->save_regs[52]); + + OUTMC(rinfo, ixMC_IMP_CNTL, rinfo->save_regs[59] /*0x00f460d6*/); + OUTMC(rinfo, ixMC_CHP_IO_CNTL_A0, rinfo->save_regs[65] /*0xfecfa666*/); + OUTMC(rinfo, ixMC_CHP_IO_CNTL_A1, rinfo->save_regs[66] /*0x141555ff*/); + OUTMC(rinfo, ixMC_CHP_IO_CNTL_B0, rinfo->save_regs[67] /*0xfecfa666*/); + OUTMC(rinfo, ixMC_CHP_IO_CNTL_B1, rinfo->save_regs[68] /*0x141555ff*/); + OUTMC(rinfo, ixMC_IMP_CNTL_0, rinfo->save_regs[71] /*0x00009249*/); + OUTREG(MC_IND_INDEX, 0); + OUTREG(CONFIG_MEMSIZE, rinfo->video_ram); + + mdelay(20); +} + +static void radeon_reinitialize_M9P(struct radeonfb_info *rinfo) +{ + u32 tmp, i; + + /* Restore a bunch of registers first */ + OUTREG(SURFACE_CNTL, rinfo->save_regs[29]); + OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]); + OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]); + OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]); + OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]); + OUTREG(OV0_BASE_ADDR, rinfo->save_regs[80]); + OUTREG(BUS_CNTL, rinfo->save_regs[36]); + OUTREG(BUS_CNTL1, rinfo->save_regs[14]); + OUTREG(MPP_TB_CONFIG, rinfo->save_regs[37]); + OUTREG(FCP_CNTL, rinfo->save_regs[38]); + OUTREG(RBBM_CNTL, rinfo->save_regs[39]); + + OUTREG(DAC_CNTL, rinfo->save_regs[40]); + OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | DAC2_EXPAND_MODE); + + /* Reset the PAD CTLR */ + radeon_pm_reset_pad_ctlr_strength(rinfo); + + /* Some PLLs are Read & written identically in the trace here... + * I suppose it's actually to switch them all off & reset, + * let's assume off is what we want. I'm just doing that for all major PLLs now. + */ + radeon_pm_all_ppls_off(rinfo); + + /* Clear tiling, reset swappers */ + INREG(SURFACE_CNTL); + OUTREG(SURFACE_CNTL, 0); + + /* Some black magic with TV_DAC_CNTL, we should restore those from backups + * rather than hard coding... + */ + tmp = INREG(TV_DAC_CNTL) & ~TV_DAC_CNTL_BGADJ_MASK; + tmp |= 6 << TV_DAC_CNTL_BGADJ__SHIFT; + OUTREG(TV_DAC_CNTL, tmp); + + tmp = INREG(TV_DAC_CNTL) & ~TV_DAC_CNTL_DACADJ_MASK; + tmp |= 6 << TV_DAC_CNTL_DACADJ__SHIFT; + OUTREG(TV_DAC_CNTL, tmp); + + OUTPLL(pllAGP_PLL_CNTL, rinfo->save_regs[78]); + + OUTREG(PAMAC0_DLY_CNTL, rinfo->save_regs[54]); + OUTREG(PAMAC1_DLY_CNTL, rinfo->save_regs[55]); + OUTREG(PAMAC2_DLY_CNTL, rinfo->save_regs[79]); + + OUTREG(AGP_CNTL, rinfo->save_regs[16]); + OUTREG(HOST_PATH_CNTL, rinfo->save_regs[41]); /* MacOS sets that to 0 !!! */ + OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]); + + tmp = rinfo->save_regs[1] + & ~(CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK | + CLK_PWRMGT_CNTL__MC_BUSY); + OUTPLL(pllCLK_PWRMGT_CNTL, tmp); + + OUTREG(FW_CNTL, rinfo->save_regs[57]); + + /* Disable SDRAM refresh */ + OUTREG(MEM_REFRESH_CNTL, INREG(MEM_REFRESH_CNTL) + | MEM_REFRESH_CNTL__MEM_REFRESH_DIS); + + /* Restore XTALIN routing (CLK_PIN_CNTL) */ + OUTPLL(pllCLK_PIN_CNTL, rinfo->save_regs[4]); + + /* Force MCLK to be PCI sourced and forced ON */ + tmp = rinfo->save_regs[2] & 0xff000000; + tmp |= MCLK_CNTL__FORCE_MCLKA | + MCLK_CNTL__FORCE_MCLKB | + MCLK_CNTL__FORCE_YCLKA | + MCLK_CNTL__FORCE_YCLKB | + MCLK_CNTL__FORCE_MC | + MCLK_CNTL__FORCE_AIC; + OUTPLL(pllMCLK_CNTL, tmp); + + /* Force SCLK to be PCI sourced with a bunch forced */ + tmp = 0 | + SCLK_CNTL__FORCE_DISP2| + SCLK_CNTL__FORCE_CP| + SCLK_CNTL__FORCE_HDP| + SCLK_CNTL__FORCE_DISP1| + SCLK_CNTL__FORCE_TOP| + SCLK_CNTL__FORCE_E2| + SCLK_CNTL__FORCE_SE| + SCLK_CNTL__FORCE_IDCT| + SCLK_CNTL__FORCE_VIP| + SCLK_CNTL__FORCE_RE| + SCLK_CNTL__FORCE_PB| + SCLK_CNTL__FORCE_TAM| + SCLK_CNTL__FORCE_TDM| + SCLK_CNTL__FORCE_RB; + OUTPLL(pllSCLK_CNTL, tmp); + + /* Clear VCLK_ECP_CNTL & PIXCLKS_CNTL */ + OUTPLL(pllVCLK_ECP_CNTL, 0); + OUTPLL(pllPIXCLKS_CNTL, 0); + + /* Setup MCLK_MISC, non dynamic mode */ + OUTPLL(pllMCLK_MISC, + MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT | + MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT); + + mdelay(5); + + /* Set back the default clock dividers */ + OUTPLL(pllM_SPLL_REF_FB_DIV, rinfo->save_regs[77]); + OUTPLL(pllMPLL_AUX_CNTL, rinfo->save_regs[75]); + OUTPLL(pllSPLL_AUX_CNTL, rinfo->save_regs[76]); + + /* PPLL and P2PLL default values & off */ + OUTPLL(pllPPLL_CNTL, rinfo->save_regs[93] | 0x3); + OUTPLL(pllP2PLL_CNTL, rinfo->save_regs[8] | 0x3); + + /* S and M PLLs are reset & off, configure them */ + OUTPLL(pllMPLL_CNTL, rinfo->save_regs[73] | 0x03); + OUTPLL(pllSPLL_CNTL, rinfo->save_regs[74] | 0x03); + + /* Default values for MDLL ... fixme */ + OUTPLL(pllMDLL_CKO, 0x9c009c); + OUTPLL(pllMDLL_RDCKA, 0x08830883); + OUTPLL(pllMDLL_RDCKB, 0x08830883); + mdelay(5); + + /* Restore PLL_PWRMGT_CNTL */ // XXXX + tmp = rinfo->save_regs[0]; + tmp &= ~PLL_PWRMGT_CNTL_SU_SCLK_USE_BCLK; + tmp |= PLL_PWRMGT_CNTL_SU_MCLK_USE_BCLK; + OUTPLL(PLL_PWRMGT_CNTL, tmp); + + /* Clear HTOTAL_CNTL & HTOTAL2_CNTL */ + OUTPLL(pllHTOTAL_CNTL, 0); + OUTPLL(pllHTOTAL2_CNTL, 0); + + /* All outputs off */ + OUTREG(CRTC_GEN_CNTL, 0x04000000); + OUTREG(CRTC2_GEN_CNTL, 0x04000000); + OUTREG(FP_GEN_CNTL, 0x00004008); + OUTREG(FP2_GEN_CNTL, 0x00000008); + OUTREG(LVDS_GEN_CNTL, 0x08000008); + + /* Restore Memory Controller configuration */ + radeon_pm_m9p_reconfigure_mc(rinfo); + + /* Now we actually start MCLK and SCLK */ + radeon_pm_start_mclk_sclk(rinfo); + + /* Full reset sdrams, this also re-inits the MDLL */ + radeon_pm_full_reset_sdram(rinfo); + + /* Fill palettes */ + OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | 0x20); + for (i=0; i<256; i++) + OUTREG(PALETTE_30_DATA, 0x15555555); + OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) & ~20); + udelay(20); + for (i=0; i<256; i++) + OUTREG(PALETTE_30_DATA, 0x15555555); + + OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) & ~0x20); + mdelay(3); + + /* Restore TV stuff, make sure TV DAC is down */ + OUTREG(TV_MASTER_CNTL, rinfo->save_regs[88]); + OUTREG(TV_DAC_CNTL, rinfo->save_regs[13] | 0x07000000); + + /* Restore GPIOS. MacOS does some magic here with one of the GPIO bits, + * possibly related to the weird PLL related workarounds and to the + * fact that CLK_PIN_CNTL is tweaked in ways I don't fully understand, + * but we keep things the simple way here + */ + OUTREG(GPIOPAD_A, rinfo->save_regs[19]); + OUTREG(GPIOPAD_EN, rinfo->save_regs[20]); + OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]); + + /* Now do things with SCLK_MORE_CNTL. Force bits are already set, copy + * high bits from backup + */ + tmp = INPLL(pllSCLK_MORE_CNTL) & 0x0000ffff; + tmp |= rinfo->save_regs[34] & 0xffff0000; + tmp |= SCLK_MORE_CNTL__FORCE_DISPREGS; + OUTPLL(pllSCLK_MORE_CNTL, tmp); + + tmp = INPLL(pllSCLK_MORE_CNTL) & 0x0000ffff; + tmp |= rinfo->save_regs[34] & 0xffff0000; + tmp |= SCLK_MORE_CNTL__FORCE_DISPREGS; + OUTPLL(pllSCLK_MORE_CNTL, tmp); + + OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11] & + ~(LVDS_EN | LVDS_ON | LVDS_DIGON | LVDS_BLON | LVDS_BL_MOD_EN)); + OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) | LVDS_BLON); + OUTREG(LVDS_PLL_CNTL, (rinfo->save_regs[12] & ~0xf0000) | 0x20000); + mdelay(20); + + /* write some stuff to the framebuffer... */ + for (i = 0; i < 0x8000; ++i) + writeb(0, rinfo->fb_base + i); + + OUTREG(0x2ec, 0x6332a020); + OUTPLL(pllSSPLL_REF_DIV, rinfo->save_regs[44] /*0x3f */); + OUTPLL(pllSSPLL_DIV_0, rinfo->save_regs[45] /*0x000081bb */); + tmp = INPLL(pllSSPLL_CNTL); + tmp &= ~2; + OUTPLL(pllSSPLL_CNTL, tmp); + mdelay(6); + tmp &= ~1; + OUTPLL(pllSSPLL_CNTL, tmp); + mdelay(5); + tmp |= 3; + OUTPLL(pllSSPLL_CNTL, tmp); + mdelay(5); + + OUTPLL(pllSS_INT_CNTL, rinfo->save_regs[90] & ~3);/*0x0020300c*/ + OUTREG(0x2ec, 0x6332a3f0); + mdelay(17); + + OUTPLL(pllPPLL_REF_DIV, rinfo->pll.ref_div);; + OUTPLL(pllPPLL_DIV_0, rinfo->save_regs[92]); + + mdelay(40); + OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) | LVDS_DIGON | LVDS_ON); + mdelay(40); + + /* Restore a few more things */ + OUTREG(GRPH_BUFFER_CNTL, rinfo->save_regs[94]); + OUTREG(GRPH2_BUFFER_CNTL, rinfo->save_regs[95]); + + /* Restore PPLL, spread spectrum & LVDS */ + radeon_pm_m10_disable_spread_spectrum(rinfo); + radeon_pm_restore_pixel_pll(rinfo); + radeon_pm_m10_enable_lvds_spread_spectrum(rinfo); +} + +#if 0 /* Not ready yet */ +static void radeon_reinitialize_QW(struct radeonfb_info *rinfo) +{ + int i; + u32 tmp, tmp2; + u32 cko, cka, ckb; + u32 cgc, cec, c2gc; + + OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]); + OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]); + OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]); + OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]); + OUTREG(BUS_CNTL, rinfo->save_regs[36]); + OUTREG(RBBM_CNTL, rinfo->save_regs[39]); + + INREG(PAD_CTLR_STRENGTH); + OUTREG(PAD_CTLR_STRENGTH, INREG(PAD_CTLR_STRENGTH) & ~0x10000); + for (i = 0; i < 65; ++i) { + mdelay(1); + INREG(PAD_CTLR_STRENGTH); + } + + OUTREG(DISP_TEST_DEBUG_CNTL, INREG(DISP_TEST_DEBUG_CNTL) | 0x10000000); + OUTREG(OV0_FLAG_CNTRL, INREG(OV0_FLAG_CNTRL) | 0x100); + OUTREG(CRTC_GEN_CNTL, INREG(CRTC_GEN_CNTL)); + OUTREG(DAC_CNTL, 0xff00410a); + OUTREG(CRTC2_GEN_CNTL, INREG(CRTC2_GEN_CNTL)); + OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | 0x4000); + + OUTREG(SURFACE_CNTL, rinfo->save_regs[29]); + OUTREG(AGP_CNTL, rinfo->save_regs[16]); + OUTREG(HOST_PATH_CNTL, rinfo->save_regs[41]); + OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]); + + OUTMC(rinfo, ixMC_CHP_IO_CNTL_A0, 0xf7bb4433); + OUTREG(MC_IND_INDEX, 0); + OUTMC(rinfo, ixMC_CHP_IO_CNTL_B0, 0xf7bb4433); + OUTREG(MC_IND_INDEX, 0); + + OUTREG(CRTC_MORE_CNTL, INREG(CRTC_MORE_CNTL)); + + tmp = INPLL(pllVCLK_ECP_CNTL); + OUTPLL(pllVCLK_ECP_CNTL, tmp); + tmp = INPLL(pllPIXCLKS_CNTL); + OUTPLL(pllPIXCLKS_CNTL, tmp); + + OUTPLL(MCLK_CNTL, 0xaa3f0000); + OUTPLL(SCLK_CNTL, 0xffff0000); + OUTPLL(pllMPLL_AUX_CNTL, 6); + OUTPLL(pllSPLL_AUX_CNTL, 1); + OUTPLL(MDLL_CKO, 0x9f009f); + OUTPLL(MDLL_RDCKA, 0x830083); + OUTPLL(pllMDLL_RDCKB, 0x830083); + OUTPLL(PPLL_CNTL, 0xa433); + OUTPLL(P2PLL_CNTL, 0xa433); + OUTPLL(MPLL_CNTL, 0x0400a403); + OUTPLL(SPLL_CNTL, 0x0400a433); + + tmp = INPLL(M_SPLL_REF_FB_DIV); + OUTPLL(M_SPLL_REF_FB_DIV, tmp); + tmp = INPLL(M_SPLL_REF_FB_DIV); + OUTPLL(M_SPLL_REF_FB_DIV, tmp | 0xc); + INPLL(M_SPLL_REF_FB_DIV); + + tmp = INPLL(MPLL_CNTL); + OUTREG8(CLOCK_CNTL_INDEX, MPLL_CNTL + PLL_WR_EN); + radeon_pll_errata_after_index(rinfo); + OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff); + radeon_pll_errata_after_data(rinfo); + + tmp = INPLL(M_SPLL_REF_FB_DIV); + OUTPLL(M_SPLL_REF_FB_DIV, tmp | 0x5900); + + tmp = INPLL(MPLL_CNTL); + OUTPLL(MPLL_CNTL, tmp & ~0x2); + mdelay(1); + tmp = INPLL(MPLL_CNTL); + OUTPLL(MPLL_CNTL, tmp & ~0x1); + mdelay(10); + + OUTPLL(MCLK_CNTL, 0xaa3f1212); + mdelay(1); + + INPLL(M_SPLL_REF_FB_DIV); + INPLL(MCLK_CNTL); + INPLL(M_SPLL_REF_FB_DIV); + + tmp = INPLL(SPLL_CNTL); + OUTREG8(CLOCK_CNTL_INDEX, SPLL_CNTL + PLL_WR_EN); + radeon_pll_errata_after_index(rinfo); + OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff); + radeon_pll_errata_after_data(rinfo); + + tmp = INPLL(M_SPLL_REF_FB_DIV); + OUTPLL(M_SPLL_REF_FB_DIV, tmp | 0x780000); + + tmp = INPLL(SPLL_CNTL); + OUTPLL(SPLL_CNTL, tmp & ~0x1); + mdelay(1); + tmp = INPLL(SPLL_CNTL); + OUTPLL(SPLL_CNTL, tmp & ~0x2); + mdelay(10); + + tmp = INPLL(SCLK_CNTL); + OUTPLL(SCLK_CNTL, tmp | 2); + mdelay(1); + + cko = INPLL(pllMDLL_CKO); + cka = INPLL(pllMDLL_RDCKA); + ckb = INPLL(pllMDLL_RDCKB); + + cko &= ~(MDLL_CKO__MCKOA_SLEEP | MDLL_CKO__MCKOB_SLEEP); + OUTPLL(pllMDLL_CKO, cko); + mdelay(1); + cko &= ~(MDLL_CKO__MCKOA_RESET | MDLL_CKO__MCKOB_RESET); + OUTPLL(pllMDLL_CKO, cko); + mdelay(5); + + cka &= ~(MDLL_RDCKA__MRDCKA0_SLEEP | MDLL_RDCKA__MRDCKA1_SLEEP); + OUTPLL(pllMDLL_RDCKA, cka); + mdelay(1); + cka &= ~(MDLL_RDCKA__MRDCKA0_RESET | MDLL_RDCKA__MRDCKA1_RESET); + OUTPLL(pllMDLL_RDCKA, cka); + mdelay(5); + + ckb &= ~(MDLL_RDCKB__MRDCKB0_SLEEP | MDLL_RDCKB__MRDCKB1_SLEEP); + OUTPLL(pllMDLL_RDCKB, ckb); + mdelay(1); + ckb &= ~(MDLL_RDCKB__MRDCKB0_RESET | MDLL_RDCKB__MRDCKB1_RESET); + OUTPLL(pllMDLL_RDCKB, ckb); + mdelay(5); + + OUTMC(rinfo, ixMC_CHP_IO_CNTL_A1, 0x151550ff); + OUTREG(MC_IND_INDEX, 0); + OUTMC(rinfo, ixMC_CHP_IO_CNTL_B1, 0x151550ff); + OUTREG(MC_IND_INDEX, 0); + mdelay(1); + OUTMC(rinfo, ixMC_CHP_IO_CNTL_A1, 0x141550ff); + OUTREG(MC_IND_INDEX, 0); + OUTMC(rinfo, ixMC_CHP_IO_CNTL_B1, 0x141550ff); + OUTREG(MC_IND_INDEX, 0); + mdelay(1); + + OUTPLL(pllHTOTAL_CNTL, 0); + OUTPLL(pllHTOTAL2_CNTL, 0); + + OUTREG(MEM_CNTL, 0x29002901); + OUTREG(MEM_SDRAM_MODE_REG, 0x45320032); /* XXX use save_regs[35]? */ + OUTREG(EXT_MEM_CNTL, 0x1a394333); + OUTREG(MEM_IO_CNTL_A1, 0x0aac0aac); + OUTREG(MEM_INIT_LATENCY_TIMER, 0x34444444); + OUTREG(MEM_REFRESH_CNTL, 0x1f1f7218); /* XXX or save_regs[42]? */ + OUTREG(MC_DEBUG, 0); + OUTREG(MEM_IO_OE_CNTL, 0x04300430); + + OUTMC(rinfo, ixMC_IMP_CNTL, 0x00f460d6); + OUTREG(MC_IND_INDEX, 0); + OUTMC(rinfo, ixMC_IMP_CNTL_0, 0x00009249); + OUTREG(MC_IND_INDEX, 0); + + OUTREG(CONFIG_MEMSIZE, rinfo->video_ram); + + radeon_pm_full_reset_sdram(rinfo); + + INREG(FP_GEN_CNTL); + OUTREG(TMDS_CNTL, 0x01000000); /* XXX ? */ + tmp = INREG(FP_GEN_CNTL); + tmp |= FP_CRTC_DONT_SHADOW_HEND | FP_CRTC_DONT_SHADOW_VPAR | 0x200; + OUTREG(FP_GEN_CNTL, tmp); + + tmp = INREG(DISP_OUTPUT_CNTL); + tmp &= ~0x400; + OUTREG(DISP_OUTPUT_CNTL, tmp); + + OUTPLL(CLK_PIN_CNTL, rinfo->save_regs[4]); + OUTPLL(CLK_PWRMGT_CNTL, rinfo->save_regs[1]); + OUTPLL(PLL_PWRMGT_CNTL, rinfo->save_regs[0]); + + tmp = INPLL(MCLK_MISC); + tmp |= MCLK_MISC__MC_MCLK_DYN_ENABLE | MCLK_MISC__IO_MCLK_DYN_ENABLE; + OUTPLL(MCLK_MISC, tmp); + + tmp = INPLL(SCLK_CNTL); + OUTPLL(SCLK_CNTL, tmp); + + OUTREG(CRTC_MORE_CNTL, 0); + OUTREG8(CRTC_GEN_CNTL+1, 6); + OUTREG8(CRTC_GEN_CNTL+3, 1); + OUTREG(CRTC_PITCH, 32); + + tmp = INPLL(VCLK_ECP_CNTL); + OUTPLL(VCLK_ECP_CNTL, tmp); + + tmp = INPLL(PPLL_CNTL); + OUTPLL(PPLL_CNTL, tmp); + + /* palette stuff and BIOS_1_SCRATCH... */ + + tmp = INREG(FP_GEN_CNTL); + tmp2 = INREG(TMDS_TRANSMITTER_CNTL); + tmp |= 2; + OUTREG(FP_GEN_CNTL, tmp); + mdelay(5); + OUTREG(FP_GEN_CNTL, tmp); + mdelay(5); + OUTREG(TMDS_TRANSMITTER_CNTL, tmp2); + OUTREG(CRTC_MORE_CNTL, 0); + mdelay(20); + + tmp = INREG(CRTC_MORE_CNTL); + OUTREG(CRTC_MORE_CNTL, tmp); + + cgc = INREG(CRTC_GEN_CNTL); + cec = INREG(CRTC_EXT_CNTL); + c2gc = INREG(CRTC2_GEN_CNTL); + + OUTREG(CRTC_H_SYNC_STRT_WID, 0x008e0580); + OUTREG(CRTC_H_TOTAL_DISP, 0x009f00d2); + OUTREG8(CLOCK_CNTL_INDEX, HTOTAL_CNTL + PLL_WR_EN); + radeon_pll_errata_after_index(rinfo); + OUTREG8(CLOCK_CNTL_DATA, 0); + radeon_pll_errata_after_data(rinfo); + OUTREG(CRTC_V_SYNC_STRT_WID, 0x00830403); + OUTREG(CRTC_V_TOTAL_DISP, 0x03ff0429); + OUTREG(FP_CRTC_H_TOTAL_DISP, 0x009f0033); + OUTREG(FP_H_SYNC_STRT_WID, 0x008e0080); + OUTREG(CRT_CRTC_H_SYNC_STRT_WID, 0x008e0080); + OUTREG(FP_CRTC_V_TOTAL_DISP, 0x03ff002a); + OUTREG(FP_V_SYNC_STRT_WID, 0x00830004); + OUTREG(CRT_CRTC_V_SYNC_STRT_WID, 0x00830004); + OUTREG(FP_HORZ_VERT_ACTIVE, 0x009f03ff); + OUTREG(FP_HORZ_STRETCH, 0); + OUTREG(FP_VERT_STRETCH, 0); + OUTREG(OVR_CLR, 0); + OUTREG(OVR_WID_LEFT_RIGHT, 0); + OUTREG(OVR_WID_TOP_BOTTOM, 0); + + tmp = INPLL(PPLL_REF_DIV); + tmp = (tmp & ~PPLL_REF_DIV_MASK) | rinfo->pll.ref_div; + OUTPLL(PPLL_REF_DIV, tmp); + INPLL(PPLL_REF_DIV); + + OUTREG8(CLOCK_CNTL_INDEX, PPLL_CNTL + PLL_WR_EN); + radeon_pll_errata_after_index(rinfo); + OUTREG8(CLOCK_CNTL_DATA + 1, 0xbc); + radeon_pll_errata_after_data(rinfo); + + tmp = INREG(CLOCK_CNTL_INDEX); + radeon_pll_errata_after_index(rinfo); + OUTREG(CLOCK_CNTL_INDEX, tmp & 0xff); + radeon_pll_errata_after_index(rinfo); + radeon_pll_errata_after_data(rinfo); + + OUTPLL(PPLL_DIV_0, 0x48090); + + tmp = INPLL(PPLL_CNTL); + OUTPLL(PPLL_CNTL, tmp & ~0x2); + mdelay(1); + tmp = INPLL(PPLL_CNTL); + OUTPLL(PPLL_CNTL, tmp & ~0x1); + mdelay(10); + + tmp = INPLL(VCLK_ECP_CNTL); + OUTPLL(VCLK_ECP_CNTL, tmp | 3); + mdelay(1); + + tmp = INPLL(VCLK_ECP_CNTL); + OUTPLL(VCLK_ECP_CNTL, tmp); + + c2gc |= CRTC2_DISP_REQ_EN_B; + OUTREG(CRTC2_GEN_CNTL, c2gc); + cgc |= CRTC_EN; + OUTREG(CRTC_GEN_CNTL, cgc); + OUTREG(CRTC_EXT_CNTL, cec); + OUTREG(CRTC_PITCH, 0xa0); + OUTREG(CRTC_OFFSET, 0); + OUTREG(CRTC_OFFSET_CNTL, 0); + + OUTREG(GRPH_BUFFER_CNTL, 0x20117c7c); + OUTREG(GRPH2_BUFFER_CNTL, 0x00205c5c); + + tmp2 = INREG(FP_GEN_CNTL); + tmp = INREG(TMDS_TRANSMITTER_CNTL); + OUTREG(0x2a8, 0x0000061b); + tmp |= TMDS_PLL_EN; + OUTREG(TMDS_TRANSMITTER_CNTL, tmp); + mdelay(1); + tmp &= ~TMDS_PLLRST; + OUTREG(TMDS_TRANSMITTER_CNTL, tmp); + tmp2 &= ~2; + tmp2 |= FP_TMDS_EN; + OUTREG(FP_GEN_CNTL, tmp2); + mdelay(5); + tmp2 |= FP_FPON; + OUTREG(FP_GEN_CNTL, tmp2); + + OUTREG(CUR_HORZ_VERT_OFF, CUR_LOCK | 1); + cgc = INREG(CRTC_GEN_CNTL); + OUTREG(CUR_HORZ_VERT_POSN, 0xbfff0fff); + cgc |= 0x10000; + OUTREG(CUR_OFFSET, 0); +} +#endif /* 0 */ + +#endif /* CONFIG_PPC_OF */ + +static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend) +{ + u16 pwr_cmd; + u32 tmp; + int i; + + if (!rinfo->pm_reg) + return; + + /* Set the chip into appropriate suspend mode (we use D2, + * D3 would require a compete re-initialization of the chip, + * including PCI config registers, clocks, AGP conf, ...) + */ + if (suspend) { + printk(KERN_DEBUG "radeonfb (%s): switching to D2 state...\n", + pci_name(rinfo->pdev)); + + /* Disable dynamic power management of clocks for the + * duration of the suspend/resume process + */ + radeon_pm_disable_dynamic_mode(rinfo); + + /* Save some registers */ + radeon_pm_save_regs(rinfo, 0); + + /* Prepare mobility chips for suspend. + */ + if (rinfo->is_mobility) { + /* Program V2CLK */ + radeon_pm_program_v2clk(rinfo); + + /* Disable IO PADs */ + radeon_pm_disable_iopad(rinfo); + + /* Set low current */ + radeon_pm_low_current(rinfo); + + /* Prepare chip for power management */ + radeon_pm_setup_for_suspend(rinfo); + + if (rinfo->family <= CHIP_FAMILY_RV280) { + /* Reset the MDLL */ + /* because both INPLL and OUTPLL take the same + * lock, that's why. */ + tmp = INPLL( pllMDLL_CKO) | MDLL_CKO__MCKOA_RESET + | MDLL_CKO__MCKOB_RESET; + OUTPLL( pllMDLL_CKO, tmp ); + } + } + + for (i = 0; i < 64; ++i) + pci_read_config_dword(rinfo->pdev, i * 4, + &rinfo->cfg_save[i]); + + /* Switch PCI power managment to D2. */ + pci_disable_device(rinfo->pdev); + for (;;) { + pci_read_config_word( + rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, + &pwr_cmd); + if (pwr_cmd & 2) + break; + pci_write_config_word( + rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, + (pwr_cmd & ~PCI_PM_CTRL_STATE_MASK) | 2); + mdelay(500); + } + } else { + printk(KERN_DEBUG "radeonfb (%s): switching to D0 state...\n", + pci_name(rinfo->pdev)); + + /* Switch back PCI powermanagment to D0 */ + mdelay(200); + pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, 0); + mdelay(500); + + if (rinfo->family <= CHIP_FAMILY_RV250) { + /* Reset the SDRAM controller */ + radeon_pm_full_reset_sdram(rinfo); + + /* Restore some registers */ + radeon_pm_restore_regs(rinfo); + } else { + /* Restore registers first */ + radeon_pm_restore_regs(rinfo); + /* init sdram controller */ + radeon_pm_full_reset_sdram(rinfo); + } + } +} + +static int radeon_restore_pci_cfg(struct radeonfb_info *rinfo) +{ + int i; + static u32 radeon_cfg_after_resume[64]; + + for (i = 0; i < 64; ++i) + pci_read_config_dword(rinfo->pdev, i * 4, + &radeon_cfg_after_resume[i]); + + if (radeon_cfg_after_resume[PCI_BASE_ADDRESS_0/4] + == rinfo->cfg_save[PCI_BASE_ADDRESS_0/4]) + return 0; /* assume everything is ok */ + + for (i = PCI_BASE_ADDRESS_0/4; i < 64; ++i) { + if (radeon_cfg_after_resume[i] != rinfo->cfg_save[i]) + pci_write_config_dword(rinfo->pdev, i * 4, + rinfo->cfg_save[i]); + } + pci_write_config_word(rinfo->pdev, PCI_CACHE_LINE_SIZE, + rinfo->cfg_save[PCI_CACHE_LINE_SIZE/4]); + pci_write_config_word(rinfo->pdev, PCI_COMMAND, + rinfo->cfg_save[PCI_COMMAND/4]); + return 1; +} + + +static/*extern*/ int susdisking = 0; + +int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct radeonfb_info *rinfo = info->par; + u8 agp; + int i; + + if (state == pdev->dev.power.power_state) + return 0; + + printk(KERN_DEBUG "radeonfb (%s): suspending to state: %d...\n", + pci_name(pdev), state); + + /* For suspend-to-disk, we cheat here. We don't suspend anything and + * let fbcon continue drawing until we are all set. That shouldn't + * really cause any problem at this point, provided that the wakeup + * code knows that any state in memory may not match the HW + */ + if (state != PM_SUSPEND_MEM) + goto done; + if (susdisking) { + printk("radeonfb (%s): suspending to disk but state = %d\n", + pci_name(pdev), state); + goto done; + } + + acquire_console_sem(); + + fb_set_suspend(info, 1); + + if (!(info->flags & FBINFO_HWACCEL_DISABLED)) { + /* Make sure engine is reset */ + radeon_engine_idle(); + radeonfb_engine_reset(rinfo); + radeon_engine_idle(); + } + + /* Blank display and LCD */ + radeon_screen_blank(rinfo, FB_BLANK_POWERDOWN, 1); + + /* Sleep */ + rinfo->asleep = 1; + rinfo->lock_blank = 1; + del_timer_sync(&rinfo->lvds_timer); + + /* Disable AGP. The AGP host should have done it, but since ordering + * isn't always properly guaranteed in this specific case, let's make + * sure it's disabled on card side now. Ultimately, when merging fbdev + * and dri into some common infrastructure, this will be handled + * more nicely. The host bridge side will (or will not) be dealt with + * by the bridge AGP driver, we don't attempt to touch it here. + */ + agp = pci_find_capability(pdev, PCI_CAP_ID_AGP); + if (agp) { + u32 cmd; + + pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd); + if (cmd & PCI_AGP_COMMAND_AGP) { + printk(KERN_INFO "radeonfb (%s): AGP was enabled, " + "disabling ...\n", + pci_name(pdev)); + cmd &= ~PCI_AGP_COMMAND_AGP; + pci_write_config_dword(pdev, agp + PCI_AGP_COMMAND, + cmd); + } + } + + /* If we support wakeup from poweroff, we save all regs we can including cfg + * space + */ + if (rinfo->pm_mode & radeon_pm_off) { + /* Always disable dynamic clocks or weird things are happening when + * the chip goes off (basically the panel doesn't shut down properly + * and we crash on wakeup), + * also, we want the saved regs context to have no dynamic clocks in + * it, we'll restore the dynamic clocks state on wakeup + */ + radeon_pm_disable_dynamic_mode(rinfo); + mdelay(50); + radeon_pm_save_regs(rinfo, 1); + + if (rinfo->is_mobility && !(rinfo->pm_mode & radeon_pm_d2)) { + /* Switch off LVDS interface */ + mdelay(1); + OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_BL_MOD_EN)); + mdelay(1); + OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_EN | LVDS_ON)); + OUTREG(LVDS_PLL_CNTL, (INREG(LVDS_PLL_CNTL) & ~30000) | 0x20000); + mdelay(20); + OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_DIGON)); + } + // FIXME: Use PCI layer + for (i = 0; i < 64; ++i) + pci_read_config_dword(pdev, i * 4, &rinfo->cfg_save[i]); + pci_disable_device(pdev); + } + /* If we support D2, we go to it (should be fixed later with a flag forcing + * D3 only for some laptops) + */ + if (rinfo->pm_mode & radeon_pm_d2) + radeon_set_suspend(rinfo, 1); + + release_console_sem(); + + done: + pdev->dev.power.power_state = state; + + return 0; +} + +int radeonfb_pci_resume(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct radeonfb_info *rinfo = info->par; + int rc = 0; + + if (pdev->dev.power.power_state == 0) + return 0; + + if (rinfo->no_schedule) { + if (try_acquire_console_sem()) + return 0; + } else + acquire_console_sem(); + + printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n", + pci_name(pdev), pdev->dev.power.power_state); + + + if (pci_enable_device(pdev)) { + rc = -ENODEV; + printk(KERN_ERR "radeonfb (%s): can't enable PCI device !\n", + pci_name(pdev)); + goto bail; + } + pci_set_master(pdev); + + if (pdev->dev.power.power_state == PM_SUSPEND_MEM) { + /* Wakeup chip. Check from config space if we were powered off + * (todo: additionally, check CLK_PIN_CNTL too) + */ + if ((rinfo->pm_mode & radeon_pm_off) && radeon_restore_pci_cfg(rinfo)) { + if (rinfo->reinit_func != NULL) + rinfo->reinit_func(rinfo); + else { + printk(KERN_ERR "radeonfb (%s): can't resume radeon from" + " D3 cold, need softboot !", pci_name(pdev)); + rc = -EIO; + goto bail; + } + } + /* If we support D2, try to resume... we should check what was our + * state though... (were we really in D2 state ?). Right now, this code + * is only enable on Macs so it's fine. + */ + else if (rinfo->pm_mode & radeon_pm_d2) + radeon_set_suspend(rinfo, 0); + + rinfo->asleep = 0; + } else + radeon_engine_idle(); + + /* Restore display & engine */ + radeon_write_mode (rinfo, &rinfo->state, 1); + if (!(info->flags & FBINFO_HWACCEL_DISABLED)) + radeonfb_engine_init (rinfo); + + fb_pan_display(info, &info->var); + fb_set_cmap(&info->cmap, info); + + /* Refresh */ + fb_set_suspend(info, 0); + + /* Unblank */ + rinfo->lock_blank = 0; + radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 1); + + /* Check status of dynclk */ + if (rinfo->dynclk == 1) + radeon_pm_enable_dynamic_mode(rinfo); + else if (rinfo->dynclk == 0) + radeon_pm_disable_dynamic_mode(rinfo); + + pdev->dev.power.power_state = PMSG_ON; + + bail: + release_console_sem(); + + return rc; +} + +#ifdef CONFIG_PPC_OF +static void radeonfb_early_resume(void *data) +{ + struct radeonfb_info *rinfo = data; + + rinfo->no_schedule = 1; + radeonfb_pci_resume(rinfo->pdev); + rinfo->no_schedule = 0; +} +#endif /* CONFIG_PPC_OF */ + +#endif /* CONFIG_PM */ + +void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk) +{ + /* Find PM registers in config space if any*/ + rinfo->pm_reg = pci_find_capability(rinfo->pdev, PCI_CAP_ID_PM); + + /* Enable/Disable dynamic clocks: TODO add sysfs access */ + rinfo->dynclk = dynclk; + if (dynclk == 1) { + radeon_pm_enable_dynamic_mode(rinfo); + printk("radeonfb: Dynamic Clock Power Management enabled\n"); + } else if (dynclk == 0) { + radeon_pm_disable_dynamic_mode(rinfo); + printk("radeonfb: Dynamic Clock Power Management disabled\n"); + } + + /* Check if we can power manage on suspend/resume. We can do + * D2 on M6, M7 and M9, and we can resume from D3 cold a few other + * "Mac" cards, but that's all. We need more infos about what the + * BIOS does tho. Right now, all this PM stuff is pmac-only for that + * reason. --BenH + */ +#if defined(CONFIG_PM) && defined(CONFIG_PPC_OF) + if (_machine == _MACH_Pmac && rinfo->of_node) { + if (rinfo->is_mobility && rinfo->pm_reg && + rinfo->family <= CHIP_FAMILY_RV250) + rinfo->pm_mode |= radeon_pm_d2; + + /* We can restart Jasper (M10 chip in albooks), BlueStone (7500 chip + * in some desktop G4s), and Via (M9+ chip on iBook G4) + */ + if (!strcmp(rinfo->of_node->name, "ATY,JasperParent")) { + rinfo->reinit_func = radeon_reinitialize_M10; + rinfo->pm_mode |= radeon_pm_off; + } +#if 0 /* Not ready yet */ + if (!strcmp(rinfo->of_node->name, "ATY,BlueStoneParent")) { + rinfo->reinit_func = radeon_reinitialize_QW; + rinfo->pm_mode |= radeon_pm_off; + } +#endif + if (!strcmp(rinfo->of_node->name, "ATY,ViaParent")) { + rinfo->reinit_func = radeon_reinitialize_M9P; + rinfo->pm_mode |= radeon_pm_off; + } + + /* If any of the above is set, we assume the machine can sleep/resume. + * It's a bit of a "shortcut" but will work fine. Ideally, we need infos + * from the platform about what happens to the chip... + * Now we tell the platform about our capability + */ + if (rinfo->pm_mode != radeon_pm_none) { + pmac_call_feature(PMAC_FTR_DEVICE_CAN_WAKE, rinfo->of_node, 0, 1); + pmac_set_early_video_resume(radeonfb_early_resume, rinfo); + } + +#if 0 + /* Power down TV DAC, taht saves a significant amount of power, + * we'll have something better once we actually have some TVOut + * support + */ + OUTREG(TV_DAC_CNTL, INREG(TV_DAC_CNTL) | 0x07000000); +#endif + } +#endif /* defined(CONFIG_PM) && defined(CONFIG_PPC_OF) */ +} + +void radeonfb_pm_exit(struct radeonfb_info *rinfo) +{ +#if defined(CONFIG_PM) && defined(CONFIG_PPC_OF) + if (rinfo->pm_mode != radeon_pm_none) + pmac_set_early_video_resume(NULL, NULL); +#endif +} diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h new file mode 100644 index 000000000000..659bc9f62244 --- /dev/null +++ b/drivers/video/aty/radeonfb.h @@ -0,0 +1,625 @@ +#ifndef __RADEONFB_H__ +#define __RADEONFB_H__ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/fb.h> + + +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/i2c-algo-bit.h> + +#include <asm/io.h> + +#ifdef CONFIG_PPC_OF +#include <asm/prom.h> +#endif + +#include <video/radeon.h> + +/*************************************************************** + * Most of the definitions here are adapted right from XFree86 * + ***************************************************************/ + + +/* + * Chip families. Must fit in the low 16 bits of a long word + */ +enum radeon_family { + CHIP_FAMILY_UNKNOW, + CHIP_FAMILY_LEGACY, + CHIP_FAMILY_RADEON, + CHIP_FAMILY_RV100, + CHIP_FAMILY_RS100, /* U1 (IGP320M) or A3 (IGP320)*/ + CHIP_FAMILY_RV200, + CHIP_FAMILY_RS200, /* U2 (IGP330M/340M/350M) or A4 (IGP330/340/345/350), + RS250 (IGP 7000) */ + CHIP_FAMILY_R200, + CHIP_FAMILY_RV250, + CHIP_FAMILY_RS300, /* Radeon 9000 IGP */ + CHIP_FAMILY_RV280, + CHIP_FAMILY_R300, + CHIP_FAMILY_R350, + CHIP_FAMILY_RV350, + CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */ + CHIP_FAMILY_R420, /* R420/R423/M18 */ + CHIP_FAMILY_LAST, +}; + +#define IS_RV100_VARIANT(rinfo) (((rinfo)->family == CHIP_FAMILY_RV100) || \ + ((rinfo)->family == CHIP_FAMILY_RV200) || \ + ((rinfo)->family == CHIP_FAMILY_RS100) || \ + ((rinfo)->family == CHIP_FAMILY_RS200) || \ + ((rinfo)->family == CHIP_FAMILY_RV250) || \ + ((rinfo)->family == CHIP_FAMILY_RV280) || \ + ((rinfo)->family == CHIP_FAMILY_RS300)) + + +#define IS_R300_VARIANT(rinfo) (((rinfo)->family == CHIP_FAMILY_R300) || \ + ((rinfo)->family == CHIP_FAMILY_RV350) || \ + ((rinfo)->family == CHIP_FAMILY_R350) || \ + ((rinfo)->family == CHIP_FAMILY_RV380) || \ + ((rinfo)->family == CHIP_FAMILY_R420)) + +/* + * Chip flags + */ +enum radeon_chip_flags { + CHIP_FAMILY_MASK = 0x0000ffffUL, + CHIP_FLAGS_MASK = 0xffff0000UL, + CHIP_IS_MOBILITY = 0x00010000UL, + CHIP_IS_IGP = 0x00020000UL, + CHIP_HAS_CRTC2 = 0x00040000UL, +}; + +/* + * Errata workarounds + */ +enum radeon_errata { + CHIP_ERRATA_R300_CG = 0x00000001, + CHIP_ERRATA_PLL_DUMMYREADS = 0x00000002, + CHIP_ERRATA_PLL_DELAY = 0x00000004, +}; + + +/* + * Monitor types + */ +enum radeon_montype { + MT_NONE = 0, + MT_CRT, /* CRT */ + MT_LCD, /* LCD */ + MT_DFP, /* DVI */ + MT_CTV, /* composite TV */ + MT_STV /* S-Video out */ +}; + +/* + * DDC i2c ports + */ +enum ddc_type { + ddc_none, + ddc_monid, + ddc_dvi, + ddc_vga, + ddc_crt2, +}; + +/* + * Connector types + */ +enum conn_type { + conn_none, + conn_proprietary, + conn_crt, + conn_DVI_I, + conn_DVI_D, +}; + + +/* + * PLL infos + */ +struct pll_info { + int ppll_max; + int ppll_min; + int sclk, mclk; + int ref_div; + int ref_clk; +}; + + +/* + * This structure contains the various registers manipulated by this + * driver for setting or restoring a mode. It's mostly copied from + * XFree's RADEONSaveRec structure. A few chip settings might still be + * tweaked without beeing reflected or saved in these registers though + */ +struct radeon_regs { + /* Common registers */ + u32 ovr_clr; + u32 ovr_wid_left_right; + u32 ovr_wid_top_bottom; + u32 ov0_scale_cntl; + u32 mpp_tb_config; + u32 mpp_gp_config; + u32 subpic_cntl; + u32 viph_control; + u32 i2c_cntl_1; + u32 gen_int_cntl; + u32 cap0_trig_cntl; + u32 cap1_trig_cntl; + u32 bus_cntl; + u32 surface_cntl; + u32 bios_5_scratch; + + /* Other registers to save for VT switches or driver load/unload */ + u32 dp_datatype; + u32 rbbm_soft_reset; + u32 clock_cntl_index; + u32 amcgpio_en_reg; + u32 amcgpio_mask; + + /* Surface/tiling registers */ + u32 surf_lower_bound[8]; + u32 surf_upper_bound[8]; + u32 surf_info[8]; + + /* CRTC registers */ + u32 crtc_gen_cntl; + u32 crtc_ext_cntl; + u32 dac_cntl; + u32 crtc_h_total_disp; + u32 crtc_h_sync_strt_wid; + u32 crtc_v_total_disp; + u32 crtc_v_sync_strt_wid; + u32 crtc_offset; + u32 crtc_offset_cntl; + u32 crtc_pitch; + u32 disp_merge_cntl; + u32 grph_buffer_cntl; + u32 crtc_more_cntl; + + /* CRTC2 registers */ + u32 crtc2_gen_cntl; + u32 dac2_cntl; + u32 disp_output_cntl; + u32 disp_hw_debug; + u32 disp2_merge_cntl; + u32 grph2_buffer_cntl; + u32 crtc2_h_total_disp; + u32 crtc2_h_sync_strt_wid; + u32 crtc2_v_total_disp; + u32 crtc2_v_sync_strt_wid; + u32 crtc2_offset; + u32 crtc2_offset_cntl; + u32 crtc2_pitch; + + /* Flat panel regs */ + u32 fp_crtc_h_total_disp; + u32 fp_crtc_v_total_disp; + u32 fp_gen_cntl; + u32 fp2_gen_cntl; + u32 fp_h_sync_strt_wid; + u32 fp2_h_sync_strt_wid; + u32 fp_horz_stretch; + u32 fp_panel_cntl; + u32 fp_v_sync_strt_wid; + u32 fp2_v_sync_strt_wid; + u32 fp_vert_stretch; + u32 lvds_gen_cntl; + u32 lvds_pll_cntl; + u32 tmds_crc; + u32 tmds_transmitter_cntl; + + /* Computed values for PLL */ + u32 dot_clock_freq; + int feedback_div; + int post_div; + + /* PLL registers */ + u32 ppll_div_3; + u32 ppll_ref_div; + u32 vclk_ecp_cntl; + u32 clk_cntl_index; + + /* Computed values for PLL2 */ + u32 dot_clock_freq_2; + int feedback_div_2; + int post_div_2; + + /* PLL2 registers */ + u32 p2pll_ref_div; + u32 p2pll_div_0; + u32 htotal_cntl2; + + /* Palette */ + int palette_valid; +}; + +struct panel_info { + int xres, yres; + int valid; + int clock; + int hOver_plus, hSync_width, hblank; + int vOver_plus, vSync_width, vblank; + int hAct_high, vAct_high, interlaced; + int pwr_delay; + int use_bios_dividers; + int ref_divider; + int post_divider; + int fbk_divider; +}; + +struct radeonfb_info; + +#ifdef CONFIG_FB_RADEON_I2C +struct radeon_i2c_chan { + struct radeonfb_info *rinfo; + u32 ddc_reg; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; +}; +#endif + +enum radeon_pm_mode { + radeon_pm_none = 0, /* Nothing supported */ + radeon_pm_d2 = 0x00000001, /* Can do D2 state */ + radeon_pm_off = 0x00000002, /* Can resume from D3 cold */ +}; + +struct radeonfb_info { + struct fb_info *info; + + struct radeon_regs state; + struct radeon_regs init_state; + + char name[DEVICE_NAME_SIZE]; + + unsigned long mmio_base_phys; + unsigned long fb_base_phys; + + void __iomem *mmio_base; + void __iomem *fb_base; + + unsigned long fb_local_base; + + struct pci_dev *pdev; +#ifdef CONFIG_PPC_OF + struct device_node *of_node; +#endif + + void __iomem *bios_seg; + int fp_bios_start; + + u32 pseudo_palette[17]; + struct { u8 red, green, blue, pad; } + palette[256]; + + int chipset; + u8 family; + u8 rev; + unsigned int errata; + unsigned long video_ram; + unsigned long mapped_vram; + int vram_width; + int vram_ddr; + + int pitch, bpp, depth; + + int has_CRTC2; + int is_mobility; + int is_IGP; + int reversed_DAC; + int reversed_TMDS; + struct panel_info panel_info; + int mon1_type; + u8 *mon1_EDID; + struct fb_videomode *mon1_modedb; + int mon1_dbsize; + int mon2_type; + u8 *mon2_EDID; + + u32 dp_gui_master_cntl; + + struct pll_info pll; + + int mtrr_hdl; + + int pm_reg; + u32 save_regs[100]; + int asleep; + int lock_blank; + int dynclk; + int no_schedule; + enum radeon_pm_mode pm_mode; + void (*reinit_func)(struct radeonfb_info *rinfo); + + /* Lock on register access */ + spinlock_t reg_lock; + + /* Timer used for delayed LVDS operations */ + struct timer_list lvds_timer; + u32 pending_lvds_gen_cntl; + +#ifdef CONFIG_FB_RADEON_I2C + struct radeon_i2c_chan i2c[4]; +#endif + + u32 cfg_save[64]; +}; + + +#define PRIMARY_MONITOR(rinfo) (rinfo->mon1_type) + + +/* + * Debugging stuffs + */ +#ifdef CONFIG_FB_RADEON_DEBUG +#define DEBUG 1 +#else +#define DEBUG 0 +#endif + +#if DEBUG +#define RTRACE printk +#else +#define RTRACE if(0) printk +#endif + + +/* + * IO macros + */ + +/* Note about this function: we have some rare cases where we must not schedule, + * this typically happen with our special "wake up early" hook which allows us to + * wake up the graphic chip (and thus get the console back) before everything else + * on some machines that support that mecanism. At this point, interrupts are off + * and scheduling is not permitted + */ +static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms) +{ + if (rinfo->no_schedule || oops_in_progress) + mdelay(ms); + else + msleep(ms); +} + + +#define INREG8(addr) readb((rinfo->mmio_base)+addr) +#define OUTREG8(addr,val) writeb(val, (rinfo->mmio_base)+addr) +#define INREG(addr) readl((rinfo->mmio_base)+addr) +#define OUTREG(addr,val) writel(val, (rinfo->mmio_base)+addr) + +static inline void _OUTREGP(struct radeonfb_info *rinfo, u32 addr, + u32 val, u32 mask) +{ + unsigned long flags; + unsigned int tmp; + + spin_lock_irqsave(&rinfo->reg_lock, flags); + tmp = INREG(addr); + tmp &= (mask); + tmp |= (val); + OUTREG(addr, tmp); + spin_unlock_irqrestore(&rinfo->reg_lock, flags); +} + +#define OUTREGP(addr,val,mask) _OUTREGP(rinfo, addr, val,mask) + +/* + * Note about PLL register accesses: + * + * I have removed the spinlock on them on purpose. The driver now + * expects that it will only manipulate the PLL registers in normal + * task environment, where radeon_msleep() will be called, protected + * by a semaphore (currently the console semaphore) so that no conflict + * will happen on the PLL register index. + * + * With the latest changes to the VT layer, this is guaranteed for all + * calls except the actual drawing/blits which aren't supposed to use + * the PLL registers anyway + * + * This is very important for the workarounds to work properly. The only + * possible exception to this rule is the call to unblank(), which may + * be done at irq time if an oops is in progress. + */ +static inline void radeon_pll_errata_after_index(struct radeonfb_info *rinfo) +{ + if (!(rinfo->errata & CHIP_ERRATA_PLL_DUMMYREADS)) + return; + + (void)INREG(CLOCK_CNTL_DATA); + (void)INREG(CRTC_GEN_CNTL); +} + +static inline void radeon_pll_errata_after_data(struct radeonfb_info *rinfo) +{ + if (rinfo->errata & CHIP_ERRATA_PLL_DELAY) { + /* we can't deal with posted writes here ... */ + _radeon_msleep(rinfo, 5); + } + if (rinfo->errata & CHIP_ERRATA_R300_CG) { + u32 save, tmp; + save = INREG(CLOCK_CNTL_INDEX); + tmp = save & ~(0x3f | PLL_WR_EN); + OUTREG(CLOCK_CNTL_INDEX, tmp); + tmp = INREG(CLOCK_CNTL_DATA); + OUTREG(CLOCK_CNTL_INDEX, save); + } +} + +static inline u32 __INPLL(struct radeonfb_info *rinfo, u32 addr) +{ + u32 data; + + OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f); + radeon_pll_errata_after_index(rinfo); + data = INREG(CLOCK_CNTL_DATA); + radeon_pll_errata_after_data(rinfo); + return data; +} + +static inline void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index, + u32 val) +{ + + OUTREG8(CLOCK_CNTL_INDEX, (index & 0x0000003f) | 0x00000080); + radeon_pll_errata_after_index(rinfo); + OUTREG(CLOCK_CNTL_DATA, val); + radeon_pll_errata_after_data(rinfo); +} + + +static inline void __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index, + u32 val, u32 mask) +{ + unsigned int tmp; + + tmp = __INPLL(rinfo, index); + tmp &= (mask); + tmp |= (val); + __OUTPLL(rinfo, index, tmp); +} + + +#define INPLL(addr) __INPLL(rinfo, addr) +#define OUTPLL(index, val) __OUTPLL(rinfo, index, val) +#define OUTPLLP(index, val, mask) __OUTPLLP(rinfo, index, val, mask) + + +#define BIOS_IN8(v) (readb(rinfo->bios_seg + (v))) +#define BIOS_IN16(v) (readb(rinfo->bios_seg + (v)) | \ + (readb(rinfo->bios_seg + (v) + 1) << 8)) +#define BIOS_IN32(v) (readb(rinfo->bios_seg + (v)) | \ + (readb(rinfo->bios_seg + (v) + 1) << 8) | \ + (readb(rinfo->bios_seg + (v) + 2) << 16) | \ + (readb(rinfo->bios_seg + (v) + 3) << 24)) + +/* + * Inline utilities + */ +static inline int round_div(int num, int den) +{ + return (num + (den / 2)) / den; +} + +static inline int var_to_depth(const struct fb_var_screeninfo *var) +{ + if (var->bits_per_pixel != 16) + return var->bits_per_pixel; + return (var->green.length == 5) ? 15 : 16; +} + +static inline u32 radeon_get_dstbpp(u16 depth) +{ + switch (depth) { + case 8: + return DST_8BPP; + case 15: + return DST_15BPP; + case 16: + return DST_16BPP; + case 32: + return DST_32BPP; + default: + return 0; + } +} + +/* + * 2D Engine helper routines + */ +static inline void radeon_engine_flush (struct radeonfb_info *rinfo) +{ + int i; + + /* initiate flush */ + OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL, + ~RB2D_DC_FLUSH_ALL); + + for (i=0; i < 2000000; i++) { + if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY)) + return; + udelay(1); + } + printk(KERN_ERR "radeonfb: Flush Timeout !\n"); +} + + +static inline void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries) +{ + int i; + + for (i=0; i<2000000; i++) { + if ((INREG(RBBM_STATUS) & 0x7f) >= entries) + return; + udelay(1); + } + printk(KERN_ERR "radeonfb: FIFO Timeout !\n"); +} + + +static inline void _radeon_engine_idle(struct radeonfb_info *rinfo) +{ + int i; + + /* ensure FIFO is empty before waiting for idle */ + _radeon_fifo_wait (rinfo, 64); + + for (i=0; i<2000000; i++) { + if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) { + radeon_engine_flush (rinfo); + return; + } + udelay(1); + } + printk(KERN_ERR "radeonfb: Idle Timeout !\n"); +} + + +#define radeon_engine_idle() _radeon_engine_idle(rinfo) +#define radeon_fifo_wait(entries) _radeon_fifo_wait(rinfo,entries) +#define radeon_msleep(ms) _radeon_msleep(rinfo,ms) + + +/* I2C Functions */ +extern void radeon_create_i2c_busses(struct radeonfb_info *rinfo); +extern void radeon_delete_i2c_busses(struct radeonfb_info *rinfo); +extern int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid); + +/* PM Functions */ +extern int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state); +extern int radeonfb_pci_resume(struct pci_dev *pdev); +extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk); +extern void radeonfb_pm_exit(struct radeonfb_info *rinfo); + +/* Monitor probe functions */ +extern void radeon_probe_screens(struct radeonfb_info *rinfo, + const char *monitor_layout, int ignore_edid); +extern void radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option); +extern int radeon_match_mode(struct radeonfb_info *rinfo, + struct fb_var_screeninfo *dest, + const struct fb_var_screeninfo *src); + +/* Accel functions */ +extern void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region); +extern void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); +extern void radeonfb_imageblit(struct fb_info *p, const struct fb_image *image); +extern int radeonfb_sync(struct fb_info *info); +extern void radeonfb_engine_init (struct radeonfb_info *rinfo); +extern void radeonfb_engine_reset(struct radeonfb_info *rinfo); + +/* Other functions */ +extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch); +extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, + int reg_only); + +#endif /* __RADEONFB_H__ */ diff --git a/drivers/video/aty/xlinit.c b/drivers/video/aty/xlinit.c new file mode 100644 index 000000000000..92643af12581 --- /dev/null +++ b/drivers/video/aty/xlinit.c @@ -0,0 +1,354 @@ +/* + * ATI Rage XL Initialization. Support for Xpert98 and Victoria + * PCI cards. + * + * Copyright (C) 2002 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <asm/io.h> +#include <video/mach64.h> +#include "atyfb.h" + +#define MPLL_GAIN 0xad +#define VPLL_GAIN 0xd5 + +enum { + VICTORIA = 0, + XPERT98, + NUM_XL_CARDS +}; + +extern const struct aty_pll_ops aty_pll_ct; + +#define DEFAULT_CARD XPERT98 +static int xl_card = DEFAULT_CARD; + +static const struct xl_card_cfg_t { + int ref_crystal; // 10^4 Hz + int mem_type; + int mem_size; + u32 mem_cntl; + u32 ext_mem_cntl; + u32 mem_addr_config; + u32 bus_cntl; + u32 dac_cntl; + u32 hw_debug; + u32 custom_macro_cntl; + u8 dll2_cntl; + u8 pll_yclk_cntl; +} card_cfg[NUM_XL_CARDS] = { + // VICTORIA + { 2700, SDRAM, 0x800000, + 0x10757A3B, 0x64000C81, 0x00110202, 0x7b33A040, + 0x82010102, 0x48803800, 0x005E0179, + 0x50, 0x25 + }, + // XPERT98 + { 1432, WRAM, 0x800000, + 0x00165A2B, 0xE0000CF1, 0x00200213, 0x7333A001, + 0x8000000A, 0x48833800, 0x007F0779, + 0x10, 0x19 + } +}; + +typedef struct { + u8 lcd_reg; + u32 val; +} lcd_tbl_t; + +static const lcd_tbl_t lcd_tbl[] = { + { 0x01, 0x000520C0 }, + { 0x08, 0x02000408 }, + { 0x03, 0x00000F00 }, + { 0x00, 0x00000000 }, + { 0x02, 0x00000000 }, + { 0x04, 0x00000000 }, + { 0x05, 0x00000000 }, + { 0x06, 0x00000000 }, + { 0x33, 0x00000000 }, + { 0x34, 0x00000000 }, + { 0x35, 0x00000000 }, + { 0x36, 0x00000000 }, + { 0x37, 0x00000000 } +}; + +static void reset_gui(struct atyfb_par *par) +{ + aty_st_8(GEN_TEST_CNTL+1, 0x01, par); + aty_st_8(GEN_TEST_CNTL+1, 0x00, par); + aty_st_8(GEN_TEST_CNTL+1, 0x02, par); + mdelay(5); +} + +static void reset_sdram(struct atyfb_par *par) +{ + u8 temp; + + temp = aty_ld_8(EXT_MEM_CNTL, par); + temp |= 0x02; + aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_SDRAM_RESET = 1b + temp |= 0x08; + aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_CYC_TEST = 10b + temp |= 0x0c; + aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_CYC_TEST = 11b + mdelay(5); + temp &= 0xf3; + aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_CYC_TEST = 00b + temp &= 0xfd; + aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_SDRAM_REST = 0b + mdelay(5); +} + +static void init_dll(struct atyfb_par *par) +{ + // enable DLL + aty_st_pll_ct(PLL_GEN_CNTL, + aty_ld_pll_ct(PLL_GEN_CNTL, par) & 0x7f, + par); + + // reset DLL + aty_st_pll_ct(DLL_CNTL, 0x82, par); + aty_st_pll_ct(DLL_CNTL, 0xE2, par); + mdelay(5); + aty_st_pll_ct(DLL_CNTL, 0x82, par); + mdelay(6); +} + +static void reset_clocks(struct atyfb_par *par, struct pll_ct *pll, + int hsync_enb) +{ + reset_gui(par); + aty_st_pll_ct(MCLK_FB_DIV, pll->mclk_fb_div, par); + aty_st_pll_ct(SCLK_FB_DIV, pll->sclk_fb_div, par); + + mdelay(15); + init_dll(par); + aty_st_8(GEN_TEST_CNTL+1, 0x00, par); + mdelay(5); + aty_st_8(CRTC_GEN_CNTL+3, 0x04, par); + mdelay(6); + reset_sdram(par); + aty_st_8(CRTC_GEN_CNTL+3, + hsync_enb ? 0x00 : 0x04, par); + + aty_st_pll_ct(SPLL_CNTL2, pll->spll_cntl2, par); + aty_st_pll_ct(PLL_GEN_CNTL, pll->pll_gen_cntl, par); + aty_st_pll_ct(PLL_VCLK_CNTL, pll->pll_vclk_cntl, par); +} + +int atyfb_xl_init(struct fb_info *info) +{ + const struct xl_card_cfg_t * card = &card_cfg[xl_card]; + struct atyfb_par *par = (struct atyfb_par *) info->par; + union aty_pll pll; + int i, err; + u32 temp; + + aty_st_8(CONFIG_STAT0, 0x85, par); + mdelay(10); + + /* + * The following needs to be set before the call + * to var_to_pll() below. They'll be re-set again + * to the same values in aty_init(). + */ + par->ref_clk_per = 100000000UL/card->ref_crystal; + par->ram_type = card->mem_type; + info->fix.smem_len = card->mem_size; + if (xl_card == VICTORIA) { + // the MCLK, XCLK are 120MHz on victoria card + par->mclk_per = 1000000/120; + par->xclk_per = 1000000/120; + par->features &= ~M64F_MFB_FORCE_4; + } + + /* + * Calculate mclk and xclk dividers, etc. The passed + * pixclock and bpp values don't matter yet, the vclk + * isn't programmed until later. + */ + if ((err = aty_pll_ct.var_to_pll(info, 39726, 8, &pll))) + return err; + + aty_st_pll_ct(LVDS_CNTL0, 0x00, par); + aty_st_pll_ct(DLL2_CNTL, card->dll2_cntl, par); + aty_st_pll_ct(V2PLL_CNTL, 0x10, par); + aty_st_pll_ct(MPLL_CNTL, MPLL_GAIN, par); + aty_st_pll_ct(VPLL_CNTL, VPLL_GAIN, par); + aty_st_pll_ct(PLL_VCLK_CNTL, 0x00, par); + aty_st_pll_ct(VFC_CNTL, 0x1B, par); + aty_st_pll_ct(PLL_REF_DIV, pll.ct.pll_ref_div, par); + aty_st_pll_ct(PLL_EXT_CNTL, pll.ct.pll_ext_cntl, par); + aty_st_pll_ct(SPLL_CNTL2, 0x03, par); + aty_st_pll_ct(PLL_GEN_CNTL, 0x44, par); + + reset_clocks(par, &pll.ct, 0); + mdelay(10); + + aty_st_pll_ct(VCLK_POST_DIV, 0x03, par); + aty_st_pll_ct(VCLK0_FB_DIV, 0xDA, par); + aty_st_pll_ct(VCLK_POST_DIV, 0x0F, par); + aty_st_pll_ct(VCLK1_FB_DIV, 0xF5, par); + aty_st_pll_ct(VCLK_POST_DIV, 0x3F, par); + aty_st_pll_ct(PLL_EXT_CNTL, 0x40 | pll.ct.pll_ext_cntl, par); + aty_st_pll_ct(VCLK2_FB_DIV, 0x00, par); + aty_st_pll_ct(VCLK_POST_DIV, 0xFF, par); + aty_st_pll_ct(PLL_EXT_CNTL, 0xC0 | pll.ct.pll_ext_cntl, par); + aty_st_pll_ct(VCLK3_FB_DIV, 0x00, par); + + aty_st_8(BUS_CNTL, 0x01, par); + aty_st_le32(BUS_CNTL, card->bus_cntl | 0x08000000, par); + + aty_st_le32(CRTC_GEN_CNTL, 0x04000200, par); + aty_st_le16(CONFIG_STAT0, 0x0020, par); + aty_st_le32(MEM_CNTL, 0x10151A33, par); + aty_st_le32(EXT_MEM_CNTL, 0xE0000C01, par); + aty_st_le16(CRTC_GEN_CNTL+2, 0x0000, par); + aty_st_le32(DAC_CNTL, card->dac_cntl, par); + aty_st_le16(GEN_TEST_CNTL, 0x0100, par); + aty_st_le32(CUSTOM_MACRO_CNTL, 0x003C0171, par); + aty_st_le32(MEM_BUF_CNTL, 0x00382848, par); + + aty_st_le32(HW_DEBUG, card->hw_debug, par); + aty_st_le16(MEM_ADDR_CONFIG, 0x0000, par); + aty_st_le16(GP_IO+2, 0x0000, par); + aty_st_le16(GEN_TEST_CNTL, 0x0000, par); + aty_st_le16(EXT_DAC_REGS+2, 0x0000, par); + aty_st_le32(CRTC_INT_CNTL, 0x00000000, par); + aty_st_le32(TIMER_CONFIG, 0x00000000, par); + aty_st_le32(0xEC, 0x00000000, par); + aty_st_le32(0xFC, 0x00000000, par); + + for (i=0; i<sizeof(lcd_tbl)/sizeof(lcd_tbl_t); i++) { + aty_st_lcd(lcd_tbl[i].lcd_reg, lcd_tbl[i].val, par); + } + + aty_st_le16(CONFIG_STAT0, 0x00A4, par); + mdelay(10); + + aty_st_8(BUS_CNTL+1, 0xA0, par); + mdelay(10); + + reset_clocks(par, &pll.ct, 1); + mdelay(10); + + // something about power management + aty_st_8(LCD_INDEX, 0x08, par); + aty_st_8(LCD_DATA, 0x0A, par); + aty_st_8(LCD_INDEX, 0x08, par); + aty_st_8(LCD_DATA+3, 0x02, par); + aty_st_8(LCD_INDEX, 0x08, par); + aty_st_8(LCD_DATA, 0x0B, par); + mdelay(2); + + // enable display requests, enable CRTC + aty_st_8(CRTC_GEN_CNTL+3, 0x02, par); + // disable display + aty_st_8(CRTC_GEN_CNTL, 0x40, par); + // disable display requests, disable CRTC + aty_st_8(CRTC_GEN_CNTL+3, 0x04, par); + mdelay(10); + + aty_st_pll_ct(PLL_YCLK_CNTL, 0x25, par); + + aty_st_le16(CUSTOM_MACRO_CNTL, 0x0179, par); + aty_st_le16(CUSTOM_MACRO_CNTL+2, 0x005E, par); + aty_st_le16(CUSTOM_MACRO_CNTL+2, card->custom_macro_cntl>>16, par); + aty_st_8(CUSTOM_MACRO_CNTL+1, + (card->custom_macro_cntl>>8) & 0xff, par); + + aty_st_le32(MEM_ADDR_CONFIG, card->mem_addr_config, par); + aty_st_le32(MEM_CNTL, card->mem_cntl, par); + aty_st_le32(EXT_MEM_CNTL, card->ext_mem_cntl, par); + + aty_st_8(CONFIG_STAT0, 0xA0 | card->mem_type, par); + + aty_st_pll_ct(PLL_YCLK_CNTL, 0x01, par); + mdelay(15); + aty_st_pll_ct(PLL_YCLK_CNTL, card->pll_yclk_cntl, par); + mdelay(1); + + reset_clocks(par, &pll.ct, 0); + mdelay(50); + reset_clocks(par, &pll.ct, 0); + mdelay(50); + + // enable extended register block + aty_st_8(BUS_CNTL+3, 0x7B, par); + mdelay(1); + // disable extended register block + aty_st_8(BUS_CNTL+3, 0x73, par); + + aty_st_8(CONFIG_STAT0, 0x80 | card->mem_type, par); + + // disable display requests, disable CRTC + aty_st_8(CRTC_GEN_CNTL+3, 0x04, par); + // disable mapping registers in VGA aperture + aty_st_8(CONFIG_CNTL, aty_ld_8(CONFIG_CNTL, par) & ~0x04, par); + mdelay(50); + // enable display requests, enable CRTC + aty_st_8(CRTC_GEN_CNTL+3, 0x02, par); + + // make GPIO's 14,15,16 all inputs + aty_st_8(LCD_INDEX, 0x07, par); + aty_st_8(LCD_DATA+3, 0x00, par); + + // enable the display + aty_st_8(CRTC_GEN_CNTL, 0x00, par); + mdelay(17); + // reset the memory controller + aty_st_8(GEN_TEST_CNTL+1, 0x02, par); + mdelay(15); + aty_st_8(GEN_TEST_CNTL+1, 0x00, par); + mdelay(30); + + // enable extended register block + aty_st_8(BUS_CNTL+3, + (u8)(aty_ld_8(BUS_CNTL+3, par) | 0x08), + par); + // set FIFO size to 512 (PIO) + aty_st_le32(GUI_CNTL, + aty_ld_le32(GUI_CNTL, par) & ~0x3, + par); + + // enable CRT and disable lcd + aty_st_8(LCD_INDEX, 0x01, par); + temp = aty_ld_le32(LCD_DATA, par); + temp = (temp | 0x01) & ~0x02; + aty_st_le32(LCD_DATA, temp, par); + return 0; +} + diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c new file mode 100644 index 000000000000..cacd88cc84ab --- /dev/null +++ b/drivers/video/au1100fb.c @@ -0,0 +1,676 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1100 LCD Driver. + * + * Copyright 2002 MontaVista Software + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * Copyright 2002 Alchemy Semiconductor + * Author: Alchemy Semiconductor + * + * Based on: + * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device + * Created 28 Dec 1997 by Geert Uytterhoeven + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <asm/au1000.h> +#include <asm/pb1100.h> +#include "au1100fb.h" + +#include <video/fbcon.h> +#include <video/fbcon-mfb.h> +#include <video/fbcon-cfb2.h> +#include <video/fbcon-cfb4.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> + +/* + * Sanity check. If this is a new Au1100 based board, search for + * the PB1100 ifdefs to make sure you modify the code accordingly. + */ +#if defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_HYDROGEN3) +#else +error Unknown Au1100 board +#endif + +#define CMAPSIZE 16 + +static int my_lcd_index; /* default is zero */ +struct known_lcd_panels *p_lcd; +AU1100_LCD *p_lcd_reg = (AU1100_LCD *)AU1100_LCD_ADDR; + +struct au1100fb_info { + struct fb_info_gen gen; + unsigned long fb_virt_start; + unsigned long fb_size; + unsigned long fb_phys; + int mmaped; + int nohwcursor; + + struct { unsigned red, green, blue, pad; } palette[256]; + +#if defined(FBCON_HAS_CFB16) + u16 fbcon_cmap16[16]; +#endif +}; + + +struct au1100fb_par { + struct fb_var_screeninfo var; + + int line_length; // in bytes + int cmap_len; // color-map length +}; + + +static struct au1100fb_info fb_info; +static struct au1100fb_par current_par; +static struct display disp; + +int au1100fb_init(void); +void au1100fb_setup(char *options, int *ints); +static int au1100fb_mmap(struct fb_info *fb, struct file *file, + struct vm_area_struct *vma); +static int au1100_blank(int blank_mode, struct fb_info_gen *info); +static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info); + +void au1100_nocursor(struct display *p, int mode, int xx, int yy){}; + +static struct fb_ops au1100fb_ops = { + owner: THIS_MODULE, + fb_get_fix: fbgen_get_fix, + fb_get_var: fbgen_get_var, + fb_set_var: fbgen_set_var, + fb_get_cmap: fbgen_get_cmap, + fb_set_cmap: fbgen_set_cmap, + fb_pan_display: fbgen_pan_display, + fb_ioctl: au1100fb_ioctl, + fb_mmap: au1100fb_mmap, +}; + +static void au1100_detect(void) +{ + /* + * This function should detect the current video mode settings + * and store it as the default video mode + */ + + /* + * Yeh, well, we're not going to change any settings so we're + * always stuck with the default ... + */ + +} + +static int au1100_encode_fix(struct fb_fix_screeninfo *fix, + const void *_par, struct fb_info_gen *_info) +{ + struct au1100fb_info *info = (struct au1100fb_info *) _info; + struct au1100fb_par *par = (struct au1100fb_par *) _par; + struct fb_var_screeninfo *var = &par->var; + + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + + fix->smem_start = info->fb_phys; + fix->smem_len = info->fb_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->visual = (var->bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->ywrapstep = 0; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->line_length = current_par.line_length; + return 0; +} + +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: /* 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; + } + + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; +} + +static int au1100_decode_var(const struct fb_var_screeninfo *var, + void *_par, struct fb_info_gen *_info) +{ + + struct au1100fb_par *par = (struct au1100fb_par *)_par; + + /* + * Don't allow setting any of these yet: xres and yres don't + * make sense for LCD panels. + */ + if (var->xres != p_lcd->xres || + var->yres != p_lcd->yres || + var->xres != p_lcd->xres || + var->yres != p_lcd->yres) { + return -EINVAL; + } + if(var->bits_per_pixel != p_lcd->bpp) { + return -EINVAL; + } + + memset(par, 0, sizeof(struct au1100fb_par)); + par->var = *var; + + /* FIXME */ + switch (var->bits_per_pixel) { + case 8: + par->var.bits_per_pixel = 8; + break; + case 16: + par->var.bits_per_pixel = 16; + break; + default: + printk("color depth %d bpp not supported\n", + var->bits_per_pixel); + return -EINVAL; + + } + set_color_bitfields(&par->var); + par->cmap_len = (par->var.bits_per_pixel == 8) ? 256 : 16; + return 0; +} + +static int au1100_encode_var(struct fb_var_screeninfo *var, + const void *par, struct fb_info_gen *_info) +{ + + *var = ((struct au1100fb_par *)par)->var; + return 0; +} + +static void +au1100_get_par(void *_par, struct fb_info_gen *_info) +{ + *(struct au1100fb_par *)_par = current_par; +} + +static void au1100_set_par(const void *par, struct fb_info_gen *info) +{ + /* nothing to do: we don't change any settings */ +} + +static int au1100_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *info) +{ + + struct au1100fb_info* i = (struct au1100fb_info*)info; + + if (regno > 255) + return 1; + + *red = i->palette[regno].red; + *green = i->palette[regno].green; + *blue = i->palette[regno].blue; + *transp = 0; + + return 0; +} + +static int au1100_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct au1100fb_info* i = (struct au1100fb_info *)info; + u32 rgbcol; + + if (regno > 255) + return 1; + + i->palette[regno].red = red; + i->palette[regno].green = green; + i->palette[regno].blue = blue; + + switch(p_lcd->bpp) { +#ifdef FBCON_HAS_CFB8 + case 8: + red >>= 10; + green >>= 10; + blue >>= 10; + p_lcd_reg->lcd_pallettebase[regno] = (blue&0x1f) | + ((green&0x3f)<<5) | ((red&0x1f)<<11); + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + i->fbcon_cmap16[regno] = + ((red & 0xf800) >> 0) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; +#endif + default: + break; + } + + return 0; +} + + +static int au1100_blank(int blank_mode, struct fb_info_gen *_info) +{ + + switch (blank_mode) { + case VESA_NO_BLANKING: + /* turn on panel */ + //printk("turn on panel\n"); +#ifdef CONFIG_MIPS_PB1100 + p_lcd_reg->lcd_control |= LCD_CONTROL_GO; + au_writew(au_readw(PB1100_G_CONTROL) | p_lcd->mode_backlight, + PB1100_G_CONTROL); +#endif +#ifdef CONFIG_MIPS_HYDROGEN3 + /* Turn controller & power supply on, GPIO213 */ + au_writel(0x20002000, 0xB1700008); + au_writel(0x00040000, 0xB1900108); + au_writel(0x01000100, 0xB1700008); +#endif + au_sync(); + break; + + case VESA_VSYNC_SUSPEND: + case VESA_HSYNC_SUSPEND: + case VESA_POWERDOWN: + /* turn off panel */ + //printk("turn off panel\n"); +#ifdef CONFIG_MIPS_PB1100 + au_writew(au_readw(PB1100_G_CONTROL) & ~p_lcd->mode_backlight, + PB1100_G_CONTROL); + p_lcd_reg->lcd_control &= ~LCD_CONTROL_GO; +#endif + au_sync(); + break; + default: + break; + + } + return 0; +} + +static void au1100_set_disp(const void *unused, struct display *disp, + struct fb_info_gen *info) +{ + disp->screen_base = (char *)fb_info.fb_virt_start; + + switch (disp->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + disp->dispsw = &fbcon_cfb8; + if (fb_info.nohwcursor) + fbcon_cfb8.cursor = au1100_nocursor; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + disp->dispsw = &fbcon_cfb16; + disp->dispsw_data = fb_info.fbcon_cmap16; + if (fb_info.nohwcursor) + fbcon_cfb16.cursor = au1100_nocursor; + break; +#endif + default: + disp->dispsw = &fbcon_dummy; + disp->dispsw_data = NULL; + break; + } +} + +static int +au1100fb_mmap(struct fb_info *_fb, + struct file *file, + struct vm_area_struct *vma) +{ + unsigned int len; + unsigned long start=0, off; + struct au1100fb_info *fb = (struct au1100fb_info *)_fb; + + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { + return -EINVAL; + } + + start = fb_info.fb_phys & PAGE_MASK; + len = PAGE_ALIGN((start & ~PAGE_MASK) + fb_info.fb_size); + + off = vma->vm_pgoff << PAGE_SHIFT; + + if ((vma->vm_end - vma->vm_start + off) > len) { + return -EINVAL; + } + + off += start; + vma->vm_pgoff = off >> PAGE_SHIFT; + + pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; + //pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; + pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6 + + /* This is an IO map - tell maydump to skip this VMA */ + vma->vm_flags |= VM_IO; + + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) { + return -EAGAIN; + } + + fb->mmaped = 1; + return 0; +} + +int au1100_pan_display(const struct fb_var_screeninfo *var, + struct fb_info_gen *info) +{ + return 0; +} + +static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info) +{ + /* nothing to do yet */ + return -EINVAL; +} + +static struct fbgen_hwswitch au1100_switch = { + au1100_detect, + au1100_encode_fix, + au1100_decode_var, + au1100_encode_var, + au1100_get_par, + au1100_set_par, + au1100_getcolreg, + au1100_setcolreg, + au1100_pan_display, + au1100_blank, + au1100_set_disp +}; + + +int au1100_setmode(void) +{ + int words; + + /* FIXME Need to accomodate for swivel mode and 12bpp, <8bpp*/ + switch (p_lcd->mode_control & LCD_CONTROL_SM) + { + case LCD_CONTROL_SM_0: + case LCD_CONTROL_SM_180: + words = (p_lcd->xres * p_lcd->yres * p_lcd->bpp) / 32; + break; + case LCD_CONTROL_SM_90: + case LCD_CONTROL_SM_270: + /* is this correct? */ + words = (p_lcd->xres * p_lcd->bpp) / 8; + break; + default: + printk("mode_control reg not initialized\n"); + return -EINVAL; + } + + /* + * Setup LCD controller + */ + + p_lcd_reg->lcd_control = p_lcd->mode_control; + p_lcd_reg->lcd_intstatus = 0; + p_lcd_reg->lcd_intenable = 0; + p_lcd_reg->lcd_horztiming = p_lcd->mode_horztiming; + p_lcd_reg->lcd_verttiming = p_lcd->mode_verttiming; + p_lcd_reg->lcd_clkcontrol = p_lcd->mode_clkcontrol; + p_lcd_reg->lcd_words = words - 1; + p_lcd_reg->lcd_dmaaddr0 = fb_info.fb_phys; + + /* turn on panel */ +#ifdef CONFIG_MIPS_PB1100 + au_writew(au_readw(PB1100_G_CONTROL) | p_lcd->mode_backlight, + PB1100_G_CONTROL); +#endif +#ifdef CONFIG_MIPS_HYDROGEN3 + /* Turn controller & power supply on, GPIO213 */ + au_writel(0x20002000, 0xB1700008); + au_writel(0x00040000, 0xB1900108); + au_writel(0x01000100, 0xB1700008); +#endif + + p_lcd_reg->lcd_control |= LCD_CONTROL_GO; + + return 0; +} + + +int __init au1100fb_init(void) +{ + uint32 sys_clksrc; + unsigned long page; + + /* + * Get the panel information/display mode and update the registry + */ + p_lcd = &panels[my_lcd_index]; + + switch (p_lcd->mode_control & LCD_CONTROL_SM) + { + case LCD_CONTROL_SM_0: + case LCD_CONTROL_SM_180: + p_lcd->xres = + (p_lcd->mode_horztiming & LCD_HORZTIMING_PPL) + 1; + p_lcd->yres = + (p_lcd->mode_verttiming & LCD_VERTTIMING_LPP) + 1; + break; + case LCD_CONTROL_SM_90: + case LCD_CONTROL_SM_270: + p_lcd->yres = + (p_lcd->mode_horztiming & LCD_HORZTIMING_PPL) + 1; + p_lcd->xres = + (p_lcd->mode_verttiming & LCD_VERTTIMING_LPP) + 1; + break; + } + + /* + * Panel dimensions x bpp must be divisible by 32 + */ + if (((p_lcd->yres * p_lcd->bpp) % 32) != 0) + printk("VERT %% 32\n"); + if (((p_lcd->xres * p_lcd->bpp) % 32) != 0) + printk("HORZ %% 32\n"); + + /* + * Allocate LCD framebuffer from system memory + */ + fb_info.fb_size = (p_lcd->xres * p_lcd->yres * p_lcd->bpp) / 8; + + current_par.var.xres = p_lcd->xres; + current_par.var.xres_virtual = p_lcd->xres; + current_par.var.yres = p_lcd->yres; + current_par.var.yres_virtual = p_lcd->yres; + current_par.var.bits_per_pixel = p_lcd->bpp; + + /* FIX!!! only works for 8/16 bpp */ + current_par.line_length = p_lcd->xres * p_lcd->bpp / 8; /* in bytes */ + fb_info.fb_virt_start = (unsigned long ) + __get_free_pages(GFP_ATOMIC | GFP_DMA, + get_order(fb_info.fb_size + 0x1000)); + if (!fb_info.fb_virt_start) { + printk("Unable to allocate fb memory\n"); + return -ENOMEM; + } + fb_info.fb_phys = virt_to_bus((void *)fb_info.fb_virt_start); + + /* + * Set page reserved so that mmap will work. This is necessary + * since we'll be remapping normal memory. + */ + for (page = fb_info.fb_virt_start; + page < PAGE_ALIGN(fb_info.fb_virt_start + fb_info.fb_size); + page += PAGE_SIZE) { + SetPageReserved(virt_to_page(page)); + } + + memset((void *)fb_info.fb_virt_start, 0, fb_info.fb_size); + + /* set freqctrl now to allow more time to stabilize */ + /* zero-out out LCD bits */ + sys_clksrc = au_readl(SYS_CLKSRC) & ~0x000003e0; + sys_clksrc |= p_lcd->mode_toyclksrc; + au_writel(sys_clksrc, SYS_CLKSRC); + + /* FIXME add check to make sure auxpll is what is expected! */ + au1100_setmode(); + + fb_info.gen.parsize = sizeof(struct au1100fb_par); + fb_info.gen.fbhw = &au1100_switch; + + strcpy(fb_info.gen.info.modename, "Au1100 LCD"); + fb_info.gen.info.changevar = NULL; + fb_info.gen.info.node = -1; + + fb_info.gen.info.fbops = &au1100fb_ops; + fb_info.gen.info.disp = &disp; + fb_info.gen.info.switch_con = &fbgen_switch; + fb_info.gen.info.updatevar = &fbgen_update_var; + fb_info.gen.info.blank = &fbgen_blank; + fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; + + /* This should give a reasonable default video mode */ + fbgen_get_var(&disp.var, -1, &fb_info.gen.info); + fbgen_do_set_var(&disp.var, 1, &fb_info.gen); + fbgen_set_disp(-1, &fb_info.gen); + fbgen_install_cmap(0, &fb_info.gen); + if (register_framebuffer(&fb_info.gen.info) < 0) + return -EINVAL; + printk(KERN_INFO "fb%d: %s frame buffer device\n", + GET_FB_IDX(fb_info.gen.info.node), + fb_info.gen.info.modename); + + return 0; +} + + +void au1100fb_cleanup(struct fb_info *info) +{ + unregister_framebuffer(info); +} + + +void au1100fb_setup(char *options, int *ints) +{ + char* this_opt; + int i; + int num_panels = sizeof(panels)/sizeof(struct known_lcd_panels); + + + if (!options || !*options) + return; + + for(this_opt=strtok(options, ","); this_opt; + this_opt=strtok(NULL, ",")) { + if (!strncmp(this_opt, "panel:", 6)) { +#if defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100) + /* Read Pb1100 Switch S10 ? */ + if (!strncmp(this_opt+6, "s10", 3)) + { + int panel; + panel = *(volatile int *)0xAE000008; /* BCSR SWITCHES */ + panel >>= 8; + panel &= 0x0F; + if (panel >= num_panels) panel = 0; + my_lcd_index = panel; + } + else +#endif + /* Get the panel name, everything else if fixed */ + for (i=0; i<num_panels; i++) { + if (!strncmp(this_opt+6, panels[i].panel_name, + strlen(this_opt))) { + my_lcd_index = i; + break; + } + } + } + else if (!strncmp(this_opt, "nohwcursor", 10)) { + printk("nohwcursor\n"); + fb_info.nohwcursor = 1; + } + } + + printk("au1100fb: Panel %d %s\n", my_lcd_index, + panels[my_lcd_index].panel_name); +} + + + +#ifdef MODULE +MODULE_LICENSE("GPL"); +int init_module(void) +{ + return au1100fb_init(); +} + +void cleanup_module(void) +{ + au1100fb_cleanup(void); +} + +MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>"); +MODULE_DESCRIPTION("Au1100 LCD framebuffer device driver"); +#endif /* MODULE */ diff --git a/drivers/video/au1100fb.h b/drivers/video/au1100fb.h new file mode 100644 index 000000000000..657c560ab73c --- /dev/null +++ b/drivers/video/au1100fb.h @@ -0,0 +1,381 @@ +/* + * BRIEF MODULE DESCRIPTION + * Hardware definitions for the Au1100 LCD controller + * + * Copyright 2002 MontaVista Software + * Copyright 2002 Alchemy Semiconductor + * Author: Alchemy Semiconductor, MontaVista Software + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _AU1100LCD_H +#define _AU1100LCD_H + +/********************************************************************/ +#define uint32 unsigned long +typedef volatile struct +{ + uint32 lcd_control; + uint32 lcd_intstatus; + uint32 lcd_intenable; + uint32 lcd_horztiming; + uint32 lcd_verttiming; + uint32 lcd_clkcontrol; + uint32 lcd_dmaaddr0; + uint32 lcd_dmaaddr1; + uint32 lcd_words; + uint32 lcd_pwmdiv; + uint32 lcd_pwmhi; + uint32 reserved[(0x0400-0x002C)/4]; + uint32 lcd_pallettebase[256]; + +} AU1100_LCD; + +/********************************************************************/ + +#define AU1100_LCD_ADDR 0xB5000000 + +/* + * Register bit definitions + */ + +/* lcd_control */ +#define LCD_CONTROL_SBPPF (7<<18) +#define LCD_CONTROL_SBPPF_655 (0<<18) +#define LCD_CONTROL_SBPPF_565 (1<<18) +#define LCD_CONTROL_SBPPF_556 (2<<18) +#define LCD_CONTROL_SBPPF_1555 (3<<18) +#define LCD_CONTROL_SBPPF_5551 (4<<18) +#define LCD_CONTROL_WP (1<<17) +#define LCD_CONTROL_WD (1<<16) +#define LCD_CONTROL_C (1<<15) +#define LCD_CONTROL_SM (3<<13) +#define LCD_CONTROL_SM_0 (0<<13) +#define LCD_CONTROL_SM_90 (1<<13) +#define LCD_CONTROL_SM_180 (2<<13) +#define LCD_CONTROL_SM_270 (3<<13) +#define LCD_CONTROL_DB (1<<12) +#define LCD_CONTROL_CCO (1<<11) +#define LCD_CONTROL_DP (1<<10) +#define LCD_CONTROL_PO (3<<8) +#define LCD_CONTROL_PO_00 (0<<8) +#define LCD_CONTROL_PO_01 (1<<8) +#define LCD_CONTROL_PO_10 (2<<8) +#define LCD_CONTROL_PO_11 (3<<8) +#define LCD_CONTROL_MPI (1<<7) +#define LCD_CONTROL_PT (1<<6) +#define LCD_CONTROL_PC (1<<5) +#define LCD_CONTROL_BPP (7<<1) +#define LCD_CONTROL_BPP_1 (0<<1) +#define LCD_CONTROL_BPP_2 (1<<1) +#define LCD_CONTROL_BPP_4 (2<<1) +#define LCD_CONTROL_BPP_8 (3<<1) +#define LCD_CONTROL_BPP_12 (4<<1) +#define LCD_CONTROL_BPP_16 (5<<1) +#define LCD_CONTROL_GO (1<<0) + +/* lcd_intstatus, lcd_intenable */ +#define LCD_INT_SD (1<<7) +#define LCD_INT_OF (1<<6) +#define LCD_INT_UF (1<<5) +#define LCD_INT_SA (1<<3) +#define LCD_INT_SS (1<<2) +#define LCD_INT_S1 (1<<1) +#define LCD_INT_S0 (1<<0) + +/* lcd_horztiming */ +#define LCD_HORZTIMING_HN2 (255<<24) +#define LCD_HORZTIMING_HN2_N(N) (((N)-1)<<24) +#define LCD_HORZTIMING_HN1 (255<<16) +#define LCD_HORZTIMING_HN1_N(N) (((N)-1)<<16) +#define LCD_HORZTIMING_HPW (63<<10) +#define LCD_HORZTIMING_HPW_N(N) (((N)-1)<<10) +#define LCD_HORZTIMING_PPL (1023<<0) +#define LCD_HORZTIMING_PPL_N(N) (((N)-1)<<0) + +/* lcd_verttiming */ +#define LCD_VERTTIMING_VN2 (255<<24) +#define LCD_VERTTIMING_VN2_N(N) (((N)-1)<<24) +#define LCD_VERTTIMING_VN1 (255<<16) +#define LCD_VERTTIMING_VN1_N(N) (((N)-1)<<16) +#define LCD_VERTTIMING_VPW (63<<10) +#define LCD_VERTTIMING_VPW_N(N) (((N)-1)<<10) +#define LCD_VERTTIMING_LPP (1023<<0) +#define LCD_VERTTIMING_LPP_N(N) (((N)-1)<<0) + +/* lcd_clkcontrol */ +#define LCD_CLKCONTROL_IB (1<<18) +#define LCD_CLKCONTROL_IC (1<<17) +#define LCD_CLKCONTROL_IH (1<<16) +#define LCD_CLKCONTROL_IV (1<<15) +#define LCD_CLKCONTROL_BF (31<<10) +#define LCD_CLKCONTROL_BF_N(N) (((N)-1)<<10) +#define LCD_CLKCONTROL_PCD (1023<<0) +#define LCD_CLKCONTROL_PCD_N(N) ((N)<<0) + +/* lcd_pwmdiv */ +#define LCD_PWMDIV_EN (1<<12) +#define LCD_PWMDIV_PWMDIV (2047<<0) +#define LCD_PWMDIV_PWMDIV_N(N) (((N)-1)<<0) + +/* lcd_pwmhi */ +#define LCD_PWMHI_PWMHI1 (2047<<12) +#define LCD_PWMHI_PWMHI1_N(N) ((N)<<12) +#define LCD_PWMHI_PWMHI0 (2047<<0) +#define LCD_PWMHI_PWMHI0_N(N) ((N)<<0) + +/* lcd_pallettebase - MONOCHROME */ +#define LCD_PALLETTE_MONO_MI (15<<0) +#define LCD_PALLETTE_MONO_MI_N(N) ((N)<<0) + +/* lcd_pallettebase - COLOR */ +#define LCD_PALLETTE_COLOR_BI (15<<8) +#define LCD_PALLETTE_COLOR_BI_N(N) ((N)<<8) +#define LCD_PALLETTE_COLOR_GI (15<<4) +#define LCD_PALLETTE_COLOR_GI_N(N) ((N)<<4) +#define LCD_PALLETTE_COLOR_RI (15<<0) +#define LCD_PALLETTE_COLOR_RI_N(N) ((N)<<0) + +/* lcd_palletebase - COLOR TFT PALLETIZED */ +#define LCD_PALLETTE_TFT_DC (65535<<0) +#define LCD_PALLETTE_TFT_DC_N(N) ((N)<<0) + +/********************************************************************/ + +struct known_lcd_panels +{ + uint32 xres; + uint32 yres; + uint32 bpp; + unsigned char panel_name[256]; + uint32 mode_control; + uint32 mode_horztiming; + uint32 mode_verttiming; + uint32 mode_clkcontrol; + uint32 mode_pwmdiv; + uint32 mode_pwmhi; + uint32 mode_toyclksrc; + uint32 mode_backlight; + +}; + +#if defined(__BIG_ENDIAN) +#define LCD_DEFAULT_PIX_FORMAT LCD_CONTROL_PO_11 +#else +#define LCD_DEFAULT_PIX_FORMAT LCD_CONTROL_PO_00 +#endif + +/* + * The fb driver assumes that AUX PLL is at 48MHz. That can + * cover up to 800x600 resolution; if you need higher resolution, + * you should modify the driver as needed, not just this structure. + */ +struct known_lcd_panels panels[] = +{ + { /* 0: Pb1100 LCDA: Sharp 320x240 TFT panel */ + 320, /* xres */ + 240, /* yres */ + 16, /* bpp */ + + "Sharp_320x240_16", + /* mode_control */ + ( LCD_CONTROL_SBPPF_565 + /*LCD_CONTROL_WP*/ + /*LCD_CONTROL_WD*/ + | LCD_CONTROL_C + | LCD_CONTROL_SM_0 + /*LCD_CONTROL_DB*/ + /*LCD_CONTROL_CCO*/ + /*LCD_CONTROL_DP*/ + | LCD_DEFAULT_PIX_FORMAT + /*LCD_CONTROL_MPI*/ + | LCD_CONTROL_PT + | LCD_CONTROL_PC + | LCD_CONTROL_BPP_16 ), + + /* mode_horztiming */ + ( LCD_HORZTIMING_HN2_N(8) + | LCD_HORZTIMING_HN1_N(60) + | LCD_HORZTIMING_HPW_N(12) + | LCD_HORZTIMING_PPL_N(320) ), + + /* mode_verttiming */ + ( LCD_VERTTIMING_VN2_N(5) + | LCD_VERTTIMING_VN1_N(17) + | LCD_VERTTIMING_VPW_N(1) + | LCD_VERTTIMING_LPP_N(240) ), + + /* mode_clkcontrol */ + ( 0 + /*LCD_CLKCONTROL_IB*/ + /*LCD_CLKCONTROL_IC*/ + /*LCD_CLKCONTROL_IH*/ + /*LCD_CLKCONTROL_IV*/ + | LCD_CLKCONTROL_PCD_N(1) ), + + /* mode_pwmdiv */ + 0, + + /* mode_pwmhi */ + 0, + + /* mode_toyclksrc */ + ((1<<7) | (1<<6) | (1<<5)), + + /* mode_backlight */ + 6 + }, + + { /* 1: Pb1100 LCDC 640x480 TFT panel */ + 640, /* xres */ + 480, /* yres */ + 16, /* bpp */ + + "Generic_640x480_16", + + /* mode_control */ + 0x004806a | LCD_DEFAULT_PIX_FORMAT, + + /* mode_horztiming */ + 0x3434d67f, + + /* mode_verttiming */ + 0x0e0e39df, + + /* mode_clkcontrol */ + ( 0 + /*LCD_CLKCONTROL_IB*/ + /*LCD_CLKCONTROL_IC*/ + /*LCD_CLKCONTROL_IH*/ + /*LCD_CLKCONTROL_IV*/ + | LCD_CLKCONTROL_PCD_N(1) ), + + /* mode_pwmdiv */ + 0, + + /* mode_pwmhi */ + 0, + + /* mode_toyclksrc */ + ((1<<7) | (1<<6) | (0<<5)), + + /* mode_backlight */ + 7 + }, + + { /* 2: Pb1100 LCDB 640x480 PrimeView TFT panel */ + 640, /* xres */ + 480, /* yres */ + 16, /* bpp */ + + "PrimeView_640x480_16", + + /* mode_control */ + 0x0004886a | LCD_DEFAULT_PIX_FORMAT, + + /* mode_horztiming */ + 0x0e4bfe7f, + + /* mode_verttiming */ + 0x210805df, + + /* mode_clkcontrol */ + 0x00038001, + + /* mode_pwmdiv */ + 0, + + /* mode_pwmhi */ + 0, + + /* mode_toyclksrc */ + ((1<<7) | (1<<6) | (0<<5)), + + /* mode_backlight */ + 7 + }, + + { /* 3: Pb1100 800x600x16bpp NEON CRT */ + 800, /* xres */ + 600, /* yres */ + 16, /* bpp */ + + "NEON_800x600_16", + + /* mode_control */ + 0x0004886A | LCD_DEFAULT_PIX_FORMAT, + + /* mode_horztiming */ + 0x005AFF1F, + + /* mode_verttiming */ + 0x16000E57, + + /* mode_clkcontrol */ + 0x00020000, + + /* mode_pwmdiv */ + 0, + + /* mode_pwmhi */ + 0, + + /* mode_toyclksrc */ + ((1<<7) | (1<<6) | (0<<5)), + + /* mode_backlight */ + 7 + }, + + { /* 4: Pb1100 640x480x16bpp NEON CRT */ + 640, /* xres */ + 480, /* yres */ + 16, /* bpp */ + + "NEON_640x480_16", + + /* mode_control */ + 0x0004886A | LCD_DEFAULT_PIX_FORMAT, + + /* mode_horztiming */ + 0x0052E27F, + + /* mode_verttiming */ + 0x18000DDF, + + /* mode_clkcontrol */ + 0x00020000, + + /* mode_pwmdiv */ + 0, + + /* mode_pwmhi */ + 0, + + /* mode_toyclksrc */ + ((1<<7) | (1<<6) | (0<<5)), + + /* mode_backlight */ + 7 + }, +}; +#endif /* _AU1100LCD_H */ diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig new file mode 100644 index 000000000000..996d543d6609 --- /dev/null +++ b/drivers/video/backlight/Kconfig @@ -0,0 +1,52 @@ +# +# Backlight & LCD drivers configuration +# + +menuconfig BACKLIGHT_LCD_SUPPORT + bool "Backlight & LCD device support" + help + Enable this to be able to choose the drivers for controlling the + backlight and the LCD panel on some platforms, for example on PDAs. + +config BACKLIGHT_CLASS_DEVICE + tristate "Lowlevel Backlight controls" + depends on BACKLIGHT_LCD_SUPPORT + default m + help + This framework adds support for low-level control of the LCD + backlight. This includes support for brightness and power. + + To have support for your specific LCD panel you will have to + select the proper drivers which depend on this option. + +config BACKLIGHT_DEVICE + bool + depends on BACKLIGHT_CLASS_DEVICE + default y + +config LCD_CLASS_DEVICE + tristate "Lowlevel LCD controls" + depends on BACKLIGHT_LCD_SUPPORT + default m + help + This framework adds support for low-level control of LCD. + Some framebuffer devices connect to platform-specific LCD modules + in order to have a platform-specific way to control the flat panel + (contrast and applying power to the LCD (not to the backlight!)). + + To have support for your specific LCD panel you will have to + select the proper drivers which depend on this option. + +config LCD_DEVICE + bool + depends on LCD_CLASS_DEVICE + default y + +config BACKLIGHT_CORGI + tristate "Sharp Corgi Backlight Driver (SL-C7xx Series)" + depends on BACKLIGHT_DEVICE && PXA_SHARPSL + default y + help + If you have a Sharp Zaurus SL-C7xx, say y to enable the + backlight driver. + diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile new file mode 100644 index 000000000000..9aae884475be --- /dev/null +++ b/drivers/video/backlight/Makefile @@ -0,0 +1,5 @@ +# Backlight & LCD drivers + +obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o +obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o +obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c new file mode 100644 index 000000000000..acc81cb01d56 --- /dev/null +++ b/drivers/video/backlight/backlight.c @@ -0,0 +1,264 @@ +/* + * Backlight Lowlevel Control Abstraction + * + * Copyright (C) 2003,2004 Hewlett-Packard Company + * + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/backlight.h> +#include <linux/notifier.h> +#include <linux/ctype.h> +#include <linux/err.h> +#include <linux/fb.h> +#include <asm/bug.h> + +static ssize_t backlight_show_power(struct class_device *cdev, char *buf) +{ + int rc; + struct backlight_device *bd = to_backlight_device(cdev); + + down(&bd->sem); + if (likely(bd->props && bd->props->get_power)) + rc = sprintf(buf, "%d\n", bd->props->get_power(bd)); + else + rc = -ENXIO; + up(&bd->sem); + + return rc; +} + +static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count) +{ + int rc, power; + char *endp; + struct backlight_device *bd = to_backlight_device(cdev); + + power = simple_strtoul(buf, &endp, 0); + if (*endp && !isspace(*endp)) + return -EINVAL; + + down(&bd->sem); + if (likely(bd->props && bd->props->set_power)) { + pr_debug("backlight: set power to %d\n", power); + bd->props->set_power(bd, power); + rc = count; + } else + rc = -ENXIO; + up(&bd->sem); + + return rc; +} + +static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf) +{ + int rc; + struct backlight_device *bd = to_backlight_device(cdev); + + down(&bd->sem); + if (likely(bd->props && bd->props->get_brightness)) + rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd)); + else + rc = -ENXIO; + up(&bd->sem); + + return rc; +} + +static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count) +{ + int rc, brightness; + char *endp; + struct backlight_device *bd = to_backlight_device(cdev); + + brightness = simple_strtoul(buf, &endp, 0); + if (*endp && !isspace(*endp)) + return -EINVAL; + + down(&bd->sem); + if (likely(bd->props && bd->props->set_brightness)) { + pr_debug("backlight: set brightness to %d\n", brightness); + bd->props->set_brightness(bd, brightness); + rc = count; + } else + rc = -ENXIO; + up(&bd->sem); + + return rc; +} + +static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf) +{ + int rc; + struct backlight_device *bd = to_backlight_device(cdev); + + down(&bd->sem); + if (likely(bd->props)) + rc = sprintf(buf, "%d\n", bd->props->max_brightness); + else + rc = -ENXIO; + up(&bd->sem); + + return rc; +} + +static void backlight_class_release(struct class_device *dev) +{ + struct backlight_device *bd = to_backlight_device(dev); + kfree(bd); +} + +static struct class backlight_class = { + .name = "backlight", + .release = backlight_class_release, +}; + +#define DECLARE_ATTR(_name,_mode,_show,_store) \ +{ \ + .attr = { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ + .show = _show, \ + .store = _store, \ +} + +static struct class_device_attribute bl_class_device_attributes[] = { + DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power), + DECLARE_ATTR(brightness, 0644, backlight_show_brightness, backlight_store_brightness), + DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL), +}; + +/* This callback gets called when something important happens inside a + * framebuffer driver. We're looking if that important event is blanking, + * and if it is, we're switching backlight power as well ... + */ +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct backlight_device *bd; + struct fb_event *evdata =(struct fb_event *)data; + + /* If we aren't interested in this event, skip it immediately ... */ + if (event != FB_EVENT_BLANK) + return 0; + + bd = container_of(self, struct backlight_device, fb_notif); + down(&bd->sem); + if (bd->props) + if (!bd->props->check_fb || bd->props->check_fb(evdata->info)) + bd->props->set_power(bd, *(int *)evdata->data); + up(&bd->sem); + return 0; +} + +/** + * backlight_device_register - create and register a new object of + * backlight_device class. + * @name: the name of the new object(must be the same as the name of the + * respective framebuffer device). + * @devdata: an optional pointer to be stored in the class_device. The + * methods may retrieve it by using class_get_devdata(&bd->class_dev). + * @bp: the backlight properties structure. + * + * Creates and registers new backlight class_device. Returns either an + * ERR_PTR() or a pointer to the newly allocated device. + */ +struct backlight_device *backlight_device_register(const char *name, void *devdata, + struct backlight_properties *bp) +{ + int i, rc; + struct backlight_device *new_bd; + + pr_debug("backlight_device_alloc: name=%s\n", name); + + new_bd = kmalloc(sizeof(struct backlight_device), GFP_KERNEL); + if (unlikely(!new_bd)) + return ERR_PTR(ENOMEM); + + init_MUTEX(&new_bd->sem); + new_bd->props = bp; + memset(&new_bd->class_dev, 0, sizeof(new_bd->class_dev)); + new_bd->class_dev.class = &backlight_class; + strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN); + class_set_devdata(&new_bd->class_dev, devdata); + + rc = class_device_register(&new_bd->class_dev); + if (unlikely(rc)) { +error: kfree(new_bd); + return ERR_PTR(rc); + } + + memset(&new_bd->fb_notif, 0, sizeof(new_bd->fb_notif)); + new_bd->fb_notif.notifier_call = fb_notifier_callback; + + rc = fb_register_client(&new_bd->fb_notif); + if (unlikely(rc)) + goto error; + + for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) { + rc = class_device_create_file(&new_bd->class_dev, + &bl_class_device_attributes[i]); + if (unlikely(rc)) { + while (--i >= 0) + class_device_remove_file(&new_bd->class_dev, + &bl_class_device_attributes[i]); + class_device_unregister(&new_bd->class_dev); + /* No need to kfree(new_bd) since release() method was called */ + return ERR_PTR(rc); + } + } + + return new_bd; +} +EXPORT_SYMBOL(backlight_device_register); + +/** + * backlight_device_unregister - unregisters a backlight device object. + * @bd: the backlight device object to be unregistered and freed. + * + * Unregisters a previously registered via backlight_device_register object. + */ +void backlight_device_unregister(struct backlight_device *bd) +{ + int i; + + if (!bd) + return; + + pr_debug("backlight_device_unregister: name=%s\n", bd->class_dev.class_id); + + for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) + class_device_remove_file(&bd->class_dev, + &bl_class_device_attributes[i]); + + down(&bd->sem); + bd->props = NULL; + up(&bd->sem); + + fb_unregister_client(&bd->fb_notif); + + class_device_unregister(&bd->class_dev); +} +EXPORT_SYMBOL(backlight_device_unregister); + +static void __exit backlight_class_exit(void) +{ + class_unregister(&backlight_class); +} + +static int __init backlight_class_init(void) +{ + return class_register(&backlight_class); +} + +/* + * if this is compiled into the kernel, we need to ensure that the + * class is registered before users of the class try to register lcd's + */ +postcore_initcall(backlight_class_init); +module_exit(backlight_class_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>"); +MODULE_DESCRIPTION("Backlight Lowlevel Control Abstraction"); diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c new file mode 100644 index 000000000000..3c026b036c86 --- /dev/null +++ b/drivers/video/backlight/corgi_bl.c @@ -0,0 +1,198 @@ +/* + * Backlight Driver for Sharp Corgi + * + * Copyright (c) 2004-2005 Richard Purdie + * + * Based on Sharp's 2.4 Backlight Driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/spinlock.h> +#include <linux/fb.h> +#include <linux/backlight.h> + +#include <asm/arch-pxa/corgi.h> +#include <asm/hardware/scoop.h> + +#define CORGI_MAX_INTENSITY 0x3e +#define CORGI_DEFAULT_INTENSITY 0x1f +#define CORGI_LIMIT_MASK 0x0b + +static int corgibl_powermode = FB_BLANK_UNBLANK; +static int current_intensity = 0; +static int corgibl_limit = 0; +static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED; + +static void corgibl_send_intensity(int intensity) +{ + unsigned long flags; + void (*corgi_kick_batt)(void); + + if (corgibl_powermode != FB_BLANK_UNBLANK) { + intensity = 0; + } else { + if (corgibl_limit) + intensity &= CORGI_LIMIT_MASK; + } + + /* Skip 0x20 as it will blank the display */ + if (intensity >= 0x20) + intensity++; + + spin_lock_irqsave(&bl_lock, flags); + /* Bits 0-4 are accessed via the SSP interface */ + corgi_ssp_blduty_set(intensity & 0x1f); + /* Bit 5 is via SCOOP */ + if (intensity & 0x0020) + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT); + else + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT); + spin_unlock_irqrestore(&bl_lock, flags); +} + +static void corgibl_blank(int blank) +{ + switch(blank) { + + case FB_BLANK_NORMAL: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + if (corgibl_powermode == FB_BLANK_UNBLANK) { + corgibl_send_intensity(0); + corgibl_powermode = blank; + } + break; + case FB_BLANK_UNBLANK: + if (corgibl_powermode != FB_BLANK_UNBLANK) { + corgibl_powermode = blank; + corgibl_send_intensity(current_intensity); + } + break; + } +} + +#ifdef CONFIG_PM +static int corgibl_suspend(struct device *dev, u32 state, u32 level) +{ + if (level == SUSPEND_POWER_DOWN) + corgibl_blank(FB_BLANK_POWERDOWN); + return 0; +} + +static int corgibl_resume(struct device *dev, u32 level) +{ + if (level == RESUME_POWER_ON) + corgibl_blank(FB_BLANK_UNBLANK); + return 0; +} +#else +#define corgibl_suspend NULL +#define corgibl_resume NULL +#endif + + +static int corgibl_set_power(struct backlight_device *bd, int state) +{ + corgibl_blank(state); + return 0; +} + +static int corgibl_get_power(struct backlight_device *bd) +{ + return corgibl_powermode; +} + +static int corgibl_set_intensity(struct backlight_device *bd, int intensity) +{ + if (intensity > CORGI_MAX_INTENSITY) + intensity = CORGI_MAX_INTENSITY; + corgibl_send_intensity(intensity); + current_intensity=intensity; + return 0; +} + +static int corgibl_get_intensity(struct backlight_device *bd) +{ + return current_intensity; +} + +/* + * Called when the battery is low to limit the backlight intensity. + * If limit==0 clear any limit, otherwise limit the intensity + */ +void corgibl_limit_intensity(int limit) +{ + corgibl_limit = (limit ? 1 : 0); + corgibl_send_intensity(current_intensity); +} +EXPORT_SYMBOL(corgibl_limit_intensity); + + +static struct backlight_properties corgibl_data = { + .owner = THIS_MODULE, + .get_power = corgibl_get_power, + .set_power = corgibl_set_power, + .max_brightness = CORGI_MAX_INTENSITY, + .get_brightness = corgibl_get_intensity, + .set_brightness = corgibl_set_intensity, +}; + +static struct backlight_device *corgi_backlight_device; + +static int __init corgibl_probe(struct device *dev) +{ + corgi_backlight_device = backlight_device_register ("corgi-bl", + NULL, &corgibl_data); + if (IS_ERR (corgi_backlight_device)) + return PTR_ERR (corgi_backlight_device); + + corgibl_set_intensity(NULL, CORGI_DEFAULT_INTENSITY); + + printk("Corgi Backlight Driver Initialized.\n"); + return 0; +} + +static int corgibl_remove(struct device *dev) +{ + backlight_device_unregister(corgi_backlight_device); + + corgibl_set_intensity(NULL, 0); + + printk("Corgi Backlight Driver Unloaded\n"); + return 0; +} + +static struct device_driver corgibl_driver = { + .name = "corgi-bl", + .bus = &platform_bus_type, + .probe = corgibl_probe, + .remove = corgibl_remove, + .suspend = corgibl_suspend, + .resume = corgibl_resume, +}; + +static int __init corgibl_init(void) +{ + return driver_register(&corgibl_driver); +} + +static void __exit corgibl_exit(void) +{ + driver_unregister(&corgibl_driver); +} + +module_init(corgibl_init); +module_exit(corgibl_exit); + +MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); +MODULE_DESCRIPTION("Corgi Backlight Driver"); +MODULE_LICENSE("GPLv2"); diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c new file mode 100644 index 000000000000..470e6f0ee4dd --- /dev/null +++ b/drivers/video/backlight/lcd.c @@ -0,0 +1,263 @@ +/* + * LCD Lowlevel Control Abstraction + * + * Copyright (C) 2003,2004 Hewlett-Packard Company + * + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/lcd.h> +#include <linux/notifier.h> +#include <linux/ctype.h> +#include <linux/err.h> +#include <linux/fb.h> +#include <asm/bug.h> + +static ssize_t lcd_show_power(struct class_device *cdev, char *buf) +{ + int rc; + struct lcd_device *ld = to_lcd_device(cdev); + + down(&ld->sem); + if (likely(ld->props && ld->props->get_power)) + rc = sprintf(buf, "%d\n", ld->props->get_power(ld)); + else + rc = -ENXIO; + up(&ld->sem); + + return rc; +} + +static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_t count) +{ + int rc, power; + char *endp; + struct lcd_device *ld = to_lcd_device(cdev); + + power = simple_strtoul(buf, &endp, 0); + if (*endp && !isspace(*endp)) + return -EINVAL; + + down(&ld->sem); + if (likely(ld->props && ld->props->set_power)) { + pr_debug("lcd: set power to %d\n", power); + ld->props->set_power(ld, power); + rc = count; + } else + rc = -ENXIO; + up(&ld->sem); + + return rc; +} + +static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf) +{ + int rc; + struct lcd_device *ld = to_lcd_device(cdev); + + down(&ld->sem); + if (likely(ld->props && ld->props->get_contrast)) + rc = sprintf(buf, "%d\n", ld->props->get_contrast(ld)); + else + rc = -ENXIO; + up(&ld->sem); + + return rc; +} + +static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, size_t count) +{ + int rc, contrast; + char *endp; + struct lcd_device *ld = to_lcd_device(cdev); + + contrast = simple_strtoul(buf, &endp, 0); + if (*endp && !isspace(*endp)) + return -EINVAL; + + down(&ld->sem); + if (likely(ld->props && ld->props->set_contrast)) { + pr_debug("lcd: set contrast to %d\n", contrast); + ld->props->set_contrast(ld, contrast); + rc = count; + } else + rc = -ENXIO; + up(&ld->sem); + + return rc; +} + +static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf) +{ + int rc; + struct lcd_device *ld = to_lcd_device(cdev); + + down(&ld->sem); + if (likely(ld->props)) + rc = sprintf(buf, "%d\n", ld->props->max_contrast); + else + rc = -ENXIO; + up(&ld->sem); + + return rc; +} + +static void lcd_class_release(struct class_device *dev) +{ + struct lcd_device *ld = to_lcd_device(dev); + kfree(ld); +} + +static struct class lcd_class = { + .name = "lcd", + .release = lcd_class_release, +}; + +#define DECLARE_ATTR(_name,_mode,_show,_store) \ +{ \ + .attr = { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ + .show = _show, \ + .store = _store, \ +} + +static struct class_device_attribute lcd_class_device_attributes[] = { + DECLARE_ATTR(power, 0644, lcd_show_power, lcd_store_power), + DECLARE_ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast), + DECLARE_ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL), +}; + +/* This callback gets called when something important happens inside a + * framebuffer driver. We're looking if that important event is blanking, + * and if it is, we're switching lcd power as well ... + */ +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct lcd_device *ld; + struct fb_event *evdata =(struct fb_event *)data; + + /* If we aren't interested in this event, skip it immediately ... */ + if (event != FB_EVENT_BLANK) + return 0; + + ld = container_of(self, struct lcd_device, fb_notif); + down(&ld->sem); + if (ld->props) + if (!ld->props->check_fb || ld->props->check_fb(evdata->info)) + ld->props->set_power(ld, *(int *)evdata->data); + up(&ld->sem); + return 0; +} + +/** + * lcd_device_register - register a new object of lcd_device class. + * @name: the name of the new object(must be the same as the name of the + * respective framebuffer device). + * @devdata: an optional pointer to be stored in the class_device. The + * methods may retrieve it by using class_get_devdata(ld->class_dev). + * @lp: the lcd properties structure. + * + * Creates and registers a new lcd class_device. Returns either an ERR_PTR() + * or a pointer to the newly allocated device. + */ +struct lcd_device *lcd_device_register(const char *name, void *devdata, + struct lcd_properties *lp) +{ + int i, rc; + struct lcd_device *new_ld; + + pr_debug("lcd_device_register: name=%s\n", name); + + new_ld = kmalloc(sizeof(struct lcd_device), GFP_KERNEL); + if (unlikely(!new_ld)) + return ERR_PTR(ENOMEM); + + init_MUTEX(&new_ld->sem); + new_ld->props = lp; + memset(&new_ld->class_dev, 0, sizeof(new_ld->class_dev)); + new_ld->class_dev.class = &lcd_class; + strlcpy(new_ld->class_dev.class_id, name, KOBJ_NAME_LEN); + class_set_devdata(&new_ld->class_dev, devdata); + + rc = class_device_register(&new_ld->class_dev); + if (unlikely(rc)) { +error: kfree(new_ld); + return ERR_PTR(rc); + } + + memset(&new_ld->fb_notif, 0, sizeof(new_ld->fb_notif)); + new_ld->fb_notif.notifier_call = fb_notifier_callback; + + rc = fb_register_client(&new_ld->fb_notif); + if (unlikely(rc)) + goto error; + + for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++) { + rc = class_device_create_file(&new_ld->class_dev, + &lcd_class_device_attributes[i]); + if (unlikely(rc)) { + while (--i >= 0) + class_device_remove_file(&new_ld->class_dev, + &lcd_class_device_attributes[i]); + class_device_unregister(&new_ld->class_dev); + /* No need to kfree(new_ld) since release() method was called */ + return ERR_PTR(rc); + } + } + + return new_ld; +} +EXPORT_SYMBOL(lcd_device_register); + +/** + * lcd_device_unregister - unregisters a object of lcd_device class. + * @ld: the lcd device object to be unregistered and freed. + * + * Unregisters a previously registered via lcd_device_register object. + */ +void lcd_device_unregister(struct lcd_device *ld) +{ + int i; + + if (!ld) + return; + + pr_debug("lcd_device_unregister: name=%s\n", ld->class_dev.class_id); + + for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++) + class_device_remove_file(&ld->class_dev, + &lcd_class_device_attributes[i]); + + down(&ld->sem); + ld->props = NULL; + up(&ld->sem); + + fb_unregister_client(&ld->fb_notif); + + class_device_unregister(&ld->class_dev); +} +EXPORT_SYMBOL(lcd_device_unregister); + +static void __exit lcd_class_exit(void) +{ + class_unregister(&lcd_class); +} + +static int __init lcd_class_init(void) +{ + return class_register(&lcd_class); +} + +/* + * if this is compiled into the kernel, we need to ensure that the + * class is registered before users of the class try to register lcd's + */ +postcore_initcall(lcd_class_init); +module_exit(lcd_class_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>"); +MODULE_DESCRIPTION("LCD Lowlevel Control Abstraction"); diff --git a/drivers/video/bt431.h b/drivers/video/bt431.h new file mode 100644 index 000000000000..c826f2787bad --- /dev/null +++ b/drivers/video/bt431.h @@ -0,0 +1,236 @@ +/* + * linux/drivers/video/bt431.h + * + * Copyright 2003 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> + * + * 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/types.h> +#include <asm/system.h> + +/* + * Bt431 cursor generator registers, 32-bit aligned. + * Two twin Bt431 are used on the DECstation's PMAG-AA. + */ +struct bt431_regs { + volatile u16 addr_lo; + u16 pad0; + volatile u16 addr_hi; + u16 pad1; + volatile u16 addr_cmap; + u16 pad2; + volatile u16 addr_reg; + u16 pad3; +}; + +static inline u16 bt431_set_value(u8 val) +{ + return ((val << 8) | (val & 0xff)) & 0xffff; +} + +static inline u8 bt431_get_value(u16 val) +{ + return val & 0xff; +} + +/* + * Additional registers addressed indirectly. + */ +#define BT431_REG_CMD 0x0000 +#define BT431_REG_CXLO 0x0001 +#define BT431_REG_CXHI 0x0002 +#define BT431_REG_CYLO 0x0003 +#define BT431_REG_CYHI 0x0004 +#define BT431_REG_WXLO 0x0005 +#define BT431_REG_WXHI 0x0006 +#define BT431_REG_WYLO 0x0007 +#define BT431_REG_WYHI 0x0008 +#define BT431_REG_WWLO 0x0009 +#define BT431_REG_WWHI 0x000a +#define BT431_REG_WHLO 0x000b +#define BT431_REG_WHHI 0x000c + +#define BT431_REG_CRAM_BASE 0x0000 +#define BT431_REG_CRAM_END 0x01ff + +/* + * Command register. + */ +#define BT431_CMD_CURS_ENABLE 0x40 +#define BT431_CMD_XHAIR_ENABLE 0x20 +#define BT431_CMD_OR_CURSORS 0x10 +#define BT431_CMD_AND_CURSORS 0x00 +#define BT431_CMD_1_1_MUX 0x00 +#define BT431_CMD_4_1_MUX 0x04 +#define BT431_CMD_5_1_MUX 0x08 +#define BT431_CMD_xxx_MUX 0x0c +#define BT431_CMD_THICK_1 0x00 +#define BT431_CMD_THICK_3 0x01 +#define BT431_CMD_THICK_5 0x02 +#define BT431_CMD_THICK_7 0x03 + +static inline void bt431_select_reg(struct bt431_regs *regs, int ir) +{ + /* + * The compiler splits the write in two bytes without these + * helper variables. + */ + volatile u16 *lo = &(regs->addr_lo); + volatile u16 *hi = &(regs->addr_hi); + + mb(); + *lo = bt431_set_value(ir & 0xff); + wmb(); + *hi = bt431_set_value((ir >> 8) & 0xff); +} + +/* Autoincrement read/write. */ +static inline u8 bt431_read_reg_inc(struct bt431_regs *regs) +{ + /* + * The compiler splits the write in two bytes without the + * helper variable. + */ + volatile u16 *r = &(regs->addr_reg); + + mb(); + return bt431_get_value(*r); +} + +static inline void bt431_write_reg_inc(struct bt431_regs *regs, u8 value) +{ + /* + * The compiler splits the write in two bytes without the + * helper variable. + */ + volatile u16 *r = &(regs->addr_reg); + + mb(); + *r = bt431_set_value(value); +} + +static inline u8 bt431_read_reg(struct bt431_regs *regs, int ir) +{ + bt431_select_reg(regs, ir); + return bt431_read_reg_inc(regs); +} + +static inline void bt431_write_reg(struct bt431_regs *regs, int ir, u8 value) +{ + bt431_select_reg(regs, ir); + bt431_write_reg_inc(regs, value); +} + +/* Autoincremented read/write for the cursor map. */ +static inline u16 bt431_read_cmap_inc(struct bt431_regs *regs) +{ + /* + * The compiler splits the write in two bytes without the + * helper variable. + */ + volatile u16 *r = &(regs->addr_cmap); + + mb(); + return *r; +} + +static inline void bt431_write_cmap_inc(struct bt431_regs *regs, u16 value) +{ + /* + * The compiler splits the write in two bytes without the + * helper variable. + */ + volatile u16 *r = &(regs->addr_cmap); + + mb(); + *r = value; +} + +static inline u16 bt431_read_cmap(struct bt431_regs *regs, int cr) +{ + bt431_select_reg(regs, cr); + return bt431_read_cmap_inc(regs); +} + +static inline void bt431_write_cmap(struct bt431_regs *regs, int cr, u16 value) +{ + bt431_select_reg(regs, cr); + bt431_write_cmap_inc(regs, value); +} + +static inline void bt431_enable_cursor(struct bt431_regs *regs) +{ + bt431_write_reg(regs, BT431_REG_CMD, + BT431_CMD_CURS_ENABLE | BT431_CMD_OR_CURSORS + | BT431_CMD_4_1_MUX | BT431_CMD_THICK_1); +} + +static inline void bt431_erase_cursor(struct bt431_regs *regs) +{ + bt431_write_reg(regs, BT431_REG_CMD, BT431_CMD_4_1_MUX); +} + +static inline void bt431_position_cursor(struct bt431_regs *regs, u16 x, u16 y) +{ + /* + * Magic from the MACH sources. + * + * Cx = x + D + H - P + * P = 37 if 1:1, 52 if 4:1, 57 if 5:1 + * D = pixel skew between outdata and external data + * H = pixels between HSYNCH falling and active video + * + * Cy = y + V - 32 + * V = scanlines between HSYNCH falling, two or more + * clocks after VSYNCH falling, and active video + */ + x += 412 - 52; + y += 68 - 32; + + /* Use autoincrement. */ + bt431_select_reg(regs, BT431_REG_CXLO); + bt431_write_reg_inc(regs, x & 0xff); /* BT431_REG_CXLO */ + bt431_write_reg_inc(regs, (x >> 8) & 0x0f); /* BT431_REG_CXHI */ + bt431_write_reg_inc(regs, y & 0xff); /* BT431_REG_CYLO */ + bt431_write_reg_inc(regs, (y >> 8) & 0x0f); /* BT431_REG_CYHI */ +} + +static inline void bt431_set_font(struct bt431_regs *regs, u8 fgc, + u16 width, u16 height) +{ + int i; + u16 fgp = fgc ? 0xffff : 0x0000; + u16 bgp = fgc ? 0x0000 : 0xffff; + + bt431_select_reg(regs, BT431_REG_CRAM_BASE); + for (i = BT431_REG_CRAM_BASE; i <= BT431_REG_CRAM_END; i++) { + u16 value; + + if (height << 6 <= i << 3) + value = bgp; + else if (width <= i % 8 << 3) + value = bgp; + else if (((width >> 3) & 0xffff) > i % 8) + value = fgp; + else + value = fgp & ~(bgp << (width % 8 << 1)); + + bt431_write_cmap_inc(regs, value); + } +} + +static inline void bt431_init_cursor(struct bt431_regs *regs) +{ + /* no crosshair window */ + bt431_select_reg(regs, BT431_REG_WXLO); + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WXLO */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WXHI */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WYLO */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WYHI */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WWLO */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WWHI */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WHLO */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WHHI */ +} diff --git a/drivers/video/bt455.h b/drivers/video/bt455.h new file mode 100644 index 000000000000..b7591fea7add --- /dev/null +++ b/drivers/video/bt455.h @@ -0,0 +1,95 @@ +/* + * linux/drivers/video/bt455.h + * + * Copyright 2003 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> + * + * 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/types.h> +#include <asm/system.h> + +/* + * Bt455 byte-wide registers, 32-bit aligned. + */ +struct bt455_regs { + volatile u8 addr_cmap; + u8 pad0[3]; + volatile u8 addr_cmap_data; + u8 pad1[3]; + volatile u8 addr_clr; + u8 pad2[3]; + volatile u8 addr_ovly; + u8 pad3[3]; +}; + +static inline void bt455_select_reg(struct bt455_regs *regs, int ir) +{ + mb(); + regs->addr_cmap = ir & 0x0f; +} + +/* + * Read/write to a Bt455 color map register. + */ +static inline void bt455_read_cmap_entry(struct bt455_regs *regs, int cr, + u8* red, u8* green, u8* blue) +{ + bt455_select_reg(regs, cr); + mb(); + *red = regs->addr_cmap_data & 0x0f; + rmb(); + *green = regs->addr_cmap_data & 0x0f; + rmb(); + *blue = regs->addr_cmap_data & 0x0f; +} + +static inline void bt455_write_cmap_entry(struct bt455_regs *regs, int cr, + u8 red, u8 green, u8 blue) +{ + bt455_select_reg(regs, cr); + wmb(); + regs->addr_cmap_data = red & 0x0f; + wmb(); + regs->addr_cmap_data = green & 0x0f; + wmb(); + regs->addr_cmap_data = blue & 0x0f; +} + +static inline void bt455_write_ovly_entry(struct bt455_regs *regs, int cr, + u8 red, u8 green, u8 blue) +{ + bt455_select_reg(regs, cr); + wmb(); + regs->addr_ovly = red & 0x0f; + wmb(); + regs->addr_ovly = green & 0x0f; + wmb(); + regs->addr_ovly = blue & 0x0f; +} + +static inline void bt455_set_cursor(struct bt455_regs *regs) +{ + mb(); + regs->addr_ovly = 0x0f; + wmb(); + regs->addr_ovly = 0x0f; + wmb(); + regs->addr_ovly = 0x0f; +} + +static inline void bt455_erase_cursor(struct bt455_regs *regs) +{ + /* bt455_write_cmap_entry(regs, 8, 0x00, 0x00, 0x00); */ + /* bt455_write_cmap_entry(regs, 9, 0x00, 0x00, 0x00); */ + bt455_write_ovly_entry(regs, 8, 0x03, 0x03, 0x03); + bt455_write_ovly_entry(regs, 9, 0x07, 0x07, 0x07); + + wmb(); + regs->addr_ovly = 0x09; + wmb(); + regs->addr_ovly = 0x09; + wmb(); + regs->addr_ovly = 0x09; +} diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c new file mode 100644 index 000000000000..3d20b2d47d46 --- /dev/null +++ b/drivers/video/bw2.c @@ -0,0 +1,428 @@ +/* bw2.c: BWTWO frame buffer driver + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * + * Driver layout based loosely on tgafb.c, see that file for credits. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <linux/mm.h> + +#include <asm/io.h> +#include <asm/sbus.h> +#include <asm/oplib.h> +#include <asm/fbio.h> + +#ifdef CONFIG_SPARC32 +#include <asm/sun4paddr.h> +#endif + +#include "sbuslib.h" + +/* + * Local functions. + */ + +static int bw2_blank(int, struct fb_info *); + +static int bw2_mmap(struct fb_info *, struct file *, struct vm_area_struct *); +static int bw2_ioctl(struct inode *, struct file *, unsigned int, + unsigned long, struct fb_info *); + +/* + * Frame buffer operations + */ + +static struct fb_ops bw2_ops = { + .owner = THIS_MODULE, + .fb_blank = bw2_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = bw2_mmap, + .fb_ioctl = bw2_ioctl, + .fb_cursor = soft_cursor, +}; + +/* OBio addresses for the bwtwo registers */ +#define BWTWO_REGISTER_OFFSET 0x400000 + +struct bt_regs { + volatile u32 addr; + volatile u32 color_map; + volatile u32 control; + volatile u32 cursor; +}; + +struct bw2_regs { + struct bt_regs cmap; + volatile u8 control; + volatile u8 status; + volatile u8 cursor_start; + volatile u8 cursor_end; + volatile u8 h_blank_start; + volatile u8 h_blank_end; + volatile u8 h_sync_start; + volatile u8 h_sync_end; + volatile u8 comp_sync_end; + volatile u8 v_blank_start_high; + volatile u8 v_blank_start_low; + volatile u8 v_blank_end; + volatile u8 v_sync_start; + volatile u8 v_sync_end; + volatile u8 xfer_holdoff_start; + volatile u8 xfer_holdoff_end; +}; + +/* Status Register Constants */ +#define BWTWO_SR_RES_MASK 0x70 +#define BWTWO_SR_1600_1280 0x50 +#define BWTWO_SR_1152_900_76_A 0x40 +#define BWTWO_SR_1152_900_76_B 0x60 +#define BWTWO_SR_ID_MASK 0x0f +#define BWTWO_SR_ID_MONO 0x02 +#define BWTWO_SR_ID_MONO_ECL 0x03 +#define BWTWO_SR_ID_MSYNC 0x04 +#define BWTWO_SR_ID_NOCONN 0x0a + +/* Control Register Constants */ +#define BWTWO_CTL_ENABLE_INTS 0x80 +#define BWTWO_CTL_ENABLE_VIDEO 0x40 +#define BWTWO_CTL_ENABLE_TIMING 0x20 +#define BWTWO_CTL_ENABLE_CURCMP 0x10 +#define BWTWO_CTL_XTAL_MASK 0x0C +#define BWTWO_CTL_DIVISOR_MASK 0x03 + +/* Status Register Constants */ +#define BWTWO_STAT_PENDING_INT 0x80 +#define BWTWO_STAT_MSENSE_MASK 0x70 +#define BWTWO_STAT_ID_MASK 0x0f + +struct bw2_par { + spinlock_t lock; + struct bw2_regs __iomem *regs; + + u32 flags; +#define BW2_FLAG_BLANKED 0x00000001 + + unsigned long physbase; + unsigned long fbsize; + + struct sbus_dev *sdev; + struct list_head list; +}; + +/** + * bw2_blank - Optional function. Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + */ +static int +bw2_blank(int blank, struct fb_info *info) +{ + struct bw2_par *par = (struct bw2_par *) info->par; + struct bw2_regs __iomem *regs = par->regs; + unsigned long flags; + u8 val; + + spin_lock_irqsave(&par->lock, flags); + + switch (blank) { + case FB_BLANK_UNBLANK: /* Unblanking */ + val = sbus_readb(®s->control); + val |= BWTWO_CTL_ENABLE_VIDEO; + sbus_writeb(val, ®s->control); + par->flags &= ~BW2_FLAG_BLANKED; + break; + + case FB_BLANK_NORMAL: /* Normal blanking */ + case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ + case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ + case FB_BLANK_POWERDOWN: /* Poweroff */ + val = sbus_readb(®s->control); + val &= ~BWTWO_CTL_ENABLE_VIDEO; + sbus_writeb(val, ®s->control); + par->flags |= BW2_FLAG_BLANKED; + break; + } + + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +static struct sbus_mmap_map bw2_mmap_map[] = { + { + .size = SBUS_MMAP_FBSIZE(1) + }, + { .size = 0 } +}; + +static int bw2_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) +{ + struct bw2_par *par = (struct bw2_par *)info->par; + + return sbusfb_mmap_helper(bw2_mmap_map, + par->physbase, par->fbsize, + (par->sdev ? + par->sdev->reg_addrs[0].which_io : + 0), + vma); +} + +static int bw2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *info) +{ + struct bw2_par *par = (struct bw2_par *) info->par; + + return sbusfb_ioctl_helper(cmd, arg, info, + FBTYPE_SUN2BW, 1, par->fbsize); +} + +/* + * Initialisation + */ + +static void +bw2_init_fix(struct fb_info *info, int linebytes) +{ + strlcpy(info->fix.id, "bwtwo", sizeof(info->fix.id)); + + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_MONO01; + + info->fix.line_length = linebytes; + + info->fix.accel = FB_ACCEL_SUN_BWTWO; +} + +static u8 bw2regs_1600[] __initdata = { + 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13, + 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e, + 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x21, 0 +}; + +static u8 bw2regs_ecl[] __initdata = { + 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c, + 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23, + 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x20, 0 +}; + +static u8 bw2regs_analog[] __initdata = { + 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13, + 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22, + 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x20, 0 +}; + +static u8 bw2regs_76hz[] __initdata = { + 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f, + 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a, + 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x24, 0 +}; + +static u8 bw2regs_66hz[] __initdata = { + 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14, + 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24, + 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x20, 0 +}; + +static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info, + int *linebytes) +{ + u8 status, mon; + u8 *p; + + status = sbus_readb(&par->regs->status); + mon = status & BWTWO_SR_RES_MASK; + switch (status & BWTWO_SR_ID_MASK) { + case BWTWO_SR_ID_MONO_ECL: + if (mon == BWTWO_SR_1600_1280) { + p = bw2regs_1600; + info->var.xres = info->var.xres_virtual = 1600; + info->var.yres = info->var.yres_virtual = 1280; + *linebytes = 1600 / 8; + } else + p = bw2regs_ecl; + break; + + case BWTWO_SR_ID_MONO: + p = bw2regs_analog; + break; + + case BWTWO_SR_ID_MSYNC: + if (mon == BWTWO_SR_1152_900_76_A || + mon == BWTWO_SR_1152_900_76_B) + p = bw2regs_76hz; + else + p = bw2regs_66hz; + break; + + case BWTWO_SR_ID_NOCONN: + return; + + default: + prom_printf("bw2: can't handle SR %02x\n", + status); + prom_halt(); + } + for ( ; *p; p += 2) { + u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]]; + sbus_writeb(p[1], regp); + } +} + +struct all_info { + struct fb_info info; + struct bw2_par par; + struct list_head list; +}; +static LIST_HEAD(bw2_list); + +static void bw2_init_one(struct sbus_dev *sdev) +{ + struct all_info *all; + struct resource *resp; +#ifdef CONFIG_SUN4 + struct resource res; +#endif + int linebytes; + + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "bw2: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); + + INIT_LIST_HEAD(&all->list); + + spin_lock_init(&all->par.lock); + all->par.sdev = sdev; + +#ifdef CONFIG_SUN4 + if (!sdev) { + all->par.physbase = sun4_bwtwo_physaddr; + res.start = sun4_bwtwo_physaddr; + res.end = res.start + BWTWO_REGISTER_OFFSET + sizeof(struct bw2_regs) - 1; + res.flags = IORESOURCE_IO; + resp = &res; + all->info.var.xres = all->info.var.xres_virtual = 1152; + all->info.var.yres = all->info.var.yres_virtual = 900; + all->info.var.bits_per_pixel = 1; + linebytes = 1152 / 8; + } else +#else + { + if (!sdev) + BUG(); + all->par.physbase = sdev->reg_addrs[0].phys_addr; + resp = &sdev->resource[0]; + sbusfb_fill_var(&all->info.var, (sdev ? sdev->prom_node : 0), 1); + linebytes = prom_getintdefault(sdev->prom_node, "linebytes", + all->info.var.xres); + } +#endif + all->info.var.red.length = all->info.var.green.length = + all->info.var.blue.length = all->info.var.bits_per_pixel; + all->info.var.red.offset = all->info.var.green.offset = + all->info.var.blue.offset = 0; + + all->par.regs = sbus_ioremap(resp, BWTWO_REGISTER_OFFSET, + sizeof(struct bw2_regs), "bw2 regs"); + + if (sdev && !prom_getbool(sdev->prom_node, "width")) + bw2_do_default_mode(&all->par, &all->info, &linebytes); + + all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + + all->info.flags = FBINFO_DEFAULT; + all->info.fbops = &bw2_ops; +#if defined(CONFIG_SPARC32) + if (sdev) + all->info.screen_base = (char __iomem *) + prom_getintdefault(sdev->prom_node, "address", 0); +#endif + if (!all->info.screen_base) + all->info.screen_base = + sbus_ioremap(resp, 0, all->par.fbsize, "bw2 ram"); + all->info.par = &all->par; + + bw2_blank(0, &all->info); + + bw2_init_fix(&all->info, linebytes); + + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "bw2: Could not register framebuffer.\n"); + kfree(all); + return; + } + + list_add(&all->list, &bw2_list); + + printk("bw2: bwtwo at %lx:%lx\n", + (long) (sdev ? sdev->reg_addrs[0].which_io : 0), + (long) all->par.physbase); +} + +int __init bw2_init(void) +{ + struct sbus_bus *sbus; + struct sbus_dev *sdev; + + if (fb_get_options("bw2fb", NULL)) + return -ENODEV; + +#ifdef CONFIG_SUN4 + bw2_init_one(NULL); +#endif + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "bwtwo")) + bw2_init_one(sdev); + } + + return 0; +} + +void __exit bw2_exit(void) +{ + struct list_head *pos, *tmp; + + list_for_each_safe(pos, tmp, &bw2_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + kfree(all); + } +} + +int __init +bw2_setup(char *arg) +{ + /* No cmdline options yet... */ + return 0; +} + +module_init(bw2_init); + +#ifdef MODULE +module_exit(bw2_exit); +#endif + +MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets"); +MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/c2p.c b/drivers/video/c2p.c new file mode 100644 index 000000000000..5c30bbd33054 --- /dev/null +++ b/drivers/video/c2p.c @@ -0,0 +1,229 @@ +/* + * Fast C2P (Chunky-to-Planar) Conversion + * + * Copyright (C) 2003 Geert Uytterhoeven + * + * NOTES: + * - This code was inspired by Scout's C2P tutorial + * - It assumes to run on a big endian system + * + * 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/string.h> +#include "c2p.h" + + + /* + * Basic transpose step + */ + +#define _transp(d, i1, i2, shift, mask) \ + do { \ + u32 t = (d[i1] ^ (d[i2] >> shift)) & mask; \ + d[i1] ^= t; \ + d[i2] ^= t << shift; \ + } while (0) + +static inline u32 get_mask(int n) +{ + switch (n) { + case 1: + return 0x55555555; + break; + + case 2: + return 0x33333333; + break; + + case 4: + return 0x0f0f0f0f; + break; + + case 8: + return 0x00ff00ff; + break; + + case 16: + return 0x0000ffff; + break; + } + return 0; +} + +#define transp_nx1(d, n) \ + do { \ + u32 mask = get_mask(n); \ + /* First block */ \ + _transp(d, 0, 1, n, mask); \ + /* Second block */ \ + _transp(d, 2, 3, n, mask); \ + /* Third block */ \ + _transp(d, 4, 5, n, mask); \ + /* Fourth block */ \ + _transp(d, 6, 7, n, mask); \ + } while (0) + +#define transp_nx2(d, n) \ + do { \ + u32 mask = get_mask(n); \ + /* First block */ \ + _transp(d, 0, 2, n, mask); \ + _transp(d, 1, 3, n, mask); \ + /* Second block */ \ + _transp(d, 4, 6, n, mask); \ + _transp(d, 5, 7, n, mask); \ + } while (0) + +#define transp_nx4(d, n) \ + do { \ + u32 mask = get_mask(n); \ + _transp(d, 0, 4, n, mask); \ + _transp(d, 1, 5, n, mask); \ + _transp(d, 2, 6, n, mask); \ + _transp(d, 3, 7, n, mask); \ + } while (0) + +#define transp(d, n, m) transp_nx ## m(d, n) + + + /* + * Perform a full C2P step on 32 8-bit pixels, stored in 8 32-bit words + * containing + * - 32 8-bit chunky pixels on input + * - permuted planar data on output + */ + +static void c2p_8bpp(u32 d[8]) +{ + transp(d, 16, 4); + transp(d, 8, 2); + transp(d, 4, 1); + transp(d, 2, 4); + transp(d, 1, 2); +} + + + /* + * Array containing the permution indices of the planar data after c2p + */ + +static const int perm_c2p_8bpp[8] = { 7, 5, 3, 1, 6, 4, 2, 0 }; + + + /* + * Compose two values, using a bitmask as decision value + * This is equivalent to (a & mask) | (b & ~mask) + */ + +static inline unsigned long comp(unsigned long a, unsigned long b, + unsigned long mask) +{ + return ((a ^ b) & mask) ^ b; +} + + + /* + * Store a full block of planar data after c2p conversion + */ + +static inline void store_planar(char *dst, u32 dst_inc, u32 bpp, u32 d[8]) +{ + int i; + + for (i = 0; i < bpp; i++, dst += dst_inc) + *(u32 *)dst = d[perm_c2p_8bpp[i]]; +} + + + /* + * Store a partial block of planar data after c2p conversion + */ + +static inline void store_planar_masked(char *dst, u32 dst_inc, u32 bpp, + u32 d[8], u32 mask) +{ + int i; + + for (i = 0; i < bpp; i++, dst += dst_inc) + *(u32 *)dst = comp(d[perm_c2p_8bpp[i]], *(u32 *)dst, mask); +} + + + /* + * c2p - Copy 8-bit chunky image data to a planar frame buffer + * @dst: Starting address of the planar frame buffer + * @dx: Horizontal destination offset (in pixels) + * @dy: Vertical destination offset (in pixels) + * @width: Image width (in pixels) + * @height: Image height (in pixels) + * @dst_nextline: Frame buffer offset to the next line (in bytes) + * @dst_nextplane: Frame buffer offset to the next plane (in bytes) + * @src_nextline: Image offset to the next line (in bytes) + * @bpp: Bits per pixel of the planar frame buffer (1-8) + */ + +void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height, + u32 dst_nextline, u32 dst_nextplane, u32 src_nextline, u32 bpp) +{ + int dst_idx; + u32 d[8], first, last, w; + const u8 *c; + u8 *p; + + dst += dy*dst_nextline+(dx & ~31); + dst_idx = dx % 32; + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+width) % 32)); + while (height--) { + c = src; + p = dst; + w = width; + if (dst_idx+width <= 32) { + /* Single destination word */ + first &= last; + memset(d, 0, sizeof(d)); + memcpy((u8 *)d+dst_idx, c, width); + c += width; + c2p_8bpp(d); + store_planar_masked(p, dst_nextplane, bpp, d, first); + p += 4; + } else { + /* Multiple destination words */ + w = width; + /* Leading bits */ + if (dst_idx) { + w = 32 - dst_idx; + memset(d, 0, dst_idx); + memcpy((u8 *)d+dst_idx, c, w); + c += w; + c2p_8bpp(d); + store_planar_masked(p, dst_nextplane, bpp, d, first); + p += 4; + w = width-w; + } + /* Main chunk */ + while (w >= 32) { + memcpy(d, c, 32); + c += 32; + c2p_8bpp(d); + store_planar(p, dst_nextplane, bpp, d); + p += 4; + w -= 32; + } + /* Trailing bits */ + w %= 32; + if (w > 0) { + memcpy(d, c, w); + memset((u8 *)d+w, 0, 32-w); + c2p_8bpp(d); + store_planar_masked(p, dst_nextplane, bpp, d, last); + } + } + src += src_nextline; + dst += dst_nextline; + } +} + diff --git a/drivers/video/c2p.h b/drivers/video/c2p.h new file mode 100644 index 000000000000..c77cbf17e043 --- /dev/null +++ b/drivers/video/c2p.h @@ -0,0 +1,16 @@ +/* + * Fast C2P (Chunky-to-Planar) Conversion + * + * Copyright (C) 2003 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. + */ + +#include <linux/types.h> + +extern void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height, + u32 dst_nextline, u32 dst_nextplane, u32 src_nextline, + u32 bpp); + diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c new file mode 100644 index 000000000000..67711f7b11b1 --- /dev/null +++ b/drivers/video/cfbcopyarea.c @@ -0,0 +1,441 @@ +/* + * Generic function for frame buffer with packed pixels of any depth. + * + * Copyright (C) 1999-2005 James Simmons <jsimmons@www.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. + * + * NOTES: + * + * This is for cfb packed pixels. Iplan and such are incorporated in the + * drivers that need them. + * + * FIXME + * + * Also need to add code to deal with cards endians that are different than + * the native cpu endians. I also need to deal with MSB position in the word. + * + * The two functions or copying forward and backward could be split up like + * the ones for filling, i.e. in aligned and unaligned versions. This would + * help moving some redundant computations and branches out of the loop, too. + */ + + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/slab.h> +#include <asm/types.h> +#include <asm/io.h> + +#if BITS_PER_LONG == 32 +# define FB_WRITEL fb_writel +# define FB_READL fb_readl +#else +# define FB_WRITEL fb_writeq +# define FB_READL fb_readq +#endif + + /* + * Compose two values, using a bitmask as decision value + * This is equivalent to (a & mask) | (b & ~mask) + */ + +static inline unsigned long +comp(unsigned long a, unsigned long b, unsigned long mask) +{ + return ((a ^ b) & mask) ^ b; +} + + /* + * Generic bitwise copy algorithm + */ + +static void +bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, + int src_idx, int bits, unsigned n) +{ + unsigned long first, last; + int const shift = dst_idx-src_idx; + int left, right; + + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % bits)); + + if (!shift) { + // Same alignment for source and dest + + if (dst_idx+n <= bits) { + // Single word + if (last) + first &= last; + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); + } else { + // Multiple destination words + + // Leading bits + if (first != ~0UL) { + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); + dst++; + src++; + n -= bits - dst_idx; + } + + // Main chunk + n /= bits; + while (n >= 8) { + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + n -= 8; + } + while (n--) + FB_WRITEL(FB_READL(src++), dst++); + + // Trailing bits + if (last) + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); + } + } else { + unsigned long d0, d1; + int m; + // Different alignment for source and dest + + right = shift & (bits - 1); + left = -shift & (bits - 1); + + if (dst_idx+n <= bits) { + // Single destination word + if (last) + first &= last; + if (shift > 0) { + // Single source word + FB_WRITEL( comp( FB_READL(src) >> right, FB_READL(dst), first), dst); + } else if (src_idx+n <= bits) { + // Single source word + FB_WRITEL( comp(FB_READL(src) << left, FB_READL(dst), first), dst); + } else { + // 2 source words + d0 = FB_READL(src++); + d1 = FB_READL(src); + FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst); + } + } else { + // Multiple destination words + /** We must always remember the last value read, because in case + SRC and DST overlap bitwise (e.g. when moving just one pixel in + 1bpp), we always collect one full long for DST and that might + overlap with the current long from SRC. We store this value in + 'd0'. */ + d0 = FB_READL(src++); + // Leading bits + if (shift > 0) { + // Single source word + FB_WRITEL( comp(d0 >> right, FB_READL(dst), first), dst); + dst++; + n -= bits - dst_idx; + } else { + // 2 source words + d1 = FB_READL(src++); + FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst); + d0 = d1; + dst++; + n -= bits - dst_idx; + } + + // Main chunk + m = n % bits; + n /= bits; + while (n >= 4) { + d1 = FB_READL(src++); + FB_WRITEL(d0 << left | d1 >> right, dst++); + d0 = d1; + d1 = FB_READL(src++); + FB_WRITEL(d0 << left | d1 >> right, dst++); + d0 = d1; + d1 = FB_READL(src++); + FB_WRITEL(d0 << left | d1 >> right, dst++); + d0 = d1; + d1 = FB_READL(src++); + FB_WRITEL(d0 << left | d1 >> right, dst++); + d0 = d1; + n -= 4; + } + while (n--) { + d1 = FB_READL(src++); + FB_WRITEL(d0 << left | d1 >> right, dst++); + d0 = d1; + } + + // Trailing bits + if (last) { + if (m <= right) { + // Single source word + FB_WRITEL( comp(d0 << left, FB_READL(dst), last), dst); + } else { + // 2 source words + d1 = FB_READL(src); + FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), last), dst); + } + } + } + } +} + + /* + * Generic bitwise copy algorithm, operating backward + */ + +static void +bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, + int src_idx, int bits, unsigned n) +{ + unsigned long first, last; + int shift; + + dst += (n-1)/bits; + src += (n-1)/bits; + if ((n-1) % bits) { + dst_idx += (n-1) % bits; + dst += dst_idx >> (ffs(bits) - 1); + dst_idx &= bits - 1; + src_idx += (n-1) % bits; + src += src_idx >> (ffs(bits) - 1); + src_idx &= bits - 1; + } + + shift = dst_idx-src_idx; + + first = ~0UL << (bits - 1 - dst_idx); + last = ~(~0UL << (bits - 1 - ((dst_idx-n) % bits))); + + if (!shift) { + // Same alignment for source and dest + + if ((unsigned long)dst_idx+1 >= n) { + // Single word + if (last) + first &= last; + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); + } else { + // Multiple destination words + + // Leading bits + if (first != ~0UL) { + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); + dst--; + src--; + n -= dst_idx+1; + } + + // Main chunk + n /= bits; + while (n >= 8) { + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + n -= 8; + } + while (n--) + FB_WRITEL(FB_READL(src--), dst--); + + // Trailing bits + if (last) + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); + } + } else { + // Different alignment for source and dest + + int const left = -shift & (bits-1); + int const right = shift & (bits-1); + + if ((unsigned long)dst_idx+1 >= n) { + // Single destination word + if (last) + first &= last; + if (shift < 0) { + // Single source word + FB_WRITEL( comp( FB_READL(src)<<left, FB_READL(dst), first), dst); + } else if (1+(unsigned long)src_idx >= n) { + // Single source word + FB_WRITEL( comp( FB_READL(src)>>right, FB_READL(dst), first), dst); + } else { + // 2 source words + FB_WRITEL( comp( (FB_READL(src)>>right | FB_READL(src-1)<<left), FB_READL(dst), first), dst); + } + } else { + // Multiple destination words + /** We must always remember the last value read, because in case + SRC and DST overlap bitwise (e.g. when moving just one pixel in + 1bpp), we always collect one full long for DST and that might + overlap with the current long from SRC. We store this value in + 'd0'. */ + unsigned long d0, d1; + int m; + + d0 = FB_READL(src--); + // Leading bits + if (shift < 0) { + // Single source word + FB_WRITEL( comp( (d0 << left), FB_READL(dst), first), dst); + } else { + // 2 source words + d1 = FB_READL(src--); + FB_WRITEL( comp( (d0>>right | d1<<left), FB_READL(dst), first), dst); + d0 = d1; + } + dst--; + n -= dst_idx+1; + + // Main chunk + m = n % bits; + n /= bits; + while (n >= 4) { + d1 = FB_READL(src--); + FB_WRITEL(d0 >> right | d1 << left, dst--); + d0 = d1; + d1 = FB_READL(src--); + FB_WRITEL(d0 >> right | d1 << left, dst--); + d0 = d1; + d1 = FB_READL(src--); + FB_WRITEL(d0 >> right | d1 << left, dst--); + d0 = d1; + d1 = FB_READL(src--); + FB_WRITEL(d0 >> right | d1 << left, dst--); + d0 = d1; + n -= 4; + } + while (n--) { + d1 = FB_READL(src--); + FB_WRITEL(d0 >> right | d1 << left, dst--); + d0 = d1; + } + + // Trailing bits + if (last) { + if (m <= left) { + // Single source word + FB_WRITEL( comp(d0 >> right, FB_READL(dst), last), dst); + } else { + // 2 source words + d1 = FB_READL(src); + FB_WRITEL( comp(d0>>right | d1<<left, FB_READL(dst), last), dst); + } + } + } + } +} + +void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) +{ + u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; + u32 height = area->height, width = area->width; + unsigned long const bits_per_line = p->fix.line_length*8u; + unsigned long __iomem *dst = NULL, *src = NULL; + int bits = BITS_PER_LONG, bytes = bits >> 3; + int dst_idx = 0, src_idx = 0, rev_copy = 0; + int x2, y2, vxres, vyres; + + if (p->state != FBINFO_STATE_RUNNING) + return; + + /* We want rotation but lack hardware to do it for us. */ + if (!p->fbops->fb_rotate && p->var.rotate) { + } + + vxres = p->var.xres_virtual; + vyres = p->var.yres_virtual; + + if (area->dx > vxres || area->sx > vxres || + area->dy > vyres || area->sy > vyres) + return; + + /* clip the destination + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. + */ + x2 = area->dx + area->width; + y2 = area->dy + area->height; + dx = area->dx > 0 ? area->dx : 0; + dy = area->dy > 0 ? area->dy : 0; + x2 = x2 < vxres ? x2 : vxres; + y2 = y2 < vyres ? y2 : vyres; + width = x2 - dx; + height = y2 - dy; + + if ((width==0) ||(height==0)) + return; + + /* update sx1,sy1 */ + sx += (dx - area->dx); + sy += (dy - area->dy); + + /* the source must be completely inside the virtual screen */ + if (sx < 0 || sy < 0 || (sx + width) > vxres || (sy + height) > vyres) + return; + + /* if the beginning of the target area might overlap with the end of + the source area, be have to copy the area reverse. */ + if ((dy == sy && dx > sx) || (dy > sy)) { + dy += height; + sy += height; + rev_copy = 1; + } + + // split the base of the framebuffer into a long-aligned address and the + // index of the first bit + dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); + dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); + // add offset of source and target area + dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; + src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel; + + if (p->fbops->fb_sync) + p->fbops->fb_sync(p); + + if (rev_copy) { + while (height--) { + dst_idx -= bits_per_line; + src_idx -= bits_per_line; + dst += dst_idx >> (ffs(bits) - 1); + dst_idx &= (bytes - 1); + src += src_idx >> (ffs(bits) - 1); + src_idx &= (bytes - 1); + bitcpy_rev(dst, dst_idx, src, src_idx, bits, + width*p->var.bits_per_pixel); + } + } else { + while (height--) { + dst += dst_idx >> (ffs(bits) - 1); + dst_idx &= (bytes - 1); + src += src_idx >> (ffs(bits) - 1); + src_idx &= (bytes - 1); + bitcpy(dst, dst_idx, src, src_idx, bits, + width*p->var.bits_per_pixel); + dst_idx += bits_per_line; + src_idx += bits_per_line; + } + } +} + +EXPORT_SYMBOL(cfb_copyarea); + +MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); +MODULE_DESCRIPTION("Generic software accelerated copyarea"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c new file mode 100644 index 000000000000..e4fc42b013eb --- /dev/null +++ b/drivers/video/cfbfillrect.c @@ -0,0 +1,454 @@ +/* + * Generic fillrect for frame buffers with packed pixels of any depth. + * + * Copyright (C) 2000 James Simmons (jsimmons@linux-fbdev.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. + * + * NOTES: + * + * The code for depths like 24 that don't have integer number of pixels per + * long is broken and needs to be fixed. For now I turned these types of + * mode off. + * + * Also need to add code to deal with cards endians that are different than + * the native cpu endians. I also need to deal with MSB position in the word. + * + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <asm/types.h> + +#if BITS_PER_LONG == 32 +# define FB_WRITEL fb_writel +# define FB_READL fb_readl +#else +# define FB_WRITEL fb_writeq +# define FB_READL fb_readq +#endif + + /* + * Compose two values, using a bitmask as decision value + * This is equivalent to (a & mask) | (b & ~mask) + */ + +static inline unsigned long +comp(unsigned long a, unsigned long b, unsigned long mask) +{ + return ((a ^ b) & mask) ^ b; +} + + /* + * Create a pattern with the given pixel's color + */ + +#if BITS_PER_LONG == 64 +static inline unsigned long +pixel_to_pat( u32 bpp, u32 pixel) +{ + switch (bpp) { + case 1: + return 0xfffffffffffffffful*pixel; + case 2: + return 0x5555555555555555ul*pixel; + case 4: + return 0x1111111111111111ul*pixel; + case 8: + return 0x0101010101010101ul*pixel; + case 12: + return 0x0001001001001001ul*pixel; + case 16: + return 0x0001000100010001ul*pixel; + case 24: + return 0x0000000001000001ul*pixel; + case 32: + return 0x0000000100000001ul*pixel; + default: + panic("pixel_to_pat(): unsupported pixelformat\n"); + } +} +#else +static inline unsigned long +pixel_to_pat( u32 bpp, u32 pixel) +{ + switch (bpp) { + case 1: + return 0xfffffffful*pixel; + case 2: + return 0x55555555ul*pixel; + case 4: + return 0x11111111ul*pixel; + case 8: + return 0x01010101ul*pixel; + case 12: + return 0x00001001ul*pixel; + case 16: + return 0x00010001ul*pixel; + case 24: + return 0x00000001ul*pixel; + case 32: + return 0x00000001ul*pixel; + default: + panic("pixel_to_pat(): unsupported pixelformat\n"); + } +} +#endif + + /* + * Aligned pattern fill using 32/64-bit memory accesses + */ + +static void +bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits) +{ + unsigned long first, last; + + if (!n) + return; + + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % bits)); + + if (dst_idx+n <= bits) { + // Single word + if (last) + first &= last; + FB_WRITEL(comp(pat, FB_READL(dst), first), dst); + } else { + // Multiple destination words + + // Leading bits + if (first!= ~0UL) { + FB_WRITEL(comp(pat, FB_READL(dst), first), dst); + dst++; + n -= bits - dst_idx; + } + + // Main chunk + n /= bits; + while (n >= 8) { + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + n -= 8; + } + while (n--) + FB_WRITEL(pat, dst++); + + // Trailing bits + if (last) + FB_WRITEL(comp(pat, FB_READL(dst), last), dst); + } +} + + + /* + * Unaligned generic pattern fill using 32/64-bit memory accesses + * The pattern must have been expanded to a full 32/64-bit value + * Left/right are the appropriate shifts to convert to the pattern to be + * used for the next 32/64-bit word + */ + +static void +bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, + int left, int right, unsigned n, int bits) +{ + unsigned long first, last; + + if (!n) + return; + + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % bits)); + + if (dst_idx+n <= bits) { + // Single word + if (last) + first &= last; + FB_WRITEL(comp(pat, FB_READL(dst), first), dst); + } else { + // Multiple destination words + // Leading bits + if (first) { + FB_WRITEL(comp(pat, FB_READL(dst), first), dst); + dst++; + pat = pat << left | pat >> right; + n -= bits - dst_idx; + } + + // Main chunk + n /= bits; + while (n >= 4) { + FB_WRITEL(pat, dst++); + pat = pat << left | pat >> right; + FB_WRITEL(pat, dst++); + pat = pat << left | pat >> right; + FB_WRITEL(pat, dst++); + pat = pat << left | pat >> right; + FB_WRITEL(pat, dst++); + pat = pat << left | pat >> right; + n -= 4; + } + while (n--) { + FB_WRITEL(pat, dst++); + pat = pat << left | pat >> right; + } + + // Trailing bits + if (last) + FB_WRITEL(comp(pat, FB_READL(dst), first), dst); + } +} + + /* + * Aligned pattern invert using 32/64-bit memory accesses + */ +static void +bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits) +{ + unsigned long val = pat, dat; + unsigned long first, last; + + if (!n) + return; + + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % bits)); + + if (dst_idx+n <= bits) { + // Single word + if (last) + first &= last; + dat = FB_READL(dst); + FB_WRITEL(comp(dat ^ val, dat, first), dst); + } else { + // Multiple destination words + // Leading bits + if (first!=0UL) { + dat = FB_READL(dst); + FB_WRITEL(comp(dat ^ val, dat, first), dst); + dst++; + n -= bits - dst_idx; + } + + // Main chunk + n /= bits; + while (n >= 8) { + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + n -= 8; + } + while (n--) { + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + } + // Trailing bits + if (last) { + dat = FB_READL(dst); + FB_WRITEL(comp(dat ^ val, dat, last), dst); + } + } +} + + + /* + * Unaligned generic pattern invert using 32/64-bit memory accesses + * The pattern must have been expanded to a full 32/64-bit value + * Left/right are the appropriate shifts to convert to the pattern to be + * used for the next 32/64-bit word + */ + +static void +bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, + int left, int right, unsigned n, int bits) +{ + unsigned long first, last, dat; + + if (!n) + return; + + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % bits)); + + if (dst_idx+n <= bits) { + // Single word + if (last) + first &= last; + dat = FB_READL(dst); + FB_WRITEL(comp(dat ^ pat, dat, first), dst); + } else { + // Multiple destination words + + // Leading bits + if (first != 0UL) { + dat = FB_READL(dst); + FB_WRITEL(comp(dat ^ pat, dat, first), dst); + dst++; + pat = pat << left | pat >> right; + n -= bits - dst_idx; + } + + // Main chunk + n /= bits; + while (n >= 4) { + FB_WRITEL(FB_READL(dst) ^ pat, dst); + dst++; + pat = pat << left | pat >> right; + FB_WRITEL(FB_READL(dst) ^ pat, dst); + dst++; + pat = pat << left | pat >> right; + FB_WRITEL(FB_READL(dst) ^ pat, dst); + dst++; + pat = pat << left | pat >> right; + FB_WRITEL(FB_READL(dst) ^ pat, dst); + dst++; + pat = pat << left | pat >> right; + n -= 4; + } + while (n--) { + FB_WRITEL(FB_READL(dst) ^ pat, dst); + dst++; + pat = pat << left | pat >> right; + } + + // Trailing bits + if (last) { + dat = FB_READL(dst); + FB_WRITEL(comp(dat ^ pat, dat, last), dst); + } + } +} + +void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) +{ + unsigned long x2, y2, vxres, vyres, height, width, pat, fg; + int bits = BITS_PER_LONG, bytes = bits >> 3; + u32 bpp = p->var.bits_per_pixel; + unsigned long __iomem *dst; + int dst_idx, left; + + if (p->state != FBINFO_STATE_RUNNING) + return; + + /* We want rotation but lack hardware to do it for us. */ + if (!p->fbops->fb_rotate && p->var.rotate) { + } + + vxres = p->var.xres_virtual; + vyres = p->var.yres_virtual; + + if (!rect->width || !rect->height || + rect->dx > vxres || rect->dy > vyres) + return; + + /* We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. */ + + x2 = rect->dx + rect->width; + y2 = rect->dy + rect->height; + x2 = x2 < vxres ? x2 : vxres; + y2 = y2 < vyres ? y2 : vyres; + width = x2 - rect->dx; + height = y2 - rect->dy; + + if (p->fix.visual == FB_VISUAL_TRUECOLOR || + p->fix.visual == FB_VISUAL_DIRECTCOLOR ) + fg = ((u32 *) (p->pseudo_palette))[rect->color]; + else + fg = rect->color; + + pat = pixel_to_pat( bpp, fg); + + dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); + dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8; + dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp; + /* FIXME For now we support 1-32 bpp only */ + left = bits % bpp; + if (p->fbops->fb_sync) + p->fbops->fb_sync(p); + if (!left) { + void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, + unsigned long pat, unsigned n, int bits) = NULL; + + switch (rect->rop) { + case ROP_XOR: + fill_op32 = bitfill_aligned_rev; + break; + case ROP_COPY: + fill_op32 = bitfill_aligned; + break; + default: + printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); + fill_op32 = bitfill_aligned; + break; + } + while (height--) { + dst += dst_idx >> (ffs(bits) - 1); + dst_idx &= (bits - 1); + fill_op32(dst, dst_idx, pat, width*bpp, bits); + dst_idx += p->fix.line_length*8; + } + } else { + int right; + int r; + int rot = (left-dst_idx) % bpp; + void (*fill_op)(unsigned long __iomem *dst, int dst_idx, + unsigned long pat, int left, int right, + unsigned n, int bits) = NULL; + + /* rotate pattern to correct start position */ + pat = pat << rot | pat >> (bpp-rot); + + right = bpp-left; + switch (rect->rop) { + case ROP_XOR: + fill_op = bitfill_unaligned_rev; + break; + case ROP_COPY: + fill_op = bitfill_unaligned; + break; + default: + printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); + fill_op = bitfill_unaligned; + break; + } + while (height--) { + dst += dst_idx >> (ffs(bits) - 1); + dst_idx &= (bits - 1); + fill_op(dst, dst_idx, pat, left, right, + width*bpp, bits); + r = (p->fix.line_length*8) % bpp; + pat = pat << (bpp-r) | pat >> r; + dst_idx += p->fix.line_length*8; + } + } +} + +EXPORT_SYMBOL(cfb_fillrect); + +MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); +MODULE_DESCRIPTION("Generic software accelerated fill rectangle"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c new file mode 100644 index 000000000000..4c123abaa843 --- /dev/null +++ b/drivers/video/cfbimgblt.c @@ -0,0 +1,339 @@ +/* + * Generic BitBLT function for frame buffer with packed pixels of any depth. + * + * Copyright (C) June 1999 James Simmons + * + * 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 function copys a image from system memory to video memory. The + * image can be a bitmap where each 0 represents the background color and + * each 1 represents the foreground color. Great for font handling. It can + * also be a color image. This is determined by image_depth. The color image + * must be laid out exactly in the same format as the framebuffer. Yes I know + * their are cards with hardware that coverts images of various depths to the + * framebuffer depth. But not every card has this. All images must be rounded + * up to the nearest byte. For example a bitmap 12 bits wide must be two + * bytes width. + * + * 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_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 + * the native cpu endians. I also need to deal with MSB position in the word. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <asm/types.h> + +#define DEBUG + +#ifdef DEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args) +#else +#define DPRINTK(fmt, args...) +#endif + +static u32 cfb_tab8[] = { +#if defined(__BIG_ENDIAN) + 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, + 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, + 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, + 0xffff0000,0xffff00ff,0xffffff00,0xffffffff +#elif defined(__LITTLE_ENDIAN) + 0x00000000,0xff000000,0x00ff0000,0xffff0000, + 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, + 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, + 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff +#else +#error FIXME: No endianness?? +#endif +}; + +static u32 cfb_tab16[] = { +#if defined(__BIG_ENDIAN) + 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff +#elif defined(__LITTLE_ENDIAN) + 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff +#else +#error FIXME: No endianness?? +#endif +}; + +static u32 cfb_tab32[] = { + 0x00000000, 0xffffffff +}; + +#define FB_WRITEL fb_writel +#define FB_READL fb_readl + +#if defined (__BIG_ENDIAN) +#define LEFT_POS(bpp) (32 - bpp) +#define SHIFT_HIGH(val, bits) ((val) >> (bits)) +#define SHIFT_LOW(val, bits) ((val) << (bits)) +#else +#define LEFT_POS(bpp) (0) +#define SHIFT_HIGH(val, bits) ((val) << (bits)) +#define SHIFT_LOW(val, bits) ((val) >> (bits)) +#endif + +static inline void color_imageblit(const struct fb_image *image, + struct fb_info *p, u8 __iomem *dst1, + u32 start_index, + u32 pitch_index) +{ + /* Draw the penguin */ + u32 __iomem *dst, *dst2; + u32 color = 0, val, shift; + int i, n, bpp = p->var.bits_per_pixel; + u32 null_bits = 32 - bpp; + u32 *palette = (u32 *) p->pseudo_palette; + const u8 *src = image->data; + + dst2 = (u32 __iomem *) dst1; + for (i = image->height; i--; ) { + n = image->width; + dst = (u32 __iomem *) dst1; + shift = 0; + val = 0; + + if (start_index) { + u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index)); + val = FB_READL(dst) & start_mask; + shift = start_index; + } + while (n--) { + if (p->fix.visual == FB_VISUAL_TRUECOLOR || + p->fix.visual == FB_VISUAL_DIRECTCOLOR ) + color = palette[*src]; + else + color = *src; + color <<= LEFT_POS(bpp); + val |= SHIFT_HIGH(color, shift); + if (shift >= null_bits) { + FB_WRITEL(val, dst++); + + val = (shift == null_bits) ? 0 : + SHIFT_LOW(color, 32 - shift); + } + shift += bpp; + shift &= (32 - 1); + src++; + } + if (shift) { + u32 end_mask = SHIFT_HIGH(~(u32)0, shift); + + FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); + } + dst1 += p->fix.line_length; + if (pitch_index) { + dst2 += p->fix.line_length; + dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1)); + + start_index += pitch_index; + start_index &= 32 - 1; + } + } +} + +static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p, + u8 __iomem *dst1, u32 fgcolor, + u32 bgcolor, + u32 start_index, + u32 pitch_index) +{ + u32 shift, color = 0, bpp = p->var.bits_per_pixel; + u32 __iomem *dst, *dst2; + u32 val, pitch = p->fix.line_length; + u32 null_bits = 32 - bpp; + u32 spitch = (image->width+7)/8; + const u8 *src = image->data, *s; + u32 i, j, l; + + dst2 = (u32 __iomem *) dst1; + + for (i = image->height; i--; ) { + shift = val = 0; + l = 8; + j = image->width; + dst = (u32 __iomem *) dst1; + s = src; + + /* write leading bits */ + if (start_index) { + u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index)); + val = FB_READL(dst) & start_mask; + shift = start_index; + } + + while (j--) { + l--; + color = (*s & (1 << l)) ? fgcolor : bgcolor; + color <<= LEFT_POS(bpp); + val |= SHIFT_HIGH(color, shift); + + /* Did the bitshift spill bits to the next long? */ + if (shift >= null_bits) { + FB_WRITEL(val, dst++); + val = (shift == null_bits) ? 0 : + SHIFT_LOW(color,32 - shift); + } + shift += bpp; + shift &= (32 - 1); + if (!l) { l = 8; s++; }; + } + + /* write trailing bits */ + if (shift) { + u32 end_mask = SHIFT_HIGH(~(u32)0, shift); + + FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); + } + + dst1 += pitch; + src += spitch; + if (pitch_index) { + dst2 += pitch; + dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1)); + start_index += pitch_index; + start_index &= 32 - 1; + } + + } +} + +/* + * fast_imageblit - optimized monochrome color expansion + * + * Only if: bits_per_pixel == 8, 16, or 32 + * image->width is divisible by pixel/dword (ppw); + * fix->line_legth is divisible by 4; + * beginning and end of a scanline is dword aligned + */ +static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p, + u8 __iomem *dst1, u32 fgcolor, + u32 bgcolor) +{ + u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel; + u32 ppw = 32/bpp, spitch = (image->width + 7)/8; + u32 bit_mask, end_mask, eorx, shift; + const char *s = image->data, *src; + u32 __iomem *dst; + u32 *tab = NULL; + int i, j, k; + + switch (bpp) { + case 8: + tab = cfb_tab8; + break; + case 16: + tab = cfb_tab16; + break; + case 32: + tab = cfb_tab32; + break; + } + + for (i = ppw-1; i--; ) { + fgx <<= bpp; + bgx <<= bpp; + fgx |= fgcolor; + bgx |= bgcolor; + } + + bit_mask = (1 << ppw) - 1; + eorx = fgx ^ bgx; + k = image->width/ppw; + + for (i = image->height; i--; ) { + dst = (u32 __iomem *) dst1, shift = 8; src = s; + + for (j = k; j--; ) { + shift -= ppw; + end_mask = tab[(*src >> shift) & bit_mask]; + FB_WRITEL((end_mask & eorx)^bgx, dst++); + if (!shift) { shift = 8; src++; } + } + dst1 += p->fix.line_length; + s += spitch; + } +} + +void cfb_imageblit(struct fb_info *p, const struct fb_image *image) +{ + u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; + u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel; + u32 width = image->width, height = image->height; + u32 dx = image->dx, dy = image->dy; + int x2, y2, vxres, vyres; + u8 __iomem *dst1; + + if (p->state != FBINFO_STATE_RUNNING) + return; + + vxres = p->var.xres_virtual; + vyres = p->var.yres_virtual; + /* + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly like we are + * doing here. + */ + if (image->dx > vxres || image->dy > vyres) + return; + + x2 = image->dx + image->width; + y2 = image->dy + image->height; + dx = image->dx > 0 ? image->dx : 0; + dy = image->dy > 0 ? image->dy : 0; + x2 = x2 < vxres ? x2 : vxres; + y2 = y2 < vyres ? y2 : vyres; + width = x2 - dx; + height = y2 - dy; + + bitstart = (dy * p->fix.line_length * 8) + (dx * bpp); + start_index = bitstart & (32 - 1); + pitch_index = (p->fix.line_length & (bpl - 1)) * 8; + + bitstart /= 8; + bitstart &= ~(bpl - 1); + dst1 = p->screen_base + bitstart; + + if (p->fbops->fb_sync) + p->fbops->fb_sync(p); + + if (image->depth == 1) { + if (p->fix.visual == FB_VISUAL_TRUECOLOR || + p->fix.visual == FB_VISUAL_DIRECTCOLOR) { + fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color]; + bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color]; + } else { + fgcolor = image->fg_color; + bgcolor = image->bg_color; + } + + if (32 % bpp == 0 && !start_index && !pitch_index && + ((width & (32/bpp-1)) == 0) && + bpp >= 8 && bpp <= 32) + fast_imageblit(image, p, dst1, fgcolor, bgcolor); + else + slow_imageblit(image, p, dst1, fgcolor, bgcolor, + start_index, pitch_index); + } else + color_imageblit(image, p, dst1, start_index, pitch_index); +} + +EXPORT_SYMBOL(cfb_imageblit); + +MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); +MODULE_DESCRIPTION("Generic software accelerated imaging drawing"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c new file mode 100644 index 000000000000..18e60b941e21 --- /dev/null +++ b/drivers/video/cg14.c @@ -0,0 +1,648 @@ +/* cg14.c: CGFOURTEEN frame buffer driver + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) + * + * Driver layout based loosely on tgafb.c, see that file for credits. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <linux/mm.h> + +#include <asm/io.h> +#include <asm/sbus.h> +#include <asm/oplib.h> +#include <asm/fbio.h> + +#include "sbuslib.h" + +/* + * Local functions. + */ + +static int cg14_setcolreg(unsigned, unsigned, unsigned, unsigned, + unsigned, struct fb_info *); + +static int cg14_mmap(struct fb_info *, struct file *, struct vm_area_struct *); +static int cg14_ioctl(struct inode *, struct file *, unsigned int, + unsigned long, struct fb_info *); +static int cg14_pan_display(struct fb_var_screeninfo *, struct fb_info *); + +/* + * Frame buffer operations + */ + +static struct fb_ops cg14_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = cg14_setcolreg, + .fb_pan_display = cg14_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = cg14_mmap, + .fb_ioctl = cg14_ioctl, + .fb_cursor = soft_cursor, +}; + +#define CG14_MCR_INTENABLE_SHIFT 7 +#define CG14_MCR_INTENABLE_MASK 0x80 +#define CG14_MCR_VIDENABLE_SHIFT 6 +#define CG14_MCR_VIDENABLE_MASK 0x40 +#define CG14_MCR_PIXMODE_SHIFT 4 +#define CG14_MCR_PIXMODE_MASK 0x30 +#define CG14_MCR_TMR_SHIFT 2 +#define CG14_MCR_TMR_MASK 0x0c +#define CG14_MCR_TMENABLE_SHIFT 1 +#define CG14_MCR_TMENABLE_MASK 0x02 +#define CG14_MCR_RESET_SHIFT 0 +#define CG14_MCR_RESET_MASK 0x01 +#define CG14_REV_REVISION_SHIFT 4 +#define CG14_REV_REVISION_MASK 0xf0 +#define CG14_REV_IMPL_SHIFT 0 +#define CG14_REV_IMPL_MASK 0x0f +#define CG14_VBR_FRAMEBASE_SHIFT 12 +#define CG14_VBR_FRAMEBASE_MASK 0x00fff000 +#define CG14_VMCR1_SETUP_SHIFT 0 +#define CG14_VMCR1_SETUP_MASK 0x000001ff +#define CG14_VMCR1_VCONFIG_SHIFT 9 +#define CG14_VMCR1_VCONFIG_MASK 0x00000e00 +#define CG14_VMCR2_REFRESH_SHIFT 0 +#define CG14_VMCR2_REFRESH_MASK 0x00000001 +#define CG14_VMCR2_TESTROWCNT_SHIFT 1 +#define CG14_VMCR2_TESTROWCNT_MASK 0x00000002 +#define CG14_VMCR2_FBCONFIG_SHIFT 2 +#define CG14_VMCR2_FBCONFIG_MASK 0x0000000c +#define CG14_VCR_REFRESHREQ_SHIFT 0 +#define CG14_VCR_REFRESHREQ_MASK 0x000003ff +#define CG14_VCR1_REFRESHENA_SHIFT 10 +#define CG14_VCR1_REFRESHENA_MASK 0x00000400 +#define CG14_VCA_CAD_SHIFT 0 +#define CG14_VCA_CAD_MASK 0x000003ff +#define CG14_VCA_VERS_SHIFT 10 +#define CG14_VCA_VERS_MASK 0x00000c00 +#define CG14_VCA_RAMSPEED_SHIFT 12 +#define CG14_VCA_RAMSPEED_MASK 0x00001000 +#define CG14_VCA_8MB_SHIFT 13 +#define CG14_VCA_8MB_MASK 0x00002000 + +#define CG14_MCR_PIXMODE_8 0 +#define CG14_MCR_PIXMODE_16 2 +#define CG14_MCR_PIXMODE_32 3 + +struct cg14_regs{ + volatile u8 mcr; /* Master Control Reg */ + volatile u8 ppr; /* Packed Pixel Reg */ + volatile u8 tms[2]; /* Test Mode Status Regs */ + volatile u8 msr; /* Master Status Reg */ + volatile u8 fsr; /* Fault Status Reg */ + volatile u8 rev; /* Revision & Impl */ + volatile u8 ccr; /* Clock Control Reg */ + volatile u32 tmr; /* Test Mode Read Back */ + volatile u8 mod; /* Monitor Operation Data Reg */ + volatile u8 acr; /* Aux Control */ + u8 xxx0[6]; + volatile u16 hct; /* Hor Counter */ + volatile u16 vct; /* Vert Counter */ + volatile u16 hbs; /* Hor Blank Start */ + volatile u16 hbc; /* Hor Blank Clear */ + volatile u16 hss; /* Hor Sync Start */ + volatile u16 hsc; /* Hor Sync Clear */ + volatile u16 csc; /* Composite Sync Clear */ + volatile u16 vbs; /* Vert Blank Start */ + volatile u16 vbc; /* Vert Blank Clear */ + volatile u16 vss; /* Vert Sync Start */ + volatile u16 vsc; /* Vert Sync Clear */ + volatile u16 xcs; + volatile u16 xcc; + volatile u16 fsa; /* Fault Status Address */ + volatile u16 adr; /* Address Registers */ + u8 xxx1[0xce]; + volatile u8 pcg[0x100]; /* Pixel Clock Generator */ + volatile u32 vbr; /* Frame Base Row */ + volatile u32 vmcr; /* VBC Master Control */ + volatile u32 vcr; /* VBC refresh */ + volatile u32 vca; /* VBC Config */ +}; + +#define CG14_CCR_ENABLE 0x04 +#define CG14_CCR_SELECT 0x02 /* HW/Full screen */ + +struct cg14_cursor { + volatile u32 cpl0[32]; /* Enable plane 0 */ + volatile u32 cpl1[32]; /* Color selection plane */ + volatile u8 ccr; /* Cursor Control Reg */ + u8 xxx0[3]; + volatile u16 cursx; /* Cursor x,y position */ + volatile u16 cursy; /* Cursor x,y position */ + volatile u32 color0; + volatile u32 color1; + u32 xxx1[0x1bc]; + volatile u32 cpl0i[32]; /* Enable plane 0 autoinc */ + volatile u32 cpl1i[32]; /* Color selection autoinc */ +}; + +struct cg14_dac { + volatile u8 addr; /* Address Register */ + u8 xxx0[255]; + volatile u8 glut; /* Gamma table */ + u8 xxx1[255]; + volatile u8 select; /* Register Select */ + u8 xxx2[255]; + volatile u8 mode; /* Mode Register */ +}; + +struct cg14_xlut{ + volatile u8 x_xlut [256]; + volatile u8 x_xlutd [256]; + u8 xxx0[0x600]; + volatile u8 x_xlut_inc [256]; + volatile u8 x_xlutd_inc [256]; +}; + +/* Color look up table (clut) */ +/* Each one of these arrays hold the color lookup table (for 256 + * colors) for each MDI page (I assume then there should be 4 MDI + * pages, I still wonder what they are. I have seen NeXTStep split + * the screen in four parts, while operating in 24 bits mode. Each + * integer holds 4 values: alpha value (transparency channel, thanks + * go to John Stone (johns@umr.edu) from OpenBSD), red, green and blue + * + * I currently use the clut instead of the Xlut + */ +struct cg14_clut { + u32 c_clut [256]; + u32 c_clutd [256]; /* i wonder what the 'd' is for */ + u32 c_clut_inc [256]; + u32 c_clutd_inc [256]; +}; + +#define CG14_MMAP_ENTRIES 16 + +struct cg14_par { + spinlock_t lock; + struct cg14_regs __iomem *regs; + struct cg14_clut __iomem *clut; + struct cg14_cursor __iomem *cursor; + + u32 flags; +#define CG14_FLAG_BLANKED 0x00000001 + + unsigned long physbase; + unsigned long iospace; + unsigned long fbsize; + + struct sbus_mmap_map mmap_map[CG14_MMAP_ENTRIES]; + + int mode; + int ramsize; + struct sbus_dev *sdev; + struct list_head list; +}; + +static void __cg14_reset(struct cg14_par *par) +{ + struct cg14_regs __iomem *regs = par->regs; + u8 val; + + val = sbus_readb(®s->mcr); + val &= ~(CG14_MCR_PIXMODE_MASK); + sbus_writeb(val, ®s->mcr); +} + +static int cg14_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct cg14_par *par = (struct cg14_par *) info->par; + unsigned long flags; + + /* We just use this to catch switches out of + * graphics mode. + */ + spin_lock_irqsave(&par->lock, flags); + __cg14_reset(par); + spin_unlock_irqrestore(&par->lock, flags); + + if (var->xoffset || var->yoffset || var->vmode) + return -EINVAL; + return 0; +} + +/** + * cg14_setcolreg - Optional function. Sets a color register. + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @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. + * @info: frame buffer info structure + */ +static int cg14_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct cg14_par *par = (struct cg14_par *) info->par; + struct cg14_clut __iomem *clut = par->clut; + unsigned long flags; + u32 val; + + if (regno >= 256) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + val = (red | (green << 8) | (blue << 16)); + + spin_lock_irqsave(&par->lock, flags); + sbus_writel(val, &clut->c_clut[regno]); + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +static int cg14_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) +{ + struct cg14_par *par = (struct cg14_par *) info->par; + + return sbusfb_mmap_helper(par->mmap_map, + par->physbase, par->fbsize, + par->iospace, vma); +} + +static int cg14_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *info) +{ + struct cg14_par *par = (struct cg14_par *) info->par; + struct cg14_regs __iomem *regs = par->regs; + struct mdi_cfginfo kmdi, __user *mdii; + unsigned long flags; + int cur_mode, mode, ret = 0; + + switch (cmd) { + case MDI_RESET: + spin_lock_irqsave(&par->lock, flags); + __cg14_reset(par); + spin_unlock_irqrestore(&par->lock, flags); + break; + + case MDI_GET_CFGINFO: + memset(&kmdi, 0, sizeof(kmdi)); + + spin_lock_irqsave(&par->lock, flags); + kmdi.mdi_type = FBTYPE_MDICOLOR; + kmdi.mdi_height = info->var.yres; + kmdi.mdi_width = info->var.xres; + kmdi.mdi_mode = par->mode; + kmdi.mdi_pixfreq = 72; /* FIXME */ + kmdi.mdi_size = par->ramsize; + spin_unlock_irqrestore(&par->lock, flags); + + mdii = (struct mdi_cfginfo __user *) arg; + if (copy_to_user(mdii, &kmdi, sizeof(kmdi))) + ret = -EFAULT; + break; + + case MDI_SET_PIXELMODE: + if (get_user(mode, (int __user *) arg)) { + ret = -EFAULT; + break; + } + + spin_lock_irqsave(&par->lock, flags); + cur_mode = sbus_readb(®s->mcr); + cur_mode &= ~CG14_MCR_PIXMODE_MASK; + switch(mode) { + case MDI_32_PIX: + cur_mode |= (CG14_MCR_PIXMODE_32 << + CG14_MCR_PIXMODE_SHIFT); + break; + + case MDI_16_PIX: + cur_mode |= (CG14_MCR_PIXMODE_16 << + CG14_MCR_PIXMODE_SHIFT); + break; + + case MDI_8_PIX: + break; + + default: + ret = -ENOSYS; + break; + }; + if (!ret) { + sbus_writeb(cur_mode, ®s->mcr); + par->mode = mode; + } + spin_unlock_irqrestore(&par->lock, flags); + break; + + default: + ret = sbusfb_ioctl_helper(cmd, arg, info, + FBTYPE_MDICOLOR, 8, par->fbsize); + break; + }; + + return ret; +} + +/* + * Initialisation + */ + +static void cg14_init_fix(struct fb_info *info, int linebytes) +{ + struct cg14_par *par = (struct cg14_par *)info->par; + const char *name; + + name = "cgfourteen"; + if (par->sdev) + name = par->sdev->prom_name; + + strlcpy(info->fix.id, name, sizeof(info->fix.id)); + + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + + info->fix.line_length = linebytes; + + info->fix.accel = FB_ACCEL_SUN_CG14; +} + +static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __initdata = { + { + .voff = CG14_REGS, + .poff = 0x80000000, + .size = 0x1000 + }, + { + .voff = CG14_XLUT, + .poff = 0x80003000, + .size = 0x1000 + }, + { + .voff = CG14_CLUT1, + .poff = 0x80004000, + .size = 0x1000 + }, + { + .voff = CG14_CLUT2, + .poff = 0x80005000, + .size = 0x1000 + }, + { + .voff = CG14_CLUT3, + .poff = 0x80006000, + .size = 0x1000 + }, + { + .voff = CG3_MMAP_OFFSET - 0x7000, + .poff = 0x80000000, + .size = 0x7000 + }, + { + .voff = CG3_MMAP_OFFSET, + .poff = 0x00000000, + .size = SBUS_MMAP_FBSIZE(1) + }, + { + .voff = MDI_CURSOR_MAP, + .poff = 0x80001000, + .size = 0x1000 + }, + { + .voff = MDI_CHUNKY_BGR_MAP, + .poff = 0x01000000, + .size = 0x400000 + }, + { + .voff = MDI_PLANAR_X16_MAP, + .poff = 0x02000000, + .size = 0x200000 + }, + { + .voff = MDI_PLANAR_C16_MAP, + .poff = 0x02800000, + .size = 0x200000 + }, + { + .voff = MDI_PLANAR_X32_MAP, + .poff = 0x03000000, + .size = 0x100000 + }, + { + .voff = MDI_PLANAR_B32_MAP, + .poff = 0x03400000, + .size = 0x100000 + }, + { + .voff = MDI_PLANAR_G32_MAP, + .poff = 0x03800000, + .size = 0x100000 + }, + { + .voff = MDI_PLANAR_R32_MAP, + .poff = 0x03c00000, + .size = 0x100000 + }, + { .size = 0 } +}; + +struct all_info { + struct fb_info info; + struct cg14_par par; + struct list_head list; +}; +static LIST_HEAD(cg14_list); + +static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node) +{ + struct all_info *all; + unsigned long phys, rphys; + u32 bases[6]; + int is_8mb, linebytes, i; + + if (!sdev) { + if (prom_getproperty(node, "address", + (char *) &bases[0], sizeof(bases)) <= 0 + || !bases[0]) { + printk(KERN_ERR "cg14: Device is not mapped.\n"); + return; + } + if (__get_iospace(bases[0]) != __get_iospace(bases[1])) { + printk(KERN_ERR "cg14: I/O spaces don't match.\n"); + return; + } + } + + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "cg14: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); + + INIT_LIST_HEAD(&all->list); + + spin_lock_init(&all->par.lock); + + sbusfb_fill_var(&all->info.var, node, 8); + all->info.var.red.length = 8; + all->info.var.green.length = 8; + all->info.var.blue.length = 8; + + linebytes = prom_getintdefault(node, "linebytes", + all->info.var.xres); + all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + + all->par.sdev = sdev; + if (sdev) { + rphys = sdev->reg_addrs[0].phys_addr; + all->par.physbase = phys = sdev->reg_addrs[1].phys_addr; + all->par.iospace = sdev->reg_addrs[0].which_io; + + all->par.regs = sbus_ioremap(&sdev->resource[0], 0, + sizeof(struct cg14_regs), + "cg14 regs"); + all->par.clut = sbus_ioremap(&sdev->resource[0], CG14_CLUT1, + sizeof(struct cg14_clut), + "cg14 clut"); + all->par.cursor = sbus_ioremap(&sdev->resource[0], CG14_CURSORREGS, + sizeof(struct cg14_cursor), + "cg14 cursor"); + all->info.screen_base = sbus_ioremap(&sdev->resource[1], 0, + all->par.fbsize, "cg14 ram"); + } else { + rphys = __get_phys(bases[0]); + all->par.physbase = phys = __get_phys(bases[1]); + all->par.iospace = __get_iospace(bases[0]); + all->par.regs = (struct cg14_regs __iomem *)(unsigned long)bases[0]; + all->par.clut = (struct cg14_clut __iomem *)((unsigned long)bases[0] + + CG14_CLUT1); + all->par.cursor = + (struct cg14_cursor __iomem *)((unsigned long)bases[0] + + CG14_CURSORREGS); + + all->info.screen_base = (char __iomem *)(unsigned long)bases[1]; + } + + prom_getproperty(node, "reg", (char *) &bases[0], sizeof(bases)); + is_8mb = (bases[5] == 0x800000); + + if (sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map)) { + extern void __cg14_mmap_sized_wrongly(void); + + __cg14_mmap_sized_wrongly(); + } + + memcpy(&all->par.mmap_map, &__cg14_mmap_map, sizeof(all->par.mmap_map)); + for (i = 0; i < CG14_MMAP_ENTRIES; i++) { + struct sbus_mmap_map *map = &all->par.mmap_map[i]; + + if (!map->size) + break; + if (map->poff & 0x80000000) + map->poff = (map->poff & 0x7fffffff) + rphys - phys; + if (is_8mb && + map->size >= 0x100000 && + map->size <= 0x400000) + map->size *= 2; + } + + all->par.mode = MDI_8_PIX; + all->par.ramsize = (is_8mb ? 0x800000 : 0x400000); + + all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + all->info.fbops = &cg14_ops; + all->info.par = &all->par; + + __cg14_reset(&all->par); + + if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { + printk(KERN_ERR "cg14: Could not allocate color map.\n"); + kfree(all); + return; + } + fb_set_cmap(&all->info.cmap, &all->info); + + cg14_init_fix(&all->info, linebytes); + + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "cg14: Could not register framebuffer.\n"); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + return; + } + + list_add(&all->list, &cg14_list); + + printk("cg14: cgfourteen at %lx:%lx, %dMB\n", + all->par.iospace, all->par.physbase, all->par.ramsize >> 20); + +} + +int __init cg14_init(void) +{ + struct sbus_bus *sbus; + struct sbus_dev *sdev; + + if (fb_get_options("cg14fb", NULL)) + return -ENODEV; + +#ifdef CONFIG_SPARC32 + { + int root, node; + + root = prom_getchild(prom_root_node); + root = prom_searchsiblings(root, "obio"); + if (root) { + node = prom_searchsiblings(prom_getchild(root), + "cgfourteen"); + if (node) + cg14_init_one(NULL, node, root); + } + } +#endif + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "cgfourteen")) + cg14_init_one(sdev, sdev->prom_node, sbus->prom_node); + } + + return 0; +} + +void __exit cg14_exit(void) +{ + struct list_head *pos, *tmp; + + list_for_each_safe(pos, tmp, &cg14_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } +} + +int __init +cg14_setup(char *arg) +{ + /* No cmdline options yet... */ + return 0; +} + +module_init(cg14_init); + +#ifdef MODULE +module_exit(cg14_exit); +#endif + +MODULE_DESCRIPTION("framebuffer driver for CGfourteen chipsets"); +MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c new file mode 100644 index 000000000000..6e7d8d45dc68 --- /dev/null +++ b/drivers/video/cg3.c @@ -0,0 +1,489 @@ +/* cg3.c: CGTHREE frame buffer driver + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * + * Driver layout based loosely on tgafb.c, see that file for credits. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <linux/mm.h> + +#include <asm/io.h> +#include <asm/sbus.h> +#include <asm/oplib.h> +#include <asm/fbio.h> + +#include "sbuslib.h" + +/* + * Local functions. + */ + +static int cg3_setcolreg(unsigned, unsigned, unsigned, unsigned, + unsigned, struct fb_info *); +static int cg3_blank(int, struct fb_info *); + +static int cg3_mmap(struct fb_info *, struct file *, struct vm_area_struct *); +static int cg3_ioctl(struct inode *, struct file *, unsigned int, + unsigned long, struct fb_info *); + +/* + * Frame buffer operations + */ + +static struct fb_ops cg3_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = cg3_setcolreg, + .fb_blank = cg3_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = cg3_mmap, + .fb_ioctl = cg3_ioctl, + .fb_cursor = soft_cursor, +}; + + +/* Control Register Constants */ +#define CG3_CR_ENABLE_INTS 0x80 +#define CG3_CR_ENABLE_VIDEO 0x40 +#define CG3_CR_ENABLE_TIMING 0x20 +#define CG3_CR_ENABLE_CURCMP 0x10 +#define CG3_CR_XTAL_MASK 0x0c +#define CG3_CR_DIVISOR_MASK 0x03 + +/* Status Register Constants */ +#define CG3_SR_PENDING_INT 0x80 +#define CG3_SR_RES_MASK 0x70 +#define CG3_SR_1152_900_76_A 0x40 +#define CG3_SR_1152_900_76_B 0x60 +#define CG3_SR_ID_MASK 0x0f +#define CG3_SR_ID_COLOR 0x01 +#define CG3_SR_ID_MONO 0x02 +#define CG3_SR_ID_MONO_ECL 0x03 + +enum cg3_type { + CG3_AT_66HZ = 0, + CG3_AT_76HZ, + CG3_RDI +}; + +struct bt_regs { + volatile u32 addr; + volatile u32 color_map; + volatile u32 control; + volatile u32 cursor; +}; + +struct cg3_regs { + struct bt_regs cmap; + volatile u8 control; + volatile u8 status; + volatile u8 cursor_start; + volatile u8 cursor_end; + volatile u8 h_blank_start; + volatile u8 h_blank_end; + volatile u8 h_sync_start; + volatile u8 h_sync_end; + volatile u8 comp_sync_end; + volatile u8 v_blank_start_high; + volatile u8 v_blank_start_low; + volatile u8 v_blank_end; + volatile u8 v_sync_start; + volatile u8 v_sync_end; + volatile u8 xfer_holdoff_start; + volatile u8 xfer_holdoff_end; +}; + +/* Offset of interesting structures in the OBIO space */ +#define CG3_REGS_OFFSET 0x400000UL +#define CG3_RAM_OFFSET 0x800000UL + +struct cg3_par { + spinlock_t lock; + struct cg3_regs __iomem *regs; + u32 sw_cmap[((256 * 3) + 3) / 4]; + + u32 flags; +#define CG3_FLAG_BLANKED 0x00000001 +#define CG3_FLAG_RDI 0x00000002 + + unsigned long physbase; + unsigned long fbsize; + + struct sbus_dev *sdev; + struct list_head list; +}; + +/** + * cg3_setcolreg - Optional function. Sets a color register. + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @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. + * @info: frame buffer info structure + * + * The cg3 palette is loaded with 4 color values at each time + * so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on. + * We keep a sw copy of the hw cmap to assist us in this esoteric + * loading procedure. + */ +static int cg3_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct cg3_par *par = (struct cg3_par *) info->par; + struct bt_regs __iomem *bt = &par->regs->cmap; + unsigned long flags; + u32 *p32; + u8 *p8; + int count; + + if (regno >= 256) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + spin_lock_irqsave(&par->lock, flags); + + p8 = (u8 *)par->sw_cmap + (regno * 3); + p8[0] = red; + p8[1] = green; + p8[2] = blue; + +#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */ +#define D4M4(x) ((x)&~0x3) /* (x/4)*4 */ + + count = 3; + p32 = &par->sw_cmap[D4M3(regno)]; + sbus_writel(D4M4(regno), &bt->addr); + while (count--) + sbus_writel(*p32++, &bt->color_map); + +#undef D4M3 +#undef D4M4 + + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +/** + * cg3_blank - Optional function. Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + */ +static int +cg3_blank(int blank, struct fb_info *info) +{ + struct cg3_par *par = (struct cg3_par *) info->par; + struct cg3_regs __iomem *regs = par->regs; + unsigned long flags; + u8 val; + + spin_lock_irqsave(&par->lock, flags); + + switch (blank) { + case FB_BLANK_UNBLANK: /* Unblanking */ + val = sbus_readb(®s->control); + val |= CG3_CR_ENABLE_VIDEO; + sbus_writeb(val, ®s->control); + par->flags &= ~CG3_FLAG_BLANKED; + break; + + case FB_BLANK_NORMAL: /* Normal blanking */ + case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ + case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ + case FB_BLANK_POWERDOWN: /* Poweroff */ + val = sbus_readb(®s->control); + val &= ~CG3_CR_ENABLE_VIDEO; + sbus_writeb(val, ®s->control); + par->flags |= CG3_FLAG_BLANKED; + break; + } + + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +static struct sbus_mmap_map cg3_mmap_map[] = { + { + .voff = CG3_MMAP_OFFSET, + .poff = CG3_RAM_OFFSET, + .size = SBUS_MMAP_FBSIZE(1) + }, + { .size = 0 } +}; + +static int cg3_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) +{ + struct cg3_par *par = (struct cg3_par *)info->par; + + return sbusfb_mmap_helper(cg3_mmap_map, + par->physbase, par->fbsize, + par->sdev->reg_addrs[0].which_io, + vma); +} + +static int cg3_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *info) +{ + struct cg3_par *par = (struct cg3_par *) info->par; + + return sbusfb_ioctl_helper(cmd, arg, info, + FBTYPE_SUN3COLOR, 8, par->fbsize); +} + +/* + * Initialisation + */ + +static void +cg3_init_fix(struct fb_info *info, int linebytes) +{ + struct cg3_par *par = (struct cg3_par *)info->par; + + strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id)); + + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + + info->fix.line_length = linebytes; + + info->fix.accel = FB_ACCEL_SUN_CGTHREE; +} + +static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var, + struct sbus_dev *sdev) +{ + char buffer[40]; + char *p; + int ww, hh; + + *buffer = 0; + prom_getstring(sdev->prom_node, "params", buffer, sizeof(buffer)); + if (*buffer) { + ww = simple_strtoul(buffer, &p, 10); + if (ww && *p == 'x') { + hh = simple_strtoul(p + 1, &p, 10); + if (hh && *p == '-') { + if (var->xres != ww || + var->yres != hh) { + var->xres = var->xres_virtual = ww; + var->yres = var->yres_virtual = hh; + } + } + } + } +} + +static u8 cg3regvals_66hz[] __initdata = { /* 1152 x 900, 66 Hz */ + 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14, + 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24, + 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x20, 0 +}; + +static u8 cg3regvals_76hz[] __initdata = { /* 1152 x 900, 76 Hz */ + 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f, + 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a, + 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x24, 0 +}; + +static u8 cg3regvals_rdi[] __initdata = { /* 640 x 480, cgRDI */ + 0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10, + 0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51, + 0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x22, 0 +}; + +static u8 *cg3_regvals[] __initdata = { + cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi +}; + +static u_char cg3_dacvals[] __initdata = { + 4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0 +}; + +static void cg3_do_default_mode(struct cg3_par *par) +{ + enum cg3_type type; + u8 *p; + + if (par->flags & CG3_FLAG_RDI) + type = CG3_RDI; + else { + u8 status = sbus_readb(&par->regs->status), mon; + if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) { + mon = status & CG3_SR_RES_MASK; + if (mon == CG3_SR_1152_900_76_A || + mon == CG3_SR_1152_900_76_B) + type = CG3_AT_76HZ; + else + type = CG3_AT_66HZ; + } else { + prom_printf("cgthree: can't handle SR %02x\n", + status); + prom_halt(); + return; + } + } + + for (p = cg3_regvals[type]; *p; p += 2) { + u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]]; + sbus_writeb(p[1], regp); + } + for (p = cg3_dacvals; *p; p += 2) { + volatile u8 __iomem *regp; + + regp = (volatile u8 __iomem *)&par->regs->cmap.addr; + sbus_writeb(p[0], regp); + regp = (volatile u8 __iomem *)&par->regs->cmap.control; + sbus_writeb(p[1], regp); + } +} + +struct all_info { + struct fb_info info; + struct cg3_par par; + struct list_head list; +}; +static LIST_HEAD(cg3_list); + +static void cg3_init_one(struct sbus_dev *sdev) +{ + struct all_info *all; + int linebytes; + + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "cg3: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); + + INIT_LIST_HEAD(&all->list); + + spin_lock_init(&all->par.lock); + all->par.sdev = sdev; + + all->par.physbase = sdev->reg_addrs[0].phys_addr; + + sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); + all->info.var.red.length = 8; + all->info.var.green.length = 8; + all->info.var.blue.length = 8; + if (!strcmp(sdev->prom_name, "cgRDI")) + all->par.flags |= CG3_FLAG_RDI; + if (all->par.flags & CG3_FLAG_RDI) + cg3_rdi_maybe_fixup_var(&all->info.var, sdev); + + linebytes = prom_getintdefault(sdev->prom_node, "linebytes", + all->info.var.xres); + all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + + all->par.regs = sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET, + sizeof(struct cg3_regs), "cg3 regs"); + + all->info.flags = FBINFO_DEFAULT; + all->info.fbops = &cg3_ops; +#ifdef CONFIG_SPARC32 + all->info.screen_base = (char __iomem *) + prom_getintdefault(sdev->prom_node, "address", 0); +#endif + if (!all->info.screen_base) + all->info.screen_base = + sbus_ioremap(&sdev->resource[0], CG3_RAM_OFFSET, + all->par.fbsize, "cg3 ram"); + all->info.par = &all->par; + + cg3_blank(0, &all->info); + + if (!prom_getbool(sdev->prom_node, "width")) + cg3_do_default_mode(&all->par); + + if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { + printk(KERN_ERR "cg3: Could not allocate color map.\n"); + kfree(all); + return; + } + fb_set_cmap(&all->info.cmap, &all->info); + + cg3_init_fix(&all->info, linebytes); + + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "cg3: Could not register framebuffer.\n"); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + return; + } + + list_add(&all->list, &cg3_list); + + printk("cg3: %s at %lx:%lx\n", + sdev->prom_name, + (long) sdev->reg_addrs[0].which_io, + (long) sdev->reg_addrs[0].phys_addr); +} + +int __init cg3_init(void) +{ + struct sbus_bus *sbus; + struct sbus_dev *sdev; + + if (fb_get_options("cg3fb", NULL)) + return -ENODEV; + + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "cgthree") || + !strcmp(sdev->prom_name, "cgRDI")) + cg3_init_one(sdev); + } + + return 0; +} + +void __exit cg3_exit(void) +{ + struct list_head *pos, *tmp; + + list_for_each_safe(pos, tmp, &cg3_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } +} + +int __init +cg3_setup(char *arg) +{ + /* No cmdline options yet... */ + return 0; +} + +module_init(cg3_init); + +#ifdef MODULE +module_exit(cg3_exit); +#endif + +MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets"); +MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c new file mode 100644 index 000000000000..49a2545671d9 --- /dev/null +++ b/drivers/video/cg6.c @@ -0,0 +1,801 @@ +/* cg6.c: CGSIX (GX, GXplus, TGX) frame buffer driver + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + * + * Driver layout based loosely on tgafb.c, see that file for credits. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <linux/mm.h> + +#include <asm/io.h> +#include <asm/sbus.h> +#include <asm/oplib.h> +#include <asm/fbio.h> + +#include "sbuslib.h" + +/* + * Local functions. + */ + +static int cg6_setcolreg(unsigned, unsigned, unsigned, unsigned, + unsigned, struct fb_info *); +static int cg6_blank(int, struct fb_info *); + +static void cg6_imageblit(struct fb_info *, const struct fb_image *); +static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *); +static int cg6_sync(struct fb_info *); +static int cg6_mmap(struct fb_info *, struct file *, struct vm_area_struct *); +static int cg6_ioctl(struct inode *, struct file *, unsigned int, + unsigned long, struct fb_info *); + +/* + * Frame buffer operations + */ + +static struct fb_ops cg6_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = cg6_setcolreg, + .fb_blank = cg6_blank, + .fb_fillrect = cg6_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cg6_imageblit, + .fb_sync = cg6_sync, + .fb_mmap = cg6_mmap, + .fb_ioctl = cg6_ioctl, + .fb_cursor = soft_cursor, +}; + +/* Offset of interesting structures in the OBIO space */ +/* + * Brooktree is the video dac and is funny to program on the cg6. + * (it's even funnier on the cg3) + * The FBC could be the frame buffer control + * The FHC could is the frame buffer hardware control. + */ +#define CG6_ROM_OFFSET 0x0UL +#define CG6_BROOKTREE_OFFSET 0x200000UL +#define CG6_DHC_OFFSET 0x240000UL +#define CG6_ALT_OFFSET 0x280000UL +#define CG6_FHC_OFFSET 0x300000UL +#define CG6_THC_OFFSET 0x301000UL +#define CG6_FBC_OFFSET 0x700000UL +#define CG6_TEC_OFFSET 0x701000UL +#define CG6_RAM_OFFSET 0x800000UL + +/* FHC definitions */ +#define CG6_FHC_FBID_SHIFT 24 +#define CG6_FHC_FBID_MASK 255 +#define CG6_FHC_REV_SHIFT 20 +#define CG6_FHC_REV_MASK 15 +#define CG6_FHC_FROP_DISABLE (1 << 19) +#define CG6_FHC_ROW_DISABLE (1 << 18) +#define CG6_FHC_SRC_DISABLE (1 << 17) +#define CG6_FHC_DST_DISABLE (1 << 16) +#define CG6_FHC_RESET (1 << 15) +#define CG6_FHC_LITTLE_ENDIAN (1 << 13) +#define CG6_FHC_RES_MASK (3 << 11) +#define CG6_FHC_1024 (0 << 11) +#define CG6_FHC_1152 (1 << 11) +#define CG6_FHC_1280 (2 << 11) +#define CG6_FHC_1600 (3 << 11) +#define CG6_FHC_CPU_MASK (3 << 9) +#define CG6_FHC_CPU_SPARC (0 << 9) +#define CG6_FHC_CPU_68020 (1 << 9) +#define CG6_FHC_CPU_386 (2 << 9) +#define CG6_FHC_TEST (1 << 8) +#define CG6_FHC_TEST_X_SHIFT 4 +#define CG6_FHC_TEST_X_MASK 15 +#define CG6_FHC_TEST_Y_SHIFT 0 +#define CG6_FHC_TEST_Y_MASK 15 + +/* FBC mode definitions */ +#define CG6_FBC_BLIT_IGNORE 0x00000000 +#define CG6_FBC_BLIT_NOSRC 0x00100000 +#define CG6_FBC_BLIT_SRC 0x00200000 +#define CG6_FBC_BLIT_ILLEGAL 0x00300000 +#define CG6_FBC_BLIT_MASK 0x00300000 + +#define CG6_FBC_VBLANK 0x00080000 + +#define CG6_FBC_MODE_IGNORE 0x00000000 +#define CG6_FBC_MODE_COLOR8 0x00020000 +#define CG6_FBC_MODE_COLOR1 0x00040000 +#define CG6_FBC_MODE_HRMONO 0x00060000 +#define CG6_FBC_MODE_MASK 0x00060000 + +#define CG6_FBC_DRAW_IGNORE 0x00000000 +#define CG6_FBC_DRAW_RENDER 0x00008000 +#define CG6_FBC_DRAW_PICK 0x00010000 +#define CG6_FBC_DRAW_ILLEGAL 0x00018000 +#define CG6_FBC_DRAW_MASK 0x00018000 + +#define CG6_FBC_BWRITE0_IGNORE 0x00000000 +#define CG6_FBC_BWRITE0_ENABLE 0x00002000 +#define CG6_FBC_BWRITE0_DISABLE 0x00004000 +#define CG6_FBC_BWRITE0_ILLEGAL 0x00006000 +#define CG6_FBC_BWRITE0_MASK 0x00006000 + +#define CG6_FBC_BWRITE1_IGNORE 0x00000000 +#define CG6_FBC_BWRITE1_ENABLE 0x00000800 +#define CG6_FBC_BWRITE1_DISABLE 0x00001000 +#define CG6_FBC_BWRITE1_ILLEGAL 0x00001800 +#define CG6_FBC_BWRITE1_MASK 0x00001800 + +#define CG6_FBC_BREAD_IGNORE 0x00000000 +#define CG6_FBC_BREAD_0 0x00000200 +#define CG6_FBC_BREAD_1 0x00000400 +#define CG6_FBC_BREAD_ILLEGAL 0x00000600 +#define CG6_FBC_BREAD_MASK 0x00000600 + +#define CG6_FBC_BDISP_IGNORE 0x00000000 +#define CG6_FBC_BDISP_0 0x00000080 +#define CG6_FBC_BDISP_1 0x00000100 +#define CG6_FBC_BDISP_ILLEGAL 0x00000180 +#define CG6_FBC_BDISP_MASK 0x00000180 + +#define CG6_FBC_INDEX_MOD 0x00000040 +#define CG6_FBC_INDEX_MASK 0x00000030 + +/* THC definitions */ +#define CG6_THC_MISC_REV_SHIFT 16 +#define CG6_THC_MISC_REV_MASK 15 +#define CG6_THC_MISC_RESET (1 << 12) +#define CG6_THC_MISC_VIDEO (1 << 10) +#define CG6_THC_MISC_SYNC (1 << 9) +#define CG6_THC_MISC_VSYNC (1 << 8) +#define CG6_THC_MISC_SYNC_ENAB (1 << 7) +#define CG6_THC_MISC_CURS_RES (1 << 6) +#define CG6_THC_MISC_INT_ENAB (1 << 5) +#define CG6_THC_MISC_INT (1 << 4) +#define CG6_THC_MISC_INIT 0x9f + +/* The contents are unknown */ +struct cg6_tec { + volatile int tec_matrix; + volatile int tec_clip; + volatile int tec_vdc; +}; + +struct cg6_thc { + uint thc_pad0[512]; + volatile uint thc_hs; /* hsync timing */ + volatile uint thc_hsdvs; + volatile uint thc_hd; + volatile uint thc_vs; /* vsync timing */ + volatile uint thc_vd; + volatile uint thc_refresh; + volatile uint thc_misc; + uint thc_pad1[56]; + volatile uint thc_cursxy; /* cursor x,y position (16 bits each) */ + volatile uint thc_cursmask[32]; /* cursor mask bits */ + volatile uint thc_cursbits[32]; /* what to show where mask enabled */ +}; + +struct cg6_fbc { + u32 xxx0[1]; + volatile u32 mode; + volatile u32 clip; + u32 xxx1[1]; + volatile u32 s; + volatile u32 draw; + volatile u32 blit; + volatile u32 font; + u32 xxx2[24]; + volatile u32 x0, y0, z0, color0; + volatile u32 x1, y1, z1, color1; + volatile u32 x2, y2, z2, color2; + volatile u32 x3, y3, z3, color3; + volatile u32 offx, offy; + u32 xxx3[2]; + volatile u32 incx, incy; + u32 xxx4[2]; + volatile u32 clipminx, clipminy; + u32 xxx5[2]; + volatile u32 clipmaxx, clipmaxy; + u32 xxx6[2]; + volatile u32 fg; + volatile u32 bg; + volatile u32 alu; + volatile u32 pm; + volatile u32 pixelm; + u32 xxx7[2]; + volatile u32 patalign; + volatile u32 pattern[8]; + u32 xxx8[432]; + volatile u32 apointx, apointy, apointz; + u32 xxx9[1]; + volatile u32 rpointx, rpointy, rpointz; + u32 xxx10[5]; + volatile u32 pointr, pointg, pointb, pointa; + volatile u32 alinex, aliney, alinez; + u32 xxx11[1]; + volatile u32 rlinex, rliney, rlinez; + u32 xxx12[5]; + volatile u32 liner, lineg, lineb, linea; + volatile u32 atrix, atriy, atriz; + u32 xxx13[1]; + volatile u32 rtrix, rtriy, rtriz; + u32 xxx14[5]; + volatile u32 trir, trig, trib, tria; + volatile u32 aquadx, aquady, aquadz; + u32 xxx15[1]; + volatile u32 rquadx, rquady, rquadz; + u32 xxx16[5]; + volatile u32 quadr, quadg, quadb, quada; + volatile u32 arectx, arecty, arectz; + u32 xxx17[1]; + volatile u32 rrectx, rrecty, rrectz; + u32 xxx18[5]; + volatile u32 rectr, rectg, rectb, recta; +}; + +struct bt_regs { + volatile u32 addr; + volatile u32 color_map; + volatile u32 control; + volatile u32 cursor; +}; + +struct cg6_par { + spinlock_t lock; + struct bt_regs __iomem *bt; + struct cg6_fbc __iomem *fbc; + struct cg6_thc __iomem *thc; + struct cg6_tec __iomem *tec; + volatile u32 __iomem *fhc; + + u32 flags; +#define CG6_FLAG_BLANKED 0x00000001 + + unsigned long physbase; + unsigned long fbsize; + + struct sbus_dev *sdev; + struct list_head list; +}; + +static int cg6_sync(struct fb_info *info) +{ + struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_fbc __iomem *fbc = par->fbc; + int limit = 10000; + + do { + if (!(sbus_readl(&fbc->s) & 0x10000000)) + break; + udelay(10); + } while (--limit > 0); + + return 0; +} + +/** + * cg6_fillrect - REQUIRED function. Can use generic routines if + * non acclerated hardware and packed pixel based. + * Draws a rectangle on the screen. + * + * @info: frame buffer structure that represents a single frame buffer + * @rect: structure defining the rectagle and operation. + */ +static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_fbc __iomem *fbc = par->fbc; + unsigned long flags; + s32 val; + + /* XXX doesn't handle ROP_XOR */ + + spin_lock_irqsave(&par->lock, flags); + cg6_sync(info); + sbus_writel(rect->color, &fbc->fg); + sbus_writel(~(u32)0, &fbc->pixelm); + sbus_writel(0xea80ff00, &fbc->alu); + sbus_writel(0, &fbc->s); + sbus_writel(0, &fbc->clip); + sbus_writel(~(u32)0, &fbc->pm); + sbus_writel(rect->dy, &fbc->arecty); + sbus_writel(rect->dx, &fbc->arectx); + sbus_writel(rect->dy + rect->height, &fbc->arecty); + sbus_writel(rect->dx + rect->width, &fbc->arectx); + do { + val = sbus_readl(&fbc->draw); + } while (val < 0 && (val & 0x20000000)); + spin_unlock_irqrestore(&par->lock, flags); +} + +/** + * cg6_imageblit - REQUIRED function. Can use generic routines if + * non acclerated hardware and packed pixel based. + * Copies a image from system memory to the screen. + * + * @info: frame buffer structure that represents a single frame buffer + * @image: structure defining the image. + */ +static void cg6_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_fbc __iomem *fbc = par->fbc; + const u8 *data = image->data; + unsigned long flags; + u32 x, y; + int i, width; + + if (image->depth > 1) { + cfb_imageblit(info, image); + return; + } + + spin_lock_irqsave(&par->lock, flags); + + cg6_sync(info); + + sbus_writel(image->fg_color, &fbc->fg); + sbus_writel(image->bg_color, &fbc->bg); + sbus_writel(0x140000, &fbc->mode); + sbus_writel(0xe880fc30, &fbc->alu); + sbus_writel(~(u32)0, &fbc->pixelm); + sbus_writel(0, &fbc->s); + sbus_writel(0, &fbc->clip); + sbus_writel(0xff, &fbc->pm); + sbus_writel(32, &fbc->incx); + sbus_writel(0, &fbc->incy); + + x = image->dx; + y = image->dy; + for (i = 0; i < image->height; i++) { + width = image->width; + + while (width >= 32) { + u32 val; + + sbus_writel(y, &fbc->y0); + sbus_writel(x, &fbc->x0); + sbus_writel(x + 32 - 1, &fbc->x1); + + val = ((u32)data[0] << 24) | + ((u32)data[1] << 16) | + ((u32)data[2] << 8) | + ((u32)data[3] << 0); + sbus_writel(val, &fbc->font); + + data += 4; + x += 32; + width -= 32; + } + if (width) { + u32 val; + + sbus_writel(y, &fbc->y0); + sbus_writel(x, &fbc->x0); + sbus_writel(x + width - 1, &fbc->x1); + if (width <= 8) { + val = (u32) data[0] << 24; + data += 1; + } else if (width <= 16) { + val = ((u32) data[0] << 24) | + ((u32) data[1] << 16); + data += 2; + } else { + val = ((u32) data[0] << 24) | + ((u32) data[1] << 16) | + ((u32) data[2] << 8); + data += 3; + } + sbus_writel(val, &fbc->font); + } + + y += 1; + x = image->dx; + } + + spin_unlock_irqrestore(&par->lock, flags); +} + +/** + * cg6_setcolreg - Optional function. Sets a color register. + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @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. + * @info: frame buffer info structure + */ +static int cg6_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct cg6_par *par = (struct cg6_par *) info->par; + struct bt_regs __iomem *bt = par->bt; + unsigned long flags; + + if (regno >= 256) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + spin_lock_irqsave(&par->lock, flags); + + sbus_writel((u32)regno << 24, &bt->addr); + sbus_writel((u32)red << 24, &bt->color_map); + sbus_writel((u32)green << 24, &bt->color_map); + sbus_writel((u32)blue << 24, &bt->color_map); + + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +/** + * cg6_blank - Optional function. Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + */ +static int +cg6_blank(int blank, struct fb_info *info) +{ + struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_thc __iomem *thc = par->thc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&par->lock, flags); + + switch (blank) { + case FB_BLANK_UNBLANK: /* Unblanking */ + val = sbus_readl(&thc->thc_misc); + val |= CG6_THC_MISC_VIDEO; + sbus_writel(val, &thc->thc_misc); + par->flags &= ~CG6_FLAG_BLANKED; + break; + + case FB_BLANK_NORMAL: /* Normal blanking */ + case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ + case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ + case FB_BLANK_POWERDOWN: /* Poweroff */ + val = sbus_readl(&thc->thc_misc); + val &= ~CG6_THC_MISC_VIDEO; + sbus_writel(val, &thc->thc_misc); + par->flags |= CG6_FLAG_BLANKED; + break; + } + + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +static struct sbus_mmap_map cg6_mmap_map[] = { + { + .voff = CG6_FBC, + .poff = CG6_FBC_OFFSET, + .size = PAGE_SIZE + }, + { + .voff = CG6_TEC, + .poff = CG6_TEC_OFFSET, + .size = PAGE_SIZE + }, + { + .voff = CG6_BTREGS, + .poff = CG6_BROOKTREE_OFFSET, + .size = PAGE_SIZE + }, + { + .voff = CG6_FHC, + .poff = CG6_FHC_OFFSET, + .size = PAGE_SIZE + }, + { + .voff = CG6_THC, + .poff = CG6_THC_OFFSET, + .size = PAGE_SIZE + }, + { + .voff = CG6_ROM, + .poff = CG6_ROM_OFFSET, + .size = 0x10000 + }, + { + .voff = CG6_RAM, + .poff = CG6_RAM_OFFSET, + .size = SBUS_MMAP_FBSIZE(1) + }, + { + .voff = CG6_DHC, + .poff = CG6_DHC_OFFSET, + .size = 0x40000 + }, + { .size = 0 } +}; + +static int cg6_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) +{ + struct cg6_par *par = (struct cg6_par *)info->par; + + return sbusfb_mmap_helper(cg6_mmap_map, + par->physbase, par->fbsize, + par->sdev->reg_addrs[0].which_io, + vma); +} + +static int cg6_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *info) +{ + struct cg6_par *par = (struct cg6_par *) info->par; + + return sbusfb_ioctl_helper(cmd, arg, info, + FBTYPE_SUNFAST_COLOR, 8, par->fbsize); +} + +/* + * Initialisation + */ + +static void +cg6_init_fix(struct fb_info *info, int linebytes) +{ + struct cg6_par *par = (struct cg6_par *)info->par; + const char *cg6_cpu_name, *cg6_card_name; + u32 conf; + + conf = sbus_readl(par->fhc); + switch(conf & CG6_FHC_CPU_MASK) { + case CG6_FHC_CPU_SPARC: + cg6_cpu_name = "sparc"; + break; + case CG6_FHC_CPU_68020: + cg6_cpu_name = "68020"; + break; + default: + cg6_cpu_name = "i386"; + break; + }; + if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) { + if (par->fbsize <= 0x100000) { + cg6_card_name = "TGX"; + } else { + cg6_card_name = "TGX+"; + } + } else { + if (par->fbsize <= 0x100000) { + cg6_card_name = "GX"; + } else { + cg6_card_name = "GX+"; + } + } + + sprintf(info->fix.id, "%s %s", cg6_card_name, cg6_cpu_name); + info->fix.id[sizeof(info->fix.id)-1] = 0; + + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + + info->fix.line_length = linebytes; + + info->fix.accel = FB_ACCEL_SUN_CGSIX; +} + +/* Initialize Brooktree DAC */ +static void cg6_bt_init(struct cg6_par *par) +{ + struct bt_regs __iomem *bt = par->bt; + + sbus_writel(0x04 << 24, &bt->addr); /* color planes */ + sbus_writel(0xff << 24, &bt->control); + sbus_writel(0x05 << 24, &bt->addr); + sbus_writel(0x00 << 24, &bt->control); + sbus_writel(0x06 << 24, &bt->addr); /* overlay plane */ + sbus_writel(0x73 << 24, &bt->control); + sbus_writel(0x07 << 24, &bt->addr); + sbus_writel(0x00 << 24, &bt->control); +} + +static void cg6_chip_init(struct fb_info *info) +{ + struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_tec __iomem *tec = par->tec; + struct cg6_fbc __iomem *fbc = par->fbc; + u32 rev, conf, mode, tmp; + int i; + + /* Turn off stuff in the Transform Engine. */ + sbus_writel(0, &tec->tec_matrix); + sbus_writel(0, &tec->tec_clip); + sbus_writel(0, &tec->tec_vdc); + + /* Take care of bugs in old revisions. */ + rev = (sbus_readl(par->fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK; + if (rev < 5) { + conf = (sbus_readl(par->fhc) & CG6_FHC_RES_MASK) | + CG6_FHC_CPU_68020 | CG6_FHC_TEST | + (11 << CG6_FHC_TEST_X_SHIFT) | + (11 << CG6_FHC_TEST_Y_SHIFT); + if (rev < 2) + conf |= CG6_FHC_DST_DISABLE; + sbus_writel(conf, par->fhc); + } + + /* Set things in the FBC. Bad things appear to happen if we do + * back to back store/loads on the mode register, so copy it + * out instead. */ + mode = sbus_readl(&fbc->mode); + do { + i = sbus_readl(&fbc->s); + } while (i & 0x10000000); + mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK | + CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK | + CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK | + CG6_FBC_BDISP_MASK); + mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 | + CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE | + CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 | + CG6_FBC_BDISP_0); + sbus_writel(mode, &fbc->mode); + + sbus_writel(0, &fbc->clip); + sbus_writel(0, &fbc->offx); + sbus_writel(0, &fbc->offy); + sbus_writel(0, &fbc->clipminx); + sbus_writel(0, &fbc->clipminy); + sbus_writel(info->var.xres - 1, &fbc->clipmaxx); + sbus_writel(info->var.yres - 1, &fbc->clipmaxy); + + /* Disable cursor in Brooktree DAC. */ + sbus_writel(0x06 << 24, &par->bt->addr); + tmp = sbus_readl(&par->bt->control); + tmp &= ~(0x03 << 24); + sbus_writel(tmp, &par->bt->control); +} + +struct all_info { + struct fb_info info; + struct cg6_par par; + struct list_head list; +}; +static LIST_HEAD(cg6_list); + +static void cg6_init_one(struct sbus_dev *sdev) +{ + struct all_info *all; + int linebytes; + + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "cg6: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); + + INIT_LIST_HEAD(&all->list); + + spin_lock_init(&all->par.lock); + all->par.sdev = sdev; + + all->par.physbase = sdev->reg_addrs[0].phys_addr; + + sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); + all->info.var.red.length = 8; + all->info.var.green.length = 8; + all->info.var.blue.length = 8; + + linebytes = prom_getintdefault(sdev->prom_node, "linebytes", + all->info.var.xres); + all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + if (prom_getbool(sdev->prom_node, "dblbuf")) + all->par.fbsize *= 4; + + all->par.fbc = sbus_ioremap(&sdev->resource[0], CG6_FBC_OFFSET, + 4096, "cgsix fbc"); + all->par.tec = sbus_ioremap(&sdev->resource[0], CG6_TEC_OFFSET, + sizeof(struct cg6_tec), "cgsix tec"); + all->par.thc = sbus_ioremap(&sdev->resource[0], CG6_THC_OFFSET, + sizeof(struct cg6_thc), "cgsix thc"); + all->par.bt = sbus_ioremap(&sdev->resource[0], CG6_BROOKTREE_OFFSET, + sizeof(struct bt_regs), "cgsix dac"); + all->par.fhc = sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET, + sizeof(u32), "cgsix fhc"); + + all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT | + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; + all->info.fbops = &cg6_ops; +#ifdef CONFIG_SPARC32 + all->info.screen_base = (char __iomem *) + prom_getintdefault(sdev->prom_node, "address", 0); +#endif + if (!all->info.screen_base) + all->info.screen_base = + sbus_ioremap(&sdev->resource[0], CG6_RAM_OFFSET, + all->par.fbsize, "cgsix ram"); + all->info.par = &all->par; + + all->info.var.accel_flags = FB_ACCELF_TEXT; + + cg6_bt_init(&all->par); + cg6_chip_init(&all->info); + cg6_blank(0, &all->info); + + if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { + printk(KERN_ERR "cg6: Could not allocate color map.\n"); + kfree(all); + return; + } + + fb_set_cmap(&all->info.cmap, &all->info); + cg6_init_fix(&all->info, linebytes); + + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "cg6: Could not register framebuffer.\n"); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + return; + } + + list_add(&all->list, &cg6_list); + + printk("cg6: CGsix [%s] at %lx:%lx\n", + all->info.fix.id, + (long) sdev->reg_addrs[0].which_io, + (long) sdev->reg_addrs[0].phys_addr); +} + +int __init cg6_init(void) +{ + struct sbus_bus *sbus; + struct sbus_dev *sdev; + + if (fb_get_options("cg6fb", NULL)) + return -ENODEV; + + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "cgsix") || + !strcmp(sdev->prom_name, "cgthree+")) + cg6_init_one(sdev); + } + + return 0; +} + +void __exit cg6_exit(void) +{ + struct list_head *pos, *tmp; + + list_for_each_safe(pos, tmp, &cg6_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } +} + +int __init +cg6_setup(char *arg) +{ + /* No cmdline options yet... */ + return 0; +} + +module_init(cg6_init); + +#ifdef MODULE +module_exit(cg6_exit); +#endif + +MODULE_DESCRIPTION("framebuffer driver for CGsix chipsets"); +MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c new file mode 100644 index 000000000000..ab98f225fe3e --- /dev/null +++ b/drivers/video/chipsfb.c @@ -0,0 +1,522 @@ +/* + * drivers/video/chipsfb.c -- frame buffer device for + * Chips & Technologies 65550 chip. + * + * Copyright (C) 1998-2002 Paul Mackerras + * + * This file is derived from the Powermac "chips" driver: + * Copyright (C) 1997 Fabio Riccardi. + * And from the frame buffer device for Open Firmware-initialized devices: + * Copyright (C) 1997 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. + */ + +#include <linux/config.h> +#include <linux/module.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <asm/io.h> + +#ifdef CONFIG_PMAC_BACKLIGHT +#include <asm/backlight.h> +#endif +#ifdef CONFIG_PMAC_PBOOK +#include <linux/adb.h> +#include <linux/pmu.h> +#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)); \ +} while (0) +#define read_ind(num, var, ap, dp) do { \ + outb((num), (ap)); var = inb((dp)); \ +} while (0) + +/* extension registers */ +#define write_xr(num, val) write_ind(num, val, 0x3d6, 0x3d7) +#define read_xr(num, var) read_ind(num, var, 0x3d6, 0x3d7) +/* flat panel registers */ +#define write_fr(num, val) write_ind(num, val, 0x3d0, 0x3d1) +#define read_fr(num, var) read_ind(num, var, 0x3d0, 0x3d1) +/* CRTC registers */ +#define write_cr(num, val) write_ind(num, val, 0x3d4, 0x3d5) +#define read_cr(num, var) read_ind(num, var, 0x3d4, 0x3d5) +/* graphics registers */ +#define write_gr(num, val) write_ind(num, val, 0x3ce, 0x3cf) +#define read_gr(num, var) read_ind(num, var, 0x3ce, 0x3cf) +/* sequencer registers */ +#define write_sr(num, val) write_ind(num, val, 0x3c4, 0x3c5) +#define read_sr(num, var) read_ind(num, var, 0x3c4, 0x3c5) +/* attribute registers - slightly strange */ +#define write_ar(num, val) do { \ + inb(0x3da); write_ind(num, val, 0x3c0, 0x3c0); \ +} while (0) +#define read_ar(num, var) do { \ + inb(0x3da); read_ind(num, var, 0x3c0, 0x3c1); \ +} while (0) + +#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, +}; +#endif + +/* + * Exported functions + */ +int chips_init(void); + +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_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_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + 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) + || var->nonstd + || (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + return -EINVAL; + + var->xres = var->xres_virtual = 800; + var->yres = var->yres_virtual = 600; + + return 0; +} + +static int chipsfb_set_par(struct fb_info *info) +{ + 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 chipsfb_blank(int blank, struct fb_info *info) +{ +#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) + set_backlight_enable(!blank); +#endif /* CONFIG_PMAC_BACKLIGHT */ + + 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) +{ + if (regno > 255) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + outb(regno, 0x3c8); + udelay(1); + outb(red, 0x3c9); + outb(green, 0x3c9); + outb(blue, 0x3c9); + + return 0; +} + +struct chips_init_reg { + unsigned char addr; + unsigned char data; +}; + +#define N_ELTS(x) (sizeof(x) / sizeof(x[0])) + +static struct chips_init_reg chips_init_sr[] = { + { 0x00, 0x03 }, + { 0x01, 0x01 }, + { 0x02, 0x0f }, + { 0x04, 0x0e } +}; + +static struct chips_init_reg chips_init_gr[] = { + { 0x05, 0x00 }, + { 0x06, 0x0d }, + { 0x08, 0xff } +}; + +static struct chips_init_reg chips_init_ar[] = { + { 0x10, 0x01 }, + { 0x12, 0x0f }, + { 0x13, 0x00 } +}; + +static struct chips_init_reg chips_init_cr[] = { + { 0x00, 0x7f }, + { 0x01, 0x63 }, + { 0x02, 0x63 }, + { 0x03, 0x83 }, + { 0x04, 0x66 }, + { 0x05, 0x10 }, + { 0x06, 0x72 }, + { 0x07, 0x3e }, + { 0x08, 0x00 }, + { 0x09, 0x40 }, + { 0x0c, 0x00 }, + { 0x0d, 0x00 }, + { 0x10, 0x59 }, + { 0x11, 0x0d }, + { 0x12, 0x57 }, + { 0x13, 0x64 }, + { 0x14, 0x00 }, + { 0x15, 0x57 }, + { 0x16, 0x73 }, + { 0x17, 0xe3 }, + { 0x18, 0xff }, + { 0x30, 0x02 }, + { 0x31, 0x02 }, + { 0x32, 0x02 }, + { 0x33, 0x02 }, + { 0x40, 0x00 }, + { 0x41, 0x00 }, + { 0x40, 0x80 } +}; + +static struct chips_init_reg chips_init_fr[] = { + { 0x01, 0x02 }, + { 0x03, 0x08 }, + { 0x04, 0x81 }, + { 0x05, 0x21 }, + { 0x08, 0x0c }, + { 0x0a, 0x74 }, + { 0x0b, 0x11 }, + { 0x10, 0x0c }, + { 0x11, 0xe0 }, + /* { 0x12, 0x40 }, -- 3400 needs 40, 2400 needs 48, no way to tell */ + { 0x20, 0x63 }, + { 0x21, 0x68 }, + { 0x22, 0x19 }, + { 0x23, 0x7f }, + { 0x24, 0x68 }, + { 0x26, 0x00 }, + { 0x27, 0x0f }, + { 0x30, 0x57 }, + { 0x31, 0x58 }, + { 0x32, 0x0d }, + { 0x33, 0x72 }, + { 0x34, 0x02 }, + { 0x35, 0x22 }, + { 0x36, 0x02 }, + { 0x37, 0x00 } +}; + +static struct chips_init_reg chips_init_xr[] = { + { 0xce, 0x00 }, /* set default memory clock */ + { 0xcc, 0x43 }, /* memory clock ratio */ + { 0xcd, 0x18 }, + { 0xce, 0xa1 }, + { 0xc8, 0x84 }, + { 0xc9, 0x0a }, + { 0xca, 0x00 }, + { 0xcb, 0x20 }, + { 0xcf, 0x06 }, + { 0xd0, 0x0e }, + { 0x09, 0x01 }, + { 0x0a, 0x02 }, + { 0x0b, 0x01 }, + { 0x20, 0x00 }, + { 0x40, 0x03 }, + { 0x41, 0x01 }, + { 0x42, 0x00 }, + { 0x80, 0x82 }, + { 0x81, 0x12 }, + { 0x82, 0x08 }, + { 0xa0, 0x00 }, + { 0xa8, 0x00 } +}; + +static void __init chips_hw_init(void) +{ + int i; + + for (i = 0; i < N_ELTS(chips_init_xr); ++i) + write_xr(chips_init_xr[i].addr, chips_init_xr[i].data); + outb(0x29, 0x3c2); /* set misc output reg */ + for (i = 0; i < N_ELTS(chips_init_sr); ++i) + write_sr(chips_init_sr[i].addr, chips_init_sr[i].data); + for (i = 0; i < N_ELTS(chips_init_gr); ++i) + write_gr(chips_init_gr[i].addr, chips_init_gr[i].data); + for (i = 0; i < N_ELTS(chips_init_ar); ++i) + write_ar(chips_init_ar[i].addr, chips_init_ar[i].data); + for (i = 0; i < N_ELTS(chips_init_cr); ++i) + write_cr(chips_init_cr[i].addr, chips_init_cr[i].data); + for (i = 0; i < N_ELTS(chips_init_fr); ++i) + write_fr(chips_init_fr[i].addr, chips_init_fr[i].data); +} + +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. +// * 2400 has 1MB composed of 2 Mitsubishi M5M4V4265CTP DRAM chips. +// Motherboard actually supports 2MB -- there are two blank locations +// for a second pair of DRAMs. (Thanks, Apple!) +// * 3400 has 1MB (I think). Don't know if it's expandable. +// -- Tim Seufert + .smem_len = 0x100000, /* 1MB */ +}; + +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, +}; + +static void __init init_chips(struct fb_info *p, unsigned long addr) +{ + p->fix = chipsfb_fix; + p->fix.smem_start = addr; + + p->var = chipsfb_var; + + p->fbops = &chipsfb_ops; + p->flags = FBINFO_DEFAULT; + + 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", + p->node, p->fix.smem_len / 1024); + + chips_hw_init(); +} + +static int __devinit +chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) +{ + struct fb_info *p = &chipsfb_info; + unsigned long addr, size; + unsigned short cmd; + + if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) + return -ENODEV; + addr = pci_resource_start(dp, 0); + size = pci_resource_len(dp, 0); + if (addr == 0) + 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 + + /* we should use pci_enable_device here, but, + the device doesn't declare its I/O ports in its BARs + so pci_enable_device won't turn on I/O responses */ + pci_read_config_word(dp, PCI_COMMAND, &cmd); + cmd |= 3; /* enable memory and IO space */ + pci_write_config_word(dp, PCI_COMMAND, cmd); + +#ifdef CONFIG_PMAC_BACKLIGHT + /* turn on the backlight */ + set_backlight_enable(1); +#endif /* CONFIG_PMAC_BACKLIGHT */ + + p->screen_base = __ioremap(addr, 0x200000, _PAGE_NO_CACHE); + if (p->screen_base == NULL) { + release_mem_region(addr, size); + return -ENOMEM; + } + p->device = &dp->dev; + 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[] = { + { 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) +{ + if (fb_get_options("chipsfb", NULL)) + return -ENODEV; + + return pci_register_driver(&chipsfb_driver); +} + +module_init(chips_init); + +static void __exit chipsfb_exit(void) +{ + pci_unregister_driver(&chipsfb_driver); +} + +#ifdef CONFIG_PMAC_PBOOK +/* + * Save the contents of the frame buffer when we go to sleep, + * and restore it when we wake up again. + */ +int +chips_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + 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 = NULL; + } + 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 = NULL; + } + chipsfb_blank(0, p); + break; + } + return PBOOK_SLEEP_OK; +} +#endif /* CONFIG_PMAC_PBOOK */ + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c new file mode 100644 index 000000000000..a3040429c27b --- /dev/null +++ b/drivers/video/cirrusfb.c @@ -0,0 +1,3326 @@ +/* + * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets + * + * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com> + * + * Contributors (thanks, all!) + * + * David Eger: + * Overhaul for Linux 2.6 + * + * Jeff Rugen: + * Major contributions; Motorola PowerStack (PPC and PCI) support, + * GD54xx, 1280x1024 mode support, change MCLK based on VCLK. + * + * Geert Uytterhoeven: + * Excellent code review. + * + * Lars Hecking: + * Amiga updates and testing. + * + * Original cirrusfb author: Frank Neumann + * + * Based on retz3fb.c and cirrusfb.c: + * Copyright (C) 1997 Jes Sorensen + * Copyright (C) 1996 Frank Neumann + * + *************************************************************** + * + * Format this code with GNU indent '-kr -i8 -pcs' options. + * + * 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. + * + */ + +#define CIRRUSFB_VERSION "2.0-pre2" + +#include <linux/config.h> +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/selection.h> +#include <asm/pgtable.h> + +#ifdef CONFIG_ZORRO +#include <linux/zorro.h> +#endif +#ifdef CONFIG_PCI +#include <linux/pci.h> +#endif +#ifdef CONFIG_AMIGA +#include <asm/amigahw.h> +#endif +#ifdef CONFIG_PPC_PREP +#include <asm/processor.h> +#define isPReP (_machine == _MACH_prep) +#else +#define isPReP 0 +#endif + +#include "video/vga.h" +#include "video/cirrus.h" + + +/***************************************************************** + * + * debugging and utility macros + * + */ + +/* enable debug output? */ +/* #define CIRRUSFB_DEBUG 1 */ + +/* disable runtime assertions? */ +/* #define CIRRUSFB_NDEBUG */ + +/* debug output */ +#ifdef CIRRUSFB_DEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +/* debugging assertions */ +#ifndef CIRRUSFB_NDEBUG +#define assert(expr) \ + if(!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n",\ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#else +#define assert(expr) +#endif + +#ifdef TRUE +#undef TRUE +#endif +#ifdef FALSE +#undef FALSE +#endif +#define TRUE 1 +#define FALSE 0 + +#define MB_ (1024*1024) +#define KB_ (1024) + +#define MAX_NUM_BOARDS 7 + + +/***************************************************************** + * + * chipset information + * + */ + +/* board types */ +typedef enum { + BT_NONE = 0, + BT_SD64, + BT_PICCOLO, + BT_PICASSO, + BT_SPECTRUM, + BT_PICASSO4, /* GD5446 */ + BT_ALPINE, /* GD543x/4x */ + BT_GD5480, + BT_LAGUNA, /* GD546x */ +} cirrusfb_board_t; + + +/* + * per-board-type information, used for enumerating and abstracting + * chip-specific information + * NOTE: MUST be in the same order as cirrusfb_board_t in order to + * use direct indexing on this array + * NOTE: '__initdata' cannot be used as some of this info + * is required at runtime. Maybe separate into an init-only and + * a run-time table? + */ +static const struct cirrusfb_board_info_rec { + char *name; /* ASCII name of chipset */ + long maxclock[5]; /* maximum video clock */ + /* for 1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */ + unsigned init_sr07 : 1; /* init SR07 during init_vgachip() */ + unsigned init_sr1f : 1; /* write SR1F during init_vgachip() */ + unsigned scrn_start_bit19 : 1; /* construct bit 19 of screen start address */ + + /* initial SR07 value, then for each mode */ + unsigned char sr07; + unsigned char sr07_1bpp; + unsigned char sr07_1bpp_mux; + unsigned char sr07_8bpp; + unsigned char sr07_8bpp_mux; + + unsigned char sr1f; /* SR1F VGA initial register value */ +} cirrusfb_board_info[] = { + [BT_SD64] = { + .name = "CL SD64", + .maxclock = { + /* guess */ + /* the SD64/P4 have a higher max. videoclock */ + 140000, 140000, 140000, 140000, 140000, + }, + .init_sr07 = TRUE, + .init_sr1f = TRUE, + .scrn_start_bit19 = TRUE, + .sr07 = 0xF0, + .sr07_1bpp = 0xF0, + .sr07_8bpp = 0xF1, + .sr1f = 0x20 + }, + [BT_PICCOLO] = { + .name = "CL Piccolo", + .maxclock = { + /* guess */ + 90000, 90000, 90000, 90000, 90000 + }, + .init_sr07 = TRUE, + .init_sr1f = TRUE, + .scrn_start_bit19 = FALSE, + .sr07 = 0x80, + .sr07_1bpp = 0x80, + .sr07_8bpp = 0x81, + .sr1f = 0x22 + }, + [BT_PICASSO] = { + .name = "CL Picasso", + .maxclock = { + /* guess */ + 90000, 90000, 90000, 90000, 90000 + }, + .init_sr07 = TRUE, + .init_sr1f = TRUE, + .scrn_start_bit19 = FALSE, + .sr07 = 0x20, + .sr07_1bpp = 0x20, + .sr07_8bpp = 0x21, + .sr1f = 0x22 + }, + [BT_SPECTRUM] = { + .name = "CL Spectrum", + .maxclock = { + /* guess */ + 90000, 90000, 90000, 90000, 90000 + }, + .init_sr07 = TRUE, + .init_sr1f = TRUE, + .scrn_start_bit19 = FALSE, + .sr07 = 0x80, + .sr07_1bpp = 0x80, + .sr07_8bpp = 0x81, + .sr1f = 0x22 + }, + [BT_PICASSO4] = { + .name = "CL Picasso4", + .maxclock = { + 135100, 135100, 85500, 85500, 0 + }, + .init_sr07 = TRUE, + .init_sr1f = FALSE, + .scrn_start_bit19 = TRUE, + .sr07 = 0x20, + .sr07_1bpp = 0x20, + .sr07_8bpp = 0x21, + .sr1f = 0 + }, + [BT_ALPINE] = { + .name = "CL Alpine", + .maxclock = { + /* for the GD5430. GD5446 can do more... */ + 85500, 85500, 50000, 28500, 0 + }, + .init_sr07 = TRUE, + .init_sr1f = TRUE, + .scrn_start_bit19 = TRUE, + .sr07 = 0xA0, + .sr07_1bpp = 0xA1, + .sr07_1bpp_mux = 0xA7, + .sr07_8bpp = 0xA1, + .sr07_8bpp_mux = 0xA7, + .sr1f = 0x1C + }, + [BT_GD5480] = { + .name = "CL GD5480", + .maxclock = { + 135100, 200000, 200000, 135100, 135100 + }, + .init_sr07 = TRUE, + .init_sr1f = TRUE, + .scrn_start_bit19 = TRUE, + .sr07 = 0x10, + .sr07_1bpp = 0x11, + .sr07_8bpp = 0x11, + .sr1f = 0x1C + }, + [BT_LAGUNA] = { + .name = "CL Laguna", + .maxclock = { + /* guess */ + 135100, 135100, 135100, 135100, 135100, + }, + .init_sr07 = FALSE, + .init_sr1f = FALSE, + .scrn_start_bit19 = TRUE, + } +}; + + +#ifdef CONFIG_PCI +#define CHIP(id, btype) \ + { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_##id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) } + +static struct pci_device_id cirrusfb_pci_table[] = { + CHIP( CIRRUS_5436, BT_ALPINE ), + CHIP( CIRRUS_5434_8, BT_ALPINE ), + CHIP( CIRRUS_5434_4, BT_ALPINE ), + CHIP( CIRRUS_5430, BT_ALPINE ), /* GD-5440 has identical id */ + CHIP( CIRRUS_7543, BT_ALPINE ), + CHIP( CIRRUS_7548, BT_ALPINE ), + CHIP( CIRRUS_5480, BT_GD5480 ), /* MacPicasso probably */ + CHIP( CIRRUS_5446, BT_PICASSO4 ), /* Picasso 4 is a GD5446 */ + CHIP( CIRRUS_5462, BT_LAGUNA ), /* CL Laguna */ + CHIP( CIRRUS_5464, BT_LAGUNA ), /* CL Laguna 3D */ + CHIP( CIRRUS_5465, BT_LAGUNA ), /* CL Laguna 3DA*/ + { 0, } +}; +MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); +#undef CHIP +#endif /* CONFIG_PCI */ + + +#ifdef CONFIG_ZORRO +static const struct zorro_device_id cirrusfb_zorro_table[] = { + { + .id = ZORRO_PROD_HELFRICH_SD64_RAM, + .driver_data = BT_SD64, + }, { + .id = ZORRO_PROD_HELFRICH_PICCOLO_RAM, + .driver_data = BT_PICCOLO, + }, { + .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, + .driver_data = BT_PICASSO, + }, { + .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, + .driver_data = BT_SPECTRUM, + }, { + .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, + .driver_data = BT_PICASSO4, + }, + { 0 } +}; + +static const struct { + zorro_id id2; + unsigned long size; +} cirrusfb_zorro_table2[] = { + [BT_SD64] = { + .id2 = ZORRO_PROD_HELFRICH_SD64_REG, + .size = 0x400000 + }, + [BT_PICCOLO] = { + .id2 = ZORRO_PROD_HELFRICH_PICCOLO_REG, + .size = 0x200000 + }, + [BT_PICASSO] = { + .id2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, + .size = 0x200000 + }, + [BT_SPECTRUM] = { + .id2 = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, + .size = 0x200000 + }, + [BT_PICASSO4] = { + .id2 = 0, + .size = 0x400000 + } +}; +#endif /* CONFIG_ZORRO */ + + +struct cirrusfb_regs { + __u32 line_length; /* in BYTES! */ + __u32 visual; + __u32 type; + + long freq; + long nom; + long den; + long div; + long multiplexing; + long mclk; + long divMCLK; + + long HorizRes; /* The x resolution in pixel */ + long HorizTotal; + long HorizDispEnd; + long HorizBlankStart; + long HorizBlankEnd; + long HorizSyncStart; + long HorizSyncEnd; + + long VertRes; /* the physical y resolution in scanlines */ + long VertTotal; + long VertDispEnd; + long VertSyncStart; + long VertSyncEnd; + long VertBlankStart; + long VertBlankEnd; +}; + + + +#ifdef CIRRUSFB_DEBUG +typedef enum { + CRT, + SEQ +} cirrusfb_dbg_reg_class_t; +#endif /* CIRRUSFB_DEBUG */ + + + + +/* info about board */ +struct cirrusfb_info { + struct fb_info *info; + + u8 __iomem *fbmem; + u8 __iomem *regbase; + u8 __iomem *mem; + unsigned long size; + cirrusfb_board_t btype; + unsigned char SFR; /* Shadow of special function register */ + + unsigned long fbmem_phys; + unsigned long fbregs_phys; + + struct cirrusfb_regs currentmode; + int blank_mode; + + u32 pseudo_palette[17]; + struct { u8 red, green, blue, pad; } palette[256]; + +#ifdef CONFIG_ZORRO + struct zorro_dev *zdev; +#endif +#ifdef CONFIG_PCI + struct pci_dev *pdev; +#endif + void (*unmap)(struct cirrusfb_info *cinfo); +}; + + +static unsigned cirrusfb_def_mode = 1; +static int noaccel = 0; + +/* + * Predefined Video Modes + */ + +static const struct { + const char *name; + struct fb_var_screeninfo var; +} cirrusfb_predefined[] = { + { + /* autodetect mode */ + .name = "Autodetect", + }, { + /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */ + .name = "640x480", + .var = { + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 480, + .bits_per_pixel = 8, + .red = { .length = 8 }, + .green = { .length = 8 }, + .blue = { .length = 8 }, + .width = -1, + .height = -1, + .pixclock = 40000, + .left_margin = 48, + .right_margin = 16, + .upper_margin = 32, + .lower_margin = 8, + .hsync_len = 96, + .vsync_len = 4, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + } + }, { + /* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */ + .name = "800x600", + .var = { + .xres = 800, + .yres = 600, + .xres_virtual = 800, + .yres_virtual = 600, + .bits_per_pixel = 8, + .red = { .length = 8 }, + .green = { .length = 8 }, + .blue = { .length = 8 }, + .width = -1, + .height = -1, + .pixclock = 20000, + .left_margin = 128, + .right_margin = 16, + .upper_margin = 24, + .lower_margin = 2, + .hsync_len = 96, + .vsync_len = 6, + .vmode = FB_VMODE_NONINTERLACED + } + }, { + /* + * Modeline from XF86Config: + * Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805 + */ + /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */ + .name = "1024x768", + .var = { + .xres = 1024, + .yres = 768, + .xres_virtual = 1024, + .yres_virtual = 768, + .bits_per_pixel = 8, + .red = { .length = 8 }, + .green = { .length = 8 }, + .blue = { .length = 8 }, + .width = -1, + .height = -1, + .pixclock = 12500, + .left_margin = 144, + .right_margin = 32, + .upper_margin = 30, + .lower_margin = 2, + .hsync_len = 192, + .vsync_len = 6, + .vmode = FB_VMODE_NONINTERLACED + } + } +}; + +#define NUM_TOTAL_MODES ARRAY_SIZE(cirrusfb_predefined) + +/****************************************************************************/ +/**** BEGIN PROTOTYPES ******************************************************/ + + +/*--- Interface used by the world ------------------------------------------*/ +static int cirrusfb_init (void); +#ifndef MODULE +static int cirrusfb_setup (char *options); +#endif + +static int cirrusfb_open (struct fb_info *info, int user); +static int cirrusfb_release (struct fb_info *info, int user); +static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info); +static int cirrusfb_check_var (struct fb_var_screeninfo *var, + struct fb_info *info); +static int cirrusfb_set_par (struct fb_info *info); +static int cirrusfb_pan_display (struct fb_var_screeninfo *var, + struct fb_info *info); +static int cirrusfb_blank (int blank_mode, struct fb_info *info); +static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region); +static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); +static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image); + +/* function table of the above functions */ +static struct fb_ops cirrusfb_ops = { + .owner = THIS_MODULE, + .fb_open = cirrusfb_open, + .fb_release = cirrusfb_release, + .fb_setcolreg = cirrusfb_setcolreg, + .fb_check_var = cirrusfb_check_var, + .fb_set_par = cirrusfb_set_par, + .fb_pan_display = cirrusfb_pan_display, + .fb_blank = cirrusfb_blank, + .fb_fillrect = cirrusfb_fillrect, + .fb_copyarea = cirrusfb_copyarea, + .fb_imageblit = cirrusfb_imageblit, + .fb_cursor = soft_cursor, +}; + +/*--- Hardware Specific Routines -------------------------------------------*/ +static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, + struct cirrusfb_regs *regs, + const struct fb_info *info); +/*--- Internal routines ----------------------------------------------------*/ +static void init_vgachip (struct cirrusfb_info *cinfo); +static void switch_monitor (struct cirrusfb_info *cinfo, int on); +static void WGen (const struct cirrusfb_info *cinfo, + int regnum, unsigned char val); +static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum); +static void AttrOn (const struct cirrusfb_info *cinfo); +static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val); +static void WSFR (struct cirrusfb_info *cinfo, unsigned char val); +static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val); +static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red, + unsigned char green, + unsigned char blue); +#if 0 +static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red, + unsigned char *green, + unsigned char *blue); +#endif +static void cirrusfb_WaitBLT (u8 __iomem *regbase); +static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel, + u_short curx, u_short cury, + u_short destx, u_short desty, + u_short width, u_short height, + u_short line_length); +static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel, + u_short x, u_short y, + u_short width, u_short height, + u_char color, u_short line_length); + +static void bestclock (long freq, long *best, + long *nom, long *den, + long *div, long maxfreq); + +#ifdef CIRRUSFB_DEBUG +static void cirrusfb_dump (void); +static void cirrusfb_dbg_reg_dump (caddr_t regbase); +static void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...); +static void cirrusfb_dbg_print_byte (const char *name, unsigned char val); +#endif /* CIRRUSFB_DEBUG */ + +/*** END PROTOTYPES ********************************************************/ +/*****************************************************************************/ +/*** BEGIN Interface Used by the World ***************************************/ + +static int opencount = 0; + +/*--- Open /dev/fbx ---------------------------------------------------------*/ +static int cirrusfb_open (struct fb_info *info, int user) +{ + if (opencount++ == 0) + switch_monitor (info->par, 1); + return 0; +} + +/*--- Close /dev/fbx --------------------------------------------------------*/ +static int cirrusfb_release (struct fb_info *info, int user) +{ + if (--opencount == 0) + switch_monitor (info->par, 0); + return 0; +} + +/**** END Interface used by the World *************************************/ +/****************************************************************************/ +/**** BEGIN Hardware specific Routines **************************************/ + +/* Get a good MCLK value */ +static long cirrusfb_get_mclk (long freq, int bpp, long *div) +{ + long mclk; + + assert (div != NULL); + + /* Calculate MCLK, in case VCLK is high enough to require > 50MHz. + * Assume a 64-bit data path for now. The formula is: + * ((B * PCLK * 2)/W) * 1.2 + * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */ + mclk = ((bpp / 8) * freq * 2) / 4; + mclk = (mclk * 12) / 10; + if (mclk < 50000) + mclk = 50000; + DPRINTK ("Use MCLK of %ld kHz\n", mclk); + + /* Calculate value for SR1F. Multiply by 2 so we can round up. */ + mclk = ((mclk * 16) / 14318); + mclk = (mclk + 1) / 2; + DPRINTK ("Set SR1F[5:0] to 0x%lx\n", mclk); + + /* Determine if we should use MCLK instead of VCLK, and if so, what we + * should divide it by to get VCLK */ + switch (freq) { + case 24751 ... 25249: + *div = 2; + DPRINTK ("Using VCLK = MCLK/2\n"); + break; + case 49501 ... 50499: + *div = 1; + DPRINTK ("Using VCLK = MCLK\n"); + break; + default: + *div = 0; + break; + } + + return mclk; +} + +static int cirrusfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct cirrusfb_info *cinfo = info->par; + int nom, den; /* translyting from pixels->bytes */ + int yres, i; + static struct { int xres, yres; } modes[] = + { { 1600, 1280 }, + { 1280, 1024 }, + { 1024, 768 }, + { 800, 600 }, + { 640, 480 }, + { -1, -1 } }; + + switch (var->bits_per_pixel) { + case 0 ... 1: + var->bits_per_pixel = 1; + nom = 4; + den = 8; + break; /* 8 pixel per byte, only 1/4th of mem usable */ + case 2 ... 8: + var->bits_per_pixel = 8; + nom = 1; + den = 1; + break; /* 1 pixel == 1 byte */ + case 9 ... 16: + var->bits_per_pixel = 16; + nom = 2; + den = 1; + break; /* 2 bytes per pixel */ + case 17 ... 24: + var->bits_per_pixel = 24; + nom = 3; + den = 1; + break; /* 3 bytes per pixel */ + case 25 ... 32: + var->bits_per_pixel = 32; + nom = 4; + den = 1; + break; /* 4 bytes per pixel */ + default: + printk ("cirrusfb: mode %dx%dx%d rejected...color depth not supported.\n", + var->xres, var->yres, var->bits_per_pixel); + DPRINTK ("EXIT - EINVAL error\n"); + return -EINVAL; + } + + if (var->xres * nom / den * var->yres > cinfo->size) { + printk ("cirrusfb: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n", + var->xres, var->yres, var->bits_per_pixel); + DPRINTK ("EXIT - EINVAL error\n"); + return -EINVAL; + } + + /* use highest possible virtual resolution */ + if (var->xres_virtual == -1 && + var->yres_virtual == -1) { + printk ("cirrusfb: using maximum available virtual resolution\n"); + for (i = 0; modes[i].xres != -1; i++) { + if (modes[i].xres * nom / den * modes[i].yres < cinfo->size / 2) + break; + } + if (modes[i].xres == -1) { + printk ("cirrusfb: could not find a virtual resolution that fits into video memory!!\n"); + DPRINTK ("EXIT - EINVAL error\n"); + return -EINVAL; + } + var->xres_virtual = modes[i].xres; + var->yres_virtual = modes[i].yres; + + printk ("cirrusfb: virtual resolution set to maximum of %dx%d\n", + var->xres_virtual, var->yres_virtual); + } + + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + if (var->xoffset < 0) + var->xoffset = 0; + if (var->yoffset < 0) + var->yoffset = 0; + + /* truncate xoffset and yoffset to maximum if too high */ + if (var->xoffset > var->xres_virtual - var->xres) + var->xoffset = var->xres_virtual - var->xres - 1; + if (var->yoffset > var->yres_virtual - var->yres) + var->yoffset = var->yres_virtual - var->yres - 1; + + switch (var->bits_per_pixel) { + case 1: + var->red.offset = 0; + var->red.length = 1; + var->green.offset = 0; + var->green.length = 1; + var->blue.offset = 0; + var->blue.length = 1; + break; + + case 8: + var->red.offset = 0; + var->red.length = 6; + var->green.offset = 0; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 6; + break; + + case 16: + if(isPReP) { + var->red.offset = 2; + var->green.offset = -3; + var->blue.offset = 8; + } else { + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + } + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + break; + + case 24: + if(isPReP) { + var->red.offset = 8; + var->green.offset = 16; + var->blue.offset = 24; + } else { + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + } + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + break; + + case 32: + if(isPReP) { + var->red.offset = 8; + var->green.offset = 16; + var->blue.offset = 24; + } else { + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + } + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + break; + + default: + DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel); + assert (FALSE); + /* should never occur */ + break; + } + + var->red.msb_right = + var->green.msb_right = + var->blue.msb_right = + var->transp.offset = + var->transp.length = + var->transp.msb_right = 0; + + yres = var->yres; + if (var->vmode & FB_VMODE_DOUBLE) + yres *= 2; + else if (var->vmode & FB_VMODE_INTERLACED) + yres = (yres + 1) / 2; + + if (yres >= 1280) { + printk (KERN_WARNING "cirrusfb: ERROR: VerticalTotal >= 1280; special treatment required! (TODO)\n"); + DPRINTK ("EXIT - EINVAL error\n"); + return -EINVAL; + } + + return 0; +} + +static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, + struct cirrusfb_regs *regs, + const struct fb_info *info) +{ + long freq; + long maxclock; + int maxclockidx = 0; + struct cirrusfb_info *cinfo = info->par; + int xres, hfront, hsync, hback; + int yres, vfront, vsync, vback; + + switch(var->bits_per_pixel) { + case 1: + regs->line_length = var->xres_virtual / 8; + regs->visual = FB_VISUAL_MONO10; + maxclockidx = 0; + break; + + case 8: + regs->line_length = var->xres_virtual; + regs->visual = FB_VISUAL_PSEUDOCOLOR; + maxclockidx = 1; + break; + + case 16: + regs->line_length = var->xres_virtual * 2; + regs->visual = FB_VISUAL_DIRECTCOLOR; + maxclockidx = 2; + break; + + case 24: + regs->line_length = var->xres_virtual * 3; + regs->visual = FB_VISUAL_DIRECTCOLOR; + maxclockidx = 3; + break; + + case 32: + regs->line_length = var->xres_virtual * 4; + regs->visual = FB_VISUAL_DIRECTCOLOR; + maxclockidx = 4; + break; + + default: + DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel); + assert (FALSE); + /* should never occur */ + break; + } + + regs->type = FB_TYPE_PACKED_PIXELS; + + /* convert from ps to kHz */ + freq = 1000000000 / var->pixclock; + + DPRINTK ("desired pixclock: %ld kHz\n", freq); + + maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; + regs->multiplexing = 0; + + /* If the frequency is greater than we can support, we might be able + * to use multiplexing for the video mode */ + if (freq > maxclock) { + switch (cinfo->btype) { + case BT_ALPINE: + case BT_GD5480: + regs->multiplexing = 1; + break; + + default: + printk (KERN_WARNING "cirrusfb: ERROR: Frequency greater than maxclock (%ld kHz)\n", maxclock); + DPRINTK ("EXIT - return -EINVAL\n"); + return -EINVAL; + } + } +#if 0 + /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where + * the VCLK is double the pixel clock. */ + switch (var->bits_per_pixel) { + case 16: + case 32: + if (regs->HorizRes <= 800) + freq /= 2; /* Xbh has this type of clock for 32-bit */ + break; + } +#endif + + bestclock (freq, ®s->freq, ®s->nom, ®s->den, ®s->div, + maxclock); + regs->mclk = cirrusfb_get_mclk (freq, var->bits_per_pixel, ®s->divMCLK); + + xres = var->xres; + hfront = var->right_margin; + hsync = var->hsync_len; + hback = var->left_margin; + + yres = var->yres; + vfront = var->lower_margin; + vsync = var->vsync_len; + vback = var->upper_margin; + + if (var->vmode & FB_VMODE_DOUBLE) { + yres *= 2; + vfront *= 2; + vsync *= 2; + vback *= 2; + } else if (var->vmode & FB_VMODE_INTERLACED) { + yres = (yres + 1) / 2; + vfront = (vfront + 1) / 2; + vsync = (vsync + 1) / 2; + vback = (vback + 1) / 2; + } + regs->HorizRes = xres; + regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5; + regs->HorizDispEnd = xres / 8 - 1; + regs->HorizBlankStart = xres / 8; + regs->HorizBlankEnd = regs->HorizTotal + 5; /* does not count with "-5" */ + regs->HorizSyncStart = (xres + hfront) / 8 + 1; + regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1; + + regs->VertRes = yres; + regs->VertTotal = yres + vfront + vsync + vback - 2; + regs->VertDispEnd = yres - 1; + regs->VertBlankStart = yres; + regs->VertBlankEnd = regs->VertTotal; + regs->VertSyncStart = yres + vfront - 1; + regs->VertSyncEnd = yres + vfront + vsync - 1; + + if (regs->VertRes >= 1024) { + regs->VertTotal /= 2; + regs->VertSyncStart /= 2; + regs->VertSyncEnd /= 2; + regs->VertDispEnd /= 2; + } + if (regs->multiplexing) { + regs->HorizTotal /= 2; + regs->HorizSyncStart /= 2; + regs->HorizSyncEnd /= 2; + regs->HorizDispEnd /= 2; + } + + return 0; +} + + +static void cirrusfb_set_mclk (const struct cirrusfb_info *cinfo, int val, int div) +{ + assert (cinfo != NULL); + + if (div == 2) { + /* VCLK = MCLK/2 */ + unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E); + vga_wseq (cinfo->regbase, CL_SEQR1E, old | 0x1); + vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f)); + } else if (div == 1) { + /* VCLK = MCLK */ + unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E); + vga_wseq (cinfo->regbase, CL_SEQR1E, old & ~0x1); + vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f)); + } else { + vga_wseq (cinfo->regbase, CL_SEQR1F, val & 0x3f); + } +} + +/************************************************************************* + cirrusfb_set_par_foo() + + actually writes the values for a new video mode into the hardware, +**************************************************************************/ +static int cirrusfb_set_par_foo (struct fb_info *info) +{ + struct cirrusfb_info *cinfo = info->par; + struct fb_var_screeninfo *var = &info->var; + struct cirrusfb_regs regs; + u8 __iomem *regbase = cinfo->regbase; + unsigned char tmp; + int offset = 0, err; + const struct cirrusfb_board_info_rec *bi; + + DPRINTK ("ENTER\n"); + DPRINTK ("Requested mode: %dx%dx%d\n", + var->xres, var->yres, var->bits_per_pixel); + DPRINTK ("pixclock: %d\n", var->pixclock); + + init_vgachip (cinfo); + + err = cirrusfb_decode_var(var, ®s, info); + if(err) { + /* should never happen */ + DPRINTK("mode change aborted. invalid var.\n"); + return -EINVAL; + } + + bi = &cirrusfb_board_info[cinfo->btype]; + + + /* unlock register VGA_CRTC_H_TOTAL..CRT7 */ + vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */ + + /* if debugging is enabled, all parameters get output before writing */ + DPRINTK ("CRT0: %ld\n", regs.HorizTotal); + vga_wcrt (regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal); + + DPRINTK ("CRT1: %ld\n", regs.HorizDispEnd); + vga_wcrt (regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd); + + DPRINTK ("CRT2: %ld\n", regs.HorizBlankStart); + vga_wcrt (regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart); + + DPRINTK ("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32); /* + 128: Compatible read */ + vga_wcrt (regbase, VGA_CRTC_H_BLANK_END, 128 + (regs.HorizBlankEnd % 32)); + + DPRINTK ("CRT4: %ld\n", regs.HorizSyncStart); + vga_wcrt (regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart); + + tmp = regs.HorizSyncEnd % 32; + if (regs.HorizBlankEnd & 32) + tmp += 128; + DPRINTK ("CRT5: %d\n", tmp); + vga_wcrt (regbase, VGA_CRTC_H_SYNC_END, tmp); + + DPRINTK ("CRT6: %ld\n", regs.VertTotal & 0xff); + vga_wcrt (regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff)); + + tmp = 16; /* LineCompare bit #9 */ + if (regs.VertTotal & 256) + tmp |= 1; + if (regs.VertDispEnd & 256) + tmp |= 2; + if (regs.VertSyncStart & 256) + tmp |= 4; + if (regs.VertBlankStart & 256) + tmp |= 8; + if (regs.VertTotal & 512) + tmp |= 32; + if (regs.VertDispEnd & 512) + tmp |= 64; + if (regs.VertSyncStart & 512) + tmp |= 128; + DPRINTK ("CRT7: %d\n", tmp); + vga_wcrt (regbase, VGA_CRTC_OVERFLOW, tmp); + + tmp = 0x40; /* LineCompare bit #8 */ + if (regs.VertBlankStart & 512) + tmp |= 0x20; + if (var->vmode & FB_VMODE_DOUBLE) + tmp |= 0x80; + DPRINTK ("CRT9: %d\n", tmp); + vga_wcrt (regbase, VGA_CRTC_MAX_SCAN, tmp); + + DPRINTK ("CRT10: %ld\n", regs.VertSyncStart & 0xff); + vga_wcrt (regbase, VGA_CRTC_V_SYNC_START, (regs.VertSyncStart & 0xff)); + + DPRINTK ("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16); + vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, (regs.VertSyncEnd % 16 + 64 + 32)); + + DPRINTK ("CRT12: %ld\n", regs.VertDispEnd & 0xff); + vga_wcrt (regbase, VGA_CRTC_V_DISP_END, (regs.VertDispEnd & 0xff)); + + DPRINTK ("CRT15: %ld\n", regs.VertBlankStart & 0xff); + vga_wcrt (regbase, VGA_CRTC_V_BLANK_START, (regs.VertBlankStart & 0xff)); + + DPRINTK ("CRT16: %ld\n", regs.VertBlankEnd & 0xff); + vga_wcrt (regbase, VGA_CRTC_V_BLANK_END, (regs.VertBlankEnd & 0xff)); + + DPRINTK ("CRT18: 0xff\n"); + vga_wcrt (regbase, VGA_CRTC_LINE_COMPARE, 0xff); + + tmp = 0; + if (var->vmode & FB_VMODE_INTERLACED) + tmp |= 1; + if (regs.HorizBlankEnd & 64) + tmp |= 16; + if (regs.HorizBlankEnd & 128) + tmp |= 32; + if (regs.VertBlankEnd & 256) + tmp |= 64; + if (regs.VertBlankEnd & 512) + tmp |= 128; + + DPRINTK ("CRT1a: %d\n", tmp); + vga_wcrt (regbase, CL_CRT1A, tmp); + + /* set VCLK0 */ + /* hardware RefClock: 14.31818 MHz */ + /* formula: VClk = (OSC * N) / (D * (1+P)) */ + /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */ + + vga_wseq (regbase, CL_SEQRB, regs.nom); + tmp = regs.den << 1; + if (regs.div != 0) + tmp |= 1; + + if ((cinfo->btype == BT_SD64) || + (cinfo->btype == BT_ALPINE) || + (cinfo->btype == BT_GD5480)) + tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */ + + DPRINTK ("CL_SEQR1B: %ld\n", (long) tmp); + vga_wseq (regbase, CL_SEQR1B, tmp); + + if (regs.VertRes >= 1024) + /* 1280x1024 */ + vga_wcrt (regbase, VGA_CRTC_MODE, 0xc7); + else + /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit + * address wrap, no compat. */ + vga_wcrt (regbase, VGA_CRTC_MODE, 0xc3); + +/* HAEH? vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20); * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */ + + /* don't know if it would hurt to also program this if no interlaced */ + /* mode is used, but I feel better this way.. :-) */ + if (var->vmode & FB_VMODE_INTERLACED) + vga_wcrt (regbase, VGA_CRTC_REGS, regs.HorizTotal / 2); + else + vga_wcrt (regbase, VGA_CRTC_REGS, 0x00); /* interlace control */ + + vga_wseq (regbase, VGA_SEQ_CHARACTER_MAP, 0); + + /* adjust horizontal/vertical sync type (low/high) */ + tmp = 0x03; /* enable display memory & CRTC I/O address for color mode */ + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + tmp |= 0x40; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + tmp |= 0x80; + WGen (cinfo, VGA_MIS_W, tmp); + + vga_wcrt (regbase, VGA_CRTC_PRESET_ROW, 0); /* Screen A Preset Row-Scan register */ + vga_wcrt (regbase, VGA_CRTC_CURSOR_START, 0); /* text cursor on and start line */ + vga_wcrt (regbase, VGA_CRTC_CURSOR_END, 31); /* text cursor end line */ + + /****************************************************** + * + * 1 bpp + * + */ + + /* programming for different color depths */ + if (var->bits_per_pixel == 1) { + DPRINTK ("cirrusfb: preparing for 1 bit deep display\n"); + vga_wgfx (regbase, VGA_GFX_MODE, 0); /* mode register */ + + /* SR07 */ + switch (cinfo->btype) { + case BT_SD64: + case BT_PICCOLO: + case BT_PICASSO: + case BT_SPECTRUM: + case BT_PICASSO4: + case BT_ALPINE: + case BT_GD5480: + DPRINTK (" (for GD54xx)\n"); + vga_wseq (regbase, CL_SEQR7, + regs.multiplexing ? + bi->sr07_1bpp_mux : bi->sr07_1bpp); + break; + + case BT_LAGUNA: + DPRINTK (" (for GD546x)\n"); + vga_wseq (regbase, CL_SEQR7, + vga_rseq (regbase, CL_SEQR7) & ~0x01); + break; + + default: + printk (KERN_WARNING "cirrusfb: unknown Board\n"); + break; + } + + /* Extended Sequencer Mode */ + switch (cinfo->btype) { + case BT_SD64: + /* setting the SEQRF on SD64 is not necessary (only during init) */ + DPRINTK ("(for SD64)\n"); + vga_wseq (regbase, CL_SEQR1F, 0x1a); /* MCLK select */ + break; + + case BT_PICCOLO: + DPRINTK ("(for Piccolo)\n"); +/* ### ueberall 0x22? */ + vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */ + vga_wseq (regbase, CL_SEQRF, 0xb0); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */ + break; + + case BT_PICASSO: + DPRINTK ("(for Picasso)\n"); + vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 22 MCLK select */ + vga_wseq (regbase, CL_SEQRF, 0xd0); /* ## vorher d0 avoid FIFO underruns..? */ + break; + + case BT_SPECTRUM: + DPRINTK ("(for Spectrum)\n"); +/* ### ueberall 0x22? */ + vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */ + vga_wseq (regbase, CL_SEQRF, 0xb0); /* evtl d0? avoid FIFO underruns..? */ + break; + + case BT_PICASSO4: + case BT_ALPINE: + case BT_GD5480: + case BT_LAGUNA: + DPRINTK (" (for GD54xx)\n"); + /* do nothing */ + break; + + default: + printk (KERN_WARNING "cirrusfb: unknown Board\n"); + break; + } + + WGen (cinfo, VGA_PEL_MSK, 0x01); /* pixel mask: pass-through for first plane */ + if (regs.multiplexing) + WHDR (cinfo, 0x4a); /* hidden dac reg: 1280x1024 */ + else + WHDR (cinfo, 0); /* hidden dac: nothing */ + vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x06); /* memory mode: odd/even, ext. memory */ + vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0x01); /* plane mask: only write to first plane */ + offset = var->xres_virtual / 16; + } + + /****************************************************** + * + * 8 bpp + * + */ + + else if (var->bits_per_pixel == 8) { + DPRINTK ("cirrusfb: preparing for 8 bit deep display\n"); + switch (cinfo->btype) { + case BT_SD64: + case BT_PICCOLO: + case BT_PICASSO: + case BT_SPECTRUM: + case BT_PICASSO4: + case BT_ALPINE: + case BT_GD5480: + DPRINTK (" (for GD54xx)\n"); + vga_wseq (regbase, CL_SEQR7, + regs.multiplexing ? + bi->sr07_8bpp_mux : bi->sr07_8bpp); + break; + + case BT_LAGUNA: + DPRINTK (" (for GD546x)\n"); + vga_wseq (regbase, CL_SEQR7, + vga_rseq (regbase, CL_SEQR7) | 0x01); + break; + + default: + printk (KERN_WARNING "cirrusfb: unknown Board\n"); + break; + } + + switch (cinfo->btype) { + case BT_SD64: + vga_wseq (regbase, CL_SEQR1F, 0x1d); /* MCLK select */ + break; + + case BT_PICCOLO: + vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */ + vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ + break; + + case BT_PICASSO: + vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */ + vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ + break; + + case BT_SPECTRUM: + vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */ + vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ + break; + + case BT_PICASSO4: +#ifdef CONFIG_ZORRO + vga_wseq (regbase, CL_SEQRF, 0xb8); /* ### INCOMPLETE!! */ +#endif +/* vga_wseq (regbase, CL_SEQR1F, 0x1c); */ + break; + + case BT_ALPINE: + DPRINTK (" (for GD543x)\n"); + cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK); + /* We already set SRF and SR1F */ + break; + + case BT_GD5480: + case BT_LAGUNA: + DPRINTK (" (for GD54xx)\n"); + /* do nothing */ + break; + + default: + printk (KERN_WARNING "cirrusfb: unknown Board\n"); + break; + } + + vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */ + WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */ + if (regs.multiplexing) + WHDR (cinfo, 0x4a); /* hidden dac reg: 1280x1024 */ + else + WHDR (cinfo, 0); /* hidden dac: nothing */ + vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */ + vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */ + offset = var->xres_virtual / 8; + } + + /****************************************************** + * + * 16 bpp + * + */ + + else if (var->bits_per_pixel == 16) { + DPRINTK ("cirrusfb: preparing for 16 bit deep display\n"); + switch (cinfo->btype) { + case BT_SD64: + vga_wseq (regbase, CL_SEQR7, 0xf7); /* Extended Sequencer Mode: 256c col. mode */ + vga_wseq (regbase, CL_SEQR1F, 0x1e); /* MCLK select */ + break; + + case BT_PICCOLO: + vga_wseq (regbase, CL_SEQR7, 0x87); + vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ + vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ + break; + + case BT_PICASSO: + vga_wseq (regbase, CL_SEQR7, 0x27); + vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ + vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ + break; + + case BT_SPECTRUM: + vga_wseq (regbase, CL_SEQR7, 0x87); + vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ + vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ + break; + + case BT_PICASSO4: + vga_wseq (regbase, CL_SEQR7, 0x27); +/* vga_wseq (regbase, CL_SEQR1F, 0x1c); */ + break; + + case BT_ALPINE: + DPRINTK (" (for GD543x)\n"); + if (regs.HorizRes >= 1024) + vga_wseq (regbase, CL_SEQR7, 0xa7); + else + vga_wseq (regbase, CL_SEQR7, 0xa3); + cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK); + break; + + case BT_GD5480: + DPRINTK (" (for GD5480)\n"); + vga_wseq (regbase, CL_SEQR7, 0x17); + /* We already set SRF and SR1F */ + break; + + case BT_LAGUNA: + DPRINTK (" (for GD546x)\n"); + vga_wseq (regbase, CL_SEQR7, + vga_rseq (regbase, CL_SEQR7) & ~0x01); + break; + + default: + printk (KERN_WARNING "CIRRUSFB: unknown Board\n"); + break; + } + + vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */ + WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */ +#ifdef CONFIG_PCI + WHDR (cinfo, 0xc0); /* Copy Xbh */ +#elif defined(CONFIG_ZORRO) + /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */ + WHDR (cinfo, 0xa0); /* hidden dac reg: nothing special */ +#endif + vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */ + vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */ + offset = var->xres_virtual / 4; + } + + /****************************************************** + * + * 32 bpp + * + */ + + else if (var->bits_per_pixel == 32) { + DPRINTK ("cirrusfb: preparing for 24/32 bit deep display\n"); + switch (cinfo->btype) { + case BT_SD64: + vga_wseq (regbase, CL_SEQR7, 0xf9); /* Extended Sequencer Mode: 256c col. mode */ + vga_wseq (regbase, CL_SEQR1F, 0x1e); /* MCLK select */ + break; + + case BT_PICCOLO: + vga_wseq (regbase, CL_SEQR7, 0x85); + vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ + vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ + break; + + case BT_PICASSO: + vga_wseq (regbase, CL_SEQR7, 0x25); + vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ + vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ + break; + + case BT_SPECTRUM: + vga_wseq (regbase, CL_SEQR7, 0x85); + vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ + vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ + break; + + case BT_PICASSO4: + vga_wseq (regbase, CL_SEQR7, 0x25); +/* vga_wseq (regbase, CL_SEQR1F, 0x1c); */ + break; + + case BT_ALPINE: + DPRINTK (" (for GD543x)\n"); + vga_wseq (regbase, CL_SEQR7, 0xa9); + cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK); + break; + + case BT_GD5480: + DPRINTK (" (for GD5480)\n"); + vga_wseq (regbase, CL_SEQR7, 0x19); + /* We already set SRF and SR1F */ + break; + + case BT_LAGUNA: + DPRINTK (" (for GD546x)\n"); + vga_wseq (regbase, CL_SEQR7, + vga_rseq (regbase, CL_SEQR7) & ~0x01); + break; + + default: + printk (KERN_WARNING "cirrusfb: unknown Board\n"); + break; + } + + vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */ + WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */ + WHDR (cinfo, 0xc5); /* hidden dac reg: 8-8-8 mode (24 or 32) */ + vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */ + vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */ + offset = var->xres_virtual / 4; + } + + /****************************************************** + * + * unknown/unsupported bpp + * + */ + + else { + printk (KERN_ERR "cirrusfb: What's this?? requested color depth == %d.\n", + var->bits_per_pixel); + } + + vga_wcrt (regbase, VGA_CRTC_OFFSET, offset & 0xff); + tmp = 0x22; + if (offset & 0x100) + tmp |= 0x10; /* offset overflow bit */ + + vga_wcrt (regbase, CL_CRT1B, tmp); /* screen start addr #16-18, fastpagemode cycles */ + + if (cinfo->btype == BT_SD64 || + cinfo->btype == BT_PICASSO4 || + cinfo->btype == BT_ALPINE || + cinfo->btype == BT_GD5480) + vga_wcrt (regbase, CL_CRT1D, 0x00); /* screen start address bit 19 */ + + vga_wcrt (regbase, VGA_CRTC_CURSOR_HI, 0); /* text cursor location high */ + vga_wcrt (regbase, VGA_CRTC_CURSOR_LO, 0); /* text cursor location low */ + vga_wcrt (regbase, VGA_CRTC_UNDERLINE, 0); /* underline row scanline = at very bottom */ + + vga_wattr (regbase, VGA_ATC_MODE, 1); /* controller mode */ + vga_wattr (regbase, VGA_ATC_OVERSCAN, 0); /* overscan (border) color */ + vga_wattr (regbase, VGA_ATC_PLANE_ENABLE, 15); /* color plane enable */ + vga_wattr (regbase, CL_AR33, 0); /* pixel panning */ + vga_wattr (regbase, VGA_ATC_COLOR_PAGE, 0); /* color select */ + + /* [ EGS: SetOffset(); ] */ + /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */ + AttrOn (cinfo); + + vga_wgfx (regbase, VGA_GFX_SR_VALUE, 0); /* set/reset register */ + vga_wgfx (regbase, VGA_GFX_SR_ENABLE, 0); /* set/reset enable */ + vga_wgfx (regbase, VGA_GFX_COMPARE_VALUE, 0); /* color compare */ + vga_wgfx (regbase, VGA_GFX_DATA_ROTATE, 0); /* data rotate */ + vga_wgfx (regbase, VGA_GFX_PLANE_READ, 0); /* read map select */ + vga_wgfx (regbase, VGA_GFX_MISC, 1); /* miscellaneous register */ + vga_wgfx (regbase, VGA_GFX_COMPARE_MASK, 15); /* color don't care */ + vga_wgfx (regbase, VGA_GFX_BIT_MASK, 255); /* bit mask */ + + vga_wseq (regbase, CL_SEQR12, 0x0); /* graphics cursor attributes: nothing special */ + + /* finally, turn on everything - turn off "FullBandwidth" bit */ + /* also, set "DotClock%2" bit where requested */ + tmp = 0x01; + +/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ? + if (var->vmode & FB_VMODE_CLOCK_HALVE) + tmp |= 0x08; +*/ + + vga_wseq (regbase, VGA_SEQ_CLOCK_MODE, tmp); + DPRINTK ("CL_SEQR1: %d\n", tmp); + + cinfo->currentmode = regs; + info->fix.type = regs.type; + info->fix.visual = regs.visual; + info->fix.line_length = regs.line_length; + + /* pan to requested offset */ + cirrusfb_pan_display (var, info); + +#ifdef CIRRUSFB_DEBUG + cirrusfb_dump (); +#endif + + DPRINTK ("EXIT\n"); + return 0; +} + +/* for some reason incomprehensible to me, cirrusfb requires that you write + * the registers twice for the settings to take..grr. -dte */ +static int cirrusfb_set_par (struct fb_info *info) +{ + cirrusfb_set_par_foo (info); + return cirrusfb_set_par_foo (info); +} + +static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct cirrusfb_info *cinfo = info->par; + + if (regno > 255) + return -EINVAL; + + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v; + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + if (regno>=16) + return 1; + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + + switch (info->var.bits_per_pixel) { + case 8: + ((u8*)(info->pseudo_palette))[regno] = v; + break; + case 16: + ((u16*)(info->pseudo_palette))[regno] = v; + break; + case 24: + case 32: + ((u32*)(info->pseudo_palette))[regno] = v; + break; + } + return 0; + } + + cinfo->palette[regno].red = red; + cinfo->palette[regno].green = green; + cinfo->palette[regno].blue = blue; + + if (info->var.bits_per_pixel == 8) { + WClut (cinfo, regno, red >> 10, green >> 10, blue >> 10); + } + + return 0; + +} + +/************************************************************************* + cirrusfb_pan_display() + + performs display panning - provided hardware permits this +**************************************************************************/ +static int cirrusfb_pan_display (struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int xoffset = 0; + int yoffset = 0; + unsigned long base; + unsigned char tmp = 0, tmp2 = 0, xpix; + struct cirrusfb_info *cinfo = info->par; + + DPRINTK ("ENTER\n"); + DPRINTK ("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset); + + /* no range checks for xoffset and yoffset, */ + /* as fb_pan_display has already done this */ + if (var->vmode & FB_VMODE_YWRAP) + return -EINVAL; + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + xoffset = var->xoffset * info->var.bits_per_pixel / 8; + yoffset = var->yoffset; + + base = yoffset * cinfo->currentmode.line_length + xoffset; + + if (info->var.bits_per_pixel == 1) { + /* base is already correct */ + xpix = (unsigned char) (var->xoffset % 8); + } else { + base /= 4; + xpix = (unsigned char) ((xoffset % 4) * 2); + } + + cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */ + + /* lower 8 + 8 bits of screen start address */ + vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, (unsigned char) (base & 0xff)); + vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, (unsigned char) (base >> 8)); + + /* construct bits 16, 17 and 18 of screen start address */ + if (base & 0x10000) + tmp |= 0x01; + if (base & 0x20000) + tmp |= 0x04; + if (base & 0x40000) + tmp |= 0x08; + + tmp2 = (vga_rcrt (cinfo->regbase, CL_CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */ + vga_wcrt (cinfo->regbase, CL_CRT1B, tmp2); + + /* construct bit 19 of screen start address */ + if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) { + tmp2 = 0; + if (base & 0x80000) + tmp2 = 0x80; + vga_wcrt (cinfo->regbase, CL_CRT1D, tmp2); + } + + /* write pixel panning value to AR33; this does not quite work in 8bpp */ + /* ### Piccolo..? Will this work? */ + if (info->var.bits_per_pixel == 1) + vga_wattr (cinfo->regbase, CL_AR33, xpix); + + cirrusfb_WaitBLT (cinfo->regbase); + + DPRINTK ("EXIT\n"); + return (0); +} + + +static int cirrusfb_blank (int blank_mode, struct fb_info *info) +{ + /* + * Blank the screen if blank_mode != 0, else unblank. If blank == NULL + * then the caller blanks by setting the CLUT (Color Look Up Table) to all + * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due + * to e.g. a video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + */ + unsigned char val; + struct cirrusfb_info *cinfo = info->par; + int current_mode = cinfo->blank_mode; + + DPRINTK ("ENTER, blank mode = %d\n", blank_mode); + + if (info->state != FBINFO_STATE_RUNNING || + current_mode == blank_mode) { + DPRINTK ("EXIT, returning 0\n"); + return 0; + } + + /* Undo current */ + if (current_mode == FB_BLANK_NORMAL || + current_mode == FB_BLANK_UNBLANK) { + /* unblank the screen */ + val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE); + vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf); /* clear "FullBandwidth" bit */ + /* and undo VESA suspend trickery */ + vga_wgfx (cinfo->regbase, CL_GRE, 0x00); + } + + /* set new */ + if(blank_mode > FB_BLANK_NORMAL) { + /* blank the screen */ + val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE); + vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20); /* set "FullBandwidth" bit */ + } + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + case FB_BLANK_NORMAL: + break; + case FB_BLANK_VSYNC_SUSPEND: + vga_wgfx (cinfo->regbase, CL_GRE, 0x04); + break; + case FB_BLANK_HSYNC_SUSPEND: + vga_wgfx (cinfo->regbase, CL_GRE, 0x02); + break; + case FB_BLANK_POWERDOWN: + vga_wgfx (cinfo->regbase, CL_GRE, 0x06); + break; + default: + DPRINTK ("EXIT, returning 1\n"); + return 1; + } + + cinfo->blank_mode = blank_mode; + DPRINTK ("EXIT, returning 0\n"); + + /* Let fbcon do a soft blank for us */ + return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; +} +/**** END Hardware specific Routines **************************************/ +/****************************************************************************/ +/**** BEGIN Internal Routines ***********************************************/ + +static void init_vgachip (struct cirrusfb_info *cinfo) +{ + const struct cirrusfb_board_info_rec *bi; + + DPRINTK ("ENTER\n"); + + assert (cinfo != NULL); + + bi = &cirrusfb_board_info[cinfo->btype]; + + /* reset board globally */ + switch (cinfo->btype) { + case BT_PICCOLO: + WSFR (cinfo, 0x01); + udelay (500); + WSFR (cinfo, 0x51); + udelay (500); + break; + case BT_PICASSO: + WSFR2 (cinfo, 0xff); + udelay (500); + break; + case BT_SD64: + case BT_SPECTRUM: + WSFR (cinfo, 0x1f); + udelay (500); + WSFR (cinfo, 0x4f); + udelay (500); + break; + case BT_PICASSO4: + vga_wcrt (cinfo->regbase, CL_CRT51, 0x00); /* disable flickerfixer */ + mdelay (100); + vga_wgfx (cinfo->regbase, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */ + vga_wgfx (cinfo->regbase, CL_GR33, 0x00); /* put blitter into 542x compat */ + vga_wgfx (cinfo->regbase, CL_GR31, 0x00); /* mode */ + break; + + case BT_GD5480: + vga_wgfx (cinfo->regbase, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */ + break; + + case BT_ALPINE: + /* Nothing to do to reset the board. */ + break; + + default: + printk (KERN_ERR "cirrusfb: Warning: Unknown board type\n"); + break; + } + + assert (cinfo->size > 0); /* make sure RAM size set by this point */ + + /* the P4 is not fully initialized here; I rely on it having been */ + /* inited under AmigaOS already, which seems to work just fine */ + /* (Klaus advised to do it this way) */ + + if (cinfo->btype != BT_PICASSO4) { + WGen (cinfo, CL_VSSM, 0x10); /* EGS: 0x16 */ + WGen (cinfo, CL_POS102, 0x01); + WGen (cinfo, CL_VSSM, 0x08); /* EGS: 0x0e */ + + if (cinfo->btype != BT_SD64) + WGen (cinfo, CL_VSSM2, 0x01); + + vga_wseq (cinfo->regbase, CL_SEQR0, 0x03); /* reset sequencer logic */ + + vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21); /* FullBandwidth (video off) and 8/9 dot clock */ + WGen (cinfo, VGA_MIS_W, 0xc1); /* polarity (-/-), disable access to display memory, VGA_CRTC_START_HI base address: color */ + +/* vga_wgfx (cinfo->regbase, CL_GRA, 0xce); "magic cookie" - doesn't make any sense to me.. */ + vga_wseq (cinfo->regbase, CL_SEQR6, 0x12); /* unlock all extension registers */ + + vga_wgfx (cinfo->regbase, CL_GR31, 0x04); /* reset blitter */ + + switch (cinfo->btype) { + case BT_GD5480: + vga_wseq (cinfo->regbase, CL_SEQRF, 0x98); + break; + case BT_ALPINE: + break; + case BT_SD64: + vga_wseq (cinfo->regbase, CL_SEQRF, 0xb8); + break; + default: + vga_wseq (cinfo->regbase, CL_SEQR16, 0x0f); + vga_wseq (cinfo->regbase, CL_SEQRF, 0xb0); + break; + } + } + vga_wseq (cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: nothing */ + vga_wseq (cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00); /* character map select: doesn't even matter in gx mode */ + vga_wseq (cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e); /* memory mode: chain-4, no odd/even, ext. memory */ + + /* controller-internal base address of video memory */ + if (bi->init_sr07) + vga_wseq (cinfo->regbase, CL_SEQR7, bi->sr07); + + /* vga_wseq (cinfo->regbase, CL_SEQR8, 0x00); *//* EEPROM control: shouldn't be necessary to write to this at all.. */ + + vga_wseq (cinfo->regbase, CL_SEQR10, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */ + vga_wseq (cinfo->regbase, CL_SEQR11, 0x00); /* graphics cursor Y position (..."... ) */ + vga_wseq (cinfo->regbase, CL_SEQR12, 0x00); /* graphics cursor attributes */ + vga_wseq (cinfo->regbase, CL_SEQR13, 0x00); /* graphics cursor pattern address */ + + /* writing these on a P4 might give problems.. */ + if (cinfo->btype != BT_PICASSO4) { + vga_wseq (cinfo->regbase, CL_SEQR17, 0x00); /* configuration readback and ext. color */ + vga_wseq (cinfo->regbase, CL_SEQR18, 0x02); /* signature generator */ + } + + /* MCLK select etc. */ + if (bi->init_sr1f) + vga_wseq (cinfo->regbase, CL_SEQR1F, bi->sr1f); + + vga_wcrt (cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00); /* Screen A preset row scan: none */ + vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20); /* Text cursor start: disable text cursor */ + vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00); /* Text cursor end: - */ + vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, 0x00); /* Screen start address high: 0 */ + vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, 0x00); /* Screen start address low: 0 */ + vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00); /* text cursor location high: 0 */ + vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00); /* text cursor location low: 0 */ + + vga_wcrt (cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00); /* Underline Row scanline: - */ + vga_wcrt (cinfo->regbase, VGA_CRTC_MODE, 0xc3); /* mode control: timing enable, byte mode, no compat modes */ + vga_wcrt (cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00); /* Line Compare: not needed */ + /* ### add 0x40 for text modes with > 30 MHz pixclock */ + vga_wcrt (cinfo->regbase, CL_CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */ + + vga_wgfx (cinfo->regbase, VGA_GFX_SR_VALUE, 0x00); /* Set/Reset registes: - */ + vga_wgfx (cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00); /* Set/Reset enable: - */ + vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00); /* Color Compare: - */ + vga_wgfx (cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00); /* Data Rotate: - */ + vga_wgfx (cinfo->regbase, VGA_GFX_PLANE_READ, 0x00); /* Read Map Select: - */ + vga_wgfx (cinfo->regbase, VGA_GFX_MODE, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */ + vga_wgfx (cinfo->regbase, VGA_GFX_MISC, 0x01); /* Miscellaneous: memory map base address, graphics mode */ + vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f); /* Color Don't care: involve all planes */ + vga_wgfx (cinfo->regbase, VGA_GFX_BIT_MASK, 0xff); /* Bit Mask: no mask at all */ + if (cinfo->btype == BT_ALPINE) + vga_wgfx (cinfo->regbase, CL_GRB, 0x20); /* (5434 can't have bit 3 set for bitblt) */ + else + vga_wgfx (cinfo->regbase, CL_GRB, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */ + + vga_wgfx (cinfo->regbase, CL_GRC, 0xff); /* Color Key compare: - */ + vga_wgfx (cinfo->regbase, CL_GRD, 0x00); /* Color Key compare mask: - */ + vga_wgfx (cinfo->regbase, CL_GRE, 0x00); /* Miscellaneous control: - */ + /* vga_wgfx (cinfo->regbase, CL_GR10, 0x00); *//* Background color byte 1: - */ +/* vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */ + + vga_wattr (cinfo->regbase, VGA_ATC_PALETTE0, 0x00); /* Attribute Controller palette registers: "identity mapping" */ + vga_wattr (cinfo->regbase, VGA_ATC_PALETTE1, 0x01); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTE2, 0x02); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTE3, 0x03); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTE4, 0x04); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTE5, 0x05); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTE6, 0x06); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTE7, 0x07); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTE8, 0x08); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTE9, 0x09); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTEA, 0x0a); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTEB, 0x0b); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTEC, 0x0c); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTED, 0x0d); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTEE, 0x0e); + vga_wattr (cinfo->regbase, VGA_ATC_PALETTEF, 0x0f); + + vga_wattr (cinfo->regbase, VGA_ATC_MODE, 0x01); /* Attribute Controller mode: graphics mode */ + vga_wattr (cinfo->regbase, VGA_ATC_OVERSCAN, 0x00); /* Overscan color reg.: reg. 0 */ + vga_wattr (cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f); /* Color Plane enable: Enable all 4 planes */ +/* ### vga_wattr (cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */ + vga_wattr (cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00); /* Color Select: - */ + + WGen (cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */ + + if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480) + WGen (cinfo, VGA_MIS_W, 0xc3); /* polarity (-/-), enable display mem, VGA_CRTC_START_HI i/o base = color */ + + vga_wgfx (cinfo->regbase, CL_GR31, 0x04); /* BLT Start/status: Blitter reset */ + vga_wgfx (cinfo->regbase, CL_GR31, 0x00); /* - " - : "end-of-reset" */ + + /* misc... */ + WHDR (cinfo, 0); /* Hidden DAC register: - */ + + printk (KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n", cinfo->size); + DPRINTK ("EXIT\n"); + return; +} + +static void switch_monitor (struct cirrusfb_info *cinfo, int on) +{ +#ifdef CONFIG_ZORRO /* only works on Zorro boards */ + static int IsOn = 0; /* XXX not ok for multiple boards */ + + DPRINTK ("ENTER\n"); + + if (cinfo->btype == BT_PICASSO4) + return; /* nothing to switch */ + if (cinfo->btype == BT_ALPINE) + return; /* nothing to switch */ + if (cinfo->btype == BT_GD5480) + return; /* nothing to switch */ + if (cinfo->btype == BT_PICASSO) { + if ((on && !IsOn) || (!on && IsOn)) + WSFR (cinfo, 0xff); + + DPRINTK ("EXIT\n"); + return; + } + if (on) { + switch (cinfo->btype) { + case BT_SD64: + WSFR (cinfo, cinfo->SFR | 0x21); + break; + case BT_PICCOLO: + WSFR (cinfo, cinfo->SFR | 0x28); + break; + case BT_SPECTRUM: + WSFR (cinfo, 0x6f); + break; + default: /* do nothing */ break; + } + } else { + switch (cinfo->btype) { + case BT_SD64: + WSFR (cinfo, cinfo->SFR & 0xde); + break; + case BT_PICCOLO: + WSFR (cinfo, cinfo->SFR & 0xd7); + break; + case BT_SPECTRUM: + WSFR (cinfo, 0x4f); + break; + default: /* do nothing */ break; + } + } + + DPRINTK ("EXIT\n"); +#endif /* CONFIG_ZORRO */ +} + + +/******************************************/ +/* Linux 2.6-style accelerated functions */ +/******************************************/ + +static void cirrusfb_prim_fillrect(struct cirrusfb_info *cinfo, + const struct fb_fillrect *region) +{ + int m; /* bytes per pixel */ + if(cinfo->info->var.bits_per_pixel == 1) { + cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel, + region->dx / 8, region->dy, + region->width / 8, region->height, + region->color, + cinfo->currentmode.line_length); + } else { + m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8; + cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel, + region->dx * m, region->dy, + region->width * m, region->height, + region->color, + cinfo->currentmode.line_length); + } + return; +} + +static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region) +{ + struct cirrusfb_info *cinfo = info->par; + struct fb_fillrect modded; + int vxres, vyres; + + if (info->state != FBINFO_STATE_RUNNING) + return; + if (info->flags & FBINFO_HWACCEL_DISABLED) { + cfb_fillrect(info, region); + return; + } + + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + + memcpy(&modded, region, sizeof(struct fb_fillrect)); + + if(!modded.width || !modded.height || + modded.dx >= vxres || modded.dy >= vyres) + return; + + if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx; + if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy; + + cirrusfb_prim_fillrect(cinfo, &modded); +} + +static void cirrusfb_prim_copyarea(struct cirrusfb_info *cinfo, + const struct fb_copyarea *area) +{ + int m; /* bytes per pixel */ + if(cinfo->info->var.bits_per_pixel == 1) { + cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel, + area->sx / 8, area->sy, + area->dx / 8, area->dy, + area->width / 8, area->height, + cinfo->currentmode.line_length); + } else { + m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8; + cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel, + area->sx * m, area->sy, + area->dx * m, area->dy, + area->width * m, area->height, + cinfo->currentmode.line_length); + } + return; +} + + +static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct cirrusfb_info *cinfo = info->par; + struct fb_copyarea modded; + u32 vxres, vyres; + modded.sx = area->sx; + modded.sy = area->sy; + modded.dx = area->dx; + modded.dy = area->dy; + modded.width = area->width; + modded.height = area->height; + + if (info->state != FBINFO_STATE_RUNNING) + return; + if (info->flags & FBINFO_HWACCEL_DISABLED) { + cfb_copyarea(info, area); + return; + } + + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + + if(!modded.width || !modded.height || + modded.sx >= vxres || modded.sy >= vyres || + modded.dx >= vxres || modded.dy >= vyres) + return; + + if(modded.sx + modded.width > vxres) modded.width = vxres - modded.sx; + if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx; + if(modded.sy + modded.height > vyres) modded.height = vyres - modded.sy; + if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy; + + cirrusfb_prim_copyarea(cinfo, &modded); +} + +static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct cirrusfb_info *cinfo = info->par; + + cirrusfb_WaitBLT(cinfo->regbase); + cfb_imageblit(info, image); +} + + +#ifdef CONFIG_PPC_PREP +#define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000) +#define PREP_IO_BASE ((volatile unsigned char *) 0x80000000) +static void get_prep_addrs (unsigned long *display, unsigned long *registers) +{ + DPRINTK ("ENTER\n"); + + *display = PREP_VIDEO_BASE; + *registers = (unsigned long) PREP_IO_BASE; + + DPRINTK ("EXIT\n"); +} + +#endif /* CONFIG_PPC_PREP */ + + +#ifdef CONFIG_PCI +static int release_io_ports = 0; + +/* Pulled the logic from XFree86 Cirrus driver to get the memory size, + * based on the DRAM bandwidth bit and DRAM bank switching bit. This + * works with 1MB, 2MB and 4MB configurations (which the Motorola boards + * seem to have. */ +static unsigned int cirrusfb_get_memsize (u8 __iomem *regbase) +{ + unsigned long mem; + unsigned char SRF; + + DPRINTK ("ENTER\n"); + + SRF = vga_rseq (regbase, CL_SEQRF); + switch ((SRF & 0x18)) { + case 0x08: mem = 512 * 1024; break; + case 0x10: mem = 1024 * 1024; break; + /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory + * on the 5430. */ + case 0x18: mem = 2048 * 1024; break; + default: printk ("CLgenfb: Unknown memory size!\n"); + mem = 1024 * 1024; + } + if (SRF & 0x80) { + /* If DRAM bank switching is enabled, there must be twice as much + * memory installed. (4MB on the 5434) */ + mem *= 2; + } + /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */ + + DPRINTK ("EXIT\n"); + return mem; +} + + + +static void get_pci_addrs (const struct pci_dev *pdev, + unsigned long *display, unsigned long *registers) +{ + assert (pdev != NULL); + assert (display != NULL); + assert (registers != NULL); + + DPRINTK ("ENTER\n"); + + *display = 0; + *registers = 0; + + /* This is a best-guess for now */ + + if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { + *display = pci_resource_start(pdev, 1); + *registers = pci_resource_start(pdev, 0); + } else { + *display = pci_resource_start(pdev, 0); + *registers = pci_resource_start(pdev, 1); + } + + assert (*display != 0); + + DPRINTK ("EXIT\n"); +} + + +static void cirrusfb_pci_unmap (struct cirrusfb_info *cinfo) +{ + struct pci_dev *pdev = cinfo->pdev; + + iounmap(cinfo->fbmem); +#if 0 /* if system didn't claim this region, we would... */ + release_mem_region(0xA0000, 65535); +#endif + if (release_io_ports) + release_region(0x3C0, 32); + pci_release_regions(pdev); + framebuffer_release(cinfo->info); + pci_disable_device(pdev); +} +#endif /* CONFIG_PCI */ + + +#ifdef CONFIG_ZORRO +static void __devexit cirrusfb_zorro_unmap (struct cirrusfb_info *cinfo) +{ + zorro_release_device(cinfo->zdev); + + if (cinfo->btype == BT_PICASSO4) { + cinfo->regbase -= 0x600000; + iounmap ((void *)cinfo->regbase); + iounmap ((void *)cinfo->fbmem); + } else { + if (zorro_resource_start(cinfo->zdev) > 0x01000000) + iounmap ((void *)cinfo->fbmem); + } + framebuffer_release(cinfo->info); +} +#endif /* CONFIG_ZORRO */ + +static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo) +{ + struct fb_info *info = cinfo->info; + struct fb_var_screeninfo *var = &info->var; + + info->par = cinfo; + info->pseudo_palette = cinfo->pseudo_palette; + info->flags = FBINFO_DEFAULT + | FBINFO_HWACCEL_XPAN + | FBINFO_HWACCEL_YPAN + | FBINFO_HWACCEL_FILLRECT + | FBINFO_HWACCEL_COPYAREA; + if (noaccel) + info->flags |= FBINFO_HWACCEL_DISABLED; + info->fbops = &cirrusfb_ops; + info->screen_base = cinfo->fbmem; + if (cinfo->btype == BT_GD5480) { + if (var->bits_per_pixel == 16) + info->screen_base += 1 * MB_; + if (var->bits_per_pixel == 24 || var->bits_per_pixel == 32) + info->screen_base += 2 * MB_; + } + + /* Fill fix common fields */ + strlcpy(info->fix.id, cirrusfb_board_info[cinfo->btype].name, + sizeof(info->fix.id)); + + /* monochrome: only 1 memory plane */ + /* 8 bit and above: Use whole memory area */ + info->fix.smem_start = cinfo->fbmem_phys; + info->fix.smem_len = (var->bits_per_pixel == 1) ? cinfo->size / 4 : cinfo->size; + info->fix.type = cinfo->currentmode.type; + info->fix.type_aux = 0; + info->fix.visual = cinfo->currentmode.visual; + info->fix.xpanstep = 1; + info->fix.ypanstep = 1; + info->fix.ywrapstep = 0; + info->fix.line_length = cinfo->currentmode.line_length; + + /* FIXME: map region at 0xB8000 if available, fill in here */ + info->fix.mmio_start = cinfo->fbregs_phys; + info->fix.mmio_len = 0; + info->fix.accel = FB_ACCEL_NONE; + + fb_alloc_cmap(&info->cmap, 256, 0); + + return 0; +} + +static int cirrusfb_register(struct cirrusfb_info *cinfo) +{ + struct fb_info *info; + int err; + cirrusfb_board_t btype; + + DPRINTK ("ENTER\n"); + + printk (KERN_INFO "cirrusfb: Driver for Cirrus Logic based graphic boards, v" CIRRUSFB_VERSION "\n"); + + info = cinfo->info; + btype = cinfo->btype; + + /* sanity checks */ + assert (btype != BT_NONE); + + DPRINTK ("cirrusfb: (RAM start set to: 0x%p)\n", cinfo->fbmem); + + /* Make pretend we've set the var so our structures are in a "good" */ + /* state, even though we haven't written the mode to the hw yet... */ + info->var = cirrusfb_predefined[cirrusfb_def_mode].var; + info->var.activate = FB_ACTIVATE_NOW; + + err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info); + if (err < 0) { + /* should never happen */ + DPRINTK("choking on default var... umm, no good.\n"); + goto err_unmap_cirrusfb; + } + + /* set all the vital stuff */ + cirrusfb_set_fbinfo(cinfo); + + err = register_framebuffer(info); + if (err < 0) { + printk (KERN_ERR "cirrusfb: could not register fb device; err = %d!\n", err); + goto err_dealloc_cmap; + } + + DPRINTK ("EXIT, returning 0\n"); + return 0; + +err_dealloc_cmap: + fb_dealloc_cmap(&info->cmap); +err_unmap_cirrusfb: + cinfo->unmap(cinfo); + return err; +} + +static void __devexit cirrusfb_cleanup (struct fb_info *info) +{ + struct cirrusfb_info *cinfo = info->par; + DPRINTK ("ENTER\n"); + + switch_monitor (cinfo, 0); + + unregister_framebuffer (info); + fb_dealloc_cmap (&info->cmap); + printk ("Framebuffer unregistered\n"); + cinfo->unmap(cinfo); + + DPRINTK ("EXIT\n"); +} + + +#ifdef CONFIG_PCI +static int cirrusfb_pci_register (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct cirrusfb_info *cinfo; + struct fb_info *info; + cirrusfb_board_t btype; + unsigned long board_addr, board_size; + int ret; + + ret = pci_enable_device(pdev); + if (ret < 0) { + printk(KERN_ERR "cirrusfb: Cannot enable PCI device\n"); + goto err_out; + } + + info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev); + if (!info) { + printk(KERN_ERR "cirrusfb: could not allocate memory\n"); + ret = -ENOMEM; + goto err_disable; + } + + cinfo = info->par; + cinfo->info = info; + cinfo->pdev = pdev; + cinfo->btype = btype = (cirrusfb_board_t) ent->driver_data; + + DPRINTK (" Found PCI device, base address 0 is 0x%lx, btype set to %d\n", + pdev->resource[0].start, btype); + DPRINTK (" base address 1 is 0x%lx\n", pdev->resource[1].start); + + if(isPReP) { + pci_write_config_dword (pdev, PCI_BASE_ADDRESS_0, 0x00000000); +#ifdef CONFIG_PPC_PREP + get_prep_addrs (&board_addr, &cinfo->fbregs_phys); +#endif + /* PReP dies if we ioremap the IO registers, but it works w/out... */ + cinfo->regbase = (char __iomem *) cinfo->fbregs_phys; + } else { + DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n"); + get_pci_addrs (pdev, &board_addr, &cinfo->fbregs_phys); + cinfo->regbase = NULL; /* FIXME: this forces VGA. alternatives? */ + } + + DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr, cinfo->fbregs_phys); + + board_size = (btype == BT_GD5480) ? + 32 * MB_ : cirrusfb_get_memsize (cinfo->regbase); + + ret = pci_request_regions(pdev, "cirrusfb"); + if (ret <0) { + printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n", + board_addr); + goto err_release_fb; + } +#if 0 /* if the system didn't claim this region, we would... */ + if (!request_mem_region(0xA0000, 65535, "cirrusfb")) { + printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n" +, + 0xA0000L); + ret = -EBUSY; + goto err_release_regions; + } +#endif + if (request_region(0x3C0, 32, "cirrusfb")) + release_io_ports = 1; + + cinfo->fbmem = ioremap(board_addr, board_size); + if (!cinfo->fbmem) { + ret = -EIO; + goto err_release_legacy; + } + + cinfo->fbmem_phys = board_addr; + cinfo->size = board_size; + cinfo->unmap = cirrusfb_pci_unmap; + + printk (" RAM (%lu kB) at 0xx%lx, ", cinfo->size / KB_, board_addr); + printk ("Cirrus Logic chipset on PCI bus\n"); + pci_set_drvdata(pdev, info); + + return cirrusfb_register(cinfo); + +err_release_legacy: + if (release_io_ports) + release_region(0x3C0, 32); +#if 0 + release_mem_region(0xA0000, 65535); +err_release_regions: +#endif + pci_release_regions(pdev); +err_release_fb: + framebuffer_release(info); +err_disable: + pci_disable_device(pdev); +err_out: + return ret; +} + +static void __devexit cirrusfb_pci_unregister (struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + DPRINTK ("ENTER\n"); + + cirrusfb_cleanup (info); + + DPRINTK ("EXIT\n"); +} + +static struct pci_driver cirrusfb_pci_driver = { + .name = "cirrusfb", + .id_table = cirrusfb_pci_table, + .probe = cirrusfb_pci_register, + .remove = __devexit_p(cirrusfb_pci_unregister), +#ifdef CONFIG_PM +#if 0 + .suspend = cirrusfb_pci_suspend, + .resume = cirrusfb_pci_resume, +#endif +#endif +}; +#endif /* CONFIG_PCI */ + + +#ifdef CONFIG_ZORRO +static int cirrusfb_zorro_register(struct zorro_dev *z, + const struct zorro_device_id *ent) +{ + struct cirrusfb_info *cinfo; + struct fb_info *info; + cirrusfb_board_t btype; + struct zorro_dev *z2 = NULL; + unsigned long board_addr, board_size, size; + int ret; + + btype = ent->driver_data; + if (cirrusfb_zorro_table2[btype].id2) + z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL); + size = cirrusfb_zorro_table2[btype].size; + printk(KERN_INFO "cirrusfb: %s board detected; ", + cirrusfb_board_info[btype].name); + + info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); + if (!info) { + printk (KERN_ERR "cirrusfb: could not allocate memory\n"); + ret = -ENOMEM; + goto err_out; + } + + cinfo = info->par; + cinfo->info = info; + cinfo->btype = btype; + + assert (z > 0); + assert (z2 >= 0); + assert (btype != BT_NONE); + + cinfo->zdev = z; + board_addr = zorro_resource_start(z); + board_size = zorro_resource_len(z); + cinfo->size = size; + + if (!zorro_request_device(z, "cirrusfb")) { + printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n", + board_addr); + ret = -EBUSY; + goto err_release_fb; + } + + printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr); + + ret = -EIO; + + if (btype == BT_PICASSO4) { + printk (" REG at $%lx\n", board_addr + 0x600000); + + /* To be precise, for the P4 this is not the */ + /* begin of the board, but the begin of RAM. */ + /* for P4, map in its address space in 2 chunks (### TEST! ) */ + /* (note the ugly hardcoded 16M number) */ + cinfo->regbase = ioremap (board_addr, 16777216); + if (!cinfo->regbase) + goto err_release_region; + + DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase); + cinfo->regbase += 0x600000; + cinfo->fbregs_phys = board_addr + 0x600000; + + cinfo->fbmem_phys = board_addr + 16777216; + cinfo->fbmem = ioremap (cinfo->fbmem_phys, 16777216); + if (!cinfo->fbmem) + goto err_unmap_regbase; + } else { + printk (" REG at $%lx\n", (unsigned long) z2->resource.start); + + cinfo->fbmem_phys = board_addr; + if (board_addr > 0x01000000) + cinfo->fbmem = ioremap (board_addr, board_size); + else + cinfo->fbmem = (caddr_t) ZTWO_VADDR (board_addr); + if (!cinfo->fbmem) + goto err_release_region; + + /* set address for REG area of board */ + cinfo->regbase = (caddr_t) ZTWO_VADDR (z2->resource.start); + cinfo->fbregs_phys = z2->resource.start; + + DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase); + } + cinfo->unmap = cirrusfb_zorro_unmap; + + printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n"); + zorro_set_drvdata(z, info); + + return cirrusfb_register(cinfo); + +err_unmap_regbase: + /* Parental advisory: explicit hack */ + iounmap(cinfo->regbase - 0x600000); +err_release_region: + release_region(board_addr, board_size); +err_release_fb: + framebuffer_release(info); +err_out: + return ret; +} + +void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) +{ + struct fb_info *info = zorro_get_drvdata(z); + DPRINTK ("ENTER\n"); + + cirrusfb_cleanup (info); + + DPRINTK ("EXIT\n"); +} + +static struct zorro_driver cirrusfb_zorro_driver = { + .name = "cirrusfb", + .id_table = cirrusfb_zorro_table, + .probe = cirrusfb_zorro_register, + .remove = __devexit_p(cirrusfb_zorro_unregister), +}; +#endif /* CONFIG_ZORRO */ + +static int __init cirrusfb_init(void) +{ + int error = 0; + +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("cirrusfb", &option)) + return -ENODEV; + cirrusfb_setup(option); +#endif + +#ifdef CONFIG_ZORRO + error |= zorro_module_init(&cirrusfb_zorro_driver); +#endif +#ifdef CONFIG_PCI + error |= pci_register_driver(&cirrusfb_pci_driver); +#endif + return error; +} + + + +#ifndef MODULE +static int __init cirrusfb_setup(char *options) { + char *this_opt, s[32]; + int i; + + DPRINTK ("ENTER\n"); + + if (!options || !*options) + return 0; + + while ((this_opt = strsep (&options, ",")) != NULL) { + if (!*this_opt) continue; + + DPRINTK("cirrusfb_setup: option '%s'\n", this_opt); + + for (i = 0; i < NUM_TOTAL_MODES; i++) { + sprintf (s, "mode:%s", cirrusfb_predefined[i].name); + if (strcmp (this_opt, s) == 0) + cirrusfb_def_mode = i; + } + if (!strcmp(this_opt, "noaccel")) + noaccel = 1; + } + return 0; +} +#endif + + + /* + * Modularization + */ + +MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>"); +MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips"); +MODULE_LICENSE("GPL"); + +static void __exit cirrusfb_exit (void) +{ +#ifdef CONFIG_PCI + pci_unregister_driver(&cirrusfb_pci_driver); +#endif +#ifdef CONFIG_ZORRO + zorro_unregister_driver(&cirrusfb_zorro_driver); +#endif +} + +module_init(cirrusfb_init); + +#ifdef MODULE +module_exit(cirrusfb_exit); +#endif + + +/**********************************************************************/ +/* about the following functions - I have used the same names for the */ +/* functions as Markus Wild did in his Retina driver for NetBSD as */ +/* they just made sense for this purpose. Apart from that, I wrote */ +/* these functions myself. */ +/**********************************************************************/ + +/*** WGen() - write into one of the external/general registers ***/ +static void WGen (const struct cirrusfb_info *cinfo, + int regnum, unsigned char val) +{ + unsigned long regofs = 0; + + if (cinfo->btype == BT_PICASSO) { + /* Picasso II specific hack */ +/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */ + if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D) + regofs = 0xfff; + } + + vga_w (cinfo->regbase, regofs + regnum, val); +} + +/*** RGen() - read out one of the external/general registers ***/ +static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum) +{ + unsigned long regofs = 0; + + if (cinfo->btype == BT_PICASSO) { + /* Picasso II specific hack */ +/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */ + if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D) + regofs = 0xfff; + } + + return vga_r (cinfo->regbase, regofs + regnum); +} + +/*** AttrOn() - turn on VideoEnable for Attribute controller ***/ +static void AttrOn (const struct cirrusfb_info *cinfo) +{ + assert (cinfo != NULL); + + DPRINTK ("ENTER\n"); + + if (vga_rcrt (cinfo->regbase, CL_CRT24) & 0x80) { + /* if we're just in "write value" mode, write back the */ + /* same value as before to not modify anything */ + vga_w (cinfo->regbase, VGA_ATT_IW, + vga_r (cinfo->regbase, VGA_ATT_R)); + } + /* turn on video bit */ +/* vga_w (cinfo->regbase, VGA_ATT_IW, 0x20); */ + vga_w (cinfo->regbase, VGA_ATT_IW, 0x33); + + /* dummy write on Reg0 to be on "write index" mode next time */ + vga_w (cinfo->regbase, VGA_ATT_IW, 0x00); + + DPRINTK ("EXIT\n"); +} + +/*** WHDR() - write into the Hidden DAC register ***/ +/* as the HDR is the only extension register that requires special treatment + * (the other extension registers are accessible just like the "ordinary" + * registers of their functional group) here is a specialized routine for + * accessing the HDR + */ +static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val) +{ + unsigned char dummy; + + if (cinfo->btype == BT_PICASSO) { + /* Klaus' hint for correct access to HDR on some boards */ + /* first write 0 to pixel mask (3c6) */ + WGen (cinfo, VGA_PEL_MSK, 0x00); + udelay (200); + /* next read dummy from pixel address (3c8) */ + dummy = RGen (cinfo, VGA_PEL_IW); + udelay (200); + } + /* now do the usual stuff to access the HDR */ + + dummy = RGen (cinfo, VGA_PEL_MSK); + udelay (200); + dummy = RGen (cinfo, VGA_PEL_MSK); + udelay (200); + dummy = RGen (cinfo, VGA_PEL_MSK); + udelay (200); + dummy = RGen (cinfo, VGA_PEL_MSK); + udelay (200); + + WGen (cinfo, VGA_PEL_MSK, val); + udelay (200); + + if (cinfo->btype == BT_PICASSO) { + /* now first reset HDR access counter */ + dummy = RGen (cinfo, VGA_PEL_IW); + udelay (200); + + /* and at the end, restore the mask value */ + /* ## is this mask always 0xff? */ + WGen (cinfo, VGA_PEL_MSK, 0xff); + udelay (200); + } +} + + +/*** WSFR() - write to the "special function register" (SFR) ***/ +static void WSFR (struct cirrusfb_info *cinfo, unsigned char val) +{ +#ifdef CONFIG_ZORRO + assert (cinfo->regbase != NULL); + cinfo->SFR = val; + z_writeb (val, cinfo->regbase + 0x8000); +#endif +} + +/* The Picasso has a second register for switching the monitor bit */ +static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val) +{ +#ifdef CONFIG_ZORRO + /* writing an arbitrary value to this one causes the monitor switcher */ + /* to flip to Amiga display */ + assert (cinfo->regbase != NULL); + cinfo->SFR = val; + z_writeb (val, cinfo->regbase + 0x9000); +#endif +} + + +/*** WClut - set CLUT entry (range: 0..63) ***/ +static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red, + unsigned char green, unsigned char blue) +{ + unsigned int data = VGA_PEL_D; + + /* address write mode register is not translated.. */ + vga_w (cinfo->regbase, VGA_PEL_IW, regnum); + + if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 || + cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) { + /* but DAC data register IS, at least for Picasso II */ + if (cinfo->btype == BT_PICASSO) + data += 0xfff; + vga_w (cinfo->regbase, data, red); + vga_w (cinfo->regbase, data, green); + vga_w (cinfo->regbase, data, blue); + } else { + vga_w (cinfo->regbase, data, blue); + vga_w (cinfo->regbase, data, green); + vga_w (cinfo->regbase, data, red); + } +} + + +#if 0 +/*** RClut - read CLUT entry (range 0..63) ***/ +static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red, + unsigned char *green, unsigned char *blue) +{ + unsigned int data = VGA_PEL_D; + + vga_w (cinfo->regbase, VGA_PEL_IR, regnum); + + if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 || + cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) { + if (cinfo->btype == BT_PICASSO) + data += 0xfff; + *red = vga_r (cinfo->regbase, data); + *green = vga_r (cinfo->regbase, data); + *blue = vga_r (cinfo->regbase, data); + } else { + *blue = vga_r (cinfo->regbase, data); + *green = vga_r (cinfo->regbase, data); + *red = vga_r (cinfo->regbase, data); + } +} +#endif + + +/******************************************************************* + cirrusfb_WaitBLT() + + Wait for the BitBLT engine to complete a possible earlier job +*********************************************************************/ + +/* FIXME: use interrupts instead */ +static void cirrusfb_WaitBLT (u8 __iomem *regbase) +{ + /* now busy-wait until we're done */ + while (vga_rgfx (regbase, CL_GR31) & 0x08) + /* do nothing */ ; +} + +/******************************************************************* + cirrusfb_BitBLT() + + perform accelerated "scrolling" +********************************************************************/ + +static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel, + u_short curx, u_short cury, u_short destx, u_short desty, + u_short width, u_short height, u_short line_length) +{ + u_short nwidth, nheight; + u_long nsrc, ndest; + u_char bltmode; + + DPRINTK ("ENTER\n"); + + nwidth = width - 1; + nheight = height - 1; + + bltmode = 0x00; + /* if source adr < dest addr, do the Blt backwards */ + if (cury <= desty) { + if (cury == desty) { + /* if src and dest are on the same line, check x */ + if (curx < destx) + bltmode |= 0x01; + } else + bltmode |= 0x01; + } + if (!bltmode) { + /* standard case: forward blitting */ + nsrc = (cury * line_length) + curx; + ndest = (desty * line_length) + destx; + } else { + /* this means start addresses are at the end, counting backwards */ + nsrc = cury * line_length + curx + nheight * line_length + nwidth; + ndest = desty * line_length + destx + nheight * line_length + nwidth; + } + + /* + run-down of registers to be programmed: + destination pitch + source pitch + BLT width/height + source start + destination start + BLT mode + BLT ROP + VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color" + start/stop + */ + + cirrusfb_WaitBLT(regbase); + + /* pitch: set to line_length */ + vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */ + vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */ + vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */ + vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */ + + /* BLT width: actual number of pixels - 1 */ + vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */ + vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */ + + /* BLT height: actual number of lines -1 */ + vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */ + vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */ + + /* BLT destination */ + vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */ + vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */ + vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */ + + /* BLT source */ + vga_wgfx (regbase, CL_GR2C, (u_char) (nsrc & 0xff)); /* BLT src low */ + vga_wgfx (regbase, CL_GR2D, (u_char) (nsrc >> 8)); /* BLT src mid */ + vga_wgfx (regbase, CL_GR2E, (u_char) (nsrc >> 16)); /* BLT src hi */ + + /* BLT mode */ + vga_wgfx (regbase, CL_GR30, bltmode); /* BLT mode */ + + /* BLT ROP: SrcCopy */ + vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */ + + /* and finally: GO! */ + vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */ + + DPRINTK ("EXIT\n"); +} + + +/******************************************************************* + cirrusfb_RectFill() + + perform accelerated rectangle fill +********************************************************************/ + +static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel, + u_short x, u_short y, u_short width, u_short height, + u_char color, u_short line_length) +{ + u_short nwidth, nheight; + u_long ndest; + u_char op; + + DPRINTK ("ENTER\n"); + + nwidth = width - 1; + nheight = height - 1; + + ndest = (y * line_length) + x; + + cirrusfb_WaitBLT(regbase); + + /* pitch: set to line_length */ + vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */ + vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */ + vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */ + vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */ + + /* BLT width: actual number of pixels - 1 */ + vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */ + vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */ + + /* BLT height: actual number of lines -1 */ + vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */ + vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */ + + /* BLT destination */ + vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */ + vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */ + vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */ + + /* BLT source: set to 0 (is a dummy here anyway) */ + vga_wgfx (regbase, CL_GR2C, 0x00); /* BLT src low */ + vga_wgfx (regbase, CL_GR2D, 0x00); /* BLT src mid */ + vga_wgfx (regbase, CL_GR2E, 0x00); /* BLT src hi */ + + /* This is a ColorExpand Blt, using the */ + /* same color for foreground and background */ + vga_wgfx (regbase, VGA_GFX_SR_VALUE, color); /* foreground color */ + vga_wgfx (regbase, VGA_GFX_SR_ENABLE, color); /* background color */ + + op = 0xc0; + if (bits_per_pixel == 16) { + vga_wgfx (regbase, CL_GR10, color); /* foreground color */ + vga_wgfx (regbase, CL_GR11, color); /* background color */ + op = 0x50; + op = 0xd0; + } else if (bits_per_pixel == 32) { + vga_wgfx (regbase, CL_GR10, color); /* foreground color */ + vga_wgfx (regbase, CL_GR11, color); /* background color */ + vga_wgfx (regbase, CL_GR12, color); /* foreground color */ + vga_wgfx (regbase, CL_GR13, color); /* background color */ + vga_wgfx (regbase, CL_GR14, 0); /* foreground color */ + vga_wgfx (regbase, CL_GR15, 0); /* background color */ + op = 0x50; + op = 0xf0; + } + /* BLT mode: color expand, Enable 8x8 copy (faster?) */ + vga_wgfx (regbase, CL_GR30, op); /* BLT mode */ + + /* BLT ROP: SrcCopy */ + vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */ + + /* and finally: GO! */ + vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */ + + DPRINTK ("EXIT\n"); +} + + +/************************************************************************** + * bestclock() - determine closest possible clock lower(?) than the + * desired pixel clock + **************************************************************************/ +static void bestclock (long freq, long *best, long *nom, + long *den, long *div, long maxfreq) +{ + long n, h, d, f; + + assert (best != NULL); + assert (nom != NULL); + assert (den != NULL); + assert (div != NULL); + assert (maxfreq > 0); + + *nom = 0; + *den = 0; + *div = 0; + + DPRINTK ("ENTER\n"); + + if (freq < 8000) + freq = 8000; + + if (freq > maxfreq) + freq = maxfreq; + + *best = 0; + f = freq * 10; + + for (n = 32; n < 128; n++) { + d = (143181 * n) / f; + if ((d >= 7) && (d <= 63)) { + if (d > 31) + d = (d / 2) * 2; + h = (14318 * n) / d; + if (abs (h - freq) < abs (*best - freq)) { + *best = h; + *nom = n; + if (d < 32) { + *den = d; + *div = 0; + } else { + *den = d / 2; + *div = 1; + } + } + } + d = ((143181 * n) + f - 1) / f; + if ((d >= 7) && (d <= 63)) { + if (d > 31) + d = (d / 2) * 2; + h = (14318 * n) / d; + if (abs (h - freq) < abs (*best - freq)) { + *best = h; + *nom = n; + if (d < 32) { + *den = d; + *div = 0; + } else { + *den = d / 2; + *div = 1; + } + } + } + } + + DPRINTK ("Best possible values for given frequency:\n"); + DPRINTK (" best: %ld kHz nom: %ld den: %ld div: %ld\n", + freq, *nom, *den, *div); + + DPRINTK ("EXIT\n"); +} + + +/* ------------------------------------------------------------------------- + * + * debugging functions + * + * ------------------------------------------------------------------------- + */ + +#ifdef CIRRUSFB_DEBUG + +/** + * cirrusfb_dbg_print_byte + * @name: name associated with byte value to be displayed + * @val: byte value to be displayed + * + * DESCRIPTION: + * Display an indented string, along with a hexidecimal byte value, and + * its decoded bits. Bits 7 through 0 are listed in left-to-right + * order. + */ + +static +void cirrusfb_dbg_print_byte (const char *name, unsigned char val) +{ + DPRINTK ("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n", + name, val, + val & 0x80 ? '1' : '0', + val & 0x40 ? '1' : '0', + val & 0x20 ? '1' : '0', + val & 0x10 ? '1' : '0', + val & 0x08 ? '1' : '0', + val & 0x04 ? '1' : '0', + val & 0x02 ? '1' : '0', + val & 0x01 ? '1' : '0'); +} + + +/** + * cirrusfb_dbg_print_regs + * @base: If using newmmio, the newmmio base address, otherwise %NULL + * @reg_class: type of registers to read: %CRT, or %SEQ + * + * DESCRIPTION: + * Dumps the given list of VGA CRTC registers. If @base is %NULL, + * old-style I/O ports are queried for information, otherwise MMIO is + * used at the given @base address to query the information. + */ + +static +void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...) +{ + va_list list; + unsigned char val = 0; + unsigned reg; + char *name; + + va_start (list, reg_class); + + name = va_arg (list, char *); + while (name != NULL) { + reg = va_arg (list, int); + + switch (reg_class) { + case CRT: + val = vga_rcrt (regbase, (unsigned char) reg); + break; + case SEQ: + val = vga_rseq (regbase, (unsigned char) reg); + break; + default: + /* should never occur */ + assert (FALSE); + break; + } + + cirrusfb_dbg_print_byte (name, val); + + name = va_arg (list, char *); + } + + va_end (list); +} + + +/** + * cirrusfb_dump + * @cirrusfbinfo: + * + * DESCRIPTION: + */ + +static +void cirrusfb_dump (void) +{ + cirrusfb_dbg_reg_dump (NULL); +} + + +/** + * cirrusfb_dbg_reg_dump + * @base: If using newmmio, the newmmio base address, otherwise %NULL + * + * DESCRIPTION: + * Dumps a list of interesting VGA and CIRRUSFB registers. If @base is %NULL, + * old-style I/O ports are queried for information, otherwise MMIO is + * used at the given @base address to query the information. + */ + +static +void cirrusfb_dbg_reg_dump (caddr_t regbase) +{ + DPRINTK ("CIRRUSFB VGA CRTC register dump:\n"); + + cirrusfb_dbg_print_regs (regbase, CRT, + "CR00", 0x00, + "CR01", 0x01, + "CR02", 0x02, + "CR03", 0x03, + "CR04", 0x04, + "CR05", 0x05, + "CR06", 0x06, + "CR07", 0x07, + "CR08", 0x08, + "CR09", 0x09, + "CR0A", 0x0A, + "CR0B", 0x0B, + "CR0C", 0x0C, + "CR0D", 0x0D, + "CR0E", 0x0E, + "CR0F", 0x0F, + "CR10", 0x10, + "CR11", 0x11, + "CR12", 0x12, + "CR13", 0x13, + "CR14", 0x14, + "CR15", 0x15, + "CR16", 0x16, + "CR17", 0x17, + "CR18", 0x18, + "CR22", 0x22, + "CR24", 0x24, + "CR26", 0x26, + "CR2D", 0x2D, + "CR2E", 0x2E, + "CR2F", 0x2F, + "CR30", 0x30, + "CR31", 0x31, + "CR32", 0x32, + "CR33", 0x33, + "CR34", 0x34, + "CR35", 0x35, + "CR36", 0x36, + "CR37", 0x37, + "CR38", 0x38, + "CR39", 0x39, + "CR3A", 0x3A, + "CR3B", 0x3B, + "CR3C", 0x3C, + "CR3D", 0x3D, + "CR3E", 0x3E, + "CR3F", 0x3F, + NULL); + + DPRINTK ("\n"); + + DPRINTK ("CIRRUSFB VGA SEQ register dump:\n"); + + cirrusfb_dbg_print_regs (regbase, SEQ, + "SR00", 0x00, + "SR01", 0x01, + "SR02", 0x02, + "SR03", 0x03, + "SR04", 0x04, + "SR08", 0x08, + "SR09", 0x09, + "SR0A", 0x0A, + "SR0B", 0x0B, + "SR0D", 0x0D, + "SR10", 0x10, + "SR11", 0x11, + "SR12", 0x12, + "SR13", 0x13, + "SR14", 0x14, + "SR15", 0x15, + "SR16", 0x16, + "SR17", 0x17, + "SR18", 0x18, + "SR19", 0x19, + "SR1A", 0x1A, + "SR1B", 0x1B, + "SR1C", 0x1C, + "SR1D", 0x1D, + "SR1E", 0x1E, + "SR1F", 0x1F, + NULL); + + DPRINTK ("\n"); +} + +#endif /* CIRRUSFB_DEBUG */ + diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c new file mode 100644 index 000000000000..8692e002986b --- /dev/null +++ b/drivers/video/clps711xfb.c @@ -0,0 +1,443 @@ +/* + * linux/drivers/video/clps711xfb.c + * + * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Framebuffer driver for the CLPS7111 and EP7212 processors. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/delay.h> + +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/uaccess.h> + +#include <asm/hardware/clps7111.h> +#include <asm/arch/syspld.h> + +struct fb_info *cfb; + +#define CMAP_MAX_SIZE 16 + +/* The /proc entry for the backlight. */ +static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL; + +static int clps7111fb_proc_backlight_read(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int clps7111fb_proc_backlight_write(struct file *file, + const char *buffer, unsigned long count, void *data); + +/* + * LCD AC Prescale. This comes from the LCD panel manufacturers specifications. + * This determines how many clocks + 1 of CL1 before the M signal toggles. + * The number of lines on the display must not be divisible by this number. + */ +static unsigned int lcd_ac_prescale = 13; + +/* + * Set a single color register. Return != 0 for invalid regno. + */ +static int +clps7111fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + unsigned int level, mask, shift, pal; + + if (regno >= (1 << info->var.bits_per_pixel)) + return 1; + + /* gray = 0.30*R + 0.58*G + 0.11*B */ + level = (red * 77 + green * 151 + blue * 28) >> 20; + + /* + * On an LCD, a high value is dark, while a low value is light. + * So we invert the level. + * + * This isn't true on all machines, so we only do it on EDB7211. + * --rmk + */ + if (machine_is_edb7211()) { + level = 15 - level; + } + + shift = 4 * (regno & 7); + level <<= shift; + mask = 15 << shift; + level &= mask; + + regno = regno < 8 ? PALLSW : PALMSW; + + pal = clps_readl(regno); + pal = (pal & ~mask) | level; + clps_writel(pal, regno); + + return 0; +} + +/* + * Validate the purposed mode. + */ +static int +clps7111fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + var->transp.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + var->red.msb_right = 0; + var->red.offset = 0; + var->red.length = var->bits_per_pixel; + var->green = var->red; + var->blue = var->red; + + if (var->bits_per_pixel > 4) + return -EINVAL; + + return 0; +} + +/* + * Set the hardware state. + */ +static int +clps7111fb_set_par(struct fb_info *info) +{ + unsigned int lcdcon, syscon, pixclock; + + switch (info->var.bits_per_pixel) { + case 1: + info->fix.visual = FB_VISUAL_MONO01; + break; + case 2: + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + case 4: + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + } + + info->fix.line_length = info->var.xres_virtual * info->var.bits_per_pixel / 8; + + lcdcon = (info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel) / 128 - 1; + lcdcon |= ((info->var.xres_virtual / 16) - 1) << 13; + lcdcon |= lcd_ac_prescale << 25; + + /* + * Calculate pixel prescale value from the pixclock. This is: + * 36.864MHz / pixclock_mhz - 1. + * However, pixclock is in picoseconds, so this ends up being: + * 36864000 * pixclock_ps / 10^12 - 1 + * and this will overflow the 32-bit math. We perform this as + * (9 * 4096000 == 36864000): + * pixclock_ps * 9 * (4096000 / 10^12) - 1 + */ + pixclock = 9 * info->var.pixclock / 244140 - 1; + lcdcon |= pixclock << 19; + + if (info->var.bits_per_pixel == 4) + lcdcon |= LCDCON_GSMD; + if (info->var.bits_per_pixel >= 2) + lcdcon |= LCDCON_GSEN; + + /* + * LCDCON must only be changed while the LCD is disabled + */ + syscon = clps_readl(SYSCON1); + clps_writel(syscon & ~SYSCON1_LCDEN, SYSCON1); + clps_writel(lcdcon, LCDCON); + clps_writel(syscon | SYSCON1_LCDEN, SYSCON1); + return 0; +} + +static int clps7111fb_blank(int blank, struct fb_info *info) +{ + if (blank) { + if (machine_is_edb7211()) { + /* Turn off the LCD backlight. */ + clps_writeb(clps_readb(PDDR) & ~EDB_PD3_LCDBL, PDDR); + + /* Power off the LCD DC-DC converter. */ + clps_writeb(clps_readb(PDDR) & ~EDB_PD1_LCD_DC_DC_EN, PDDR); + + /* Delay for a little while (half a second). */ + udelay(100); + + /* Power off the LCD panel. */ + clps_writeb(clps_readb(PDDR) & ~EDB_PD2_LCDEN, PDDR); + + /* Power off the LCD controller. */ + clps_writel(clps_readl(SYSCON1) & ~SYSCON1_LCDEN, + SYSCON1); + } + } else { + if (machine_is_edb7211()) { + /* Power up the LCD controller. */ + clps_writel(clps_readl(SYSCON1) | SYSCON1_LCDEN, + SYSCON1); + + /* Power up the LCD panel. */ + clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR); + + /* Delay for a little while. */ + udelay(100); + + /* Power up the LCD DC-DC converter. */ + clps_writeb(clps_readb(PDDR) | EDB_PD1_LCD_DC_DC_EN, + PDDR); + + /* Turn on the LCD backlight. */ + clps_writeb(clps_readb(PDDR) | EDB_PD3_LCDBL, PDDR); + } + } + return 0; +} + +static struct fb_ops clps7111fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = clps7111fb_check_var, + .fb_set_par = clps7111fb_set_par, + .fb_setcolreg = clps7111fb_setcolreg, + .fb_blank = clps7111fb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +static int +clps7111fb_proc_backlight_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + /* We need at least two characters, one for the digit, and one for + * the terminating NULL. */ + if (count < 2) + return -EINVAL; + + if (machine_is_edb7211()) { + return sprintf(page, "%d\n", + (clps_readb(PDDR) & EDB_PD3_LCDBL) ? 1 : 0); + } + + return 0; +} + +static int +clps7111fb_proc_backlight_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned char char_value; + int value; + + if (count < 1) { + return -EINVAL; + } + + if (copy_from_user(&char_value, buffer, 1)) + return -EFAULT; + + value = char_value - '0'; + + if (machine_is_edb7211()) { + unsigned char port_d; + + port_d = clps_readb(PDDR); + + if (value) { + port_d |= EDB_PD3_LCDBL; + } else { + port_d &= ~EDB_PD3_LCDBL; + } + + clps_writeb(port_d, PDDR); + } + + return count; +} + +static void __init clps711x_guess_lcd_params(struct fb_info *info) +{ + unsigned int lcdcon, syscon, size; + unsigned long phys_base = PAGE_OFFSET; + void *virt_base = (void *)PAGE_OFFSET; + + info->var.xres_virtual = 640; + info->var.yres_virtual = 240; + info->var.bits_per_pixel = 4; + info->var.activate = FB_ACTIVATE_NOW; + info->var.height = -1; + info->var.width = -1; + info->var.pixclock = 93006; /* 10.752MHz pixel clock */ + + /* + * If the LCD controller is already running, decode the values + * in LCDCON to xres/yres/bpp/pixclock/acprescale + */ + syscon = clps_readl(SYSCON1); + if (syscon & SYSCON1_LCDEN) { + lcdcon = clps_readl(LCDCON); + + /* + * Decode GSMD and GSEN bits to bits per pixel + */ + switch (lcdcon & (LCDCON_GSMD | LCDCON_GSEN)) { + case LCDCON_GSMD | LCDCON_GSEN: + info->var.bits_per_pixel = 4; + break; + + case LCDCON_GSEN: + info->var.bits_per_pixel = 2; + break; + + default: + info->var.bits_per_pixel = 1; + break; + } + + /* + * Decode xres/yres + */ + info->var.xres_virtual = (((lcdcon >> 13) & 0x3f) + 1) * 16; + info->var.yres_virtual = (((lcdcon & 0x1fff) + 1) * 128) / + (info->var.xres_virtual * + info->var.bits_per_pixel); + + /* + * Calculate pixclock + */ + info->var.pixclock = (((lcdcon >> 19) & 0x3f) + 1) * 244140 / 9; + + /* + * Grab AC prescale + */ + lcd_ac_prescale = (lcdcon >> 25) & 0x1f; + } + + info->var.xres = info->var.xres_virtual; + info->var.yres = info->var.yres_virtual; + info->var.grayscale = info->var.bits_per_pixel > 1; + + size = info->var.xres * info->var.yres * info->var.bits_per_pixel / 8; + + /* + * Might be worth checking to see if we can use the on-board + * RAM if size here... + * CLPS7110 - no on-board SRAM + * EP7212 - 38400 bytes + */ + if (size <= 38400) { + printk(KERN_INFO "CLPS711xFB: could use on-board SRAM?\n"); + } + + if ((syscon & SYSCON1_LCDEN) == 0) { + /* + * The display isn't running. Ensure that + * the display memory is empty. + */ + memset(virt_base, 0, size); + } + + info->screen_base = virt_base; + info->fix.smem_start = phys_base; + info->fix.smem_len = PAGE_ALIGN(size); + info->fix.type = FB_TYPE_PACKED_PIXELS; +} + +int __init clps711xfb_init(void) +{ + int err = -ENOMEM; + + if (fb_get_options("clps711xfb", NULL)) + return -ENODEV; + + cfb = kmalloc(sizeof(*cfb), GFP_KERNEL); + if (!cfb) + goto out; + + memset(cfb, 0, sizeof(*cfb)); + strcpy(cfb->fix.id, "clps711x"); + + cfb->fbops = &clps7111fb_ops; + cfb->flags = FBINFO_DEFAULT; + + clps711x_guess_lcd_params(cfb); + + fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0); + + /* Register the /proc entries. */ + clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444, + &proc_root); + if (clps7111fb_backlight_proc_entry == NULL) { + printk("Couldn't create the /proc entry for the backlight.\n"); + return -EINVAL; + } + + clps7111fb_backlight_proc_entry->read_proc = + &clps7111fb_proc_backlight_read; + clps7111fb_backlight_proc_entry->write_proc = + &clps7111fb_proc_backlight_write; + + /* + * Power up the LCD + */ + if (machine_is_p720t()) { + PLD_LCDEN = PLD_LCDEN_EN; + PLD_PWR |= (PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON); + } + + if (machine_is_edb7211()) { + /* Power up the LCD panel. */ + clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR); + + /* Delay for a little while. */ + udelay(100); + + /* Power up the LCD DC-DC converter. */ + clps_writeb(clps_readb(PDDR) | EDB_PD1_LCD_DC_DC_EN, PDDR); + + /* Turn on the LCD backlight. */ + clps_writeb(clps_readb(PDDR) | EDB_PD3_LCDBL, PDDR); + } + + err = register_framebuffer(cfb); + +out: return err; +} + +static void __exit clps711xfb_exit(void) +{ + unregister_framebuffer(cfb); + kfree(cfb); + + /* + * Power down the LCD + */ + if (machine_is_p720t()) { + PLD_LCDEN = 0; + PLD_PWR &= ~(PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON); + } +} + +module_init(clps711xfb_init); +module_exit(clps711xfb_exit); + +MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); +MODULE_DESCRIPTION("CLPS711x framebuffer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig new file mode 100644 index 000000000000..ccf55811d24f --- /dev/null +++ b/drivers/video/console/Kconfig @@ -0,0 +1,191 @@ +# +# Video configuration +# + +menu "Console display driver support" + +config VGA_CONSOLE + bool "VGA text console" if EMBEDDED || !X86 + depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC32 && !SPARC64 && !M68K && !PARISC + default y + help + Saying Y here will allow you to use Linux in text mode through a + display that complies with the generic VGA standard. Virtually + everyone wants that. + + The program SVGATextMode can be used to utilize SVGA video cards to + their full potential in text mode. Download it from + <ftp://ibiblio.org/pub/Linux/utils/console/>. + + Say Y. + +# if [ "$CONFIG_PCI" = "y" -a "$CONFIG_VGA_CONSOLE" = "y" ]; then +# bool ' Allow VGA on any bus?' CONFIG_VGA_HOSE +# if [ "$CONFIG_VGA_HOSE" = "y" ]; then +# define_bool CONFIG_DUMMY_CONSOLE y +# fi +# fi + +config VIDEO_SELECT + bool "Video mode selection support" + depends on (X86 || X86_64) && VGA_CONSOLE + ---help--- + This enables support for text mode selection on kernel startup. If + you want to take advantage of some high-resolution text mode your + card's BIOS offers, but the traditional Linux utilities like + SVGATextMode don't, you can say Y here and set the mode using the + "vga=" option from your boot loader (lilo or loadlin) or set + "vga=ask" which brings up a video mode menu on kernel startup. (Try + "man bootparam" or see the documentation of your boot loader about + how to pass options to the kernel.) + + Read the file <file:Documentation/svga.txt> for more information + about the Video mode selection support. If unsure, say N. + +config MDA_CONSOLE + depends on !M68K && !PARISC && ISA + tristate "MDA text console (dual-headed) (EXPERIMENTAL)" + ---help--- + Say Y here if you have an old MDA or monochrome Hercules graphics + adapter in your system acting as a second head ( = video card). You + will then be able to use two monitors with your Linux system. Do not + say Y here if your MDA card is the primary card in your system; the + normal VGA driver will handle it. + + To compile this driver as a module, choose M here: the + module will be called mdacon. + + If unsure, say N. + +config SGI_NEWPORT_CONSOLE + tristate "SGI Newport Console support" + depends on SGI_IP22 + help + Say Y here if you want the console on the Newport aka XL graphics + card of your Indy. Most people say Y here. + +# bool 'IODC console' CONFIG_IODC_CONSOLE + +config PROM_CONSOLE + bool "PROM console" + depends on SPARC32 || SPARC64 + help + Say Y to build a console driver for Sun machines that uses the + terminal emulation built into their console PROMS. + +config DUMMY_CONSOLE + bool + depends on PROM_CONSOLE!=y || VGA_CONSOLE!=y || SGI_NEWPORT_CONSOLE!=y + default y + +config DUMMY_CONSOLE_COLUMNS + int "Initial number of console screen columns" + depends on PARISC && DUMMY_CONSOLE + 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 console screen rows" + depends on PARISC && DUMMY_CONSOLE + 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 FRAMEBUFFER_CONSOLE + tristate "Framebuffer Console support" + depends on FB + select CRC32 + +config STI_CONSOLE + tristate "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 FONTS + bool "Select compiled-in fonts" + depends on FRAMEBUFFER_CONSOLE + help + Say Y here if you would like to use fonts other than the default + your frame buffer console usually use. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about foreign fonts. + + If unsure, say N (the default choices are safe). + +config FONT_8x8 + bool "VGA 8x8 font" if FONTS + depends on FRAMEBUFFER_CONSOLE + default y if !SPARC32 && !SPARC64 && !FONTS + help + This is the "high resolution" font for the VGA frame buffer (the one + provided by the text console 80x50 (and higher) modes). + + Note that this is a poor quality font. The VGA 8x16 font is quite a + lot more readable. + + Given the resolution provided by the frame buffer device, answer N + here is safe. + +config FONT_8x16 + bool "VGA 8x16 font" if FONTS + depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y + default y if !SPARC32 && !SPARC64 && !FONTS + help + This is the "high resolution" font for the VGA frame buffer (the one + provided by the VGA text console 80x25 mode. + + If unsure, say Y. + +config FONT_6x11 + bool "Mac console 6x11 font (not supported by all drivers)" if FONTS + depends on FRAMEBUFFER_CONSOLE + default y if !SPARC32 && !SPARC64 && !FONTS && MAC + help + Small console font with Macintosh-style high-half glyphs. Some Mac + framebuffer drivers don't support this one at all. + +config FONT_PEARL_8x8 + bool "Pearl (old m68k) console 8x8 font" if FONTS + depends on FRAMEBUFFER_CONSOLE + default y if !SPARC32 && !SPARC64 && !FONTS && AMIGA + help + Small console font with PC-style control-character and high-half + glyphs. + +config FONT_ACORN_8x8 + bool "Acorn console 8x8 font" if FONTS + depends on FRAMEBUFFER_CONSOLE + default y if !SPARC32 && !SPARC64 && !FONTS && ARM && ARCH_ACORN + help + Small console font with PC-style control characters and high-half + glyphs. + +config FONT_MINI_4x6 + bool "Mini 4x6 font" + depends on !SPARC32 && !SPARC64 && FONTS + +config FONT_SUN8x16 + bool "Sparc console 8x16 font" + depends on FRAMEBUFFER_CONSOLE && (!SPARC32 && !SPARC64 && FONTS || SPARC32 || SPARC64) + help + This is the high resolution console font for Sun machines. Say Y. + +config FONT_SUN12x22 + bool "Sparc console 12x22 font (not supported by all drivers)" + 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 + standard font is unreadable for you, say Y, otherwise say N. + +endmenu + diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile new file mode 100644 index 000000000000..33516447f9f2 --- /dev/null +++ b/drivers/video/console/Makefile @@ -0,0 +1,43 @@ +# Makefile for the Linux graphics to console drivers. +# 5 Aug 1999, James Simmons, <mailto:jsimmons@users.sf.net> +# Rewritten to use lists instead of if-statements. + +# Font handling +font-objs := fonts.o + +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. + +obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o +obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o font.o +obj-$(CONFIG_PROM_CONSOLE) += promcon.o promcon_tbl.o +obj-$(CONFIG_STI_CONSOLE) += sticon.o sticore.o font.o +obj-$(CONFIG_VGA_CONSOLE) += vgacon.o +obj-$(CONFIG_MDA_CONSOLE) += mdacon.o +obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o +ifeq ($(CONFIG_FB_TILEBLITTING),y) +obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += tileblit.o +endif + +obj-$(CONFIG_FB_STI) += sticore.o font.o + +# Targets that kbuild needs to know about +targets := promcon_tbl.c + +quiet_cmd_conmakehash = CNMKHSH $@ + cmd_conmakehash = scripts/conmakehash $< | \ + sed -e '/\#include <[^>]*>/p' -e 's/types/init/' \ + -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > $@ + +$(obj)/promcon_tbl.c: $(src)/prom.uni + $(call cmd,conmakehash) diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c new file mode 100644 index 000000000000..b28a4b0e395e --- /dev/null +++ b/drivers/video/console/bitblit.c @@ -0,0 +1,405 @@ +/* + * linux/drivers/video/console/bitblit.c -- BitBlitting Operation + * + * Originally from the 'accel_*' routines in drivers/video/console/fbcon.c + * + * Copyright (C) 2004 Antonino Daplas <adaplas @pol.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. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/vt_kern.h> +#include <linux/console.h> +#include <asm/types.h> +#include "fbcon.h" + +/* + * Accelerated handlers. + */ +#define FBCON_ATTRIBUTE_UNDERLINE 1 +#define FBCON_ATTRIBUTE_REVERSE 2 +#define FBCON_ATTRIBUTE_BOLD 4 + +static inline int real_y(struct display *p, int ypos) +{ + int rows = p->vrows; + + ypos += p->yscroll; + return ypos < rows ? ypos : ypos - rows; +} + + +static inline int get_attribute(struct fb_info *info, u16 c) +{ + int attribute = 0; + + if (fb_get_color_depth(&info->var) == 1) { + if (attr_underline(c)) + attribute |= FBCON_ATTRIBUTE_UNDERLINE; + if (attr_reverse(c)) + attribute |= FBCON_ATTRIBUTE_REVERSE; + if (attr_bold(c)) + attribute |= FBCON_ATTRIBUTE_BOLD; + } + + return attribute; +} + +static inline void update_attr(u8 *dst, u8 *src, int attribute, + struct vc_data *vc) +{ + int i, offset = (vc->vc_font.height < 10) ? 1 : 2; + int width = (vc->vc_font.width + 7) >> 3; + unsigned int cellsize = vc->vc_font.height * width; + u8 c; + + offset = cellsize - (offset * width); + for (i = 0; i < cellsize; i++) { + c = src[i]; + if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset) + c = 0xff; + if (attribute & FBCON_ATTRIBUTE_BOLD) + c |= c >> 1; + if (attribute & FBCON_ATTRIBUTE_REVERSE) + c = ~c; + dst[i] = c; + } +} + +static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) +{ + struct fb_copyarea area; + + area.sx = sx * vc->vc_font.width; + area.sy = sy * vc->vc_font.height; + area.dx = dx * vc->vc_font.width; + area.dy = dy * vc->vc_font.height; + area.height = height * vc->vc_font.height; + area.width = width * vc->vc_font.width; + + info->fbops->fb_copyarea(info, &area); +} + +static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width) +{ + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + struct fb_fillrect region; + + region.color = attr_bgcol_ec(bgshift, vc); + region.dx = sx * vc->vc_font.width; + region.dy = sy * vc->vc_font.height; + region.width = width * vc->vc_font.width; + region.height = height * vc->vc_font.height; + region.rop = ROP_COPY; + + info->fbops->fb_fillrect(info, ®ion); +} + +static void bit_putcs(struct vc_data *vc, struct fb_info *info, + const unsigned short *s, int count, int yy, int xx, + int fg, int bg) +{ + void (*move_unaligned)(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 idx, + u32 height, u32 shift_high, u32 shift_low, + u32 mod); + void (*move_aligned)(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, + u32 height); + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + unsigned int width = (vc->vc_font.width + 7) >> 3; + unsigned int cellsize = vc->vc_font.height * width; + unsigned int maxcnt = info->pixmap.size/cellsize; + unsigned int scan_align = info->pixmap.scan_align - 1; + unsigned int buf_align = info->pixmap.buf_align - 1; + unsigned int shift_low = 0, mod = vc->vc_font.width % 8; + unsigned int shift_high = 8, pitch, cnt, size, k; + unsigned int idx = vc->vc_font.width >> 3; + unsigned int attribute = get_attribute(info, scr_readw(s)); + struct fb_image image; + u8 *src, *dst, *buf = NULL; + + if (attribute) { + buf = kmalloc(cellsize, GFP_KERNEL); + if (!buf) + return; + } + + image.fg_color = fg; + image.bg_color = bg; + + image.dx = xx * vc->vc_font.width; + image.dy = yy * vc->vc_font.height; + image.height = vc->vc_font.height; + image.depth = 1; + + if (info->pixmap.outbuf && info->pixmap.inbuf) { + move_aligned = fb_iomove_buf_aligned; + move_unaligned = fb_iomove_buf_unaligned; + } else { + move_aligned = fb_sysmove_buf_aligned; + move_unaligned = fb_sysmove_buf_unaligned; + } + while (count) { + if (count > maxcnt) + cnt = k = maxcnt; + else + cnt = k = count; + + image.width = vc->vc_font.width * cnt; + pitch = ((image.width + 7) >> 3) + scan_align; + pitch &= ~scan_align; + size = pitch * image.height + buf_align; + size &= ~buf_align; + dst = fb_get_buffer_offset(info, &info->pixmap, size); + image.data = dst; + if (mod) { + while (k--) { + src = vc->vc_font.data + (scr_readw(s++)& + charmask)*cellsize; + + if (attribute) { + update_attr(buf, src, attribute, vc); + src = buf; + } + + move_unaligned(info, &info->pixmap, dst, pitch, + src, idx, image.height, + shift_high, shift_low, mod); + shift_low += mod; + dst += (shift_low >= 8) ? width : width - 1; + shift_low &= 7; + shift_high = 8 - shift_low; + } + } else { + while (k--) { + src = vc->vc_font.data + (scr_readw(s++)& + charmask)*cellsize; + + if (attribute) { + update_attr(buf, src, attribute, vc); + src = buf; + } + + move_aligned(info, &info->pixmap, dst, pitch, + src, idx, image.height); + dst += width; + } + } + info->fbops->fb_imageblit(info, &image); + image.dx += cnt * vc->vc_font.width; + count -= cnt; + } + + /* buf is always NULL except when in monochrome mode, so in this case + it's a gain to check buf against NULL even though kfree() handles + NULL pointers just fine */ + if (unlikely(buf)) + kfree(buf); +} + +static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, + int bottom_only) +{ + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + unsigned int cw = vc->vc_font.width; + unsigned int ch = vc->vc_font.height; + unsigned int rw = info->var.xres - (vc->vc_cols*cw); + unsigned int bh = info->var.yres - (vc->vc_rows*ch); + unsigned int rs = info->var.xres - rw; + unsigned int bs = info->var.yres - bh; + struct fb_fillrect region; + + region.color = attr_bgcol_ec(bgshift, vc); + region.rop = ROP_COPY; + + if (rw && !bottom_only) { + region.dx = info->var.xoffset + rs; + region.dy = 0; + region.width = rw; + region.height = info->var.yres_virtual; + info->fbops->fb_fillrect(info, ®ion); + } + + if (bh) { + region.dx = info->var.xoffset; + region.dy = info->var.yoffset + bs; + region.width = rs; + region.height = bh; + info->fbops->fb_fillrect(info, ®ion); + } +} + +static void bit_cursor(struct vc_data *vc, struct fb_info *info, + struct display *p, int mode, int softback_lines, int fg, int bg) +{ + struct fb_cursor cursor; + struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int w = (vc->vc_font.width + 7) >> 3, c; + int y = real_y(p, vc->vc_y); + int attribute, use_sw = (vc->vc_cursor_type & 0x10); + char *src; + + cursor.set = 0; + + if (softback_lines) { + if (y + softback_lines >= vc->vc_rows) { + mode = CM_ERASE; + ops->cursor_flash = 0; + return; + } else + y += softback_lines; + } + + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); + src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); + + if (ops->cursor_state.image.data != src || + ops->cursor_reset) { + ops->cursor_state.image.data = src; + cursor.set |= FB_CUR_SETIMAGE; + } + + if (attribute) { + u8 *dst; + + dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC); + if (!dst) + return; + kfree(ops->cursor_data); + ops->cursor_data = dst; + update_attr(dst, src, attribute, vc); + src = dst; + } + + if (ops->cursor_state.image.fg_color != fg || + ops->cursor_state.image.bg_color != bg || + ops->cursor_reset) { + ops->cursor_state.image.fg_color = fg; + ops->cursor_state.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + + if ((ops->cursor_state.image.dx != (vc->vc_font.width * vc->vc_x)) || + (ops->cursor_state.image.dy != (vc->vc_font.height * y)) || + ops->cursor_reset) { + ops->cursor_state.image.dx = vc->vc_font.width * vc->vc_x; + ops->cursor_state.image.dy = vc->vc_font.height * y; + cursor.set |= FB_CUR_SETPOS; + } + + if (ops->cursor_state.image.height != vc->vc_font.height || + ops->cursor_state.image.width != vc->vc_font.width || + ops->cursor_reset) { + ops->cursor_state.image.height = vc->vc_font.height; + ops->cursor_state.image.width = vc->vc_font.width; + cursor.set |= FB_CUR_SETSIZE; + } + + if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || + ops->cursor_reset) { + ops->cursor_state.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if (cursor.set & FB_CUR_SETSIZE || + vc->vc_cursor_type != p->cursor_shape || + ops->cursor_state.mask == NULL || + ops->cursor_reset) { + char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC); + int cur_height, size, i = 0; + u8 msk = 0xff; + + if (!mask) + return; + + kfree(ops->cursor_state.mask); + ops->cursor_state.mask = mask; + + p->cursor_shape = vc->vc_cursor_type; + cursor.set |= FB_CUR_SETSHAPE; + + switch (p->cursor_shape & CUR_HWMASK) { + case CUR_NONE: + cur_height = 0; + break; + case CUR_UNDERLINE: + cur_height = (vc->vc_font.height < 10) ? 1 : 2; + break; + case CUR_LOWER_THIRD: + cur_height = vc->vc_font.height/3; + break; + case CUR_LOWER_HALF: + cur_height = vc->vc_font.height >> 1; + break; + case CUR_TWO_THIRDS: + cur_height = (vc->vc_font.height << 1)/3; + break; + case CUR_BLOCK: + default: + cur_height = vc->vc_font.height; + break; + } + size = (vc->vc_font.height - cur_height) * w; + while (size--) + mask[i++] = ~msk; + size = cur_height * w; + while (size--) + mask[i++] = msk; + } + + switch (mode) { + case CM_ERASE: + ops->cursor_state.enable = 0; + break; + case CM_DRAW: + case CM_MOVE: + default: + ops->cursor_state.enable = (use_sw) ? 0 : 1; + break; + } + + cursor.image.data = src; + cursor.image.fg_color = ops->cursor_state.image.fg_color; + cursor.image.bg_color = ops->cursor_state.image.bg_color; + cursor.image.dx = ops->cursor_state.image.dx; + cursor.image.dy = ops->cursor_state.image.dy; + cursor.image.height = ops->cursor_state.image.height; + cursor.image.width = ops->cursor_state.image.width; + cursor.hot.x = ops->cursor_state.hot.x; + cursor.hot.y = ops->cursor_state.hot.y; + cursor.mask = ops->cursor_state.mask; + cursor.enable = ops->cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + + info->fbops->fb_cursor(info, &cursor); + + ops->cursor_reset = 0; +} + +void fbcon_set_bitops(struct fbcon_ops *ops) +{ + ops->bmove = bit_bmove; + ops->clear = bit_clear; + ops->putcs = bit_putcs; + ops->clear_margins = bit_clear_margins; + ops->cursor = bit_cursor; +} + +EXPORT_SYMBOL(fbcon_set_bitops); + +MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); +MODULE_DESCRIPTION("Bit Blitting Operation"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c new file mode 100644 index 000000000000..1ecda91e5a9c --- /dev/null +++ b/drivers/video/console/dummycon.c @@ -0,0 +1,80 @@ +/* + * linux/drivers/video/dummycon.c -- A dummy console driver + * + * To be used if there's no other console driver (e.g. for plain VGA text) + * available, usually until fbcon takes console over. + */ + +#include <linux/types.h> +#include <linux/kdev_t.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/vt_kern.h> +#include <linux/init.h> +#include <linux/module.h> + +/* + * Dummy console driver + */ + +#if defined(__arm__) +#define DUMMY_COLUMNS ORIG_VIDEO_COLS +#define DUMMY_ROWS ORIG_VIDEO_LINES +#elif defined(__hppa__) +/* 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 +#endif + +static const char *dummycon_startup(void) +{ + return "dummy device"; +} + +static void dummycon_init(struct vc_data *vc, int init) +{ + vc->vc_can_do_color = 1; + if (init) { + vc->vc_cols = DUMMY_COLUMNS; + vc->vc_rows = DUMMY_ROWS; + } else + vc_resize(vc, DUMMY_COLUMNS, DUMMY_ROWS); +} + +static int dummycon_dummy(void) +{ + return 0; +} + +#define DUMMY (void *)dummycon_dummy + +/* + * The console `switch' structure for the dummy console + * + * Most of the operations are dummies. + */ + +const struct consw dummy_con = { + .owner = THIS_MODULE, + .con_startup = dummycon_startup, + .con_init = dummycon_init, + .con_deinit = DUMMY, + .con_clear = DUMMY, + .con_putc = DUMMY, + .con_putcs = DUMMY, + .con_cursor = DUMMY, + .con_scroll = DUMMY, + .con_bmove = DUMMY, + .con_switch = DUMMY, + .con_blank = DUMMY, + .con_font_set = DUMMY, + .con_font_get = DUMMY, + .con_font_default = DUMMY, + .con_font_copy = DUMMY, + .con_set_palette = DUMMY, + .con_scrolldelta = DUMMY, +}; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c new file mode 100644 index 000000000000..59e3b4b4e7e3 --- /dev/null +++ b/drivers/video/console/fbcon.c @@ -0,0 +1,2814 @@ +/* + * linux/drivers/video/fbcon.c -- Low level frame buffer based console driver + * + * Copyright (C) 1995 Geert Uytterhoeven + * + * + * This file is based on the original Amiga console driver (amicon.c): + * + * Copyright (C) 1993 Hamish Macdonald + * Greg Harp + * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] + * + * with work by William Rucklidge (wjr@cs.cornell.edu) + * Geert Uytterhoeven + * Jes Sorensen (jds@kom.auc.dk) + * Martin Apel + * + * and on the original Atari console driver (atacon.c): + * + * Copyright (C) 1993 Bjoern Brauel + * Roman Hodek + * + * with work by Guenther Kelleter + * Martin Schaller + * Andreas Schwab + * + * Hardware cursor support added by Emmanuel Marty (core@ggi-project.org) + * Smart redraw scrolling, arbitrary font width support, 512char font support + * and software scrollback added by + * Jakub Jelinek (jj@ultra.linux.cz) + * + * Random hacking by Martin Mares <mj@ucw.cz> + * + * 2001 - Documented with DocBook + * - Brad Douglas <brad@neruo.com> + * + * The low level operations for the various display memory organizations are + * now in separate source files. + * + * Currently the following organizations are supported: + * + * o afb Amiga bitplanes + * o cfb{2,4,8,16,24,32} Packed pixels + * o ilbm Amiga interleaved bitplanes + * o iplan2p[248] Atari interleaved bitplanes + * o mfb Monochrome + * o vga VGA characters/attributes + * + * To do: + * + * - Implement 16 plane mode (iplan2p16) + * + * + * 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. + */ + +#undef FBCONDEBUG + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/delay.h> /* MSch: for IRQ probe */ +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/string.h> +#include <linux/kd.h> +#include <linux/slab.h> +#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> +#include <linux/crc32.h> /* For counting font checksums */ +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#ifdef CONFIG_ATARI +#include <asm/atariints.h> +#endif +#ifdef CONFIG_MAC +#include <asm/macints.h> +#endif +#if defined(__mc68000__) || defined(CONFIG_APUS) +#include <asm/machdep.h> +#include <asm/setup.h> +#endif + +#include "fbcon.h" + +#ifdef FBCONDEBUG +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + +enum { + FBCON_LOGO_CANSHOW = -1, /* the logo can be shown */ + FBCON_LOGO_DRAW = -2, /* draw the logo to a console */ + FBCON_LOGO_DONTSHOW = -3 /* do not show the logo */ +}; + +struct display fb_display[MAX_NR_CONSOLES]; +static signed char con2fb_map[MAX_NR_CONSOLES]; +static signed char con2fb_map_boot[MAX_NR_CONSOLES]; +static int logo_height; +static int logo_lines; +/* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO + enums. */ +static int logo_shown = FBCON_LOGO_CANSHOW; +/* Software scrollback */ +static int fbcon_softback_size = 32768; +static unsigned long softback_buf, softback_curr; +static unsigned long softback_in; +static unsigned long softback_top, softback_end; +static int softback_lines; +/* console mappings */ +static int first_fb_vc; +static int last_fb_vc = MAX_NR_CONSOLES - 1; +static int fbcon_is_default = 1; +/* font data */ +static char fontname[40]; + +/* current fb_info */ +static int info_idx = -1; + +static const struct consw fb_con; + +#define CM_SOFTBACK (8) + +#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) + +static void fbcon_free_font(struct display *); +static int fbcon_set_origin(struct vc_data *); + +#define CURSOR_DRAW_DELAY (1) + +/* # VBL ints between cursor state changes */ +#define ARM_CURSOR_BLINK_RATE (10) +#define ATARI_CURSOR_BLINK_RATE (42) +#define MAC_CURSOR_BLINK_RATE (32) +#define DEFAULT_CURSOR_BLINK_RATE (20) + +static int vbl_cursor_cnt; + +#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) + +/* + * Interface used by the world + */ + +static const char *fbcon_startup(void); +static void fbcon_init(struct vc_data *vc, int init); +static void fbcon_deinit(struct vc_data *vc); +static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, + int width); +static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos); +static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, + int count, int ypos, int xpos); +static void fbcon_clear_margins(struct vc_data *vc, int bottom_only); +static void fbcon_cursor(struct vc_data *vc, int mode); +static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, + int count); +static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, + int height, int width); +static int fbcon_switch(struct vc_data *vc); +static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); +static int fbcon_set_palette(struct vc_data *vc, unsigned char *table); +static int fbcon_scrolldelta(struct vc_data *vc, int lines); + +/* + * Internal routines + */ +static __inline__ int real_y(struct display *p, int ypos); +static __inline__ void ywrap_up(struct vc_data *vc, int count); +static __inline__ void ywrap_down(struct vc_data *vc, int count); +static __inline__ void ypan_up(struct vc_data *vc, int count); +static __inline__ void ypan_down(struct vc_data *vc, int count); +static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, + int dy, int dx, int height, int width, u_int y_break); +static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, + struct vc_data *vc); +static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var, + int unit); +static void fbcon_redraw_move(struct vc_data *vc, struct display *p, + int line, int count, int dy); + +#ifdef CONFIG_MAC +/* + * On the Macintoy, there may or may not be a working VBL int. We need to probe + */ +static int vbl_detected; + +static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp) +{ + vbl_detected++; + return IRQ_HANDLED; +} +#endif + +static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) +{ + struct fbcon_ops *ops = info->fbcon_par; + + return (info->state != FBINFO_STATE_RUNNING || + vc->vc_mode != KD_TEXT || ops->graphics); +} + +static inline int get_color(struct vc_data *vc, struct fb_info *info, + u16 c, int is_fg) +{ + int depth = fb_get_color_depth(&info->var); + int color = 0; + + if (console_blanked) { + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + + c = vc->vc_video_erase_char & charmask; + } + + if (depth != 1) + color = (is_fg) ? attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, c) + : attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, c); + + switch (depth) { + case 1: + { + /* 0 or 1 */ + int fg = (info->fix.visual != FB_VISUAL_MONO01) ? 1 : 0; + int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : 1; + + if (console_blanked) + fg = bg; + + color = (is_fg) ? fg : bg; + break; + } + case 2: + /* + * Scale down 16-colors to 4 colors. Default 4-color palette + * is grayscale. + */ + color /= 4; + break; + case 3: + /* + * Last 8 entries of default 16-color palette is a more intense + * version of the first 8 (i.e., same chrominance, different + * luminance). + */ + color &= 7; + break; + } + + + return color; +} + +static void fb_flashcursor(void *private) +{ + struct fb_info *info = private; + struct fbcon_ops *ops = info->fbcon_par; + struct display *p; + struct vc_data *vc = NULL; + int c; + int mode; + + if (ops->currcon != -1) + vc = vc_cons[ops->currcon].d; + + if (!vc || !CON_IS_VISIBLE(vc) || + fbcon_is_inactive(vc, info) || + registered_fb[con2fb_map[vc->vc_num]] != info) + return; + acquire_console_sem(); + p = &fb_display[vc->vc_num]; + c = scr_readw((u16 *) vc->vc_pos); + mode = (!ops->cursor_flash || ops->cursor_state.enable) ? + CM_ERASE : CM_DRAW; + ops->cursor(vc, info, p, mode, softback_lines, get_color(vc, info, c, 1), + get_color(vc, info, c, 0)); + release_console_sem(); +} + +#if (defined(__arm__) && defined(IRQ_VSYNCPULSE)) || defined(CONFIG_ATARI) || defined(CONFIG_MAC) +static int cursor_blink_rate; +static irqreturn_t fb_vbl_handler(int irq, void *dev_id, struct pt_regs *fp) +{ + struct fb_info *info = dev_id; + + if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) { + schedule_work(&info->queue); + vbl_cursor_cnt = cursor_blink_rate; + } + return IRQ_HANDLED; +} +#endif + +static void cursor_timer_handler(unsigned long dev_addr) +{ + struct fb_info *info = (struct fb_info *) dev_addr; + struct fbcon_ops *ops = info->fbcon_par; + + schedule_work(&info->queue); + mod_timer(&ops->cursor_timer, jiffies + HZ/5); +} + +#ifndef MODULE +static int __init fb_console_setup(char *this_opt) +{ + char *options; + int i, j; + + if (!this_opt || !*this_opt) + return 0; + + while ((options = strsep(&this_opt, ",")) != NULL) { + if (!strncmp(options, "font:", 5)) + strcpy(fontname, options + 5); + + if (!strncmp(options, "scrollback:", 11)) { + options += 11; + if (*options) { + fbcon_softback_size = simple_strtoul(options, &options, 0); + if (*options == 'k' || *options == 'K') { + fbcon_softback_size *= 1024; + options++; + } + if (*options != ',') + return 0; + options++; + } else + return 0; + } + + if (!strncmp(options, "map:", 4)) { + options += 4; + if (*options) + for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) { + if (!options[j]) + j = 0; + con2fb_map_boot[i] = + (options[j++]-'0') % FB_MAX; + } + return 0; + } + + if (!strncmp(options, "vc:", 3)) { + options += 3; + if (*options) + first_fb_vc = simple_strtoul(options, &options, 10) - 1; + if (first_fb_vc < 0) + first_fb_vc = 0; + if (*options++ == '-') + last_fb_vc = simple_strtoul(options, &options, 10) - 1; + fbcon_is_default = 0; + } + } + return 0; +} + +__setup("fbcon=", fb_console_setup); +#endif + +static int search_fb_in_map(int idx) +{ + int i, retval = 0; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (con2fb_map[i] == idx) + retval = 1; + } + return retval; +} + +static int search_for_mapped_con(void) +{ + int i, retval = 0; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (con2fb_map[i] != -1) + retval = 1; + } + return retval; +} + +static int fbcon_takeover(int show_logo) +{ + int err, i; + + if (!num_registered_fb) + return -ENODEV; + + if (!show_logo) + logo_shown = FBCON_LOGO_DONTSHOW; + + for (i = first_fb_vc; i <= last_fb_vc; i++) + con2fb_map[i] = info_idx; + + err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, + fbcon_is_default); + if (err) { + for (i = first_fb_vc; i <= last_fb_vc; i++) { + con2fb_map[i] = -1; + } + info_idx = -1; + } + + return err; +} + +static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, + int cols, int rows, int new_cols, int new_rows) +{ + /* Need to make room for the logo */ + int cnt, erase = vc->vc_video_erase_char, step; + unsigned short *save = NULL, *r, *q; + + /* + * remove underline attribute from erase character + * if black and white framebuffer. + */ + if (fb_get_color_depth(&info->var) == 1) + erase &= ~0x400; + logo_height = fb_prepare_logo(info); + logo_lines = (logo_height + vc->vc_font.height - 1) / + vc->vc_font.height; + q = (unsigned short *) (vc->vc_origin + + vc->vc_size_row * rows); + step = logo_lines * cols; + for (r = q - logo_lines * cols; r < q; r++) + if (scr_readw(r) != vc->vc_video_erase_char) + break; + if (r != q && new_rows >= rows + logo_lines) { + save = kmalloc(logo_lines * new_cols * 2, GFP_KERNEL); + if (save) { + int i = cols < new_cols ? cols : new_cols; + scr_memsetw(save, erase, logo_lines * new_cols * 2); + r = q - step; + for (cnt = 0; cnt < logo_lines; cnt++, r += i) + scr_memcpyw(save + cnt * new_cols, r, 2 * i); + r = q; + } + } + if (r == q) { + /* We can scroll screen down */ + r = q - step - cols; + for (cnt = rows - logo_lines; cnt > 0; cnt--) { + scr_memcpyw(r + step, r, vc->vc_size_row); + r -= cols; + } + if (!save) { + vc->vc_y += logo_lines; + vc->vc_pos += logo_lines * vc->vc_size_row; + } + } + scr_memsetw((unsigned short *) vc->vc_origin, + erase, + vc->vc_size_row * logo_lines); + + if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { + fbcon_clear_margins(vc, 0); + update_screen(vc); + } + + if (save) { + q = (unsigned short *) (vc->vc_origin + + vc->vc_size_row * + rows); + scr_memcpyw(q, save, logo_lines * new_cols * 2); + vc->vc_y += logo_lines; + vc->vc_pos += logo_lines * vc->vc_size_row; + kfree(save); + } + + if (logo_lines > vc->vc_bottom) { + logo_shown = FBCON_LOGO_CANSHOW; + printk(KERN_INFO + "fbcon_init: disable boot-logo (boot-logo bigger than screen).\n"); + } else if (logo_shown != FBCON_LOGO_DONTSHOW) { + logo_shown = FBCON_LOGO_DRAW; + vc->vc_top = logo_lines; + } +} + +#ifdef CONFIG_FB_TILEBLITTING +static void set_blitting_type(struct vc_data *vc, struct fb_info *info, + struct display *p) +{ + struct fbcon_ops *ops = info->fbcon_par; + + if ((info->flags & FBINFO_MISC_TILEBLITTING)) + fbcon_set_tileops(vc, info, p, ops); + else + fbcon_set_bitops(ops); +} +#else +static void set_blitting_type(struct vc_data *vc, struct fb_info *info, + struct display *p) +{ + struct fbcon_ops *ops = info->fbcon_par; + + info->flags &= ~FBINFO_MISC_TILEBLITTING; + fbcon_set_bitops(ops); +} +#endif /* CONFIG_MISC_TILEBLITTING */ + + +static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info, + int unit, int oldidx) +{ + struct fbcon_ops *ops = NULL; + int err = 0; + + if (!try_module_get(info->fbops->owner)) + err = -ENODEV; + + if (!err && info->fbops->fb_open && + info->fbops->fb_open(info, 0)) + err = -ENODEV; + + if (!err) { + ops = kmalloc(sizeof(struct fbcon_ops), GFP_KERNEL); + if (!ops) + err = -ENOMEM; + } + + if (!err) { + memset(ops, 0, sizeof(struct fbcon_ops)); + info->fbcon_par = ops; + set_blitting_type(vc, info, NULL); + } + + if (err) { + con2fb_map[unit] = oldidx; + module_put(info->fbops->owner); + } + + return err; +} + +static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, + struct fb_info *newinfo, int unit, + int oldidx, int found) +{ + struct fbcon_ops *ops = oldinfo->fbcon_par; + int err = 0; + + if (oldinfo->fbops->fb_release && + oldinfo->fbops->fb_release(oldinfo, 0)) { + con2fb_map[unit] = oldidx; + if (!found && newinfo->fbops->fb_release) + newinfo->fbops->fb_release(newinfo, 0); + if (!found) + module_put(newinfo->fbops->owner); + err = -ENODEV; + } + + if (!err) { + if (oldinfo->queue.func == fb_flashcursor) + del_timer_sync(&ops->cursor_timer); + + kfree(ops->cursor_state.mask); + kfree(ops->cursor_data); + kfree(oldinfo->fbcon_par); + oldinfo->fbcon_par = NULL; + module_put(oldinfo->fbops->owner); + } + + return err; +} + +static void con2fb_init_newinfo(struct fb_info *info) +{ + if (!info->queue.func || info->queue.func == fb_flashcursor) { + struct fbcon_ops *ops = info->fbcon_par; + + if (!info->queue.func) + INIT_WORK(&info->queue, fb_flashcursor, info); + + init_timer(&ops->cursor_timer); + ops->cursor_timer.function = cursor_timer_handler; + ops->cursor_timer.expires = jiffies + HZ / 5; + ops->cursor_timer.data = (unsigned long ) info; + add_timer(&ops->cursor_timer); + } +} + +static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, + int unit, int show_logo) +{ + struct fbcon_ops *ops = info->fbcon_par; + + ops->currcon = fg_console; + + if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) + info->fbops->fb_set_par(info); + + ops->flags |= FBCON_FLAGS_INIT; + ops->graphics = 0; + + if (vc) + fbcon_set_disp(info, &info->var, vc); + else + fbcon_preset_disp(info, &info->var, unit); + + if (show_logo) { + struct vc_data *fg_vc = vc_cons[fg_console].d; + struct fb_info *fg_info = + registered_fb[con2fb_map[fg_console]]; + + fbcon_prepare_logo(fg_vc, fg_info, fg_vc->vc_cols, + fg_vc->vc_rows, fg_vc->vc_cols, + fg_vc->vc_rows); + } + + update_screen(vc_cons[fg_console].d); +} + +/** + * set_con2fb_map - map console to frame buffer device + * @unit: virtual console number to map + * @newidx: frame buffer index to map virtual console to + * @user: user request + * + * Maps a virtual console @unit to a frame buffer device + * @newidx. + */ +static int set_con2fb_map(int unit, int newidx, int user) +{ + struct vc_data *vc = vc_cons[unit].d; + int oldidx = con2fb_map[unit]; + struct fb_info *info = registered_fb[newidx]; + struct fb_info *oldinfo = NULL; + int found, err = 0; + + if (oldidx == newidx) + return 0; + + if (!info) + err = -EINVAL; + + if (!err && !search_for_mapped_con()) { + info_idx = newidx; + return fbcon_takeover(0); + } + + if (oldidx != -1) + oldinfo = registered_fb[oldidx]; + + found = search_fb_in_map(newidx); + + acquire_console_sem(); + con2fb_map[unit] = newidx; + if (!err && !found) + err = con2fb_acquire_newinfo(vc, info, unit, oldidx); + + + /* + * If old fb is not mapped to any of the consoles, + * fbcon should release it. + */ + if (!err && oldinfo && !search_fb_in_map(oldidx)) + err = con2fb_release_oldinfo(vc, oldinfo, info, unit, oldidx, + found); + + if (!err) { + int show_logo = (fg_console == 0 && !user && + logo_shown != FBCON_LOGO_DONTSHOW); + + if (!found) + con2fb_init_newinfo(info); + con2fb_map_boot[unit] = newidx; + con2fb_init_display(vc, info, unit, show_logo); + } + + release_console_sem(); + return err; +} + +/* + * Low Level Operations + */ +/* NOTE: fbcon cannot be __init: it may be called from take_over_console later */ +static int var_to_display(struct display *disp, + struct fb_var_screeninfo *var, + struct fb_info *info) +{ + disp->xres_virtual = var->xres_virtual; + disp->yres_virtual = var->yres_virtual; + disp->bits_per_pixel = var->bits_per_pixel; + disp->grayscale = var->grayscale; + disp->nonstd = var->nonstd; + disp->accel_flags = var->accel_flags; + disp->height = var->height; + disp->width = var->width; + disp->red = var->red; + disp->green = var->green; + disp->blue = var->blue; + disp->transp = var->transp; + disp->rotate = var->rotate; + disp->mode = fb_match_mode(var, &info->modelist); + if (disp->mode == NULL) + /* This should not happen */ + return -EINVAL; + return 0; +} + +static void display_to_var(struct fb_var_screeninfo *var, + struct display *disp) +{ + fb_videomode_to_var(var, disp->mode); + var->xres_virtual = disp->xres_virtual; + var->yres_virtual = disp->yres_virtual; + var->bits_per_pixel = disp->bits_per_pixel; + var->grayscale = disp->grayscale; + var->nonstd = disp->nonstd; + var->accel_flags = disp->accel_flags; + var->height = disp->height; + var->width = disp->width; + var->red = disp->red; + var->green = disp->green; + var->blue = disp->blue; + var->transp = disp->transp; + var->rotate = disp->rotate; +} + +static const char *fbcon_startup(void) +{ + const char *display_desc = "frame buffer device"; + struct display *p = &fb_display[fg_console]; + struct vc_data *vc = vc_cons[fg_console].d; + struct font_desc *font = NULL; + struct module *owner; + struct fb_info *info = NULL; + struct fbcon_ops *ops; + int rows, cols; + int irqres; + + irqres = 1; + /* + * If num_registered_fb is zero, this is a call for the dummy part. + * The frame buffer devices weren't initialized yet. + */ + if (!num_registered_fb || info_idx == -1) + return display_desc; + /* + * Instead of blindly using registered_fb[0], we use info_idx, set by + * fb_console_init(); + */ + info = registered_fb[info_idx]; + if (!info) + return NULL; + + owner = info->fbops->owner; + if (!try_module_get(owner)) + return NULL; + if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) { + module_put(owner); + return NULL; + } + + ops = kmalloc(sizeof(struct fbcon_ops), GFP_KERNEL); + if (!ops) { + module_put(owner); + return NULL; + } + + memset(ops, 0, sizeof(struct fbcon_ops)); + ops->currcon = -1; + ops->graphics = 1; + info->fbcon_par = ops; + set_blitting_type(vc, info, NULL); + + if (info->fix.type != FB_TYPE_TEXT) { + if (fbcon_softback_size) { + if (!softback_buf) { + softback_buf = + (unsigned long) + kmalloc(fbcon_softback_size, + GFP_KERNEL); + if (!softback_buf) { + fbcon_softback_size = 0; + softback_top = 0; + } + } + } else { + if (softback_buf) { + kfree((void *) softback_buf); + softback_buf = 0; + softback_top = 0; + } + } + if (softback_buf) + softback_in = softback_top = softback_curr = + softback_buf; + softback_lines = 0; + } + + /* Setup default font */ + if (!p->fontdata) { + if (!fontname[0] || !(font = find_font(fontname))) + font = get_default_font(info->var.xres, + info->var.yres); + vc->vc_font.width = font->width; + vc->vc_font.height = font->height; + vc->vc_font.data = p->fontdata = font->data; + vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ + } + + cols = info->var.xres / vc->vc_font.width; + rows = info->var.yres / vc->vc_font.height; + vc_resize(vc, cols, rows); + + DPRINTK("mode: %s\n", info->fix.id); + DPRINTK("visual: %d\n", info->fix.visual); + DPRINTK("res: %dx%d-%d\n", info->var.xres, + info->var.yres, + info->var.bits_per_pixel); + +#ifdef CONFIG_ATARI + if (MACH_IS_ATARI) { + cursor_blink_rate = ATARI_CURSOR_BLINK_RATE; + irqres = + request_irq(IRQ_AUTO_4, fb_vbl_handler, + IRQ_TYPE_PRIO, "framebuffer vbl", + info); + } +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_MAC + /* + * On a Macintoy, the VBL interrupt may or may not be active. + * As interrupt based cursor is more reliable and race free, we + * probe for VBL interrupts. + */ + if (MACH_IS_MAC) { + int ct = 0; + /* + * Probe for VBL: set temp. handler ... + */ + irqres = request_irq(IRQ_MAC_VBL, fb_vbl_detect, 0, + "framebuffer vbl", info); + vbl_detected = 0; + + /* + * ... and spin for 20 ms ... + */ + while (!vbl_detected && ++ct < 1000) + udelay(20); + + if (ct == 1000) + printk + ("fbcon_startup: No VBL detected, using timer based cursor.\n"); + + free_irq(IRQ_MAC_VBL, fb_vbl_detect); + + if (vbl_detected) { + /* + * interrupt based cursor ok + */ + cursor_blink_rate = MAC_CURSOR_BLINK_RATE; + irqres = + request_irq(IRQ_MAC_VBL, fb_vbl_handler, 0, + "framebuffer vbl", info); + } else { + /* + * VBL not detected: fall through, use timer based cursor + */ + irqres = 1; + } + } +#endif /* CONFIG_MAC */ + +#if defined(__arm__) && defined(IRQ_VSYNCPULSE) + cursor_blink_rate = ARM_CURSOR_BLINK_RATE; + irqres = request_irq(IRQ_VSYNCPULSE, fb_vbl_handler, SA_SHIRQ, + "framebuffer vbl", info); +#endif + /* Initialize the work queue. If the driver provides its + * own work queue this means it will use something besides + * default timer to flash the cursor. */ + if (!info->queue.func) { + INIT_WORK(&info->queue, fb_flashcursor, info); + + init_timer(&ops->cursor_timer); + ops->cursor_timer.function = cursor_timer_handler; + ops->cursor_timer.expires = jiffies + HZ / 5; + ops->cursor_timer.data = (unsigned long ) info; + add_timer(&ops->cursor_timer); + } + return display_desc; +} + +static void fbcon_init(struct vc_data *vc, int init) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops; + struct vc_data **default_mode = vc->vc_display_fg; + struct vc_data *svc = *default_mode; + struct display *t, *p = &fb_display[vc->vc_num]; + int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256; + int cap = info->flags; + + if (info_idx == -1 || info == NULL) + return; + if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW || + (info->fix.type == FB_TYPE_TEXT)) + logo = 0; + + info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ + + if (var_to_display(p, &info->var, info)) + return; + + /* If we are not the first console on this + fb, copy the font from that console */ + t = &fb_display[svc->vc_num]; + if (!vc->vc_font.data) { + vc->vc_font.data = p->fontdata = t->fontdata; + vc->vc_font.width = (*default_mode)->vc_font.width; + vc->vc_font.height = (*default_mode)->vc_font.height; + p->userfont = t->userfont; + if (p->userfont) + REFCOUNT(p->fontdata)++; + } + if (p->userfont) + charcnt = FNTCHARCNT(p->fontdata); + vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1); + vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; + if (charcnt == 256) { + vc->vc_hi_font_mask = 0; + } else { + vc->vc_hi_font_mask = 0x100; + if (vc->vc_can_do_color) + vc->vc_complement_mask <<= 1; + } + + if (!*svc->vc_uni_pagedir_loc) + con_set_default_unimap(svc); + if (!*vc->vc_uni_pagedir_loc) + con_copy_unimap(vc, svc); + + cols = vc->vc_cols; + rows = vc->vc_rows; + new_cols = info->var.xres / vc->vc_font.width; + new_rows = info->var.yres / vc->vc_font.height; + vc_resize(vc, new_cols, new_rows); + + ops = info->fbcon_par; + /* + * We must always set the mode. The mode of the previous console + * driver could be in the same resolution but we are using different + * hardware so we have to initialize the hardware. + * + * We need to do it in fbcon_init() to prevent screen corruption. + */ + if (CON_IS_VISIBLE(vc)) { + if (info->fbops->fb_set_par && + !(ops->flags & FBCON_FLAGS_INIT)) + info->fbops->fb_set_par(info); + ops->flags |= FBCON_FLAGS_INIT; + } + + ops->graphics = 0; + + if ((cap & FBINFO_HWACCEL_COPYAREA) && + !(cap & FBINFO_HWACCEL_DISABLED)) + p->scrollmode = SCROLL_MOVE; + else /* default to something safe */ + p->scrollmode = SCROLL_REDRAW; + + /* + * ++guenther: console.c:vc_allocate() relies on initializing + * vc_{cols,rows}, but we must not set those if we are only + * resizing the console. + */ + if (!init) { + vc->vc_cols = new_cols; + vc->vc_rows = new_rows; + } + + if (logo) + fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows); + + if (vc == svc && softback_buf) { + int l = fbcon_softback_size / vc->vc_size_row; + if (l > 5) + softback_end = softback_buf + l * vc->vc_size_row; + else { + /* Smaller scrollback makes no sense, and 0 would screw + the operation totally */ + softback_top = 0; + } + } +} + +static void fbcon_deinit(struct vc_data *vc) +{ + struct display *p = &fb_display[vc->vc_num]; + + if (info_idx != -1) + return; + fbcon_free_font(p); +} + +/* ====================================================================== */ + +/* fbcon_XXX routines - interface used by the world + * + * This system is now divided into two levels because of complications + * caused by hardware scrolling. Top level functions: + * + * fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins() + * + * handles y values in range [0, scr_height-1] that correspond to real + * screen positions. y_wrap shift means that first line of bitmap may be + * anywhere on this display. These functions convert lineoffsets to + * bitmap offsets and deal with the wrap-around case by splitting blits. + * + * fbcon_bmove_physical_8() -- These functions fast implementations + * fbcon_clear_physical_8() -- of original fbcon_XXX fns. + * fbcon_putc_physical_8() -- (font width != 8) may be added later + * + * WARNING: + * + * At the moment fbcon_putc() cannot blit across vertical wrap boundary + * Implies should only really hardware scroll in rows. Only reason for + * restriction is simplicity & efficiency at the moment. + */ + +static __inline__ int real_y(struct display *p, int ypos) +{ + int rows = p->vrows; + + ypos += p->yscroll; + return ypos < rows ? ypos : ypos - rows; +} + + +static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, + int width) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + + struct display *p = &fb_display[vc->vc_num]; + u_int y_break; + + if (fbcon_is_inactive(vc, info)) + return; + + if (!height || !width) + return; + + /* Split blits that cross physical y_wrap boundary */ + + y_break = p->vrows - p->yscroll; + if (sy < y_break && sy + height - 1 >= y_break) { + u_int b = y_break - sy; + ops->clear(vc, info, real_y(p, sy), sx, b, width); + ops->clear(vc, info, real_y(p, sy + b), sx, height - b, + width); + } else + ops->clear(vc, info, real_y(p, sy), sx, height, width); +} + +static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, + int count, int ypos, int xpos) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + struct fbcon_ops *ops = info->fbcon_par; + + if (!fbcon_is_inactive(vc, info)) + ops->putcs(vc, info, s, count, real_y(p, ypos), xpos, + get_color(vc, info, scr_readw(s), 1), + get_color(vc, info, scr_readw(s), 0)); +} + +static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) +{ + unsigned short chr; + + scr_writew(c, &chr); + fbcon_putcs(vc, &chr, 1, ypos, xpos); +} + +static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + + if (!fbcon_is_inactive(vc, info)) + ops->clear_margins(vc, info, bottom_only); +} + +static void fbcon_cursor(struct vc_data *vc, int mode) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + struct display *p = &fb_display[vc->vc_num]; + int y; + int c = scr_readw((u16 *) vc->vc_pos); + + if (fbcon_is_inactive(vc, info)) + return; + + ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; + if (mode & CM_SOFTBACK) { + mode &= ~CM_SOFTBACK; + y = softback_lines; + } else { + if (softback_lines) + fbcon_set_origin(vc); + y = 0; + } + + ops->cursor(vc, info, p, mode, y, get_color(vc, info, c, 1), + get_color(vc, info, c, 0)); + vbl_cursor_cnt = CURSOR_DRAW_DELAY; +} + +static int scrollback_phys_max = 0; +static int scrollback_max = 0; +static int scrollback_current = 0; + +static int update_var(int con, struct fb_info *info) +{ + if (con == ((struct fbcon_ops *)info->fbcon_par)->currcon) + return fb_pan_display(info, &info->var); + return 0; +} + +/* + * If no vc is existent yet, just set struct display + */ +static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var, + int unit) +{ + struct display *p = &fb_display[unit]; + struct display *t = &fb_display[fg_console]; + + var->xoffset = var->yoffset = p->yscroll = 0; + if (var_to_display(p, var, info)) + return; + + p->fontdata = t->fontdata; + p->userfont = t->userfont; + if (p->userfont) + REFCOUNT(p->fontdata)++; +} + +static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, + struct vc_data *vc) +{ + struct display *p = &fb_display[vc->vc_num], *t; + struct vc_data **default_mode = vc->vc_display_fg; + struct vc_data *svc = *default_mode; + int rows, cols, charcnt = 256; + + var->xoffset = var->yoffset = p->yscroll = 0; + if (var_to_display(p, var, info)) + return; + t = &fb_display[svc->vc_num]; + if (!vc->vc_font.data) { + vc->vc_font.data = p->fontdata = t->fontdata; + vc->vc_font.width = (*default_mode)->vc_font.width; + vc->vc_font.height = (*default_mode)->vc_font.height; + p->userfont = t->userfont; + if (p->userfont) + REFCOUNT(p->fontdata)++; + } + if (p->userfont) + charcnt = FNTCHARCNT(p->fontdata); + + vc->vc_can_do_color = (fb_get_color_depth(var) != 1); + vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; + if (charcnt == 256) { + vc->vc_hi_font_mask = 0; + } else { + vc->vc_hi_font_mask = 0x100; + if (vc->vc_can_do_color) + vc->vc_complement_mask <<= 1; + } + + if (!*svc->vc_uni_pagedir_loc) + con_set_default_unimap(svc); + if (!*vc->vc_uni_pagedir_loc) + con_copy_unimap(vc, svc); + + cols = var->xres / vc->vc_font.width; + rows = var->yres / vc->vc_font.height; + vc_resize(vc, cols, rows); + if (CON_IS_VISIBLE(vc)) { + update_screen(vc); + if (softback_buf) { + int l = fbcon_softback_size / vc->vc_size_row; + + if (l > 5) + softback_end = softback_buf + l * + vc->vc_size_row; + else { + /* Smaller scrollback makes no sense, and 0 + would screw the operation totally */ + softback_top = 0; + } + } + } +} + +static __inline__ void ywrap_up(struct vc_data *vc, int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + + p->yscroll += count; + if (p->yscroll >= p->vrows) /* Deal with wrap */ + p->yscroll -= p->vrows; + info->var.xoffset = 0; + info->var.yoffset = p->yscroll * vc->vc_font.height; + info->var.vmode |= FB_VMODE_YWRAP; + update_var(vc->vc_num, info); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; + scrollback_current = 0; +} + +static __inline__ void ywrap_down(struct vc_data *vc, int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + + p->yscroll -= count; + if (p->yscroll < 0) /* Deal with wrap */ + p->yscroll += p->vrows; + info->var.xoffset = 0; + info->var.yoffset = p->yscroll * vc->vc_font.height; + info->var.vmode |= FB_VMODE_YWRAP; + update_var(vc->vc_num, info); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; + scrollback_current = 0; +} + +static __inline__ void ypan_up(struct vc_data *vc, int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + struct fbcon_ops *ops = info->fbcon_par; + + p->yscroll += count; + if (p->yscroll > p->vrows - vc->vc_rows) { + ops->bmove(vc, info, p->vrows - vc->vc_rows, + 0, 0, 0, vc->vc_rows, vc->vc_cols); + p->yscroll -= p->vrows - vc->vc_rows; + } + info->var.xoffset = 0; + info->var.yoffset = p->yscroll * vc->vc_font.height; + info->var.vmode &= ~FB_VMODE_YWRAP; + update_var(vc->vc_num, info); + fbcon_clear_margins(vc, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; + scrollback_current = 0; +} + +static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + int redraw = 0; + + p->yscroll += count; + if (p->yscroll > p->vrows - vc->vc_rows) { + p->yscroll -= p->vrows - vc->vc_rows; + redraw = 1; + } + + info->var.xoffset = 0; + info->var.yoffset = p->yscroll * vc->vc_font.height; + info->var.vmode &= ~FB_VMODE_YWRAP; + if (redraw) + fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); + update_var(vc->vc_num, info); + fbcon_clear_margins(vc, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; + scrollback_current = 0; +} + +static __inline__ void ypan_down(struct vc_data *vc, int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + struct fbcon_ops *ops = info->fbcon_par; + + p->yscroll -= count; + if (p->yscroll < 0) { + ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, + 0, vc->vc_rows, vc->vc_cols); + p->yscroll += p->vrows - vc->vc_rows; + } + info->var.xoffset = 0; + info->var.yoffset = p->yscroll * vc->vc_font.height; + info->var.vmode &= ~FB_VMODE_YWRAP; + update_var(vc->vc_num, info); + fbcon_clear_margins(vc, 1); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; + scrollback_current = 0; +} + +static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + int redraw = 0; + + p->yscroll -= count; + if (p->yscroll < 0) { + p->yscroll += p->vrows - vc->vc_rows; + redraw = 1; + } + info->var.xoffset = 0; + info->var.yoffset = p->yscroll * vc->vc_font.height; + info->var.vmode &= ~FB_VMODE_YWRAP; + if (redraw) + fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); + update_var(vc->vc_num, info); + fbcon_clear_margins(vc, 1); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; + scrollback_current = 0; +} + +static void fbcon_redraw_softback(struct vc_data *vc, struct display *p, + long delta) +{ + int count = vc->vc_rows; + unsigned short *d, *s; + unsigned long n; + int line = 0; + + d = (u16 *) softback_curr; + if (d == (u16 *) softback_in) + d = (u16 *) vc->vc_origin; + n = softback_curr + delta * vc->vc_size_row; + softback_lines -= delta; + if (delta < 0) { + if (softback_curr < softback_top && n < softback_buf) { + n += softback_end - softback_buf; + if (n < softback_top) { + softback_lines -= + (softback_top - n) / vc->vc_size_row; + n = softback_top; + } + } else if (softback_curr >= softback_top + && n < softback_top) { + softback_lines -= + (softback_top - n) / vc->vc_size_row; + n = softback_top; + } + } else { + if (softback_curr > softback_in && n >= softback_end) { + n += softback_buf - softback_end; + if (n > softback_in) { + n = softback_in; + softback_lines = 0; + } + } else if (softback_curr <= softback_in && n > softback_in) { + n = softback_in; + softback_lines = 0; + } + } + if (n == softback_curr) + return; + softback_curr = n; + s = (u16 *) softback_curr; + if (s == (u16 *) softback_in) + s = (u16 *) vc->vc_origin; + while (count--) { + unsigned short *start; + unsigned short *le; + unsigned short c; + int x = 0; + unsigned short attr = 1; + + start = s; + le = advance_row(s, 1); + do { + c = scr_readw(s); + if (attr != (c & 0xff00)) { + attr = c & 0xff00; + if (s > start) { + fbcon_putcs(vc, start, s - start, + line, x); + x += s - start; + start = s; + } + } + if (c == scr_readw(d)) { + if (s > start) { + fbcon_putcs(vc, start, s - start, + line, x); + x += s - start + 1; + start = s + 1; + } else { + x++; + start++; + } + } + s++; + d++; + } while (s < le); + if (s > start) + fbcon_putcs(vc, start, s - start, line, x); + line++; + if (d == (u16 *) softback_end) + d = (u16 *) softback_buf; + if (d == (u16 *) softback_in) + d = (u16 *) vc->vc_origin; + if (s == (u16 *) softback_end) + s = (u16 *) softback_buf; + if (s == (u16 *) softback_in) + s = (u16 *) vc->vc_origin; + } +} + +static void fbcon_redraw_move(struct vc_data *vc, struct display *p, + int line, int count, int dy) +{ + unsigned short *s = (unsigned short *) + (vc->vc_origin + vc->vc_size_row * line); + + while (count--) { + unsigned short *start = s; + unsigned short *le = advance_row(s, 1); + unsigned short c; + int x = 0; + unsigned short attr = 1; + + do { + c = scr_readw(s); + if (attr != (c & 0xff00)) { + attr = c & 0xff00; + if (s > start) { + fbcon_putcs(vc, start, s - start, + dy, x); + x += s - start; + start = s; + } + } + console_conditional_schedule(); + s++; + } while (s < le); + if (s > start) + fbcon_putcs(vc, start, s - start, dy, x); + console_conditional_schedule(); + dy++; + } +} + +static void fbcon_redraw(struct vc_data *vc, struct display *p, + int line, int count, int offset) +{ + unsigned short *d = (unsigned short *) + (vc->vc_origin + vc->vc_size_row * line); + unsigned short *s = d + offset; + + while (count--) { + unsigned short *start = s; + unsigned short *le = advance_row(s, 1); + unsigned short c; + int x = 0; + unsigned short attr = 1; + + do { + c = scr_readw(s); + if (attr != (c & 0xff00)) { + attr = c & 0xff00; + if (s > start) { + fbcon_putcs(vc, start, s - start, + line, x); + x += s - start; + start = s; + } + } + if (c == scr_readw(d)) { + if (s > start) { + fbcon_putcs(vc, start, s - start, + line, x); + x += s - start + 1; + start = s + 1; + } else { + x++; + start++; + } + } + scr_writew(c, d); + console_conditional_schedule(); + s++; + d++; + } while (s < le); + if (s > start) + fbcon_putcs(vc, start, s - start, line, x); + console_conditional_schedule(); + if (offset > 0) + line++; + else { + line--; + /* NOTE: We subtract two lines from these pointers */ + s -= vc->vc_size_row; + d -= vc->vc_size_row; + } + } +} + +static inline void fbcon_softback_note(struct vc_data *vc, int t, + int count) +{ + unsigned short *p; + + if (vc->vc_num != fg_console) + return; + p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row); + + while (count) { + scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row); + count--; + p = advance_row(p, 1); + softback_in += vc->vc_size_row; + if (softback_in == softback_end) + softback_in = softback_buf; + if (softback_in == softback_top) { + softback_top += vc->vc_size_row; + if (softback_top == softback_end) + softback_top = softback_buf; + } + } + softback_curr = softback_in; +} + +static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, + int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + struct fbcon_ops *ops = info->fbcon_par; + int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; + + if (fbcon_is_inactive(vc, info)) + return -EINVAL; + + fbcon_cursor(vc, CM_ERASE); + + /* + * ++Geert: Only use ywrap/ypan if the console is in text mode + * ++Andrew: Only use ypan on hardware text mode when scrolling the + * whole screen (prevents flicker). + */ + + switch (dir) { + case SM_UP: + if (count > vc->vc_rows) /* Maximum realistic size */ + count = vc->vc_rows; + if (softback_top) + fbcon_softback_note(vc, t, count); + if (logo_shown >= 0) + goto redraw_up; + switch (p->scrollmode) { + case SCROLL_MOVE: + ops->bmove(vc, info, t + count, 0, t, 0, + b - t - count, vc->vc_cols); + ops->clear(vc, info, b - count, 0, count, + vc->vc_cols); + break; + + case SCROLL_WRAP_MOVE: + if (b - t - count > 3 * vc->vc_rows >> 2) { + if (t > 0) + fbcon_bmove(vc, 0, 0, count, 0, t, + vc->vc_cols); + ywrap_up(vc, count); + if (vc->vc_rows - b > 0) + fbcon_bmove(vc, b - count, 0, b, 0, + vc->vc_rows - b, + vc->vc_cols); + } else if (info->flags & FBINFO_READS_FAST) + fbcon_bmove(vc, t + count, 0, t, 0, + b - t - count, vc->vc_cols); + else + goto redraw_up; + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + break; + + case SCROLL_PAN_REDRAW: + if ((p->yscroll + count <= + 2 * (p->vrows - vc->vc_rows)) + && ((!scroll_partial && (b - t == vc->vc_rows)) + || (scroll_partial + && (b - t - count > + 3 * vc->vc_rows >> 2)))) { + if (t > 0) + fbcon_redraw_move(vc, p, 0, t, count); + ypan_up_redraw(vc, t, count); + if (vc->vc_rows - b > 0) + fbcon_redraw_move(vc, p, b - count, + vc->vc_rows - b, b); + } else + fbcon_redraw_move(vc, p, t + count, b - t - count, t); + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + break; + + case SCROLL_PAN_MOVE: + if ((p->yscroll + count <= + 2 * (p->vrows - vc->vc_rows)) + && ((!scroll_partial && (b - t == vc->vc_rows)) + || (scroll_partial + && (b - t - count > + 3 * vc->vc_rows >> 2)))) { + if (t > 0) + fbcon_bmove(vc, 0, 0, count, 0, t, + vc->vc_cols); + ypan_up(vc, count); + if (vc->vc_rows - b > 0) + fbcon_bmove(vc, b - count, 0, b, 0, + vc->vc_rows - b, + vc->vc_cols); + } else if (info->flags & FBINFO_READS_FAST) + fbcon_bmove(vc, t + count, 0, t, 0, + b - t - count, vc->vc_cols); + else + goto redraw_up; + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + break; + + case SCROLL_REDRAW: + redraw_up: + fbcon_redraw(vc, p, t, b - t - count, + count * vc->vc_cols); + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + scr_memsetw((unsigned short *) (vc->vc_origin + + vc->vc_size_row * + (b - count)), + vc->vc_video_erase_char, + vc->vc_size_row * count); + return 1; + } + break; + + case SM_DOWN: + if (count > vc->vc_rows) /* Maximum realistic size */ + count = vc->vc_rows; + switch (p->scrollmode) { + case SCROLL_MOVE: + ops->bmove(vc, info, t, 0, t + count, 0, + b - t - count, vc->vc_cols); + ops->clear(vc, info, t, 0, count, vc->vc_cols); + break; + + case SCROLL_WRAP_MOVE: + if (b - t - count > 3 * vc->vc_rows >> 2) { + if (vc->vc_rows - b > 0) + fbcon_bmove(vc, b, 0, b - count, 0, + vc->vc_rows - b, + vc->vc_cols); + ywrap_down(vc, count); + if (t > 0) + fbcon_bmove(vc, count, 0, 0, 0, t, + vc->vc_cols); + } else if (info->flags & FBINFO_READS_FAST) + fbcon_bmove(vc, t, 0, t + count, 0, + b - t - count, vc->vc_cols); + else + goto redraw_down; + fbcon_clear(vc, t, 0, count, vc->vc_cols); + break; + + case SCROLL_PAN_MOVE: + if ((count - p->yscroll <= p->vrows - vc->vc_rows) + && ((!scroll_partial && (b - t == vc->vc_rows)) + || (scroll_partial + && (b - t - count > + 3 * vc->vc_rows >> 2)))) { + if (vc->vc_rows - b > 0) + fbcon_bmove(vc, b, 0, b - count, 0, + vc->vc_rows - b, + vc->vc_cols); + ypan_down(vc, count); + if (t > 0) + fbcon_bmove(vc, count, 0, 0, 0, t, + vc->vc_cols); + } else if (info->flags & FBINFO_READS_FAST) + fbcon_bmove(vc, t, 0, t + count, 0, + b - t - count, vc->vc_cols); + else + goto redraw_down; + fbcon_clear(vc, t, 0, count, vc->vc_cols); + break; + + case SCROLL_PAN_REDRAW: + if ((count - p->yscroll <= p->vrows - vc->vc_rows) + && ((!scroll_partial && (b - t == vc->vc_rows)) + || (scroll_partial + && (b - t - count > + 3 * vc->vc_rows >> 2)))) { + if (vc->vc_rows - b > 0) + fbcon_redraw_move(vc, p, b, vc->vc_rows - b, + b - count); + ypan_down_redraw(vc, t, count); + if (t > 0) + fbcon_redraw_move(vc, p, count, t, 0); + } else + fbcon_redraw_move(vc, p, t, b - t - count, t + count); + fbcon_clear(vc, t, 0, count, vc->vc_cols); + break; + + case SCROLL_REDRAW: + redraw_down: + fbcon_redraw(vc, p, b - 1, b - t - count, + -count * vc->vc_cols); + fbcon_clear(vc, t, 0, count, vc->vc_cols); + scr_memsetw((unsigned short *) (vc->vc_origin + + vc->vc_size_row * + t), + vc->vc_video_erase_char, + vc->vc_size_row * count); + return 1; + } + } + return 0; +} + + +static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, + int height, int width) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + + if (fbcon_is_inactive(vc, info)) + return; + + if (!width || !height) + return; + + /* Split blits that cross physical y_wrap case. + * Pathological case involves 4 blits, better to use recursive + * code rather than unrolled case + * + * Recursive invocations don't need to erase the cursor over and + * over again, so we use fbcon_bmove_rec() + */ + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width, + p->vrows - p->yscroll); +} + +static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, + int dy, int dx, int height, int width, u_int y_break) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + u_int b; + + if (sy < y_break && sy + height > y_break) { + b = y_break - sy; + if (dy < sy) { /* Avoid trashing self */ + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, + y_break); + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, + height - b, width, y_break); + } else { + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, + height - b, width, y_break); + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, + y_break); + } + return; + } + + if (dy < y_break && dy + height > y_break) { + b = y_break - dy; + if (dy < sy) { /* Avoid trashing self */ + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, + y_break); + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, + height - b, width, y_break); + } else { + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, + height - b, width, y_break); + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, + y_break); + } + return; + } + ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, + height, width); +} + +static __inline__ void updatescrollmode(struct display *p, struct fb_info *info, + struct vc_data *vc) +{ + int fh = vc->vc_font.height; + int cap = info->flags; + int good_pan = (cap & FBINFO_HWACCEL_YPAN) + && divides(info->fix.ypanstep, vc->vc_font.height) + && info->var.yres_virtual > info->var.yres; + int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) + && divides(info->fix.ywrapstep, vc->vc_font.height) + && divides(vc->vc_font.height, info->var.yres_virtual); + int reading_fast = cap & FBINFO_READS_FAST; + int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED); + int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && !(cap & FBINFO_HWACCEL_DISABLED); + + p->vrows = info->var.yres_virtual/fh; + if (info->var.yres > (fh * (vc->vc_rows + 1))) + p->vrows -= (info->var.yres - (fh * vc->vc_rows)) / fh; + if ((info->var.yres % fh) && (info->var.yres_virtual % fh < + info->var.yres % fh)) + p->vrows--; + + if (good_wrap || good_pan) { + if (reading_fast || fast_copyarea) + p->scrollmode = good_wrap ? SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE; + else + p->scrollmode = good_wrap ? SCROLL_REDRAW : + SCROLL_PAN_REDRAW; + } else { + if (reading_fast || (fast_copyarea && !fast_imageblit)) + p->scrollmode = SCROLL_MOVE; + else + p->scrollmode = SCROLL_REDRAW; + } +} + +static int fbcon_resize(struct vc_data *vc, unsigned int width, + unsigned int height) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + struct fb_var_screeninfo var = info->var; + int x_diff, y_diff; + int fw = vc->vc_font.width; + int fh = vc->vc_font.height; + + var.xres = width * fw; + var.yres = height * fh; + x_diff = info->var.xres - var.xres; + y_diff = info->var.yres - var.yres; + if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) { + struct fb_videomode *mode; + + DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); + mode = fb_find_best_mode(&var, &info->modelist); + if (mode == NULL) + return -EINVAL; + fb_videomode_to_var(&var, mode); + if (width > var.xres/fw || height > var.yres/fh) + return -EINVAL; + /* + * The following can probably have any value... Do we need to + * set all of them? + */ + var.bits_per_pixel = p->bits_per_pixel; + var.xres_virtual = p->xres_virtual; + var.yres_virtual = p->yres_virtual; + var.accel_flags = p->accel_flags; + var.width = p->width; + var.height = p->height; + var.red = p->red; + var.green = p->green; + var.blue = p->blue; + var.transp = p->transp; + var.nonstd = p->nonstd; + + DPRINTK("resize now %ix%i\n", var.xres, var.yres); + if (CON_IS_VISIBLE(vc)) { + var.activate = FB_ACTIVATE_NOW | + FB_ACTIVATE_FORCE; + fb_set_var(info, &var); + } + var_to_display(p, &info->var, info); + } + updatescrollmode(p, info, vc); + return 0; +} + +static int fbcon_switch(struct vc_data *vc) +{ + struct fb_info *info; + struct display *p = &fb_display[vc->vc_num]; + struct fb_var_screeninfo var; + int i, prev_console; + + info = registered_fb[con2fb_map[vc->vc_num]]; + + if (softback_top) { + int l = fbcon_softback_size / vc->vc_size_row; + if (softback_lines) + fbcon_set_origin(vc); + softback_top = softback_curr = softback_in = softback_buf; + softback_lines = 0; + + if (l > 5) + softback_end = softback_buf + l * vc->vc_size_row; + else { + /* Smaller scrollback makes no sense, and 0 would screw + the operation totally */ + softback_top = 0; + } + } + + if (logo_shown >= 0) { + struct vc_data *conp2 = vc_cons[logo_shown].d; + + if (conp2->vc_top == logo_lines + && conp2->vc_bottom == conp2->vc_rows) + conp2->vc_top = 0; + logo_shown = FBCON_LOGO_CANSHOW; + } + + prev_console = ((struct fbcon_ops *)info->fbcon_par)->currcon; + + /* + * FIXME: If we have multiple fbdev's loaded, we need to + * update all info->currcon. Perhaps, we can place this + * in a centralized structure, but this might break some + * drivers. + * + * info->currcon = vc->vc_num; + */ + for (i = 0; i < FB_MAX; i++) { + if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) { + struct fbcon_ops *ops = registered_fb[i]->fbcon_par; + + ops->currcon = vc->vc_num; + } + } + memset(&var, 0, sizeof(struct fb_var_screeninfo)); + display_to_var(&var, p); + var.activate = FB_ACTIVATE_NOW; + + /* + * make sure we don't unnecessarily trip the memcmp() + * in fb_set_var() + */ + info->var.activate = var.activate; + info->var.yoffset = info->var.xoffset = p->yscroll = 0; + fb_set_var(info, &var); + + if (prev_console != -1 && + registered_fb[con2fb_map[prev_console]] != info && + info->fbops->fb_set_par) + info->fbops->fb_set_par(info); + + set_blitting_type(vc, info, p); + ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1; + + vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1); + vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; + updatescrollmode(p, info, vc); + + switch (p->scrollmode) { + case SCROLL_WRAP_MOVE: + scrollback_phys_max = p->vrows - vc->vc_rows; + break; + case SCROLL_PAN_MOVE: + case SCROLL_PAN_REDRAW: + scrollback_phys_max = p->vrows - 2 * vc->vc_rows; + if (scrollback_phys_max < 0) + scrollback_phys_max = 0; + break; + default: + scrollback_phys_max = 0; + break; + } + scrollback_max = 0; + scrollback_current = 0; + + update_var(vc->vc_num, info); + fbcon_set_palette(vc, color_table); + fbcon_clear_margins(vc, 0); + + if (logo_shown == FBCON_LOGO_DRAW) { + + logo_shown = fg_console; + /* This is protected above by initmem_freed */ + fb_show_logo(info); + update_region(vc, + vc->vc_origin + vc->vc_size_row * vc->vc_top, + vc->vc_size_row * (vc->vc_bottom - + vc->vc_top) / 2); + return 0; + } + return 1; +} + +static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, + int blank) +{ + if (blank) { + unsigned short charmask = vc->vc_hi_font_mask ? + 0x1ff : 0xff; + unsigned short oldc; + + oldc = vc->vc_video_erase_char; + vc->vc_video_erase_char &= charmask; + fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols); + vc->vc_video_erase_char = oldc; + } +} + +static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + + if (mode_switch) { + struct fb_var_screeninfo var = info->var; + + ops->graphics = 1; + + if (!blank) { + var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; + fb_set_var(info, &var); + ops->graphics = 0; + } + } + + if (!fbcon_is_inactive(vc, info)) { + if (ops->blank_state != blank) { + ops->blank_state = blank; + fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); + ops->cursor_flash = (!blank); + + if (fb_blank(info, blank)) + fbcon_generic_blank(vc, info, blank); + } + + if (!blank) + update_screen(vc); + } + + return 0; +} + +static void fbcon_free_font(struct display *p) +{ + if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) + kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); + p->fontdata = NULL; + p->userfont = 0; +} + +static int fbcon_get_font(struct vc_data *vc, struct console_font *font) +{ + u8 *fontdata = vc->vc_font.data; + u8 *data = font->data; + int i, j; + + font->width = vc->vc_font.width; + font->height = vc->vc_font.height; + font->charcount = vc->vc_hi_font_mask ? 512 : 256; + if (!font->data) + return 0; + + if (font->width <= 8) { + j = vc->vc_font.height; + for (i = 0; i < font->charcount; i++) { + memcpy(data, fontdata, j); + memset(data + j, 0, 32 - j); + data += 32; + fontdata += j; + } + } else if (font->width <= 16) { + j = vc->vc_font.height * 2; + for (i = 0; i < font->charcount; i++) { + memcpy(data, fontdata, j); + memset(data + j, 0, 64 - j); + data += 64; + fontdata += j; + } + } else if (font->width <= 24) { + for (i = 0; i < font->charcount; i++) { + for (j = 0; j < vc->vc_font.height; j++) { + *data++ = fontdata[0]; + *data++ = fontdata[1]; + *data++ = fontdata[2]; + fontdata += sizeof(u32); + } + memset(data, 0, 3 * (32 - j)); + data += 3 * (32 - j); + } + } else { + j = vc->vc_font.height * 4; + for (i = 0; i < font->charcount; i++) { + memcpy(data, fontdata, j); + memset(data + j, 0, 128 - j); + data += 128; + fontdata += j; + } + } + return 0; +} + +static int fbcon_do_set_font(struct vc_data *vc, int w, int h, + u8 * data, int userfont) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + int resize; + int cnt; + char *old_data = NULL; + + if (CON_IS_VISIBLE(vc) && softback_lines) + fbcon_set_origin(vc); + + resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); + if (p->userfont) + old_data = vc->vc_font.data; + if (userfont) + cnt = FNTCHARCNT(data); + else + cnt = 256; + vc->vc_font.data = p->fontdata = data; + if ((p->userfont = userfont)) + REFCOUNT(data)++; + vc->vc_font.width = w; + vc->vc_font.height = h; + if (vc->vc_hi_font_mask && cnt == 256) { + vc->vc_hi_font_mask = 0; + if (vc->vc_can_do_color) { + vc->vc_complement_mask >>= 1; + vc->vc_s_complement_mask >>= 1; + } + + /* ++Edmund: reorder the attribute bits */ + if (vc->vc_can_do_color) { + unsigned short *cp = + (unsigned short *) vc->vc_origin; + int count = vc->vc_screenbuf_size / 2; + unsigned short c; + for (; count > 0; count--, cp++) { + c = scr_readw(cp); + scr_writew(((c & 0xfe00) >> 1) | + (c & 0xff), cp); + } + c = vc->vc_video_erase_char; + vc->vc_video_erase_char = + ((c & 0xfe00) >> 1) | (c & 0xff); + vc->vc_attr >>= 1; + } + } else if (!vc->vc_hi_font_mask && cnt == 512) { + vc->vc_hi_font_mask = 0x100; + if (vc->vc_can_do_color) { + vc->vc_complement_mask <<= 1; + vc->vc_s_complement_mask <<= 1; + } + + /* ++Edmund: reorder the attribute bits */ + { + unsigned short *cp = + (unsigned short *) vc->vc_origin; + int count = vc->vc_screenbuf_size / 2; + unsigned short c; + for (; count > 0; count--, cp++) { + unsigned short newc; + c = scr_readw(cp); + if (vc->vc_can_do_color) + newc = + ((c & 0xff00) << 1) | (c & + 0xff); + else + newc = c & ~0x100; + scr_writew(newc, cp); + } + c = vc->vc_video_erase_char; + if (vc->vc_can_do_color) { + vc->vc_video_erase_char = + ((c & 0xff00) << 1) | (c & 0xff); + vc->vc_attr <<= 1; + } else + vc->vc_video_erase_char = c & ~0x100; + } + + } + + if (resize) { + /* reset wrap/pan */ + info->var.xoffset = info->var.yoffset = p->yscroll = 0; + vc_resize(vc, info->var.xres / w, info->var.yres / h); + if (CON_IS_VISIBLE(vc) && softback_buf) { + int l = fbcon_softback_size / vc->vc_size_row; + if (l > 5) + softback_end = + softback_buf + l * vc->vc_size_row; + else { + /* Smaller scrollback makes no sense, and 0 would screw + the operation totally */ + softback_top = 0; + } + } + } else if (CON_IS_VISIBLE(vc) + && vc->vc_mode == KD_TEXT) { + fbcon_clear_margins(vc, 0); + update_screen(vc); + } + + if (old_data && (--REFCOUNT(old_data) == 0)) + kfree(old_data - FONT_EXTRA_WORDS * sizeof(int)); + return 0; +} + +static int fbcon_copy_font(struct vc_data *vc, int con) +{ + struct display *od = &fb_display[con]; + struct console_font *f = &vc->vc_font; + + if (od->fontdata == f->data) + return 0; /* already the same font... */ + return fbcon_do_set_font(vc, f->width, f->height, od->fontdata, od->userfont); +} + +/* + * User asked to set font; we are guaranteed that + * a) width and height are in range 1..32 + * b) charcount does not exceed 512 + * but lets not assume that, since someone might someday want to use larger + * fonts. And charcount of 512 is small for unicode support. + * + * However, user space gives the font in 32 rows , regardless of + * actual font height. So a new API is needed if support for larger fonts + * is ever implemented. + */ + +static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags) +{ + unsigned charcount = font->charcount; + int w = font->width; + int h = font->height; + int size; + int i, csum; + u8 *new_data, *data = font->data; + int pitch = (font->width+7) >> 3; + + /* Is there a reason why fbconsole couldn't handle any charcount >256? + * If not this check should be changed to charcount < 256 */ + if (charcount != 256 && charcount != 512) + return -EINVAL; + + size = h * pitch * charcount; + + new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER); + + if (!new_data) + return -ENOMEM; + + new_data += FONT_EXTRA_WORDS * sizeof(int); + FNTSIZE(new_data) = size; + FNTCHARCNT(new_data) = charcount; + REFCOUNT(new_data) = 0; /* usage counter */ + for (i=0; i< charcount; i++) { + memcpy(new_data + i*h*pitch, data + i*32*pitch, h*pitch); + } + + /* Since linux has a nice crc32 function use it for counting font + * checksums. */ + csum = crc32(0, new_data, size); + + FNTSUM(new_data) = csum; + /* Check if the same font is on some other console already */ + for (i = 0; i < MAX_NR_CONSOLES; i++) { + struct vc_data *tmp = vc_cons[i].d; + + if (fb_display[i].userfont && + fb_display[i].fontdata && + FNTSUM(fb_display[i].fontdata) == csum && + FNTSIZE(fb_display[i].fontdata) == size && + tmp->vc_font.width == w && + !memcmp(fb_display[i].fontdata, new_data, size)) { + kfree(new_data - FONT_EXTRA_WORDS * sizeof(int)); + new_data = fb_display[i].fontdata; + break; + } + } + return fbcon_do_set_font(vc, font->width, font->height, new_data, 1); +} + +static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct font_desc *f; + + if (!name) + f = get_default_font(info->var.xres, info->var.yres); + else if (!(f = find_font(name))) + return -ENOENT; + + font->width = f->width; + font->height = f->height; + return fbcon_do_set_font(vc, f->width, f->height, f->data, 0); +} + +static u16 palette_red[16]; +static u16 palette_green[16]; +static u16 palette_blue[16]; + +static struct fb_cmap palette_cmap = { + 0, 16, palette_red, palette_green, palette_blue, NULL +}; + +static int fbcon_set_palette(struct vc_data *vc, unsigned char *table) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + int i, j, k, depth; + u8 val; + + if (fbcon_is_inactive(vc, info)) + return -EINVAL; + + if (!CON_IS_VISIBLE(vc)) + return 0; + + depth = fb_get_color_depth(&info->var); + if (depth > 3) { + for (i = j = 0; i < 16; i++) { + k = table[i]; + val = vc->vc_palette[j++]; + palette_red[k] = (val << 8) | val; + val = vc->vc_palette[j++]; + palette_green[k] = (val << 8) | val; + val = vc->vc_palette[j++]; + palette_blue[k] = (val << 8) | val; + } + palette_cmap.len = 16; + palette_cmap.start = 0; + /* + * If framebuffer is capable of less than 16 colors, + * use default palette of fbcon. + */ + } else + fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap); + + return fb_set_cmap(&palette_cmap, info); +} + +static u16 *fbcon_screen_pos(struct vc_data *vc, int offset) +{ + unsigned long p; + int line; + + if (vc->vc_num != fg_console || !softback_lines) + return (u16 *) (vc->vc_origin + offset); + line = offset / vc->vc_size_row; + if (line >= softback_lines) + return (u16 *) (vc->vc_origin + offset - + softback_lines * vc->vc_size_row); + p = softback_curr + offset; + if (p >= softback_end) + p += softback_buf - softback_end; + return (u16 *) p; +} + +static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos, + int *px, int *py) +{ + unsigned long ret; + int x, y; + + if (pos >= vc->vc_origin && pos < vc->vc_scr_end) { + unsigned long offset = (pos - vc->vc_origin) / 2; + + x = offset % vc->vc_cols; + y = offset / vc->vc_cols; + if (vc->vc_num == fg_console) + y += softback_lines; + ret = pos + (vc->vc_cols - x) * 2; + } else if (vc->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 % vc->vc_cols; + y = offset / vc->vc_cols; + ret = pos + (vc->vc_cols - x) * 2; + if (ret == softback_end) + ret = softback_buf; + if (ret == softback_in) + ret = vc->vc_origin; + } else { + /* Should not happen */ + x = y = 0; + ret = vc->vc_origin; + } + if (px) + *px = x; + if (py) + *py = y; + return ret; +} + +/* As we might be inside of softback, we may work with non-contiguous buffer, + that's why we have to use a separate routine. */ +static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt) +{ + while (cnt--) { + u16 a = scr_readw(p); + if (!vc->vc_can_do_color) + a ^= 0x0800; + else if (vc->vc_hi_font_mask == 0x100) + a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | + (((a) & 0x0e00) << 4); + else + a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | + (((a) & 0x0700) << 4); + scr_writew(a, p++); + if (p == (u16 *) softback_end) + p = (u16 *) softback_buf; + if (p == (u16 *) softback_in) + p = (u16 *) vc->vc_origin; + } +} + +static int fbcon_scrolldelta(struct vc_data *vc, int lines) +{ + struct fb_info *info = registered_fb[con2fb_map[fg_console]]; + struct display *p = &fb_display[fg_console]; + int offset, limit, scrollback_old; + + if (softback_top) { + if (vc->vc_num != fg_console) + return 0; + if (vc->vc_mode != KD_TEXT || !lines) + return 0; + if (logo_shown >= 0) { + struct vc_data *conp2 = vc_cons[logo_shown].d; + + if (conp2->vc_top == logo_lines + && conp2->vc_bottom == conp2->vc_rows) + conp2->vc_top = 0; + if (logo_shown == vc->vc_num) { + unsigned long p, q; + int i; + + p = softback_in; + q = vc->vc_origin + + logo_lines * vc->vc_size_row; + for (i = 0; i < logo_lines; i++) { + if (p == softback_top) + break; + if (p == softback_buf) + p = softback_end; + p -= vc->vc_size_row; + q -= vc->vc_size_row; + scr_memcpyw((u16 *) q, (u16 *) p, + vc->vc_size_row); + } + softback_in = p; + update_region(vc, vc->vc_origin, + logo_lines * vc->vc_cols); + } + logo_shown = FBCON_LOGO_CANSHOW; + } + fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK); + fbcon_redraw_softback(vc, p, lines); + fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK); + return 0; + } + + if (!scrollback_phys_max) + return -ENOSYS; + + scrollback_old = scrollback_current; + scrollback_current -= lines; + if (scrollback_current < 0) + scrollback_current = 0; + else if (scrollback_current > scrollback_max) + scrollback_current = scrollback_max; + if (scrollback_current == scrollback_old) + return 0; + + if (fbcon_is_inactive(vc, info)) + return 0; + + fbcon_cursor(vc, CM_ERASE); + + offset = p->yscroll - scrollback_current; + limit = p->vrows; + switch (p->scrollmode) { + case SCROLL_WRAP_MOVE: + info->var.vmode |= FB_VMODE_YWRAP; + break; + case SCROLL_PAN_MOVE: + case SCROLL_PAN_REDRAW: + limit -= vc->vc_rows; + info->var.vmode &= ~FB_VMODE_YWRAP; + break; + } + if (offset < 0) + offset += limit; + else if (offset >= limit) + offset -= limit; + info->var.xoffset = 0; + info->var.yoffset = offset * vc->vc_font.height; + update_var(vc->vc_num, info); + if (!scrollback_current) + fbcon_cursor(vc, CM_DRAW); + return 0; +} + +static int fbcon_set_origin(struct vc_data *vc) +{ + if (softback_lines) + fbcon_scrolldelta(vc, softback_lines); + return 0; +} + +static void fbcon_suspended(struct fb_info *info) +{ + struct vc_data *vc = NULL; + struct fbcon_ops *ops = info->fbcon_par; + + if (!ops || ops->currcon < 0) + return; + vc = vc_cons[ops->currcon].d; + + /* Clear cursor, restore saved data */ + fbcon_cursor(vc, CM_ERASE); +} + +static void fbcon_resumed(struct fb_info *info) +{ + struct vc_data *vc; + struct fbcon_ops *ops = info->fbcon_par; + + if (!ops || ops->currcon < 0) + return; + vc = vc_cons[ops->currcon].d; + + update_screen(vc); +} + +static void fbcon_modechanged(struct fb_info *info) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct vc_data *vc; + struct display *p; + int rows, cols; + + if (!ops || ops->currcon < 0) + return; + vc = vc_cons[ops->currcon].d; + if (vc->vc_mode != KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info) + return; + + p = &fb_display[vc->vc_num]; + + info->var.xoffset = info->var.yoffset = p->yscroll = 0; + + if (CON_IS_VISIBLE(vc)) { + var_to_display(p, &info->var, info); + cols = info->var.xres / vc->vc_font.width; + rows = info->var.yres / vc->vc_font.height; + vc_resize(vc, cols, rows); + updatescrollmode(p, info, vc); + scrollback_max = 0; + scrollback_current = 0; + update_var(vc->vc_num, info); + fbcon_set_palette(vc, color_table); + update_screen(vc); + if (softback_buf) { + int l = fbcon_softback_size / vc->vc_size_row; + if (l > 5) + softback_end = softback_buf + l * vc->vc_size_row; + else { + /* Smaller scrollback makes no sense, and 0 + would screw the operation totally */ + softback_top = 0; + } + } + } +} + +static int fbcon_mode_deleted(struct fb_info *info, + struct fb_videomode *mode) +{ + struct fb_info *fb_info; + struct display *p; + int i, j, found = 0; + + /* before deletion, ensure that mode is not in use */ + for (i = first_fb_vc; i <= last_fb_vc; i++) { + j = con2fb_map[i]; + if (j == -1) + continue; + fb_info = registered_fb[j]; + if (fb_info != info) + continue; + p = &fb_display[i]; + if (!p || !p->mode) + continue; + if (fb_mode_is_equal(p->mode, mode)) { + found = 1; + break; + } + } + return found; +} + +static int fbcon_fb_registered(int idx) +{ + int ret = 0, i; + + if (info_idx == -1) { + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (con2fb_map_boot[i] == idx) { + info_idx = idx; + break; + } + } + if (info_idx != -1) + ret = fbcon_takeover(1); + } else { + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (con2fb_map_boot[i] == idx) + set_con2fb_map(i, idx, 0); + } + } + + return ret; +} + +static void fbcon_fb_blanked(struct fb_info *info, int blank) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct vc_data *vc; + + if (!ops || ops->currcon < 0) + return; + + vc = vc_cons[ops->currcon].d; + if (vc->vc_mode != KD_TEXT || + registered_fb[con2fb_map[ops->currcon]] != info) + return; + + if (CON_IS_VISIBLE(vc)) { + if (blank) + do_blank_screen(0); + else + do_unblank_screen(0); + } + ops->blank_state = blank; +} + +static void fbcon_new_modelist(struct fb_info *info) +{ + int i; + struct vc_data *vc; + struct fb_var_screeninfo var; + struct fb_videomode *mode; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (registered_fb[con2fb_map[i]] != info) + continue; + if (!fb_display[i].mode) + continue; + vc = vc_cons[i].d; + display_to_var(&var, &fb_display[i]); + mode = fb_find_nearest_mode(&var, &info->modelist); + fb_videomode_to_var(&var, mode); + + if (vc) + fbcon_set_disp(info, &var, vc); + else + fbcon_preset_disp(info, &var, i); + + } +} + +static int fbcon_event_notify(struct notifier_block *self, + unsigned long action, void *data) +{ + struct fb_event *event = data; + struct fb_info *info = event->info; + struct fb_videomode *mode; + struct fb_con2fbmap *con2fb; + int ret = 0; + + switch(action) { + case FB_EVENT_SUSPEND: + fbcon_suspended(info); + break; + case FB_EVENT_RESUME: + fbcon_resumed(info); + break; + case FB_EVENT_MODE_CHANGE: + fbcon_modechanged(info); + break; + case FB_EVENT_MODE_DELETE: + mode = event->data; + ret = fbcon_mode_deleted(info, mode); + break; + case FB_EVENT_FB_REGISTERED: + ret = fbcon_fb_registered(info->node); + break; + case FB_EVENT_SET_CONSOLE_MAP: + con2fb = event->data; + ret = set_con2fb_map(con2fb->console - 1, + con2fb->framebuffer, 1); + break; + case FB_EVENT_GET_CONSOLE_MAP: + con2fb = event->data; + con2fb->framebuffer = con2fb_map[con2fb->console - 1]; + break; + case FB_EVENT_BLANK: + fbcon_fb_blanked(info, *(int *)event->data); + break; + case FB_EVENT_NEW_MODELIST: + fbcon_new_modelist(info); + break; + } + + return ret; +} + +/* + * The console `switch' structure for the frame buffer based console + */ + +static const struct consw fb_con = { + .owner = THIS_MODULE, + .con_startup = fbcon_startup, + .con_init = fbcon_init, + .con_deinit = fbcon_deinit, + .con_clear = fbcon_clear, + .con_putc = fbcon_putc, + .con_putcs = fbcon_putcs, + .con_cursor = fbcon_cursor, + .con_scroll = fbcon_scroll, + .con_bmove = fbcon_bmove, + .con_switch = fbcon_switch, + .con_blank = fbcon_blank, + .con_font_set = fbcon_set_font, + .con_font_get = fbcon_get_font, + .con_font_default = fbcon_set_def_font, + .con_font_copy = fbcon_copy_font, + .con_set_palette = fbcon_set_palette, + .con_scrolldelta = fbcon_scrolldelta, + .con_set_origin = fbcon_set_origin, + .con_invert_region = fbcon_invert_region, + .con_screen_pos = fbcon_screen_pos, + .con_getxy = fbcon_getxy, + .con_resize = fbcon_resize, +}; + +static struct notifier_block fbcon_event_notifier = { + .notifier_call = fbcon_event_notify, +}; + +static int __init fb_console_init(void) +{ + int i; + + acquire_console_sem(); + fb_register_client(&fbcon_event_notifier); + release_console_sem(); + + for (i = 0; i < MAX_NR_CONSOLES; i++) + con2fb_map[i] = -1; + + if (num_registered_fb) { + for (i = 0; i < FB_MAX; i++) { + if (registered_fb[i] != NULL) { + info_idx = i; + break; + } + } + fbcon_takeover(0); + } + + return 0; +} + +module_init(fb_console_init); + +#ifdef MODULE + +static void __exit fb_console_exit(void) +{ + acquire_console_sem(); + fb_unregister_client(&fbcon_event_notifier); + release_console_sem(); + give_up_console(&fb_con); +} + +module_exit(fb_console_exit); + +#endif + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h new file mode 100644 index 000000000000..5d377860bce2 --- /dev/null +++ b/drivers/video/console/fbcon.h @@ -0,0 +1,170 @@ +/* + * linux/drivers/video/console/fbcon.h -- Low level frame buffer based console driver + * + * Copyright (C) 1997 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_FBCON_H +#define _VIDEO_FBCON_H + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/vt_buffer.h> +#include <linux/vt_kern.h> + +#include <asm/io.h> + +#define FBCON_FLAGS_INIT 1 + + /* + * This is the interface between the low-level console driver and the + * low-level frame buffer device + */ + +struct display { + /* Filled in by the frame buffer device */ + u_short inverse; /* != 0 text black on white as default */ + /* Filled in by the low-level console driver */ + u_char *fontdata; + int userfont; /* != 0 if fontdata kmalloc()ed */ + u_short scrollmode; /* Scroll Method */ + short yscroll; /* Hardware scrolling */ + int vrows; /* number of virtual rows */ + int cursor_shape; + u32 xres_virtual; + u32 yres_virtual; + u32 height; + u32 width; + u32 bits_per_pixel; + u32 grayscale; + u32 nonstd; + u32 accel_flags; + u32 rotate; + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + struct fb_videomode *mode; +}; + +struct fbcon_ops { + void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width); + void (*clear)(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width); + void (*putcs)(struct vc_data *vc, struct fb_info *info, + const unsigned short *s, int count, int yy, int xx, + int fg, int bg); + void (*clear_margins)(struct vc_data *vc, struct fb_info *info, + int bottom_only); + void (*cursor)(struct vc_data *vc, struct fb_info *info, + struct display *p, int mode, int softback_lines, int fg, int bg); + + struct timer_list cursor_timer; /* Cursor timer */ + struct fb_cursor cursor_state; + int currcon; /* Current VC. */ + int cursor_flash; + int cursor_reset; + int blank_state; + int graphics; + int flags; + char *cursor_data; +}; + /* + * Attribute Decoding + */ + +/* Color */ +#define attr_fgcol(fgshift,s) \ + (((s) >> (fgshift)) & 0x0f) +#define attr_bgcol(bgshift,s) \ + (((s) >> (bgshift)) & 0x0f) +#define attr_bgcol_ec(bgshift,vc) \ + ((vc) ? (((vc)->vc_video_erase_char >> (bgshift)) & 0x0f) : 0) +#define attr_fgcol_ec(fgshift,vc) \ + ((vc) ? (((vc)->vc_video_erase_char >> (fgshift)) & 0x0f) : 0) + +/* Monochrome */ +#define attr_bold(s) \ + ((s) & 0x200) +#define attr_reverse(s) \ + ((s) & 0x800) +#define attr_underline(s) \ + ((s) & 0x400) +#define attr_blink(s) \ + ((s) & 0x8000) + +/* Font */ +#define REFCOUNT(fd) (((int *)(fd))[-1]) +#define FNTSIZE(fd) (((int *)(fd))[-2]) +#define FNTCHARCNT(fd) (((int *)(fd))[-3]) +#define FNTSUM(fd) (((int *)(fd))[-4]) +#define FONT_EXTRA_WORDS 4 + + /* + * Scroll Method + */ + +/* There are several methods fbcon can use to move text around the screen: + * + * Operation Pan Wrap + *--------------------------------------------- + * SCROLL_MOVE copyarea No No + * SCROLL_PAN_MOVE copyarea Yes No + * SCROLL_WRAP_MOVE copyarea No Yes + * SCROLL_REDRAW imageblit No No + * SCROLL_PAN_REDRAW imageblit Yes No + * SCROLL_WRAP_REDRAW imageblit No Yes + * + * (SCROLL_WRAP_REDRAW is not implemented yet) + * + * In general, fbcon will choose the best scrolling + * method based on the rule below: + * + * Pan/Wrap > accel imageblit > accel copyarea > + * soft imageblit > (soft copyarea) + * + * Exception to the rule: Pan + accel copyarea is + * preferred over Pan + accel imageblit. + * + * The above is typical for PCI/AGP cards. Unless + * overridden, fbcon will never use soft copyarea. + * + * If you need to override the above rule, set the + * appropriate flags in fb_info->flags. For example, + * to prefer copyarea over imageblit, set + * FBINFO_READS_FAST. + * + * Other notes: + * + use the hardware engine to move the text + * (hw-accelerated copyarea() and fillrect()) + * + use hardware-supported panning on a large virtual screen + * + amifb can not only pan, but also wrap the display by N lines + * (i.e. visible line i = physical line (i+N) % yres). + * + read what's already rendered on the screen and + * write it in a different place (this is cfb_copyarea()) + * + re-render the text to the screen + * + * Whether to use wrapping or panning can only be figured out at + * runtime (when we know whether our font height is a multiple + * of the pan/wrap step) + * + */ + +#define SCROLL_MOVE 0x001 +#define SCROLL_PAN_MOVE 0x002 +#define SCROLL_WRAP_MOVE 0x003 +#define SCROLL_REDRAW 0x004 +#define SCROLL_PAN_REDRAW 0x005 + +#ifdef CONFIG_FB_TILEBLITTING +extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, + struct display *p, struct fbcon_ops *ops); +#endif +extern void fbcon_set_bitops(struct fbcon_ops *ops); + +#endif /* _VIDEO_FBCON_H */ diff --git a/drivers/video/console/font_6x11.c b/drivers/video/console/font_6x11.c new file mode 100644 index 000000000000..c52f1294044a --- /dev/null +++ b/drivers/video/console/font_6x11.c @@ -0,0 +1,3351 @@ +/**********************************************/ +/* */ +/* Font file generated by rthelen */ +/* */ +/**********************************************/ + +#include <linux/font.h> + +#define FONTDATAMAX (11*256) + +static unsigned char fontdata_6x11[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x84, /* 0000 00 */ + 0xcc, /* 00 00 */ + 0x84, /* 0000 00 */ + 0xb4, /* 0 0 00 */ + 0x84, /* 0000 00 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 2 0x02 '^B' */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0xfc, /* 00 */ + 0xb4, /* 0 0 00 */ + 0xfc, /* 00 */ + 0xcc, /* 00 00 */ + 0xfc, /* 00 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 3 0x03 '^C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x7c, /* 0 00 */ + 0x7c, /* 0 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x7c, /* 0 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x38, /* 00 000 */ + 0x6c, /* 0 0 00 */ + 0x6c, /* 0 0 00 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 6 0x06 '^F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x7c, /* 0 00 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x78, /* 0 000 */ + 0x30, /* 00 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* */ + 0xff, /* */ + 0xff, /* */ + 0xcf, /* 00 */ + 0x87, /* 0000 */ + 0xcf, /* 00 */ + 0xff, /* */ + 0xff, /* */ + 0xff, /* */ + 0xff, /* */ + 0xff, /* */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x48, /* 0 00 000 */ + 0x84, /* 0000 00 */ + 0x48, /* 0 00 000 */ + 0x30, /* 00 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* */ + 0xff, /* */ + 0xcf, /* 00 */ + 0xb7, /* 0 0 */ + 0x7b, /* 0 0 */ + 0xb7, /* 0 0 */ + 0xcf, /* 00 */ + 0xff, /* */ + 0xff, /* */ + 0xff, /* */ + 0xff, /* */ + + /* 11 0x0b '^K' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x14, /* 000 0 00 */ + 0x20, /* 00 00000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 12 0x0c '^L' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 13 0x0d '^M' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x24, /* 00 00 00 */ + 0x3c, /* 00 00 */ + 0x20, /* 00 00000 */ + 0x20, /* 00 00000 */ + 0xe0, /* 00000 */ + 0xc0, /* 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 14 0x0e '^N' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0xcc, /* 00 00 */ + 0xcc, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 15 0x0f '^O' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x6c, /* 0 0 00 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 16 0x10 '^P' */ + 0x00, /* 00000000 */ + 0x40, /* 0 000000 */ + 0x60, /* 0 00000 */ + 0x70, /* 0 0000 */ + 0x7c, /* 0 00 */ + 0x70, /* 0 0000 */ + 0x60, /* 0 00000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x00, /* 00000000 */ + 0x04, /* 00000 00 */ + 0x0c, /* 0000 00 */ + 0x1c, /* 000 00 */ + 0x7c, /* 0 00 */ + 0x1c, /* 000 00 */ + 0x0c, /* 0000 00 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x10, /* 000 0000 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 19 0x13 '^S' */ + 0x00, /* 00000000 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x00, /* 00000000 */ + 0x48, /* 0 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x3c, /* 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x3c, /* 00 00 */ + 0x14, /* 000 0 00 */ + 0x14, /* 000 0 00 */ + 0x14, /* 000 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x24, /* 00 00 00 */ + 0x50, /* 0 0 0000 */ + 0x48, /* 0 00 000 */ + 0x24, /* 00 00 00 */ + 0x14, /* 000 0 00 */ + 0x48, /* 0 00 000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 000 */ + 0xf8, /* 000 */ + 0xf8, /* 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x10, /* 000 0000 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 24 0x18 '^X' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x7c, /* 0 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x7c, /* 0 00 */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x48, /* 0 00 000 */ + 0x84, /* 0000 00 */ + 0xfc, /* 00 */ + 0x84, /* 0000 00 */ + 0x48, /* 0 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x38, /* 00 000 */ + 0x7c, /* 0 00 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^`' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x7c, /* 0 00 */ + 0x38, /* 00 000 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x7c, /* 0 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x7c, /* 0 00 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x50, /* 0 0 0000 */ + 0x38, /* 00 000 */ + 0x14, /* 000 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0x64, /* 0 00 00 */ + 0x64, /* 0 00 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x4c, /* 0 00 00 */ + 0x4c, /* 0 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x48, /* 0 00 000 */ + 0x50, /* 0 0 0000 */ + 0x20, /* 00 00000 */ + 0x54, /* 0 0 0 00 */ + 0x48, /* 0 00 000 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x30, /* 00 0000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 000 000 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x20, /* 00 00000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x64, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x18, /* 000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x1c, /* 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x04, /* 00000 00 */ + 0x18, /* 000 000 */ + 0x04, /* 00000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x18, /* 000 000 */ + 0x28, /* 00 0 000 */ + 0x48, /* 0 00 000 */ + 0x7c, /* 0 00 */ + 0x08, /* 0000 000 */ + 0x1c, /* 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x3c, /* 00 00 */ + 0x04, /* 00000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 000 000 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x18, /* 000 000 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x30, /* 00 0000 */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x30, /* 00 0000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + + /* 60 0x3c '<' */ + 0x00, /* 00000000 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x00, /* 00000000 */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x74, /* 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x4c, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x00, /* 00000000 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x48, /* 0 00 000 */ + 0x50, /* 0 0 0000 */ + 0x60, /* 0 00000 */ + 0x50, /* 0 0 0000 */ + 0x48, /* 0 00 000 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0x00, /* 00000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x6c, /* 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x64, /* 0 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x4c, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 82 0x52 'R' */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x38, /* 00 000 */ + 0x04, /* 00000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x6c, /* 0 0 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x40, /* 0 000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x0c, /* 0000 00 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x0c, /* 0000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x20, /* 00 00000 */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x30, /* 00 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x30, /* 00 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 96 0x60 '`' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0x00, /* 00000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x00, /* 00000000 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x00, /* 00000000 */ + 0x0c, /* 0000 00 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x3c, /* 00 00 */ + 0x04, /* 00000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + + /* 104 0x68 'h' */ + 0x00, /* 00000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x60, /* 0 00000 */ + 0x00, /* 00000000 */ + + /* 107 0x6b 'k' */ + 0x00, /* 00000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x48, /* 0 00 000 */ + 0x50, /* 0 0 0000 */ + 0x70, /* 0 0000 */ + 0x48, /* 0 00 000 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x58, /* 0 0 000 */ + 0x64, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x3c, /* 00 00 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x58, /* 0 0 000 */ + 0x64, /* 0 00 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x40, /* 0 000000 */ + 0x38, /* 00 000 */ + 0x04, /* 00000 00 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x0c, /* 0000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x3c, /* 00 00 */ + 0x04, /* 00000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x04, /* 00000 00 */ + + /* 124 0x7c '|' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + + /* 126 0x7e '~' */ + 0x00, /* 00000000 */ + 0x34, /* 00 0 00 */ + 0x58, /* 0 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '^?' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '\200' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + + /* 129 0x81 '\201' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '\202' */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 131 0x83 '\203' */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '\204' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '\205' */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '\206' */ + 0x18, /* 000 000 */ + 0x24, /* 00 00 00 */ + 0x18, /* 000 000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '\207' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + + /* 136 0x88 '\210' */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '\211' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 138 0x8a '\212' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '\213' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 140 0x8c '\214' */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '\215' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 142 0x8e '\216' */ + 0x84, /* 0000 00 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '\217' */ + 0x58, /* 0 0 000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '\220' */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '\221' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x5c, /* 0 0 00 */ + 0x50, /* 0 0 0000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '\222' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x50, /* 0 0 0000 */ + 0x50, /* 0 0 0000 */ + 0x78, /* 0 000 */ + 0x50, /* 0 0 0000 */ + 0x50, /* 0 0 0000 */ + 0x5c, /* 0 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '\223' */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '\224' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '\225' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '\226' */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '\227' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '\230' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x3c, /* 00 00 */ + 0x04, /* 00000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + + /* 153 0x99 '\231' */ + 0x84, /* 0000 00 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a '\232' */ + 0x88, /* 000 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '\233' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x50, /* 0 0 0000 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 156 0x9c '\234' */ + 0x30, /* 00 0000 */ + 0x48, /* 0 00 000 */ + 0x40, /* 0 000000 */ + 0x70, /* 0 0000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '\235' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 158 0x9e '\236' */ + 0x00, /* 00000000 */ + 0x70, /* 0 0000 */ + 0x48, /* 0 00 000 */ + 0x70, /* 0 0000 */ + 0x48, /* 0 00 000 */ + 0x5c, /* 0 0 00 */ + 0x48, /* 0 00 000 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 159 0x9f '\237' */ + 0x00, /* 00000000 */ + 0x0c, /* 0000 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x60, /* 0 00000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 '\240' */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '\241' */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '\242' */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '\243' */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '\244' */ + 0x34, /* 00 0 00 */ + 0x58, /* 0 0 000 */ + 0x00, /* 00000000 */ + 0x58, /* 0 0 000 */ + 0x64, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '\245' */ + 0x58, /* 0 0 000 */ + 0x44, /* 0 000 00 */ + 0x64, /* 0 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x4c, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '\246' */ + 0x00, /* 00000000 */ + 0x1c, /* 000 00 */ + 0x24, /* 00 00 00 */ + 0x24, /* 00 00 00 */ + 0x1c, /* 000 00 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '\247' */ + 0x00, /* 00000000 */ + 0x18, /* 000 000 */ + 0x24, /* 00 00 00 */ + 0x24, /* 00 00 00 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '\250' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x40, /* 0 000000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '\251' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa '\252' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '\253' */ + 0x20, /* 00 00000 */ + 0x60, /* 0 00000 */ + 0x24, /* 00 00 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x44, /* 0 000 00 */ + 0x08, /* 0000 000 */ + 0x1c, /* 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 172 0xac '\254' */ + 0x20, /* 00 00000 */ + 0x60, /* 0 00000 */ + 0x24, /* 00 00 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x58, /* 0 0 000 */ + 0x3c, /* 00 00 */ + 0x08, /* 0000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 173 0xad '\255' */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '\256' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x24, /* 00 00 00 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x24, /* 00 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '\257' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x48, /* 0 00 000 */ + 0x24, /* 00 00 00 */ + 0x24, /* 00 00 00 */ + 0x48, /* 0 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '\260' */ + 0x11, /* 000 000 */ + 0x44, /* 0 000 00 */ + 0x11, /* 000 000 */ + 0x44, /* 0 000 00 */ + 0x11, /* 000 000 */ + 0x44, /* 0 000 00 */ + 0x11, /* 000 000 */ + 0x44, /* 0 000 00 */ + 0x11, /* 000 000 */ + 0x44, /* 0 000 00 */ + 0x11, /* 000 000 */ + + /* 177 0xb1 '\261' */ + 0x55, /* 0 0 0 0 */ + 0xaa, /* 0 0 0 0 */ + 0x55, /* 0 0 0 0 */ + 0xaa, /* 0 0 0 0 */ + 0x55, /* 0 0 0 0 */ + 0xaa, /* 0 0 0 0 */ + 0x55, /* 0 0 0 0 */ + 0xaa, /* 0 0 0 0 */ + 0x55, /* 0 0 0 0 */ + 0xaa, /* 0 0 0 0 */ + 0x55, /* 0 0 0 0 */ + + /* 178 0xb2 '\262' */ + 0xdd, /* 0 0 */ + 0x77, /* 0 0 */ + 0xdd, /* 0 0 */ + 0x77, /* 0 0 */ + 0xdd, /* 0 0 */ + 0x77, /* 0 0 */ + 0xdd, /* 0 0 */ + 0x77, /* 0 0 */ + 0xdd, /* 0 0 */ + 0x77, /* 0 0 */ + 0xdd, /* 0 0 */ + + /* 179 0xb3 '\263' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 180 0xb4 '\264' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0xf0, /* 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 181 0xb5 '\265' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0xf0, /* 0000 */ + 0x10, /* 000 0000 */ + 0xf0, /* 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 182 0xb6 '\266' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0xe8, /* 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 183 0xb7 '\267' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 184 0xb8 '\270' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf0, /* 0000 */ + 0x10, /* 000 0000 */ + 0xf0, /* 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 185 0xb9 '\271' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0xe8, /* 0 000 */ + 0x08, /* 0000 000 */ + 0xe8, /* 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 186 0xba '\272' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 187 0xbb '\273' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 000 */ + 0x08, /* 0000 000 */ + 0xe8, /* 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 188 0xbc '\274' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0xe8, /* 0 000 */ + 0x08, /* 0000 000 */ + 0xf8, /* 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '\275' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0xf8, /* 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '\276' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0xf0, /* 0000 */ + 0x10, /* 000 0000 */ + 0xf0, /* 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '\277' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf0, /* 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 192 0xc0 '\300' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x1c, /* 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 '\301' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 '\302' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 195 0xc3 '\303' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x1c, /* 000 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 196 0xc4 '\304' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 '\305' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0xfc, /* 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 198 0xc6 '\306' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x1c, /* 000 00 */ + 0x10, /* 000 0000 */ + 0x1c, /* 000 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 199 0xc7 '\307' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x2c, /* 00 0 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 200 0xc8 '\310' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x2c, /* 00 0 00 */ + 0x20, /* 00 00000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 '\311' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x20, /* 00 00000 */ + 0x2c, /* 00 0 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 202 0xca '\312' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0xec, /* 0 00 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb '\313' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0xec, /* 0 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 204 0xcc '\314' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x2c, /* 00 0 00 */ + 0x20, /* 00 00000 */ + 0x2c, /* 00 0 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 205 0xcd '\315' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce '\316' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0xec, /* 0 00 */ + 0x00, /* 00000000 */ + 0xec, /* 0 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 207 0xcf '\317' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 '\320' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 '\321' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 210 0xd2 '\322' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 211 0xd3 '\323' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 '\324' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x1c, /* 000 00 */ + 0x10, /* 000 0000 */ + 0x1c, /* 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 '\325' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 000 00 */ + 0x10, /* 000 0000 */ + 0x1c, /* 000 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 214 0xd6 '\326' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 215 0xd7 '\327' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0xfc, /* 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + + /* 216 0xd8 '\330' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0xfc, /* 00 */ + 0x10, /* 000 0000 */ + 0xfc, /* 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 217 0xd9 '\331' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0xf0, /* 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda '\332' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 219 0xdb '\333' */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + + /* 220 0xdc '\334' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + + /* 221 0xdd '\335' */ + 0xe0, /* 00000 */ + 0xe0, /* 00000 */ + 0xe0, /* 00000 */ + 0xe0, /* 00000 */ + 0xe0, /* 00000 */ + 0xe0, /* 00000 */ + 0xe0, /* 00000 */ + 0xe0, /* 00000 */ + 0xe0, /* 00000 */ + 0xe0, /* 00000 */ + 0xe0, /* 00000 */ + + /* 222 0xde '\336' */ + 0x1c, /* 000 00 */ + 0x1c, /* 000 00 */ + 0x1c, /* 000 00 */ + 0x1c, /* 000 00 */ + 0x1c, /* 000 00 */ + 0x1c, /* 000 00 */ + 0x1c, /* 000 00 */ + 0x1c, /* 000 00 */ + 0x1c, /* 000 00 */ + 0x1c, /* 000 00 */ + 0x1c, /* 000 00 */ + + /* 223 0xdf '\337' */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 '\340' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x24, /* 00 00 00 */ + 0x58, /* 0 0 000 */ + 0x50, /* 0 0 0000 */ + 0x54, /* 0 0 0 00 */ + 0x2c, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 '\341' */ + 0x18, /* 000 000 */ + 0x24, /* 00 00 00 */ + 0x44, /* 0 000 00 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x58, /* 0 0 000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 '\342' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 '\343' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 '\344' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x24, /* 00 00 00 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x24, /* 00 00 00 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 '\345' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x30, /* 00 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 '\346' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x74, /* 0 0 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + + /* 231 0xe7 '\347' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 0 0 00 */ + 0x98, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 '\350' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 233 0xe9 '\351' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x4c, /* 0 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x64, /* 0 00 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 234 0xea '\352' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x6c, /* 0 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 235 0xeb '\353' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x0c, /* 0000 00 */ + 0x14, /* 000 0 00 */ + 0x24, /* 00 00 00 */ + 0x24, /* 00 00 00 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 236 0xec '\354' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed '\355' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x04, /* 00000 00 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 238 0xee '\356' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 239 0xef '\357' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 '\360' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0xfc, /* 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 '\361' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 '\362' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x1c, /* 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 '\363' */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 '\364' */ + 0x00, /* 00000000 */ + 0x0c, /* 0000 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + + /* 245 0xf5 '\365' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x60, /* 0 00000 */ + 0x00, /* 00000000 */ + + /* 246 0xf6 '\366' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '\367' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x34, /* 00 0 00 */ + 0x48, /* 0 00 000 */ + 0x00, /* 00000000 */ + 0x34, /* 00 0 00 */ + 0x48, /* 0 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 '\370' */ + 0x18, /* 000 000 */ + 0x24, /* 00 00 00 */ + 0x24, /* 00 00 00 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 '\371' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa '\372' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb '\373' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 0000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x50, /* 0 0 0000 */ + 0x20, /* 00 00000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 252 0xfc '\374' */ + 0x00, /* 00000000 */ + 0x50, /* 0 0 0000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd '\375' */ + 0x00, /* 00000000 */ + 0x70, /* 0 0000 */ + 0x08, /* 0000 000 */ + 0x20, /* 00 00000 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe '\376' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x38, /* 00 000 */ + 0x38, /* 00 000 */ + 0x38, /* 00 000 */ + 0x38, /* 00 000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff '\377' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; + + +struct font_desc font_vga_6x11 = { + VGA6x11_IDX, + "ProFont6x11", + 6, + 11, + fontdata_6x11, + -2000 /* Try avoiding this font if possible unless on MAC */ +}; diff --git a/drivers/video/console/font_8x16.c b/drivers/video/console/font_8x16.c new file mode 100644 index 000000000000..e6f8dbaa122b --- /dev/null +++ b/drivers/video/console/font_8x16.c @@ -0,0 +1,4631 @@ +/**********************************************/ +/* */ +/* Font file generated by cpi2fnt */ +/* */ +/**********************************************/ + +#include <linux/font.h> + +#define FONTDATAMAX 4096 + +static unsigned char fontdata_8x16[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 2 0x02 '^B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 3 0x03 '^C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 6 0x06 '^F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x1a, /* 00011010 */ + 0x32, /* 00110010 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 12 0x0c '^L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 13 0x0d '^M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 14 0x0e '^N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe7, /* 11100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 15 0x0f '^O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 16 0x10 '^P' */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0xf0, /* 11110000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0e, /* 00001110 */ + 0x1e, /* 00011110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 19 0x13 '^S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 24 0x18 '^X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x86, /* 10000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x78, /* 01111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 60 0x3c '<' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xdc, /* 11011100 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xde, /* 11011110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xde, /* 11011110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 82 0x52 'R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0xee, /* 11101110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0x70, /* 01110000 */ + 0x38, /* 00111000 */ + 0x1c, /* 00011100 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 96 0x60 '`' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x36, /* 00110110 */ + 0x32, /* 00110010 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 104 0x68 'h' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 107 0x6b 'k' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 129 0x81 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 131 0x83 '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 136 0x88 '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 138 0x8a '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 140 0x8c '' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 142 0x8e '' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x6e, /* 01101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 153 0x99 '' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a '' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 156 0x9c '' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xe6, /* 11100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 158 0x9e '' */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xf8, /* 11111000 */ + 0xc4, /* 11000100 */ + 0xcc, /* 11001100 */ + 0xde, /* 11011110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 159 0x9f '' */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 '' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xdc, /* 11011100 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 172 0xac '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xce, /* 11001110 */ + 0x9a, /* 10011010 */ + 0x3f, /* 00111111 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 173 0xad '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '' */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + + /* 177 0xb1 '' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '' */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + + /* 179 0xb3 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb '' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd '' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde '' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf '' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 231 0xe7 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 233 0xe9 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 234 0xea '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 235 0xeb '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 236 0xec '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x03, /* 00000011 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xf3, /* 11110011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 238 0xee '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 239 0xef '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 246 0xf6 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 '' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb '' */ + 0x00, /* 00000000 */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 252 0xfc '' */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd '' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; + + +struct font_desc font_vga_8x16 = { + VGA8x16_IDX, + "VGA8x16", + 8, + 16, + fontdata_8x16, + 0 +}; diff --git a/drivers/video/console/font_8x8.c b/drivers/video/console/font_8x8.c new file mode 100644 index 000000000000..57fbe266a6b9 --- /dev/null +++ b/drivers/video/console/font_8x8.c @@ -0,0 +1,2583 @@ +/**********************************************/ +/* */ +/* Font file generated by cpi2fnt */ +/* */ +/**********************************************/ + +#include <linux/font.h> + +#define FONTDATAMAX 2048 + +static unsigned char fontdata_8x8[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + + /* 2 0x02 '^B' */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + + /* 3 0x03 '^C' */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 6 0x06 '^F' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x0f, /* 00001111 */ + 0x07, /* 00000111 */ + 0x0f, /* 00001111 */ + 0x7d, /* 01111101 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + + /* 12 0x0c '^L' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + + /* 13 0x0d '^M' */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + + /* 14 0x0e '^N' */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + + /* 15 0x0f '^O' */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + + /* 16 0x10 '^P' */ + 0x80, /* 10000000 */ + 0xe0, /* 11100000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xe0, /* 11100000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x02, /* 00000010 */ + 0x0e, /* 00001110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x0e, /* 00001110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + + /* 19 0x13 '^S' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x3e, /* 00111110 */ + 0x61, /* 01100001 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x86, /* 10000110 */ + 0x7c, /* 01111100 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + + /* 24 0x18 '^X' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x24, /* 00100100 */ + 0x66, /* 01100110 */ + 0xff, /* 11111111 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x60, /* 01100000 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 60 0x3c '<' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xc0, /* 11000000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0xfe, /* 11111110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0xfe, /* 11111110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xce, /* 11001110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xce, /* 11001110 */ + 0x7c, /* 01111100 */ + 0x0e, /* 00001110 */ + + /* 82 0x52 'R' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x8c, /* 10001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0xc0, /* 11000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + + /* 96 0x60 '`' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0xf8, /* 11111000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + + /* 104 0x68 'h' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + + /* 107 0x6b 'k' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x4c, /* 01001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + + /* 129 0x81 '' */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 131 0x83 '' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + + /* 136 0x88 '' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 138 0x8a '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '' */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 140 0x8c '' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 142 0x8e '' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '' */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '' */ + 0x78, /* 01111000 */ + 0x84, /* 10000100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 153 0x99 '' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a '' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 156 0x9c '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 158 0x9e '' */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfa, /* 11111010 */ + 0xc6, /* 11000110 */ + 0xcf, /* 11001111 */ + 0xc6, /* 11000110 */ + 0xc7, /* 11000111 */ + + /* 159 0x9f '' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 '' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '' */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x63, /* 01100011 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7e, /* 01111110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x0f, /* 00001111 */ + + /* 172 0xac '' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7a, /* 01111010 */ + 0x36, /* 00110110 */ + 0x6a, /* 01101010 */ + 0xdf, /* 11011111 */ + 0x06, /* 00000110 */ + + /* 173 0xad '' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '' */ + 0x00, /* 00000000 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '' */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '' */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + + /* 177 0xb1 '' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '' */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + + /* 179 0xb3 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb '' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd '' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde '' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf '' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xc8, /* 11001000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 '' */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 '' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 '' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0xc0, /* 11000000 */ + + /* 231 0xe7 '' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 '' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + + /* 233 0xe9 '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 234 0xea '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + + /* 235 0xeb '' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 236 0xec '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed '' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + + /* 238 0xee '' */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 239 0xef '' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 '' */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 '' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + + /* 246 0xf6 '' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb '' */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + + /* 252 0xfc '' */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd '' */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; + + +struct font_desc font_vga_8x8 = { + VGA8x8_IDX, + "VGA8x8", + 8, + 8, + fontdata_8x8, + 0 +}; diff --git a/drivers/video/console/font_acorn_8x8.c b/drivers/video/console/font_acorn_8x8.c new file mode 100644 index 000000000000..d565505e3069 --- /dev/null +++ b/drivers/video/console/font_acorn_8x8.c @@ -0,0 +1,276 @@ +/* Acorn-like font definition, with PC graphics characters */ + +#include <linux/config.h> +#include <linux/font.h> + +static unsigned char acorndata_8x8[] = { +/* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */ +/* 01 */ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, /* ^A */ +/* 02 */ 0x7e, 0xff, 0xbd, 0xff, 0xc3, 0xe7, 0xff, 0x7e, /* ^B */ +/* 03 */ 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, /* ^C */ +/* 04 */ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, /* ^D */ +/* 05 */ 0x00, 0x18, 0x3c, 0xe7, 0xe7, 0x3c, 0x18, 0x00, /* ^E */ +/* 06 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 07 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 08 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 09 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 0A */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 0B */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 0C */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 0D */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 0E */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 0F */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 10 */ 0x00, 0x60, 0x78, 0x7e, 0x7e, 0x78, 0x60, 0x00, /* |> */ +/* 11 */ 0x00, 0x06, 0x1e, 0x7e, 0x7e, 0x1e, 0x06, 0x00, /* <| */ +/* 12 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 13 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 14 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 15 */ 0x3c, 0x60, 0x3c, 0x66, 0x3c, 0x06, 0x3c, 0x00, +/* 16 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 17 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 18 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 19 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 1A */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 1B */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 1C */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 1D */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 1E */ 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x7e, 0x7e, 0x00, /* /\ */ +/* 1F */ 0x00, 0x7e, 0x7e, 0x3c, 0x3c, 0x18, 0x18, 0x00, /* \/ */ +/* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* */ +/* 21 */ 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, /* ! */ +/* 22 */ 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, /* " */ +/* 23 */ 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00, /* # */ +/* 24 */ 0x0C, 0x3F, 0x68, 0x3E, 0x0B, 0x7E, 0x18, 0x00, /* $ */ +/* 25 */ 0x60, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x06, 0x00, /* % */ +/* 26 */ 0x38, 0x6C, 0x6C, 0x38, 0x6D, 0x66, 0x3B, 0x00, /* & */ +/* 27 */ 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' */ +/* 28 */ 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, /* ( */ +/* 29 */ 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, /* ) */ +/* 2A */ 0x00, 0x18, 0x7E, 0x3C, 0x7E, 0x18, 0x00, 0x00, /* * */ +/* 2B */ 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, /* + */ +/* 2C */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, /* , */ +/* 2D */ 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, /* - */ +/* 2E */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, /* . */ +/* 2F */ 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, /* / */ +/* 30 */ 0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x3C, 0x00, /* 0 */ +/* 31 */ 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, /* 1 */ +/* 32 */ 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00, /* 2 */ +/* 33 */ 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, /* 3 */ +/* 34 */ 0x0C, 0x1C, 0x3C, 0x6C, 0x7E, 0x0C, 0x0C, 0x00, /* 4 */ +/* 35 */ 0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00, /* 5 */ +/* 36 */ 0x1C, 0x30, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, /* 6 */ +/* 37 */ 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, /* 7 */ +/* 38 */ 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, /* 8 */ +/* 39 */ 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00, /* 9 */ +/* 3A */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, /* : */ +/* 3B */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, /* ; */ +/* 3C */ 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, /* < */ +/* 3D */ 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, /* = */ +/* 3E */ 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, /* > */ +/* 3F */ 0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, /* ? */ +/* 40 */ 0x3C, 0x66, 0x6E, 0x6A, 0x6E, 0x60, 0x3C, 0x00, /* @ */ +/* 41 */ 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, /* A */ +/* 42 */ 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, /* B */ +/* 43 */ 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, /* C */ +/* 44 */ 0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00, /* D */ +/* 45 */ 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00, /* E */ +/* 46 */ 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00, /* F */ +/* 47 */ 0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00, /* G */ +/* 48 */ 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, /* H */ +/* 49 */ 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, /* I */ +/* 4A */ 0x3E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00, /* J */ +/* 4B */ 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00, /* K */ +/* 4C */ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, /* L */ +/* 4D */ 0x63, 0x77, 0x7F, 0x6B, 0x6B, 0x63, 0x63, 0x00, /* M */ +/* 4E */ 0x66, 0x66, 0x76, 0x7E, 0x6E, 0x66, 0x66, 0x00, /* N */ +/* 4F */ 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, /* O */ +/* 50 */ 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00, /* P */ +/* 51 */ 0x3C, 0x66, 0x66, 0x66, 0x6A, 0x6C, 0x36, 0x00, /* Q */ +/* 52 */ 0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00, /* R */ +/* 53 */ 0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, /* S */ +/* 54 */ 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, /* T */ +/* 55 */ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, /* U */ +/* 56 */ 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, /* V */ +/* 57 */ 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x77, 0x63, 0x00, /* W */ +/* 58 */ 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, /* X */ +/* 59 */ 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, /* Y */ +/* 5A */ 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, /* Z */ +/* 5B */ 0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7C, 0x00, /* [ */ +/* 5C */ 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, /* \ */ +/* 5D */ 0x3E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3E, 0x00, /* ] */ +/* 5E */ 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^ */ +/* 5F */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, /* _ */ +/* 60 */ 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ` */ +/* 61 */ 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, /* a */ +/* 62 */ 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00, /* b */ +/* 63 */ 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00, /* c */ +/* 64 */ 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, /* d */ +/* 65 */ 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, /* e */ +/* 66 */ 0x1C, 0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x00, /* f */ +/* 67 */ 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x3C, /* g */ +/* 68 */ 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, /* h */ +/* 69 */ 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, /* i */ +/* 6A */ 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x70, /* j */ +/* 6B */ 0x60, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00, /* k */ +/* 6C */ 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, /* l */ +/* 6D */ 0x00, 0x00, 0x36, 0x7F, 0x6B, 0x6B, 0x63, 0x00, /* m */ +/* 6E */ 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, /* n */ +/* 6F */ 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, /* o */ +/* 70 */ 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, /* p */ +/* 71 */ 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x07, /* q */ +/* 72 */ 0x00, 0x00, 0x6C, 0x76, 0x60, 0x60, 0x60, 0x00, /* r */ +/* 73 */ 0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00, /* s */ +/* 74 */ 0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x1C, 0x00, /* t */ +/* 75 */ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, /* u */ +/* 76 */ 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, /* v */ +/* 77 */ 0x00, 0x00, 0x63, 0x6B, 0x6B, 0x7F, 0x36, 0x00, /* w */ +/* 78 */ 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, /* x */ +/* 79 */ 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x3C, /* y */ +/* 7A */ 0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00, /* z */ +/* 7B */ 0x0C, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0C, 0x00, /* { */ +/* 7C */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, /* | */ +/* 7D */ 0x30, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x30, 0x00, /* } */ +/* 7E */ 0x31, 0x6B, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, /* ~ */ +/* 7F */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* */ +/* 80 */ 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x30, 0x60, +/* 81 */ 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00, +/* 82 */ 0x0c, 0x18, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, +/* 83 */ 0x18, 0x66, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, +/* 84 */ 0x66, 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, +/* 85 */ 0x30, 0x18, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, +/* 86 */ 0x3c, 0x66, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, +/* 87 */ 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x60, +/* 88 */ 0x3c, 0x66, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, +/* 89 */ 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, +/* 8A */ 0x30, 0x18, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, +/* 8B */ 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, +/* 8C */ 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, +/* 8D */ 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, +/* 8E */ 0x66, 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x66, 0x00, +/* 8F */ 0x18, 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x66, 0x00, +/* 90 */ 0x0c, 0x18, 0x7e, 0x60, 0x7c, 0x60, 0x7e, 0x00, +/* 91 */ 0x00, 0x00, 0x3f, 0x0d, 0x3f, 0x6c, 0x3f, 0x00, +/* 92 */ 0x3f, 0x66, 0x66, 0x7f, 0x66, 0x66, 0x67, 0x00, +/* 93 */ 0x3c, 0x66, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00, +/* 94 */ 0x66, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00, +/* 95 */ 0x30, 0x18, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00, +/* 96 */ 0x3c, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00, +/* 97 */ 0x30, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00, +/* 98 */ 0x66, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, +/* 99 */ 0x66, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00, +/* 9A */ 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, +/* 9B */ 0x08, 0x3e, 0x6b, 0x68, 0x6b, 0x3e, 0x08, 0x00, +/* 9C */ 0x1c, 0x36, 0x30, 0x7c, 0x30, 0x30, 0x7e, 0x00, +/* 9D */ 0x66, 0x3c, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, +/* 9E */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* 9F */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* A0 */ 0x0c, 0x18, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, +/* A1 */ 0x0c, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, +/* A2 */ 0x0c, 0x18, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00, +/* A3 */ 0x0c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00, +/* A4 */ 0x36, 0x6c, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x00, +/* A5 */ 0x36, 0x6c, 0x00, 0x66, 0x76, 0x6e, 0x66, 0x00, +/* A6 */ 0x1c, 0x06, 0x1e, 0x36, 0x1e, 0x00, 0x3e, 0x00, +/* A7 */ 0x1c, 0x36, 0x36, 0x36, 0x1c, 0x00, 0x3e, 0x00, +/* A8 */ 0x18, 0x00, 0x18, 0x18, 0x30, 0x66, 0x3c, 0x00, +/* A9 */ 0x7e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* AA */ 0x7e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* AB */ 0x40, 0xc0, 0x40, 0x4f, 0x41, 0x0f, 0x08, 0x0f, +/* AC */ 0x40, 0xc0, 0x40, 0x48, 0x48, 0x0a, 0x0f, 0x02, +/* AD */ 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, +/* AE */ 0x00, 0x33, 0x66, 0xcc, 0xcc, 0x66, 0x33, 0x00, +/* AF */ 0x00, 0xcc, 0x66, 0x33, 0x33, 0x66, 0xcc, 0x00, +/* B0 */ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, +/* B1 */ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, +/* B2 */ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, +/* B3 */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* B4 */ 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, +/* B5 */ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, +/* B6 */ 0x66, 0x66, 0x66, 0xe6, 0x66, 0x66, 0x66, 0x66, +/* B7 */ 0x00, 0x00, 0x00, 0xfe, 0x66, 0x66, 0x66, 0x66, +/* B8 */ 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, +/* B9 */ 0x66, 0x66, 0xe6, 0x06, 0xe6, 0x66, 0x66, 0x66, +/* BA */ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +/* BB */ 0x00, 0x00, 0xfe, 0x06, 0xe6, 0x66, 0x66, 0x66, +/* BC */ 0x66, 0x66, 0xe6, 0x06, 0xfe, 0x00, 0x00, 0x00, +/* BD */ 0x66, 0x66, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, +/* BE */ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, +/* BF */ 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, +/* C0 */ 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, +/* C1 */ 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, +/* C2 */ 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, +/* C3 */ 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +/* C4 */ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, +/* C5 */ 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, +/* C6 */ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, +/* C7 */ 0x66, 0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, +/* C8 */ 0x66, 0x66, 0x67, 0x60, 0x7f, 0x00, 0x00, 0x00, +/* C9 */ 0x00, 0x00, 0x7f, 0x60, 0x67, 0x66, 0x66, 0x66, +/* CA */ 0x66, 0x66, 0xe7, 0x00, 0xff, 0x00, 0x00, 0x00, +/* CB */ 0x00, 0x00, 0xff, 0x00, 0xe7, 0x66, 0x66, 0x66, +/* CC */ 0x66, 0x66, 0x67, 0x60, 0x67, 0x66, 0x66, 0x66, +/* CD */ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, +/* CE */ 0x66, 0x66, 0xe7, 0x00, 0xe7, 0x66, 0x66, 0x66, +/* CF */ 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, +/* D0 */ 0x66, 0x66, 0x66, 0xff, 0x00, 0x00, 0x00, 0x00, +/* D1 */ 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, +/* D2 */ 0x00, 0x00, 0x00, 0xff, 0x66, 0x66, 0x66, 0x66, +/* D3 */ 0x66, 0x66, 0x66, 0x7f, 0x00, 0x00, 0x00, 0x00, +/* D4 */ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, +/* D5 */ 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, +/* D6 */ 0x00, 0x00, 0x00, 0x7f, 0x66, 0x66, 0x66, 0x66, +/* D7 */ 0x66, 0x66, 0x66, 0xff, 0x66, 0x66, 0x66, 0x66, +/* D8 */ 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, +/* D9 */ 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, +/* DA */ 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, +/* DB */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* DC */ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, +/* DD */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* DE */ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, +/* DF */ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +/* E0 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* E1 */ 0x3c, 0x66, 0x66, 0x6c, 0x66, 0x66, 0x6c, 0xc0, +/* E2 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* E3 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* E4 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* E5 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* E6 */ 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x60, +/* E7 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* E8 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* E9 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* EA */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* EB */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* EC */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* ED */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* EE */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* EF */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* F0 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* F1 */ 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, +/* F2 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* F3 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* F4 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* F5 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* F6 */ 0x00, 0x18, 0x00, 0xff, 0x00, 0x18, 0x00, 0x00, +/* F7 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* F8 */ 0x3c, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, +/* F9 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* FA */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, +/* FB */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* FC */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* FD */ 0x38, 0x04, 0x18, 0x20, 0x3c, 0x00, 0x00, 0x00, +/* FE */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, +/* FF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +struct font_desc font_acorn_8x8 = { + ACORN8x8_IDX, + "Acorn8x8", + 8, + 8, + acorndata_8x8, +#ifdef CONFIG_ARCH_ACORN + 20 +#else + 0 +#endif +}; diff --git a/drivers/video/console/font_mini_4x6.c b/drivers/video/console/font_mini_4x6.c new file mode 100644 index 000000000000..593b95500a0c --- /dev/null +++ b/drivers/video/console/font_mini_4x6.c @@ -0,0 +1,2158 @@ + +/* Hand composed "Miniscule" 4x6 font, with binary data generated using + * Perl stub. + * + * Use 'perl -x mini_4x6.c < mini_4x6.c > new_version.c' to regenerate + * binary data. + * + * Created by Kenneth Albanowski. + * No rights reserved, released to the public domain. + * + * Version 1.0 + */ + +/* + +#!/usr/bin/perl -pn + +s{((0x)?[0-9a-fA-F]+)(.*\[([\*\ ]{4})\])}{ + + ($num,$pat,$bits) = ($1,$3,$4); + + $bits =~ s/([^\s0])|(.)/ defined($1) + 0 /ge; + + $num = ord(pack("B8", $bits)); + $num |= $num >> 4; + $num = sprintf("0x%.2x", $num); + + #print "$num,$pat,$bits\n"; + + $num . $pat; +}ge; + +__END__; +*/ + +/* Note: binary data consists of one byte for each row of each character top + to bottom, character 0 to character 255, six bytes per character. Each + byte contains the same four character bits in both nybbles. + MSBit to LSBit = left to right. + */ + +#include <linux/font.h> + +#define FONTDATAMAX 1536 + +static unsigned char fontdata_mini_4x6[FONTDATAMAX] = { + + /*{*/ + /* Char 0: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 1: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 2: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 3: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 4: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 5: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 6: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 7: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 8: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 9: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 10: '' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 11: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 12: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 13: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 14: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 15: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 16: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 17: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 18: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 19: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 20: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 21: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 22: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 23: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 24: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 25: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 26: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 27: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 28: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 29: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 30: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 31: ' ' */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 32: ' ' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 33: '!' */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 34: '"' */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 35: '#' */ + 0xaa, /*= [* * ] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 36: '$' */ + 0x44, /*= [ * ] */ + 0x66, /*= [ ** ] */ + 0xee, /*= [*** ] */ + 0xcc, /*= [** ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 37: '%' */ + 0xaa, /*= [* * ] */ + 0x22, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x88, /*= [* ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 38: '&' */ + 0x66, /*= [ ** ] */ + 0x99, /*= [* *] */ + 0x66, /*= [ ** ] */ + 0xaa, /*= [* * ] */ + 0xdd, /*= [** *] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 39: ''' */ + 0x22, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 40: '(' */ + 0x22, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 41: ')' */ + 0x44, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 42: '*' */ + 0x00, /*= [ ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 43: '+' */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0xee, /*= [*** ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 44: ',' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0x88, /*= [* ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 45: '-' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 46: '.' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 47: '/' */ + 0x00, /*= [ ] */ + 0x22, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x88, /*= [* ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 48: '0' */ + 0x44, /*= [ * ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 49: '1' */ + 0x44, /*= [ * ] */ + 0xcc, /*= [** ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 50: '2' */ + 0xcc, /*= [** ] */ + 0x22, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x88, /*= [* ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ + /* Char 51: '3' */ + 0xee, /*= [*** ] */ + 0x22, /*= [ * ] */ + 0x66, /*= [ ** ] */ + 0x22, /*= [ * ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 52: '4' */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0x22, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 53: '5' */ + 0xee, /*= [*** ] */ + 0x88, /*= [* ] */ + 0xee, /*= [*** ] */ + 0x22, /*= [ * ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 54: '6' */ + 0xee, /*= [*** ] */ + 0x88, /*= [* ] */ + 0xee, /*= [*** ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 55: '7' */ + 0xee, /*= [*** ] */ + 0x22, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 56: '8' */ + 0xee, /*= [*** ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 57: '9' */ + 0xee, /*= [*** ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0x22, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 58: ':' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 59: ';' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0x88, /*= [* ] */ + /*}*/ + /*{*/ /* Char 60: '<' */ + 0x22, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x88, /*= [* ] */ + 0x44, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 61: '=' */ + 0x00, /*= [ ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 62: '>' */ + 0x88, /*= [* ] */ + 0x44, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x88, /*= [* ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 63: '?' */ + 0xee, /*= [*** ] */ + 0x22, /*= [ * ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 64: '@' */ + 0x44, /*= [ * ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x88, /*= [* ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 65: 'A' */ + 0x44, /*= [ * ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 66: 'B' */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0xcc, /*= [** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 67: 'C' */ + 0x66, /*= [ ** ] */ + 0x88, /*= [* ] */ + 0x88, /*= [* ] */ + 0x88, /*= [* ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 68: 'D' */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xcc, /*= [** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 69: 'E' */ + 0xee, /*= [*** ] */ + 0x88, /*= [* ] */ + 0xee, /*= [*** ] */ + 0x88, /*= [* ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 70: 'F' */ + 0xee, /*= [*** ] */ + 0x88, /*= [* ] */ + 0xee, /*= [*** ] */ + 0x88, /*= [* ] */ + 0x88, /*= [* ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 71: 'G' */ + 0x66, /*= [ ** ] */ + 0x88, /*= [* ] */ + 0xee, /*= [*** ] */ + 0xaa, /*= [* * ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 72: 'H' */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 73: 'I' */ + 0xee, /*= [*** ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 74: 'J' */ + 0x22, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0xaa, /*= [* * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 75: 'K' */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 76: 'L' */ + 0x88, /*= [* ] */ + 0x88, /*= [* ] */ + 0x88, /*= [* ] */ + 0x88, /*= [* ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 77: 'M' */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 78: 'N' */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 79: 'O' */ + 0x44, /*= [ * ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 80: 'P' */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0xcc, /*= [** ] */ + 0x88, /*= [* ] */ + 0x88, /*= [* ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 81: 'Q' */ + 0x44, /*= [ * ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 82: 'R' */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 83: 'S' */ + 0x66, /*= [ ** ] */ + 0x88, /*= [* ] */ + 0x44, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0xcc, /*= [** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 84: 'T' */ + 0xee, /*= [*** ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 85: 'U' */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 86: 'V' */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 87: 'W' */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 88: 'X' */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x44, /*= [ * ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 89: 'Y' */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 90: 'Z' */ + 0xee, /*= [*** ] */ + 0x22, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x88, /*= [* ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 91: '[' */ + 0x66, /*= [ ** ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 92: '\' */ + 0x00, /*= [ ] */ + 0x88, /*= [* ] */ + 0x44, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 93: ']' */ + 0x66, /*= [ ** ] */ + 0x22, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 94: '^' */ + 0x44, /*= [ * ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 95: '_' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xff, /*= [****] */ + /*}*/ + /*{*/ /* Char 96: '`' */ + 0x88, /*= [* ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 97: 'a' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x66, /*= [ ** ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 98: 'b' */ + 0x88, /*= [* ] */ + 0x88, /*= [* ] */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0xcc, /*= [** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 99: 'c' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x66, /*= [ ** ] */ + 0x88, /*= [* ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 100: 'd' */ + 0x22, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x66, /*= [ ** ] */ + 0xaa, /*= [* * ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 101: 'e' */ + 0x00, /*= [ ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x88, /*= [* ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 102: 'f' */ + 0x22, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xee, /*= [*** ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 103: 'g' */ + 0x00, /*= [ ] */ + 0x66, /*= [ ** ] */ + 0xaa, /*= [* * ] */ + 0x66, /*= [ ** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 104: 'h' */ + 0x88, /*= [* ] */ + 0x88, /*= [* ] */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 105: 'i' */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 106: 'j' */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x88, /*= [* ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 107: 'k' */ + 0x00, /*= [ ] */ + 0x88, /*= [* ] */ + 0xaa, /*= [* * ] */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 108: 'l' */ + 0x00, /*= [ ] */ + 0xcc, /*= [** ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 109: 'm' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 110: 'n' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 111: 'o' */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 112: 'p' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0xcc, /*= [** ] */ + 0x88, /*= [* ] */ + /*}*/ + /*{*/ /* Char 113: 'q' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x66, /*= [ ** ] */ + 0xaa, /*= [* * ] */ + 0x66, /*= [ ** ] */ + 0x22, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 114: 'r' */ + 0x00, /*= [ ] */ + 0xcc, /*= [** ] */ + 0xaa, /*= [* * ] */ + 0x88, /*= [* ] */ + 0x88, /*= [* ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 115: 's' */ + 0x00, /*= [ ] */ + 0x66, /*= [ ** ] */ + 0xcc, /*= [** ] */ + 0x22, /*= [ * ] */ + 0xcc, /*= [** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 116: 't' */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0xee, /*= [*** ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 117: 'u' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 118: 'v' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 119: 'w' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 120: 'x' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xaa, /*= [* * ] */ + 0x44, /*= [ * ] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 121: 'y' */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0x22, /*= [ * ] */ + 0xcc, /*= [** ] */ + /*}*/ + /*{*/ /* Char 122: 'z' */ + 0x00, /*= [ ] */ + 0xee, /*= [*** ] */ + 0x66, /*= [ ** ] */ + 0xcc, /*= [** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 123: '{' */ + 0x22, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xcc, /*= [** ] */ + 0x44, /*= [ * ] */ + 0x22, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 124: '|' */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 125: '}' */ + 0x88, /*= [* ] */ + 0x44, /*= [ * ] */ + 0x66, /*= [ ** ] */ + 0x44, /*= [ * ] */ + 0x88, /*= [* ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 126: '~' */ + 0x55, /*= [ * *] */ + 0xaa, /*= [* * ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 127: '' */ + 0x44, /*= [ * ] */ + 0xaa, /*= [* * ] */ + 0xaa, /*= [* * ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 128: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 129: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 130: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 131: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 132: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 133: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 134: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 135: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 136: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 137: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 138: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 139: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 140: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 141: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 142: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 143: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 144: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 145: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 146: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 147: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 148: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 149: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 150: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 151: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 152: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 153: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 154: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 155: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 156: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 157: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 158: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 159: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 160: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 161: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 162: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 163: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 164: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 165: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 166: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 167: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 168: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 169: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 170: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 171: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 172: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 173: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 174: */ + 0x00, /*= [ ] */ + 0x66, /*= [ ** ] */ + 0xcc, /*= [** ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 175: */ + 0x00, /*= [ ] */ + 0xcc, /*= [** ] */ + 0x66, /*= [ ** ] */ + 0xcc, /*= [** ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 176: */ + 0x88, /*= [* ] */ + 0x22, /*= [ * ] */ + 0x88, /*= [* ] */ + 0x22, /*= [ * ] */ + 0x88, /*= [* ] */ + 0x22, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 177: */ + 0xaa, /*= [* * ] */ + 0x55, /*= [ * *] */ + 0xaa, /*= [* * ] */ + 0x55, /*= [ * *] */ + 0xaa, /*= [* * ] */ + 0x55, /*= [ * *] */ + /*}*/ + /*{*/ /* Char 178: */ + 0xdd, /*= [** *] */ + 0xbb, /*= [* **] */ + 0xdd, /*= [** *] */ + 0xbb, /*= [* **] */ + 0xdd, /*= [** *] */ + 0xbb, /*= [* **] */ + /*}*/ + /*{*/ /* Char 179: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 180: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xcc, /*= [** ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 181: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xcc, /*= [** ] */ + 0xcc, /*= [** ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 182: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0xee, /*= [*** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 183: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xee, /*= [*** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 184: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xcc, /*= [** ] */ + 0xcc, /*= [** ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 185: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 186: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 187: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 188: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 189: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 190: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xcc, /*= [** ] */ + 0xcc, /*= [** ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 191: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xcc, /*= [** ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 192: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x77, /*= [ ***] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 193: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xff, /*= [****] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 194: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xff, /*= [****] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 195: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x77, /*= [ ***] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 196: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xff, /*= [****] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 197: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xff, /*= [****] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 198: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x77, /*= [ ***] */ + 0x77, /*= [ ***] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 199: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x77, /*= [ ***] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 200: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x77, /*= [ ***] */ + 0x77, /*= [ ***] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 201: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x77, /*= [ ***] */ + 0x77, /*= [ ***] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 202: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 203: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 204: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x77, /*= [ ***] */ + 0x77, /*= [ ***] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 205: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 206: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 207: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 208: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0xff, /*= [****] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 209: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 210: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xff, /*= [****] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 211: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x77, /*= [ ***] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 212: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x77, /*= [ ***] */ + 0x77, /*= [ ***] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 213: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x77, /*= [ ***] */ + 0x77, /*= [ ***] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 214: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x77, /*= [ ***] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 215: */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0xff, /*= [****] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + /*}*/ + /*{*/ /* Char 216: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 217: */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0xcc, /*= [** ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 218: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x77, /*= [ ***] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + 0x44, /*= [ * ] */ + /*}*/ + /*{*/ /* Char 219: */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + /*}*/ + /*{*/ /* Char 220: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + /*}*/ + /*{*/ /* Char 221: */ + 0xcc, /*= [** ] */ + 0xcc, /*= [** ] */ + 0xcc, /*= [** ] */ + 0xcc, /*= [** ] */ + 0xcc, /*= [** ] */ + 0xcc, /*= [** ] */ + /*}*/ + /*{*/ /* Char 222: */ + 0x33, /*= [ **] */ + 0x33, /*= [ **] */ + 0x33, /*= [ **] */ + 0x33, /*= [ **] */ + 0x33, /*= [ **] */ + 0x33, /*= [ **] */ + /*}*/ + /*{*/ /* Char 223: */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0xff, /*= [****] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 224: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 225: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 226: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 227: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 228: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 229: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 230: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 231: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 232: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 233: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 234: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 235: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 236: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 237: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 238: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 239: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 240: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 241: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 242: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 243: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 244: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 245: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 246: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 247: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 248: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 249: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 250: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 251: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 252: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 253: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 254: */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + 0x66, /*= [ ** ] */ + 0x66, /*= [ ** ] */ + 0x00, /*= [ ] */ + 0x00, /*= [ ] */ + /*}*/ + /*{*/ /* Char 255: */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0xee, /*= [*** ] */ + 0x00, /*= [ ] */ + /*}*/ +}; + +struct font_desc font_mini_4x6 = { + MINI4x6_IDX, + "MINI4x6", + 4, + 6, + fontdata_mini_4x6, + 3 +}; + diff --git a/drivers/video/console/font_pearl_8x8.c b/drivers/video/console/font_pearl_8x8.c new file mode 100644 index 000000000000..5fa95f118818 --- /dev/null +++ b/drivers/video/console/font_pearl_8x8.c @@ -0,0 +1,2587 @@ +/**********************************************/ +/* */ +/* Font file generated by cpi2fnt */ +/* ------------------------------ */ +/* Combined with the alpha-numeric */ +/* portion of Greg Harp's old PEARL */ +/* font (from earlier versions of */ +/* linux-m86k) by John Shifflett */ +/* */ +/**********************************************/ + +#include <linux/font.h> + +#define FONTDATAMAX 2048 + +static unsigned char fontdata_pearl8x8[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + + /* 2 0x02 '^B' */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + + /* 3 0x03 '^C' */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 6 0x06 '^F' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x0f, /* 00001111 */ + 0x07, /* 00000111 */ + 0x0f, /* 00001111 */ + 0x7d, /* 01111101 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + + /* 12 0x0c '^L' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + + /* 13 0x0d '^M' */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + + /* 14 0x0e '^N' */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + + /* 15 0x0f '^O' */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + + /* 16 0x10 '^P' */ + 0x80, /* 10000000 */ + 0xe0, /* 11100000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xe0, /* 11100000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x02, /* 00000010 */ + 0x0e, /* 00001110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x0e, /* 00001110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + + /* 19 0x13 '^S' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x3e, /* 00111110 */ + 0x61, /* 01100001 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x86, /* 10000110 */ + 0x7c, /* 01111100 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + + /* 24 0x18 '^X' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x24, /* 00100100 */ + 0x66, /* 01100110 */ + 0xff, /* 11111111 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x60, /* 01100000 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x68, /* 01101000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x03, /* 00000011 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xfe, /* 11111110 */ + 0xf6, /* 11110110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x18, /* 00011000 */ + 0x78, /* 01111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x1c, /* 00011100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 60 0x3c '<' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xf0, /* 11110000 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0x82, /* 10000010 */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + + /* 82 0x52 'R' */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0xee, /* 11101110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0xc3, /* 11000011 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc3, /* 11000011 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0xc0, /* 11000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x03, /* 00000011 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + + /* 96 0x60 '`' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x7c, /* 01111100 */ + + /* 104 0x68 'h' */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + + /* 107 0x6b 'k' */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xf0, /* 11110000 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc3, /* 11000011 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x72, /* 01110010 */ + 0x9c, /* 10011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + + /* 129 0x81 '' */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 131 0x83 '' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + + /* 136 0x88 '' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 138 0x8a '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '' */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 140 0x8c '' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 142 0x8e '' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '' */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '' */ + 0x78, /* 01111000 */ + 0x84, /* 10000100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 153 0x99 '' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a '' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 156 0x9c '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 158 0x9e '' */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfa, /* 11111010 */ + 0xc6, /* 11000110 */ + 0xcf, /* 11001111 */ + 0xc6, /* 11000110 */ + 0xc7, /* 11000111 */ + + /* 159 0x9f '' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 '' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '' */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x63, /* 01100011 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7e, /* 01111110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x0f, /* 00001111 */ + + /* 172 0xac '' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7a, /* 01111010 */ + 0x36, /* 00110110 */ + 0x6a, /* 01101010 */ + 0xdf, /* 11011111 */ + 0x06, /* 00000110 */ + + /* 173 0xad '' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '' */ + 0x00, /* 00000000 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '' */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '' */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + + /* 177 0xb1 '' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '' */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + + /* 179 0xb3 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb '' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd '' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde '' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf '' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xc8, /* 11001000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 '' */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 '' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 '' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0xc0, /* 11000000 */ + + /* 231 0xe7 '' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 '' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + + /* 233 0xe9 '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 234 0xea '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + + /* 235 0xeb '' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 236 0xec '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed '' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + + /* 238 0xee '' */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 239 0xef '' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 '' */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 '' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 '' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + + /* 246 0xf6 '' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb '' */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + + /* 252 0xfc '' */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd '' */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; + +struct font_desc font_pearl_8x8 = { + PEARL8x8_IDX, + "PEARL8x8", + 8, + 8, + fontdata_pearl8x8, + 2 +}; diff --git a/drivers/video/console/font_sun12x22.c b/drivers/video/console/font_sun12x22.c new file mode 100644 index 000000000000..05215d0c3e09 --- /dev/null +++ b/drivers/video/console/font_sun12x22.c @@ -0,0 +1,6220 @@ +#include <linux/font.h> + +#define FONTDATAMAX 11264 + +static unsigned char fontdata_sun12x22[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 1 0x01 '^A' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 2 0x02 '^B' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 3 0x03 '^C' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 4 0x04 '^D' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 5 0x05 '^E' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 6 0x06 '^F' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 7 0x07 '^G' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 8 0x08 '^H' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 9 0x09 '^I' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 10 0x0a '^J' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 11 0x0b '^K' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 12 0x0c '^L' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 13 0x0d '^M' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 14 0x0e '^N' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 15 0x0f '^O' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 16 0x10 '^P' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 17 0x11 '^Q' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 18 0x12 '^R' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 19 0x13 '^S' */ + 0x00, 0x00, /* 000000000000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 20 0x14 '^T' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0xf0, /* 000111111111 */ + 0x3c, 0xc0, /* 001111001100 */ + 0x7c, 0xc0, /* 011111001100 */ + 0x7c, 0xc0, /* 011111001100 */ + 0x7c, 0xc0, /* 011111001100 */ + 0x3c, 0xc0, /* 001111001100 */ + 0x1c, 0xc0, /* 000111001100 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x1c, 0xe0, /* 000111001110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 21 0x15 '^U' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x01, 0x80, /* 000000011000 */ + 0x01, 0x80, /* 000000011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 22 0x16 '^V' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 23 0x17 '^W' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 24 0x18 '^X' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 25 0x19 '^Y' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 26 0x1a '^Z' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 27 0x1b '^[' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 28 0x1c '^\' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 29 0x1d '^]' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 30 0x1e '^^' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 31 0x1f '^_' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 32 0x20 ' ' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 33 0x21 '!' */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 34 0x22 '"' */ + 0x00, 0x00, /* 000000000000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 35 0x23 '#' */ + 0x00, 0x00, /* 000000000000 */ + 0x03, 0x30, /* 000000110011 */ + 0x03, 0x30, /* 000000110011 */ + 0x03, 0x30, /* 000000110011 */ + 0x06, 0x60, /* 000001100110 */ + 0x1f, 0xf0, /* 000111111111 */ + 0x1f, 0xf0, /* 000111111111 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x33, 0x00, /* 001100110000 */ + 0x66, 0x00, /* 011001100000 */ + 0x66, 0x00, /* 011001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 36 0x24 '$' */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x66, 0xe0, /* 011001101110 */ + 0x66, 0x60, /* 011001100110 */ + 0x66, 0x00, /* 011001100000 */ + 0x3e, 0x00, /* 001111100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x07, 0xc0, /* 000001111100 */ + 0x06, 0x60, /* 000001100110 */ + 0x06, 0x60, /* 000001100110 */ + 0x66, 0x60, /* 011001100110 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x3f, 0x80, /* 001111111000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 37 0x25 '%' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x38, 0xc0, /* 001110001100 */ + 0x4c, 0xc0, /* 010011001100 */ + 0x45, 0x80, /* 010001011000 */ + 0x65, 0x80, /* 011001011000 */ + 0x3b, 0x00, /* 001110110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0d, 0xc0, /* 000011011100 */ + 0x1a, 0x60, /* 000110100110 */ + 0x1a, 0x20, /* 000110100010 */ + 0x33, 0x20, /* 001100110010 */ + 0x31, 0xc0, /* 001100011100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 38 0x26 '&' */ + 0x00, 0x00, /* 000000000000 */ + 0x07, 0x00, /* 000001110000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x18, 0xc0, /* 000110001100 */ + 0x18, 0xc0, /* 000110001100 */ + 0x0f, 0x80, /* 000011111000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x3e, 0x00, /* 001111100000 */ + 0x77, 0x00, /* 011101110000 */ + 0x63, 0x60, /* 011000110110 */ + 0x61, 0xe0, /* 011000011110 */ + 0x61, 0xc0, /* 011000011100 */ + 0x61, 0x80, /* 011000011000 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x1e, 0x60, /* 000111100110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 39 0x27 ''' */ + 0x00, 0x00, /* 000000000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x10, 0x00, /* 000100000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 40 0x28 '(' */ + 0x00, 0x00, /* 000000000000 */ + 0x01, 0x80, /* 000000011000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x03, 0x00, /* 000000110000 */ + 0x01, 0x80, /* 000000011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 41 0x29 ')' */ + 0x00, 0x00, /* 000000000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 42 0x2a '*' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x66, 0x60, /* 011001100110 */ + 0x76, 0xe0, /* 011101101110 */ + 0x19, 0x80, /* 000110011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x19, 0x80, /* 000110011000 */ + 0x76, 0xe0, /* 011101101110 */ + 0x66, 0x60, /* 011001100110 */ + 0x06, 0x00, /* 000001100000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 43 0x2b '+' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 44 0x2c ',' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x10, 0x00, /* 000100000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 45 0x2d '-' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 46 0x2e '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 47 0x2f '/' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x01, 0x80, /* 000000011000 */ + 0x01, 0x80, /* 000000011000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 48 0x30 '0' */ + 0x00, 0x00, /* 000000000000 */ + 0x07, 0x00, /* 000001110000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x11, 0x80, /* 000100011000 */ + 0x10, 0xc0, /* 000100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0x80, /* 001100001000 */ + 0x18, 0x80, /* 000110001000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 49 0x31 '1' */ + 0x00, 0x00, /* 000000000000 */ + 0x02, 0x00, /* 000000100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x36, 0x00, /* 001101100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 50 0x32 '2' */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x3f, 0x80, /* 001111111000 */ + 0x61, 0xc0, /* 011000011100 */ + 0x40, 0xc0, /* 010000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x01, 0x80, /* 000000011000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x30, 0x20, /* 001100000010 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 51 0x33 '3' */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x1f, 0xc0, /* 000111111100 */ + 0x20, 0xe0, /* 001000001110 */ + 0x40, 0x60, /* 010000000110 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0xe0, /* 000000001110 */ + 0x07, 0xc0, /* 000001111100 */ + 0x0f, 0xc0, /* 000011111100 */ + 0x00, 0xe0, /* 000000001110 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0x60, /* 000000000110 */ + 0x40, 0x60, /* 010000000110 */ + 0x60, 0x40, /* 011000000100 */ + 0x3f, 0x80, /* 001111111000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 52 0x34 '4' */ + 0x00, 0x00, /* 000000000000 */ + 0x01, 0x80, /* 000000011000 */ + 0x03, 0x80, /* 000000111000 */ + 0x03, 0x80, /* 000000111000 */ + 0x05, 0x80, /* 000001011000 */ + 0x05, 0x80, /* 000001011000 */ + 0x09, 0x80, /* 000010011000 */ + 0x09, 0x80, /* 000010011000 */ + 0x11, 0x80, /* 000100011000 */ + 0x11, 0x80, /* 000100011000 */ + 0x21, 0x80, /* 001000011000 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x01, 0x80, /* 000000011000 */ + 0x01, 0x80, /* 000000011000 */ + 0x01, 0x80, /* 000000011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 53 0x35 '5' */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0xc0, /* 000011111100 */ + 0x0f, 0xc0, /* 000011111100 */ + 0x10, 0x00, /* 000100000000 */ + 0x10, 0x00, /* 000100000000 */ + 0x20, 0x00, /* 001000000000 */ + 0x3f, 0x80, /* 001111111000 */ + 0x31, 0xc0, /* 001100011100 */ + 0x00, 0xe0, /* 000000001110 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0x60, /* 000000000110 */ + 0x40, 0x60, /* 010000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x30, 0xc0, /* 001100001100 */ + 0x1f, 0x80, /* 000111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 54 0x36 '6' */ + 0x00, 0x00, /* 000000000000 */ + 0x07, 0x00, /* 000001110000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x67, 0x80, /* 011001111000 */ + 0x6f, 0xc0, /* 011011111100 */ + 0x70, 0xe0, /* 011100001110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x70, 0x40, /* 011100000100 */ + 0x3f, 0x80, /* 001111111000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 55 0x37 '7' */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0xe0, /* 000111111110 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x60, 0x40, /* 011000000100 */ + 0x00, 0x40, /* 000000000100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0x80, /* 000000001000 */ + 0x00, 0x80, /* 000000001000 */ + 0x01, 0x80, /* 000000011000 */ + 0x01, 0x00, /* 000000010000 */ + 0x01, 0x00, /* 000000010000 */ + 0x03, 0x00, /* 000000110000 */ + 0x02, 0x00, /* 000000100000 */ + 0x02, 0x00, /* 000000100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x04, 0x00, /* 000001000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 56 0x38 '8' */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x11, 0x80, /* 000100011000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x18, 0x80, /* 000110001000 */ + 0x0d, 0x00, /* 000011010000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0b, 0x00, /* 000010110000 */ + 0x11, 0x80, /* 000100011000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x18, 0x80, /* 000110001000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 57 0x39 '9' */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x11, 0xc0, /* 000100011100 */ + 0x20, 0xe0, /* 001000001110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x70, 0xe0, /* 011100001110 */ + 0x3f, 0x60, /* 001111110110 */ + 0x1e, 0x60, /* 000111100110 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x01, 0x80, /* 000000011000 */ + 0x07, 0x00, /* 000001110000 */ + 0x3c, 0x00, /* 001111000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 58 0x3a ':' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 59 0x3b ';' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x10, 0x00, /* 000100000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 60 0x3c '<' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x60, /* 000000000110 */ + 0x01, 0xc0, /* 000000011100 */ + 0x07, 0x00, /* 000001110000 */ + 0x1c, 0x00, /* 000111000000 */ + 0x70, 0x00, /* 011100000000 */ + 0x70, 0x00, /* 011100000000 */ + 0x1c, 0x00, /* 000111000000 */ + 0x07, 0x00, /* 000001110000 */ + 0x01, 0xc0, /* 000000011100 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 61 0x3d '=' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 62 0x3e '>' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x38, 0x00, /* 001110000000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x03, 0x80, /* 000000111000 */ + 0x00, 0xe0, /* 000000001110 */ + 0x00, 0xe0, /* 000000001110 */ + 0x03, 0x80, /* 000000111000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x38, 0x00, /* 001110000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 63 0x3f '?' */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x39, 0xc0, /* 001110011100 */ + 0x20, 0xc0, /* 001000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x01, 0x80, /* 000000011000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 64 0x40 '@' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x30, 0x60, /* 001100000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x67, 0x20, /* 011001110010 */ + 0x6f, 0xa0, /* 011011111010 */ + 0x6c, 0xa0, /* 011011001010 */ + 0x6c, 0xa0, /* 011011001010 */ + 0x67, 0xe0, /* 011001111110 */ + 0x60, 0x00, /* 011000000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x0f, 0xe0, /* 000011111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 65 0x41 'A' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0b, 0x00, /* 000010110000 */ + 0x0b, 0x00, /* 000010110000 */ + 0x09, 0x00, /* 000010010000 */ + 0x11, 0x80, /* 000100011000 */ + 0x11, 0x80, /* 000100011000 */ + 0x10, 0x80, /* 000100001000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x20, 0xc0, /* 001000001100 */ + 0x20, 0x40, /* 001000000100 */ + 0x40, 0x60, /* 010000000110 */ + 0x40, 0x60, /* 010000000110 */ + 0xe0, 0xf0, /* 111000001111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 66 0x42 'B' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0x00, /* 111111110000 */ + 0x60, 0x80, /* 011000001000 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x61, 0x80, /* 011000011000 */ + 0x7f, 0x80, /* 011111111000 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0xc0, /* 011000001100 */ + 0xff, 0x80, /* 111111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 67 0x43 'C' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0xc0, /* 000011111100 */ + 0x10, 0x60, /* 000100000110 */ + 0x20, 0x20, /* 001000000010 */ + 0x20, 0x00, /* 001000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x20, 0x00, /* 001000000000 */ + 0x30, 0x20, /* 001100000010 */ + 0x18, 0x40, /* 000110000100 */ + 0x0f, 0x80, /* 000011111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 68 0x44 'D' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0x00, /* 111111110000 */ + 0x61, 0xc0, /* 011000011100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x40, /* 011000000100 */ + 0x61, 0x80, /* 011000011000 */ + 0xfe, 0x00, /* 111111100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 69 0x45 'E' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x30, 0x40, /* 001100000100 */ + 0x30, 0x40, /* 001100000100 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x80, /* 001100001000 */ + 0x3f, 0x80, /* 001111111000 */ + 0x30, 0x80, /* 001100001000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x20, /* 001100000010 */ + 0x30, 0x20, /* 001100000010 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 70 0x46 'F' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x30, 0x40, /* 001100000100 */ + 0x30, 0x40, /* 001100000100 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x80, /* 001100001000 */ + 0x3f, 0x80, /* 001111111000 */ + 0x30, 0x80, /* 001100001000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 71 0x47 'G' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0xc0, /* 000011111100 */ + 0x10, 0x60, /* 000100000110 */ + 0x20, 0x20, /* 001000000010 */ + 0x20, 0x00, /* 001000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x61, 0xf0, /* 011000011111 */ + 0x60, 0x60, /* 011000000110 */ + 0x20, 0x60, /* 001000000110 */ + 0x30, 0x60, /* 001100000110 */ + 0x18, 0x60, /* 000110000110 */ + 0x0f, 0x80, /* 000011111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 72 0x48 'H' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xf0, 0xf0, /* 111100001111 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0xf0, 0xf0, /* 111100001111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 73 0x49 'I' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 74 0x4a 'J' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x04, 0x00, /* 000001000000 */ + 0x38, 0x00, /* 001110000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 75 0x4b 'K' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xf0, 0xe0, /* 111100001110 */ + 0x61, 0x80, /* 011000011000 */ + 0x63, 0x00, /* 011000110000 */ + 0x66, 0x00, /* 011001100000 */ + 0x6c, 0x00, /* 011011000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x7c, 0x00, /* 011111000000 */ + 0x6e, 0x00, /* 011011100000 */ + 0x67, 0x00, /* 011001110000 */ + 0x63, 0x80, /* 011000111000 */ + 0x61, 0xc0, /* 011000011100 */ + 0x60, 0xe0, /* 011000001110 */ + 0xf0, 0x70, /* 111100000111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 76 0x4c 'L' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x20, /* 001100000010 */ + 0x30, 0x20, /* 001100000010 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 77 0x4d 'M' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xe0, 0x70, /* 111000000111 */ + 0x60, 0xe0, /* 011000001110 */ + 0x70, 0xe0, /* 011100001110 */ + 0x70, 0xe0, /* 011100001110 */ + 0x70, 0xe0, /* 011100001110 */ + 0x59, 0x60, /* 010110010110 */ + 0x59, 0x60, /* 010110010110 */ + 0x59, 0x60, /* 010110010110 */ + 0x4d, 0x60, /* 010011010110 */ + 0x4e, 0x60, /* 010011100110 */ + 0x4e, 0x60, /* 010011100110 */ + 0x44, 0x60, /* 010001000110 */ + 0x44, 0x60, /* 010001000110 */ + 0xe4, 0xf0, /* 111001001111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 78 0x4e 'N' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xc0, 0x70, /* 110000000111 */ + 0x60, 0x20, /* 011000000010 */ + 0x70, 0x20, /* 011100000010 */ + 0x78, 0x20, /* 011110000010 */ + 0x58, 0x20, /* 010110000010 */ + 0x4c, 0x20, /* 010011000010 */ + 0x46, 0x20, /* 010001100010 */ + 0x47, 0x20, /* 010001110010 */ + 0x43, 0x20, /* 010000110010 */ + 0x41, 0xa0, /* 010000011010 */ + 0x40, 0xe0, /* 010000001110 */ + 0x40, 0xe0, /* 010000001110 */ + 0x40, 0x60, /* 010000000110 */ + 0xe0, 0x30, /* 111000000011 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 79 0x4f 'O' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x11, 0xc0, /* 000100011100 */ + 0x20, 0xc0, /* 001000001100 */ + 0x20, 0x60, /* 001000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x20, 0x40, /* 001000000100 */ + 0x30, 0x40, /* 001100000100 */ + 0x18, 0x80, /* 000110001000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 80 0x50 'P' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0x80, /* 011111111000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0x60, /* 001100000110 */ + 0x30, 0x60, /* 001100000110 */ + 0x30, 0x60, /* 001100000110 */ + 0x30, 0xc0, /* 001100001100 */ + 0x37, 0x80, /* 001101111000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 81 0x51 'Q' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x11, 0xc0, /* 000100011100 */ + 0x20, 0xc0, /* 001000001100 */ + 0x20, 0x60, /* 001000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x30, 0x40, /* 001100000100 */ + 0x38, 0x40, /* 001110000100 */ + 0x1f, 0x80, /* 000111111000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x23, 0x90, /* 001000111001 */ + 0x01, 0xe0, /* 000000011110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 82 0x52 'R' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0x00, /* 111111110000 */ + 0x61, 0x80, /* 011000011000 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0x80, /* 011000001000 */ + 0x7f, 0x00, /* 011111110000 */ + 0x7c, 0x00, /* 011111000000 */ + 0x6e, 0x00, /* 011011100000 */ + 0x67, 0x00, /* 011001110000 */ + 0x63, 0x80, /* 011000111000 */ + 0x61, 0xc0, /* 011000011100 */ + 0x60, 0xe0, /* 011000001110 */ + 0xf0, 0x70, /* 111100000111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 83 0x53 'S' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0xe0, /* 000111111110 */ + 0x30, 0x60, /* 001100000110 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x70, 0x00, /* 011100000000 */ + 0x3c, 0x00, /* 001111000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x07, 0x80, /* 000001111000 */ + 0x01, 0xc0, /* 000000011100 */ + 0x00, 0xe0, /* 000000001110 */ + 0x40, 0x60, /* 010000000110 */ + 0x40, 0x60, /* 010000000110 */ + 0x60, 0xc0, /* 011000001100 */ + 0x7f, 0x80, /* 011111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 84 0x54 'T' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x46, 0x20, /* 010001100010 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 85 0x55 'U' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xf0, 0x70, /* 111100000111 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x70, 0x40, /* 011100000100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x1f, 0x80, /* 000111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 86 0x56 'V' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xe0, 0xe0, /* 111000001110 */ + 0x60, 0x40, /* 011000000100 */ + 0x30, 0x80, /* 001100001000 */ + 0x30, 0x80, /* 001100001000 */ + 0x30, 0x80, /* 001100001000 */ + 0x19, 0x00, /* 000110010000 */ + 0x19, 0x00, /* 000110010000 */ + 0x19, 0x00, /* 000110010000 */ + 0x0a, 0x00, /* 000010100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x04, 0x00, /* 000001000000 */ + 0x04, 0x00, /* 000001000000 */ + 0x04, 0x00, /* 000001000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 87 0x57 'W' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xfe, 0xf0, /* 111111101111 */ + 0x66, 0x20, /* 011001100010 */ + 0x66, 0x20, /* 011001100010 */ + 0x66, 0x20, /* 011001100010 */ + 0x76, 0x20, /* 011101100010 */ + 0x77, 0x40, /* 011101110100 */ + 0x33, 0x40, /* 001100110100 */ + 0x37, 0x40, /* 001101110100 */ + 0x3b, 0xc0, /* 001110111100 */ + 0x3b, 0x80, /* 001110111000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 88 0x58 'X' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xf0, 0x70, /* 111100000111 */ + 0x60, 0x20, /* 011000000010 */ + 0x30, 0x40, /* 001100000100 */ + 0x38, 0x80, /* 001110001000 */ + 0x18, 0x80, /* 000110001000 */ + 0x0d, 0x00, /* 000011010000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0b, 0x00, /* 000010110000 */ + 0x11, 0x80, /* 000100011000 */ + 0x11, 0xc0, /* 000100011100 */ + 0x20, 0xc0, /* 001000001100 */ + 0x40, 0x60, /* 010000000110 */ + 0xe0, 0xf0, /* 111000001111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 89 0x59 'Y' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xf0, 0x70, /* 111100000111 */ + 0x60, 0x20, /* 011000000010 */ + 0x30, 0x40, /* 001100000100 */ + 0x18, 0x80, /* 000110001000 */ + 0x18, 0x80, /* 000110001000 */ + 0x0d, 0x00, /* 000011010000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 90 0x5a 'Z' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x20, 0xc0, /* 001000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x01, 0x80, /* 000000011000 */ + 0x01, 0x80, /* 000000011000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x18, 0x20, /* 000110000010 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 91 0x5b '[' */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 92 0x5c '\' */ + 0x00, 0x00, /* 000000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x01, 0x80, /* 000000011000 */ + 0x01, 0x80, /* 000000011000 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 93 0x5d ']' */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 94 0x5e '^' */ + 0x00, 0x00, /* 000000000000 */ + 0x04, 0x00, /* 000001000000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x1b, 0x00, /* 000110110000 */ + 0x31, 0x80, /* 001100011000 */ + 0x60, 0xc0, /* 011000001100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 95 0x5f '_' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 96 0x60 '`' */ + 0x00, 0x00, /* 000000000000 */ + 0x01, 0x00, /* 000000010000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x07, 0x80, /* 000001111000 */ + 0x07, 0x80, /* 000001111000 */ + 0x03, 0x00, /* 000000110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 97 0x61 'a' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x10, 0xc0, /* 000100001100 */ + 0x03, 0xc0, /* 000000111100 */ + 0x1c, 0xc0, /* 000111001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1e, 0xe0, /* 000111101110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 98 0x62 'b' */ + 0x00, 0x00, /* 000000000000 */ + 0x20, 0x00, /* 001000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0xe0, 0x00, /* 111000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x67, 0x80, /* 011001111000 */ + 0x6f, 0xc0, /* 011011111100 */ + 0x70, 0xe0, /* 011100001110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x70, 0x60, /* 011100000110 */ + 0x78, 0xc0, /* 011110001100 */ + 0x4f, 0x80, /* 010011111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 99 0x63 'c' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x31, 0xc0, /* 001100011100 */ + 0x20, 0xc0, /* 001000001100 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x70, 0x40, /* 011100000100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x1f, 0x80, /* 000111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 100 0x64 'd' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0xe0, /* 000000001110 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0x60, /* 000000000110 */ + 0x0f, 0x60, /* 000011110110 */ + 0x31, 0xe0, /* 001100011110 */ + 0x20, 0xe0, /* 001000001110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x70, 0xe0, /* 011100001110 */ + 0x39, 0x60, /* 001110010110 */ + 0x1e, 0x70, /* 000111100111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 101 0x65 'e' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x18, 0x60, /* 000110000110 */ + 0x0f, 0x80, /* 000011111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 102 0x66 'f' */ + 0x00, 0x00, /* 000000000000 */ + 0x03, 0x80, /* 000000111000 */ + 0x04, 0xc0, /* 000001001100 */ + 0x04, 0xc0, /* 000001001100 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x3f, 0x80, /* 001111111000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 103 0x67 'g' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0x20, /* 000111110010 */ + 0x31, 0xe0, /* 001100011110 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x31, 0x80, /* 001100011000 */ + 0x3f, 0x00, /* 001111110000 */ + 0x60, 0x00, /* 011000000000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x20, 0x60, /* 001000000110 */ + 0x40, 0x20, /* 010000000010 */ + 0x40, 0x20, /* 010000000010 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x3f, 0x80, /* 001111111000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 104 0x68 'h' */ + 0x00, 0x00, /* 000000000000 */ + 0x10, 0x00, /* 000100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x70, 0x00, /* 011100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x37, 0x80, /* 001101111000 */ + 0x39, 0xc0, /* 001110011100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x79, 0xe0, /* 011110011110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 105 0x69 'i' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 106 0x6a 'j' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x03, 0xc0, /* 000000111100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x20, 0xc0, /* 001000001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x38, 0x80, /* 001110001000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 107 0x6b 'k' */ + 0x00, 0x00, /* 000000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0xe0, 0x00, /* 111000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x61, 0xc0, /* 011000011100 */ + 0x63, 0x00, /* 011000110000 */ + 0x66, 0x00, /* 011001100000 */ + 0x7c, 0x00, /* 011111000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x7c, 0x00, /* 011111000000 */ + 0x6e, 0x00, /* 011011100000 */ + 0x67, 0x00, /* 011001110000 */ + 0x63, 0x80, /* 011000111000 */ + 0xf1, 0xe0, /* 111100011110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 108 0x6c 'l' */ + 0x00, 0x00, /* 000000000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 109 0x6d 'm' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xdd, 0xc0, /* 110111011100 */ + 0x6e, 0xe0, /* 011011101110 */ + 0x66, 0x60, /* 011001100110 */ + 0x66, 0x60, /* 011001100110 */ + 0x66, 0x60, /* 011001100110 */ + 0x66, 0x60, /* 011001100110 */ + 0x66, 0x60, /* 011001100110 */ + 0x66, 0x60, /* 011001100110 */ + 0x66, 0x60, /* 011001100110 */ + 0xef, 0x70, /* 111011110111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 110 0x6e 'n' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x27, 0x80, /* 001001111000 */ + 0x79, 0xc0, /* 011110011100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x79, 0xe0, /* 011110011110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 111 0x6f 'o' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x11, 0xc0, /* 000100011100 */ + 0x20, 0xe0, /* 001000001110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x70, 0x40, /* 011100000100 */ + 0x38, 0x80, /* 001110001000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 112 0x70 'p' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xef, 0x80, /* 111011111000 */ + 0x71, 0xc0, /* 011100011100 */ + 0x60, 0xe0, /* 011000001110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x40, /* 011000000100 */ + 0x70, 0x80, /* 011100001000 */ + 0x7f, 0x00, /* 011111110000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0xf0, 0x00, /* 111100000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 113 0x71 'q' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x20, /* 000011110010 */ + 0x11, 0xe0, /* 000100011110 */ + 0x20, 0xe0, /* 001000001110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x70, 0x60, /* 011100000110 */ + 0x38, 0xe0, /* 001110001110 */ + 0x1f, 0xe0, /* 000111111110 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0xf0, /* 000000001111 */ + 0x00, 0x00, /* 000000000000 */ + + /* 114 0x72 'r' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x73, 0x80, /* 011100111000 */ + 0x34, 0xc0, /* 001101001100 */ + 0x38, 0xc0, /* 001110001100 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 115 0x73 's' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0xc0, /* 000111111100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0x40, /* 001100000100 */ + 0x38, 0x00, /* 001110000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x07, 0x80, /* 000001111000 */ + 0x01, 0xc0, /* 000000011100 */ + 0x20, 0xc0, /* 001000001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x3f, 0x80, /* 001111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 116 0x74 't' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x04, 0x00, /* 000001000000 */ + 0x04, 0x00, /* 000001000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x20, /* 000011000010 */ + 0x0e, 0x40, /* 000011100100 */ + 0x07, 0x80, /* 000001111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 117 0x75 'u' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x79, 0xe0, /* 011110011110 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1e, 0x60, /* 000111100110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 118 0x76 'v' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xf0, 0x70, /* 111100000111 */ + 0x60, 0x20, /* 011000000010 */ + 0x30, 0x40, /* 001100000100 */ + 0x30, 0x40, /* 001100000100 */ + 0x18, 0x80, /* 000110001000 */ + 0x18, 0x80, /* 000110001000 */ + 0x0d, 0x00, /* 000011010000 */ + 0x0d, 0x00, /* 000011010000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 119 0x77 'w' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0x70, /* 111111110111 */ + 0x66, 0x20, /* 011001100010 */ + 0x66, 0x20, /* 011001100010 */ + 0x66, 0x20, /* 011001100010 */ + 0x37, 0x40, /* 001101110100 */ + 0x3b, 0x40, /* 001110110100 */ + 0x3b, 0x40, /* 001110110100 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 120 0x78 'x' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xf8, 0xf0, /* 111110001111 */ + 0x70, 0x40, /* 011100000100 */ + 0x38, 0x80, /* 001110001000 */ + 0x1d, 0x00, /* 000111010000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x07, 0x00, /* 000001110000 */ + 0x0b, 0x80, /* 000010111000 */ + 0x11, 0xc0, /* 000100011100 */ + 0x20, 0xe0, /* 001000001110 */ + 0xf1, 0xf0, /* 111100011111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 121 0x79 'y' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xf0, 0xf0, /* 111100001111 */ + 0x60, 0x20, /* 011000000010 */ + 0x30, 0x40, /* 001100000100 */ + 0x30, 0x40, /* 001100000100 */ + 0x18, 0x80, /* 000110001000 */ + 0x18, 0x80, /* 000110001000 */ + 0x0d, 0x00, /* 000011010000 */ + 0x0d, 0x00, /* 000011010000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x04, 0x00, /* 000001000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x08, 0x00, /* 000010000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x70, 0x00, /* 011100000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 122 0x7a 'z' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x60, 0xe0, /* 011000001110 */ + 0x41, 0xc0, /* 010000011100 */ + 0x03, 0x80, /* 000000111000 */ + 0x07, 0x00, /* 000001110000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x1c, 0x00, /* 000111000000 */ + 0x38, 0x20, /* 001110000010 */ + 0x70, 0x60, /* 011100000110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 123 0x7b '{' */ + 0x00, 0x00, /* 000000000000 */ + 0x03, 0x80, /* 000000111000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x38, 0x00, /* 001110000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x03, 0x80, /* 000000111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 124 0x7c '|' */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 125 0x7d '}' */ + 0x00, 0x00, /* 000000000000 */ + 0x1c, 0x00, /* 000111000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x03, 0x00, /* 000000110000 */ + 0x01, 0xc0, /* 000000011100 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1c, 0x00, /* 000111000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 126 0x7e '~' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1c, 0x20, /* 000111000010 */ + 0x3e, 0x60, /* 001111100110 */ + 0x67, 0xc0, /* 011001111100 */ + 0x43, 0x80, /* 010000111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 127 0x7f '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 128 0x80 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0xc0, /* 000011111100 */ + 0x10, 0x60, /* 000100000110 */ + 0x20, 0x20, /* 001000000010 */ + 0x20, 0x00, /* 001000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x20, 0x00, /* 001000000000 */ + 0x30, 0x20, /* 001100000010 */ + 0x18, 0x40, /* 000110000100 */ + 0x0f, 0x80, /* 000011111000 */ + 0x06, 0x00, /* 000001100000 */ + 0x03, 0x00, /* 000000110000 */ + 0x01, 0x80, /* 000000011000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 129 0x81 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x79, 0xe0, /* 011110011110 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1e, 0x60, /* 000111100110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 130 0x82 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x01, 0x80, /* 000000011000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x18, 0x60, /* 000110000110 */ + 0x0f, 0x80, /* 000011111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 131 0x83 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x02, 0x00, /* 000000100000 */ + 0x07, 0x00, /* 000001110000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x10, 0xc0, /* 000100001100 */ + 0x03, 0xc0, /* 000000111100 */ + 0x1c, 0xc0, /* 000111001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1e, 0xe0, /* 000111101110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 132 0x84 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x10, 0xc0, /* 000100001100 */ + 0x03, 0xc0, /* 000000111100 */ + 0x1c, 0xc0, /* 000111001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1e, 0xe0, /* 000111101110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 133 0x85 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x03, 0x00, /* 000000110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x10, 0xc0, /* 000100001100 */ + 0x03, 0xc0, /* 000000111100 */ + 0x1c, 0xc0, /* 000111001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1e, 0xe0, /* 000111101110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 134 0x86 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x07, 0x00, /* 000001110000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x07, 0x00, /* 000001110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x10, 0xc0, /* 000100001100 */ + 0x03, 0xc0, /* 000000111100 */ + 0x1c, 0xc0, /* 000111001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1e, 0xe0, /* 000111101110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 135 0x87 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x31, 0xc0, /* 001100011100 */ + 0x20, 0xc0, /* 001000001100 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x70, 0x40, /* 011100000100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x1f, 0x80, /* 000111111000 */ + 0x06, 0x00, /* 000001100000 */ + 0x03, 0x00, /* 000000110000 */ + 0x01, 0x80, /* 000000011000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 136 0x88 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x02, 0x00, /* 000000100000 */ + 0x07, 0x00, /* 000001110000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x18, 0x60, /* 000110000110 */ + 0x0f, 0x80, /* 000011111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 137 0x89 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x18, 0x60, /* 000110000110 */ + 0x0f, 0x80, /* 000011111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 138 0x8a '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x03, 0x00, /* 000000110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x60, 0x00, /* 011000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x18, 0x60, /* 000110000110 */ + 0x0f, 0x80, /* 000011111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 139 0x8b '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 140 0x8c '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x04, 0x00, /* 000001000000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x1b, 0x00, /* 000110110000 */ + 0x31, 0x80, /* 001100011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 141 0x8d '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 142 0x8e '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x04, 0x00, /* 000001000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0b, 0x00, /* 000010110000 */ + 0x0b, 0x00, /* 000010110000 */ + 0x19, 0x80, /* 000110011000 */ + 0x11, 0x80, /* 000100011000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x20, 0xc0, /* 001000001100 */ + 0x60, 0x60, /* 011000000110 */ + 0x40, 0x60, /* 010000000110 */ + 0xe0, 0xf0, /* 111000001111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 143 0x8f '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x19, 0x80, /* 000110011000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x04, 0x00, /* 000001000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0b, 0x00, /* 000010110000 */ + 0x0b, 0x00, /* 000010110000 */ + 0x19, 0x80, /* 000110011000 */ + 0x11, 0x80, /* 000100011000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x20, 0xc0, /* 001000001100 */ + 0x60, 0x60, /* 011000000110 */ + 0x40, 0x60, /* 010000000110 */ + 0xe0, 0xf0, /* 111000001111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 144 0x90 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x08, 0x00, /* 000010000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x30, 0x20, /* 001100000010 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x80, /* 001100001000 */ + 0x3f, 0x80, /* 001111111000 */ + 0x30, 0x80, /* 001100001000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x20, /* 001100000010 */ + 0x30, 0x20, /* 001100000010 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 145 0x91 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3d, 0xe0, /* 001111011110 */ + 0x66, 0x30, /* 011001100011 */ + 0x46, 0x30, /* 010001100011 */ + 0x06, 0x30, /* 000001100011 */ + 0x3f, 0xf0, /* 001111111111 */ + 0x66, 0x00, /* 011001100000 */ + 0xc6, 0x00, /* 110001100000 */ + 0xc6, 0x00, /* 110001100000 */ + 0xe7, 0x30, /* 111001110011 */ + 0x7d, 0xe0, /* 011111011110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 146 0x92 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x03, 0xf0, /* 000000111111 */ + 0x07, 0x10, /* 000001110001 */ + 0x07, 0x10, /* 000001110001 */ + 0x0b, 0x00, /* 000010110000 */ + 0x0b, 0x00, /* 000010110000 */ + 0x0b, 0x20, /* 000010110010 */ + 0x13, 0xe0, /* 000100111110 */ + 0x13, 0x20, /* 000100110010 */ + 0x3f, 0x00, /* 001111110000 */ + 0x23, 0x00, /* 001000110000 */ + 0x23, 0x00, /* 001000110000 */ + 0x43, 0x10, /* 010000110001 */ + 0x43, 0x10, /* 010000110001 */ + 0xe7, 0xf0, /* 111001111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 147 0x93 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x02, 0x00, /* 000000100000 */ + 0x07, 0x00, /* 000001110000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x11, 0xc0, /* 000100011100 */ + 0x20, 0xe0, /* 001000001110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x70, 0x40, /* 011100000100 */ + 0x38, 0x80, /* 001110001000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 148 0x94 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x11, 0xc0, /* 000100011100 */ + 0x20, 0xe0, /* 001000001110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x70, 0x40, /* 011100000100 */ + 0x38, 0x80, /* 001110001000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 149 0x95 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x03, 0x00, /* 000000110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x11, 0xc0, /* 000100011100 */ + 0x20, 0xe0, /* 001000001110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x70, 0x40, /* 011100000100 */ + 0x38, 0x80, /* 001110001000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 150 0x96 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x02, 0x00, /* 000000100000 */ + 0x07, 0x00, /* 000001110000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x00, 0x00, /* 000000000000 */ + 0x79, 0xe0, /* 011110011110 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1e, 0x60, /* 000111100110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 151 0x97 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x79, 0xe0, /* 011110011110 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1e, 0x60, /* 000111100110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 152 0x98 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xf0, 0xf0, /* 111100001111 */ + 0x60, 0x20, /* 011000000010 */ + 0x30, 0x40, /* 001100000100 */ + 0x30, 0x40, /* 001100000100 */ + 0x18, 0x80, /* 000110001000 */ + 0x18, 0x80, /* 000110001000 */ + 0x0d, 0x00, /* 000011010000 */ + 0x0d, 0x00, /* 000011010000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x04, 0x00, /* 000001000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x08, 0x00, /* 000010000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x70, 0x00, /* 011100000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 153 0x99 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x11, 0xc0, /* 000100011100 */ + 0x20, 0xc0, /* 001000001100 */ + 0x20, 0x60, /* 001000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x20, 0x40, /* 001000000100 */ + 0x30, 0x40, /* 001100000100 */ + 0x18, 0x80, /* 000110001000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 154 0x9a '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0xe0, 0x30, /* 111000000011 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x60, 0x20, /* 011000000010 */ + 0x70, 0x40, /* 011100000100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x1f, 0x80, /* 000111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 155 0x9b '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x36, 0xc0, /* 001101101100 */ + 0x26, 0xc0, /* 001001101100 */ + 0x66, 0x00, /* 011001100000 */ + 0x66, 0x00, /* 011001100000 */ + 0x66, 0x00, /* 011001100000 */ + 0x66, 0x00, /* 011001100000 */ + 0x76, 0x40, /* 011101100100 */ + 0x36, 0xc0, /* 001101101100 */ + 0x1f, 0x80, /* 000111111000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 156 0x9c '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x1c, 0xc0, /* 000111001100 */ + 0x18, 0xc0, /* 000110001100 */ + 0x18, 0x00, /* 000110000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x7e, 0x00, /* 011111100000 */ + 0x7e, 0x00, /* 011111100000 */ + 0x18, 0x00, /* 000110000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x3e, 0x20, /* 001111100010 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x61, 0xc0, /* 011000011100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 157 0x9d '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x30, 0xc0, /* 001100001100 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 158 0x9e '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 159 0x9f '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 160 0xa0 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x01, 0x80, /* 000000011000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x10, 0xc0, /* 000100001100 */ + 0x03, 0xc0, /* 000000111100 */ + 0x1c, 0xc0, /* 000111001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1e, 0xe0, /* 000111101110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 161 0xa1 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x01, 0x80, /* 000000011000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 162 0xa2 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x01, 0x80, /* 000000011000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x11, 0xc0, /* 000100011100 */ + 0x20, 0xe0, /* 001000001110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x70, 0x40, /* 011100000100 */ + 0x38, 0x80, /* 001110001000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 163 0xa3 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x01, 0x80, /* 000000011000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x79, 0xe0, /* 011110011110 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1e, 0x60, /* 000111100110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 164 0xa4 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x1c, 0x40, /* 000111000100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x23, 0x80, /* 001000111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x27, 0x80, /* 001001111000 */ + 0x79, 0xc0, /* 011110011100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x79, 0xe0, /* 011110011110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 165 0xa5 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x1c, 0x40, /* 000111000100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x23, 0x80, /* 001000111000 */ + 0xc0, 0x70, /* 110000000111 */ + 0x60, 0x20, /* 011000000010 */ + 0x70, 0x20, /* 011100000010 */ + 0x78, 0x20, /* 011110000010 */ + 0x5c, 0x20, /* 010111000010 */ + 0x4e, 0x20, /* 010011100010 */ + 0x47, 0x20, /* 010001110010 */ + 0x43, 0xa0, /* 010000111010 */ + 0x41, 0xe0, /* 010000011110 */ + 0x40, 0xe0, /* 010000001110 */ + 0x40, 0x60, /* 010000000110 */ + 0xe0, 0x30, /* 111000000011 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 166 0xa6 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x31, 0x80, /* 001100011000 */ + 0x01, 0x80, /* 000000011000 */ + 0x07, 0x80, /* 000001111000 */ + 0x19, 0x80, /* 000110011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x31, 0x80, /* 001100011000 */ + 0x33, 0x80, /* 001100111000 */ + 0x1d, 0xc0, /* 000111011100 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 167 0xa7 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x07, 0x00, /* 000001110000 */ + 0x19, 0x80, /* 000110011000 */ + 0x10, 0xc0, /* 000100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0x80, /* 001100001000 */ + 0x19, 0x80, /* 000110011000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 168 0xa8 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x40, /* 001100000100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1f, 0x80, /* 000111111000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 169 0xa9 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 170 0xaa '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 171 0xab '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x10, 0x00, /* 000100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x10, 0x00, /* 000100000000 */ + 0x10, 0x40, /* 000100000100 */ + 0x10, 0x80, /* 000100001000 */ + 0x11, 0x00, /* 000100010000 */ + 0x3a, 0x00, /* 001110100000 */ + 0x05, 0xc0, /* 000001011100 */ + 0x0a, 0x20, /* 000010100010 */ + 0x10, 0x20, /* 000100000010 */ + 0x20, 0xc0, /* 001000001100 */ + 0x41, 0x00, /* 010000010000 */ + 0x02, 0x00, /* 000000100000 */ + 0x03, 0xe0, /* 000000111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 172 0xac '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x10, 0x00, /* 000100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x10, 0x00, /* 000100000000 */ + 0x10, 0x40, /* 000100000100 */ + 0x10, 0x80, /* 000100001000 */ + 0x11, 0x00, /* 000100010000 */ + 0x3a, 0x40, /* 001110100100 */ + 0x04, 0xc0, /* 000001001100 */ + 0x09, 0x40, /* 000010010100 */ + 0x12, 0x40, /* 000100100100 */ + 0x24, 0x40, /* 001001000100 */ + 0x47, 0xe0, /* 010001111110 */ + 0x00, 0x40, /* 000000000100 */ + 0x00, 0x40, /* 000000000100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 173 0xad '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 174 0xae '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x60, /* 000001100110 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x19, 0x80, /* 000110011000 */ + 0x33, 0x00, /* 001100110000 */ + 0x66, 0x00, /* 011001100000 */ + 0x33, 0x00, /* 001100110000 */ + 0x19, 0x80, /* 000110011000 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x06, 0x60, /* 000001100110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 175 0xaf '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x66, 0x00, /* 011001100000 */ + 0x33, 0x00, /* 001100110000 */ + 0x19, 0x80, /* 000110011000 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x06, 0x60, /* 000001100110 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x19, 0x80, /* 000110011000 */ + 0x33, 0x00, /* 001100110000 */ + 0x66, 0x00, /* 011001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 176 0xb0 '.' */ + 0x0c, 0x30, /* 000011000011 */ + 0x08, 0x20, /* 000010000010 */ + 0x61, 0x80, /* 011000011000 */ + 0x20, 0x80, /* 001000001000 */ + 0x0c, 0x30, /* 000011000011 */ + 0x08, 0x20, /* 000010000010 */ + 0x61, 0x80, /* 011000011000 */ + 0x20, 0x80, /* 001000001000 */ + 0x0c, 0x30, /* 000011000011 */ + 0x08, 0x20, /* 000010000010 */ + 0x61, 0x80, /* 011000011000 */ + 0x20, 0x80, /* 001000001000 */ + 0x0c, 0x30, /* 000011000011 */ + 0x08, 0x20, /* 000010000010 */ + 0x61, 0x80, /* 011000011000 */ + 0x20, 0x80, /* 001000001000 */ + 0x0c, 0x30, /* 000011000011 */ + 0x08, 0x20, /* 000010000010 */ + 0x61, 0x80, /* 011000011000 */ + 0x20, 0x80, /* 001000001000 */ + 0x0c, 0x30, /* 000011000011 */ + 0x08, 0x20, /* 000010000010 */ + + /* 177 0xb1 '.' */ + 0x77, 0x70, /* 011101110111 */ + 0x22, 0x20, /* 001000100010 */ + 0x88, 0x80, /* 100010001000 */ + 0xdd, 0xd0, /* 110111011101 */ + 0x88, 0x80, /* 100010001000 */ + 0x22, 0x20, /* 001000100010 */ + 0x77, 0x70, /* 011101110111 */ + 0x22, 0x20, /* 001000100010 */ + 0x88, 0x80, /* 100010001000 */ + 0xdd, 0xd0, /* 110111011101 */ + 0x88, 0x80, /* 100010001000 */ + 0x22, 0x20, /* 001000100010 */ + 0x77, 0x70, /* 011101110111 */ + 0x22, 0x20, /* 001000100010 */ + 0x88, 0x80, /* 100010001000 */ + 0xdd, 0xd0, /* 110111011101 */ + 0x88, 0x80, /* 100010001000 */ + 0x22, 0x20, /* 001000100010 */ + 0x77, 0x70, /* 011101110111 */ + 0x22, 0x20, /* 001000100010 */ + 0x88, 0x80, /* 100010001000 */ + 0xdd, 0xd0, /* 110111011101 */ + + /* 178 0xb2 '.' */ + 0xf3, 0xc0, /* 111100111100 */ + 0xf7, 0xd0, /* 111101111101 */ + 0x9e, 0x70, /* 100111100111 */ + 0xdf, 0x70, /* 110111110111 */ + 0xf3, 0xc0, /* 111100111100 */ + 0xf7, 0xd0, /* 111101111101 */ + 0x9e, 0x70, /* 100111100111 */ + 0xdf, 0x70, /* 110111110111 */ + 0xf3, 0xc0, /* 111100111100 */ + 0xf7, 0xd0, /* 111101111101 */ + 0x9e, 0x70, /* 100111100111 */ + 0xdf, 0x70, /* 110111110111 */ + 0xf3, 0xc0, /* 111100111100 */ + 0xf7, 0xd0, /* 111101111101 */ + 0x9e, 0x70, /* 100111100111 */ + 0xdf, 0x70, /* 110111110111 */ + 0xf3, 0xc0, /* 111100111100 */ + 0xf7, 0xd0, /* 111101111101 */ + 0x9e, 0x70, /* 100111100111 */ + 0xdf, 0x70, /* 110111110111 */ + 0xf3, 0xc0, /* 111100111100 */ + 0xf7, 0xd0, /* 111101111101 */ + + /* 179 0xb3 '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 180 0xb4 '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 181 0xb5 '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 182 0xb6 '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0xfd, 0x80, /* 111111011000 */ + 0xfd, 0x80, /* 111111011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 183 0xb7 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0x80, /* 111111111000 */ + 0xff, 0x80, /* 111111111000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 184 0xb8 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xfe, 0x00, /* 111111100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 185 0xb9 '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0xfd, 0x80, /* 111111011000 */ + 0xfd, 0x80, /* 111111011000 */ + 0x01, 0x80, /* 000000011000 */ + 0xfd, 0x80, /* 111111011000 */ + 0xfd, 0x80, /* 111111011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 186 0xba '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 187 0xbb '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0x80, /* 111111111000 */ + 0xff, 0x80, /* 111111111000 */ + 0x01, 0x80, /* 000000011000 */ + 0xfd, 0x80, /* 111111011000 */ + 0xfd, 0x80, /* 111111011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 188 0xbc '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0xfd, 0x80, /* 111111011000 */ + 0xfd, 0x80, /* 111111011000 */ + 0x01, 0x80, /* 000000011000 */ + 0xff, 0x80, /* 111111111000 */ + 0xff, 0x80, /* 111111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 189 0xbd '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0xff, 0x80, /* 111111111000 */ + 0xff, 0x80, /* 111111111000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 190 0xbe '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 191 0xbf '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xfe, 0x00, /* 111111100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 192 0xc0 '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x07, 0xf0, /* 000001111111 */ + 0x07, 0xf0, /* 000001111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 193 0xc1 '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 194 0xc2 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 195 0xc3 '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x07, 0xf0, /* 000001111111 */ + 0x07, 0xf0, /* 000001111111 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 196 0xc4 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 197 0xc5 '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 198 0xc6 '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x07, 0xf0, /* 000001111111 */ + 0x07, 0xf0, /* 000001111111 */ + 0x06, 0x00, /* 000001100000 */ + 0x07, 0xf0, /* 000001111111 */ + 0x07, 0xf0, /* 000001111111 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 199 0xc7 '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0xf0, /* 000011011111 */ + 0x0d, 0xf0, /* 000011011111 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 200 0xc8 '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0xf0, /* 000011011111 */ + 0x0d, 0xf0, /* 000011011111 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0f, 0xf0, /* 000011111111 */ + 0x0f, 0xf0, /* 000011111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 201 0xc9 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0xf0, /* 000011111111 */ + 0x0f, 0xf0, /* 000011111111 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0d, 0xf0, /* 000011011111 */ + 0x0d, 0xf0, /* 000011011111 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 202 0xca '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0xfd, 0xf0, /* 111111011111 */ + 0xfd, 0xf0, /* 111111011111 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 203 0xcb '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ + 0xfd, 0xf0, /* 111111011111 */ + 0xfd, 0xf0, /* 111111011111 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 204 0xcc '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0xf0, /* 000011011111 */ + 0x0d, 0xf0, /* 000011011111 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0d, 0xf0, /* 000011011111 */ + 0x0d, 0xf0, /* 000011011111 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 205 0xcd '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 206 0xce '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0xfd, 0xf0, /* 111111011111 */ + 0xfd, 0xf0, /* 111111011111 */ + 0x00, 0x00, /* 000000000000 */ + 0xfd, 0xf0, /* 111111011111 */ + 0xfd, 0xf0, /* 111111011111 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 207 0xcf '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 208 0xd0 '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 209 0xd1 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 210 0xd2 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 211 0xd3 '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0f, 0xf0, /* 000011111111 */ + 0x0f, 0xf0, /* 000011111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 212 0xd4 '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x07, 0xf0, /* 000001111111 */ + 0x07, 0xf0, /* 000001111111 */ + 0x06, 0x00, /* 000001100000 */ + 0x07, 0xf0, /* 000001111111 */ + 0x07, 0xf0, /* 000001111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 213 0xd5 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x07, 0xf0, /* 000001111111 */ + 0x07, 0xf0, /* 000001111111 */ + 0x06, 0x00, /* 000001100000 */ + 0x07, 0xf0, /* 000001111111 */ + 0x07, 0xf0, /* 000001111111 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 214 0xd6 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0xf0, /* 000011111111 */ + 0x0f, 0xf0, /* 000011111111 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 215 0xd7 '.' */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + 0x0d, 0x80, /* 000011011000 */ + + /* 216 0xd8 '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x06, 0x00, /* 000001100000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 217 0xd9 '.' */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0xfe, 0x00, /* 111111100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 218 0xda '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x07, 0xf0, /* 000001111111 */ + 0x07, 0xf0, /* 000001111111 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + + /* 219 0xdb '.' */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + + /* 220 0xdc '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + + /* 221 0xdd '.' */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + 0xfc, 0x00, /* 111111000000 */ + + /* 222 0xde '.' */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + 0x03, 0xf0, /* 000000111111 */ + + /* 223 0xdf '.' */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 224 0xe0 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 225 0xe1 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x19, 0x80, /* 000110011000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x31, 0x80, /* 001100011000 */ + 0x37, 0x80, /* 001101111000 */ + 0x31, 0x80, /* 001100011000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x31, 0x80, /* 001100011000 */ + 0x77, 0x00, /* 011101110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 226 0xe2 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 227 0xe3 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 228 0xe4 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 229 0xe5 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 230 0xe6 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x39, 0xc0, /* 001110011100 */ + 0x36, 0xe0, /* 001101101110 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 231 0xe7 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 232 0xe8 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 233 0xe9 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 234 0xea '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 235 0xeb '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 236 0xec '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 237 0xed '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 238 0xee '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 239 0xef '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 240 0xf0 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 241 0xf1 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 242 0xf2 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 243 0xf3 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 244 0xf4 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 245 0xf5 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 246 0xf6 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 247 0xf7 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 248 0xf8 '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 249 0xf9 '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 250 0xfa '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 251 0xfb '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 252 0xfc '.' */ + /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 253 0xfd '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x31, 0x80, /* 001100011000 */ + 0x21, 0x80, /* 001000011000 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x18, 0x40, /* 000110000100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 254 0xfe '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + + /* 255 0xff '.' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + +}; + + +struct font_desc font_sun_12x22 = { + SUN12x22_IDX, + "SUN12x22", + 12, + 22, + fontdata_sun12x22, +#ifdef __sparc__ + 5 +#else + -1 +#endif +}; diff --git a/drivers/video/console/font_sun8x16.c b/drivers/video/console/font_sun8x16.c new file mode 100644 index 000000000000..2af3ab354652 --- /dev/null +++ b/drivers/video/console/font_sun8x16.c @@ -0,0 +1,275 @@ +#include <linux/font.h> + +#define FONTDATAMAX 4096 + +static unsigned char fontdata_sun8x16[FONTDATAMAX] = { +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x7e,0x81,0xa5,0x81,0x81,0xbd,0x99,0x81,0x81,0x7e,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x7e,0xff,0xdb,0xff,0xff,0xc3,0xe7,0xff,0xff,0x7e,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x6c,0xfe,0xfe,0xfe,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x18,0x3c,0x3c,0xe7,0xe7,0xe7,0x18,0x18,0x3c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x18,0x3c,0x7e,0xff,0xff,0x7e,0x18,0x18,0x3c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff,0xff,0xff,0xff,0xff, +/* */ 0x00,0x00,0x00,0x00,0x00,0x3c,0x66,0x42,0x42,0x66,0x3c,0x00,0x00,0x00,0x00,0x00, +/* */ 0xff,0xff,0xff,0xff,0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff,0xff,0xff,0xff,0xff, +/* */ 0x00,0x00,0x1e,0x0e,0x1a,0x32,0x78,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x3c,0x66,0x66,0x66,0x66,0x3c,0x18,0x7e,0x18,0x18,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x3f,0x33,0x3f,0x30,0x30,0x30,0x30,0x70,0xf0,0xe0,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x7f,0x63,0x7f,0x63,0x63,0x63,0x63,0x67,0xe7,0xe6,0xc0,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x18,0x18,0xdb,0x3c,0xe7,0x3c,0xdb,0x18,0x18,0x00,0x00,0x00,0x00, +/* */ 0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfe,0xf8,0xf0,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00, +/* */ 0x00,0x02,0x06,0x0e,0x1e,0x3e,0xfe,0x3e,0x1e,0x0e,0x06,0x02,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x7f,0xdb,0xdb,0xdb,0x7b,0x1b,0x1b,0x1b,0x1b,0x1b,0x00,0x00,0x00,0x00, +/* */ 0x00,0x7c,0xc6,0x60,0x38,0x6c,0xc6,0xc6,0x6c,0x38,0x0c,0xc6,0x7c,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xfe,0xfe,0xfe,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x7e,0x3c,0x18,0x7e,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x18,0x0c,0xfe,0x0c,0x18,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xfe,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xc0,0xc0,0xfe,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x24,0x66,0xff,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7c,0x7c,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0xfe,0xfe,0x7c,0x7c,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*!*/ 0x00,0x00,0x18,0x3c,0x3c,0x3c,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, +/*"*/ 0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*#*/ 0x00,0x00,0x00,0x6c,0x6c,0xfe,0x6c,0x6c,0x6c,0xfe,0x6c,0x6c,0x00,0x00,0x00,0x00, +/*$*/ 0x18,0x18,0x7c,0xc6,0xc2,0xc0,0x7c,0x06,0x06,0x86,0xc6,0x7c,0x18,0x18,0x00,0x00, +/*%*/ 0x00,0x00,0x00,0x00,0xc2,0xc6,0x0c,0x18,0x30,0x60,0xc6,0x86,0x00,0x00,0x00,0x00, +/*&*/ 0x00,0x00,0x38,0x6c,0x6c,0x38,0x76,0xdc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/*'*/ 0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*(*/ 0x00,0x00,0x0c,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0c,0x00,0x00,0x00,0x00, +/*)*/ 0x00,0x00,0x30,0x18,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x18,0x30,0x00,0x00,0x00,0x00, +/***/ 0x00,0x00,0x00,0x00,0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x00,0x00,0x00, +/*+*/ 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00, +/*,*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00, +/*-*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*.*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x02,0x06,0x0c,0x18,0x30,0x60,0xc0,0x80,0x00,0x00,0x00,0x00, +/*0*/ 0x00,0x00,0x7c,0xc6,0xc6,0xce,0xde,0xf6,0xe6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/*1*/ 0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x00,0x00,0x00,0x00, +/*2*/ 0x00,0x00,0x7c,0xc6,0x06,0x0c,0x18,0x30,0x60,0xc0,0xc6,0xfe,0x00,0x00,0x00,0x00, +/*3*/ 0x00,0x00,0x7c,0xc6,0x06,0x06,0x3c,0x06,0x06,0x06,0xc6,0x7c,0x00,0x00,0x00,0x00, +/*4*/ 0x00,0x00,0x0c,0x1c,0x3c,0x6c,0xcc,0xfe,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00, +/*5*/ 0x00,0x00,0xfe,0xc0,0xc0,0xc0,0xfc,0x06,0x06,0x06,0xc6,0x7c,0x00,0x00,0x00,0x00, +/*6*/ 0x00,0x00,0x38,0x60,0xc0,0xc0,0xfc,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/*7*/ 0x00,0x00,0xfe,0xc6,0x06,0x06,0x0c,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00, +/*8*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0x7c,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/*9*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0x7e,0x06,0x06,0x06,0x0c,0x78,0x00,0x00,0x00,0x00, +/*:*/ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, +/*;*/ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00, +/*<*/ 0x00,0x00,0x00,0x06,0x0c,0x18,0x30,0x60,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00, +/*=*/ 0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*>*/ 0x00,0x00,0x00,0x60,0x30,0x18,0x0c,0x06,0x0c,0x18,0x30,0x60,0x00,0x00,0x00,0x00, +/*?*/ 0x00,0x00,0x7c,0xc6,0xc6,0x0c,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, +/*@*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xde,0xde,0xde,0xdc,0xc0,0x7c,0x00,0x00,0x00,0x00, +/*A*/ 0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00, +/*B*/ 0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x66,0x66,0x66,0x66,0xfc,0x00,0x00,0x00,0x00, +/*C*/ 0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xc0,0xc0,0xc2,0x66,0x3c,0x00,0x00,0x00,0x00, +/*D*/ 0x00,0x00,0xf8,0x6c,0x66,0x66,0x66,0x66,0x66,0x66,0x6c,0xf8,0x00,0x00,0x00,0x00, +/*E*/ 0x00,0x00,0xfe,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00, +/*F*/ 0x00,0x00,0xfe,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00, +/*G*/ 0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xde,0xc6,0xc6,0x66,0x3a,0x00,0x00,0x00,0x00, +/*H*/ 0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00, +/*I*/ 0x00,0x00,0x3c,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00, +/*J*/ 0x00,0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00,0x00, +/*K*/ 0x00,0x00,0xe6,0x66,0x66,0x6c,0x78,0x78,0x6c,0x66,0x66,0xe6,0x00,0x00,0x00,0x00, +/*L*/ 0x00,0x00,0xf0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00, +/*M*/ 0x00,0x00,0xc3,0xe7,0xff,0xff,0xdb,0xc3,0xc3,0xc3,0xc3,0xc3,0x00,0x00,0x00,0x00, +/*N*/ 0x00,0x00,0xc6,0xe6,0xf6,0xfe,0xde,0xce,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00, +/*O*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/*P*/ 0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00, +/*Q*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xd6,0xde,0x7c,0x0c,0x0e,0x00,0x00, +/*R*/ 0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x6c,0x66,0x66,0x66,0xe6,0x00,0x00,0x00,0x00, +/*S*/ 0x00,0x00,0x7c,0xc6,0xc6,0x60,0x38,0x0c,0x06,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/*T*/ 0x00,0x00,0xff,0xdb,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00, +/*U*/ 0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/*V*/ 0x00,0x00,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0x66,0x3c,0x18,0x00,0x00,0x00,0x00, +/*W*/ 0x00,0x00,0xc3,0xc3,0xc3,0xc3,0xc3,0xdb,0xdb,0xff,0x66,0x66,0x00,0x00,0x00,0x00, +/*X*/ 0x00,0x00,0xc3,0xc3,0x66,0x3c,0x18,0x18,0x3c,0x66,0xc3,0xc3,0x00,0x00,0x00,0x00, +/*Y*/ 0x00,0x00,0xc3,0xc3,0xc3,0x66,0x3c,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00, +/*Z*/ 0x00,0x00,0xff,0xc3,0x86,0x0c,0x18,0x30,0x60,0xc1,0xc3,0xff,0x00,0x00,0x00,0x00, +/*[*/ 0x00,0x00,0x3c,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3c,0x00,0x00,0x00,0x00, +/*\*/ 0x00,0x00,0x00,0x80,0xc0,0xe0,0x70,0x38,0x1c,0x0e,0x06,0x02,0x00,0x00,0x00,0x00, +/*]*/ 0x00,0x00,0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00,0x00,0x00,0x00, +/*^*/ 0x10,0x38,0x6c,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*_*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00, +/*`*/ 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*a*/ 0x00,0x00,0x00,0x00,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/*b*/ 0x00,0x00,0xe0,0x60,0x60,0x78,0x6c,0x66,0x66,0x66,0x66,0x7c,0x00,0x00,0x00,0x00, +/*c*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xc0,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00, +/*d*/ 0x00,0x00,0x1c,0x0c,0x0c,0x3c,0x6c,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/*e*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00, +/*f*/ 0x00,0x00,0x38,0x6c,0x64,0x60,0xf0,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00, +/*g*/ 0x00,0x00,0x00,0x00,0x00,0x76,0xcc,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0xcc,0x78,0x00, +/*h*/ 0x00,0x00,0xe0,0x60,0x60,0x6c,0x76,0x66,0x66,0x66,0x66,0xe6,0x00,0x00,0x00,0x00, +/*i*/ 0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00, +/*j*/ 0x00,0x00,0x06,0x06,0x00,0x0e,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3c,0x00, +/*k*/ 0x00,0x00,0xe0,0x60,0x60,0x66,0x6c,0x78,0x78,0x6c,0x66,0xe6,0x00,0x00,0x00,0x00, +/*l*/ 0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00, +/*m*/ 0x00,0x00,0x00,0x00,0x00,0xe6,0xff,0xdb,0xdb,0xdb,0xdb,0xdb,0x00,0x00,0x00,0x00, +/*n*/ 0x00,0x00,0x00,0x00,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00, +/*o*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/*p*/ 0x00,0x00,0x00,0x00,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x7c,0x60,0x60,0xf0,0x00, +/*q*/ 0x00,0x00,0x00,0x00,0x00,0x76,0xcc,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0x0c,0x1e,0x00, +/*r*/ 0x00,0x00,0x00,0x00,0x00,0xdc,0x76,0x66,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00, +/*s*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0x60,0x38,0x0c,0xc6,0x7c,0x00,0x00,0x00,0x00, +/*t*/ 0x00,0x00,0x10,0x30,0x30,0xfc,0x30,0x30,0x30,0x30,0x36,0x1c,0x00,0x00,0x00,0x00, +/*u*/ 0x00,0x00,0x00,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/*v*/ 0x00,0x00,0x00,0x00,0x00,0xc3,0xc3,0xc3,0xc3,0x66,0x3c,0x18,0x00,0x00,0x00,0x00, +/*w*/ 0x00,0x00,0x00,0x00,0x00,0xc3,0xc3,0xc3,0xdb,0xdb,0xff,0x66,0x00,0x00,0x00,0x00, +/*x*/ 0x00,0x00,0x00,0x00,0x00,0xc3,0x66,0x3c,0x18,0x3c,0x66,0xc3,0x00,0x00,0x00,0x00, +/*y*/ 0x00,0x00,0x00,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0xf8,0x00, +/*z*/ 0x00,0x00,0x00,0x00,0x00,0xfe,0xcc,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00, +/*{*/ 0x00,0x00,0x0e,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0e,0x00,0x00,0x00,0x00, +/*|*/ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/*}*/ 0x00,0x00,0x70,0x18,0x18,0x18,0x0e,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00, +/*~*/ 0x00,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xc6,0xfe,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xc0,0xc2,0x66,0x3c,0x0c,0x06,0x7c,0x00,0x00, +/* */ 0x00,0x00,0xcc,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/* */ 0x00,0x0c,0x18,0x30,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x10,0x38,0x6c,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0xcc,0x00,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/* */ 0x00,0x60,0x30,0x18,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/* */ 0x00,0x38,0x6c,0x38,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x3c,0x66,0x60,0x60,0x66,0x3c,0x0c,0x06,0x3c,0x00,0x00,0x00, +/* */ 0x00,0x10,0x38,0x6c,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0xc6,0x00,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x60,0x30,0x18,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x18,0x3c,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00, +/* */ 0x00,0xc6,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00, +/* */ 0x38,0x6c,0x38,0x00,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00, +/* */ 0x18,0x30,0x60,0x00,0xfe,0x66,0x60,0x7c,0x60,0x60,0x66,0xfe,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x6e,0x3b,0x1b,0x7e,0xd8,0xdc,0x77,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x3e,0x6c,0xcc,0xcc,0xfe,0xcc,0xcc,0xcc,0xcc,0xce,0x00,0x00,0x00,0x00, +/* */ 0x00,0x10,0x38,0x6c,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0xc6,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x60,0x30,0x18,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x30,0x78,0xcc,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/* */ 0x00,0x60,0x30,0x18,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0xc6,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0x78,0x00, +/* */ 0x00,0xc6,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/* */ 0x00,0xc6,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x18,0x18,0x7e,0xc3,0xc0,0xc0,0xc0,0xc3,0x7e,0x18,0x18,0x00,0x00,0x00,0x00, +/* */ 0x00,0x38,0x6c,0x64,0x60,0xf0,0x60,0x60,0x60,0x60,0xe6,0xfc,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0xc3,0x66,0x3c,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/* */ 0x00,0xfc,0x66,0x66,0x7c,0x62,0x66,0x6f,0x66,0x66,0x66,0xf3,0x00,0x00,0x00,0x00, +/* */ 0x00,0x0e,0x1b,0x18,0x18,0x18,0x7e,0x18,0x18,0x18,0x18,0x18,0xd8,0x70,0x00,0x00, +/* */ 0x00,0x18,0x30,0x60,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/* */ 0x00,0x0c,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x18,0x30,0x60,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x18,0x30,0x60,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x76,0xdc,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00, +/* */ 0x76,0xdc,0x00,0xc6,0xe6,0xf6,0xfe,0xde,0xce,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00, +/* */ 0x00,0x3c,0x6c,0x6c,0x3e,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x38,0x6c,0x6c,0x38,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xc0,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0xc0,0xc0,0xc2,0xc6,0xcc,0x18,0x30,0x60,0xce,0x9b,0x06,0x0c,0x1f,0x00,0x00, +/* */ 0x00,0xc0,0xc0,0xc2,0xc6,0xcc,0x18,0x30,0x66,0xce,0x96,0x3e,0x06,0x06,0x00,0x00, +/* */ 0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3c,0x3c,0x3c,0x18,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x36,0x6c,0xd8,0x6c,0x36,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0xd8,0x6c,0x36,0x6c,0xd8,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44, +/* */ 0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa, +/* */ 0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77, +/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x36,0x36,0x36,0x36,0x36,0xf6,0x06,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x00,0x00,0x00,0x00,0x00,0xfe,0x06,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x36,0x36,0x36,0x36,0x36,0xf6,0x06,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x3f,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x36,0x36,0x36,0x36,0x36,0xf7,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xf7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x36,0x36,0x36,0x36,0x36,0xf7,0x00,0xf7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x18,0x18,0x18,0x18,0x18,0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xff,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* */ 0x18,0x18,0x18,0x18,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +/* */ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, +/* */ 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, +/* */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x76,0xdc,0xd8,0xd8,0xd8,0xdc,0x76,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x78,0xcc,0xcc,0xcc,0xd8,0xcc,0xc6,0xc6,0xc6,0xcc,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0xfe,0xc6,0xc6,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0xfe,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0xfe,0xc6,0x60,0x30,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x7e,0xd8,0xd8,0xd8,0xd8,0xd8,0x70,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7c,0x60,0x60,0xc0,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x76,0xdc,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x7e,0x18,0x3c,0x66,0x66,0x66,0x3c,0x18,0x7e,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0x6c,0x38,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x38,0x6c,0xc6,0xc6,0xc6,0x6c,0x6c,0x6c,0x6c,0xee,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x1e,0x30,0x18,0x0c,0x3e,0x66,0x66,0x66,0x66,0x3c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x7e,0xdb,0xdb,0xdb,0x7e,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x03,0x06,0x7e,0xdb,0xdb,0xf3,0x7e,0x60,0xc0,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x1c,0x30,0x60,0x60,0x7c,0x60,0x60,0x60,0x30,0x1c,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00,0xff,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x30,0x18,0x0c,0x06,0x0c,0x18,0x30,0x00,0x7e,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x0c,0x18,0x30,0x60,0x30,0x18,0x0c,0x00,0x7e,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x0e,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xd8,0xd8,0xd8,0x70,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7e,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x76,0xdc,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x38,0x6c,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x0f,0x0c,0x0c,0x0c,0x0c,0x0c,0xec,0x6c,0x6c,0x3c,0x1c,0x00,0x00,0x00,0x00, +/* */ 0x00,0xd8,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x70,0xd8,0x30,0x60,0xc8,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x00,0x00,0x00,0x00,0x00, +/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +struct font_desc font_sun_8x16 = { + SUN8x16_IDX, + "SUN8x16", + 8, + 16, + fontdata_sun8x16, +#ifdef __sparc__ + 10 +#else + -1 +#endif +}; diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c new file mode 100644 index 000000000000..465d678230ae --- /dev/null +++ b/drivers/video/console/fonts.c @@ -0,0 +1,139 @@ +/* + * linux/drivers/video/fonts.c -- `Soft' font definitions + * + * Created 1995 by Geert Uytterhoeven + * Rewritten 1998 by Martin Mares <mj@ucw.cz> + * + * 2001 - Documented with DocBook + * - Brad Douglas <brad@neruo.com> + * + * 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/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/string.h> +#if defined(__mc68000__) || defined(CONFIG_APUS) +#include <asm/setup.h> +#endif +#include <linux/font.h> + +#define NO_FONTS + +static struct font_desc *fonts[] = { +#ifdef CONFIG_FONT_8x8 +#undef NO_FONTS + &font_vga_8x8, +#endif +#ifdef CONFIG_FONT_8x16 +#undef NO_FONTS + &font_vga_8x16, +#endif +#ifdef CONFIG_FONT_6x11 +#undef NO_FONTS + &font_vga_6x11, +#endif +#ifdef CONFIG_FONT_SUN8x16 +#undef NO_FONTS + &font_sun_8x16, +#endif +#ifdef CONFIG_FONT_SUN12x22 +#undef NO_FONTS + &font_sun_12x22, +#endif +#ifdef CONFIG_FONT_ACORN_8x8 +#undef NO_FONTS + &font_acorn_8x8, +#endif +#ifdef CONFIG_FONT_PEARL_8x8 +#undef NO_FONTS + &font_pearl_8x8, +#endif +#ifdef CONFIG_FONT_MINI_4x6 +#undef NO_FONTS + &font_mini_4x6, +#endif +}; + +#define num_fonts (sizeof(fonts)/sizeof(*fonts)) + +#ifdef NO_FONTS +#error No fonts configured. +#endif + + +/** + * find_font - find a font + * @name: string name of a font + * + * Find a specified font with string name @name. + * + * Returns %NULL if no font found, or a pointer to the + * specified font. + * + */ + +struct font_desc *find_font(char *name) +{ + unsigned int i; + + for (i = 0; i < num_fonts; i++) + if (!strcmp(fonts[i]->name, name)) + return fonts[i]; + return NULL; +} + + +/** + * get_default_font - get default font + * @xres: screen size of X + * @yres: screen size of Y + * + * Get the default font for a specified screen size. + * Dimensions are in pixels. + * + * Returns %NULL if no font is found, or a pointer to the + * chosen font. + * + */ + +struct font_desc *get_default_font(int xres, int yres) +{ + int i, c, cc; + struct font_desc *f, *g; + + g = NULL; + cc = -10000; + for(i=0; i<num_fonts; i++) { + f = fonts[i]; + c = f->pref; +#if defined(__mc68000__) || defined(CONFIG_APUS) +#ifdef CONFIG_FONT_PEARL_8x8 + if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX) + c = 100; +#endif +#ifdef CONFIG_FONT_6x11 + if (MACH_IS_MAC && xres < 640 && f->idx == VGA6x11_IDX) + c = 100; +#endif +#endif + if ((yres < 400) == (f->height <= 8)) + c += 1000; + if (c > cc) { + cc = c; + g = f; + } + } + return g; +} + +EXPORT_SYMBOL(fonts); +EXPORT_SYMBOL(find_font); +EXPORT_SYMBOL(get_default_font); + +MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); +MODULE_DESCRIPTION("Console Fonts"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c new file mode 100644 index 000000000000..989e4d49e5bb --- /dev/null +++ b/drivers/video/console/mdacon.c @@ -0,0 +1,603 @@ +/* + * linux/drivers/video/mdacon.c -- Low level MDA based console driver + * + * (c) 1998 Andrew Apted <ajapted@netspace.net.au> + * + * including portions (c) 1995-1998 Patrick Caulfield. + * + * slight improvements (c) 2000 Edward Betts <edward@debian.org> + * + * This file is based on the VGA console driver (vgacon.c): + * + * Created 28 Sep 1997 by Geert Uytterhoeven + * + * Rewritten by Martin Mares <mj@ucw.cz>, July 1998 + * + * and on the old console.c, vga.c and vesa_blank.c drivers: + * + * Copyright (C) 1991, 1992 Linus Torvalds + * 1995 Jay Estabrook + * + * 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. + * + * Changelog: + * Paul G. (03/2001) Fix mdacon= boot prompt to use __setup(). + */ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/string.h> +#include <linux/kd.h> +#include <linux/slab.h> +#include <linux/vt_kern.h> +#include <linux/vt_buffer.h> +#include <linux/selection.h> +#include <linux/spinlock.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/vga.h> + +static DEFINE_SPINLOCK(mda_lock); + +/* description of the hardware layout */ + +static unsigned long mda_vram_base; /* Base of video memory */ +static unsigned long mda_vram_len; /* Size of video memory */ +static unsigned int mda_num_columns; /* Number of text columns */ +static unsigned int mda_num_lines; /* Number of text lines */ + +static unsigned int mda_index_port; /* Register select port */ +static unsigned int mda_value_port; /* Register value port */ +static unsigned int mda_mode_port; /* Mode control port */ +static unsigned int mda_status_port; /* Status and Config port */ +static unsigned int mda_gfx_port; /* Graphics control port */ + +/* current hardware state */ + +static int mda_cursor_loc=-1; +static int mda_cursor_size_from=-1; +static int mda_cursor_size_to=-1; + +static enum { TYPE_MDA, TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } mda_type; +static char *mda_type_name; + +/* console information */ + +static int mda_first_vc = 1; +static int mda_last_vc = 16; + +static struct vc_data *mda_display_fg = NULL; + +module_param(mda_first_vc, int, 0); +module_param(mda_last_vc, int, 0); + +/* MDA register values + */ + +#define MDA_CURSOR_BLINKING 0x00 +#define MDA_CURSOR_OFF 0x20 +#define MDA_CURSOR_SLOWBLINK 0x60 + +#define MDA_MODE_GRAPHICS 0x02 +#define MDA_MODE_VIDEO_EN 0x08 +#define MDA_MODE_BLINK_EN 0x20 +#define MDA_MODE_GFX_PAGE1 0x80 + +#define MDA_STATUS_HSYNC 0x01 +#define MDA_STATUS_VSYNC 0x80 +#define MDA_STATUS_VIDEO 0x08 + +#define MDA_CONFIG_COL132 0x08 +#define MDA_GFX_MODE_EN 0x01 +#define MDA_GFX_PAGE_EN 0x02 + + +/* + * MDA could easily be classified as "pre-dinosaur hardware". + */ + +static void write_mda_b(unsigned int val, unsigned char reg) +{ + unsigned long flags; + + spin_lock_irqsave(&mda_lock, flags); + + outb_p(reg, mda_index_port); + outb_p(val, mda_value_port); + + spin_unlock_irqrestore(&mda_lock, flags); +} + +static void write_mda_w(unsigned int val, unsigned char reg) +{ + unsigned long flags; + + spin_lock_irqsave(&mda_lock, flags); + + outb_p(reg, mda_index_port); outb_p(val >> 8, mda_value_port); + outb_p(reg+1, mda_index_port); outb_p(val & 0xff, mda_value_port); + + spin_unlock_irqrestore(&mda_lock, flags); +} + +#ifdef TEST_MDA_B +static int test_mda_b(unsigned char val, unsigned char reg) +{ + unsigned long flags; + + spin_lock_irqsave(&mda_lock, flags); + + outb_p(reg, mda_index_port); + outb (val, mda_value_port); + + udelay(20); val = (inb_p(mda_value_port) == val); + + spin_unlock_irqrestore(&mda_lock, flags); + return val; +} +#endif + +static inline void mda_set_cursor(unsigned int location) +{ + if (mda_cursor_loc == location) + return; + + write_mda_w(location >> 1, 0x0e); + + mda_cursor_loc = location; +} + +static inline void mda_set_cursor_size(int from, int to) +{ + if (mda_cursor_size_from==from && mda_cursor_size_to==to) + return; + + if (from > to) { + write_mda_b(MDA_CURSOR_OFF, 0x0a); /* disable cursor */ + } else { + write_mda_b(from, 0x0a); /* cursor start */ + write_mda_b(to, 0x0b); /* cursor end */ + } + + mda_cursor_size_from = from; + mda_cursor_size_to = to; +} + + +#ifndef MODULE +static int __init mdacon_setup(char *str) +{ + /* command line format: mdacon=<first>,<last> */ + + int ints[3]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + if (ints[0] < 2) + return 0; + + if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES || + ints[2] < 1 || ints[2] > MAX_NR_CONSOLES) + return 0; + + mda_first_vc = ints[1]; + mda_last_vc = ints[2]; + return 1; +} + +__setup("mdacon=", mdacon_setup); +#endif + +static int __init mda_detect(void) +{ + int count=0; + u16 *p, p_save; + u16 *q, q_save; + + /* do a memory check */ + + p = (u16 *) mda_vram_base; + q = (u16 *) (mda_vram_base + 0x01000); + + p_save = scr_readw(p); q_save = scr_readw(q); + + scr_writew(0xAA55, p); if (scr_readw(p) == 0xAA55) count++; + scr_writew(0x55AA, p); if (scr_readw(p) == 0x55AA) count++; + scr_writew(p_save, p); + + if (count != 2) { + return 0; + } + + /* check if we have 4K or 8K */ + + scr_writew(0xA55A, q); scr_writew(0x0000, p); + if (scr_readw(q) == 0xA55A) count++; + + scr_writew(0x5AA5, q); scr_writew(0x0000, p); + if (scr_readw(q) == 0x5AA5) count++; + + scr_writew(p_save, p); scr_writew(q_save, q); + + if (count == 4) { + mda_vram_len = 0x02000; + } + + /* Ok, there is definitely a card registering at the correct + * memory location, so now we do an I/O port test. + */ + +#ifdef TEST_MDA_B + /* Edward: These two mess `tests' mess up my cursor on bootup */ + + /* cursor low register */ + if (! test_mda_b(0x66, 0x0f)) { + return 0; + } + + /* cursor low register */ + if (! test_mda_b(0x99, 0x0f)) { + return 0; + } +#endif + + /* See if the card is a Hercules, by checking whether the vsync + * bit of the status register is changing. This test lasts for + * approximately 1/10th of a second. + */ + + p_save = q_save = inb_p(mda_status_port) & MDA_STATUS_VSYNC; + + for (count=0; count < 50000 && p_save == q_save; count++) { + q_save = inb(mda_status_port) & MDA_STATUS_VSYNC; + udelay(2); + } + + if (p_save != q_save) { + switch (inb_p(mda_status_port) & 0x70) { + case 0x10: + mda_type = TYPE_HERCPLUS; + mda_type_name = "HerculesPlus"; + break; + case 0x50: + mda_type = TYPE_HERCCOLOR; + mda_type_name = "HerculesColor"; + break; + default: + mda_type = TYPE_HERC; + mda_type_name = "Hercules"; + break; + } + } + + return 1; +} + +static void __init mda_initialize(void) +{ + write_mda_b(97, 0x00); /* horizontal total */ + write_mda_b(80, 0x01); /* horizontal displayed */ + write_mda_b(82, 0x02); /* horizontal sync pos */ + write_mda_b(15, 0x03); /* horizontal sync width */ + + write_mda_b(25, 0x04); /* vertical total */ + write_mda_b(6, 0x05); /* vertical total adjust */ + write_mda_b(25, 0x06); /* vertical displayed */ + write_mda_b(25, 0x07); /* vertical sync pos */ + + write_mda_b(2, 0x08); /* interlace mode */ + write_mda_b(13, 0x09); /* maximum scanline */ + write_mda_b(12, 0x0a); /* cursor start */ + write_mda_b(13, 0x0b); /* cursor end */ + + write_mda_w(0x0000, 0x0c); /* start address */ + write_mda_w(0x0000, 0x0e); /* cursor location */ + + outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port); + outb_p(0x00, mda_status_port); + outb_p(0x00, mda_gfx_port); +} + +static const char __init *mdacon_startup(void) +{ + mda_num_columns = 80; + mda_num_lines = 25; + + mda_vram_base = VGA_MAP_MEM(0xb0000); + mda_vram_len = 0x01000; + + mda_index_port = 0x3b4; + mda_value_port = 0x3b5; + mda_mode_port = 0x3b8; + mda_status_port = 0x3ba; + mda_gfx_port = 0x3bf; + + mda_type = TYPE_MDA; + mda_type_name = "MDA"; + + if (! mda_detect()) { + printk("mdacon: MDA card not detected.\n"); + return NULL; + } + + if (mda_type != TYPE_MDA) { + mda_initialize(); + } + + /* cursor looks ugly during boot-up, so turn it off */ + mda_set_cursor(mda_vram_len - 1); + + printk("mdacon: %s with %ldK of memory detected.\n", + mda_type_name, mda_vram_len/1024); + + return "MDA-2"; +} + +static void mdacon_init(struct vc_data *c, int init) +{ + c->vc_complement_mask = 0x0800; /* reverse video */ + c->vc_display_fg = &mda_display_fg; + + if (init) { + c->vc_cols = mda_num_columns; + c->vc_rows = mda_num_lines; + } else + vc_resize(c, mda_num_columns, mda_num_lines); + + /* make the first MDA console visible */ + + if (mda_display_fg == NULL) + mda_display_fg = c; +} + +static void mdacon_deinit(struct vc_data *c) +{ + /* con_set_default_unimap(c->vc_num); */ + + if (mda_display_fg == c) + mda_display_fg = NULL; +} + +static inline u16 mda_convert_attr(u16 ch) +{ + u16 attr = 0x0700; + + /* Underline and reverse-video are mutually exclusive on MDA. + * Since reverse-video is used for cursors and selected areas, + * it takes precedence. + */ + + if (ch & 0x0800) attr = 0x7000; /* reverse */ + else if (ch & 0x0400) attr = 0x0100; /* underline */ + + return ((ch & 0x0200) << 2) | /* intensity */ + (ch & 0x8000) | /* blink */ + (ch & 0x00ff) | attr; +} + +static u8 mdacon_build_attr(struct vc_data *c, u8 color, u8 intensity, + u8 blink, u8 underline, u8 reverse) +{ + /* The attribute is just a bit vector: + * + * Bit 0..1 : intensity (0..2) + * Bit 2 : underline + * Bit 3 : reverse + * Bit 7 : blink + */ + + return (intensity & 3) | + ((underline & 1) << 2) | + ((reverse & 1) << 3) | + ((blink & 1) << 7); +} + +static void mdacon_invert_region(struct vc_data *c, u16 *p, int count) +{ + for (; count > 0; count--) { + scr_writew(scr_readw(p) ^ 0x0800, p); + p++; + } +} + +#define MDA_ADDR(x,y) ((u16 *) mda_vram_base + (y)*mda_num_columns + (x)) + +static void mdacon_putc(struct vc_data *c, int ch, int y, int x) +{ + scr_writew(mda_convert_attr(ch), MDA_ADDR(x, y)); +} + +static void mdacon_putcs(struct vc_data *c, const unsigned short *s, + int count, int y, int x) +{ + u16 *dest = MDA_ADDR(x, y); + + for (; count > 0; count--) { + scr_writew(mda_convert_attr(scr_readw(s++)), dest++); + } +} + +static void mdacon_clear(struct vc_data *c, int y, int x, + int height, int width) +{ + u16 *dest = MDA_ADDR(x, y); + u16 eattr = mda_convert_attr(c->vc_video_erase_char); + + if (width <= 0 || height <= 0) + return; + + if (x==0 && width==mda_num_columns) { + scr_memsetw(dest, eattr, height*width*2); + } else { + for (; height > 0; height--, dest+=mda_num_columns) + scr_memsetw(dest, eattr, width*2); + } +} + +static void mdacon_bmove(struct vc_data *c, int sy, int sx, + int dy, int dx, int height, int width) +{ + u16 *src, *dest; + + if (width <= 0 || height <= 0) + return; + + if (sx==0 && dx==0 && width==mda_num_columns) { + scr_memmovew(MDA_ADDR(0,dy), MDA_ADDR(0,sy), height*width*2); + + } else if (dy < sy || (dy == sy && dx < sx)) { + src = MDA_ADDR(sx, sy); + dest = MDA_ADDR(dx, dy); + + for (; height > 0; height--) { + scr_memmovew(dest, src, width*2); + src += mda_num_columns; + dest += mda_num_columns; + } + } else { + src = MDA_ADDR(sx, sy+height-1); + dest = MDA_ADDR(dx, dy+height-1); + + for (; height > 0; height--) { + scr_memmovew(dest, src, width*2); + src -= mda_num_columns; + dest -= mda_num_columns; + } + } +} + +static int mdacon_switch(struct vc_data *c) +{ + return 1; /* redrawing needed */ +} + +static int mdacon_set_palette(struct vc_data *c, unsigned char *table) +{ + return -EINVAL; +} + +static int mdacon_blank(struct vc_data *c, int blank, int mode_switch) +{ + if (mda_type == TYPE_MDA) { + if (blank) + scr_memsetw((void *)mda_vram_base, + mda_convert_attr(c->vc_video_erase_char), + c->vc_screenbuf_size); + /* Tell console.c that it has to restore the screen itself */ + return 1; + } else { + if (blank) + outb_p(0x00, mda_mode_port); /* disable video */ + else + outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, + mda_mode_port); + return 0; + } +} + +static int mdacon_scrolldelta(struct vc_data *c, int lines) +{ + return 0; +} + +static void mdacon_cursor(struct vc_data *c, int mode) +{ + if (mode == CM_ERASE) { + mda_set_cursor(mda_vram_len - 1); + return; + } + + mda_set_cursor(c->vc_y*mda_num_columns*2 + c->vc_x*2); + + switch (c->vc_cursor_type & 0x0f) { + + case CUR_LOWER_THIRD: mda_set_cursor_size(10, 13); break; + case CUR_LOWER_HALF: mda_set_cursor_size(7, 13); break; + case CUR_TWO_THIRDS: mda_set_cursor_size(4, 13); break; + case CUR_BLOCK: mda_set_cursor_size(1, 13); break; + case CUR_NONE: mda_set_cursor_size(14, 13); break; + default: mda_set_cursor_size(12, 13); break; + } +} + +static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) +{ + u16 eattr = mda_convert_attr(c->vc_video_erase_char); + + if (!lines) + return 0; + + if (lines > c->vc_rows) /* maximum realistic size */ + lines = c->vc_rows; + + switch (dir) { + + case SM_UP: + scr_memmovew(MDA_ADDR(0,t), MDA_ADDR(0,t+lines), + (b-t-lines)*mda_num_columns*2); + scr_memsetw(MDA_ADDR(0,b-lines), eattr, + lines*mda_num_columns*2); + break; + + case SM_DOWN: + scr_memmovew(MDA_ADDR(0,t+lines), MDA_ADDR(0,t), + (b-t-lines)*mda_num_columns*2); + scr_memsetw(MDA_ADDR(0,t), eattr, lines*mda_num_columns*2); + break; + } + + return 0; +} + + +/* + * The console `switch' structure for the MDA based console + */ + +static const struct consw mda_con = { + .owner = THIS_MODULE, + .con_startup = mdacon_startup, + .con_init = mdacon_init, + .con_deinit = mdacon_deinit, + .con_clear = mdacon_clear, + .con_putc = mdacon_putc, + .con_putcs = mdacon_putcs, + .con_cursor = mdacon_cursor, + .con_scroll = mdacon_scroll, + .con_bmove = mdacon_bmove, + .con_switch = mdacon_switch, + .con_blank = mdacon_blank, + .con_set_palette = mdacon_set_palette, + .con_scrolldelta = mdacon_scrolldelta, + .con_build_attr = mdacon_build_attr, + .con_invert_region = mdacon_invert_region, +}; + +int __init mda_console_init(void) +{ + if (mda_first_vc > mda_last_vc) + return 1; + + return take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0); +} + +static void __exit mda_console_exit(void) +{ + give_up_console(&mda_con); +} + +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 new file mode 100644 index 000000000000..e793ffd39db5 --- /dev/null +++ b/drivers/video/console/newport_con.c @@ -0,0 +1,745 @@ +/* + * newport_con.c: Abscon for newport hardware + * + * (C) 1998 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * (C) 1999 Ulf Carlsson (ulfc@thepuffingruop.com) + * + * This driver is based on sgicons.c and cons_newport. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx) + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/tty.h> +#include <linux/kd.h> +#include <linux/selection.h> +#include <linux/console.h> +#include <linux/vt_kern.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <video/newport.h> + +#include <linux/linux_logo.h> +#include <linux/font.h> + + +extern struct font_desc font_vga_8x16; +extern unsigned long sgi_gfxaddr; + +#define FONT_DATA ((unsigned char *)font_vga_8x16.data) + +/* borrowed from fbcon.c */ +#define REFCOUNT(fd) (((int *)(fd))[-1]) +#define FNTSIZE(fd) (((int *)(fd))[-2]) +#define FNTCHARCNT(fd) (((int *)(fd))[-3]) +#define FONT_EXTRA_WORDS 3 + +static unsigned char *font_data[MAX_NR_CONSOLES]; + +static struct newport_regs *npregs; + +static int logo_active; +static int topscan; +static int xcurs_correction = 29; +static int newport_xsize; +static int newport_ysize; + +static int newport_set_def_font(int unit, struct console_font *op); + +#define BMASK(c) (c << 24) + +#define RENDER(regs, cp) do { \ +(regs)->go.zpattern = BMASK((cp)[0x0]); (regs)->go.zpattern = BMASK((cp)[0x1]); \ +(regs)->go.zpattern = BMASK((cp)[0x2]); (regs)->go.zpattern = BMASK((cp)[0x3]); \ +(regs)->go.zpattern = BMASK((cp)[0x4]); (regs)->go.zpattern = BMASK((cp)[0x5]); \ +(regs)->go.zpattern = BMASK((cp)[0x6]); (regs)->go.zpattern = BMASK((cp)[0x7]); \ +(regs)->go.zpattern = BMASK((cp)[0x8]); (regs)->go.zpattern = BMASK((cp)[0x9]); \ +(regs)->go.zpattern = BMASK((cp)[0xa]); (regs)->go.zpattern = BMASK((cp)[0xb]); \ +(regs)->go.zpattern = BMASK((cp)[0xc]); (regs)->go.zpattern = BMASK((cp)[0xd]); \ +(regs)->go.zpattern = BMASK((cp)[0xe]); (regs)->go.zpattern = BMASK((cp)[0xf]); \ +} while(0) + +#define TESTVAL 0xdeadbeef +#define XSTI_TO_FXSTART(val) (((val) & 0xffff) << 11) + +static inline void newport_render_background(int xstart, int ystart, + int xend, int yend, int ci) +{ + newport_wait(npregs); + npregs->set.wrmask = 0xffffffff; + npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | + NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX + | NPORT_DMODE0_STOPY); + npregs->set.colori = ci; + npregs->set.xystarti = + (xstart << 16) | ((ystart + topscan) & 0x3ff); + npregs->go.xyendi = + ((xend + 7) << 16) | ((yend + topscan + 15) & 0x3ff); +} + +static inline void newport_init_cmap(void) +{ + unsigned short i; + + for (i = 0; i < 16; i++) { + newport_bfwait(npregs); + newport_cmap_setaddr(npregs, color_table[i]); + newport_cmap_setrgb(npregs, + default_red[i], + default_grn[i], default_blu[i]); + } +} + +static void newport_show_logo(void) +{ +#ifdef CONFIG_LOGO_SGI_CLUT224 + const struct linux_logo *logo = fb_find_logo(8); + const unsigned char *clut = logo->clut; + const unsigned char *data = logo->data; + unsigned long i; + + for (i = 0; i < logo->clutsize; i++) { + newport_bfwait(npregs); + newport_cmap_setaddr(npregs, i + 0x20); + newport_cmap_setrgb(npregs, clut[0], clut[1], clut[2]); + clut += 3; + } + + newport_wait(npregs); + npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | + NPORT_DMODE0_CHOST); + + npregs->set.xystarti = ((newport_xsize - logo->width) << 16) | (0); + npregs->set.xyendi = ((newport_xsize - 1) << 16); + newport_wait(npregs); + + for (i = 0; i < logo->width*logo->height; i++) + npregs->go.hostrw0 = *data++ << 24; +#endif /* CONFIG_LOGO_SGI_CLUT224 */ +} + +static inline void newport_clear_screen(int xstart, int ystart, int xend, + int yend, int ci) +{ + if (logo_active) + return; + + newport_wait(npregs); + npregs->set.wrmask = 0xffffffff; + npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | + NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX + | NPORT_DMODE0_STOPY); + npregs->set.colori = ci; + npregs->set.xystarti = (xstart << 16) | ystart; + npregs->go.xyendi = (xend << 16) | yend; +} + +static inline void newport_clear_lines(int ystart, int yend, int ci) +{ + ystart = ((ystart << 4) + topscan) & 0x3ff; + yend = ((yend << 4) + topscan + 15) & 0x3ff; + newport_clear_screen(0, ystart, 1280 + 63, yend, ci); +} + +void newport_reset(void) +{ + unsigned short treg; + int i; + + newport_wait(npregs); + treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); + newport_vc2_set(npregs, VC2_IREG_CONTROL, + (treg | VC2_CTRL_EVIDEO)); + + treg = newport_vc2_get(npregs, VC2_IREG_CENTRY); + newport_vc2_set(npregs, VC2_IREG_RADDR, treg); + npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM | + NPORT_DMODE_W2 | VC2_PROTOCOL); + for (i = 0; i < 128; i++) { + newport_bfwait(npregs); + if (i == 92 || i == 94) + npregs->set.dcbdata0.byshort.s1 = 0xff00; + else + npregs->set.dcbdata0.byshort.s1 = 0x0000; + } + + newport_init_cmap(); + + /* turn off popup plane */ + npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL | + XM9_CRS_CONFIG | NPORT_DMODE_W1); + npregs->set.dcbdata0.bybytes.b3 &= ~XM9_PUPMODE; + npregs->set.dcbmode = (DCB_XMAP1 | R_DCB_XMAP9_PROTOCOL | + XM9_CRS_CONFIG | NPORT_DMODE_W1); + npregs->set.dcbdata0.bybytes.b3 &= ~XM9_PUPMODE; + + topscan = 0; + npregs->cset.topscan = 0x3ff; + npregs->cset.xywin = (4096 << 16) | 4096; + + /* Clear the screen. */ + newport_clear_screen(0, 0, 1280 + 63, 1024, 0); +} + +/* + * calculate the actual screen size by reading + * the video timing out of the VC2 + */ +void newport_get_screensize(void) +{ + int i, cols; + unsigned short ventry, treg; + unsigned short linetable[128]; /* should be enough */ + + ventry = newport_vc2_get(npregs, VC2_IREG_VENTRY); + newport_vc2_set(npregs, VC2_IREG_RADDR, ventry); + npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM | + NPORT_DMODE_W2 | VC2_PROTOCOL); + for (i = 0; i < 128; i++) { + newport_bfwait(npregs); + linetable[i] = npregs->set.dcbdata0.byshort.s1; + } + + newport_xsize = newport_ysize = 0; + for (i = 0; linetable[i + 1] && (i < sizeof(linetable)); i += 2) { + cols = 0; + newport_vc2_set(npregs, VC2_IREG_RADDR, linetable[i]); + npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM | + NPORT_DMODE_W2 | VC2_PROTOCOL); + do { + newport_bfwait(npregs); + treg = npregs->set.dcbdata0.byshort.s1; + if ((treg & 1) == 0) + cols += (treg >> 7) & 0xfe; + if ((treg & 0x80) == 0) { + newport_bfwait(npregs); + treg = npregs->set.dcbdata0.byshort.s1; + } + } while ((treg & 0x8000) == 0); + if (cols) { + if (cols > newport_xsize) + newport_xsize = cols; + newport_ysize += linetable[i + 1]; + } + } + printk("NG1: Screensize %dx%d\n", newport_xsize, newport_ysize); +} + +static void newport_get_revisions(void) +{ + unsigned int tmp; + unsigned int board_rev; + unsigned int rex3_rev; + unsigned int vc2_rev; + unsigned int cmap_rev; + unsigned int xmap9_rev; + unsigned int bt445_rev; + unsigned int bitplanes; + + rex3_rev = npregs->cset.status & NPORT_STAT_VERS; + + npregs->set.dcbmode = (DCB_CMAP0 | NCMAP_PROTOCOL | + NCMAP_REGADDR_RREG | NPORT_DMODE_W1); + tmp = npregs->set.dcbdata0.bybytes.b3; + cmap_rev = tmp & 7; + board_rev = (tmp >> 4) & 7; + bitplanes = ((board_rev > 1) && (tmp & 0x80)) ? 8 : 24; + + npregs->set.dcbmode = (DCB_CMAP1 | NCMAP_PROTOCOL | + NCMAP_REGADDR_RREG | NPORT_DMODE_W1); + tmp = npregs->set.dcbdata0.bybytes.b3; + if ((tmp & 7) < cmap_rev) + cmap_rev = (tmp & 7); + + vc2_rev = (newport_vc2_get(npregs, VC2_IREG_CONFIG) >> 5) & 7; + + npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL | + XM9_CRS_REVISION | NPORT_DMODE_W1); + xmap9_rev = npregs->set.dcbdata0.bybytes.b3 & 7; + + npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL | + BT445_CSR_ADDR_REG | NPORT_DMODE_W1); + npregs->set.dcbdata0.bybytes.b3 = BT445_REVISION_REG; + npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL | + BT445_CSR_REVISION | NPORT_DMODE_W1); + bt445_rev = (npregs->set.dcbdata0.bybytes.b3 >> 4) - 0x0a; + +#define L(a) (char)('A'+(a)) + printk + ("NG1: Revision %d, %d bitplanes, REX3 revision %c, VC2 revision %c, xmap9 revision %c, cmap revision %c, bt445 revision %c\n", + board_rev, bitplanes, L(rex3_rev), L(vc2_rev), L(xmap9_rev), + L(cmap_rev ? (cmap_rev + 1) : 0), L(bt445_rev)); +#undef L + + if (board_rev == 3) /* I don't know all affected revisions */ + xcurs_correction = 21; +} + +/* Can't be __init, take_over_console may call it later */ +static const char *newport_startup(void) +{ + int i; + + if (!sgi_gfxaddr) + return NULL; + npregs = (struct newport_regs *) /* ioremap cannot fail */ + ioremap(sgi_gfxaddr, sizeof(struct newport_regs)); + npregs->cset.config = NPORT_CFG_GD0; + + if (newport_wait(npregs)) + goto out_unmap; + + npregs->set.xstarti = TESTVAL; + if (npregs->set._xstart.word != XSTI_TO_FXSTART(TESTVAL)) + goto out_unmap; + + for (i = 0; i < MAX_NR_CONSOLES; i++) + font_data[i] = FONT_DATA; + + newport_reset(); + newport_get_revisions(); + newport_get_screensize(); + + return "SGI Newport"; + +out_unmap: + iounmap((void *)npregs); + return NULL; +} + +static void newport_init(struct vc_data *vc, int init) +{ + vc->vc_cols = newport_xsize / 8; + vc->vc_rows = newport_ysize / 16; + vc->vc_can_do_color = 1; +} + +static void newport_deinit(struct vc_data *c) +{ + int i; + + /* free memory used by user font */ + for (i = 0; i < MAX_NR_CONSOLES; i++) + newport_set_def_font(i, NULL); +} + +static void newport_clear(struct vc_data *vc, int sy, int sx, int height, + int width) +{ + int xend = ((sx + width) << 3) - 1; + int ystart = ((sy << 4) + topscan) & 0x3ff; + int yend = (((sy + height) << 4) + topscan - 1) & 0x3ff; + + if (logo_active) + return; + + if (ystart < yend) { + newport_clear_screen(sx << 3, ystart, xend, yend, + (vc->vc_color & 0xf0) >> 4); + } else { + newport_clear_screen(sx << 3, ystart, xend, 1023, + (vc->vc_color & 0xf0) >> 4); + newport_clear_screen(sx << 3, 0, xend, yend, + (vc->vc_color & 0xf0) >> 4); + } +} + +static void newport_putc(struct vc_data *vc, int charattr, int ypos, + int xpos) +{ + unsigned char *p; + + p = &font_data[vc->vc_num][(charattr & 0xff) << 4]; + charattr = (charattr >> 8) & 0xff; + xpos <<= 3; + ypos <<= 4; + + newport_render_background(xpos, ypos, xpos, ypos, + (charattr & 0xf0) >> 4); + + /* Set the color and drawing mode. */ + newport_wait(npregs); + npregs->set.colori = charattr & 0xf; + npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | + NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB | + NPORT_DMODE0_L32); + + /* Set coordinates for bitmap operation. */ + npregs->set.xystarti = (xpos << 16) | ((ypos + topscan) & 0x3ff); + npregs->set.xyendi = ((xpos + 7) << 16); + newport_wait(npregs); + + /* Go, baby, go... */ + RENDER(npregs, p); +} + +static void newport_putcs(struct vc_data *vc, const unsigned short *s, + int count, int ypos, int xpos) +{ + int i; + int charattr; + unsigned char *p; + + charattr = (scr_readw(s) >> 8) & 0xff; + + xpos <<= 3; + ypos <<= 4; + + if (!logo_active) + /* Clear the area behing the string */ + newport_render_background(xpos, ypos, + xpos + ((count - 1) << 3), ypos, + (charattr & 0xf0) >> 4); + + newport_wait(npregs); + + /* Set the color and drawing mode. */ + npregs->set.colori = charattr & 0xf; + npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | + NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB | + NPORT_DMODE0_L32); + + for (i = 0; i < count; i++, xpos += 8) { + p = &font_data[vc->vc_num][(scr_readw(s++) & 0xff) << 4]; + + newport_wait(npregs); + + /* Set coordinates for bitmap operation. */ + npregs->set.xystarti = + (xpos << 16) | ((ypos + topscan) & 0x3ff); + npregs->set.xyendi = ((xpos + 7) << 16); + + /* Go, baby, go... */ + RENDER(npregs, p); + } +} + +static void newport_cursor(struct vc_data *vc, int mode) +{ + unsigned short treg; + int xcurs, ycurs; + + switch (mode) { + case CM_ERASE: + treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); + newport_vc2_set(npregs, VC2_IREG_CONTROL, + (treg & ~(VC2_CTRL_ECDISP))); + break; + + case CM_MOVE: + case CM_DRAW: + treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); + newport_vc2_set(npregs, VC2_IREG_CONTROL, + (treg | VC2_CTRL_ECDISP)); + xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2; + ycurs = ((xcurs / vc->vc_cols) << 4) + 31; + xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction; + newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs); + newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs); + } +} + +static int newport_switch(struct vc_data *vc) +{ + static int logo_drawn = 0; + + topscan = 0; + npregs->cset.topscan = 0x3ff; + + if (!logo_drawn) { + newport_show_logo(); + logo_drawn = 1; + logo_active = 1; + } + + return 1; +} + +static int newport_blank(struct vc_data *c, int blank, int mode_switch) +{ + unsigned short treg; + + if (blank == 0) { + /* unblank console */ + treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); + newport_vc2_set(npregs, VC2_IREG_CONTROL, + (treg | VC2_CTRL_EDISP)); + } else { + /* blank console */ + treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); + newport_vc2_set(npregs, VC2_IREG_CONTROL, + (treg & ~(VC2_CTRL_EDISP))); + } + return 1; +} + +static int newport_set_font(int unit, struct console_font *op) +{ + int w = op->width; + int h = op->height; + int size = h * op->charcount; + int i; + unsigned char *new_data, *data = op->data, *p; + + /* ladis: when I grow up, there will be a day... and more sizes will + * be supported ;-) */ + if ((w != 8) || (h != 16) + || (op->charcount != 256 && op->charcount != 512)) + return -EINVAL; + + if (!(new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, + GFP_USER))) return -ENOMEM; + + new_data += FONT_EXTRA_WORDS * sizeof(int); + FNTSIZE(new_data) = size; + FNTCHARCNT(new_data) = op->charcount; + REFCOUNT(new_data) = 0; /* usage counter */ + + p = new_data; + for (i = 0; i < op->charcount; i++) { + memcpy(p, data, h); + data += 32; + p += h; + } + + /* check if font is already used by other console */ + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (font_data[i] != FONT_DATA + && FNTSIZE(font_data[i]) == size + && !memcmp(font_data[i], new_data, size)) { + kfree(new_data - FONT_EXTRA_WORDS * sizeof(int)); + /* current font is the same as the new one */ + if (i == unit) + return 0; + new_data = font_data[i]; + break; + } + } + /* old font is user font */ + if (font_data[unit] != FONT_DATA) { + if (--REFCOUNT(font_data[unit]) == 0) + kfree(font_data[unit] - + FONT_EXTRA_WORDS * sizeof(int)); + } + REFCOUNT(new_data)++; + font_data[unit] = new_data; + + return 0; +} + +static int newport_set_def_font(int unit, struct console_font *op) +{ + if (font_data[unit] != FONT_DATA) { + if (--REFCOUNT(font_data[unit]) == 0) + kfree(font_data[unit] - + FONT_EXTRA_WORDS * sizeof(int)); + font_data[unit] = FONT_DATA; + } + + return 0; +} + +static int newport_font_default(struct vc_data *vc, struct console_font *op, char *name) +{ + return newport_set_def_font(vc->vc_num, op); +} + +static int newport_font_set(struct vc_data *vc, struct console_font *font, unsigned flags) +{ + return newport_set_font(vc->vc_num, font); +} + +static int newport_set_palette(struct vc_data *vc, unsigned char *table) +{ + return -EINVAL; +} + +static int newport_scrolldelta(struct vc_data *vc, int lines) +{ + /* there is (nearly) no off-screen memory, so we can't scroll back */ + return 0; +} + +static int newport_scroll(struct vc_data *vc, int t, int b, int dir, + int lines) +{ + int count, x, y; + unsigned short *s, *d; + unsigned short chattr; + + logo_active = 0; /* it's time to disable the logo now.. */ + + if (t == 0 && b == vc->vc_rows) { + if (dir == SM_UP) { + topscan = (topscan + (lines << 4)) & 0x3ff; + newport_clear_lines(vc->vc_rows - lines, + vc->vc_rows - 1, + (vc->vc_color & 0xf0) >> 4); + } else { + topscan = (topscan + (-lines << 4)) & 0x3ff; + newport_clear_lines(0, lines - 1, + (vc->vc_color & 0xf0) >> 4); + } + npregs->cset.topscan = (topscan - 1) & 0x3ff; + return 0; + } + + count = (b - t - lines) * vc->vc_cols; + if (dir == SM_UP) { + x = 0; + y = t; + s = (unsigned short *) (vc->vc_origin + + vc->vc_size_row * (t + lines)); + d = (unsigned short *) (vc->vc_origin + + vc->vc_size_row * t); + while (count--) { + chattr = scr_readw(s++); + if (chattr != scr_readw(d)) { + newport_putc(vc, chattr, y, x); + scr_writew(chattr, d); + } + d++; + if (++x == vc->vc_cols) { + x = 0; + y++; + } + } + d = (unsigned short *) (vc->vc_origin + + vc->vc_size_row * (b - lines)); + x = 0; + y = b - lines; + for (count = 0; count < (lines * vc->vc_cols); count++) { + if (scr_readw(d) != vc->vc_video_erase_char) { + newport_putc(vc, vc->vc_video_erase_char, + y, x); + scr_writew(vc->vc_video_erase_char, d); + } + d++; + if (++x == vc->vc_cols) { + x = 0; + y++; + } + } + } else { + x = vc->vc_cols - 1; + y = b - 1; + s = (unsigned short *) (vc->vc_origin + + vc->vc_size_row * (b - lines) - 2); + d = (unsigned short *) (vc->vc_origin + + vc->vc_size_row * b - 2); + while (count--) { + chattr = scr_readw(s--); + if (chattr != scr_readw(d)) { + newport_putc(vc, chattr, y, x); + scr_writew(chattr, d); + } + d--; + if (x-- == 0) { + x = vc->vc_cols - 1; + y--; + } + } + d = (unsigned short *) (vc->vc_origin + + vc->vc_size_row * t); + x = 0; + y = t; + for (count = 0; count < (lines * vc->vc_cols); count++) { + if (scr_readw(d) != vc->vc_video_erase_char) { + newport_putc(vc, vc->vc_video_erase_char, + y, x); + scr_writew(vc->vc_video_erase_char, d); + } + d++; + if (++x == vc->vc_cols) { + x = 0; + y++; + } + } + } + return 1; +} + +static void newport_bmove(struct vc_data *vc, int sy, int sx, int dy, + int dx, int h, int w) +{ + short xs, ys, xe, ye, xoffs, yoffs, tmp; + + xs = sx << 3; + xe = ((sx + w) << 3) - 1; + /* + * as bmove is only used to move stuff around in the same line + * (h == 1), we don't care about wrap arounds caused by topscan != 0 + */ + ys = ((sy << 4) + topscan) & 0x3ff; + ye = (((sy + h) << 4) - 1 + topscan) & 0x3ff; + xoffs = (dx - sx) << 3; + yoffs = (dy - sy) << 4; + if (xoffs > 0) { + /* move to the right, exchange starting points */ + tmp = xe; + xe = xs; + xs = tmp; + } + newport_wait(npregs); + npregs->set.drawmode0 = (NPORT_DMODE0_S2S | NPORT_DMODE0_BLOCK | + NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX + | NPORT_DMODE0_STOPY); + npregs->set.xystarti = (xs << 16) | ys; + npregs->set.xyendi = (xe << 16) | ye; + npregs->go.xymove = (xoffs << 16) | yoffs; +} + +static int newport_dummy(struct vc_data *c) +{ + return 0; +} + +#define DUMMY (void *) newport_dummy + +const struct consw newport_con = { + .owner = THIS_MODULE, + .con_startup = newport_startup, + .con_init = newport_init, + .con_deinit = newport_deinit, + .con_clear = newport_clear, + .con_putc = newport_putc, + .con_putcs = newport_putcs, + .con_cursor = newport_cursor, + .con_scroll = newport_scroll, + .con_bmove = newport_bmove, + .con_switch = newport_switch, + .con_blank = newport_blank, + .con_font_set = newport_font_set, + .con_font_default = newport_font_default, + .con_set_palette = newport_set_palette, + .con_scrolldelta = newport_scrolldelta, + .con_set_origin = DUMMY, + .con_save_screen = DUMMY +}; + +#ifdef MODULE +static int __init newport_console_init(void) +{ + return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1); +} + +static void __exit newport_console_exit(void) +{ + give_up_console(&newport_con); + iounmap((void *)npregs); +} + +module_init(newport_console_init); +module_exit(newport_console_exit); +#endif + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/prom.uni b/drivers/video/console/prom.uni new file mode 100644 index 000000000000..58f9c04ed9d3 --- /dev/null +++ b/drivers/video/console/prom.uni @@ -0,0 +1,11 @@ +# +# Unicode mapping table for font in Sun PROM +# +# +0x20-0x7e idem +0xa0-0xff idem +# +0x7c U+2502 +0x2d U+2500 +0x2b U+250c U+2510 U+2514 U+2518 U+251c U+2524 U+252c U+2534 U+253c +0xa4 U+fffd diff --git a/drivers/video/console/promcon.c b/drivers/video/console/promcon.c new file mode 100644 index 000000000000..04f42fcaac59 --- /dev/null +++ b/drivers/video/console/promcon.c @@ -0,0 +1,599 @@ +/* $Id: promcon.c,v 1.17 2000/07/26 23:02:52 davem Exp $ + * Console driver utilizing PROM sun terminal emulation + * + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#include <linux/config.h> +#include <linux/module.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/delay.h> +#include <linux/console.h> +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/kd.h> + +#include <asm/oplib.h> +#include <asm/uaccess.h> + +static short pw = 80 - 1, ph = 34 - 1; +static short px, py; +static unsigned long promcon_uni_pagedir[2]; + +extern u8 promfont_unicount[]; +extern u16 promfont_unitable[]; + +#define PROMCON_COLOR 0 + +#if PROMCON_COLOR +#define inverted(s) ((((s) & 0x7700) == 0x0700) ? 0 : 1) +#else +#define inverted(s) (((s) & 0x0800) ? 1 : 0) +#endif + +static __inline__ void +promcon_puts(char *buf, int cnt) +{ + prom_printf("%*.*s", cnt, cnt, buf); +} + +static int +promcon_start(struct vc_data *conp, char *b) +{ + unsigned short *s = (unsigned short *) + (conp->vc_origin + py * conp->vc_size_row + (px << 1)); + u16 cs; + + cs = scr_readw(s); + if (px == pw) { + unsigned short *t = s - 1; + u16 ct = scr_readw(t); + + if (inverted(cs) && inverted(ct)) + return sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs, + ct); + else if (inverted(cs)) + return sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs, + ct); + else if (inverted(ct)) + return sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs, + ct); + else + return sprintf(b, "\b%c\b\033[@%c", cs, ct); + } + + if (inverted(cs)) + return sprintf(b, "\033[7m%c\033[m\b", cs); + else + return sprintf(b, "%c\b", cs); +} + +static int +promcon_end(struct vc_data *conp, char *b) +{ + unsigned short *s = (unsigned short *) + (conp->vc_origin + py * conp->vc_size_row + (px << 1)); + char *p = b; + u16 cs; + + b += sprintf(b, "\033[%d;%dH", py + 1, px + 1); + + cs = scr_readw(s); + if (px == pw) { + unsigned short *t = s - 1; + u16 ct = scr_readw(t); + + if (inverted(cs) && inverted(ct)) + b += sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs, ct); + else if (inverted(cs)) + b += sprintf(b, "\b%c\b\033[@%c", cs, ct); + else if (inverted(ct)) + b += sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs, ct); + else + b += sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs, ct); + return b - p; + } + + if (inverted(cs)) + b += sprintf(b, "%c\b", cs); + else + b += sprintf(b, "\033[7m%c\033[m\b", cs); + return b - p; +} + +const char __init *promcon_startup(void) +{ + const char *display_desc = "PROM"; + int node; + char buf[40]; + + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "options"); + if (prom_getproperty(node, "screen-#columns", buf, 40) != -1) { + pw = simple_strtoul(buf, NULL, 0); + if (pw < 10 || pw > 256) + pw = 80; + pw--; + } + if (prom_getproperty(node, "screen-#rows", buf, 40) != -1) { + ph = simple_strtoul(buf, NULL, 0); + if (ph < 10 || ph > 256) + ph = 34; + ph--; + } + promcon_puts("\033[H\033[J", 6); + return display_desc; +} + +static void __init +promcon_init_unimap(struct vc_data *conp) +{ + mm_segment_t old_fs = get_fs(); + struct unipair *p, *p1; + u16 *q; + int i, j, k; + + p = kmalloc(256*sizeof(struct unipair), GFP_KERNEL); + if (!p) return; + + q = promfont_unitable; + p1 = p; + k = 0; + for (i = 0; i < 256; i++) + for (j = promfont_unicount[i]; j; j--) { + p1->unicode = *q++; + p1->fontpos = i; + p1++; + k++; + } + set_fs(KERNEL_DS); + con_clear_unimap(conp, NULL); + con_set_unimap(conp, k, p); + con_protect_unimap(conp, 1); + set_fs(old_fs); + kfree(p); +} + +static void +promcon_init(struct vc_data *conp, int init) +{ + unsigned long p; + + conp->vc_can_do_color = PROMCON_COLOR; + if (init) { + conp->vc_cols = pw + 1; + conp->vc_rows = ph + 1; + } + p = *conp->vc_uni_pagedir_loc; + if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir || + !--conp->vc_uni_pagedir_loc[1]) + con_free_unimap(conp); + conp->vc_uni_pagedir_loc = promcon_uni_pagedir; + promcon_uni_pagedir[1]++; + if (!promcon_uni_pagedir[0] && p) { + promcon_init_unimap(conp); + } + if (!init) { + if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1) + vc_resize(conp, pw + 1, ph + 1); + } +} + +static void +promcon_deinit(struct vc_data *conp) +{ + /* When closing the last console, reset video origin */ + if (!--promcon_uni_pagedir[1]) + con_free_unimap(conp); + conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir; + con_set_default_unimap(conp); +} + +static int +promcon_switch(struct vc_data *conp) +{ + return 1; +} + +static unsigned short * +promcon_repaint_line(unsigned short *s, unsigned char *buf, unsigned char **bp) +{ + int cnt = pw + 1; + int attr = -1; + unsigned char *b = *bp; + + while (cnt--) { + u16 c = scr_readw(s); + if (attr != inverted(c)) { + attr = inverted(c); + if (attr) { + strcpy (b, "\033[7m"); + b += 4; + } else { + strcpy (b, "\033[m"); + b += 3; + } + } + *b++ = c; + s++; + if (b - buf >= 224) { + promcon_puts(buf, b - buf); + b = buf; + } + } + *bp = b; + return s; +} + +static void +promcon_putcs(struct vc_data *conp, const unsigned short *s, + int count, int y, int x) +{ + unsigned char buf[256], *b = buf; + unsigned short attr = scr_readw(s); + unsigned char save; + int i, last = 0; + + if (console_blanked) + return; + + if (count <= 0) + return; + + b += promcon_start(conp, b); + + if (x + count >= pw + 1) { + if (count == 1) { + x -= 1; + save = scr_readw((unsigned short *)(conp->vc_origin + + y * conp->vc_size_row + + (x << 1))); + + if (px != x || py != y) { + b += sprintf(b, "\033[%d;%dH", y + 1, x + 1); + px = x; + py = y; + } + + if (inverted(attr)) + b += sprintf(b, "\033[7m%c\033[m", scr_readw(s++)); + else + b += sprintf(b, "%c", scr_readw(s++)); + + strcpy(b, "\b\033[@"); + b += 4; + + if (inverted(save)) + b += sprintf(b, "\033[7m%c\033[m", save); + else + b += sprintf(b, "%c", save); + + px++; + + b += promcon_end(conp, b); + promcon_puts(buf, b - buf); + return; + } else { + last = 1; + count = pw - x - 1; + } + } + + if (inverted(attr)) { + strcpy(b, "\033[7m"); + b += 4; + } + + if (px != x || py != y) { + b += sprintf(b, "\033[%d;%dH", y + 1, x + 1); + px = x; + py = y; + } + + for (i = 0; i < count; i++) { + if (b - buf >= 224) { + promcon_puts(buf, b - buf); + b = buf; + } + *b++ = scr_readw(s++); + } + + px += count; + + if (last) { + save = scr_readw(s++); + b += sprintf(b, "%c\b\033[@%c", scr_readw(s++), save); + px++; + } + + if (inverted(attr)) { + strcpy(b, "\033[m"); + b += 3; + } + + b += promcon_end(conp, b); + promcon_puts(buf, b - buf); +} + +static void +promcon_putc(struct vc_data *conp, int c, int y, int x) +{ + unsigned short s; + + if (console_blanked) + return; + + scr_writew(c, &s); + promcon_putcs(conp, &s, 1, y, x); +} + +static void +promcon_clear(struct vc_data *conp, int sy, int sx, int height, int width) +{ + unsigned char buf[256], *b = buf; + int i, j; + + if (console_blanked) + return; + + b += promcon_start(conp, b); + + if (!sx && width == pw + 1) { + + if (!sy && height == ph + 1) { + strcpy(b, "\033[H\033[J"); + b += 6; + b += promcon_end(conp, b); + promcon_puts(buf, b - buf); + return; + } else if (sy + height == ph + 1) { + b += sprintf(b, "\033[%dH\033[J", sy + 1); + b += promcon_end(conp, b); + promcon_puts(buf, b - buf); + return; + } + + b += sprintf(b, "\033[%dH", sy + 1); + for (i = 1; i < height; i++) { + strcpy(b, "\033[K\n"); + b += 4; + } + + strcpy(b, "\033[K"); + b += 3; + + b += promcon_end(conp, b); + promcon_puts(buf, b - buf); + return; + + } else if (sx + width == pw + 1) { + + b += sprintf(b, "\033[%d;%dH", sy + 1, sx + 1); + for (i = 1; i < height; i++) { + strcpy(b, "\033[K\n"); + b += 4; + } + + strcpy(b, "\033[K"); + b += 3; + + b += promcon_end(conp, b); + promcon_puts(buf, b - buf); + return; + } + + for (i = sy + 1; i <= sy + height; i++) { + b += sprintf(b, "\033[%d;%dH", i, sx + 1); + for (j = 0; j < width; j++) + *b++ = ' '; + if (b - buf + width >= 224) { + promcon_puts(buf, b - buf); + b = buf; + } + } + + b += promcon_end(conp, b); + promcon_puts(buf, b - buf); +} + +static void +promcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width) +{ + char buf[256], *b = buf; + + if (console_blanked) + return; + + b += promcon_start(conp, b); + if (sy == dy && height == 1) { + if (dx > sx && dx + width == conp->vc_cols) + b += sprintf(b, "\033[%d;%dH\033[%d@\033[%d;%dH", + sy + 1, sx + 1, dx - sx, py + 1, px + 1); + else if (dx < sx && sx + width == conp->vc_cols) + b += sprintf(b, "\033[%d;%dH\033[%dP\033[%d;%dH", + dy + 1, dx + 1, sx - dx, py + 1, px + 1); + + b += promcon_end(conp, b); + promcon_puts(buf, b - buf); + return; + } + + /* + * FIXME: What to do here??? + * Current console.c should not call it like that ever. + */ + prom_printf("\033[7mFIXME: bmove not handled\033[m\n"); +} + +static void +promcon_cursor(struct vc_data *conp, int mode) +{ + char buf[32], *b = buf; + + switch (mode) { + case CM_ERASE: + break; + + case CM_MOVE: + case CM_DRAW: + b += promcon_start(conp, b); + if (px != conp->vc_x || py != conp->vc_y) { + px = conp->vc_x; + py = conp->vc_y; + b += sprintf(b, "\033[%d;%dH", py + 1, px + 1); + } + promcon_puts(buf, b - buf); + break; + } +} + +static int +promcon_blank(struct vc_data *conp, int blank, int mode_switch) +{ + if (blank) { + promcon_puts("\033[H\033[J\033[7m \033[m\b", 15); + return 0; + } else { + /* Let console.c redraw */ + return 1; + } +} + +static int +promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) +{ + unsigned char buf[256], *p = buf; + unsigned short *s; + int i; + + if (console_blanked) + return 0; + + p += promcon_start(conp, p); + + switch (dir) { + case SM_UP: + if (b == ph + 1) { + p += sprintf(p, "\033[%dH\033[%dM", t + 1, count); + px = 0; + py = t; + p += promcon_end(conp, p); + promcon_puts(buf, p - buf); + break; + } + + s = (unsigned short *)(conp->vc_origin + + (t + count) * conp->vc_size_row); + + p += sprintf(p, "\033[%dH", t + 1); + + for (i = t; i < b - count; i++) + s = promcon_repaint_line(s, buf, &p); + + for (; i < b - 1; i++) { + strcpy(p, "\033[K\n"); + p += 4; + if (p - buf >= 224) { + promcon_puts(buf, p - buf); + p = buf; + } + } + + strcpy(p, "\033[K"); + p += 3; + + p += promcon_end(conp, p); + promcon_puts(buf, p - buf); + break; + + case SM_DOWN: + if (b == ph + 1) { + p += sprintf(p, "\033[%dH\033[%dL", t + 1, count); + px = 0; + py = t; + p += promcon_end(conp, p); + promcon_puts(buf, p - buf); + break; + } + + s = (unsigned short *)(conp->vc_origin + t * conp->vc_size_row); + + p += sprintf(p, "\033[%dH", t + 1); + + for (i = t; i < t + count; i++) { + strcpy(p, "\033[K\n"); + p += 4; + if (p - buf >= 224) { + promcon_puts(buf, p - buf); + p = buf; + } + } + + for (; i < b; i++) + s = promcon_repaint_line(s, buf, &p); + + p += promcon_end(conp, p); + promcon_puts(buf, p - buf); + break; + } + + return 0; +} + +#if !(PROMCON_COLOR) +static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse) +{ + return (_reverse) ? 0xf : 0x7; +} +#endif + +/* + * The console 'switch' structure for the VGA based console + */ + +static int promcon_dummy(void) +{ + return 0; +} + +#define DUMMY (void *) promcon_dummy + +const struct consw prom_con = { + .owner = THIS_MODULE, + .con_startup = promcon_startup, + .con_init = promcon_init, + .con_deinit = promcon_deinit, + .con_clear = promcon_clear, + .con_putc = promcon_putc, + .con_putcs = promcon_putcs, + .con_cursor = promcon_cursor, + .con_scroll = promcon_scroll, + .con_bmove = promcon_bmove, + .con_switch = promcon_switch, + .con_blank = promcon_blank, + .con_set_palette = DUMMY, + .con_scrolldelta = DUMMY, +#if !(PROMCON_COLOR) + .con_build_attr = promcon_build_attr, +#endif +}; + +void __init prom_con_init(void) +{ +#ifdef CONFIG_DUMMY_CONSOLE + if (conswitchp == &dummy_con) + take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1); + else +#endif + if (conswitchp == &prom_con) + promcon_init_unimap(vc_cons[fg_console].d); +} diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c new file mode 100644 index 000000000000..fd5940f41271 --- /dev/null +++ b/drivers/video/console/sticon.c @@ -0,0 +1,392 @@ +/* + * 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 + * + * Created 28 Sep 1997 by Geert Uytterhoeven + * Rewritten by Martin Mares <mj@ucw.cz>, July 1998 + * Copyright (C) 1991, 1992 Linus Torvalds + * 1995 Jay Estabrook + * Copyright (C) 1995 Geert Uytterhoeven + * Copyright (C) 1993 Bjoern Brauel + * Roman Hodek + * Copyright (C) 1993 Hamish Macdonald + * Greg Harp + * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] + * + * with work by William Rucklidge (wjr@cs.cornell.edu) + * Geert Uytterhoeven + * Jes Sorensen (jds@kom.auc.dk) + * Martin Apel + * with work by Guenther Kelleter + * Martin Schaller + * Andreas Schwab + * Emmanuel Marty (core@ggi-project.org) + * Jakub Jelinek (jj@ultra.linux.cz) + * Martin Mares <mj@ucw.cz> + * + * 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/init.h> +#include <linux/kernel.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/errno.h> +#include <linux/vt_kern.h> +#include <linux/kd.h> +#include <linux/selection.h> +#include <linux/module.h> + +#include <asm/io.h> + +#include "../sticore.h" + +/* switching to graphics mode */ +#define BLANK 0 +static int vga_is_gfx; + +/* this is the sti_struct used for this console */ +static struct sti_struct *sticon_sti; + +/* 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; + +/* 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) +{ + vbl_cursor_cnt = 0; + cursor_drawn = 0; +} + +static const char *__init sticon_startup(void) +{ + return "STI console"; +} + +static int sticon_set_palette(struct vc_data *c, unsigned char *table) +{ + return -EINVAL; +} + +static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos) +{ + int redraw_cursor = 0; + + if (vga_is_gfx || console_blanked) + return; + + if (conp->vc_mode != KD_TEXT) + return; +#if 0 + if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) { + cursor_undrawn(); + redraw_cursor = 1; + } +#endif + + sti_putc(sticon_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 redraw_cursor = 0; + + if (vga_is_gfx || console_blanked) + return; + + if (conp->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(sticon_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(sticon_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(sticon_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) +{ + struct sti_struct *sti = sticon_sti; + + if (vga_is_gfx) + return 0; + + sticon_cursor(conp, CM_ERASE); + + 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; + + 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; +} + +static void sticon_bmove(struct vc_data *conp, int sy, int sx, + int dy, int dx, int height, int 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(sticon_sti, sy, sx, dy, dx, height, width); +} + +static void sticon_init(struct vc_data *c, int init) +{ + struct sti_struct *sti = sticon_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_cols, vc_rows); +/* vc_resize_con(vc_rows, vc_cols, c->vc_num); */ + } +} + +static void sticon_deinit(struct vc_data *c) +{ +} + +static void sticon_clear(struct vc_data *conp, int sy, int sx, int height, + int width) +{ + if (!height || !width) + return; + + sti_clear(sticon_sti, sy, sx, height, width, conp->vc_video_erase_char); +} + +static int sticon_switch(struct vc_data *conp) +{ + return 1; /* needs refreshing */ +} + +static int sticon_set_origin(struct vc_data *conp) +{ + return 0; +} + +static int sticon_blank(struct vc_data *c, int blank, int mode_switch) +{ + if (blank == 0) { + if (mode_switch) + vga_is_gfx = 0; + return 1; + } + sticon_set_origin(c); + sti_clear(sticon_sti, 0,0, c->vc_rows, c->vc_cols, BLANK); + if (mode_switch) + vga_is_gfx = 1; + return 1; +} + +static int sticon_scrolldelta(struct vc_data *conp, int lines) +{ + return 0; +} + +static u16 *sticon_screen_pos(struct vc_data *conp, int offset) +{ + 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 unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos, + int *px, int *py) +{ + 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; +} + +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; +} + +static 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++); + } +} + +static void sticon_save_screen(struct vc_data *conp) +{ +} + +static struct consw sti_con = { + .owner = THIS_MODULE, + .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_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, +}; + + + +int __init sticonsole_init(void) +{ + /* already initialized ? */ + if (sticon_sti) + return 0; + + sticon_sti = sti_get_rom(0); + if (!sticon_sti) + return -ENODEV; + + if (conswitchp == &dummy_con) { + printk(KERN_INFO "sticon: Initializing STI text console.\n"); + return take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1, 1); + } + return 0; +} + +module_init(sticonsole_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c new file mode 100644 index 000000000000..d940f605acb6 --- /dev/null +++ b/drivers/video/console/sticore.c @@ -0,0 +1,1088 @@ +/* + * linux/drivers/video/console/sticore.c - + * core code for console driver using HP's STI firmware + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * Copyright (C) 2001-2003 Helge Deller <deller@gmx.de> + * 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 ;) + * + */ + +#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/hardware.h> +#include <asm/parisc-device.h> +#include <asm/cacheflush.h> + +#include "../sticore.h" + +#define STI_DRIVERVERSION "Version 0.9a" + +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 */ + + +/* The colour indices used by STI are + * 0 - Black + * 1 - White + * 2 - Red + * 3 - Yellow/Brown + * 4 - Green + * 5 - Cyan + * 6 - Blue + * 7 - Magenta + * + * So we have the same colours as VGA (basically one bit each for R, G, B), + * but have to translate them, anyway. */ + +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 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, +}; + +int +sti_init_graph(struct sti_struct *sti) +{ + struct sti_init_inptr_ext inptr_ext = { 0, }; + struct sti_init_inptr inptr = { + .text_planes = 3, /* # of text planes (max 3 for STI) */ + .ext_ptr = STI_PTR(&inptr_ext) + }; + struct sti_init_outptr outptr = { 0, }; + unsigned long flags; + int ret; + + spin_lock_irqsave(&sti->lock, flags); + + ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr, + &outptr, sti->glob_cfg); + + 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 const struct sti_conf_flags default_conf_flags = { + .wait = STI_WAIT, +}; + +void +sti_inq_conf(struct sti_struct *sti) +{ + 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, &sti->outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } 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 = { + .font_start_addr= STI_PTR(sti->font->raw), + .index = c_index(sti, c), + .fg_color = c_fg(sti, c), + .bg_color = c_bg(sti, c), + .dest_x = x * sti->font_width, + .dest_y = y * sti->font_height, + }; + struct sti_font_outptr outptr = { 0, }; + s32 ret; + unsigned long flags; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->font_unpmv, &default_font_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while (ret == 1); +} + +static const struct sti_blkmv_flags clear_blkmv_flags = { + .wait = STI_WAIT, + .color = 1, + .clear = 1, +}; + +void +sti_set(struct sti_struct *sti, int src_y, int src_x, + int height, int width, u8 color) +{ + struct sti_blkmv_inptr inptr = { + .fg_color = color, + .bg_color = color, + .src_x = src_x, + .src_y = src_y, + .dest_x = src_x, + .dest_y = src_y, + .width = width, + .height = height, + }; + struct sti_blkmv_outptr outptr = { 0, }; + s32 ret; + unsigned long flags; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->block_move, &clear_blkmv_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while (ret == 1); +} + +void +sti_clear(struct sti_struct *sti, int src_y, int src_x, + int height, int width, int c) +{ + struct sti_blkmv_inptr inptr = { + .fg_color = c_fg(sti, c), + .bg_color = c_bg(sti, c), + .src_x = src_x * sti->font_width, + .src_y = src_y * sti->font_height, + .dest_x = src_x * sti->font_width, + .dest_y = src_y * sti->font_height, + .width = width * sti->font_width, + .height = height* sti->font_height, + }; + struct sti_blkmv_outptr outptr = { 0, }; + s32 ret; + unsigned long flags; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->block_move, &clear_blkmv_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while (ret == 1); +} + +static const struct sti_blkmv_flags default_blkmv_flags = { + .wait = STI_WAIT, +}; + +void +sti_bmove(struct sti_struct *sti, int src_y, int src_x, + int dst_y, int dst_x, int height, int width) +{ + struct sti_blkmv_inptr inptr = { + .src_x = src_x * sti->font_width, + .src_y = src_y * sti->font_height, + .dest_x = dst_x * sti->font_width, + .dest_y = dst_y * sti->font_height, + .width = width * sti->font_width, + .height = height* sti->font_height, + }; + struct sti_blkmv_outptr outptr = { 0, }; + s32 ret; + unsigned long flags; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->block_move, &default_blkmv_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while (ret == 1); +} + + +/* FIXME: Do we have another solution for this ? */ +static void sti_flush(unsigned long from, unsigned long len) +{ + flush_data_cache(); + flush_kernel_dcache_range(from, len); + flush_icache_range(from, from+len); +} + +void __init +sti_rom_copy(unsigned long base, unsigned long count, void *dest) +{ + unsigned long dest_len = count; + unsigned long dest_start = (unsigned long) dest; + + /* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */ + while (count >= 4) { + count -= 4; + *(u32 *)dest = gsc_readl(base); + base += 4; + dest += 4; + } + while (count) { + count--; + *(u8 *)dest = gsc_readb(base); + base++; + dest++; + } + + sti_flush(dest_start, dest_len); +} + + + + +static char default_sti_path[21]; + +#ifndef MODULE +static int __init sti_setup(char *str) +{ + if (str) + strlcpy (default_sti_path, str, sizeof (default_sti_path)); + + return 0; +} + +/* 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); +#endif + + + +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]; +#ifndef MODULE +static int __init sti_font_setup(char *str) +{ + char *x; + int i = 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 */ + } + + if ((x = strchr(str, ','))) + *x++ = 0; + str = x; + + i++; + } + + return 0; +} + +/* 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); +#endif + + + +static void __init +sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request) +{ + 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 %08x\n", + glob_cfg->text_planes, + glob_cfg->onscreen_x, glob_cfg->onscreen_y, + glob_cfg->offscreen_x, glob_cfg->offscreen_y, + glob_cfg->total_x, glob_cfg->total_y, + glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1], + glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3], + 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)); + + /* 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_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)); +} + +static 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(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)) { + kfree(glob_cfg); + kfree(glob_cfg_ext); + kfree(save_addr); + kfree(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, 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); + 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; + +/* XXX: Enabling IOREMAP debugging causes a crash, so we must be passing + * a virtual address to something expecting a physical address that doesn't + * go through a readX macro */ +#if 0 + 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) ); +#else + if (len) + glob_cfg->region_ptrs[i] = sti->regions_phys[i]; +#endif + + 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 = glob_cfg; + + return 0; +} + +#ifdef CONFIG_FB +struct sti_cooked_font * __init +sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name ) +{ + 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; + + cooked_rom->font_start = cooked_font; + + return cooked_font; +} +#else +struct sti_cooked_font * __init +sti_select_fbfont(struct sti_cooked_rom *cooked_rom, char *fbfont_name) +{ + return NULL; +} +#endif + +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 " 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; + + cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL); + if (!cooked_font) + return 0; + + cooked_rom->font_start = cooked_font; + + raw_font = ((void *)raw_rom) + (raw_rom->font_start); + + font_start = raw_font; + cooked_font->raw = raw_font; + + 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; +} + +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; + + while (count) { + count--; + *(u8 *)dest = gsc_readl(base); + base += 4; + dest++; + } + sti_flush(dest_start, dest_len); +} + +static 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; +} + +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 = gsc_readl(address + offsetof(struct sti_rom,last_addr)); + + raw = kmalloc(size, GFP_KERNEL); + if(raw) + sti_rom_copy(address, size, raw); + + return raw; +} + +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: + kfree(raw); + kfree(cooked); + return 0; +} + +static struct sti_struct * __init +sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd) +{ + 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)); + spin_lock_init(&sti->lock); + +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(address)) + goto out_err; + + sig = gsc_readl(address); + + /* check for a PCI ROM structure */ + if ((le32_to_cpu(sig)==0xaa55)) { + unsigned int i, rm_offset; + u32 *rm; + i = gsc_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 = gsc_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++ = gsc_readl(address+rm_offset+0x00); + *rm++ = gsc_readl(address+rm_offset+0x04); + *rm++ = gsc_readl(address+rm_offset+0x08); + *rm++ = gsc_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(gsc_readl(address+8)); + DPRINTK(("sig %04x, PCI STI ROM at %08lx\n", sig, address)); + goto test_rom; + } + + ok = 0; + + if ((sig & 0xff) == 0x01) { + DPRINTK((" byte mode ROM at %08lx, hpa at %08lx\n", + address, hpa)); + ok = sti_read_rom(0, sti, address); + } + + if ((sig & 0xffff) == 0x0303) { + DPRINTK((" word mode ROM at %08lx, hpa at %08lx\n", + address, hpa)); + ok = sti_read_rom(1, sti, address); + } + + if (!ok) + goto out_err; + + 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")); + } + + if (sti_init_graph(sti)) + goto out_err; + + sti_inq_conf(sti); + sti_dump_globcfg(sti->glob_cfg, sti->sti_mem_request); + sti_dump_outptr(sti); + + printk(KERN_INFO " graphics card name: %s\n", sti->outptr.dev_name ); + + sti_roms[num_sti_roms] = sti; + num_sti_roms++; + + return sti; + +out_err: + kfree(sti); + return NULL; +} + +static void __init sticore_check_for_default_sti(struct sti_struct *sti, char *path) +{ + if (strcmp (path, default_sti_path) == 0) + default_sti = sti; +} + +/* + * 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) +{ + 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; +} + + +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)); + } + + 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", + pci_name(pd)); + return -ENODEV; + } +#endif /* CONFIG_PCI */ + + return 0; +} + + +static void __devexit sticore_pci_remove(struct pci_dev *pd) +{ + BUG(); +} + + +static struct pci_device_id sti_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_EG) }, + { PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX6) }, + { PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX4) }, + { PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX2) }, + { PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FXE) }, + { 0, } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, sti_pci_tbl); + +static struct pci_driver pci_sti_driver = { + .name = "sti", + .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, } +}; + +static struct parisc_driver pa_sti_driver = { + .name = "sti", + .id_table = sti_pa_tbl, + .probe = sticore_pa_init, +}; + + +/* + * sti_init_roms() - detects all STI ROMs and stores them in sti_roms[] + */ + +static int sticore_initialized; + +static void __init sti_init_roms(void) +{ + if (sticore_initialized) + return; + + sticore_initialized = 1; + + printk(KERN_INFO "STI GSC/PCI core graphics driver " + STI_DRIVERVERSION "\n"); + + /* Register drivers for native & PCI cards */ + register_parisc_driver(&pa_sti_driver); + pci_register_driver(&pci_sti_driver); + + /* if we didn't find the given default sti, take the first one */ + if (!default_sti) + default_sti = sti_roms[0]; + +} + +/* + * index = 0 gives default sti + * index > 0 gives other stis in detection order + */ +struct sti_struct * sti_get_rom(unsigned int index) +{ + if (!sticore_initialized) + sti_init_roms(); + + if (index == 0) + return default_sti; + + if (index > num_sti_roms) + return NULL; + + return sti_roms[index-1]; +} +EXPORT_SYMBOL(sti_get_rom); + +MODULE_AUTHOR("Philipp Rumpf, Helge Deller, Thomas Bogendoerfer"); +MODULE_DESCRIPTION("Core STI driver for HP's NGLE series graphics cards in HP PARISC machines"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c new file mode 100644 index 000000000000..7f76e2c6a4a1 --- /dev/null +++ b/drivers/video/console/tileblit.c @@ -0,0 +1,148 @@ +/* + * linux/drivers/video/console/tileblit.c -- Tile Blitting Operation + * + * Copyright (C) 2004 Antonino Daplas <adaplas @pol.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. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/vt_kern.h> +#include <linux/console.h> +#include <asm/types.h> +#include "fbcon.h" + +static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) +{ + struct fb_tilearea area; + + area.sx = sx; + area.sy = sy; + area.dx = dx; + area.dy = dy; + area.height = height; + area.width = width; + + info->tileops->fb_tilecopy(info, &area); +} + +static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width) +{ + struct fb_tilerect rect; + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; + + rect.index = vc->vc_video_erase_char & + ((vc->vc_hi_font_mask) ? 0x1ff : 0xff); + rect.fg = attr_fgcol_ec(fgshift, vc); + rect.bg = attr_bgcol_ec(bgshift, vc); + rect.sx = sx; + rect.sy = sy; + rect.width = width; + rect.height = height; + rect.rop = ROP_COPY; + + info->tileops->fb_tilefill(info, &rect); +} + +static void tile_putcs(struct vc_data *vc, struct fb_info *info, + const unsigned short *s, int count, int yy, int xx, + int fg, int bg) +{ + struct fb_tileblit blit; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int size = sizeof(u32) * count, i; + + blit.sx = xx; + blit.sy = yy; + blit.width = count; + blit.height = 1; + blit.fg = fg; + blit.bg = bg; + blit.length = count; + blit.indices = (u32 *) fb_get_buffer_offset(info, &info->pixmap, size); + for (i = 0; i < count; i++) + blit.indices[i] = (u32)(scr_readw(s++) & charmask); + + info->tileops->fb_tileblit(info, &blit); +} + +static void tile_clear_margins(struct vc_data *vc, struct fb_info *info, + int bottom_only) +{ + return; +} + +static void tile_cursor(struct vc_data *vc, struct fb_info *info, + struct display *p, int mode, int softback_lines, + int fg, int bg) +{ + struct fb_tilecursor cursor; + int use_sw = (vc->vc_cursor_type & 0x01); + + cursor.sx = vc->vc_x; + cursor.sy = vc->vc_y; + cursor.mode = (mode == CM_ERASE || use_sw) ? 0 : 1; + cursor.fg = fg; + cursor.bg = bg; + + switch (vc->vc_cursor_type & 0x0f) { + case CUR_NONE: + cursor.shape = FB_TILE_CURSOR_NONE; + break; + case CUR_UNDERLINE: + cursor.shape = FB_TILE_CURSOR_UNDERLINE; + break; + case CUR_LOWER_THIRD: + cursor.shape = FB_TILE_CURSOR_LOWER_THIRD; + break; + case CUR_LOWER_HALF: + cursor.shape = FB_TILE_CURSOR_LOWER_HALF; + break; + case CUR_TWO_THIRDS: + cursor.shape = FB_TILE_CURSOR_TWO_THIRDS; + break; + case CUR_BLOCK: + default: + cursor.shape = FB_TILE_CURSOR_BLOCK; + break; + } + + info->tileops->fb_tilecursor(info, &cursor); +} + +void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, + struct display *p, struct fbcon_ops *ops) +{ + struct fb_tilemap map; + + ops->bmove = tile_bmove; + ops->clear = tile_clear; + ops->putcs = tile_putcs; + ops->clear_margins = tile_clear_margins; + ops->cursor = tile_cursor; + + if (p) { + map.width = vc->vc_font.width; + map.height = vc->vc_font.height; + map.depth = 1; + map.length = (p->userfont) ? + FNTCHARCNT(p->fontdata) : 256; + map.data = p->fontdata; + info->tileops->fb_settile(info, &map); + } +} + +EXPORT_SYMBOL(fbcon_set_tileops); + +MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); +MODULE_DESCRIPTION("Tile Blitting Operation"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c new file mode 100644 index 000000000000..7d1ae06667c6 --- /dev/null +++ b/drivers/video/console/vgacon.c @@ -0,0 +1,1103 @@ +/* + * linux/drivers/video/vgacon.c -- Low level VGA based console driver + * + * Created 28 Sep 1997 by Geert Uytterhoeven + * + * Rewritten by Martin Mares <mj@ucw.cz>, July 1998 + * + * This file is based on the old console.c, vga.c and vesa_blank.c drivers. + * + * Copyright (C) 1991, 1992 Linus Torvalds + * 1995 Jay Estabrook + * + * User definable mapping table and font loading by Eugene G. Crosser, + * <crosser@average.org> + * + * Improved loadable font/UTF-8 support by H. Peter Anvin + * Feb-Sep 1995 <peter.anvin@linux.org> + * + * Colour palette handling, by Simon Tatham + * 17-Jun-95 <sgt20@cam.ac.uk> + * + * if 512 char mode is already enabled don't re-enable it, + * because it causes screen to flicker, by Mitja Horvat + * 5-May-96 <mitja.horvat@guest.arnes.si> + * + * Use 2 outw instead of 4 outb_p to reduce erroneous text + * flashing on RHS of screen during heavy console scrolling . + * Oct 1996, Paul Gortmaker. + * + * + * 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/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/string.h> +#include <linux/kd.h> +#include <linux/slab.h> +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/spinlock.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/smp_lock.h> +#include <video/vga.h> +#include <asm/io.h> + +static DEFINE_SPINLOCK(vga_lock); +static int cursor_size_lastfrom; +static int cursor_size_lastto; +static struct vgastate state; + +#define BLANK 0x0020 + +#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */ +#define CAN_LOAD_PALETTE /* undefine if the user must not do this */ + +/* You really do _NOT_ want to define this, unless you have buggy + * Trident VGA which will resize cursor when moving it between column + * 15 & 16. If you define this and your VGA is OK, inverse bug will + * appear. + */ +#undef TRIDENT_GLITCH + +/* + * Interface used by the world + */ + +static const char *vgacon_startup(void); +static void vgacon_init(struct vc_data *c, int init); +static void vgacon_deinit(struct vc_data *c); +static void vgacon_cursor(struct vc_data *c, int mode); +static int vgacon_switch(struct vc_data *c); +static int vgacon_blank(struct vc_data *c, int blank, int mode_switch); +static int vgacon_set_palette(struct vc_data *vc, unsigned char *table); +static int vgacon_scrolldelta(struct vc_data *c, int lines); +static int vgacon_set_origin(struct vc_data *c); +static void vgacon_save_screen(struct vc_data *c); +static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, + int lines); +static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, + u8 blink, u8 underline, u8 reverse); +static void vgacon_invert_region(struct vc_data *c, u16 * p, int count); +static unsigned long vgacon_uni_pagedir[2]; + + +/* Description of the hardware situation */ +static unsigned long vga_vram_base; /* Base of video memory */ +static unsigned long vga_vram_end; /* End of video memory */ +static u16 vga_video_port_reg; /* Video register select port */ +static u16 vga_video_port_val; /* Video register value port */ +static unsigned int vga_video_num_columns; /* Number of text columns */ +static unsigned int vga_video_num_lines; /* Number of text lines */ +static int vga_can_do_color = 0; /* Do we support colors? */ +static unsigned int vga_default_font_height;/* Height of default screen font */ +static unsigned char vga_video_type; /* Card type */ +static unsigned char vga_hardscroll_enabled; +static unsigned char vga_hardscroll_user_enable = 1; +static unsigned char vga_font_is_default = 1; +static int vga_vesa_blanked; +static int vga_palette_blanked; +static int vga_is_gfx; +static int vga_512_chars; +static int vga_video_font_height; +static int vga_scan_lines; +static unsigned int vga_rolled_over = 0; + +static int __init no_scroll(char *str) +{ + /* + * Disabling scrollback is required for the Braillex ib80-piezo + * Braille reader made by F.H. Papenmeier (Germany). + * Use the "no-scroll" bootflag. + */ + vga_hardscroll_user_enable = vga_hardscroll_enabled = 0; + return 1; +} + +__setup("no-scroll", no_scroll); + +/* + * By replacing the four outb_p with two back to back outw, we can reduce + * the window of opportunity to see text mislocated to the RHS of the + * console during heavy scrolling activity. However there is the remote + * possibility that some pre-dinosaur hardware won't like the back to back + * I/O. Since the Xservers get away with it, we should be able to as well. + */ +static inline void write_vga(unsigned char reg, unsigned int val) +{ + unsigned int v1, v2; + unsigned long flags; + + /* + * ddprintk might set the console position from interrupt + * handlers, thus the write has to be IRQ-atomic. + */ + spin_lock_irqsave(&vga_lock, flags); + +#ifndef SLOW_VGA + v1 = reg + (val & 0xff00); + v2 = reg + 1 + ((val << 8) & 0xff00); + outw(v1, vga_video_port_reg); + outw(v2, vga_video_port_reg); +#else + outb_p(reg, vga_video_port_reg); + outb_p(val >> 8, vga_video_port_val); + outb_p(reg + 1, vga_video_port_reg); + outb_p(val & 0xff, vga_video_port_val); +#endif + spin_unlock_irqrestore(&vga_lock, flags); +} + +static const char __init *vgacon_startup(void) +{ + const char *display_desc = NULL; + u16 saved1, saved2; + volatile u16 *p; + + if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) { + no_vga: +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; + return conswitchp->con_startup(); +#else + return NULL; +#endif + } + + /* VGA16 modes are not handled by VGACON */ + if ((ORIG_VIDEO_MODE == 0x0D) || /* 320x200/4 */ + (ORIG_VIDEO_MODE == 0x0E) || /* 640x200/4 */ + (ORIG_VIDEO_MODE == 0x10) || /* 640x350/4 */ + (ORIG_VIDEO_MODE == 0x12) || /* 640x480/4 */ + (ORIG_VIDEO_MODE == 0x6A)) /* 800x600/4, 0x6A is very common */ + goto no_vga; + + vga_video_num_lines = ORIG_VIDEO_LINES; + vga_video_num_columns = ORIG_VIDEO_COLS; + state.vgabase = NULL; + + if (ORIG_VIDEO_MODE == 7) { /* Is this a monochrome display? */ + vga_vram_base = 0xb0000; + vga_video_port_reg = VGA_CRT_IM; + vga_video_port_val = VGA_CRT_DM; + if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { + static struct resource ega_console_resource = + { "ega", 0x3B0, 0x3BF }; + vga_video_type = VIDEO_TYPE_EGAM; + vga_vram_end = 0xb8000; + display_desc = "EGA+"; + request_resource(&ioport_resource, + &ega_console_resource); + } else { + static struct resource mda1_console_resource = + { "mda", 0x3B0, 0x3BB }; + static struct resource mda2_console_resource = + { "mda", 0x3BF, 0x3BF }; + vga_video_type = VIDEO_TYPE_MDA; + vga_vram_end = 0xb2000; + display_desc = "*MDA"; + request_resource(&ioport_resource, + &mda1_console_resource); + request_resource(&ioport_resource, + &mda2_console_resource); + vga_video_font_height = 14; + } + } else { + /* If not, it is color. */ + vga_can_do_color = 1; + vga_vram_base = 0xb8000; + vga_video_port_reg = VGA_CRT_IC; + vga_video_port_val = VGA_CRT_DC; + if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { + int i; + + vga_vram_end = 0xc0000; + + if (!ORIG_VIDEO_ISVGA) { + static struct resource ega_console_resource + = { "ega", 0x3C0, 0x3DF }; + vga_video_type = VIDEO_TYPE_EGAC; + display_desc = "EGA"; + request_resource(&ioport_resource, + &ega_console_resource); + } else { + static struct resource vga_console_resource + = { "vga+", 0x3C0, 0x3DF }; + vga_video_type = VIDEO_TYPE_VGAC; + display_desc = "VGA+"; + request_resource(&ioport_resource, + &vga_console_resource); + +#ifdef VGA_CAN_DO_64KB + /* + * get 64K rather than 32K of video RAM. + * This doesn't actually work on all "VGA" + * controllers (it seems like setting MM=01 + * and COE=1 isn't necessarily a good idea) + */ + vga_vram_base = 0xa0000; + vga_vram_end = 0xb0000; + outb_p(6, VGA_GFX_I); + outb_p(6, VGA_GFX_D); +#endif + /* + * Normalise the palette registers, to point + * the 16 screen colours to the first 16 + * DAC entries. + */ + + for (i = 0; i < 16; i++) { + inb_p(VGA_IS1_RC); + outb_p(i, VGA_ATT_W); + outb_p(i, VGA_ATT_W); + } + outb_p(0x20, VGA_ATT_W); + + /* + * Now set the DAC registers back to their + * default values + */ + for (i = 0; i < 16; i++) { + outb_p(color_table[i], VGA_PEL_IW); + outb_p(default_red[i], VGA_PEL_D); + outb_p(default_grn[i], VGA_PEL_D); + outb_p(default_blu[i], VGA_PEL_D); + } + } + } else { + static struct resource cga_console_resource = + { "cga", 0x3D4, 0x3D5 }; + vga_video_type = VIDEO_TYPE_CGA; + vga_vram_end = 0xba000; + display_desc = "*CGA"; + request_resource(&ioport_resource, + &cga_console_resource); + vga_video_font_height = 8; + } + } + + vga_vram_base = VGA_MAP_MEM(vga_vram_base); + vga_vram_end = VGA_MAP_MEM(vga_vram_end); + + /* + * Find out if there is a graphics card present. + * Are there smarter methods around? + */ + p = (volatile u16 *) vga_vram_base; + saved1 = scr_readw(p); + saved2 = scr_readw(p + 1); + scr_writew(0xAA55, p); + scr_writew(0x55AA, p + 1); + if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) { + scr_writew(saved1, p); + scr_writew(saved2, p + 1); + goto no_vga; + } + scr_writew(0x55AA, p); + scr_writew(0xAA55, p + 1); + if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) { + scr_writew(saved1, p); + scr_writew(saved2, p + 1); + goto no_vga; + } + scr_writew(saved1, p); + scr_writew(saved2, p + 1); + + if (vga_video_type == VIDEO_TYPE_EGAC + || vga_video_type == VIDEO_TYPE_VGAC + || vga_video_type == VIDEO_TYPE_EGAM) { + vga_hardscroll_enabled = vga_hardscroll_user_enable; + vga_default_font_height = ORIG_VIDEO_POINTS; + vga_video_font_height = ORIG_VIDEO_POINTS; + /* This may be suboptimal but is a safe bet - go with it */ + vga_scan_lines = + vga_video_font_height * vga_video_num_lines; + } + return display_desc; +} + +static void vgacon_init(struct vc_data *c, int init) +{ + unsigned long p; + + /* We cannot be loaded as a module, therefore init is always 1 */ + c->vc_can_do_color = vga_can_do_color; + c->vc_cols = vga_video_num_columns; + c->vc_rows = vga_video_num_lines; + c->vc_scan_lines = vga_scan_lines; + c->vc_font.height = vga_video_font_height; + c->vc_complement_mask = 0x7700; + p = *c->vc_uni_pagedir_loc; + if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir || + !--c->vc_uni_pagedir_loc[1]) + con_free_unimap(c); + c->vc_uni_pagedir_loc = vgacon_uni_pagedir; + vgacon_uni_pagedir[1]++; + if (!vgacon_uni_pagedir[0] && p) + con_set_default_unimap(c); +} + +static inline void vga_set_mem_top(struct vc_data *c) +{ + write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2); +} + +static void vgacon_deinit(struct vc_data *c) +{ + /* When closing the last console, reset video origin */ + if (!--vgacon_uni_pagedir[1]) { + c->vc_visible_origin = vga_vram_base; + vga_set_mem_top(c); + con_free_unimap(c); + } + c->vc_uni_pagedir_loc = &c->vc_uni_pagedir; + con_set_default_unimap(c); +} + +static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, + u8 blink, u8 underline, u8 reverse) +{ + u8 attr = color; + + if (vga_can_do_color) { + if (underline) + attr = (attr & 0xf0) | c->vc_ulcolor; + else if (intensity == 0) + attr = (attr & 0xf0) | c->vc_halfcolor; + } + if (reverse) + attr = + ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) & + 0x77); + if (blink) + attr ^= 0x80; + if (intensity == 2) + attr ^= 0x08; + if (!vga_can_do_color) { + if (underline) + attr = (attr & 0xf8) | 0x01; + else if (intensity == 0) + attr = (attr & 0xf0) | 0x08; + } + return attr; +} + +static void vgacon_invert_region(struct vc_data *c, u16 * p, int count) +{ + int col = 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++); + } +} + +static void vgacon_set_cursor_size(int xpos, int from, int to) +{ + unsigned long flags; + int curs, cure; + +#ifdef TRIDENT_GLITCH + if (xpos < 16) + from--, to--; +#endif + + if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto)) + return; + cursor_size_lastfrom = from; + cursor_size_lastto = to; + + spin_lock_irqsave(&vga_lock, flags); + outb_p(0x0a, vga_video_port_reg); /* Cursor start */ + curs = inb_p(vga_video_port_val); + outb_p(0x0b, vga_video_port_reg); /* Cursor end */ + cure = inb_p(vga_video_port_val); + + curs = (curs & 0xc0) | from; + cure = (cure & 0xe0) | to; + + outb_p(0x0a, vga_video_port_reg); /* Cursor start */ + outb_p(curs, vga_video_port_val); + outb_p(0x0b, vga_video_port_reg); /* Cursor end */ + outb_p(cure, vga_video_port_val); + spin_unlock_irqrestore(&vga_lock, flags); +} + +static void vgacon_cursor(struct vc_data *c, int mode) +{ + if (c->vc_origin != c->vc_visible_origin) + vgacon_scrolldelta(c, 0); + switch (mode) { + case CM_ERASE: + write_vga(14, (vga_vram_end - vga_vram_base - 1) / 2); + break; + + case CM_MOVE: + case CM_DRAW: + write_vga(14, (c->vc_pos - vga_vram_base) / 2); + switch (c->vc_cursor_type & 0x0f) { + case CUR_UNDERLINE: + vgacon_set_cursor_size(c->vc_x, + c->vc_font.height - + (c->vc_font.height < + 10 ? 2 : 3), + c->vc_font.height - + (c->vc_font.height < + 10 ? 1 : 2)); + break; + case CUR_TWO_THIRDS: + vgacon_set_cursor_size(c->vc_x, + c->vc_font.height / 3, + c->vc_font.height - + (c->vc_font.height < + 10 ? 1 : 2)); + break; + case CUR_LOWER_THIRD: + vgacon_set_cursor_size(c->vc_x, + (c->vc_font.height * 2) / 3, + c->vc_font.height - + (c->vc_font.height < + 10 ? 1 : 2)); + break; + case CUR_LOWER_HALF: + vgacon_set_cursor_size(c->vc_x, + c->vc_font.height / 2, + c->vc_font.height - + (c->vc_font.height < + 10 ? 1 : 2)); + break; + case CUR_NONE: + vgacon_set_cursor_size(c->vc_x, 31, 30); + break; + default: + vgacon_set_cursor_size(c->vc_x, 1, + c->vc_font.height); + break; + } + break; + } +} + +static int vgacon_switch(struct vc_data *c) +{ + /* + * We need to save screen size here as it's the only way + * we can spot the screen has been resized and we need to + * set size of freshly allocated screens ourselves. + */ + vga_video_num_columns = c->vc_cols; + vga_video_num_lines = c->vc_rows; + if (!vga_is_gfx) + scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, + c->vc_screenbuf_size); + return 0; /* Redrawing not needed */ +} + +static void vga_set_palette(struct vc_data *vc, unsigned char *table) +{ + int i, j; + + for (i = j = 0; i < 16; i++) { + vga_w(state.vgabase, VGA_PEL_IW, table[i]); + vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); + vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); + vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); + } +} + +static int vgacon_set_palette(struct vc_data *vc, unsigned char *table) +{ +#ifdef CAN_LOAD_PALETTE + if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked + || !CON_IS_VISIBLE(vc)) + return -EINVAL; + vga_set_palette(vc, table); + return 0; +#else + return -EINVAL; +#endif +} + +/* structure holding original VGA register settings */ +static struct { + unsigned char SeqCtrlIndex; /* Sequencer Index reg. */ + unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */ + unsigned char CrtMiscIO; /* Miscellaneous register */ + unsigned char HorizontalTotal; /* CRT-Controller:00h */ + unsigned char HorizDisplayEnd; /* CRT-Controller:01h */ + unsigned char StartHorizRetrace; /* CRT-Controller:04h */ + unsigned char EndHorizRetrace; /* CRT-Controller:05h */ + unsigned char Overflow; /* CRT-Controller:07h */ + unsigned char StartVertRetrace; /* CRT-Controller:10h */ + unsigned char EndVertRetrace; /* CRT-Controller:11h */ + unsigned char ModeControl; /* CRT-Controller:17h */ + unsigned char ClockingMode; /* Seq-Controller:01h */ +} vga_state; + +static void vga_vesa_blank(struct vgastate *state, int mode) +{ + /* save original values of VGA controller registers */ + if (!vga_vesa_blanked) { + spin_lock_irq(&vga_lock); + vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I); + vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg); + vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R); + spin_unlock_irq(&vga_lock); + + outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */ + vga_state.HorizontalTotal = inb_p(vga_video_port_val); + outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */ + vga_state.HorizDisplayEnd = inb_p(vga_video_port_val); + outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */ + vga_state.StartHorizRetrace = inb_p(vga_video_port_val); + outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */ + vga_state.EndHorizRetrace = inb_p(vga_video_port_val); + outb_p(0x07, vga_video_port_reg); /* Overflow */ + vga_state.Overflow = inb_p(vga_video_port_val); + outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */ + vga_state.StartVertRetrace = inb_p(vga_video_port_val); + outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */ + vga_state.EndVertRetrace = inb_p(vga_video_port_val); + outb_p(0x17, vga_video_port_reg); /* ModeControl */ + vga_state.ModeControl = inb_p(vga_video_port_val); + vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE); + } + + /* assure that video is enabled */ + /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */ + spin_lock_irq(&vga_lock); + vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20); + + /* test for vertical retrace in process.... */ + if ((vga_state.CrtMiscIO & 0x80) == 0x80) + vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF); + + /* + * Set <End of vertical retrace> to minimum (0) and + * <Start of vertical Retrace> to maximum (incl. overflow) + * Result: turn off vertical sync (VSync) pulse. + */ + if (mode & VESA_VSYNC_SUSPEND) { + outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */ + outb_p(0xff, vga_video_port_val); /* maximum value */ + outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */ + outb_p(0x40, vga_video_port_val); /* minimum (bits 0..3) */ + outb_p(0x07, vga_video_port_reg); /* Overflow */ + outb_p(vga_state.Overflow | 0x84, vga_video_port_val); /* bits 9,10 of vert. retrace */ + } + + if (mode & VESA_HSYNC_SUSPEND) { + /* + * Set <End of horizontal retrace> to minimum (0) and + * <Start of horizontal Retrace> to maximum + * Result: turn off horizontal sync (HSync) pulse. + */ + outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */ + outb_p(0xff, vga_video_port_val); /* maximum */ + outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */ + outb_p(0x00, vga_video_port_val); /* minimum (0) */ + } + + /* restore both index registers */ + vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex); + outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg); + spin_unlock_irq(&vga_lock); +} + +static void vga_vesa_unblank(struct vgastate *state) +{ + /* restore original values of VGA controller registers */ + spin_lock_irq(&vga_lock); + vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO); + + outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */ + outb_p(vga_state.HorizontalTotal, vga_video_port_val); + outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */ + outb_p(vga_state.HorizDisplayEnd, vga_video_port_val); + outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */ + outb_p(vga_state.StartHorizRetrace, vga_video_port_val); + outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */ + outb_p(vga_state.EndHorizRetrace, vga_video_port_val); + outb_p(0x07, vga_video_port_reg); /* Overflow */ + outb_p(vga_state.Overflow, vga_video_port_val); + outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */ + outb_p(vga_state.StartVertRetrace, vga_video_port_val); + outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */ + outb_p(vga_state.EndVertRetrace, vga_video_port_val); + outb_p(0x17, vga_video_port_reg); /* ModeControl */ + outb_p(vga_state.ModeControl, vga_video_port_val); + /* ClockingMode */ + vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode); + + /* restore index/control registers */ + vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex); + outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg); + spin_unlock_irq(&vga_lock); +} + +static void vga_pal_blank(struct vgastate *state) +{ + int i; + + for (i = 0; i < 16; i++) { + vga_w(state->vgabase, VGA_PEL_IW, i); + vga_w(state->vgabase, VGA_PEL_D, 0); + vga_w(state->vgabase, VGA_PEL_D, 0); + vga_w(state->vgabase, VGA_PEL_D, 0); + } +} + +static int vgacon_blank(struct vc_data *c, int blank, int mode_switch) +{ + switch (blank) { + case 0: /* Unblank */ + if (vga_vesa_blanked) { + vga_vesa_unblank(&state); + vga_vesa_blanked = 0; + } + if (vga_palette_blanked) { + vga_set_palette(c, color_table); + vga_palette_blanked = 0; + return 0; + } + vga_is_gfx = 0; + /* Tell console.c that it has to restore the screen itself */ + return 1; + case 1: /* Normal blanking */ + case -1: /* Obsolete */ + if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) { + vga_pal_blank(&state); + vga_palette_blanked = 1; + return 0; + } + vgacon_set_origin(c); + scr_memsetw((void *) vga_vram_base, BLANK, + c->vc_screenbuf_size); + if (mode_switch) + vga_is_gfx = 1; + return 1; + default: /* VESA blanking */ + if (vga_video_type == VIDEO_TYPE_VGAC) { + vga_vesa_blank(&state, blank - 1); + vga_vesa_blanked = blank; + } + return 0; + } +} + +/* + * PIO_FONT support. + * + * The font loading code goes back to the codepage package by + * Joel Hoffman (joel@wam.umd.edu). (He reports that the original + * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2 + * Video Systems_ by Richard Wilton. 1987. Microsoft Press".) + * + * Change for certain monochrome monitors by Yury Shevchuck + * (sizif@botik.yaroslavl.su). + */ + +#ifdef CAN_LOAD_EGA_FONTS + +#define colourmap 0xa0000 +/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we + should use 0xA0000 for the bwmap as well.. */ +#define blackwmap 0xa0000 +#define cmapsz 8192 + +static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) +{ + unsigned short video_port_status = vga_video_port_reg + 6; + int font_select = 0x00, beg, i; + char *charmap; + + if (vga_video_type != VIDEO_TYPE_EGAM) { + charmap = (char *) VGA_MAP_MEM(colourmap); + beg = 0x0e; +#ifdef VGA_CAN_DO_64KB + if (vga_video_type == VIDEO_TYPE_VGAC) + beg = 0x06; +#endif + } else { + charmap = (char *) VGA_MAP_MEM(blackwmap); + beg = 0x0a; + } + +#ifdef BROKEN_GRAPHICS_PROGRAMS + /* + * All fonts are loaded in slot 0 (0:1 for 512 ch) + */ + + if (!arg) + return -EINVAL; /* Return to default font not supported */ + + vga_font_is_default = 0; + font_select = ch512 ? 0x04 : 0x00; +#else + /* + * The default font is kept in slot 0 and is never touched. + * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch) + */ + + if (set) { + vga_font_is_default = !arg; + if (!arg) + ch512 = 0; /* Default font is always 256 */ + font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00; + } + + if (!vga_font_is_default) + charmap += 4 * cmapsz; +#endif + + unlock_kernel(); + spin_lock_irq(&vga_lock); + /* First, the Sequencer */ + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); + /* CPU writes only to map 2 */ + vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04); + /* Sequential addressing */ + vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07); + /* Clear synchronous reset */ + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03); + + /* Now, the graphics controller, select map 2 */ + vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02); + /* disable odd-even addressing */ + vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00); + /* map start at A000:0000 */ + vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00); + spin_unlock_irq(&vga_lock); + + if (arg) { + if (set) + for (i = 0; i < cmapsz; i++) + vga_writeb(arg[i], charmap + i); + else + for (i = 0; i < cmapsz; i++) + arg[i] = vga_readb(charmap + i); + + /* + * In 512-character mode, the character map is not contiguous if + * we want to remain EGA compatible -- which we do + */ + + if (ch512) { + charmap += 2 * cmapsz; + arg += cmapsz; + if (set) + for (i = 0; i < cmapsz; i++) + vga_writeb(arg[i], charmap + i); + else + for (i = 0; i < cmapsz; i++) + arg[i] = vga_readb(charmap + i); + } + } + + spin_lock_irq(&vga_lock); + /* First, the sequencer, Synchronous reset */ + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01); + /* CPU writes to maps 0 and 1 */ + vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03); + /* odd-even addressing */ + vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03); + /* Character Map Select */ + if (set) + vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select); + /* clear synchronous reset */ + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03); + + /* Now, the graphics controller, select map 0 for CPU */ + vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00); + /* enable even-odd addressing */ + vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10); + /* map starts at b800:0 or b000:0 */ + vga_wgfx(state->vgabase, VGA_GFX_MISC, beg); + + /* if 512 char mode is already enabled don't re-enable it. */ + if ((set) && (ch512 != vga_512_chars)) { + int i; + + /* attribute controller */ + for (i = 0; i < MAX_NR_CONSOLES; i++) { + struct vc_data *c = vc_cons[i].d; + if (c && c->vc_sw == &vga_con) + c->vc_hi_font_mask = ch512 ? 0x0800 : 0; + } + vga_512_chars = ch512; + /* 256-char: enable intensity bit + 512-char: disable intensity bit */ + inb_p(video_port_status); /* clear address flip-flop */ + /* color plane enable register */ + vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f); + /* Wilton (1987) mentions the following; I don't know what + it means, but it works, and it appears necessary */ + inb_p(video_port_status); + vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0); + } + spin_unlock_irq(&vga_lock); + lock_kernel(); + return 0; +} + +/* + * Adjust the screen to fit a font of a certain height + */ +static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight) +{ + unsigned char ovr, vde, fsr; + int rows, maxscan, i; + + rows = vc->vc_scan_lines / fontheight; /* Number of video rows we end up with */ + maxscan = rows * fontheight - 1; /* Scan lines to actually display-1 */ + + /* Reprogram the CRTC for the new font size + Note: the attempt to read the overflow register will fail + on an EGA, but using 0xff for the previous value appears to + be OK for EGA text modes in the range 257-512 scan lines, so I + guess we don't need to worry about it. + + The same applies for the spill bits in the font size and cursor + registers; they are write-only on EGA, but it appears that they + are all don't care bits on EGA, so I guess it doesn't matter. */ + + spin_lock_irq(&vga_lock); + outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */ + ovr = inb_p(vga_video_port_val); + outb_p(0x09, vga_video_port_reg); /* Font size register */ + fsr = inb_p(vga_video_port_val); + spin_unlock_irq(&vga_lock); + + vde = maxscan & 0xff; /* Vertical display end reg */ + ovr = (ovr & 0xbd) + /* Overflow register */ + ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3); + fsr = (fsr & 0xe0) + (fontheight - 1); /* Font size register */ + + spin_lock_irq(&vga_lock); + outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */ + outb_p(ovr, vga_video_port_val); + outb_p(0x09, vga_video_port_reg); /* Font size */ + outb_p(fsr, vga_video_port_val); + outb_p(0x12, vga_video_port_reg); /* Vertical display limit */ + outb_p(vde, vga_video_port_val); + spin_unlock_irq(&vga_lock); + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + struct vc_data *c = vc_cons[i].d; + + if (c && c->vc_sw == &vga_con) { + if (CON_IS_VISIBLE(c)) { + /* void size to cause regs to be rewritten */ + cursor_size_lastfrom = 0; + cursor_size_lastto = 0; + c->vc_sw->con_cursor(c, CM_DRAW); + } + c->vc_font.height = fontheight; + vc_resize(c, 0, rows); /* Adjust console size */ + } + } + return 0; +} + +static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags) +{ + unsigned charcount = font->charcount; + int rc; + + if (vga_video_type < VIDEO_TYPE_EGAM) + return -EINVAL; + + if (font->width != 8 || (charcount != 256 && charcount != 512)) + return -EINVAL; + + rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512); + if (rc) + return rc; + + if (!(flags & KD_FONT_FLAG_DONT_RECALC)) + rc = vgacon_adjust_height(c, font->height); + return rc; +} + +static int vgacon_font_get(struct vc_data *c, struct console_font *font) +{ + if (vga_video_type < VIDEO_TYPE_EGAM) + return -EINVAL; + + font->width = 8; + font->height = c->vc_font.height; + font->charcount = vga_512_chars ? 512 : 256; + if (!font->data) + return 0; + return vgacon_do_font_op(&state, font->data, 0, 0); +} + +#else + +#define vgacon_font_set NULL +#define vgacon_font_get NULL + +#endif + +static int vgacon_scrolldelta(struct vc_data *c, int lines) +{ + if (!lines) /* Turn scrollback off */ + c->vc_visible_origin = c->vc_origin; + else { + int vram_size = vga_vram_end - vga_vram_base; + int margin = c->vc_size_row * 4; + int ul, we, p, st; + + if (vga_rolled_over > + (c->vc_scr_end - vga_vram_base) + margin) { + ul = c->vc_scr_end - vga_vram_base; + we = vga_rolled_over + c->vc_size_row; + } else { + ul = 0; + we = vram_size; + } + p = (c->vc_visible_origin - vga_vram_base - ul + we) % we + + lines * c->vc_size_row; + st = (c->vc_origin - vga_vram_base - ul + we) % we; + if (st < 2 * margin) + margin = 0; + if (p < margin) + p = 0; + if (p > st - margin) + p = st; + c->vc_visible_origin = vga_vram_base + (p + ul) % we; + } + vga_set_mem_top(c); + return 1; +} + +static int vgacon_set_origin(struct vc_data *c) +{ + if (vga_is_gfx || /* We don't play origin tricks in graphic modes */ + (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */ + return 0; + c->vc_origin = c->vc_visible_origin = vga_vram_base; + vga_set_mem_top(c); + vga_rolled_over = 0; + return 1; +} + +static void vgacon_save_screen(struct vc_data *c) +{ + static int vga_bootup_console = 0; + + if (!vga_bootup_console) { + /* This is a gross hack, but here is the only place we can + * set bootup console parameters without messing up generic + * console initialization routines. + */ + vga_bootup_console = 1; + c->vc_x = ORIG_X; + c->vc_y = ORIG_Y; + } + if (!vga_is_gfx) + scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, + c->vc_screenbuf_size); +} + +static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, + int lines) +{ + unsigned long oldo; + unsigned int delta; + + if (t || b != c->vc_rows || vga_is_gfx) + return 0; + + if (c->vc_origin != c->vc_visible_origin) + vgacon_scrolldelta(c, 0); + + if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2) + return 0; + + oldo = c->vc_origin; + delta = lines * c->vc_size_row; + if (dir == SM_UP) { + if (c->vc_scr_end + delta >= vga_vram_end) { + scr_memcpyw((u16 *) vga_vram_base, + (u16 *) (oldo + delta), + c->vc_screenbuf_size - delta); + c->vc_origin = vga_vram_base; + vga_rolled_over = oldo - vga_vram_base; + } else + c->vc_origin += delta; + scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size - + delta), c->vc_video_erase_char, + delta); + } else { + if (oldo - delta < vga_vram_base) { + scr_memmovew((u16 *) (vga_vram_end - + c->vc_screenbuf_size + + delta), (u16 *) oldo, + c->vc_screenbuf_size - delta); + c->vc_origin = vga_vram_end - c->vc_screenbuf_size; + vga_rolled_over = 0; + } else + c->vc_origin -= delta; + c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; + scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char, + delta); + } + c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; + c->vc_visible_origin = c->vc_origin; + vga_set_mem_top(c); + c->vc_pos = (c->vc_pos - oldo) + c->vc_origin; + return 1; +} + + +/* + * The console `switch' structure for the VGA based console + */ + +static int vgacon_dummy(struct vc_data *c) +{ + return 0; +} + +#define DUMMY (void *) vgacon_dummy + +const struct consw vga_con = { + .owner = THIS_MODULE, + .con_startup = vgacon_startup, + .con_init = vgacon_init, + .con_deinit = vgacon_deinit, + .con_clear = DUMMY, + .con_putc = DUMMY, + .con_putcs = DUMMY, + .con_cursor = vgacon_cursor, + .con_scroll = vgacon_scroll, + .con_bmove = DUMMY, + .con_switch = vgacon_switch, + .con_blank = vgacon_blank, + .con_font_set = vgacon_font_set, + .con_font_get = vgacon_font_get, + .con_set_palette = vgacon_set_palette, + .con_scrolldelta = vgacon_scrolldelta, + .con_set_origin = vgacon_set_origin, + .con_save_screen = vgacon_save_screen, + .con_build_attr = vgacon_build_attr, + .con_invert_region = vgacon_invert_region, +}; + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c new file mode 100644 index 000000000000..989e700159e0 --- /dev/null +++ b/drivers/video/controlfb.c @@ -0,0 +1,1102 @@ +/* + * controlfb.c -- frame buffer device for the PowerMac 'control' display + * + * Created 12 July 1998 by Dan Jacobowitz <dan@debian.org> + * Copyright (C) 1998 Dan Jacobowitz + * Copyright (C) 2001 Takashi Oe + * + * Mmap code by Michel Lanners <mlan@cpu.lu> + * + * Frame buffer structure from: + * drivers/video/chipsfb.c -- frame buffer device for + * Chips & Technologies 65550 chip. + * + * Copyright (C) 1998 Paul Mackerras + * + * This file is derived from the Powermac "chips" driver: + * Copyright (C) 1997 Fabio Riccardi. + * And from the frame buffer device for Open Firmware-initialized devices: + * Copyright (C) 1997 Geert Uytterhoeven. + * + * Hardware information from: + * 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. + */ + +#include <linux/config.h> +#include <linux/module.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/nvram.h> +#include <linux/adb.h> +#include <linux/cuda.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/pgtable.h> +#include <asm/btext.h> + +#include "macmodes.h" +#include "controlfb.h" + +struct fb_par_control { + int vmode, cmode; + int xres, yres; + int vxres, vyres; + int xoffset, yoffset; + int pitch; + struct control_regvals regvals; + unsigned long sync; + unsigned char ctrl; +}; + +#define DIRTY(z) ((x)->z != (y)->z) +#define DIRTY_CMAP(z) (memcmp(&((x)->z), &((y)->z), sizeof((y)->z))) +static inline int PAR_EQUAL(struct fb_par_control *x, struct fb_par_control *y) +{ + int i, results; + + results = 1; + for (i = 0; i < 3; i++) + results &= !DIRTY(regvals.clock_params[i]); + if (!results) + return 0; + for (i = 0; i < 16; i++) + results &= !DIRTY(regvals.regs[i]); + if (!results) + return 0; + return (!DIRTY(cmode) && !DIRTY(xres) && !DIRTY(yres) + && !DIRTY(vxres) && !DIRTY(vyres)); +} +static inline int VAR_MATCH(struct fb_var_screeninfo *x, struct fb_var_screeninfo *y) +{ + return (!DIRTY(bits_per_pixel) && !DIRTY(xres) + && !DIRTY(yres) && !DIRTY(xres_virtual) + && !DIRTY(yres_virtual) + && !DIRTY_CMAP(red) && !DIRTY_CMAP(green) && !DIRTY_CMAP(blue)); +} + +struct fb_info_control { + struct fb_info info; + struct fb_par_control par; + u32 pseudo_palette[17]; + + struct cmap_regs __iomem *cmap_regs; + unsigned long cmap_regs_phys; + + struct control_regs __iomem *control_regs; + unsigned long control_regs_phys; + unsigned long control_regs_size; + + __u8 __iomem *frame_buffer; + unsigned long frame_buffer_phys; + unsigned long fb_orig_base; + unsigned long fb_orig_size; + + int control_use_bank2; + unsigned long total_vram; + unsigned char vram_attr; +}; + +/* control register access macro */ +#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, + 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); +static int controlfb_blank(int blank_mode, struct fb_info *info); +static int controlfb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma); +static int controlfb_set_par (struct fb_info *info); +static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info); + +/* + * inititialization + */ +int control_init(void); +void control_setup(char *); + +/******************** Prototypes for internal functions **********************/ + +static void set_control_clock(unsigned char *params); +static int init_control(struct fb_info_control *p); +static void control_set_hardware(struct fb_info_control *p, + struct fb_par_control *par); +static int control_of_init(struct device_node *dp); +static void find_vram_size(struct fb_info_control *p); +static int read_control_sense(struct fb_info_control *p); +static int calc_clock_params(unsigned long clk, unsigned char *param); +static int control_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_control *par, const struct fb_info *fb_info); +static inline void control_par_to_var(struct fb_par_control *par, + struct fb_var_screeninfo *var); +static void control_init_info(struct fb_info *info, struct fb_info_control *p); +static void control_cleanup(void); + + +/************************** Internal variables *******************************/ + +static struct fb_info_control *control_fb; + +static int default_vmode __initdata = VMODE_NVRAM; +static int default_cmode __initdata = CMODE_NVRAM; + + +static struct fb_ops controlfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = controlfb_check_var, + .fb_set_par = controlfb_set_par, + .fb_setcolreg = controlfb_setcolreg, + .fb_pan_display = controlfb_pan_display, + .fb_blank = controlfb_blank, + .fb_mmap = controlfb_mmap, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + + +/******************** The functions for controlfb_ops ********************/ + +#ifdef MODULE +MODULE_LICENSE("GPL"); + +int init_module(void) +{ + struct device_node *dp; + + dp = find_devices("control"); + if (dp != 0 && !control_of_init(dp)) + return 0; + + return -ENXIO; +} + +void cleanup_module(void) +{ + control_cleanup(); +} +#endif + +/* + * Checks a var structure + */ +static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct fb_par_control par; + int err; + + err = control_var_to_par(var, &par, info); + if (err) + return err; + control_par_to_var(&par, var); + + return 0; +} + +/* + * Applies current var to display + */ +static int controlfb_set_par (struct fb_info *info) +{ + struct fb_info_control *p = (struct fb_info_control *) info; + struct fb_par_control par; + int err; + + if((err = control_var_to_par(&info->var, &par, info))) { + printk (KERN_ERR "controlfb_set_par: error calling" + " control_var_to_par: %d.\n", err); + return err; + } + + control_set_hardware(p, &par); + + info->fix.visual = (p->par.cmode == CMODE_8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + info->fix.line_length = p->par.pitch; + info->fix.xpanstep = 32 >> p->par.cmode; + info->fix.ypanstep = 1; + + return 0; +} + +/* + * Set screen start address according to var offset values + */ +static inline void set_screen_start(int xoffset, int yoffset, + struct fb_info_control *p) +{ + struct fb_par_control *par = &p->par; + + par->xoffset = xoffset; + par->yoffset = yoffset; + out_le32(CNTRL_REG(p,start_addr), + par->yoffset * par->pitch + (par->xoffset << par->cmode)); +} + + +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; + struct fb_par_control *par = &p->par; + + /* + * make sure start addr will be 32-byte aligned + */ + hstep = 0x1f >> par->cmode; + xoffset = (var->xoffset + hstep) & ~hstep; + + if (xoffset+par->xres > par->vxres || + var->yoffset+par->yres > par->vyres) + return -EINVAL; + + set_screen_start(xoffset, var->yoffset, p); + + return 0; +} + + +/* + * Private mmap since we want to have a different caching on the framebuffer + * for controlfb. + * Note there's no locking in here; it's done in fb_mmap() in fbmem.c. + */ +static int controlfb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + unsigned long off, start; + u32 len; + + off = vma->vm_pgoff << PAGE_SHIFT; + + /* frame buffer memory */ + start = info->fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.smem_len); + if (off >= len) { + /* memory mapped io */ + off -= len; + if (info->var.accel_flags) + return -EINVAL; + start = info->fix.mmio_start; + len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.mmio_len); + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED; + } else { + /* framebuffer */ + pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU; + } + start &= PAGE_MASK; + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + off += start; + vma->vm_pgoff = off >> PAGE_SHIFT; + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + +static int controlfb_blank(int blank_mode, struct fb_info *info) +{ + struct fb_info_control *p = (struct fb_info_control *) info; + unsigned ctrl; + + ctrl = ld_le32(CNTRL_REG(p,ctrl)); + if (blank_mode > 0) + switch (blank_mode) { + case FB_BLANK_VSYNC_SUSPEND: + ctrl &= ~3; + break; + case FB_BLANK_HSYNC_SUSPEND: + ctrl &= ~0x30; + break; + case FB_BLANK_POWERDOWN: + ctrl &= ~0x33; + /* fall through */ + case FB_BLANK_NORMAL: + ctrl |= 0x400; + break; + default: + break; + } + else { + ctrl &= ~0x400; + ctrl |= 0x33; + } + out_le32(CNTRL_REG(p,ctrl), ctrl); + + return 0; +} + +static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct fb_info_control *p = (struct fb_info_control *) info; + __u8 r, g, b; + + if (regno > 255) + return 1; + + r = red >> 8; + g = green >> 8; + b = blue >> 8; + + out_8(&p->cmap_regs->addr, regno); /* tell clut what addr to fill */ + out_8(&p->cmap_regs->lut, r); /* send one color channel at */ + out_8(&p->cmap_regs->lut, g); /* a time... */ + out_8(&p->cmap_regs->lut, b); + + if (regno < 16) { + int i; + switch (p->par.cmode) { + case CMODE_16: + p->pseudo_palette[regno] = + (regno << 10) | (regno << 5) | regno; + break; + case CMODE_32: + i = (regno << 8) | regno; + p->pseudo_palette[regno] = (i << 16) | i; + break; + } + } + + return 0; +} + + +/******************** End of controlfb_ops implementation ******************/ + + + +static void set_control_clock(unsigned char *params) +{ +#ifdef CONFIG_ADB_CUDA + struct adb_request req; + int i; + + for (i = 0; i < 3; ++i) { + cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, + 0x50, i + 1, params[i]); + while (!req.complete) + cuda_poll(); + } +#endif +} + + +/* + * finish off the driver initialization and register + */ +static int __init init_control(struct fb_info_control *p) +{ + int full, sense, vmode, cmode, vyres; + struct fb_var_screeninfo var; + int rc; + + printk(KERN_INFO "controlfb: "); + + full = p->total_vram == 0x400000; + + /* Try to pick a video mode out of NVRAM if we have one. */ + if (default_cmode == CMODE_NVRAM){ + cmode = nvram_read_byte(NV_CMODE); + if(cmode < CMODE_8 || cmode > CMODE_32) + cmode = CMODE_8; + } else + cmode=default_cmode; + + if (default_vmode == VMODE_NVRAM) { + vmode = nvram_read_byte(NV_VMODE); + if (vmode < 1 || vmode > VMODE_MAX || + control_mac_modes[vmode - 1].m[full] < cmode) { + sense = read_control_sense(p); + printk("Monitor sense value = 0x%x, ", sense); + vmode = mac_map_monitor_sense(sense); + if (control_mac_modes[vmode - 1].m[full] < cmode) + vmode = VMODE_640_480_60; + } + } else { + vmode=default_vmode; + if (control_mac_modes[vmode - 1].m[full] < cmode) { + if (cmode > CMODE_8) + cmode--; + else + vmode = VMODE_640_480_60; + } + } + + /* Initialize info structure */ + control_init_info(&p->info, p); + + /* Setup default var */ + if (mac_vmode_to_var(vmode, cmode, &var) < 0) { + /* This shouldn't happen! */ + printk("mac_vmode_to_var(%d, %d,) failed\n", vmode, cmode); +try_again: + vmode = VMODE_640_480_60; + cmode = CMODE_8; + if (mac_vmode_to_var(vmode, cmode, &var) < 0) { + printk(KERN_ERR "controlfb: mac_vmode_to_var() failed\n"); + return -ENXIO; + } + printk(KERN_INFO "controlfb: "); + } + printk("using video mode %d and color mode %d.\n", vmode, cmode); + + vyres = (p->total_vram - CTRLFB_OFF) / (var.xres << cmode); + if (vyres > var.yres) + var.yres_virtual = vyres; + + /* Apply default var */ + var.activate = FB_ACTIVATE_NOW; + rc = fb_set_var(&p->info, &var); + if (rc && (vmode != VMODE_640_480_60 || cmode != CMODE_8)) + goto try_again; + + /* Register with fbdev layer */ + if (register_framebuffer(&p->info) < 0) + return -ENXIO; + + printk(KERN_INFO "fb%d: control display adapter\n", p->info.node); + + return 0; +} + +#define RADACAL_WRITE(a,d) \ + out_8(&p->cmap_regs->addr, (a)); \ + out_8(&p->cmap_regs->dat, (d)) + +/* Now how about actually saying, Make it so! */ +/* Some things in here probably don't need to be done each time. */ +static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par) +{ + struct control_regvals *r; + volatile struct preg __iomem *rp; + int i, cmode; + + if (PAR_EQUAL(&p->par, par)) { + /* + * check if only xoffset or yoffset differs. + * this prevents flickers in typical VT switch case. + */ + if (p->par.xoffset != par->xoffset || + p->par.yoffset != par->yoffset) + set_screen_start(par->xoffset, par->yoffset, p); + + return; + } + + p->par = *par; + cmode = p->par.cmode; + r = &par->regvals; + + /* Turn off display */ + out_le32(CNTRL_REG(p,ctrl), 0x400 | par->ctrl); + + set_control_clock(r->clock_params); + + RADACAL_WRITE(0x20, r->radacal_ctrl); + RADACAL_WRITE(0x21, p->control_use_bank2 ? 0 : 1); + RADACAL_WRITE(0x10, 0); + RADACAL_WRITE(0x11, 0); + + rp = &p->control_regs->vswin; + for (i = 0; i < 16; ++i, ++rp) + out_le32(&rp->r, r->regs[i]); + + out_le32(CNTRL_REG(p,pitch), par->pitch); + out_le32(CNTRL_REG(p,mode), r->mode); + out_le32(CNTRL_REG(p,vram_attr), p->vram_attr); + out_le32(CNTRL_REG(p,start_addr), par->yoffset * par->pitch + + (par->xoffset << cmode)); + out_le32(CNTRL_REG(p,rfrcnt), 0x1e5); + out_le32(CNTRL_REG(p,intr_ena), 0); + + /* Turn on display */ + out_le32(CNTRL_REG(p,ctrl), par->ctrl); + +#ifdef CONFIG_BOOTX_TEXT + btext_update_display(p->frame_buffer_phys + CTRLFB_OFF, + p->par.xres, p->par.yres, + (cmode == CMODE_32? 32: cmode == CMODE_16? 16: 8), + p->par.pitch); +#endif /* CONFIG_BOOTX_TEXT */ +} + + +/* + * Called from fbmem.c for probing & initializing + */ +int __init control_init(void) +{ + struct device_node *dp; + char *option = NULL; + + if (fb_get_options("controlfb", &option)) + return -ENODEV; + control_setup(option); + + dp = find_devices("control"); + if (dp != 0 && !control_of_init(dp)) + return 0; + + return -ENXIO; +} + +module_init(control_init); + +/* Work out which banks of VRAM we have installed. */ +/* danj: I guess the card just ignores writes to nonexistant VRAM... */ + +static void __init find_vram_size(struct fb_info_control *p) +{ + int bank1, bank2; + + /* + * Set VRAM in 2MB (bank 1) mode + * VRAM Bank 2 will be accessible through offset 0x600000 if present + * and VRAM Bank 1 will not respond at that offset even if present + */ + out_le32(CNTRL_REG(p,vram_attr), 0x31); + + out_8(&p->frame_buffer[0x600000], 0xb3); + out_8(&p->frame_buffer[0x600001], 0x71); + asm volatile("eieio; dcbf 0,%0" : : "r" (&p->frame_buffer[0x600000]) + : "memory" ); + mb(); + asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000]) + : "memory" ); + mb(); + + bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xb3) + && (in_8(&p->frame_buffer[0x600001]) == 0x71); + + /* + * Set VRAM in 2MB (bank 2) mode + * VRAM Bank 1 will be accessible through offset 0x000000 if present + * and VRAM Bank 2 will not respond at that offset even if present + */ + out_le32(CNTRL_REG(p,vram_attr), 0x39); + + out_8(&p->frame_buffer[0], 0x5a); + out_8(&p->frame_buffer[1], 0xc7); + asm volatile("eieio; dcbf 0,%0" : : "r" (&p->frame_buffer[0]) + : "memory" ); + mb(); + asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0]) + : "memory" ); + mb(); + + bank1 = (in_8(&p->frame_buffer[0]) == 0x5a) + && (in_8(&p->frame_buffer[1]) == 0xc7); + + if (bank2) { + if (!bank1) { + /* + * vram bank 2 only + */ + p->control_use_bank2 = 1; + p->vram_attr = 0x39; + p->frame_buffer += 0x600000; + p->frame_buffer_phys += 0x600000; + } else { + /* + * 4 MB vram + */ + p->vram_attr = 0x51; + } + } else { + /* + * vram bank 1 only + */ + p->vram_attr = 0x31; + } + + p->total_vram = (bank1 + bank2) * 0x200000; + + printk(KERN_INFO "controlfb: VRAM Total = %dMB " + "(%dMB @ bank 1, %dMB @ bank 2)\n", + (bank1 + bank2) << 1, bank1 << 1, bank2 << 1); +} + + +/* + * find "control" and initialize + */ +static int __init control_of_init(struct device_node *dp) +{ + struct fb_info_control *p; + unsigned long addr; + int i; + + if (control_fb) { + printk(KERN_ERR "controlfb: only one control is supported\n"); + return -ENXIO; + } + if(dp->n_addrs != 2) { + printk(KERN_ERR "expecting 2 address for control (got %d)", dp->n_addrs); + return -ENXIO; + } + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (p == 0) + return -ENXIO; + control_fb = p; /* save it for cleanups */ + memset(p, 0, sizeof(*p)); + + /* Map in frame buffer and registers */ + for (i = 0; i < dp->n_addrs; ++i) { + addr = dp->addrs[i].address; + if (dp->addrs[i].size >= 0x800000) { + p->fb_orig_base = addr; + p->fb_orig_size = dp->addrs[i].size; + /* use the big-endian aperture (??) */ + p->frame_buffer_phys = addr + 0x800000; + } else { + p->control_regs_phys = addr; + p->control_regs_size = dp->addrs[i].size; + } + } + + if (!p->fb_orig_base || + !request_mem_region(p->fb_orig_base,p->fb_orig_size,"controlfb")) { + p->fb_orig_base = 0; + goto error_out; + } + /* map at most 8MB for the frame buffer */ + p->frame_buffer = __ioremap(p->frame_buffer_phys, 0x800000, + _PAGE_WRITETHRU); + + if (!p->control_regs_phys || + !request_mem_region(p->control_regs_phys, p->control_regs_size, + "controlfb regs")) { + p->control_regs_phys = 0; + goto error_out; + } + p->control_regs = ioremap(p->control_regs_phys, p->control_regs_size); + + p->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ + if (!request_mem_region(p->cmap_regs_phys, 0x1000, "controlfb cmap")) { + p->cmap_regs_phys = 0; + goto error_out; + } + p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000); + + if (!p->cmap_regs || !p->control_regs || !p->frame_buffer) + goto error_out; + + find_vram_size(p); + if (!p->total_vram) + goto error_out; + + if (init_control(p) < 0) + goto error_out; + + return 0; + +error_out: + control_cleanup(); + return -ENXIO; +} + +/* + * Get the monitor sense value. + * Note that this can be called before calibrate_delay, + * so we can't use udelay. + */ +static int read_control_sense(struct fb_info_control *p) +{ + int sense; + + out_le32(CNTRL_REG(p,mon_sense), 7); /* drive all lines high */ + __delay(200); + out_le32(CNTRL_REG(p,mon_sense), 077); /* turn off drivers */ + __delay(2000); + sense = (in_le32(CNTRL_REG(p,mon_sense)) & 0x1c0) << 2; + + /* drive each sense line low in turn and collect the other 2 */ + out_le32(CNTRL_REG(p,mon_sense), 033); /* drive A low */ + __delay(2000); + sense |= (in_le32(CNTRL_REG(p,mon_sense)) & 0xc0) >> 2; + out_le32(CNTRL_REG(p,mon_sense), 055); /* drive B low */ + __delay(2000); + sense |= ((in_le32(CNTRL_REG(p,mon_sense)) & 0x100) >> 5) + | ((in_le32(CNTRL_REG(p,mon_sense)) & 0x40) >> 4); + out_le32(CNTRL_REG(p,mon_sense), 066); /* drive C low */ + __delay(2000); + sense |= (in_le32(CNTRL_REG(p,mon_sense)) & 0x180) >> 7; + + out_le32(CNTRL_REG(p,mon_sense), 077); /* turn off drivers */ + + return sense; +} + +/********************** Various translation functions **********************/ + +#define CONTROL_PIXCLOCK_BASE 256016 +#define CONTROL_PIXCLOCK_MIN 5000 /* ~ 200 MHz dot clock */ + +/* + * calculate the clock paramaters to be sent to CUDA according to given + * pixclock in pico second. + */ +static int calc_clock_params(unsigned long clk, unsigned char *param) +{ + unsigned long p0, p1, p2, k, l, m, n, min; + + if (clk > (CONTROL_PIXCLOCK_BASE << 3)) + return 1; + + p2 = ((clk << 4) < CONTROL_PIXCLOCK_BASE)? 3: 2; + l = clk << p2; + p0 = 0; + p1 = 0; + for (k = 1, min = l; k < 32; k++) { + unsigned long rem; + + m = CONTROL_PIXCLOCK_BASE * k; + n = m / l; + rem = m % l; + if (n && (n < 128) && rem < min) { + p0 = k; + p1 = n; + min = rem; + } + } + if (!p0 || !p1) + return 1; + + param[0] = p0; + param[1] = p1; + param[2] = p2; + + return 0; +} + + +/* + * This routine takes a user-supplied var, and picks the best vmode/cmode + * from it. + */ + +static int control_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_control *par, const struct fb_info *fb_info) +{ + int cmode, piped_diff, hstep; + unsigned hperiod, hssync, hsblank, hesync, heblank, piped, heq, hlfln, + hserr, vperiod, vssync, vesync, veblank, vsblank, vswin, vewin; + unsigned long pixclock; + struct fb_info_control *p = (struct fb_info_control *) fb_info; + struct control_regvals *r = &par->regvals; + + switch (var->bits_per_pixel) { + case 8: + par->cmode = CMODE_8; + if (p->total_vram > 0x200000) { + r->mode = 3; + r->radacal_ctrl = 0x20; + piped_diff = 13; + } else { + r->mode = 2; + r->radacal_ctrl = 0x10; + piped_diff = 9; + } + break; + case 15: + case 16: + par->cmode = CMODE_16; + if (p->total_vram > 0x200000) { + r->mode = 2; + r->radacal_ctrl = 0x24; + piped_diff = 5; + } else { + r->mode = 1; + r->radacal_ctrl = 0x14; + piped_diff = 3; + } + break; + case 32: + par->cmode = CMODE_32; + if (p->total_vram > 0x200000) { + r->mode = 1; + r->radacal_ctrl = 0x28; + } else { + r->mode = 0; + r->radacal_ctrl = 0x18; + } + piped_diff = 1; + break; + default: + return -EINVAL; + } + + /* + * adjust xres and vxres so that the corresponding memory widths are + * 32-byte aligned + */ + hstep = 31 >> par->cmode; + par->xres = (var->xres + hstep) & ~hstep; + par->vxres = (var->xres_virtual + hstep) & ~hstep; + par->xoffset = (var->xoffset + hstep) & ~hstep; + if (par->vxres < par->xres) + par->vxres = par->xres; + par->pitch = par->vxres << par->cmode; + + par->yres = var->yres; + par->vyres = var->yres_virtual; + par->yoffset = var->yoffset; + if (par->vyres < par->yres) + par->vyres = par->yres; + + par->sync = var->sync; + + if (par->pitch * par->vyres + CTRLFB_OFF > p->total_vram) + return -EINVAL; + + if (par->xoffset + par->xres > par->vxres) + par->xoffset = par->vxres - par->xres; + if (par->yoffset + par->yres > par->vyres) + par->yoffset = par->vyres - par->yres; + + pixclock = (var->pixclock < CONTROL_PIXCLOCK_MIN)? CONTROL_PIXCLOCK_MIN: + var->pixclock; + if (calc_clock_params(pixclock, r->clock_params)) + return -EINVAL; + + hperiod = ((var->left_margin + par->xres + var->right_margin + + var->hsync_len) >> 1) - 2; + hssync = hperiod + 1; + hsblank = hssync - (var->right_margin >> 1); + hesync = (var->hsync_len >> 1) - 1; + heblank = (var->left_margin >> 1) + hesync; + piped = heblank - piped_diff; + heq = var->hsync_len >> 2; + hlfln = (hperiod+2) >> 1; + hserr = hssync-hesync; + vperiod = (var->vsync_len + var->lower_margin + par->yres + + var->upper_margin) << 1; + vssync = vperiod - 2; + vesync = (var->vsync_len << 1) - vperiod + vssync; + veblank = (var->upper_margin << 1) + vesync; + vsblank = vssync - (var->lower_margin << 1); + vswin = (vsblank+vssync) >> 1; + vewin = (vesync+veblank) >> 1; + + r->regs[0] = vswin; + r->regs[1] = vsblank; + r->regs[2] = veblank; + r->regs[3] = vewin; + r->regs[4] = vesync; + r->regs[5] = vssync; + r->regs[6] = vperiod; + r->regs[7] = piped; + r->regs[8] = hperiod; + r->regs[9] = hsblank; + r->regs[10] = heblank; + r->regs[11] = hesync; + r->regs[12] = hssync; + r->regs[13] = heq; + r->regs[14] = hlfln; + r->regs[15] = hserr; + + if (par->xres >= 1280 && par->cmode >= CMODE_16) + par->ctrl = 0x7f; + else + par->ctrl = 0x3b; + + if (mac_var_to_vmode(var, &par->vmode, &cmode)) + par->vmode = 0; + + return 0; +} + + +/* + * Convert hardware data in par to an fb_var_screeninfo + */ + +static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var) +{ + struct control_regints *rv; + + rv = (struct control_regints *) par->regvals.regs; + + memset(var, 0, sizeof(*var)); + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->vxres; + var->yres_virtual = par->vyres; + var->xoffset = par->xoffset; + var->yoffset = par->yoffset; + + switch(par->cmode) { + default: + case CMODE_8: + var->bits_per_pixel = 8; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + break; + case CMODE_16: /* RGB 555 */ + var->bits_per_pixel = 16; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.length = 5; + break; + case CMODE_32: /* RGB 888 */ + var->bits_per_pixel = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + } + var->height = -1; + var->width = -1; + var->vmode = FB_VMODE_NONINTERLACED; + + var->left_margin = (rv->heblank - rv->hesync) << 1; + var->right_margin = (rv->hssync - rv->hsblank) << 1; + var->hsync_len = (rv->hperiod + 2 - rv->hssync + rv->hesync) << 1; + + var->upper_margin = (rv->veblank - rv->vesync) >> 1; + var->lower_margin = (rv->vssync - rv->vsblank) >> 1; + var->vsync_len = (rv->vperiod - rv->vssync + rv->vesync) >> 1; + + var->sync = par->sync; + + /* + * 10^12 * clock_params[0] / (3906400 * clock_params[1] + * * 2^clock_params[2]) + * (10^12 * clock_params[0] / (3906400 * clock_params[1])) + * >> clock_params[2] + */ + /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */ + var->pixclock = CONTROL_PIXCLOCK_BASE * par->regvals.clock_params[0]; + var->pixclock /= par->regvals.clock_params[1]; + var->pixclock >>= par->regvals.clock_params[2]; +} + +/* + * Set misc info vars for this driver + */ +static void __init control_init_info(struct fb_info *info, struct fb_info_control *p) +{ + /* Fill fb_info */ + info->par = &p->par; + info->fbops = &controlfb_ops; + info->pseudo_palette = p->pseudo_palette; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + info->screen_base = p->frame_buffer + CTRLFB_OFF; + + fb_alloc_cmap(&info->cmap, 256, 0); + + /* Fill fix common fields */ + strcpy(info->fix.id, "control"); + info->fix.mmio_start = p->control_regs_phys; + info->fix.mmio_len = sizeof(struct control_regs); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.smem_start = p->frame_buffer_phys + CTRLFB_OFF; + info->fix.smem_len = p->total_vram - CTRLFB_OFF; + info->fix.ywrapstep = 0; + info->fix.type_aux = 0; + info->fix.accel = FB_ACCEL_NONE; +} + + +static void control_cleanup(void) +{ + struct fb_info_control *p = control_fb; + + if (!p) + return; + + if (p->cmap_regs) + iounmap(p->cmap_regs); + if (p->control_regs) + iounmap(p->control_regs); + if (p->frame_buffer) { + if (p->control_use_bank2) + p->frame_buffer -= 0x600000; + iounmap(p->frame_buffer); + } + if (p->cmap_regs_phys) + release_mem_region(p->cmap_regs_phys, 0x1000); + if (p->control_regs_phys) + release_mem_region(p->control_regs_phys, p->control_regs_size); + if (p->fb_orig_base) + release_mem_region(p->fb_orig_base, p->fb_orig_size); + kfree(p); +} + + +/* + * Parse user speficied options (`video=controlfb:') + */ +void __init control_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "vmode:", 6)) { + int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX && + control_mac_modes[vmode - 1].m[1] >= 0) + default_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + int depth = simple_strtoul(this_opt+6, NULL, 0); + switch (depth) { + case CMODE_8: + case CMODE_16: + case CMODE_32: + default_cmode = depth; + break; + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + case 24: + case 32: + default_cmode = CMODE_32; + break; + } + } + } +} + diff --git a/drivers/video/controlfb.h b/drivers/video/controlfb.h new file mode 100644 index 000000000000..6026c60fc100 --- /dev/null +++ b/drivers/video/controlfb.h @@ -0,0 +1,145 @@ +/* + * controlfb_hw.h: Constants of all sorts for controlfb + * + * Copyright (C) 1998 Daniel Jacobowitz <dan@debian.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Based on an awful lot of code, including: + * + * control.c: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1996 Paul Mackerras. + * + * The so far unpublished platinumfb.c + * Copyright (C) 1998 Jon Howell + */ + +/* + * Structure of the registers for the RADACAL colormap device. + */ +struct cmap_regs { + unsigned char addr; /* index for both cmap and misc registers */ + char pad1[15]; + unsigned char crsr; /* cursor palette */ + char pad2[15]; + unsigned char dat; /* RADACAL misc register data */ + char pad3[15]; + unsigned char lut; /* cmap data */ + char pad4[15]; +}; + +/* + * Structure of the registers for the "control" display adaptor. + */ +#define PAD(x) char x[12] + +struct preg { /* padded register */ + unsigned r; + char pad[12]; +}; + +struct control_regs { + struct preg vcount; /* vertical counter */ + /* Vertical parameters are in units of 1/2 scan line */ + struct preg vswin; /* between vsblank and vssync */ + struct preg vsblank; /* vert start blank */ + struct preg veblank; /* vert end blank (display start) */ + struct preg vewin; /* between vesync and veblank */ + struct preg vesync; /* vert end sync */ + struct preg vssync; /* vert start sync */ + struct preg vperiod; /* vert period */ + struct preg piped; /* pipe delay hardware cursor */ + /* Horizontal params are in units of 2 pixels */ + struct preg hperiod; /* horiz period - 2 */ + struct preg hsblank; /* horiz start blank */ + struct preg heblank; /* horiz end blank */ + struct preg hesync; /* horiz end sync */ + struct preg hssync; /* horiz start sync */ + struct preg heq; /* half horiz sync len */ + struct preg hlfln; /* half horiz period */ + struct preg hserr; /* horiz period - horiz sync len */ + struct preg cnttst; + struct preg ctrl; /* display control */ + struct preg start_addr; /* start address: 5 lsbs zero */ + struct preg pitch; /* addrs diff between scan lines */ + struct preg mon_sense; /* monitor sense bits */ + struct preg vram_attr; /* enable vram banks */ + struct preg mode; + struct preg rfrcnt; /* refresh count */ + struct preg intr_ena; /* interrupt enable */ + struct preg intr_stat; /* interrupt status */ + struct preg res[5]; +}; + +struct control_regints { + /* Vertical parameters are in units of 1/2 scan line */ + unsigned vswin; /* between vsblank and vssync */ + unsigned vsblank; /* vert start blank */ + unsigned veblank; /* vert end blank (display start) */ + unsigned vewin; /* between vesync and veblank */ + unsigned vesync; /* vert end sync */ + unsigned vssync; /* vert start sync */ + unsigned vperiod; /* vert period */ + unsigned piped; /* pipe delay hardware cursor */ + /* Horizontal params are in units of 2 pixels */ + /* Except, apparently, for hres > 1024 (or == 1280?) */ + unsigned hperiod; /* horiz period - 2 */ + unsigned hsblank; /* horiz start blank */ + unsigned heblank; /* horiz end blank */ + unsigned hesync; /* horiz end sync */ + unsigned hssync; /* horiz start sync */ + unsigned heq; /* half horiz sync len */ + unsigned hlfln; /* half horiz period */ + unsigned hserr; /* horiz period - horiz sync len */ +}; + +/* + * Dot clock rate is + * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0]. + */ +struct control_regvals { + unsigned regs[16]; /* for vswin .. hserr */ + unsigned char mode; + unsigned char radacal_ctrl; + unsigned char clock_params[3]; +}; + +#define CTRLFB_OFF 16 /* position of pixel 0 in frame buffer */ + + +/* + * Best cmode supported by control + */ +struct max_cmodes { + int m[2]; /* 0: 2MB vram, 1: 4MB vram */ +}; + +/* + * Video modes supported by macmodes.c + */ +static struct max_cmodes control_mac_modes[] = { + {{-1,-1}}, /* 512x384, 60Hz interlaced (NTSC) */ + {{-1,-1}}, /* 512x384, 60Hz */ + {{-1,-1}}, /* 640x480, 50Hz interlaced (PAL) */ + {{-1,-1}}, /* 640x480, 60Hz interlaced (NTSC) */ + {{ 2, 2}}, /* 640x480, 60Hz (VGA) */ + {{ 2, 2}}, /* 640x480, 67Hz */ + {{-1,-1}}, /* 640x870, 75Hz (portrait) */ + {{-1,-1}}, /* 768x576, 50Hz (PAL full frame) */ + {{ 2, 2}}, /* 800x600, 56Hz */ + {{ 2, 2}}, /* 800x600, 60Hz */ + {{ 2, 2}}, /* 800x600, 72Hz */ + {{ 2, 2}}, /* 800x600, 75Hz */ + {{ 1, 2}}, /* 832x624, 75Hz */ + {{ 1, 2}}, /* 1024x768, 60Hz */ + {{ 1, 2}}, /* 1024x768, 70Hz (or 72Hz?) */ + {{ 1, 2}}, /* 1024x768, 75Hz (VESA) */ + {{ 1, 2}}, /* 1024x768, 75Hz */ + {{ 1, 2}}, /* 1152x870, 75Hz */ + {{ 0, 1}}, /* 1280x960, 75Hz */ + {{ 0, 1}}, /* 1280x1024, 75Hz */ +}; + diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c new file mode 100644 index 000000000000..8b1b7c687a99 --- /dev/null +++ b/drivers/video/cyber2000fb.c @@ -0,0 +1,1761 @@ +/* + * linux/drivers/video/cyber2000fb.c + * + * Copyright (C) 1998-2002 Russell King + * + * MIPS and 50xx clock support + * Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com> + * + * 32 bit support, text color and panning fixes for modes != 8 bit + * Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device + * + * Based on cyberfb.c. + * + * Note that we now use the new fbcon fix, var and cmap scheme. We do + * still have to check which console is the currently displayed one + * however, especially for the colourmap stuff. + * + * We also use the new hotplug PCI subsystem. I'm not sure if there + * are any such cards, but I'm erring on the side of caution. We don't + * want to go pop just because someone does have one. + * + * Note that this doesn't work fully in the case of multiple CyberPro + * cards with grabbers. We currently can only attach to the first + * CyberPro card found. + * + * When we're in truecolour mode, we power down the LUT RAM as a power + * saving feature. Also, when we enter any of the powersaving modes + * (except soft blanking) we power down the RAMDACs. This saves about + * 1W, which is roughly 8% of the power consumption of a NetWinder + * (which, incidentally, is about the same saving as a 2.5in hard disk + * entering standby mode.) + */ +#include <linux/config.h> +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/uaccess.h> + +#ifdef __arm__ +#include <asm/mach-types.h> +#endif + +#include "cyber2000fb.h" + +struct cfb_info { + struct fb_info fb; + struct display_switch *dispsw; + struct display *display; + struct pci_dev *dev; + unsigned char __iomem *region; + unsigned char __iomem *regs; + u_int id; + int func_use_count; + u_long ref_ps; + + /* + * Clock divisors + */ + u_int divisors[4]; + + struct { + u8 red, green, blue; + } palette[NR_PALETTE]; + + u_char mem_ctl1; + u_char mem_ctl2; + u_char mclk_mult; + u_char mclk_div; + /* + * RAMDAC control register is both of these or'ed together + */ + u_char ramdac_ctrl; + u_char ramdac_powerdown; +}; + +static char *default_font = "Acorn8x8"; +module_param(default_font, charp, 0); +MODULE_PARM_DESC(default_font, "Default font name"); + +/* + * Our access methods. + */ +#define cyber2000fb_writel(val,reg,cfb) writel(val, (cfb)->regs + (reg)) +#define cyber2000fb_writew(val,reg,cfb) writew(val, (cfb)->regs + (reg)) +#define cyber2000fb_writeb(val,reg,cfb) writeb(val, (cfb)->regs + (reg)) + +#define cyber2000fb_readb(reg,cfb) readb((cfb)->regs + (reg)) + +static inline void +cyber2000_crtcw(unsigned int reg, unsigned int val, struct cfb_info *cfb) +{ + cyber2000fb_writew((reg & 255) | val << 8, 0x3d4, cfb); +} + +static inline void +cyber2000_grphw(unsigned int reg, unsigned int val, struct cfb_info *cfb) +{ + cyber2000fb_writew((reg & 255) | val << 8, 0x3ce, cfb); +} + +static inline unsigned int +cyber2000_grphr(unsigned int reg, struct cfb_info *cfb) +{ + cyber2000fb_writeb(reg, 0x3ce, cfb); + return cyber2000fb_readb(0x3cf, cfb); +} + +static inline void +cyber2000_attrw(unsigned int reg, unsigned int val, struct cfb_info *cfb) +{ + cyber2000fb_readb(0x3da, cfb); + cyber2000fb_writeb(reg, 0x3c0, cfb); + cyber2000fb_readb(0x3c1, cfb); + cyber2000fb_writeb(val, 0x3c0, cfb); +} + +static inline void +cyber2000_seqw(unsigned int reg, unsigned int val, struct cfb_info *cfb) +{ + cyber2000fb_writew((reg & 255) | val << 8, 0x3c4, cfb); +} + +/* -------------------- Hardware specific routines ------------------------- */ + +/* + * Hardware Cyber2000 Acceleration + */ +static void +cyber2000fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct cfb_info *cfb = (struct cfb_info *)info; + unsigned long dst, col; + + if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) { + cfb_fillrect(info, rect); + return; + } + + cyber2000fb_writeb(0, CO_REG_CONTROL, cfb); + cyber2000fb_writew(rect->width - 1, CO_REG_PIXWIDTH, cfb); + cyber2000fb_writew(rect->height - 1, CO_REG_PIXHEIGHT, cfb); + + col = rect->color; + if (cfb->fb.var.bits_per_pixel > 8) + col = ((u32 *)cfb->fb.pseudo_palette)[col]; + cyber2000fb_writel(col, CO_REG_FGCOLOUR, cfb); + + dst = rect->dx + rect->dy * cfb->fb.var.xres_virtual; + if (cfb->fb.var.bits_per_pixel == 24) { + cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb); + dst *= 3; + } + + cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb); + cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb); + cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb); + cyber2000fb_writew(CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb); +} + +static void +cyber2000fb_copyarea(struct fb_info *info, const struct fb_copyarea *region) +{ + struct cfb_info *cfb = (struct cfb_info *)info; + unsigned int cmd = CO_CMD_L_PATTERN_FGCOL; + unsigned long src, dst; + + if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) { + cfb_copyarea(info, region); + return; + } + + cyber2000fb_writeb(0, CO_REG_CONTROL, cfb); + cyber2000fb_writew(region->width - 1, CO_REG_PIXWIDTH, cfb); + cyber2000fb_writew(region->height - 1, CO_REG_PIXHEIGHT, cfb); + + src = region->sx + region->sy * cfb->fb.var.xres_virtual; + dst = region->dx + region->dy * cfb->fb.var.xres_virtual; + + if (region->sx < region->dx) { + src += region->width - 1; + dst += region->width - 1; + cmd |= CO_CMD_L_INC_LEFT; + } + + if (region->sy < region->dy) { + src += (region->height - 1) * cfb->fb.var.xres_virtual; + dst += (region->height - 1) * cfb->fb.var.xres_virtual; + cmd |= CO_CMD_L_INC_UP; + } + + if (cfb->fb.var.bits_per_pixel == 24) { + cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb); + src *= 3; + dst *= 3; + } + cyber2000fb_writel(src, CO_REG_SRC1_PTR, cfb); + cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb); + cyber2000fb_writew(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb); + cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb); + cyber2000fb_writew(CO_CMD_H_FGSRCMAP | CO_CMD_H_BLITTER, + CO_REG_CMD_H, cfb); +} + +static void +cyber2000fb_imageblit(struct fb_info *info, const struct fb_image *image) +{ +// struct cfb_info *cfb = (struct cfb_info *)info; + +// if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) { + cfb_imageblit(info, image); + return; +// } +} + +static int cyber2000fb_sync(struct fb_info *info) +{ + struct cfb_info *cfb = (struct cfb_info *)info; + int count = 100000; + + if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) + return 0; + + while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & CO_CTRL_BUSY) { + if (!count--) { + debug_printf("accel_wait timed out\n"); + cyber2000fb_writeb(0, CO_REG_CONTROL, cfb); + break; + } + udelay(1); + } + return 0; +} + +/* + * =========================================================================== + */ + +static inline u32 convert_bitfield(u_int val, struct fb_bitfield *bf) +{ + u_int mask = (1 << bf->length) - 1; + + return (val >> (16 - bf->length) & mask) << bf->offset; +} + +/* + * Set a single color register. Return != 0 for invalid regno. + */ +static int +cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct cfb_info *cfb = (struct cfb_info *)info; + struct fb_var_screeninfo *var = &cfb->fb.var; + u32 pseudo_val; + int ret = 1; + + switch (cfb->fb.fix.visual) { + default: + return 1; + + /* + * Pseudocolour: + * 8 8 + * pixel --/--+--/--> red lut --> red dac + * | 8 + * +--/--> green lut --> green dac + * | 8 + * +--/--> blue lut --> blue dac + */ + case FB_VISUAL_PSEUDOCOLOR: + if (regno >= NR_PALETTE) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + cfb->palette[regno].red = red; + cfb->palette[regno].green = green; + cfb->palette[regno].blue = blue; + + cyber2000fb_writeb(regno, 0x3c8, cfb); + cyber2000fb_writeb(red, 0x3c9, cfb); + cyber2000fb_writeb(green, 0x3c9, cfb); + cyber2000fb_writeb(blue, 0x3c9, cfb); + return 0; + + /* + * Direct colour: + * n rl + * pixel --/--+--/--> red lut --> red dac + * | gl + * +--/--> green lut --> green dac + * | bl + * +--/--> blue lut --> blue dac + * n = bpp, rl = red length, gl = green length, bl = blue length + */ + case FB_VISUAL_DIRECTCOLOR: + red >>= 8; + green >>= 8; + blue >>= 8; + + if (var->green.length == 6 && regno < 64) { + cfb->palette[regno << 2].green = green; + + /* + * The 6 bits of the green component are applied + * to the high 6 bits of the LUT. + */ + cyber2000fb_writeb(regno << 2, 0x3c8, cfb); + cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb); + cyber2000fb_writeb(green, 0x3c9, cfb); + cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb); + + green = cfb->palette[regno << 3].green; + + ret = 0; + } + + if (var->green.length >= 5 && regno < 32) { + cfb->palette[regno << 3].red = red; + cfb->palette[regno << 3].green = green; + cfb->palette[regno << 3].blue = blue; + + /* + * The 5 bits of each colour component are + * applied to the high 5 bits of the LUT. + */ + cyber2000fb_writeb(regno << 3, 0x3c8, cfb); + cyber2000fb_writeb(red, 0x3c9, cfb); + cyber2000fb_writeb(green, 0x3c9, cfb); + cyber2000fb_writeb(blue, 0x3c9, cfb); + ret = 0; + } + + if (var->green.length == 4 && regno < 16) { + cfb->palette[regno << 4].red = red; + cfb->palette[regno << 4].green = green; + cfb->palette[regno << 4].blue = blue; + + /* + * The 5 bits of each colour component are + * applied to the high 5 bits of the LUT. + */ + cyber2000fb_writeb(regno << 4, 0x3c8, cfb); + cyber2000fb_writeb(red, 0x3c9, cfb); + cyber2000fb_writeb(green, 0x3c9, cfb); + cyber2000fb_writeb(blue, 0x3c9, cfb); + ret = 0; + } + + /* + * Since this is only used for the first 16 colours, we + * don't have to care about overflowing for regno >= 32 + */ + pseudo_val = regno << var->red.offset | + regno << var->green.offset | + regno << var->blue.offset; + break; + + /* + * True colour: + * n rl + * pixel --/--+--/--> red dac + * | gl + * +--/--> green dac + * | bl + * +--/--> blue dac + * n = bpp, rl = red length, gl = green length, bl = blue length + */ + case FB_VISUAL_TRUECOLOR: + pseudo_val = convert_bitfield(transp ^ 0xffff, &var->transp); + pseudo_val |= convert_bitfield(red, &var->red); + pseudo_val |= convert_bitfield(green, &var->green); + pseudo_val |= convert_bitfield(blue, &var->blue); + break; + } + + /* + * Now set our pseudo palette for the CFB16/24/32 drivers. + */ + if (regno < 16) + ((u32 *)cfb->fb.pseudo_palette)[regno] = pseudo_val; + + return ret; +} + +struct par_info { + /* + * Hardware + */ + u_char clock_mult; + u_char clock_div; + u_char extseqmisc; + u_char co_pixfmt; + u_char crtc_ofl; + u_char crtc[19]; + u_int width; + u_int pitch; + u_int fetch; + + /* + * Other + */ + u_char ramdac; +}; + +static const u_char crtc_idx[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 +}; + +static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb) +{ + unsigned int i; + unsigned int val = cfb->ramdac_ctrl | cfb->ramdac_powerdown; + + cyber2000fb_writeb(0x56, 0x3ce, cfb); + i = cyber2000fb_readb(0x3cf, cfb); + cyber2000fb_writeb(i | 4, 0x3cf, cfb); + cyber2000fb_writeb(val, 0x3c6, cfb); + cyber2000fb_writeb(i, 0x3cf, cfb); +} + +static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) +{ + u_int i; + + /* + * Blank palette + */ + for (i = 0; i < NR_PALETTE; i++) { + cyber2000fb_writeb(i, 0x3c8, cfb); + cyber2000fb_writeb(0, 0x3c9, cfb); + cyber2000fb_writeb(0, 0x3c9, cfb); + cyber2000fb_writeb(0, 0x3c9, cfb); + } + + cyber2000fb_writeb(0xef, 0x3c2, cfb); + cyber2000_crtcw(0x11, 0x0b, cfb); + cyber2000_attrw(0x11, 0x00, cfb); + + cyber2000_seqw(0x00, 0x01, cfb); + cyber2000_seqw(0x01, 0x01, cfb); + cyber2000_seqw(0x02, 0x0f, cfb); + cyber2000_seqw(0x03, 0x00, cfb); + cyber2000_seqw(0x04, 0x0e, cfb); + cyber2000_seqw(0x00, 0x03, cfb); + + for (i = 0; i < sizeof(crtc_idx); i++) + cyber2000_crtcw(crtc_idx[i], hw->crtc[i], cfb); + + for (i = 0x0a; i < 0x10; i++) + cyber2000_crtcw(i, 0, cfb); + + cyber2000_grphw(EXT_CRT_VRTOFL, hw->crtc_ofl, cfb); + cyber2000_grphw(0x00, 0x00, cfb); + cyber2000_grphw(0x01, 0x00, cfb); + cyber2000_grphw(0x02, 0x00, cfb); + cyber2000_grphw(0x03, 0x00, cfb); + cyber2000_grphw(0x04, 0x00, cfb); + cyber2000_grphw(0x05, 0x60, cfb); + cyber2000_grphw(0x06, 0x05, cfb); + cyber2000_grphw(0x07, 0x0f, cfb); + cyber2000_grphw(0x08, 0xff, cfb); + + /* Attribute controller registers */ + for (i = 0; i < 16; i++) + cyber2000_attrw(i, i, cfb); + + cyber2000_attrw(0x10, 0x01, cfb); + cyber2000_attrw(0x11, 0x00, cfb); + cyber2000_attrw(0x12, 0x0f, cfb); + cyber2000_attrw(0x13, 0x00, cfb); + cyber2000_attrw(0x14, 0x00, cfb); + + /* PLL registers */ + cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb); + cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb); + cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb); + cyber2000_grphw(EXT_MCLK_DIV, cfb->mclk_div, cfb); + cyber2000_grphw(0x90, 0x01, cfb); + cyber2000_grphw(0xb9, 0x80, cfb); + cyber2000_grphw(0xb9, 0x00, cfb); + + cfb->ramdac_ctrl = hw->ramdac; + cyber2000fb_write_ramdac_ctrl(cfb); + + cyber2000fb_writeb(0x20, 0x3c0, cfb); + cyber2000fb_writeb(0xff, 0x3c6, cfb); + + cyber2000_grphw(0x14, hw->fetch, cfb); + cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) | + ((hw->pitch >> 4) & 0x30), cfb); + cyber2000_grphw(EXT_SEQ_MISC, hw->extseqmisc, cfb); + + /* + * Set up accelerator registers + */ + cyber2000fb_writew(hw->width, CO_REG_SRC_WIDTH, cfb); + cyber2000fb_writew(hw->width, CO_REG_DEST_WIDTH, cfb); + cyber2000fb_writeb(hw->co_pixfmt, CO_REG_PIXFMT, cfb); +} + +static inline int +cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var) +{ + u_int base = var->yoffset * var->xres_virtual + var->xoffset; + + base *= var->bits_per_pixel; + + /* + * Convert to bytes and shift two extra bits because DAC + * can only start on 4 byte aligned data. + */ + base >>= 5; + + if (base >= 1 << 20) + return -EINVAL; + + cyber2000_grphw(0x10, base >> 16 | 0x10, cfb); + cyber2000_crtcw(0x0c, base >> 8, cfb); + cyber2000_crtcw(0x0d, base, cfb); + + return 0; +} + +static int +cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb, + struct fb_var_screeninfo *var) +{ + u_int Htotal, Hblankend, Hsyncend; + u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend; +#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2) + + hw->crtc[13] = hw->pitch; + hw->crtc[17] = 0xe3; + hw->crtc[14] = 0; + hw->crtc[8] = 0; + + Htotal = var->xres + var->right_margin + + var->hsync_len + var->left_margin; + + if (Htotal > 2080) + return -EINVAL; + + hw->crtc[0] = (Htotal >> 3) - 5; + hw->crtc[1] = (var->xres >> 3) - 1; + hw->crtc[2] = var->xres >> 3; + hw->crtc[4] = (var->xres + var->right_margin) >> 3; + + Hblankend = (Htotal - 4*8) >> 3; + + hw->crtc[3] = BIT(Hblankend, 0, 0x1f, 0) | + BIT(1, 0, 0x01, 7); + + Hsyncend = (var->xres + var->right_margin + var->hsync_len) >> 3; + + hw->crtc[5] = BIT(Hsyncend, 0, 0x1f, 0) | + BIT(Hblankend, 5, 0x01, 7); + + Vdispend = var->yres - 1; + Vsyncstart = var->yres + var->lower_margin; + Vsyncend = var->yres + var->lower_margin + var->vsync_len; + Vtotal = var->yres + var->lower_margin + var->vsync_len + + var->upper_margin - 2; + + if (Vtotal > 2047) + return -EINVAL; + + Vblankstart = var->yres + 6; + Vblankend = Vtotal - 10; + + hw->crtc[6] = Vtotal; + hw->crtc[7] = BIT(Vtotal, 8, 0x01, 0) | + BIT(Vdispend, 8, 0x01, 1) | + BIT(Vsyncstart, 8, 0x01, 2) | + BIT(Vblankstart,8, 0x01, 3) | + BIT(1, 0, 0x01, 4) | + BIT(Vtotal, 9, 0x01, 5) | + BIT(Vdispend, 9, 0x01, 6) | + BIT(Vsyncstart, 9, 0x01, 7); + hw->crtc[9] = BIT(0, 0, 0x1f, 0) | + BIT(Vblankstart,9, 0x01, 5) | + BIT(1, 0, 0x01, 6); + hw->crtc[10] = Vsyncstart; + hw->crtc[11] = BIT(Vsyncend, 0, 0x0f, 0) | + BIT(1, 0, 0x01, 7); + hw->crtc[12] = Vdispend; + hw->crtc[15] = Vblankstart; + hw->crtc[16] = Vblankend; + hw->crtc[18] = 0xff; + + /* + * overflow - graphics reg 0x11 + * 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10 + * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT + */ + hw->crtc_ofl = + BIT(Vtotal, 10, 0x01, 0) | + BIT(Vdispend, 10, 0x01, 1) | + BIT(Vsyncstart, 10, 0x01, 2) | + BIT(Vblankstart,10, 0x01, 3) | + EXT_CRT_VRTOFL_LINECOMP10; + + /* woody: set the interlaced bit... */ + /* FIXME: what about doublescan? */ + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + hw->crtc_ofl |= EXT_CRT_VRTOFL_INTERLACE; + + return 0; +} + +/* + * The following was discovered by a good monitor, bit twiddling, theorising + * and but mostly luck. Strangely, it looks like everyone elses' PLL! + * + * Clock registers: + * fclock = fpll / div2 + * fpll = fref * mult / div1 + * where: + * fref = 14.318MHz (69842ps) + * mult = reg0xb0.7:0 + * div1 = (reg0xb1.5:0 + 1) + * div2 = 2^(reg0xb1.7:6) + * fpll should be between 115 and 260 MHz + * (8696ps and 3846ps) + */ +static int +cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb, + struct fb_var_screeninfo *var) +{ + u_long pll_ps = var->pixclock; + const u_long ref_ps = cfb->ref_ps; + u_int div2, t_div1, best_div1, best_mult; + int best_diff; + int vco; + + /* + * Step 1: + * find div2 such that 115MHz < fpll < 260MHz + * and 0 <= div2 < 4 + */ + for (div2 = 0; div2 < 4; div2++) { + u_long new_pll; + + new_pll = pll_ps / cfb->divisors[div2]; + if (8696 > new_pll && new_pll > 3846) { + pll_ps = new_pll; + break; + } + } + + if (div2 == 4) + return -EINVAL; + + /* + * Step 2: + * Given pll_ps and ref_ps, find: + * pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005 + * where { 1 < best_div1 < 32, 1 < best_mult < 256 } + * pll_ps_calc = best_div1 / (ref_ps * best_mult) + */ + best_diff = 0x7fffffff; + best_mult = 32; + best_div1 = 255; + for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) { + u_int rr, t_mult, t_pll_ps; + int diff; + + /* + * Find the multiplier for this divisor + */ + rr = ref_ps * t_div1; + t_mult = (rr + pll_ps / 2) / pll_ps; + + /* + * Is the multiplier within the correct range? + */ + if (t_mult > 256 || t_mult < 2) + continue; + + /* + * Calculate the actual clock period from this multiplier + * and divisor, and estimate the error. + */ + t_pll_ps = (rr + t_mult / 2) / t_mult; + diff = pll_ps - t_pll_ps; + if (diff < 0) + diff = -diff; + + if (diff < best_diff) { + best_diff = diff; + best_mult = t_mult; + best_div1 = t_div1; + } + + /* + * If we hit an exact value, there is no point in continuing. + */ + if (diff == 0) + break; + } + + /* + * Step 3: + * combine values + */ + hw->clock_mult = best_mult - 1; + hw->clock_div = div2 << 6 | (best_div1 - 1); + + vco = ref_ps * best_div1 / best_mult; + if ((ref_ps == 40690) && (vco < 5556)) + /* Set VFSEL when VCO > 180MHz (5.556 ps). */ + hw->clock_div |= EXT_DCLK_DIV_VFSEL; + + return 0; +} + +/* + * Set the User Defined Part of the Display + */ +static int +cyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct cfb_info *cfb = (struct cfb_info *)info; + struct par_info hw; + unsigned int mem; + int err; + + var->transp.msb_right = 0; + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + + switch (var->bits_per_pixel) { + case 8: /* PSEUDOCOLOUR, 256 */ + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + break; + + case 16:/* DIRECTCOLOUR, 64k or 32k */ + switch (var->green.length) { + case 6: /* RGB565, 64k */ + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + + default: + case 5: /* RGB555, 32k */ + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + break; + + case 4: /* RGB444, 4k + transparency? */ + var->transp.offset = 12; + var->transp.length = 4; + var->red.offset = 8; + var->red.length = 4; + var->green.offset = 4; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; + break; + } + break; + + case 24:/* TRUECOLOUR, 16m */ + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + break; + + case 32:/* TRUECOLOUR, 16m */ + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + break; + + default: + return -EINVAL; + } + + mem = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8); + if (mem > cfb->fb.fix.smem_len) + var->yres_virtual = cfb->fb.fix.smem_len * 8 / + (var->bits_per_pixel * var->xres_virtual); + + if (var->yres > var->yres_virtual) + var->yres = var->yres_virtual; + if (var->xres > var->xres_virtual) + var->xres = var->xres_virtual; + + err = cyber2000fb_decode_clock(&hw, cfb, var); + if (err) + return err; + + err = cyber2000fb_decode_crtc(&hw, cfb, var); + if (err) + return err; + + return 0; +} + +static int cyber2000fb_set_par(struct fb_info *info) +{ + struct cfb_info *cfb = (struct cfb_info *)info; + struct fb_var_screeninfo *var = &cfb->fb.var; + struct par_info hw; + unsigned int mem; + + hw.width = var->xres_virtual; + hw.ramdac = RAMDAC_VREFEN | RAMDAC_DAC8BIT; + + switch (var->bits_per_pixel) { + case 8: + hw.co_pixfmt = CO_PIXFMT_8BPP; + hw.pitch = hw.width >> 3; + hw.extseqmisc = EXT_SEQ_MISC_8; + break; + + case 16: + hw.co_pixfmt = CO_PIXFMT_16BPP; + hw.pitch = hw.width >> 2; + + switch (var->green.length) { + case 6: /* RGB565, 64k */ + hw.extseqmisc = EXT_SEQ_MISC_16_RGB565; + break; + case 5: /* RGB555, 32k */ + hw.extseqmisc = EXT_SEQ_MISC_16_RGB555; + break; + case 4: /* RGB444, 4k + transparency? */ + hw.extseqmisc = EXT_SEQ_MISC_16_RGB444; + break; + default: + BUG(); + } + case 24:/* TRUECOLOUR, 16m */ + hw.co_pixfmt = CO_PIXFMT_24BPP; + hw.width *= 3; + hw.pitch = hw.width >> 3; + hw.ramdac |= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN); + hw.extseqmisc = EXT_SEQ_MISC_24_RGB888; + break; + + case 32:/* TRUECOLOUR, 16m */ + hw.co_pixfmt = CO_PIXFMT_32BPP; + hw.pitch = hw.width >> 1; + hw.ramdac |= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN); + hw.extseqmisc = EXT_SEQ_MISC_32; + break; + + default: + BUG(); + } + + /* + * Sigh, this is absolutely disgusting, but caused by + * the way the fbcon developers want to separate out + * the "checking" and the "setting" of the video mode. + * + * If the mode is not suitable for the hardware here, + * we can't prevent it being set by returning an error. + * + * In theory, since NetWinders contain just one VGA card, + * we should never end up hitting this problem. + */ + BUG_ON(cyber2000fb_decode_clock(&hw, cfb, var) != 0); + BUG_ON(cyber2000fb_decode_crtc(&hw, cfb, var) != 0); + + hw.width -= 1; + hw.fetch = hw.pitch; + if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT)) + hw.fetch <<= 1; + hw.fetch += 1; + + cfb->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8; + + /* + * Same here - if the size of the video mode exceeds the + * available RAM, we can't prevent this mode being set. + * + * In theory, since NetWinders contain just one VGA card, + * we should never end up hitting this problem. + */ + mem = cfb->fb.fix.line_length * var->yres_virtual; + BUG_ON(mem > cfb->fb.fix.smem_len); + + /* + * 8bpp displays are always pseudo colour. 16bpp and above + * are direct colour or true colour, depending on whether + * the RAMDAC palettes are bypassed. (Direct colour has + * palettes, true colour does not.) + */ + if (var->bits_per_pixel == 8) + cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; + else if (hw.ramdac & RAMDAC_BYPASS) + cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; + else + cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; + + cyber2000fb_set_timing(cfb, &hw); + cyber2000fb_update_start(cfb, var); + + return 0; +} + + +/* + * Pan or Wrap the Display + */ +static int +cyber2000fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct cfb_info *cfb = (struct cfb_info *)info; + + if (cyber2000fb_update_start(cfb, var)) + return -EINVAL; + + cfb->fb.var.xoffset = var->xoffset; + cfb->fb.var.yoffset = var->yoffset; + + if (var->vmode & FB_VMODE_YWRAP) { + cfb->fb.var.vmode |= FB_VMODE_YWRAP; + } else { + cfb->fb.var.vmode &= ~FB_VMODE_YWRAP; + } + + return 0; +} + +/* + * (Un)Blank the display. + * + * Blank the screen if blank_mode != 0, else unblank. If + * blank == NULL then the caller blanks by setting the CLUT + * (Color Look Up Table) to all black. Return 0 if blanking + * succeeded, != 0 if un-/blanking failed due to e.g. a + * video mode which doesn't support it. Implements VESA + * suspend and powerdown modes on hardware that supports + * disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + * + * wms...Enable VESA DMPS compatible powerdown mode + * run "setterm -powersave powerdown" to take advantage + */ +static int cyber2000fb_blank(int blank, struct fb_info *info) +{ + struct cfb_info *cfb = (struct cfb_info *)info; + unsigned int sync = 0; + int i; + + switch (blank) { + case FB_BLANK_POWERDOWN: /* powerdown - both sync lines down */ + sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0; + break; + case FB_BLANK_HSYNC_SUSPEND: /* hsync off */ + sync = EXT_SYNC_CTL_VS_NORMAL | EXT_SYNC_CTL_HS_0; + break; + case FB_BLANK_VSYNC_SUSPEND: /* vsync off */ + sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL; + break; + case FB_BLANK_NORMAL: /* soft blank */ + default: /* unblank */ + break; + } + + cyber2000_grphw(EXT_SYNC_CTL, sync, cfb); + + if (blank <= 1) { + /* turn on ramdacs */ + cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN); + cyber2000fb_write_ramdac_ctrl(cfb); + } + + /* + * Soft blank/unblank the display. + */ + if (blank) { /* soft blank */ + for (i = 0; i < NR_PALETTE; i++) { + cyber2000fb_writeb(i, 0x3c8, cfb); + cyber2000fb_writeb(0, 0x3c9, cfb); + cyber2000fb_writeb(0, 0x3c9, cfb); + cyber2000fb_writeb(0, 0x3c9, cfb); + } + } else { /* unblank */ + for (i = 0; i < NR_PALETTE; i++) { + cyber2000fb_writeb(i, 0x3c8, cfb); + cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb); + cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb); + cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb); + } + } + + if (blank >= 2) { + /* turn off ramdacs */ + cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN; + cyber2000fb_write_ramdac_ctrl(cfb); + } + + return 0; +} + +static struct fb_ops cyber2000fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = cyber2000fb_check_var, + .fb_set_par = cyber2000fb_set_par, + .fb_setcolreg = cyber2000fb_setcolreg, + .fb_blank = cyber2000fb_blank, + .fb_pan_display = cyber2000fb_pan_display, + .fb_fillrect = cyber2000fb_fillrect, + .fb_copyarea = cyber2000fb_copyarea, + .fb_imageblit = cyber2000fb_imageblit, + .fb_cursor = soft_cursor, + .fb_sync = cyber2000fb_sync, +}; + +/* + * This is the only "static" reference to the internal data structures + * of this driver. It is here solely at the moment to support the other + * CyberPro modules external to this driver. + */ +static struct cfb_info *int_cfb_info; + +/* + * Enable access to the extended registers + */ +void cyber2000fb_enable_extregs(struct cfb_info *cfb) +{ + cfb->func_use_count += 1; + + if (cfb->func_use_count == 1) { + int old; + + old = cyber2000_grphr(EXT_FUNC_CTL, cfb); + old |= EXT_FUNC_CTL_EXTREGENBL; + cyber2000_grphw(EXT_FUNC_CTL, old, cfb); + } +} + +/* + * Disable access to the extended registers + */ +void cyber2000fb_disable_extregs(struct cfb_info *cfb) +{ + if (cfb->func_use_count == 1) { + int old; + + old = cyber2000_grphr(EXT_FUNC_CTL, cfb); + old &= ~EXT_FUNC_CTL_EXTREGENBL; + cyber2000_grphw(EXT_FUNC_CTL, old, cfb); + } + + if (cfb->func_use_count == 0) + printk(KERN_ERR "disable_extregs: count = 0\n"); + else + cfb->func_use_count -= 1; +} + +void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var) +{ + memcpy(var, &cfb->fb.var, sizeof(struct fb_var_screeninfo)); +} + +/* + * Attach a capture/tv driver to the core CyberX0X0 driver. + */ +int cyber2000fb_attach(struct cyberpro_info *info, int idx) +{ + if (int_cfb_info != NULL) { + info->dev = int_cfb_info->dev; + info->regs = int_cfb_info->regs; + info->fb = int_cfb_info->fb.screen_base; + info->fb_size = int_cfb_info->fb.fix.smem_len; + info->enable_extregs = cyber2000fb_enable_extregs; + info->disable_extregs = cyber2000fb_disable_extregs; + info->info = int_cfb_info; + + strlcpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name)); + } + + return int_cfb_info != NULL; +} + +/* + * Detach a capture/tv driver from the core CyberX0X0 driver. + */ +void cyber2000fb_detach(int idx) +{ +} + +EXPORT_SYMBOL(cyber2000fb_attach); +EXPORT_SYMBOL(cyber2000fb_detach); +EXPORT_SYMBOL(cyber2000fb_enable_extregs); +EXPORT_SYMBOL(cyber2000fb_disable_extregs); +EXPORT_SYMBOL(cyber2000fb_get_fb_var); + +/* + * These parameters give + * 640x480, hsync 31.5kHz, vsync 60Hz + */ +static struct fb_videomode __devinitdata cyber2000fb_default_mode = { + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39722, + .left_margin = 56, + .right_margin = 16, + .upper_margin = 34, + .lower_margin = 9, + .hsync_len = 88, + .vsync_len = 2, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED +}; + +static char igs_regs[] = { + EXT_CRT_IRQ, 0, + EXT_CRT_TEST, 0, + EXT_SYNC_CTL, 0, + EXT_SEG_WRITE_PTR, 0, + EXT_SEG_READ_PTR, 0, + EXT_BIU_MISC, EXT_BIU_MISC_LIN_ENABLE | + EXT_BIU_MISC_COP_ENABLE | + EXT_BIU_MISC_COP_BFC, + EXT_FUNC_CTL, 0, + CURS_H_START, 0, + CURS_H_START + 1, 0, + CURS_H_PRESET, 0, + CURS_V_START, 0, + CURS_V_START + 1, 0, + CURS_V_PRESET, 0, + CURS_CTL, 0, + EXT_ATTRIB_CTL, EXT_ATTRIB_CTL_EXT, + EXT_OVERSCAN_RED, 0, + EXT_OVERSCAN_GREEN, 0, + EXT_OVERSCAN_BLUE, 0, + + /* some of these are questionable when we have a BIOS */ + EXT_MEM_CTL0, EXT_MEM_CTL0_7CLK | + EXT_MEM_CTL0_RAS_1 | + EXT_MEM_CTL0_MULTCAS, + EXT_HIDDEN_CTL1, 0x30, + EXT_FIFO_CTL, 0x0b, + EXT_FIFO_CTL + 1, 0x17, + 0x76, 0x00, + EXT_HIDDEN_CTL4, 0xc8 +}; + +/* + * Initialise the CyberPro hardware. On the CyberPro5XXXX, + * ensure that we're using the correct PLL (5XXX's may be + * programmed to use an additional set of PLLs.) + */ +static void cyberpro_init_hw(struct cfb_info *cfb) +{ + int i; + + for (i = 0; i < sizeof(igs_regs); i += 2) + cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb); + + if (cfb->id == ID_CYBERPRO_5000) { + unsigned char val; + cyber2000fb_writeb(0xba, 0x3ce, cfb); + val = cyber2000fb_readb(0x3cf, cfb) & 0x80; + cyber2000fb_writeb(val, 0x3cf, cfb); + } +} + +static struct cfb_info * __devinit +cyberpro_alloc_fb_info(unsigned int id, char *name) +{ + struct cfb_info *cfb; + + cfb = kmalloc(sizeof(struct cfb_info) + + sizeof(u32) * 16, GFP_KERNEL); + + if (!cfb) + return NULL; + + memset(cfb, 0, sizeof(struct cfb_info)); + + cfb->id = id; + + if (id == ID_CYBERPRO_5000) + cfb->ref_ps = 40690; // 24.576 MHz + else + cfb->ref_ps = 69842; // 14.31818 MHz (69841?) + + cfb->divisors[0] = 1; + cfb->divisors[1] = 2; + cfb->divisors[2] = 4; + + if (id == ID_CYBERPRO_2000) + cfb->divisors[3] = 8; + else + cfb->divisors[3] = 6; + + strcpy(cfb->fb.fix.id, name); + + cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; + cfb->fb.fix.type_aux = 0; + cfb->fb.fix.xpanstep = 0; + cfb->fb.fix.ypanstep = 1; + cfb->fb.fix.ywrapstep = 0; + + switch (id) { + case ID_IGA_1682: + cfb->fb.fix.accel = 0; + break; + + case ID_CYBERPRO_2000: + cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2000; + break; + + case ID_CYBERPRO_2010: + cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2010; + break; + + case ID_CYBERPRO_5000: + cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER5000; + break; + } + + cfb->fb.var.nonstd = 0; + cfb->fb.var.activate = FB_ACTIVATE_NOW; + cfb->fb.var.height = -1; + cfb->fb.var.width = -1; + cfb->fb.var.accel_flags = FB_ACCELF_TEXT; + + cfb->fb.fbops = &cyber2000fb_ops; + cfb->fb.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + cfb->fb.pseudo_palette = (void *)(cfb + 1); + + fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0); + + return cfb; +} + +static void +cyberpro_free_fb_info(struct cfb_info *cfb) +{ + if (cfb) { + /* + * Free the colourmap + */ + fb_alloc_cmap(&cfb->fb.cmap, 0, 0); + + kfree(cfb); + } +} + +/* + * Parse Cyber2000fb options. Usage: + * video=cyber2000:font:fontname + */ +#ifndef MODULE +static int +cyber2000fb_setup(char *options) +{ + char *opt; + + if (!options || !*options) + return 0; + + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + + if (strncmp(opt, "font:", 5) == 0) { + static char default_font_storage[40]; + + strlcpy(default_font_storage, opt + 5, sizeof(default_font_storage)); + default_font = default_font_storage; + continue; + } + + printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n", opt); + } + return 0; +} +#endif /* MODULE */ + +/* + * The CyberPro chips can be placed on many different bus types. + * This probe function is common to all bus types. The bus-specific + * probe function is expected to have: + * - enabled access to the linear memory region + * - memory mapped access to the registers + * - initialised mem_ctl1 and mem_ctl2 appropriately. + */ +static int __devinit cyberpro_common_probe(struct cfb_info *cfb) +{ + u_long smem_size; + u_int h_sync, v_sync; + int err; + + cyberpro_init_hw(cfb); + + /* + * Get the video RAM size and width from the VGA register. + * This should have been already initialised by the BIOS, + * but if it's garbage, claim default 1MB VRAM (woody) + */ + cfb->mem_ctl1 = cyber2000_grphr(EXT_MEM_CTL1, cfb); + cfb->mem_ctl2 = cyber2000_grphr(EXT_MEM_CTL2, cfb); + + /* + * Determine the size of the memory. + */ + switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) { + case MEM_CTL2_SIZE_4MB: smem_size = 0x00400000; break; + case MEM_CTL2_SIZE_2MB: smem_size = 0x00200000; break; + case MEM_CTL2_SIZE_1MB: smem_size = 0x00100000; break; + default: smem_size = 0x00100000; break; + } + + cfb->fb.fix.smem_len = smem_size; + cfb->fb.fix.mmio_len = MMIO_SIZE; + cfb->fb.screen_base = cfb->region; + + err = -EINVAL; + if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0, + &cyber2000fb_default_mode, 8)) { + printk("%s: no valid mode found\n", cfb->fb.fix.id); + goto failed; + } + + cfb->fb.var.yres_virtual = cfb->fb.fix.smem_len * 8 / + (cfb->fb.var.bits_per_pixel * cfb->fb.var.xres_virtual); + + if (cfb->fb.var.yres_virtual < cfb->fb.var.yres) + cfb->fb.var.yres_virtual = cfb->fb.var.yres; + +// fb_set_var(&cfb->fb.var, -1, &cfb->fb); + + /* + * Calculate the hsync and vsync frequencies. Note that + * we split the 1e12 constant up so that we can preserve + * the precision and fit the results into 32-bit registers. + * (1953125000 * 512 = 1e12) + */ + h_sync = 1953125000 / cfb->fb.var.pixclock; + h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin + + cfb->fb.var.right_margin + cfb->fb.var.hsync_len); + v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin + + cfb->fb.var.lower_margin + cfb->fb.var.vsync_len); + + printk(KERN_INFO "%s: %dKiB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", + cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10, + cfb->fb.var.xres, cfb->fb.var.yres, + h_sync / 1000, h_sync % 1000, v_sync); + + if (cfb->dev) + cfb->fb.device = &cfb->dev->dev; + err = register_framebuffer(&cfb->fb); + +failed: + return err; +} + +static void cyberpro_common_resume(struct cfb_info *cfb) +{ + cyberpro_init_hw(cfb); + + /* + * Reprogram the MEM_CTL1 and MEM_CTL2 registers + */ + cyber2000_grphw(EXT_MEM_CTL1, cfb->mem_ctl1, cfb); + cyber2000_grphw(EXT_MEM_CTL2, cfb->mem_ctl2, cfb); + + /* + * Restore the old video mode and the palette. + * We also need to tell fbcon to redraw the console. + */ + cyber2000fb_set_par(&cfb->fb); +} + +#ifdef CONFIG_ARCH_SHARK + +#include <asm/arch/hardware.h> + +static int __devinit +cyberpro_vl_probe(void) +{ + struct cfb_info *cfb; + int err = -ENOMEM; + + if (!request_mem_region(FB_START,FB_SIZE,"CyberPro2010")) return err; + + cfb = cyberpro_alloc_fb_info(ID_CYBERPRO_2010, "CyberPro2010"); + if (!cfb) + goto failed_release; + + cfb->dev = NULL; + cfb->region = ioremap(FB_START,FB_SIZE); + if (!cfb->region) + goto failed_ioremap; + + cfb->regs = cfb->region + MMIO_OFFSET; + cfb->fb.fix.mmio_start = FB_START + MMIO_OFFSET; + cfb->fb.fix.smem_start = FB_START; + + /* + * Bring up the hardware. This is expected to enable access + * to the linear memory region, and allow access to the memory + * mapped registers. Also, mem_ctl1 and mem_ctl2 must be + * initialised. + */ + cyber2000fb_writeb(0x18, 0x46e8, cfb); + cyber2000fb_writeb(0x01, 0x102, cfb); + cyber2000fb_writeb(0x08, 0x46e8, cfb); + cyber2000fb_writeb(EXT_BIU_MISC, 0x3ce, cfb); + cyber2000fb_writeb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf, cfb); + + cfb->mclk_mult = 0xdb; + cfb->mclk_div = 0x54; + + err = cyberpro_common_probe(cfb); + if (err) + goto failed; + + if (int_cfb_info == NULL) + int_cfb_info = cfb; + + return 0; + +failed: + iounmap(cfb->region); +failed_ioremap: + cyberpro_free_fb_info(cfb); +failed_release: + release_mem_region(FB_START,FB_SIZE); + + return err; +} +#endif /* CONFIG_ARCH_SHARK */ + +/* + * PCI specific support. + */ +#ifdef CONFIG_PCI +/* + * We need to wake up the CyberPro, and make sure its in linear memory + * mode. Unfortunately, this is specific to the platform and card that + * we are running on. + * + * On x86 and ARM, should we be initialising the CyberPro first via the + * IO registers, and then the MMIO registers to catch all cases? Can we + * end up in the situation where the chip is in MMIO mode, but not awake + * on an x86 system? + */ +static int cyberpro_pci_enable_mmio(struct cfb_info *cfb) +{ + unsigned char val; + +#if defined(__sparc_v9__) +#error "You lose, consult DaveM." +#elif defined(__sparc__) + /* + * SPARC does not have an "outb" instruction, so we generate + * I/O cycles storing into a reserved memory space at + * physical address 0x3000000 + */ + unsigned char *iop; + + iop = ioremap(0x3000000, 0x5000); + if (iop == NULL) { + prom_printf("iga5000: cannot map I/O\n"); + return -ENOMEM; + } + + writeb(0x18, iop + 0x46e8); + writeb(0x01, iop + 0x102); + writeb(0x08, iop + 0x46e8); + writeb(EXT_BIU_MISC, iop + 0x3ce); + writeb(EXT_BIU_MISC_LIN_ENABLE, iop + 0x3cf); + + iounmap((void *)iop); +#else + /* + * Most other machine types are "normal", so + * we use the standard IO-based wakeup. + */ + outb(0x18, 0x46e8); + outb(0x01, 0x102); + outb(0x08, 0x46e8); + outb(EXT_BIU_MISC, 0x3ce); + outb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf); +#endif + + /* + * Allow the CyberPro to accept PCI burst accesses + */ + val = cyber2000_grphr(EXT_BUS_CTL, cfb); + if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) { + printk(KERN_INFO "%s: enabling PCI bursts\n", cfb->fb.fix.id); + + val |= EXT_BUS_CTL_PCIBURST_WRITE; + + if (cfb->id == ID_CYBERPRO_5000) + val |= EXT_BUS_CTL_PCIBURST_READ; + + cyber2000_grphw(EXT_BUS_CTL, val, cfb); + } + + return 0; +} + +static int __devinit +cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct cfb_info *cfb; + char name[16]; + int err; + + sprintf(name, "CyberPro%4X", id->device); + + err = pci_enable_device(dev); + if (err) + return err; + + err = pci_request_regions(dev, name); + if (err) + return err; + + err = -ENOMEM; + cfb = cyberpro_alloc_fb_info(id->driver_data, name); + if (!cfb) + goto failed_release; + + cfb->dev = dev; + cfb->region = ioremap(pci_resource_start(dev, 0), + pci_resource_len(dev, 0)); + if (!cfb->region) + goto failed_ioremap; + + cfb->regs = cfb->region + MMIO_OFFSET; + cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET; + cfb->fb.fix.smem_start = pci_resource_start(dev, 0); + + /* + * Bring up the hardware. This is expected to enable access + * to the linear memory region, and allow access to the memory + * mapped registers. Also, mem_ctl1 and mem_ctl2 must be + * initialised. + */ + err = cyberpro_pci_enable_mmio(cfb); + if (err) + goto failed; + + /* + * Use MCLK from BIOS. FIXME: what about hotplug? + */ + cfb->mclk_mult = cyber2000_grphr(EXT_MCLK_MULT, cfb); + cfb->mclk_div = cyber2000_grphr(EXT_MCLK_DIV, cfb); + +#ifdef __arm__ + /* + * MCLK on the NetWinder and the Shark is fixed at 75MHz + */ + if (machine_is_netwinder()) { + cfb->mclk_mult = 0xdb; + cfb->mclk_div = 0x54; + } +#endif + + err = cyberpro_common_probe(cfb); + if (err) + goto failed; + + /* + * Our driver data + */ + pci_set_drvdata(dev, cfb); + if (int_cfb_info == NULL) + int_cfb_info = cfb; + + return 0; + +failed: + iounmap(cfb->region); +failed_ioremap: + cyberpro_free_fb_info(cfb); +failed_release: + pci_release_regions(dev); + + return err; +} + +static void __devexit cyberpro_pci_remove(struct pci_dev *dev) +{ + struct cfb_info *cfb = pci_get_drvdata(dev); + + if (cfb) { + /* + * If unregister_framebuffer fails, then + * we will be leaving hooks that could cause + * oopsen laying around. + */ + if (unregister_framebuffer(&cfb->fb)) + printk(KERN_WARNING "%s: danger Will Robinson, " + "danger danger! Oopsen imminent!\n", + cfb->fb.fix.id); + iounmap(cfb->region); + cyberpro_free_fb_info(cfb); + + /* + * Ensure that the driver data is no longer + * valid. + */ + pci_set_drvdata(dev, NULL); + if (cfb == int_cfb_info) + int_cfb_info = NULL; + + pci_release_regions(dev); + } +} + +static int cyberpro_pci_suspend(struct pci_dev *dev, pm_message_t state) +{ + return 0; +} + +/* + * Re-initialise the CyberPro hardware + */ +static int cyberpro_pci_resume(struct pci_dev *dev) +{ + struct cfb_info *cfb = pci_get_drvdata(dev); + + if (cfb) { + cyberpro_pci_enable_mmio(cfb); + cyberpro_common_resume(cfb); + } + + return 0; +} + +static struct pci_device_id cyberpro_pci_table[] = { +// Not yet +// { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682, +// PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 }, + { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 }, + { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2010 }, + { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_5000 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci,cyberpro_pci_table); + +static struct pci_driver cyberpro_driver = { + .name = "CyberPro", + .probe = cyberpro_pci_probe, + .remove = __devexit_p(cyberpro_pci_remove), + .suspend = cyberpro_pci_suspend, + .resume = cyberpro_pci_resume, + .id_table = cyberpro_pci_table +}; +#endif + +/* + * I don't think we can use the "module_init" stuff here because + * the fbcon stuff may not be initialised yet. Hence the #ifdef + * around module_init. + * + * Tony: "module_init" is now required + */ +static int __init cyber2000fb_init(void) +{ + int ret = -1, err; + +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("cyber2000fb", &option)) + return -ENODEV; + cyber2000fb_setup(option); +#endif + +#ifdef CONFIG_ARCH_SHARK + err = cyberpro_vl_probe(); + if (!err) { + ret = 0; + __module_get(THIS_MODULE); + } +#endif +#ifdef CONFIG_PCI + err = pci_register_driver(&cyberpro_driver); + if (!err) + ret = 0; +#endif + + return ret ? err : 0; +} + +static void __exit cyberpro_exit(void) +{ + pci_unregister_driver(&cyberpro_driver); +} + +module_init(cyber2000fb_init); +module_exit(cyberpro_exit); + +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/cyber2000fb.h b/drivers/video/cyber2000fb.h new file mode 100644 index 000000000000..bd7e1c040781 --- /dev/null +++ b/drivers/video/cyber2000fb.h @@ -0,0 +1,508 @@ +/* + * linux/drivers/video/cyber2000fb.h + * + * Copyright (C) 1998-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Integraphics Cyber2000 frame buffer device + */ +#include <linux/config.h> + +/* + * Internal CyberPro sizes and offsets. + */ +#define MMIO_OFFSET 0x00800000 +#define MMIO_SIZE 0x000c0000 + +#define NR_PALETTE 256 + +#if defined(DEBUG) && defined(CONFIG_DEBUG_LL) +static void debug_printf(char *fmt, ...) +{ + extern void printascii(const char *); + char buffer[128]; + va_list ap; + + va_start(ap, fmt); + vsprintf(buffer, fmt, ap); + va_end(ap); + + printascii(buffer); +} +#else +#define debug_printf(x...) do { } while (0) +#endif + +#define RAMDAC_RAMPWRDN 0x01 +#define RAMDAC_DAC8BIT 0x02 +#define RAMDAC_VREFEN 0x04 +#define RAMDAC_BYPASS 0x10 +#define RAMDAC_DACPWRDN 0x40 + +#define EXT_CRT_VRTOFL 0x11 +#define EXT_CRT_VRTOFL_LINECOMP10 0x10 +#define EXT_CRT_VRTOFL_INTERLACE 0x20 + +#define EXT_CRT_IRQ 0x12 +#define EXT_CRT_IRQ_ENABLE 0x01 +#define EXT_CRT_IRQ_ACT_HIGH 0x04 + +#define EXT_CRT_TEST 0x13 + +#define EXT_SYNC_CTL 0x16 +#define EXT_SYNC_CTL_HS_NORMAL 0x00 +#define EXT_SYNC_CTL_HS_0 0x01 +#define EXT_SYNC_CTL_HS_1 0x02 +#define EXT_SYNC_CTL_HS_HSVS 0x03 +#define EXT_SYNC_CTL_VS_NORMAL 0x00 +#define EXT_SYNC_CTL_VS_0 0x04 +#define EXT_SYNC_CTL_VS_1 0x08 +#define EXT_SYNC_CTL_VS_COMP 0x0c + +#define EXT_BUS_CTL 0x30 +#define EXT_BUS_CTL_LIN_1MB 0x00 +#define EXT_BUS_CTL_LIN_2MB 0x01 +#define EXT_BUS_CTL_LIN_4MB 0x02 +#define EXT_BUS_CTL_ZEROWAIT 0x04 +#define EXT_BUS_CTL_PCIBURST_WRITE 0x20 +#define EXT_BUS_CTL_PCIBURST_READ 0x80 /* CyberPro 5000 only */ + +#define EXT_SEG_WRITE_PTR 0x31 +#define EXT_SEG_READ_PTR 0x32 +#define EXT_BIU_MISC 0x33 +#define EXT_BIU_MISC_LIN_ENABLE 0x01 +#define EXT_BIU_MISC_COP_ENABLE 0x04 +#define EXT_BIU_MISC_COP_BFC 0x08 + +#define EXT_FUNC_CTL 0x3c +#define EXT_FUNC_CTL_EXTREGENBL 0x80 /* enable access to 0xbcxxx */ + +#define PCI_BM_CTL 0x3e +#define PCI_BM_CTL_ENABLE 0x01 /* enable bus-master */ +#define PCI_BM_CTL_BURST 0x02 /* enable burst */ +#define PCI_BM_CTL_BACK2BACK 0x04 /* enable back to back */ +#define PCI_BM_CTL_DUMMY 0x08 /* insert dummy cycle */ + +#define X_V2_VID_MEM_START 0x40 +#define X_V2_VID_SRC_WIDTH 0x43 +#define X_V2_X_START 0x45 +#define X_V2_X_END 0x47 +#define X_V2_Y_START 0x49 +#define X_V2_Y_END 0x4b +#define X_V2_VID_SRC_WIN_WIDTH 0x4d + +#define Y_V2_DDA_X_INC 0x43 +#define Y_V2_DDA_Y_INC 0x47 +#define Y_V2_VID_FIFO_CTL 0x49 +#define Y_V2_VID_FMT 0x4b +#define Y_V2_VID_DISP_CTL1 0x4c +#define Y_V2_VID_FIFO_CTL1 0x4d + +#define J_X2_VID_MEM_START 0x40 +#define J_X2_VID_SRC_WIDTH 0x43 +#define J_X2_X_START 0x47 +#define J_X2_X_END 0x49 +#define J_X2_Y_START 0x4b +#define J_X2_Y_END 0x4d +#define J_X2_VID_SRC_WIN_WIDTH 0x4f + +#define K_X2_DDA_X_INIT 0x40 +#define K_X2_DDA_X_INC 0x42 +#define K_X2_DDA_Y_INIT 0x44 +#define K_X2_DDA_Y_INC 0x46 +#define K_X2_VID_FMT 0x48 +#define K_X2_VID_DISP_CTL1 0x49 + +#define K_CAP_X2_CTL1 0x49 + +#define CURS_H_START 0x50 +#define CURS_H_PRESET 0x52 +#define CURS_V_START 0x53 +#define CURS_V_PRESET 0x55 +#define CURS_CTL 0x56 + +#define EXT_ATTRIB_CTL 0x57 +#define EXT_ATTRIB_CTL_EXT 0x01 + +#define EXT_OVERSCAN_RED 0x58 +#define EXT_OVERSCAN_GREEN 0x59 +#define EXT_OVERSCAN_BLUE 0x5a + +#define CAP_X_START 0x60 +#define CAP_X_END 0x62 +#define CAP_Y_START 0x64 +#define CAP_Y_END 0x66 +#define CAP_DDA_X_INIT 0x68 +#define CAP_DDA_X_INC 0x6a +#define CAP_DDA_Y_INIT 0x6c +#define CAP_DDA_Y_INC 0x6e + +#define EXT_MEM_CTL0 0x70 +#define EXT_MEM_CTL0_7CLK 0x01 +#define EXT_MEM_CTL0_RAS_1 0x02 +#define EXT_MEM_CTL0_RAS2CAS_1 0x04 +#define EXT_MEM_CTL0_MULTCAS 0x08 +#define EXT_MEM_CTL0_ASYM 0x10 +#define EXT_MEM_CTL0_CAS1ON 0x20 +#define EXT_MEM_CTL0_FIFOFLUSH 0x40 +#define EXT_MEM_CTL0_SEQRESET 0x80 + +#define EXT_MEM_CTL1 0x71 +#define EXT_MEM_CTL1_PAR 0x00 +#define EXT_MEM_CTL1_SERPAR 0x01 +#define EXT_MEM_CTL1_SER 0x03 +#define EXT_MEM_CTL1_SYNC 0x04 +#define EXT_MEM_CTL1_VRAM 0x08 +#define EXT_MEM_CTL1_4K_REFRESH 0x10 +#define EXT_MEM_CTL1_256Kx4 0x00 +#define EXT_MEM_CTL1_512Kx8 0x40 +#define EXT_MEM_CTL1_1Mx16 0x60 + +#define EXT_MEM_CTL2 0x72 +#define MEM_CTL2_SIZE_1MB 0x00 +#define MEM_CTL2_SIZE_2MB 0x01 +#define MEM_CTL2_SIZE_4MB 0x02 +#define MEM_CTL2_SIZE_MASK 0x03 +#define MEM_CTL2_64BIT 0x04 + +#define EXT_HIDDEN_CTL1 0x73 + +#define EXT_FIFO_CTL 0x74 + +#define EXT_SEQ_MISC 0x77 +#define EXT_SEQ_MISC_8 0x01 +#define EXT_SEQ_MISC_16_RGB565 0x02 +#define EXT_SEQ_MISC_32 0x03 +#define EXT_SEQ_MISC_24_RGB888 0x04 +#define EXT_SEQ_MISC_16_RGB555 0x06 +#define EXT_SEQ_MISC_8_RGB332 0x09 +#define EXT_SEQ_MISC_16_RGB444 0x0a + +#define EXT_HIDDEN_CTL4 0x7a + +#define CURS_MEM_START 0x7e /* bits 23..12 */ + +#define CAP_PIP_X_START 0x80 +#define CAP_PIP_X_END 0x82 +#define CAP_PIP_Y_START 0x84 +#define CAP_PIP_Y_END 0x86 + +#define EXT_CAP_CTL1 0x88 + +#define EXT_CAP_CTL2 0x89 +#define EXT_CAP_CTL2_ODDFRAMEIRQ 0x01 +#define EXT_CAP_CTL2_ANYFRAMEIRQ 0x02 + +#define BM_CTRL0 0x9c +#define BM_CTRL1 0x9d + +#define EXT_CAP_MODE1 0xa4 +#define EXT_CAP_MODE1_8BIT 0x01 /* enable 8bit capture mode */ +#define EXT_CAP_MODE1_CCIR656 0x02 /* CCIR656 mode */ +#define EXT_CAP_MODE1_IGNOREVGT 0x04 /* ignore VGT */ +#define EXT_CAP_MODE1_ALTFIFO 0x10 /* use alternate FIFO for capture */ +#define EXT_CAP_MODE1_SWAPUV 0x20 /* swap UV bytes */ +#define EXT_CAP_MODE1_MIRRORY 0x40 /* mirror vertically */ +#define EXT_CAP_MODE1_MIRRORX 0x80 /* mirror horizontally */ + +#define EXT_CAP_MODE2 0xa5 +#define EXT_CAP_MODE2_CCIRINVOE 0x01 +#define EXT_CAP_MODE2_CCIRINVVGT 0x02 +#define EXT_CAP_MODE2_CCIRINVHGT 0x04 +#define EXT_CAP_MODE2_CCIRINVDG 0x08 +#define EXT_CAP_MODE2_DATEND 0x10 +#define EXT_CAP_MODE2_CCIRDGH 0x20 +#define EXT_CAP_MODE2_FIXSONY 0x40 +#define EXT_CAP_MODE2_SYNCFREEZE 0x80 + +#define EXT_TV_CTL 0xae + +#define EXT_DCLK_MULT 0xb0 +#define EXT_DCLK_DIV 0xb1 +#define EXT_DCLK_DIV_VFSEL 0x20 +#define EXT_MCLK_MULT 0xb2 +#define EXT_MCLK_DIV 0xb3 + +#define EXT_LATCH1 0xb5 +#define EXT_LATCH1_VAFC_EN 0x01 /* enable VAFC */ + +#define EXT_FEATURE 0xb7 +#define EXT_FEATURE_BUS_MASK 0x07 /* host bus mask */ +#define EXT_FEATURE_BUS_PCI 0x00 +#define EXT_FEATURE_BUS_VL_STD 0x04 +#define EXT_FEATURE_BUS_VL_LINEAR 0x05 +#define EXT_FEATURE_1682 0x20 /* IGS 1682 compatibility */ + +#define EXT_LATCH2 0xb6 +#define EXT_LATCH2_I2C_CLKEN 0x10 +#define EXT_LATCH2_I2C_CLK 0x20 +#define EXT_LATCH2_I2C_DATEN 0x40 +#define EXT_LATCH2_I2C_DAT 0x80 + +#define EXT_XT_CTL 0xbe +#define EXT_XT_CAP16 0x04 +#define EXT_XT_LINEARFB 0x08 +#define EXT_XT_PAL 0x10 + +#define EXT_MEM_START 0xc0 /* ext start address 21 bits */ +#define HOR_PHASE_SHIFT 0xc2 /* high 3 bits */ +#define EXT_SRC_WIDTH 0xc3 /* ext offset phase 10 bits */ +#define EXT_SRC_HEIGHT 0xc4 /* high 6 bits */ +#define EXT_X_START 0xc5 /* ext->screen, 16 bits */ +#define EXT_X_END 0xc7 /* ext->screen, 16 bits */ +#define EXT_Y_START 0xc9 /* ext->screen, 16 bits */ +#define EXT_Y_END 0xcb /* ext->screen, 16 bits */ +#define EXT_SRC_WIN_WIDTH 0xcd /* 8 bits */ +#define EXT_COLOUR_COMPARE 0xce /* 24 bits */ +#define EXT_DDA_X_INIT 0xd1 /* ext->screen 16 bits */ +#define EXT_DDA_X_INC 0xd3 /* ext->screen 16 bits */ +#define EXT_DDA_Y_INIT 0xd5 /* ext->screen 16 bits */ +#define EXT_DDA_Y_INC 0xd7 /* ext->screen 16 bits */ + +#define EXT_VID_FIFO_CTL 0xd9 + +#define EXT_VID_FMT 0xdb +#define EXT_VID_FMT_YUV422 0x00 /* formats - does this cause conversion? */ +#define EXT_VID_FMT_RGB555 0x01 +#define EXT_VID_FMT_RGB565 0x02 +#define EXT_VID_FMT_RGB888_24 0x03 +#define EXT_VID_FMT_RGB888_32 0x04 +#define EXT_VID_FMT_RGB8 0x05 +#define EXT_VID_FMT_RGB4444 0x06 +#define EXT_VID_FMT_RGB8T 0x07 +#define EXT_VID_FMT_DUP_PIX_ZOON 0x08 /* duplicate pixel zoom */ +#define EXT_VID_FMT_MOD_3RD_PIX 0x20 /* modify 3rd duplicated pixel */ +#define EXT_VID_FMT_DBL_H_PIX 0x40 /* double horiz pixels */ +#define EXT_VID_FMT_YUV128 0x80 /* YUV data offset by 128 */ + +#define EXT_VID_DISP_CTL1 0xdc +#define EXT_VID_DISP_CTL1_INTRAM 0x01 /* video pixels go to internal RAM */ +#define EXT_VID_DISP_CTL1_IGNORE_CCOMP 0x02 /* ignore colour compare registers */ +#define EXT_VID_DISP_CTL1_NOCLIP 0x04 /* do not clip to 16235,16240 */ +#define EXT_VID_DISP_CTL1_UV_AVG 0x08 /* U/V data is averaged */ +#define EXT_VID_DISP_CTL1_Y128 0x10 /* Y data offset by 128 (if YUV128 set) */ +#define EXT_VID_DISP_CTL1_VINTERPOL_OFF 0x20 /* disable vertical interpolation */ +#define EXT_VID_DISP_CTL1_FULL_WIN 0x40 /* video out window full */ +#define EXT_VID_DISP_CTL1_ENABLE_WINDOW 0x80 /* enable video window */ + +#define EXT_VID_FIFO_CTL1 0xdd +#define EXT_VID_FIFO_CTL1_OE_HIGH 0x02 +#define EXT_VID_FIFO_CTL1_INTERLEAVE 0x04 /* enable interleaved memory read */ + +#define EXT_ROM_UCB4GH 0xe5 +#define EXT_ROM_UCB4GH_FREEZE 0x02 /* capture frozen */ +#define EXT_ROM_UCB4GH_ODDFRAME 0x04 /* 1 = odd frame captured */ +#define EXT_ROM_UCB4GH_1HL 0x08 /* first horizonal line after VGT falling edge */ +#define EXT_ROM_UCB4GH_ODD 0x10 /* odd frame indicator */ +#define EXT_ROM_UCB4GH_INTSTAT 0x20 /* video interrupt */ + +#define VFAC_CTL1 0xe8 +#define VFAC_CTL1_CAPTURE 0x01 /* capture enable (only when VSYNC high)*/ +#define VFAC_CTL1_VFAC_ENABLE 0x02 /* vfac enable */ +#define VFAC_CTL1_FREEZE_CAPTURE 0x04 /* freeze capture */ +#define VFAC_CTL1_FREEZE_CAPTURE_SYNC 0x08 /* sync freeze capture */ +#define VFAC_CTL1_VALIDFRAME_SRC 0x10 /* select valid frame source */ +#define VFAC_CTL1_PHILIPS 0x40 /* select Philips mode */ +#define VFAC_CTL1_MODVINTERPOLCLK 0x80 /* modify vertical interpolation clocl */ + +#define VFAC_CTL2 0xe9 +#define VFAC_CTL2_INVERT_VIDDATAVALID 0x01 /* invert video data valid */ +#define VFAC_CTL2_INVERT_GRAPHREADY 0x02 /* invert graphic ready output sig */ +#define VFAC_CTL2_INVERT_DATACLK 0x04 /* invert data clock signal */ +#define VFAC_CTL2_INVERT_HSYNC 0x08 /* invert hsync input */ +#define VFAC_CTL2_INVERT_VSYNC 0x10 /* invert vsync input */ +#define VFAC_CTL2_INVERT_FRAME 0x20 /* invert frame odd/even input */ +#define VFAC_CTL2_INVERT_BLANK 0x40 /* invert blank output */ +#define VFAC_CTL2_INVERT_OVSYNC 0x80 /* invert other vsync input */ + +#define VFAC_CTL3 0xea +#define VFAC_CTL3_CAP_LARGE_FIFO 0x01 /* large capture fifo */ +#define VFAC_CTL3_CAP_INTERLACE 0x02 /* capture odd and even fields */ +#define VFAC_CTL3_CAP_HOLD_4NS 0x00 /* hold capture data for 4ns */ +#define VFAC_CTL3_CAP_HOLD_2NS 0x04 /* hold capture data for 2ns */ +#define VFAC_CTL3_CAP_HOLD_6NS 0x08 /* hold capture data for 6ns */ +#define VFAC_CTL3_CAP_HOLD_0NS 0x0c /* hold capture data for 0ns */ +#define VFAC_CTL3_CHROMAKEY 0x20 /* capture data will be chromakeyed */ +#define VFAC_CTL3_CAP_IRQ 0x40 /* enable capture interrupt */ + +#define CAP_MEM_START 0xeb /* 18 bits */ +#define CAP_MAP_WIDTH 0xed /* high 6 bits */ +#define CAP_PITCH 0xee /* 8 bits */ + +#define CAP_CTL_MISC 0xef +#define CAP_CTL_MISC_HDIV 0x01 +#define CAP_CTL_MISC_HDIV4 0x02 +#define CAP_CTL_MISC_ODDEVEN 0x04 +#define CAP_CTL_MISC_HSYNCDIV2 0x08 +#define CAP_CTL_MISC_SYNCTZHIGH 0x10 +#define CAP_CTL_MISC_SYNCTZOR 0x20 +#define CAP_CTL_MISC_DISPUSED 0x80 + +#define REG_BANK 0xfa +#define REG_BANK_X 0x00 +#define REG_BANK_Y 0x01 +#define REG_BANK_W 0x02 +#define REG_BANK_T 0x03 +#define REG_BANK_J 0x04 +#define REG_BANK_K 0x05 + +/* + * Bus-master + */ +#define BM_VID_ADDR_LOW 0xbc040 +#define BM_VID_ADDR_HIGH 0xbc044 +#define BM_ADDRESS_LOW 0xbc080 +#define BM_ADDRESS_HIGH 0xbc084 +#define BM_LENGTH 0xbc088 +#define BM_CONTROL 0xbc08c +#define BM_CONTROL_ENABLE 0x01 /* enable transfer */ +#define BM_CONTROL_IRQEN 0x02 /* enable IRQ at end of transfer */ +#define BM_CONTROL_INIT 0x04 /* initialise status & count */ +#define BM_COUNT 0xbc090 /* read-only */ + +/* + * TV registers + */ +#define TV_VBLANK_EVEN_START 0xbe43c +#define TV_VBLANK_EVEN_END 0xbe440 +#define TV_VBLANK_ODD_START 0xbe444 +#define TV_VBLANK_ODD_END 0xbe448 +#define TV_SYNC_YGAIN 0xbe44c +#define TV_UV_GAIN 0xbe450 +#define TV_PED_UVDET 0xbe454 +#define TV_UV_BURST_AMP 0xbe458 +#define TV_HSYNC_START 0xbe45c +#define TV_HSYNC_END 0xbe460 +#define TV_Y_DELAY1 0xbe464 +#define TV_Y_DELAY2 0xbe468 +#define TV_UV_DELAY1 0xbe46c +#define TV_BURST_START 0xbe470 +#define TV_BURST_END 0xbe474 +#define TV_HBLANK_START 0xbe478 +#define TV_HBLANK_END 0xbe47c +#define TV_PED_EVEN_START 0xbe480 +#define TV_PED_EVEN_END 0xbe484 +#define TV_PED_ODD_START 0xbe488 +#define TV_PED_ODD_END 0xbe48c +#define TV_VSYNC_EVEN_START 0xbe490 +#define TV_VSYNC_EVEN_END 0xbe494 +#define TV_VSYNC_ODD_START 0xbe498 +#define TV_VSYNC_ODD_END 0xbe49c +#define TV_SCFL 0xbe4a0 +#define TV_SCFH 0xbe4a4 +#define TV_SCP 0xbe4a8 +#define TV_DELAYBYPASS 0xbe4b4 +#define TV_EQL_END 0xbe4bc +#define TV_SERR_START 0xbe4c0 +#define TV_SERR_END 0xbe4c4 +#define TV_CTL 0xbe4dc /* reflects a previous register- MVFCLR, MVPCLR etc P241*/ +#define TV_VSYNC_VGA_HS 0xbe4e8 +#define TV_FLICK_XMIN 0xbe514 +#define TV_FLICK_XMAX 0xbe518 +#define TV_FLICK_YMIN 0xbe51c +#define TV_FLICK_YMAX 0xbe520 + +/* + * Graphics Co-processor + */ +#define CO_REG_CONTROL 0xbf011 +#define CO_CTRL_BUSY 0x80 +#define CO_CTRL_CMDFULL 0x04 +#define CO_CTRL_FIFOEMPTY 0x02 +#define CO_CTRL_READY 0x01 + +#define CO_REG_SRC_WIDTH 0xbf018 +#define CO_REG_PIXFMT 0xbf01c +#define CO_PIXFMT_32BPP 0x03 +#define CO_PIXFMT_24BPP 0x02 +#define CO_PIXFMT_16BPP 0x01 +#define CO_PIXFMT_8BPP 0x00 + +#define CO_REG_FGMIX 0xbf048 +#define CO_FG_MIX_ZERO 0x00 +#define CO_FG_MIX_SRC_AND_DST 0x01 +#define CO_FG_MIX_SRC_AND_NDST 0x02 +#define CO_FG_MIX_SRC 0x03 +#define CO_FG_MIX_NSRC_AND_DST 0x04 +#define CO_FG_MIX_DST 0x05 +#define CO_FG_MIX_SRC_XOR_DST 0x06 +#define CO_FG_MIX_SRC_OR_DST 0x07 +#define CO_FG_MIX_NSRC_AND_NDST 0x08 +#define CO_FG_MIX_SRC_XOR_NDST 0x09 +#define CO_FG_MIX_NDST 0x0a +#define CO_FG_MIX_SRC_OR_NDST 0x0b +#define CO_FG_MIX_NSRC 0x0c +#define CO_FG_MIX_NSRC_OR_DST 0x0d +#define CO_FG_MIX_NSRC_OR_NDST 0x0e +#define CO_FG_MIX_ONES 0x0f + +#define CO_REG_FGCOLOUR 0xbf058 +#define CO_REG_BGCOLOUR 0xbf05c +#define CO_REG_PIXWIDTH 0xbf060 +#define CO_REG_PIXHEIGHT 0xbf062 +#define CO_REG_X_PHASE 0xbf078 +#define CO_REG_CMD_L 0xbf07c +#define CO_CMD_L_PATTERN_FGCOL 0x8000 +#define CO_CMD_L_INC_LEFT 0x0004 +#define CO_CMD_L_INC_UP 0x0002 + +#define CO_REG_CMD_H 0xbf07e +#define CO_CMD_H_BGSRCMAP 0x8000 /* otherwise bg colour */ +#define CO_CMD_H_FGSRCMAP 0x2000 /* otherwise fg colour */ +#define CO_CMD_H_BLITTER 0x0800 + +#define CO_REG_SRC1_PTR 0xbf170 +#define CO_REG_SRC2_PTR 0xbf174 +#define CO_REG_DEST_PTR 0xbf178 +#define CO_REG_DEST_WIDTH 0xbf218 + +/* + * Private structure + */ +struct cfb_info; + +struct cyberpro_info { + struct pci_dev *dev; + unsigned char __iomem *regs; + char __iomem *fb; + char dev_name[32]; + unsigned int fb_size; + unsigned int chip_id; + + /* + * The following is a pointer to be passed into the + * functions below. The modules outside the main + * cyber2000fb.c driver have no knowledge as to what + * is within this structure. + */ + struct cfb_info *info; + + /* + * Use these to enable the BM or TV registers. In an SMP + * environment, these two function pointers should only be + * called from the module_init() or module_exit() + * functions. + */ + void (*enable_extregs)(struct cfb_info *); + void (*disable_extregs)(struct cfb_info *); +}; + +#define ID_IGA_1682 0 +#define ID_CYBERPRO_2000 1 +#define ID_CYBERPRO_2010 2 +#define ID_CYBERPRO_5000 3 + +struct fb_var_screeninfo; + +/* + * Note! Writing to the Cyber20x0 registers from an interrupt + * routine is definitely a bad idea atm. + */ +int cyber2000fb_attach(struct cyberpro_info *info, int idx); +void cyber2000fb_detach(int idx); +void cyber2000fb_enable_extregs(struct cfb_info *cfb); +void cyber2000fb_disable_extregs(struct cfb_info *cfb); +void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var); diff --git a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c new file mode 100644 index 000000000000..a3e189f90a7d --- /dev/null +++ b/drivers/video/cyberfb.c @@ -0,0 +1,2296 @@ +/* +* linux/drivers/video/cyberfb.c -- CyberVision64 frame buffer device +* $Id: cyberfb.c,v 1.6 1998/09/11 04:54:58 abair Exp $ +* +* Copyright (C) 1998 Alan Bair +* +* This file is based on two CyberVision64 frame buffer device drivers +* +* The second CyberVision64 frame buffer device (cvision.c cvision_core.c): +* +* Copyright (c) 1997 Antonio Santos +* +* Released as a patch to 2.1.35, but never included in the source tree. +* This is based on work from the NetBSD CyberVision64 frame buffer driver +* and support files (grf_cv.c, grf_cvreg.h, ite_cv.c): +* Permission to use the source of this driver was obtained from the +* author Michael Teske by Alan Bair. +* +* Copyright (c) 1995 Michael Teske +* +* The first CyberVision64 frame buffer device (cyberfb.c): +* +* Copyright (C) 1996 Martin Apel +* Geert Uytterhoeven +* +* Which is based on the Amiga frame buffer device (amifb.c): +* +* Copyright (C) 1995 Geert Uytterhoeven +* +* +* History: +* - 22 Dec 95: Original version by Martin Apel +* - 05 Jan 96: Geert: integration into the current source tree +* - 01 Aug 98: Alan: Merge in code from cvision.c and cvision_core.c +* $Log: cyberfb.c,v $ +* Revision 1.6 1998/09/11 04:54:58 abair +* Update for 2.1.120 change in include file location. +* Clean up for public release. +* +* Revision 1.5 1998/09/03 04:27:13 abair +* Move cv64_load_video_mode to cyber_set_video so a new video mode is install +* with each change of the 'var' data. +* +* Revision 1.4 1998/09/01 00:31:17 abair +* Put in a set of default 8,16,24 bpp modes and map cyber8,16 to them. +* Update operations with 'par' to handle a more complete set of parameter +* values for encode/decode process. +* +* Revision 1.3 1998/08/31 21:31:33 abair +* Swap 800x490 for 640x480 video mode and more cleanup. +* Abandon idea to resurrect "custom" mode setting via kernel opts, +* instead work on making use of fbset program to do this. +* +* Revision 1.2 1998/08/31 06:17:08 abair +* Make updates for changes in cyberfb.c released in 2.1.119 +* and do some cleanup of the code. +* +* Revision 1.1 1998/08/29 18:38:31 abair +* Initial revision +* +* Revision 1.3 1998/08/17 06:21:53 abair +* Remove more redundant code after merging in cvision_core.c +* Set blanking by colormap to pale red to detect this vs trying to +* use video blanking. More formating to Linux code style. +* +* Revision 1.2 1998/08/15 17:51:37 abair +* Added cvision_core.c code from 2.1.35 patches. +* Changed to compile correctly and switch to using initialization +* code. Added debugging and dropping of duplicate code. +* +* +* +* 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/kernel.h> +#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/zorro.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/pgtable.h> +#include <asm/amigahw.h> +#include <asm/io.h> + +#include "cyberfb.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> + +/*#define CYBERFBDEBUG*/ +#ifdef CYBERFBDEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +static void cv64_dump(void); +#else +#define DPRINTK(fmt, args...) +#endif + +#define wb_64(regs,reg,dat) (*(((volatile unsigned char *)regs) + reg) = dat) +#define rb_64(regs, reg) (*(((volatile unsigned char *)regs) + reg)) + +#define ww_64(regs,reg,dat) (*((volatile unsigned short *)(regs + reg) = dat) + +struct cyberfb_par { + struct fb_var_screeninfo var; + __u32 type; + __u32 type_aux; + __u32 visual; + __u32 line_length; +}; + +static struct cyberfb_par current_par; + +static int current_par_valid = 0; + +static struct display disp; +static struct fb_info fb_info; + + +/* + * Frame Buffer Name + */ + +static char cyberfb_name[16] = "Cybervision"; + + +/* + * CyberVision Graphics Board + */ + +static unsigned char Cyber_colour_table [256][3]; +static unsigned long CyberSize; +static volatile unsigned char *CyberBase; +static volatile unsigned char *CyberMem; +static volatile unsigned char *CyberRegs; +static unsigned long CyberMem_phys; +static unsigned long CyberRegs_phys; + +/* + * Predefined Video Modes + */ + +static struct { + const char *name; + struct fb_var_screeninfo var; +} cyberfb_predefined[] __initdata = { + { "640x480-8", { /* Default 8 BPP mode (cyber8) */ + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, + { "640x480-16", { /* Default 16 BPP mode (cyber16) */ + 640, 480, 640, 480, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, + { "640x480-24", { /* Default 24 BPP mode */ + 640, 480, 640, 480, 0, 0, 24, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, + { "800x490-8", { /* Cybervision 8 bpp */ + /* NO Acceleration */ + 800, 490, 800, 490, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, 33333, 80, 24, 23, 1, 56, 8, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, +/* I can't test these with my monitor, but I suspect they will + * be OK, since Antonio Santos indicated he had tested them in + * his system. + */ + { "800x600-8", { /* Cybervision 8 bpp */ + 800, 600, 800, 600, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 27778, 64, 24, 22, 1, 72, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, + { "1024x768-8", { /* Cybervision 8 bpp */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 16667, 224, 72, 60, 12, 168, 4, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, + { "1152x886-8", { /* Cybervision 8 bpp */ + 1152, 886, 1152, 886, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 15873, 184, 40, 24, 1, 56, 16, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, + { "1280x1024-8", { /* Cybervision 8 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 16667, 256, 48, 50, 12, 72, 4, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_INTERLACED + }} +}; + +#define NUM_TOTAL_MODES ARRAY_SIZE(cyberfb_predefined) + +static int Cyberfb_inverse = 0; + +/* + * Some default modes + */ + +#define CYBER8_DEFMODE (0) +#define CYBER16_DEFMODE (1) + +static struct fb_var_screeninfo cyberfb_default; +static int cyberfb_usermode __initdata = 0; + +/* + * Interface used by the world + */ + +int cyberfb_setup(char *options); + +static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int cyberfb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int cyberfb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int cyberfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int cyberfb_blank(int blank, struct fb_info *info); + +/* + * Interface to the low level console driver + */ + +int cyberfb_init(void); +static int Cyberfb_switch(int con, struct fb_info *info); +static int Cyberfb_updatevar(int con, struct fb_info *info); + +/* + * Text console acceleration + */ + +#ifdef FBCON_HAS_CFB8 +static struct display_switch fbcon_cyber8; +#endif + +/* + * Accelerated Functions used by the low level console driver + */ + +static void Cyber_WaitQueue(u_short fifo); +static void Cyber_WaitBlit(void); +static void Cyber_BitBLT(u_short curx, u_short cury, u_short destx, + u_short desty, u_short width, u_short height, + u_short mode); +static void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height, + u_short mode, u_short color); +#if 0 +static void Cyber_MoveCursor(u_short x, u_short y); +#endif + +/* + * Hardware Specific Routines + */ + +static int Cyber_init(void); +static int Cyber_encode_fix(struct fb_fix_screeninfo *fix, + struct cyberfb_par *par); +static int Cyber_decode_var(struct fb_var_screeninfo *var, + struct cyberfb_par *par); +static int Cyber_encode_var(struct fb_var_screeninfo *var, + struct cyberfb_par *par); +static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info); + +/* + * Internal routines + */ + +static void cyberfb_get_par(struct cyberfb_par *par); +static void cyberfb_set_par(struct cyberfb_par *par); +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive); +static void cyberfb_set_disp(int con, struct fb_info *info); +static int get_video_mode(const char *name); + +/* For cvision_core.c */ +static unsigned short cv64_compute_clock(unsigned long); +static int cv_has_4mb (volatile unsigned char *); +static void cv64_board_init (void); +static void cv64_load_video_mode (struct fb_var_screeninfo *); + + +/* -------------------- Hardware specific routines ------------------------- */ + + +/* + * Initialization + * + * Set the default video mode for this chipset. If a video mode was + * specified on the command line, it will override the default mode. + */ + +static int Cyber_init(void) +{ + volatile unsigned char *regs = CyberRegs; + volatile unsigned long *CursorBase; + int i; + DPRINTK("ENTER\n"); + +/* Init local cmap as greyscale levels */ + for (i = 0; i < 256; i++) { + Cyber_colour_table [i][0] = i; + Cyber_colour_table [i][1] = i; + Cyber_colour_table [i][2] = i; + } + +/* Initialize the board and determine fbmem size */ + cv64_board_init(); +#ifdef CYBERFBDEBUG + DPRINTK("Register state after initing board\n"); + cv64_dump(); +#endif +/* Clear framebuffer memory */ + DPRINTK("Clear framebuffer memory\n"); + memset ((char *)CyberMem, 0, CyberSize); + +/* Disable hardware cursor */ + DPRINTK("Disable HW cursor\n"); + wb_64(regs, S3_CRTC_ADR, S3_REG_LOCK2); + wb_64(regs, S3_CRTC_DATA, 0xa0); + wb_64(regs, S3_CRTC_ADR, S3_HGC_MODE); + wb_64(regs, S3_CRTC_DATA, 0x00); + wb_64(regs, S3_CRTC_ADR, S3_HWGC_DX); + wb_64(regs, S3_CRTC_DATA, 0x00); + wb_64(regs, S3_CRTC_ADR, S3_HWGC_DY); + wb_64(regs, S3_CRTC_DATA, 0x00); + +/* Initialize hardware cursor */ + DPRINTK("Init HW cursor\n"); + CursorBase = (u_long *)((char *)(CyberMem) + CyberSize - 0x400); + for (i=0; i < 8; i++) + { + *(CursorBase +(i*4)) = 0xffffff00; + *(CursorBase+1+(i*4)) = 0xffff0000; + *(CursorBase+2+(i*4)) = 0xffff0000; + *(CursorBase+3+(i*4)) = 0xffff0000; + } + for (i=8; i < 64; i++) + { + *(CursorBase +(i*4)) = 0xffff0000; + *(CursorBase+1+(i*4)) = 0xffff0000; + *(CursorBase+2+(i*4)) = 0xffff0000; + *(CursorBase+3+(i*4)) = 0xffff0000; + } + + cyberfb_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, NULL /* unused */); + cyberfb_setcolreg (254, 0, 0, 0, 0, NULL /* unused */); + + DPRINTK("EXIT\n"); + return 0; +} + + +/* + * This function should fill in the `fix' structure based on the + * values in the `par' structure. + */ + +static int Cyber_encode_fix(struct fb_fix_screeninfo *fix, + struct cyberfb_par *par) +{ + DPRINTK("ENTER\n"); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, cyberfb_name); + fix->smem_start = CyberMem_phys; + fix->smem_len = CyberSize; + fix->mmio_start = CyberRegs_phys; + fix->mmio_len = 0x10000; + + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + if (par->var.bits_per_pixel == 15 || par->var.bits_per_pixel == 16 || + par->var.bits_per_pixel == 24 || par->var.bits_per_pixel == 32) { + fix->visual = FB_VISUAL_DIRECTCOLOR; + } else { + fix->visual = FB_VISUAL_PSEUDOCOLOR; + } + + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = 0; + fix->accel = FB_ACCEL_S3_TRIO64; + + DPRINTK("EXIT\n"); + return(0); +} + + +/* +* Fill the `par' structure based on the values in `var'. +* TODO: Verify and adjust values, return -EINVAL if bad. +*/ + +static int Cyber_decode_var(struct fb_var_screeninfo *var, + struct cyberfb_par *par) +{ + DPRINTK("ENTER\n"); + par->var.xres = var->xres; + par->var.yres = var->yres; + par->var.xres_virtual = var->xres_virtual; + par->var.yres_virtual = var->yres_virtual; + par->var.xoffset = var->xoffset; + par->var.yoffset = var->yoffset; + par->var.bits_per_pixel = var->bits_per_pixel; + par->var.grayscale = var->grayscale; + par->var.red = var->red; + par->var.green = var->green; + par->var.blue = var->blue; + par->var.transp = var->transp; + par->var.nonstd = var->nonstd; + par->var.activate = var->activate; + par->var.height = var->height; + par->var.width = var->width; + if (var->accel_flags & FB_ACCELF_TEXT) { + par->var.accel_flags = FB_ACCELF_TEXT; + } else { + par->var.accel_flags = 0; + } + par->var.pixclock = var->pixclock; + par->var.left_margin = var->left_margin; + par->var.right_margin = var->right_margin; + par->var.upper_margin = var->upper_margin; + par->var.lower_margin = var->lower_margin; + par->var.hsync_len = var->hsync_len; + par->var.vsync_len = var->vsync_len; + par->var.sync = var->sync; + par->var.vmode = var->vmode; + DPRINTK("EXIT\n"); + return(0); +} + +/* +* Fill the `var' structure based on the values in `par' and maybe +* other values read out of the hardware. +*/ + +static int Cyber_encode_var(struct fb_var_screeninfo *var, + struct cyberfb_par *par) +{ + DPRINTK("ENTER\n"); + var->xres = par->var.xres; + var->yres = par->var.yres; + var->xres_virtual = par->var.xres_virtual; + var->yres_virtual = par->var.yres_virtual; + var->xoffset = par->var.xoffset; + var->yoffset = par->var.yoffset; + + var->bits_per_pixel = par->var.bits_per_pixel; + var->grayscale = par->var.grayscale; + + var->red = par->var.red; + var->green = par->var.green; + var->blue = par->var.blue; + var->transp = par->var.transp; + + var->nonstd = par->var.nonstd; + var->activate = par->var.activate; + + var->height = par->var.height; + var->width = par->var.width; + + var->accel_flags = par->var.accel_flags; + + var->pixclock = par->var.pixclock; + var->left_margin = par->var.left_margin; + var->right_margin = par->var.right_margin; + var->upper_margin = par->var.upper_margin; + var->lower_margin = par->var.lower_margin; + var->hsync_len = par->var.hsync_len; + var->vsync_len = par->var.vsync_len; + var->sync = par->var.sync; + var->vmode = par->var.vmode; + + DPRINTK("EXIT\n"); + return(0); +} + + +/* + * Set a single color register. Return != 0 for invalid regno. + */ + +static int cyberfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + volatile unsigned char *regs = CyberRegs; + + /*DPRINTK("ENTER\n");*/ + if (regno > 255) { + DPRINTK("EXIT - Register # > 255\n"); + return (1); + } + + wb_64(regs, 0x3c8, (unsigned char) regno); + + red >>= 10; + green >>= 10; + blue >>= 10; + + Cyber_colour_table [regno][0] = red; + Cyber_colour_table [regno][1] = green; + Cyber_colour_table [regno][2] = blue; + + wb_64(regs, 0x3c9, red); + wb_64(regs, 0x3c9, green); + wb_64(regs, 0x3c9, blue); + + /*DPRINTK("EXIT\n");*/ + return (0); +} + + +/* +* Read a single color register and split it into +* colors/transparent. Return != 0 for invalid regno. +*/ + +static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info) +{ + int t; + + /*DPRINTK("ENTER\n");*/ + if (regno > 255) { + DPRINTK("EXIT - Register # > 255\n"); + return (1); + } + /* ARB This shifting & oring seems VERY strange */ + t = Cyber_colour_table [regno][0]; + *red = (t<<10) | (t<<4) | (t>>2); + t = Cyber_colour_table [regno][1]; + *green = (t<<10) | (t<<4) | (t>>2); + t = Cyber_colour_table [regno][2]; + *blue = (t<<10) | (t<<4) | (t>>2); + *transp = 0; + /*DPRINTK("EXIT\n");*/ + return (0); +} + + +/* +* (Un)Blank the screen +* blank: 1 = zero fb cmap +* 0 = restore fb cmap from local cmap +*/ +static int cyberfb_blank(int blank, struct fb_info *info) +{ + volatile unsigned char *regs = CyberRegs; + int i; + + DPRINTK("ENTER\n"); +#if 0 +/* Blank by turning gfx off */ + gfx_on_off (1, regs); +#else + if (blank) { + for (i = 0; i < 256; i++) { + wb_64(regs, 0x3c8, (unsigned char) i); + /* ARB Pale red to detect this blanking method */ + wb_64(regs, 0x3c9, 48); + wb_64(regs, 0x3c9, 0); + wb_64(regs, 0x3c9, 0); + } + } else { + for (i = 0; i < 256; i++) { + wb_64(regs, 0x3c8, (unsigned char) i); + wb_64(regs, 0x3c9, Cyber_colour_table[i][0]); + wb_64(regs, 0x3c9, Cyber_colour_table[i][1]); + wb_64(regs, 0x3c9, Cyber_colour_table[i][2]); + } + } +#endif + DPRINTK("EXIT\n"); + return 0; +} + + +/************************************************************** + * We are waiting for "fifo" FIFO-slots empty + */ +static void Cyber_WaitQueue (u_short fifo) +{ + unsigned short status; + + DPRINTK("ENTER\n"); + do { + status = *((u_short volatile *)(CyberRegs + S3_GP_STAT)); + } while (status & fifo); + DPRINTK("EXIT\n"); +} + +/************************************************************** + * We are waiting for Hardware (Graphics Engine) not busy + */ +static void Cyber_WaitBlit (void) +{ + unsigned short status; + + DPRINTK("ENTER\n"); + do { + status = *((u_short volatile *)(CyberRegs + S3_GP_STAT)); + } while (status & S3_HDW_BUSY); + DPRINTK("EXIT\n"); +} + +/************************************************************** + * BitBLT - Through the Plane + */ +static void Cyber_BitBLT (u_short curx, u_short cury, u_short destx, + u_short desty, u_short width, u_short height, + u_short mode) +{ + volatile unsigned char *regs = CyberRegs; + u_short blitcmd = S3_BITBLT; + + DPRINTK("ENTER\n"); + /* Set drawing direction */ + /* -Y, X maj, -X (default) */ + if (curx > destx) { + blitcmd |= 0x0020; /* Drawing direction +X */ + } else { + curx += (width - 1); + destx += (width - 1); + } + + if (cury > desty) { + blitcmd |= 0x0080; /* Drawing direction +Y */ + } else { + cury += (height - 1); + desty += (height - 1); + } + + Cyber_WaitQueue (0x8000); + + *((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000; + *((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0060 | mode); + + *((u_short volatile *)(regs + S3_CUR_X)) = curx; + *((u_short volatile *)(regs + S3_CUR_Y)) = cury; + + *((u_short volatile *)(regs + S3_DESTX_DIASTP)) = destx; + *((u_short volatile *)(regs + S3_DESTY_AXSTP)) = desty; + + *((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1; + *((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width - 1; + + *((u_short volatile *)(regs + S3_CMD)) = blitcmd; + DPRINTK("EXIT\n"); +} + +/************************************************************** + * Rectangle Fill Solid + */ +static void Cyber_RectFill (u_short x, u_short y, u_short width, + u_short height, u_short mode, u_short color) +{ + volatile unsigned char *regs = CyberRegs; + u_short blitcmd = S3_FILLEDRECT; + + DPRINTK("ENTER\n"); + Cyber_WaitQueue (0x8000); + + *((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000; + *((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0020 | mode); + + *((u_short volatile *)(regs + S3_MULT_MISC)) = 0xe000; + *((u_short volatile *)(regs + S3_FRGD_COLOR)) = color; + + *((u_short volatile *)(regs + S3_CUR_X)) = x; + *((u_short volatile *)(regs + S3_CUR_Y)) = y; + + *((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1; + *((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width - 1; + + *((u_short volatile *)(regs + S3_CMD)) = blitcmd; + DPRINTK("EXIT\n"); +} + + +#if 0 +/************************************************************** + * Move cursor to x, y + */ +static void Cyber_MoveCursor (u_short x, u_short y) +{ + volatile unsigned char *regs = CyberRegs; + DPRINTK("ENTER\n"); + *(regs + S3_CRTC_ADR) = 0x39; + *(regs + S3_CRTC_DATA) = 0xa0; + + *(regs + S3_CRTC_ADR) = S3_HWGC_ORGX_H; + *(regs + S3_CRTC_DATA) = (char)((x & 0x0700) >> 8); + *(regs + S3_CRTC_ADR) = S3_HWGC_ORGX_L; + *(regs + S3_CRTC_DATA) = (char)(x & 0x00ff); + + *(regs + S3_CRTC_ADR) = S3_HWGC_ORGY_H; + *(regs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8); + *(regs + S3_CRTC_ADR) = S3_HWGC_ORGY_L; + *(regs + S3_CRTC_DATA) = (char)(y & 0x00ff); + DPRINTK("EXIT\n"); +} +#endif + + +/* -------------------- Generic routines ---------------------------------- */ + + +/* + * Fill the hardware's `par' structure. + */ + +static void cyberfb_get_par(struct cyberfb_par *par) +{ + DPRINTK("ENTER\n"); + if (current_par_valid) { + *par = current_par; + } else { + Cyber_decode_var(&cyberfb_default, par); + } + DPRINTK("EXIT\n"); +} + + +static void cyberfb_set_par(struct cyberfb_par *par) +{ + DPRINTK("ENTER\n"); + current_par = *par; + current_par_valid = 1; + DPRINTK("EXIT\n"); +} + + +static void cyber_set_video(struct fb_var_screeninfo *var) +{ + + /* Load the video mode defined by the 'var' data */ + cv64_load_video_mode (var); +#ifdef CYBERFBDEBUG + DPRINTK("Register state after loading video mode\n"); + cv64_dump(); +#endif +} + + +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +{ + int err, activate; + struct cyberfb_par par; + + DPRINTK("ENTER\n"); + if ((err = Cyber_decode_var(var, &par))) { + DPRINTK("EXIT - decode_var failed\n"); + return(err); + } + activate = var->activate; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) + cyberfb_set_par(&par); + Cyber_encode_var(var, &par); + var->activate = activate; + + cyber_set_video(var); + DPRINTK("EXIT\n"); + return 0; +} + +/* + * Get the Fixed Part of the Display + */ + +static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct cyberfb_par par; + int error = 0; + + DPRINTK("ENTER\n"); + if (con == -1) { + cyberfb_get_par(&par); + } else { + error = Cyber_decode_var(&fb_display[con].var, &par); + } + DPRINTK("EXIT\n"); + return(error ? error : Cyber_encode_fix(fix, &par)); +} + + +/* + * Get the User Defined Part of the Display + */ + +static int cyberfb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct cyberfb_par par; + int error = 0; + + DPRINTK("ENTER\n"); + if (con == -1) { + cyberfb_get_par(&par); + error = Cyber_encode_var(var, &par); + disp.var = *var; /* ++Andre: don't know if this is the right place */ + } else { + *var = fb_display[con].var; + } + + DPRINTK("EXIT\n"); + return(error); +} + + +static void cyberfb_set_disp(int con, struct fb_info *info) +{ + struct fb_fix_screeninfo fix; + struct display *display; + + DPRINTK("ENTER\n"); + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + cyberfb_get_fix(&fix, con, info); + if (con == -1) + con = 0; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->can_soft_blank = 1; + display->inverse = Cyberfb_inverse; + switch (display->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + if (display->var.accel_flags & FB_ACCELF_TEXT) { + display->dispsw = &fbcon_cyber8; +#warning FIXME: We should reinit the graphics engine here + } else + display->dispsw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + display->dispsw = &fbcon_cfb16; + break; +#endif + default: + display->dispsw = NULL; + break; + } + DPRINTK("EXIT\n"); +} + + +/* + * Set the User Defined Part of the Display + */ + +static int cyberfb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel; + + DPRINTK("ENTER\n"); + if ((err = do_fb_set_var(var, con == info->currcon))) { + DPRINTK("EXIT - do_fb_set_var failed\n"); + return(err); + } + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres = fb_display[con].var.xres; + oldyres = fb_display[con].var.yres; + oldvxres = fb_display[con].var.xres_virtual; + oldvyres = fb_display[con].var.yres_virtual; + oldbpp = fb_display[con].var.bits_per_pixel; + oldaccel = fb_display[con].var.accel_flags; + fb_display[con].var = *var; + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || + oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel || + oldaccel != var->accel_flags) { + cyberfb_set_disp(con, info); + (*fb_info.changevar)(con); + fb_alloc_cmap(&fb_display[con].cmap, 0, 0); + do_install_cmap(con, info); + } + } + var->activate = 0; + DPRINTK("EXIT\n"); + return(0); +} + + +/* + * Get the Colormap + */ + +static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + DPRINTK("ENTER\n"); + if (con == info->currcon) { /* current console? */ + DPRINTK("EXIT - console is current console\n"); + return(fb_get_cmap(cmap, kspc, Cyber_getcolreg, info)); + } else if (fb_display[con].cmap.len) { /* non default colormap? */ + DPRINTK("Use console cmap\n"); + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + } else { + DPRINTK("Use default cmap\n"); + fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), + cmap, kspc ? 0 : 2); + } + DPRINTK("EXIT\n"); + return(0); +} + +static struct fb_ops cyberfb_ops = { + .owner = THIS_MODULE, + .fb_get_fix = cyberfb_get_fix, + .fb_get_var = cyberfb_get_var, + .fb_set_var = cyberfb_set_var, + .fb_get_cmap = cyberfb_get_cmap, + .fb_set_cmap = gen_set_cmap, + .fb_setcolreg = cyberfb_setcolreg, + .fb_blank = cyberfb_blank, +}; + +int __init cyberfb_setup(char *options) +{ + char *this_opt; + DPRINTK("ENTER\n"); + + fb_info.fontname[0] = '\0'; + + if (!options || !*options) { + DPRINTK("EXIT - no options\n"); + return 0; + } + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + if (!strcmp(this_opt, "inverse")) { + Cyberfb_inverse = 1; + fb_invert_cmaps(); + } else if (!strncmp(this_opt, "font:", 5)) { + strcpy(fb_info.fontname, this_opt+5); + } else if (!strcmp (this_opt, "cyber8")) { + cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var; + cyberfb_usermode = 1; + } else if (!strcmp (this_opt, "cyber16")) { + cyberfb_default = cyberfb_predefined[CYBER16_DEFMODE].var; + cyberfb_usermode = 1; + } else get_video_mode(this_opt); + } + + DPRINTK("default mode: xres=%d, yres=%d, bpp=%d\n", + cyberfb_default.xres, + cyberfb_default.yres, + cyberfb_default.bits_per_pixel); + DPRINTK("EXIT\n"); + return 0; +} + +/* + * Initialization + */ + +int __init cyberfb_init(void) +{ + unsigned long board_addr, board_size; + struct cyberfb_par par; + struct zorro_dev *z = NULL; + DPRINTK("ENTER\n"); + + while ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERVISION64, z))) { + board_addr = z->resource.start; + board_size = z->resource.end-z->resource.start+1; + CyberMem_phys = board_addr + 0x01400000; + CyberRegs_phys = CyberMem_phys + 0x00c00000; + if (!request_mem_region(CyberRegs_phys, 0x10000, "S3 Trio64")) + continue; + if (!request_mem_region(CyberMem_phys, 0x400000, "RAM")) { + release_mem_region(CyberRegs_phys, 0x10000); + continue; + } + DPRINTK("board_addr=%08lx\n", board_addr); + DPRINTK("board_size=%08lx\n", board_size); + + CyberBase = ioremap(board_addr, board_size); + CyberRegs = CyberBase + 0x02000000; + CyberMem = CyberBase + 0x01400000; + DPRINTK("CyberBase=%08lx CyberRegs=%08lx CyberMem=%08lx\n", + CyberBase, (long unsigned int)CyberRegs, CyberMem); + +#ifdef CYBERFBDEBUG + DPRINTK("Register state just after mapping memory\n"); + cv64_dump(); +#endif + + strcpy(fb_info.modename, cyberfb_name); + fb_info.changevar = NULL; + fb_info.fbops = &cyberfb_ops; + fb_info.screen_base = (unsigned char *)CyberMem; + fb_info.disp = &disp; + fb_info.currcon = -1; + fb_info.switch_con = &Cyberfb_switch; + fb_info.updatevar = &Cyberfb_updatevar; + + Cyber_init(); + /* ++Andre: set cyberfb default mode */ + if (!cyberfb_usermode) { + cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var; + DPRINTK("Use default cyber8 mode\n"); + } + Cyber_decode_var(&cyberfb_default, &par); + Cyber_encode_var(&cyberfb_default, &par); + + do_fb_set_var(&cyberfb_default, 1); + cyberfb_get_var(&fb_display[0].var, -1, &fb_info); + cyberfb_set_disp(-1, &fb_info); + do_install_cmap(0, &fb_info); + + if (register_framebuffer(&fb_info) < 0) { + DPRINTK("EXIT - register_framebuffer failed\n"); + release_mem_region(CyberMem_phys, 0x400000); + release_mem_region(CyberRegs_phys, 0x10000); + return -EINVAL; + } + + printk("fb%d: %s frame buffer device, using %ldK of video memory\n", + fb_info.node, fb_info.modename, CyberSize>>10); + + /* TODO: This driver cannot be unloaded yet */ + DPRINTK("EXIT\n"); + return 0; + } + return -ENXIO; +} + + +static int Cyberfb_switch(int con, struct fb_info *info) +{ + DPRINTK("ENTER\n"); + /* Do we have to save the colormap? */ + if (fb_display[info->currcon].cmap.len) { + fb_get_cmap(&fb_display[info->currcon].cmap, 1, Cyber_getcolreg, + info); + } + + do_fb_set_var(&fb_display[con].var, 1); + info->currcon = con; + /* Install new colormap */ + do_install_cmap(con, info); + DPRINTK("EXIT\n"); + return(0); +} + + +/* + * Update the `var' structure (called by fbcon.c) + * + * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. + * Since it's called by a kernel driver, no range checking is done. + */ + +static int Cyberfb_updatevar(int con, struct fb_info *info) +{ + DPRINTK("Enter - Exit\n"); + return(0); +} + + +/* + * Get a Video Mode + */ + +static int __init get_video_mode(const char *name) +{ + int i; + + DPRINTK("ENTER\n"); + for (i = 0; i < NUM_TOTAL_MODES; i++) { + if (!strcmp(name, cyberfb_predefined[i].name)) { + cyberfb_default = cyberfb_predefined[i].var; + cyberfb_usermode = 1; + DPRINTK("EXIT - Matched predefined mode\n"); + return(i); + } + } + return(0); +} + + +/* + * Text console acceleration + */ + +#ifdef FBCON_HAS_CFB8 +static void fbcon_cyber8_bmove(struct display *p, int sy, int sx, int dy, + int dx, int height, int width) +{ + DPRINTK("ENTER\n"); + sx *= 8; dx *= 8; width *= 8; + Cyber_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx, + (u_short)(dy*fontheight(p)), (u_short)width, + (u_short)(height*fontheight(p)), (u_short)S3_NEW); + DPRINTK("EXIT\n"); +} + +static void fbcon_cyber8_clear(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + unsigned char bg; + + DPRINTK("ENTER\n"); + sx *= 8; width *= 8; + bg = attr_bgcol_ec(p,conp); + Cyber_RectFill((u_short)sx, + (u_short)(sy*fontheight(p)), + (u_short)width, + (u_short)(height*fontheight(p)), + (u_short)S3_NEW, + (u_short)bg); + DPRINTK("EXIT\n"); +} + +static void fbcon_cyber8_putc(struct vc_data *conp, struct display *p, int c, + int yy, int xx) +{ + DPRINTK("ENTER\n"); + Cyber_WaitBlit(); + fbcon_cfb8_putc(conp, p, c, yy, xx); + DPRINTK("EXIT\n"); +} + +static void fbcon_cyber8_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, + int yy, int xx) +{ + DPRINTK("ENTER\n"); + Cyber_WaitBlit(); + fbcon_cfb8_putcs(conp, p, s, count, yy, xx); + DPRINTK("EXIT\n"); +} + +static void fbcon_cyber8_revc(struct display *p, int xx, int yy) +{ + DPRINTK("ENTER\n"); + Cyber_WaitBlit(); + fbcon_cfb8_revc(p, xx, yy); + DPRINTK("EXIT\n"); +} + +static struct display_switch fbcon_cyber8 = { + .setup = fbcon_cfb8_setup, + .bmove = fbcon_cyber8_bmove, + .clear = fbcon_cyber8_clear, + .putc = fbcon_cyber8_putc, + .putcs = fbcon_cyber8_putcs, + .revc = fbcon_cyber8_revc, + .clear_margins =fbcon_cfb8_clear_margins, + .fontwidthmask =FONTWIDTH(8) +}; +#endif + + +#ifdef MODULE +MODULE_LICENSE("GPL"); + +int init_module(void) +{ + return cyberfb_init(); +} +#endif /* MODULE */ + +/* + * + * Low level initialization routines for the CyberVision64 graphics card + * + * Most of the following code is from cvision_core.c + * + */ + +#define MAXPIXELCLOCK 135000000 /* safety */ + +#ifdef CV_AGGRESSIVE_TIMING +long cv64_memclk = 55000000; +#else +long cv64_memclk = 50000000; +#endif + +/*********************/ + +static unsigned char clocks[]={ + 0x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69, + 0x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c, + 0x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a, + 0x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69, + 0x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65, + 0x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63, + 0x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d, + 0x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49, + 0x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42, + 0x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43, + 0x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49, + 0x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a, + 0x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49, + 0x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41, + 0x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43, + 0x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45, + 0x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45, + 0x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45, + 0x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44, + 0x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46, + 0x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f, + 0x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22, + 0x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46, + 0x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b, + 0x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44, + 0x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26, + 0x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b, + 0x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25, + 0x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25, + 0x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21, + 0x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29, + 0x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29, + 0x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29, + 0x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28, + 0x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26, + 0x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21, + 0x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28, + 0x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27, + 0x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22, + 0x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27, + 0x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27, + 0x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21, + 0x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26, + 0x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27, + 0x13, 0x1, 0x13, 0x1, 0x7d, 0x27, 0x4c, 0x9, + 0x37, 0x22, 0x5b, 0xb, 0x71, 0x26, 0x5c, 0xb, + 0x6b, 0xd, 0x47, 0x23, 0x14, 0x1, 0x4f, 0x9, + 0x23, 0x3, 0x75, 0x26, 0x7d, 0xf, 0x1c, 0x2, + 0x51, 0x9, 0x59, 0x24, 0x61, 0xb, 0x69, 0x25, + 0x79, 0x26, 0x34, 0x5, 0x1d, 0x2, 0x6b, 0x25, + 0x54, 0x9, 0x35, 0x5, 0x45, 0x7, 0x6d, 0x25, + 0x7d, 0x26, 0x16, 0x1, 0x7f, 0x26, 0x77, 0xd, + 0x4f, 0x23, 0x78, 0xd, 0x2f, 0x21, 0x27, 0x3, + 0x1f, 0x2, 0x59, 0x9, 0x6a, 0xb, 0x73, 0x25, + 0x6b, 0xb, 0x63, 0x24, 0x5b, 0x9, 0x20, 0x2, + 0x7e, 0xd, 0x4b, 0x7, 0x65, 0x24, 0x43, 0x22, + 0x18, 0x1, 0x6f, 0xb, 0x5e, 0x9, 0x70, 0xb, + 0x2a, 0x3, 0x33, 0x4, 0x45, 0x6, 0x60, 0x9, + 0x7b, 0xc, 0x19, 0x1, 0x19, 0x1, 0x7d, 0xc, + 0x74, 0xb, 0x50, 0x7, 0x75, 0xb, 0x63, 0x9, + 0x51, 0x7, 0x23, 0x2, 0x3f, 0x5, 0x1a, 0x1, + 0x65, 0x9, 0x2d, 0x3, 0x40, 0x5, 0x0, 0x0, +}; + +/* Console colors */ +unsigned char cvconscolors[16][3] = { /* background, foreground, hilite */ + /* R G B */ + {0x30, 0x30, 0x30}, + {0x00, 0x00, 0x00}, + {0x80, 0x00, 0x00}, + {0x00, 0x80, 0x00}, + {0x00, 0x00, 0x80}, + {0x80, 0x80, 0x00}, + {0x00, 0x80, 0x80}, + {0x80, 0x00, 0x80}, + {0xff, 0xff, 0xff}, + {0x40, 0x40, 0x40}, + {0xff, 0x00, 0x00}, + {0x00, 0xff, 0x00}, + {0x00, 0x00, 0xff}, + {0xff, 0xff, 0x00}, + {0x00, 0xff, 0xff}, + {0x00, 0x00, 0xff} +}; + +/* -------------------- Hardware specific routines ------------------------- */ + +/* Read Attribute Controller Register=idx */ +inline unsigned char RAttr (volatile unsigned char *regs, short idx) +{ + wb_64 (regs, ACT_ADDRESS_W, idx); + mb(); + udelay(100); + return (rb_64(regs, ACT_ADDRESS_R)); +} + +/* Read Sequencer Register=idx */ +inline unsigned char RSeq (volatile unsigned char *regs, short idx) +{ + wb_64 (regs, SEQ_ADDRESS, idx); + mb(); + return (rb_64(regs, SEQ_ADDRESS_R)); +} + +/* Read CRT Controller Register=idx */ +inline unsigned char RCrt (volatile unsigned char *regs, short idx) +{ + wb_64 (regs, CRT_ADDRESS, idx); + mb(); + return (rb_64(regs, CRT_ADDRESS_R)); +} + +/* Read Graphics Controller Register=idx */ +inline unsigned char RGfx (volatile unsigned char *regs, short idx) +{ + wb_64 (regs, GCT_ADDRESS, idx); + mb(); + return (rb_64(regs, GCT_ADDRESS_R)); +} + +/* + * Special wakeup/passthrough registers on graphics boards + */ + +inline void cv64_write_port (unsigned short bits, + volatile unsigned char *base) +{ + volatile unsigned char *addr; + static unsigned char cvportbits = 0; /* Mirror port bits here */ + DPRINTK("ENTER\n"); + + addr = base + 0x40001; + if (bits & 0x8000) { + cvportbits |= bits & 0xff; /* Set bits */ + DPRINTK("Set bits: %04x\n", bits); + } else { + bits = bits & 0xff; + bits = (~bits) & 0xff; + cvportbits &= bits; /* Clear bits */ + DPRINTK("Clear bits: %04x\n", bits); + } + + *addr = cvportbits; + DPRINTK("EXIT\n"); +} + +/* + * Monitor switch on CyberVision board + * + * toggle: + * 0 = CyberVision Signal + * 1 = Amiga Signal + * board = board addr + * + */ +inline void cvscreen (int toggle, volatile unsigned char *board) +{ + DPRINTK("ENTER\n"); + if (toggle == 1) { + DPRINTK("Show Amiga video\n"); + cv64_write_port (0x10, board); + } else { + DPRINTK("Show CyberVision video\n"); + cv64_write_port (0x8010, board); + } + DPRINTK("EXIT\n"); +} + +/* Control screen display */ +/* toggle: 0 = on, 1 = off */ +/* board = registerbase */ +inline void gfx_on_off(int toggle, volatile unsigned char *regs) +{ + int r; + DPRINTK("ENTER\n"); + + toggle &= 0x1; + toggle = toggle << 5; + DPRINTK("Turn display %s\n", (toggle ? "off" : "on")); + + r = (int) RSeq(regs, SEQ_ID_CLOCKING_MODE); + r &= 0xdf; /* Set bit 5 to 0 */ + + WSeq (regs, SEQ_ID_CLOCKING_MODE, r | toggle); + DPRINTK("EXIT\n"); +} + +/* + * Computes M, N, and R values from + * given input frequency. It uses a table of + * precomputed values, to keep CPU time low. + * + * The return value consist of: + * lower byte: Bits 4-0: N Divider Value + * Bits 5-6: R Value for e.g. SR10 or SR12 + * higher byte: Bits 0-6: M divider value for e.g. SR11 or SR13 + */ +static unsigned short cv64_compute_clock(unsigned long freq) +{ + static unsigned char *mnr, *save; /* M, N + R vals */ + unsigned long work_freq, r; + unsigned short erg; + long diff, d2; + + DPRINTK("ENTER\n"); + if (freq < 12500000 || freq > MAXPIXELCLOCK) { + printk("CV64 driver: Illegal clock frequency %ld, using 25MHz\n", + freq); + freq = 25000000; + } + DPRINTK("Freq = %ld\n", freq); + mnr = clocks; /* there the vals are stored */ + d2 = 0x7fffffff; + + while (*mnr) { /* mnr vals are 0-terminated */ + work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2); + + r = (mnr[1] >> 5) & 0x03; + if (r != 0) { + work_freq = work_freq >> r; /* r is the freq divider */ + } + + work_freq *= 0x3E8; /* 2nd part of OSC */ + + diff = abs(freq - work_freq); + + if (d2 >= diff) { + d2 = diff; + /* In save are the vals for minimal diff */ + save = mnr; + } + mnr += 2; + } + erg = *((unsigned short *)save); + + DPRINTK("EXIT\n"); + return (erg); +} + +static int cv_has_4mb (volatile unsigned char *fb) +{ + volatile unsigned long *tr, *tw; + DPRINTK("ENTER\n"); + + /* write patterns in memory and test if they can be read */ + tw = (volatile unsigned long *) fb; + tr = (volatile unsigned long *) (fb + 0x02000000); + + *tw = 0x87654321; + + if (*tr != 0x87654321) { + DPRINTK("EXIT - <4MB\n"); + return (0); + } + + /* upper memory region */ + tw = (volatile unsigned long *) (fb + 0x00200000); + tr = (volatile unsigned long *) (fb + 0x02200000); + + *tw = 0x87654321; + + if (*tr != 0x87654321) { + DPRINTK("EXIT - <4MB\n"); + return (0); + } + + *tw = 0xAAAAAAAA; + + if (*tr != 0xAAAAAAAA) { + DPRINTK("EXIT - <4MB\n"); + return (0); + } + + *tw = 0x55555555; + + if (*tr != 0x55555555) { + DPRINTK("EXIT - <4MB\n"); + return (0); + } + + DPRINTK("EXIT\n"); + return (1); +} + +static void cv64_board_init (void) +{ + volatile unsigned char *regs = CyberRegs; + int i; + unsigned int clockpar; + unsigned char test; + + DPRINTK("ENTER\n"); + + /* + * Special CyberVision 64 board operations + */ + /* Reset board */ + for (i = 0; i < 6; i++) { + cv64_write_port (0xff, CyberBase); + } + /* Return to operational mode */ + cv64_write_port (0x8004, CyberBase); + + /* + * Generic (?) S3 chip wakeup + */ + /* Disable I/O & memory decoders, video in setup mode */ + wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x10); + /* Video responds to cmds, addrs & data */ + wb_64 (regs, SREG_OPTION_SELECT, 0x1); + /* Enable I/O & memory decoders, video in operational mode */ + wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x8); + /* VGA color emulation, enable cpu access to display mem */ + wb_64 (regs, GREG_MISC_OUTPUT_W, 0x03); + /* Unlock S3 VGA regs */ + WCrt (regs, CRT_ID_REGISTER_LOCK_1, 0x48); + /* Unlock system control & extension registers */ + WCrt (regs, CRT_ID_REGISTER_LOCK_2, 0xA5); +/* GRF - Enable interrupts */ + /* Enable enhanced regs access, Ready cntl 0 wait states */ + test = RCrt (regs, CRT_ID_SYSTEM_CONFIG); + test = test | 0x01; /* enable enhanced register access */ + test = test & 0xEF; /* clear bit 4, 0 wait state */ + WCrt (regs, CRT_ID_SYSTEM_CONFIG, test); + /* + * bit 0=1: Enable enhaced mode functions + * bit 2=0: Enhanced mode 8+ bits/pixel + * bit 4=1: Enable linear addressing + * bit 5=1: Enable MMIO + */ + wb_64 (regs, ECR_ADV_FUNC_CNTL, 0x31); + /* + * bit 0=1: Color emulation + * bit 1=1: Enable CPU access to display memory + * bit 5=1: Select high 64K memory page + */ +/* GRF - 0xE3 */ + wb_64 (regs, GREG_MISC_OUTPUT_W, 0x23); + + /* Cpu base addr */ + WCrt (regs, CRT_ID_EXT_SYS_CNTL_4, 0x0); + + /* Reset. This does nothing on Trio, but standard VGA practice */ + /* WSeq (CyberRegs, SEQ_ID_RESET, 0x03); */ + /* Character clocks 8 dots wide */ + WSeq (regs, SEQ_ID_CLOCKING_MODE, 0x01); + /* Enable cpu write to all color planes */ + WSeq (regs, SEQ_ID_MAP_MASK, 0x0F); + /* Font table in 1st 8k of plane 2, font A=B disables swtich */ + WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x0); + /* Allow mem access to 256kb */ + WSeq (regs, SEQ_ID_MEMORY_MODE, 0x2); + /* Unlock S3 extensions to VGA Sequencer regs */ + WSeq (regs, SEQ_ID_UNLOCK_EXT, 0x6); + + /* Enable 4MB fast page mode */ + test = RSeq (regs, SEQ_ID_BUS_REQ_CNTL); + test = test | 1 << 6; + WSeq (regs, SEQ_ID_BUS_REQ_CNTL, test); + + /* Faster LUT write: 1 DCLK LUT write cycle, RAMDAC clk doubled */ + WSeq (regs, SEQ_ID_RAMDAC_CNTL, 0xC0); + + /* Clear immediate clock load bit */ + test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2); + test = test & 0xDF; + /* If > 55MHz, enable 2 cycle memory write */ + if (cv64_memclk >= 55000000) { + test |= 0x80; + } + WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test); + + /* Set MCLK value */ + clockpar = cv64_compute_clock (cv64_memclk); + test = (clockpar & 0xFF00) >> 8; + WSeq (regs, SEQ_ID_MCLK_HI, test); + test = clockpar & 0xFF; + WSeq (regs, SEQ_ID_MCLK_LO, test); + + /* Chip rev specific: Not in my Trio manual!!! */ + if (RCrt (regs, CRT_ID_REVISION) == 0x10) + WSeq (regs, SEQ_ID_MORE_MAGIC, test); + + /* We now load an 25 MHz, 31kHz, 640x480 standard VGA Mode. */ + + /* Set DCLK value */ + WSeq (regs, SEQ_ID_DCLK_HI, 0x13); + WSeq (regs, SEQ_ID_DCLK_LO, 0x41); + + /* Load DCLK (and MCLK?) immediately */ + test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2); + test = test | 0x22; + WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test); + + /* Enable loading of DCLK */ + test = rb_64(regs, GREG_MISC_OUTPUT_R); + test = test | 0x0C; + wb_64 (regs, GREG_MISC_OUTPUT_W, test); + + /* Turn off immediate xCLK load */ + WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, 0x2); + + /* Horizontal character clock counts */ + /* 8 LSB of 9 bits = total line - 5 */ + WCrt (regs, CRT_ID_HOR_TOTAL, 0x5F); + /* Active display line */ + WCrt (regs, CRT_ID_HOR_DISP_ENA_END, 0x4F); + /* Blank assertion start */ + WCrt (regs, CRT_ID_START_HOR_BLANK, 0x50); + /* Blank assertion end */ + WCrt (regs, CRT_ID_END_HOR_BLANK, 0x82); + /* HSYNC assertion start */ + WCrt (regs, CRT_ID_START_HOR_RETR, 0x54); + /* HSYNC assertion end */ + WCrt (regs, CRT_ID_END_HOR_RETR, 0x80); + WCrt (regs, CRT_ID_VER_TOTAL, 0xBF); + WCrt (regs, CRT_ID_OVERFLOW, 0x1F); + WCrt (regs, CRT_ID_PRESET_ROW_SCAN, 0x0); + WCrt (regs, CRT_ID_MAX_SCAN_LINE, 0x40); + WCrt (regs, CRT_ID_CURSOR_START, 0x00); + WCrt (regs, CRT_ID_CURSOR_END, 0x00); + WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00); + WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00); + WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00); + WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00); + WCrt (regs, CRT_ID_START_VER_RETR, 0x9C); + WCrt (regs, CRT_ID_END_VER_RETR, 0x0E); + WCrt (regs, CRT_ID_VER_DISP_ENA_END, 0x8F); + WCrt (regs, CRT_ID_SCREEN_OFFSET, 0x50); + WCrt (regs, CRT_ID_UNDERLINE_LOC, 0x00); + WCrt (regs, CRT_ID_START_VER_BLANK, 0x96); + WCrt (regs, CRT_ID_END_VER_BLANK, 0xB9); + WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3); + WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF); + WCrt (regs, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */ + WCrt (regs, CRT_ID_MISC_1, 0x35); + WCrt (regs, CRT_ID_DISPLAY_FIFO, 0x5A); + WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, 0x70); + WCrt (regs, CRT_ID_LAW_POS_LO, 0x40); + WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, 0xFF); + + WGfx (regs, GCT_ID_SET_RESET, 0x0); + WGfx (regs, GCT_ID_ENABLE_SET_RESET, 0x0); + WGfx (regs, GCT_ID_COLOR_COMPARE, 0x0); + WGfx (regs, GCT_ID_DATA_ROTATE, 0x0); + WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x0); + WGfx (regs, GCT_ID_GRAPHICS_MODE, 0x40); + WGfx (regs, GCT_ID_MISC, 0x01); + WGfx (regs, GCT_ID_COLOR_XCARE, 0x0F); + WGfx (regs, GCT_ID_BITMASK, 0xFF); + + /* Colors for text mode */ + for (i = 0; i < 0xf; i++) + WAttr (regs, i, i); + + WAttr (regs, ACT_ID_ATTR_MODE_CNTL, 0x41); + WAttr (regs, ACT_ID_OVERSCAN_COLOR, 0x01); + WAttr (regs, ACT_ID_COLOR_PLANE_ENA, 0x0F); + WAttr (regs, ACT_ID_HOR_PEL_PANNING, 0x0); + WAttr (regs, ACT_ID_COLOR_SELECT, 0x0); + + wb_64 (regs, VDAC_MASK, 0xFF); + + *((unsigned long *) (regs + ECR_FRGD_COLOR)) = 0xFF; + *((unsigned long *) (regs + ECR_BKGD_COLOR)) = 0; + + /* Colors initially set to grayscale */ + + wb_64 (regs, VDAC_ADDRESS_W, 0); + for (i = 255; i >= 0; i--) { + wb_64(regs, VDAC_DATA, i); + wb_64(regs, VDAC_DATA, i); + wb_64(regs, VDAC_DATA, i); + } + + /* GFx hardware cursor off */ + WCrt (regs, CRT_ID_HWGC_MODE, 0x00); + + /* Set first to 4MB, so test will work */ + WCrt (regs, CRT_ID_LAW_CNTL, 0x13); + /* Find "correct" size of fbmem of Z3 board */ + if (cv_has_4mb (CyberMem)) { + CyberSize = 1024 * 1024 * 4; + WCrt (regs, CRT_ID_LAW_CNTL, 0x13); + DPRINTK("4MB board\n"); + } else { + CyberSize = 1024 * 1024 * 2; + WCrt (regs, CRT_ID_LAW_CNTL, 0x12); + DPRINTK("2MB board\n"); + } + + /* Initialize graphics engine */ + Cyber_WaitBlit(); + vgaw16 (regs, ECR_FRGD_MIX, 0x27); + vgaw16 (regs, ECR_BKGD_MIX, 0x07); + vgaw16 (regs, ECR_READ_REG_DATA, 0x1000); + udelay(200); + vgaw16 (regs, ECR_READ_REG_DATA, 0x2000); + Cyber_WaitBlit(); + vgaw16 (regs, ECR_READ_REG_DATA, 0x3FFF); + Cyber_WaitBlit(); + udelay(200); + vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF); + Cyber_WaitBlit(); + vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, ~0); + Cyber_WaitBlit(); + vgaw16 (regs, ECR_READ_REG_DATA, 0xE000); + vgaw16 (regs, ECR_CURRENT_Y_POS2, 0x00); + vgaw16 (regs, ECR_CURRENT_X_POS2, 0x00); + vgaw16 (regs, ECR_READ_REG_DATA, 0xA000); + vgaw16 (regs, ECR_DEST_Y__AX_STEP, 0x00); + vgaw16 (regs, ECR_DEST_Y2__AX_STEP2, 0x00); + vgaw16 (regs, ECR_DEST_X__DIA_STEP, 0x00); + vgaw16 (regs, ECR_DEST_X2__DIA_STEP2, 0x00); + vgaw16 (regs, ECR_SHORT_STROKE, 0x00); + vgaw16 (regs, ECR_DRAW_CMD, 0x01); + + Cyber_WaitBlit(); + + vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF); + vgaw16 (regs, ECR_BKGD_COLOR, 0x01); + vgaw16 (regs, ECR_FRGD_COLOR, 0x00); + + + /* Enable video display (set bit 5) */ +/* ARB - Would also seem to write to AR13. + * May want to use parts of WAttr to set JUST bit 5 + */ + WAttr (regs, 0x33, 0); + +/* GRF - function code ended here */ + + /* Turn gfx on again */ + gfx_on_off (0, regs); + + /* Pass-through */ + cvscreen (0, CyberBase); + + DPRINTK("EXIT\n"); +} + +static void cv64_load_video_mode (struct fb_var_screeninfo *video_mode) +{ + volatile unsigned char *regs = CyberRegs; + int fx, fy; + unsigned short mnr; + unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS, VSE, VT; + char LACE, DBLSCAN, TEXT, CONSOLE; + int cr50, sr15, sr18, clock_mode, test; + int m, n; + int tfillm, temptym; + int hmul; + + /* ---------------- */ + int xres, hfront, hsync, hback; + int yres, vfront, vsync, vback; + int bpp; +#if 0 + float freq_f; +#endif + long freq; + /* ---------------- */ + + DPRINTK("ENTER\n"); + TEXT = 0; /* if depth == 4 */ + CONSOLE = 0; /* mode num == 255 (console) */ + fx = fy = 8; /* force 8x8 font */ + +/* GRF - Disable interrupts */ + + gfx_on_off (1, regs); + + switch (video_mode->bits_per_pixel) { + case 15: + case 16: + hmul = 2; + break; + + default: + hmul = 1; + break; + } + + bpp = video_mode->bits_per_pixel; + xres = video_mode->xres; + hfront = video_mode->right_margin; + hsync = video_mode->hsync_len; + hback = video_mode->left_margin; + + LACE = 0; + DBLSCAN = 0; + + if (video_mode->vmode & FB_VMODE_DOUBLE) { + yres = video_mode->yres * 2; + vfront = video_mode->lower_margin * 2; + vsync = video_mode->vsync_len * 2; + vback = video_mode->upper_margin * 2; + DBLSCAN = 1; + } else if (video_mode->vmode & FB_VMODE_INTERLACED) { + yres = (video_mode->yres + 1) / 2; + vfront = (video_mode->lower_margin + 1) / 2; + vsync = (video_mode->vsync_len + 1) / 2; + vback = (video_mode->upper_margin + 1) / 2; + LACE = 1; + } else { + yres = video_mode->yres; + vfront = video_mode->lower_margin; + vsync = video_mode->vsync_len; + vback = video_mode->upper_margin; + } + + /* ARB Dropping custom setup method from cvision.c */ +#if 0 + if (cvision_custom_mode) { + HBS = hbs / 8 * hmul; + HBE = hbe / 8 * hmul; + HSS = hss / 8 * hmul; + HSE = hse / 8 * hmul; + HT = ht / 8 * hmul - 5; + + VBS = vbs - 1; + VSS = vss; + VSE = vse; + VBE = vbe; + VT = vt - 2; + } else { +#else + { +#endif + HBS = hmul * (xres / 8); + HBE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8) - 2); + HSS = hmul * ((xres/8) + (hfront/8) + 2); + HSE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + 1); + HT = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8)); + + VBS = yres; + VBE = yres + vfront + vsync + vback - 2; + VSS = yres + vfront - 1; + VSE = yres + vfront + vsync - 1; + VT = yres + vfront + vsync + vback - 2; + } + + wb_64 (regs, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31)); + + if (TEXT) + HDE = ((video_mode->xres + fx - 1) / fx) - 1; + else + HDE = (video_mode->xres + 3) * hmul / 8 - 1; + + VDE = video_mode->yres - 1; + + WCrt (regs, CRT_ID_HWGC_MODE, 0x00); + WCrt (regs, CRT_ID_EXT_DAC_CNTL, 0x00); + + WSeq (regs, SEQ_ID_MEMORY_MODE, + (TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x0e); + WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x00); + WSeq (regs, SEQ_ID_MAP_MASK, + (video_mode->bits_per_pixel == 1) ? 0x01 : 0xFF); + WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x00); + + /* cv64_compute_clock accepts arguments in Hz */ + /* pixclock is in ps ... convert to Hz */ + +#if 0 + freq_f = (1.0 / (float) video_mode->pixclock) * 1000000000; + freq = ((long) freq_f) * 1000; +#else +/* freq = (long) ((long long)1000000000000 / (long long) video_mode->pixclock); + */ + freq = (1000000000 / video_mode->pixclock) * 1000; +#endif + + mnr = cv64_compute_clock (freq); + WSeq (regs, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8)); + WSeq (regs, SEQ_ID_DCLK_LO, (mnr & 0xFF)); + + /* Load display parameters into board */ + WCrt (regs, CRT_ID_EXT_HOR_OVF, + ((HT & 0x100) ? 0x01 : 0x00) | + ((HDE & 0x100) ? 0x02 : 0x00) | + ((HBS & 0x100) ? 0x04 : 0x00) | + /* ((HBE & 0x40) ? 0x08 : 0x00) | */ + ((HSS & 0x100) ? 0x10 : 0x00) | + /* ((HSE & 0x20) ? 0x20 : 0x00) | */ + (((HT-5) & 0x100) ? 0x40 : 0x00) + ); + + WCrt (regs, CRT_ID_EXT_VER_OVF, + 0x40 | + ((VT & 0x400) ? 0x01 : 0x00) | + ((VDE & 0x400) ? 0x02 : 0x00) | + ((VBS & 0x400) ? 0x04 : 0x00) | + ((VSS & 0x400) ? 0x10 : 0x00) + ); + + WCrt (regs, CRT_ID_HOR_TOTAL, HT); + WCrt (regs, CRT_ID_DISPLAY_FIFO, HT - 5); + WCrt (regs, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE)); + WCrt (regs, CRT_ID_START_HOR_BLANK, HBS); + WCrt (regs, CRT_ID_END_HOR_BLANK, ((HBE & 0x1F) | 0x80)); + WCrt (regs, CRT_ID_START_HOR_RETR, HSS); + WCrt (regs, CRT_ID_END_HOR_RETR, + (HSE & 0x1F) | + ((HBE & 0x20) ? 0x80 : 0x00) + ); + WCrt (regs, CRT_ID_VER_TOTAL, VT); + WCrt (regs, CRT_ID_OVERFLOW, + 0x10 | + ((VT & 0x100) ? 0x01 : 0x00) | + ((VDE & 0x100) ? 0x02 : 0x00) | + ((VSS & 0x100) ? 0x04 : 0x00) | + ((VBS & 0x100) ? 0x08 : 0x00) | + ((VT & 0x200) ? 0x20 : 0x00) | + ((VDE & 0x200) ? 0x40 : 0x00) | + ((VSS & 0x200) ? 0x80 : 0x00) + ); + WCrt (regs, CRT_ID_MAX_SCAN_LINE, + 0x40 | + (DBLSCAN ? 0x80 : 0x00) | + ((VBS & 0x200) ? 0x20 : 0x00) | + (TEXT ? ((fy - 1) & 0x1F) : 0x00) + ); + + WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3); + + /* Text cursor */ + + if (TEXT) { +#if 1 + WCrt (regs, CRT_ID_CURSOR_START, (fy & 0x1f) - 2); + WCrt (regs, CRT_ID_CURSOR_END, (fy & 0x1F) - 1); +#else + WCrt (regs, CRT_ID_CURSOR_START, 0x00); + WCrt (regs, CRT_ID_CURSOR_END, fy & 0x1F); +#endif + WCrt (regs, CRT_ID_UNDERLINE_LOC, (fy - 1) & 0x1F); + WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00); + WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00); + } + + WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00); + WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00); + WCrt (regs, CRT_ID_START_VER_RETR, VSS); + WCrt (regs, CRT_ID_END_VER_RETR, (VSE & 0x0F)); + WCrt (regs, CRT_ID_VER_DISP_ENA_END, VDE); + WCrt (regs, CRT_ID_START_VER_BLANK, VBS); + WCrt (regs, CRT_ID_END_VER_BLANK, VBE); + WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF); + WCrt (regs, CRT_ID_LACE_RETR_START, HT / 2); + WCrt (regs, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00)); + WGfx (regs, GCT_ID_GRAPHICS_MODE, + ((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x00 : 0x40)); + WGfx (regs, GCT_ID_MISC, (TEXT ? 0x04 : 0x01)); + WSeq (regs, SEQ_ID_MEMORY_MODE, + ((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x02)); + + wb_64 (regs, VDAC_MASK, 0xFF); + + /* Blank border */ + test = RCrt (regs, CRT_ID_BACKWAD_COMP_2); + WCrt (regs, CRT_ID_BACKWAD_COMP_2, (test | 0x20)); + + sr15 = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2); + sr15 &= 0xEF; + sr18 = RSeq (regs, SEQ_ID_RAMDAC_CNTL); + sr18 &= 0x7F; + clock_mode = 0x00; + cr50 = 0x00; + + test = RCrt (regs, CRT_ID_EXT_MISC_CNTL_2); + test &= 0xD; + + /* Clear roxxler byte-swapping... */ + cv64_write_port (0x0040, CyberBase); + cv64_write_port (0x0020, CyberBase); + + switch (video_mode->bits_per_pixel) { + case 1: + case 4: /* text */ + HDE = video_mode->xres / 16; + break; + + case 8: + if (freq > 80000000) { + clock_mode = 0x10 | 0x02; + sr15 |= 0x10; + sr18 |= 0x80; + } + HDE = video_mode->xres / 8; + cr50 |= 0x00; + break; + + case 15: + cv64_write_port (0x8020, CyberBase); + clock_mode = 0x30; + HDE = video_mode->xres / 4; + cr50 |= 0x10; + break; + + case 16: + cv64_write_port (0x8020, CyberBase); + clock_mode = 0x50; + HDE = video_mode->xres / 4; + cr50 |= 0x10; + break; + + case 24: + case 32: + cv64_write_port (0x8040, CyberBase); + clock_mode = 0xD0; + HDE = video_mode->xres / 2; + cr50 |= 0x30; + break; + } + + WCrt (regs, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test); + WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, sr15); + WSeq (regs, SEQ_ID_RAMDAC_CNTL, sr18); + WCrt (regs, CRT_ID_SCREEN_OFFSET, HDE); + + WCrt (regs, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35)); + + test = RCrt (regs, CRT_ID_EXT_SYS_CNTL_2); + test &= ~0x30; + test |= (HDE >> 4) & 0x30; + WCrt (regs, CRT_ID_EXT_SYS_CNTL_2, test); + + /* Set up graphics engine */ + switch (video_mode->xres) { + case 1024: + cr50 |= 0x00; + break; + + case 640: + cr50 |= 0x40; + break; + + case 800: + cr50 |= 0x80; + break; + + case 1280: + cr50 |= 0xC0; + break; + + case 1152: + cr50 |= 0x01; + break; + + case 1600: + cr50 |= 0x81; + break; + + default: /* XXX */ + break; + } + + WCrt (regs, CRT_ID_EXT_SYS_CNTL_1, cr50); + + udelay(100); + WAttr (regs, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41)); + udelay(100); + WAttr (regs, ACT_ID_COLOR_PLANE_ENA, + (video_mode->bits_per_pixel == 1) ? 0x01 : 0x0F); + udelay(100); + + tfillm = (96 * (cv64_memclk / 1000)) / 240000; + + switch (video_mode->bits_per_pixel) { + case 32: + case 24: + temptym = (24 * (cv64_memclk / 1000)) / (freq / 1000); + break; + case 15: + case 16: + temptym = (48 * (cv64_memclk / 1000)) / (freq / 1000); + break; + case 4: + temptym = (192 * (cv64_memclk / 1000)) / (freq / 1000); + break; + default: + temptym = (96 * (cv64_memclk / 1000)) / (freq / 1000); + break; + } + + m = (temptym - tfillm - 9) / 2; + if (m < 0) + m = 0; + m = (m & 0x1F) << 3; + if (m < 0x18) + m = 0x18; + n = 0xFF; + + WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, m); + WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, n); + udelay(10); + + /* Text initialization */ + + if (TEXT) { + /* Do text initialization here ! */ + } + + if (CONSOLE) { + int i; + wb_64 (regs, VDAC_ADDRESS_W, 0); + for (i = 0; i < 4; i++) { + wb_64 (regs, VDAC_DATA, cvconscolors [i][0]); + wb_64 (regs, VDAC_DATA, cvconscolors [i][1]); + wb_64 (regs, VDAC_DATA, cvconscolors [i][2]); + } + } + + WAttr (regs, 0x33, 0); + + /* Turn gfx on again */ + gfx_on_off (0, (volatile unsigned char *) regs); + + /* Pass-through */ + cvscreen (0, CyberBase); + +DPRINTK("EXIT\n"); +} + +void cvision_bitblt (u_short sx, u_short sy, u_short dx, u_short dy, + u_short w, u_short h) +{ + volatile unsigned char *regs = CyberRegs; + unsigned short drawdir = 0; + + DPRINTK("ENTER\n"); + if (sx > dx) { + drawdir |= 1 << 5; + } else { + sx += w - 1; + dx += w - 1; + } + + if (sy > dy) { + drawdir |= 1 << 7; + } else { + sy += h - 1; + dy += h - 1; + } + + Cyber_WaitBlit(); + vgaw16 (regs, ECR_READ_REG_DATA, 0xA000); + vgaw16 (regs, ECR_BKGD_MIX, 0x7); + vgaw16 (regs, ECR_FRGD_MIX, 0x67); + vgaw16 (regs, ECR_BKGD_COLOR, 0x0); + vgaw16 (regs, ECR_FRGD_COLOR, 0x1); + vgaw16 (regs, ECR_BITPLANE_READ_MASK, 0x1); + vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, 0xFFF); + vgaw16 (regs, ECR_CURRENT_Y_POS, sy); + vgaw16 (regs, ECR_CURRENT_X_POS, sx); + vgaw16 (regs, ECR_DEST_Y__AX_STEP, dy); + vgaw16 (regs, ECR_DEST_X__DIA_STEP, dx); + vgaw16 (regs, ECR_READ_REG_DATA, h - 1); + vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1); + vgaw16 (regs, ECR_DRAW_CMD, 0xC051 | drawdir); + DPRINTK("EXIT\n"); +} + +void cvision_clear (u_short dx, u_short dy, u_short w, u_short h, u_short bg) +{ + volatile unsigned char *regs = CyberRegs; + DPRINTK("ENTER\n"); + Cyber_WaitBlit(); + vgaw16 (regs, ECR_FRGD_MIX, 0x0027); + vgaw16 (regs, ECR_FRGD_COLOR, bg); + vgaw16 (regs, ECR_READ_REG_DATA, 0xA000); + vgaw16 (regs, ECR_CURRENT_Y_POS, dy); + vgaw16 (regs, ECR_CURRENT_X_POS, dx); + vgaw16 (regs, ECR_READ_REG_DATA, h - 1); + vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1); + vgaw16 (regs, ECR_DRAW_CMD, 0x40B1); + DPRINTK("EXIT\n"); +} + +#ifdef CYBERFBDEBUG +/* + * Dump internal settings of CyberVision board + */ +static void cv64_dump (void) +{ + volatile unsigned char *regs = CyberRegs; + DPRINTK("ENTER\n"); + /* Dump the VGA setup values */ + *(regs + S3_CRTC_ADR) = 0x00; + DPRINTK("CR00 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x01; + DPRINTK("CR01 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x02; + DPRINTK("CR02 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x03; + DPRINTK("CR03 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x04; + DPRINTK("CR04 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x05; + DPRINTK("CR05 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x06; + DPRINTK("CR06 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x07; + DPRINTK("CR07 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x08; + DPRINTK("CR08 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x09; + DPRINTK("CR09 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x10; + DPRINTK("CR10 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x11; + DPRINTK("CR11 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x12; + DPRINTK("CR12 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x13; + DPRINTK("CR13 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x15; + DPRINTK("CR15 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x16; + DPRINTK("CR16 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x36; + DPRINTK("CR36 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x37; + DPRINTK("CR37 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x42; + DPRINTK("CR42 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x43; + DPRINTK("CR43 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x50; + DPRINTK("CR50 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x51; + DPRINTK("CR51 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x53; + DPRINTK("CR53 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x58; + DPRINTK("CR58 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x59; + DPRINTK("CR59 = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x5A; + DPRINTK("CR5A = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x5D; + DPRINTK("CR5D = %x\n", *(regs + S3_CRTC_DATA)); + *(regs + S3_CRTC_ADR) = 0x5E; + DPRINTK("CR5E = %x\n", *(regs + S3_CRTC_DATA)); + DPRINTK("MISC = %x\n", *(regs + GREG_MISC_OUTPUT_R)); + *(regs + SEQ_ADDRESS) = 0x01; + DPRINTK("SR01 = %x\n", *(regs + SEQ_ADDRESS_R)); + *(regs + SEQ_ADDRESS) = 0x02; + DPRINTK("SR02 = %x\n", *(regs + SEQ_ADDRESS_R)); + *(regs + SEQ_ADDRESS) = 0x03; + DPRINTK("SR03 = %x\n", *(regs + SEQ_ADDRESS_R)); + *(regs + SEQ_ADDRESS) = 0x09; + DPRINTK("SR09 = %x\n", *(regs + SEQ_ADDRESS_R)); + *(regs + SEQ_ADDRESS) = 0x10; + DPRINTK("SR10 = %x\n", *(regs + SEQ_ADDRESS_R)); + *(regs + SEQ_ADDRESS) = 0x11; + DPRINTK("SR11 = %x\n", *(regs + SEQ_ADDRESS_R)); + *(regs + SEQ_ADDRESS) = 0x12; + DPRINTK("SR12 = %x\n", *(regs + SEQ_ADDRESS_R)); + *(regs + SEQ_ADDRESS) = 0x13; + DPRINTK("SR13 = %x\n", *(regs + SEQ_ADDRESS_R)); + *(regs + SEQ_ADDRESS) = 0x15; + DPRINTK("SR15 = %x\n", *(regs + SEQ_ADDRESS_R)); + + return; +} +#endif diff --git a/drivers/video/cyberfb.h b/drivers/video/cyberfb.h new file mode 100644 index 000000000000..8435c430ad27 --- /dev/null +++ b/drivers/video/cyberfb.h @@ -0,0 +1,415 @@ +/* + * linux/arch/m68k/console/cvision.h -- CyberVision64 definitions for the + * text console driver. + * + * Copyright (c) 1998 Alan Bair + * + * This file is based on the initial port to Linux of grf_cvreg.h: + * + * Copyright (c) 1997 Antonio Santos + * + * The original work is from the NetBSD CyberVision 64 framebuffer driver + * and support files (grf_cv.c, grf_cvreg.h, ite_cv.c): + * Permission to use the source of this driver was obtained from the + * author Michael Teske by Alan Bair. + * + * Copyright (c) 1995 Michael Teske + * + * History: + * + * + * + * 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. + */ + +/* s3 commands */ +#define S3_BITBLT 0xc011 +#define S3_TWOPOINTLINE 0x2811 +#define S3_FILLEDRECT 0x40b1 + +#define S3_FIFO_EMPTY 0x0400 +#define S3_HDW_BUSY 0x0200 + +/* Enhanced register mapping (MMIO mode) */ + +#define S3_READ_SEL 0xbee8 /* offset f */ +#define S3_MULT_MISC 0xbee8 /* offset e */ +#define S3_ERR_TERM 0x92e8 +#define S3_FRGD_COLOR 0xa6e8 +#define S3_BKGD_COLOR 0xa2e8 +#define S3_PIXEL_CNTL 0xbee8 /* offset a */ +#define S3_FRGD_MIX 0xbae8 +#define S3_BKGD_MIX 0xb6e8 +#define S3_CUR_Y 0x82e8 +#define S3_CUR_X 0x86e8 +#define S3_DESTY_AXSTP 0x8ae8 +#define S3_DESTX_DIASTP 0x8ee8 +#define S3_MIN_AXIS_PCNT 0xbee8 /* offset 0 */ +#define S3_MAJ_AXIS_PCNT 0x96e8 +#define S3_CMD 0x9ae8 +#define S3_GP_STAT 0x9ae8 +#define S3_ADVFUNC_CNTL 0x4ae8 +#define S3_WRT_MASK 0xaae8 +#define S3_RD_MASK 0xaee8 + +/* Enhanced register mapping (Packed MMIO mode, write only) */ +#define S3_ALT_CURXY 0x8100 +#define S3_ALT_CURXY2 0x8104 +#define S3_ALT_STEP 0x8108 +#define S3_ALT_STEP2 0x810c +#define S3_ALT_ERR 0x8110 +#define S3_ALT_CMD 0x8118 +#define S3_ALT_MIX 0x8134 +#define S3_ALT_PCNT 0x8148 +#define S3_ALT_PAT 0x8168 + +/* Drawing modes */ +#define S3_NOTCUR 0x0000 +#define S3_LOGICALZERO 0x0001 +#define S3_LOGICALONE 0x0002 +#define S3_LEAVEASIS 0x0003 +#define S3_NOTNEW 0x0004 +#define S3_CURXORNEW 0x0005 +#define S3_NOT_CURXORNEW 0x0006 +#define S3_NEW 0x0007 +#define S3_NOTCURORNOTNEW 0x0008 +#define S3_CURORNOTNEW 0x0009 +#define S3_NOTCURORNEW 0x000a +#define S3_CURORNEW 0x000b +#define S3_CURANDNEW 0x000c +#define S3_NOTCURANDNEW 0x000d +#define S3_CURANDNOTNEW 0x000e +#define S3_NOTCURANDNOTNEW 0x000f + +#define S3_CRTC_ADR 0x03d4 +#define S3_CRTC_DATA 0x03d5 + +#define S3_REG_LOCK2 0x39 +#define S3_HGC_MODE 0x45 + +#define S3_HWGC_ORGX_H 0x46 +#define S3_HWGC_ORGX_L 0x47 +#define S3_HWGC_ORGY_H 0x48 +#define S3_HWGC_ORGY_L 0x49 +#define S3_HWGC_DX 0x4e +#define S3_HWGC_DY 0x4f + +#define S3_LAW_CTL 0x58 + +/**************************************************/ + +/* support for a BitBlt operation. The op-codes are identical + to X11 GCs */ +#define GRFBBOPclear 0x0 /* 0 */ +#define GRFBBOPand 0x1 /* src AND dst */ +#define GRFBBOPandReverse 0x2 /* src AND NOT dst */ +#define GRFBBOPcopy 0x3 /* src */ +#define GRFBBOPandInverted 0x4 /* NOT src AND dst */ +#define GRFBBOPnoop 0x5 /* dst */ +#define GRFBBOPxor 0x6 /* src XOR dst */ +#define GRFBBOPor 0x7 /* src OR dst */ +#define GRFBBOPnor 0x8 /* NOT src AND NOT dst */ +#define GRFBBOPequiv 0x9 /* NOT src XOR dst */ +#define GRFBBOPinvert 0xa /* NOT dst */ +#define GRFBBOPorReverse 0xb /* src OR NOT dst */ +#define GRFBBOPcopyInverted 0xc /* NOT src */ +#define GRFBBOPorInverted 0xd /* NOT src OR dst */ +#define GRFBBOPnand 0xe /* NOT src OR NOT dst */ +#define GRFBBOPset 0xf /* 1 */ + + +/* Write 16 Bit VGA register */ +#define vgaw16(ba, reg, val) \ +*((unsigned short *) (((volatile unsigned char *)ba)+reg)) = val + +/* + * Defines for the used register addresses (mw) + * + * NOTE: There are some registers that have different addresses when + * in mono or color mode. We only support color mode, and thus + * some addresses won't work in mono-mode! + * + * General and VGA-registers taken from retina driver. Fixed a few + * bugs in it. (SR and GR read address is Port + 1, NOT Port) + * + */ + +/* General Registers: */ +#define GREG_MISC_OUTPUT_R 0x03CC +#define GREG_MISC_OUTPUT_W 0x03C2 +#define GREG_FEATURE_CONTROL_R 0x03CA +#define GREG_FEATURE_CONTROL_W 0x03DA +#define GREG_INPUT_STATUS0_R 0x03C2 +#define GREG_INPUT_STATUS1_R 0x03DA + +/* Setup Registers: */ +#define SREG_OPTION_SELECT 0x0102 +#define SREG_VIDEO_SUBS_ENABLE 0x46E8 + +/* Attribute Controller: */ +#define ACT_ADDRESS 0x03C0 +#define ACT_ADDRESS_R 0x03C1 +#define ACT_ADDRESS_W 0x03C0 +#define ACT_ADDRESS_RESET 0x03DA +#define ACT_ID_PALETTE0 0x00 +#define ACT_ID_PALETTE1 0x01 +#define ACT_ID_PALETTE2 0x02 +#define ACT_ID_PALETTE3 0x03 +#define ACT_ID_PALETTE4 0x04 +#define ACT_ID_PALETTE5 0x05 +#define ACT_ID_PALETTE6 0x06 +#define ACT_ID_PALETTE7 0x07 +#define ACT_ID_PALETTE8 0x08 +#define ACT_ID_PALETTE9 0x09 +#define ACT_ID_PALETTE10 0x0A +#define ACT_ID_PALETTE11 0x0B +#define ACT_ID_PALETTE12 0x0C +#define ACT_ID_PALETTE13 0x0D +#define ACT_ID_PALETTE14 0x0E +#define ACT_ID_PALETTE15 0x0F +#define ACT_ID_ATTR_MODE_CNTL 0x10 +#define ACT_ID_OVERSCAN_COLOR 0x11 +#define ACT_ID_COLOR_PLANE_ENA 0x12 +#define ACT_ID_HOR_PEL_PANNING 0x13 +#define ACT_ID_COLOR_SELECT 0x14 + +/* Graphics Controller: */ +#define GCT_ADDRESS 0x03CE +#define GCT_ADDRESS_R 0x03CF +#define GCT_ADDRESS_W 0x03CF +#define GCT_ID_SET_RESET 0x00 +#define GCT_ID_ENABLE_SET_RESET 0x01 +#define GCT_ID_COLOR_COMPARE 0x02 +#define GCT_ID_DATA_ROTATE 0x03 +#define GCT_ID_READ_MAP_SELECT 0x04 +#define GCT_ID_GRAPHICS_MODE 0x05 +#define GCT_ID_MISC 0x06 +#define GCT_ID_COLOR_XCARE 0x07 +#define GCT_ID_BITMASK 0x08 + +/* Sequencer: */ +#define SEQ_ADDRESS 0x03C4 +#define SEQ_ADDRESS_R 0x03C5 +#define SEQ_ADDRESS_W 0x03C5 +#define SEQ_ID_RESET 0x00 +#define SEQ_ID_CLOCKING_MODE 0x01 +#define SEQ_ID_MAP_MASK 0x02 +#define SEQ_ID_CHAR_MAP_SELECT 0x03 +#define SEQ_ID_MEMORY_MODE 0x04 +#define SEQ_ID_UNKNOWN1 0x05 +#define SEQ_ID_UNKNOWN2 0x06 +#define SEQ_ID_UNKNOWN3 0x07 +/* S3 extensions */ +#define SEQ_ID_UNLOCK_EXT 0x08 +#define SEQ_ID_EXT_SEQ_REG9 0x09 +#define SEQ_ID_BUS_REQ_CNTL 0x0A +#define SEQ_ID_EXT_MISC_SEQ 0x0B +#define SEQ_ID_UNKNOWN4 0x0C +#define SEQ_ID_EXT_SEQ 0x0D +#define SEQ_ID_UNKNOWN5 0x0E +#define SEQ_ID_UNKNOWN6 0x0F +#define SEQ_ID_MCLK_LO 0x10 +#define SEQ_ID_MCLK_HI 0x11 +#define SEQ_ID_DCLK_LO 0x12 +#define SEQ_ID_DCLK_HI 0x13 +#define SEQ_ID_CLKSYN_CNTL_1 0x14 +#define SEQ_ID_CLKSYN_CNTL_2 0x15 +#define SEQ_ID_CLKSYN_TEST_HI 0x16 /* reserved for S3 testing of the */ +#define SEQ_ID_CLKSYN_TEST_LO 0x17 /* internal clock synthesizer */ +#define SEQ_ID_RAMDAC_CNTL 0x18 +#define SEQ_ID_MORE_MAGIC 0x1A + +/* CRT Controller: */ +#define CRT_ADDRESS 0x03D4 +#define CRT_ADDRESS_R 0x03D5 +#define CRT_ADDRESS_W 0x03D5 +#define CRT_ID_HOR_TOTAL 0x00 +#define CRT_ID_HOR_DISP_ENA_END 0x01 +#define CRT_ID_START_HOR_BLANK 0x02 +#define CRT_ID_END_HOR_BLANK 0x03 +#define CRT_ID_START_HOR_RETR 0x04 +#define CRT_ID_END_HOR_RETR 0x05 +#define CRT_ID_VER_TOTAL 0x06 +#define CRT_ID_OVERFLOW 0x07 +#define CRT_ID_PRESET_ROW_SCAN 0x08 +#define CRT_ID_MAX_SCAN_LINE 0x09 +#define CRT_ID_CURSOR_START 0x0A +#define CRT_ID_CURSOR_END 0x0B +#define CRT_ID_START_ADDR_HIGH 0x0C +#define CRT_ID_START_ADDR_LOW 0x0D +#define CRT_ID_CURSOR_LOC_HIGH 0x0E +#define CRT_ID_CURSOR_LOC_LOW 0x0F +#define CRT_ID_START_VER_RETR 0x10 +#define CRT_ID_END_VER_RETR 0x11 +#define CRT_ID_VER_DISP_ENA_END 0x12 +#define CRT_ID_SCREEN_OFFSET 0x13 +#define CRT_ID_UNDERLINE_LOC 0x14 +#define CRT_ID_START_VER_BLANK 0x15 +#define CRT_ID_END_VER_BLANK 0x16 +#define CRT_ID_MODE_CONTROL 0x17 +#define CRT_ID_LINE_COMPARE 0x18 +#define CRT_ID_GD_LATCH_RBACK 0x22 +#define CRT_ID_ACT_TOGGLE_RBACK 0x24 +#define CRT_ID_ACT_INDEX_RBACK 0x26 +/* S3 extensions: S3 VGA Registers */ +#define CRT_ID_DEVICE_HIGH 0x2D +#define CRT_ID_DEVICE_LOW 0x2E +#define CRT_ID_REVISION 0x2F +#define CRT_ID_CHIP_ID_REV 0x30 +#define CRT_ID_MEMORY_CONF 0x31 +#define CRT_ID_BACKWAD_COMP_1 0x32 +#define CRT_ID_BACKWAD_COMP_2 0x33 +#define CRT_ID_BACKWAD_COMP_3 0x34 +#define CRT_ID_REGISTER_LOCK 0x35 +#define CRT_ID_CONFIG_1 0x36 +#define CRT_ID_CONFIG_2 0x37 +#define CRT_ID_REGISTER_LOCK_1 0x38 +#define CRT_ID_REGISTER_LOCK_2 0x39 +#define CRT_ID_MISC_1 0x3A +#define CRT_ID_DISPLAY_FIFO 0x3B +#define CRT_ID_LACE_RETR_START 0x3C +/* S3 extensions: System Control Registers */ +#define CRT_ID_SYSTEM_CONFIG 0x40 +#define CRT_ID_BIOS_FLAG 0x41 +#define CRT_ID_LACE_CONTROL 0x42 +#define CRT_ID_EXT_MODE 0x43 +#define CRT_ID_HWGC_MODE 0x45 /* HWGC = Hardware Graphics Cursor */ +#define CRT_ID_HWGC_ORIGIN_X_HI 0x46 +#define CRT_ID_HWGC_ORIGIN_X_LO 0x47 +#define CRT_ID_HWGC_ORIGIN_Y_HI 0x48 +#define CRT_ID_HWGC_ORIGIN_Y_LO 0x49 +#define CRT_ID_HWGC_FG_STACK 0x4A +#define CRT_ID_HWGC_BG_STACK 0x4B +#define CRT_ID_HWGC_START_AD_HI 0x4C +#define CRT_ID_HWGC_START_AD_LO 0x4D +#define CRT_ID_HWGC_DSTART_X 0x4E +#define CRT_ID_HWGC_DSTART_Y 0x4F +/* S3 extensions: System Extension Registers */ +#define CRT_ID_EXT_SYS_CNTL_1 0x50 +#define CRT_ID_EXT_SYS_CNTL_2 0x51 +#define CRT_ID_EXT_BIOS_FLAG_1 0x52 +#define CRT_ID_EXT_MEM_CNTL_1 0x53 +#define CRT_ID_EXT_MEM_CNTL_2 0x54 +#define CRT_ID_EXT_DAC_CNTL 0x55 +#define CRT_ID_EX_SYNC_1 0x56 +#define CRT_ID_EX_SYNC_2 0x57 +#define CRT_ID_LAW_CNTL 0x58 /* LAW = Linear Address Window */ +#define CRT_ID_LAW_POS_HI 0x59 +#define CRT_ID_LAW_POS_LO 0x5A +#define CRT_ID_GOUT_PORT 0x5C +#define CRT_ID_EXT_HOR_OVF 0x5D +#define CRT_ID_EXT_VER_OVF 0x5E +#define CRT_ID_EXT_MEM_CNTL_3 0x60 +#define CRT_ID_EX_SYNC_3 0x63 +#define CRT_ID_EXT_MISC_CNTL 0x65 +#define CRT_ID_EXT_MISC_CNTL_1 0x66 +#define CRT_ID_EXT_MISC_CNTL_2 0x67 +#define CRT_ID_CONFIG_3 0x68 +#define CRT_ID_EXT_SYS_CNTL_3 0x69 +#define CRT_ID_EXT_SYS_CNTL_4 0x6A +#define CRT_ID_EXT_BIOS_FLAG_3 0x6B +#define CRT_ID_EXT_BIOS_FLAG_4 0x6C + +/* Enhanced Commands Registers: */ +#define ECR_SUBSYSTEM_STAT 0x42E8 +#define ECR_SUBSYSTEM_CNTL 0x42E8 +#define ECR_ADV_FUNC_CNTL 0x4AE8 +#define ECR_CURRENT_Y_POS 0x82E8 +#define ECR_CURRENT_Y_POS2 0x82EA /* Trio64 only */ +#define ECR_CURRENT_X_POS 0x86E8 +#define ECR_CURRENT_X_POS2 0x86EA /* Trio64 only */ +#define ECR_DEST_Y__AX_STEP 0x8AE8 +#define ECR_DEST_Y2__AX_STEP2 0x8AEA /* Trio64 only */ +#define ECR_DEST_X__DIA_STEP 0x8EE8 +#define ECR_DEST_X2__DIA_STEP2 0x8EEA /* Trio64 only */ +#define ECR_ERR_TERM 0x92E8 +#define ECR_ERR_TERM2 0x92EA /* Trio64 only */ +#define ECR_MAJ_AXIS_PIX_CNT 0x96E8 +#define ECR_MAJ_AXIS_PIX_CNT2 0x96EA /* Trio64 only */ +#define ECR_GP_STAT 0x9AE8 /* GP = Graphics Processor */ +#define ECR_DRAW_CMD 0x9AE8 +#define ECR_DRAW_CMD2 0x9AEA /* Trio64 only */ +#define ECR_SHORT_STROKE 0x9EE8 +#define ECR_BKGD_COLOR 0xA2E8 /* BKGD = Background */ +#define ECR_FRGD_COLOR 0xA6E8 /* FRGD = Foreground */ +#define ECR_BITPLANE_WRITE_MASK 0xAAE8 +#define ECR_BITPLANE_READ_MASK 0xAEE8 +#define ECR_COLOR_COMPARE 0xB2E8 +#define ECR_BKGD_MIX 0xB6E8 +#define ECR_FRGD_MIX 0xBAE8 +#define ECR_READ_REG_DATA 0xBEE8 +#define ECR_ID_MIN_AXIS_PIX_CNT 0x00 +#define ECR_ID_SCISSORS_TOP 0x01 +#define ECR_ID_SCISSORS_LEFT 0x02 +#define ECR_ID_SCISSORS_BUTTOM 0x03 +#define ECR_ID_SCISSORS_RIGHT 0x04 +#define ECR_ID_PIX_CNTL 0x0A +#define ECR_ID_MULT_CNTL_MISC_2 0x0D +#define ECR_ID_MULT_CNTL_MISC 0x0E +#define ECR_ID_READ_SEL 0x0F +#define ECR_PIX_TRANS 0xE2E8 +#define ECR_PIX_TRANS_EXT 0xE2EA +#define ECR_PATTERN_Y 0xEAE8 /* Trio64 only */ +#define ECR_PATTERN_X 0xEAEA /* Trio64 only */ + + +/* Pass-through */ +#define PASS_ADDRESS 0x40001 +#define PASS_ADDRESS_W 0x40001 + +/* Video DAC */ +#define VDAC_ADDRESS 0x03c8 +#define VDAC_ADDRESS_W 0x03c8 +#define VDAC_ADDRESS_R 0x03c7 +#define VDAC_STATE 0x03c7 +#define VDAC_DATA 0x03c9 +#define VDAC_MASK 0x03c6 + + +#define WGfx(ba, idx, val) \ +do { wb_64(ba, GCT_ADDRESS, idx); wb_64(ba, GCT_ADDRESS_W , val); } while (0) + +#define WSeq(ba, idx, val) \ +do { wb_64(ba, SEQ_ADDRESS, idx); wb_64(ba, SEQ_ADDRESS_W , val); } while (0) + +#define WCrt(ba, idx, val) \ +do { wb_64(ba, CRT_ADDRESS, idx); wb_64(ba, CRT_ADDRESS_W , val); } while (0) + +#define WAttr(ba, idx, val) \ +do { \ + unsigned char tmp;\ + tmp = rb_64(ba, ACT_ADDRESS_RESET);\ + wb_64(ba, ACT_ADDRESS_W, idx);\ + wb_64(ba, ACT_ADDRESS_W, val);\ +} while (0) + +#define SetTextPlane(ba, m) \ +do { \ + WGfx(ba, GCT_ID_READ_MAP_SELECT, m & 3 );\ + WSeq(ba, SEQ_ID_MAP_MASK, (1 << (m & 3)));\ +} while (0) + + /* --------------------------------- */ + /* prototypes */ + /* --------------------------------- */ + +inline unsigned char RAttr(volatile unsigned char * board, short idx); +inline unsigned char RSeq(volatile unsigned char * board, short idx); +inline unsigned char RCrt(volatile unsigned char * board, short idx); +inline unsigned char RGfx(volatile unsigned char * board, short idx); +inline void cv64_write_port(unsigned short bits, + volatile unsigned char *board); +inline void cvscreen(int toggle, volatile unsigned char *board); +inline void gfx_on_off(int toggle, volatile unsigned char *board); +#if 0 +unsigned short cv64_compute_clock(unsigned long freq); +int cv_has_4mb(volatile unsigned char * fb); +void cv64_board_init(void); +void cv64_load_video_mode(struct fb_var_screeninfo *video_mode); +#endif + +void cvision_bitblt(u_short sx, u_short sy, u_short dx, u_short dy, u_short w, + u_short h); +void cvision_clear(u_short dx, u_short dy, u_short w, u_short h, u_short bg); diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c new file mode 100644 index 000000000000..1dbb82dca40b --- /dev/null +++ b/drivers/video/dnfb.c @@ -0,0 +1,302 @@ +#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/delay.h> +#include <linux/interrupt.h> +#include <asm/setup.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/amigahw.h> +#include <asm/amigaints.h> +#include <asm/apollohw.h> +#include <linux/fb.h> +#include <linux/module.h> + +/* apollo video HW definitions */ + +/* + * Control Registers. IOBASE + $x + * + * Note: these are the Memory/IO BASE definitions for a mono card set to the + * alternate address + * + * Control 3A and 3B serve identical functions except that 3A + * deals with control 1 and 3b deals with Color LUT reg. + */ + +#define AP_IOBASE 0x3b0 /* Base address of 1 plane board. */ +#define AP_STATUS isaIO2mem(AP_IOBASE+0) /* Status register. Read */ +#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */ +#define AP_DEVICE_ID isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */ +#define AP_ROP_1 isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */ +#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+4) /* Diagnostic Memory Request. Write Word */ +#define AP_CONTROL_0 isaIO2mem(AP_IOBASE+8) /* Control Register 0. Read/Write */ +#define AP_CONTROL_1 isaIO2mem(AP_IOBASE+0xa) /* Control Register 1. Read/Write */ +#define AP_CONTROL_3A isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */ +#define AP_CONTROL_2 isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */ + + +#define FRAME_BUFFER_START 0x0FA0000 +#define FRAME_BUFFER_LEN 0x40000 + +/* CREG 0 */ +#define VECTOR_MODE 0x40 /* 010x.xxxx */ +#define DBLT_MODE 0x80 /* 100x.xxxx */ +#define NORMAL_MODE 0xE0 /* 111x.xxxx */ +#define SHIFT_BITS 0x1F /* xxx1.1111 */ + /* other bits are Shift value */ + +/* CREG 1 */ +#define AD_BLT 0x80 /* 1xxx.xxxx */ +#define NORMAL 0x80 /* 1xxx.xxxx */ /* What is happening here ?? */ +#define INVERSE 0x00 /* 0xxx.xxxx */ /* Clearing this reverses the screen */ +#define PIX_BLT 0x00 /* 0xxx.xxxx */ + +#define AD_HIBIT 0x40 /* xIxx.xxxx */ + +#define ROP_EN 0x10 /* xxx1.xxxx */ +#define DST_EQ_SRC 0x00 /* xxx0.xxxx */ +#define nRESET_SYNC 0x08 /* xxxx.1xxx */ +#define SYNC_ENAB 0x02 /* xxxx.xx1x */ + +#define BLANK_DISP 0x00 /* xxxx.xxx0 */ +#define ENAB_DISP 0x01 /* xxxx.xxx1 */ + +#define NORM_CREG1 (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */ + +/* CREG 2 */ + +/* + * Following 3 defines are common to 1, 4 and 8 plane. + */ + +#define S_DATA_1s 0x00 /* 00xx.xxxx */ /* set source to all 1's -- vector drawing */ +#define S_DATA_PIX 0x40 /* 01xx.xxxx */ /* takes source from ls-bits and replicates over 16 bits */ +#define S_DATA_PLN 0xC0 /* 11xx.xxxx */ /* normal, each data access =16-bits in + one plane of image mem */ + +/* CREG 3A/CREG 3B */ +# define RESET_CREG 0x80 /* 1000.0000 */ + +/* ROP REG - all one nibble */ +/* ********* NOTE : this is used r0,r1,r2,r3 *********** */ +#define ROP(r2,r3,r0,r1) ( (U_SHORT)((r0)|((r1)<<4)|((r2)<<8)|((r3)<<12)) ) +#define DEST_ZERO 0x0 +#define SRC_AND_DEST 0x1 +#define SRC_AND_nDEST 0x2 +#define SRC 0x3 +#define nSRC_AND_DEST 0x4 +#define DEST 0x5 +#define SRC_XOR_DEST 0x6 +#define SRC_OR_DEST 0x7 +#define SRC_NOR_DEST 0x8 +#define SRC_XNOR_DEST 0x9 +#define nDEST 0xA +#define SRC_OR_nDEST 0xB +#define nSRC 0xC +#define nSRC_OR_DEST 0xD +#define SRC_NAND_DEST 0xE +#define DEST_ONE 0xF + +#define SWAP(A) ((A>>8) | ((A&0xff) <<8)) + +/* frame buffer operations */ + +static int dnfb_blank(int blank, struct fb_info *info); +static void dnfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); + +static struct fb_ops dn_fb_ops = { + .owner = THIS_MODULE, + .fb_blank = dnfb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = dnfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +struct fb_var_screeninfo dnfb_var __devinitdata = { + .xres = 1280, + .yres = 1024, + .xres_virtual = 2048, + .yres_virtual = 1024, + .bits_per_pixel = 1, + .height = -1, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo dnfb_fix __devinitdata = { + .id = "Apollo Mono", + .smem_start = (FRAME_BUFFER_START + IO_BASE), + .smem_len = FRAME_BUFFER_LEN, + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_MONO10, + .line_length = 256, +}; + +static int dnfb_blank(int blank, struct fb_info *info) +{ + if (blank) + out_8(AP_CONTROL_3A, 0x0); + else + out_8(AP_CONTROL_3A, 0x1); + return 0; +} + +static +void dnfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + + int incr, y_delta, pre_read = 0, x_end, x_word_count; + uint start_mask, end_mask, dest; + ushort *src, dummy; + short i, j; + + incr = (area->dy <= area->sy) ? 1 : -1; + + src = (ushort *)(info->screen_base + area->sy * info->fix.line_length + + (area->sx >> 4)); + dest = area->dy * (info->fix.line_length >> 1) + (area->dx >> 4); + + if (incr > 0) { + y_delta = (info->fix.line_length * 8) - area->sx - area->width; + x_end = area->dx + area->width - 1; + x_word_count = (x_end >> 4) - (area->dx >> 4) + 1; + start_mask = 0xffff0000 >> (area->dx & 0xf); + end_mask = 0x7ffff >> (x_end & 0xf); + out_8(AP_CONTROL_0, + (((area->dx & 0xf) - (area->sx & 0xf)) % 16) | (0x4 << 5)); + if ((area->dx & 0xf) < (area->sx & 0xf)) + pre_read = 1; + } else { + y_delta = -((info->fix.line_length * 8) - area->sx - area->width); + x_end = area->dx - area->width + 1; + x_word_count = (area->dx >> 4) - (x_end >> 4) + 1; + start_mask = 0x7ffff >> (area->dx & 0xf); + end_mask = 0xffff0000 >> (x_end & 0xf); + out_8(AP_CONTROL_0, + ((-((area->sx & 0xf) - (area->dx & 0xf))) % 16) | + (0x4 << 5)); + if ((area->dx & 0xf) > (area->sx & 0xf)) + pre_read = 1; + } + + for (i = 0; i < area->height; i++) { + + out_8(AP_CONTROL_3A, 0xc | (dest >> 16)); + + if (pre_read) { + dummy = *src; + src += incr; + } + + if (x_word_count) { + out_8(AP_WRITE_ENABLE, start_mask); + *src = dest; + src += incr; + dest += incr; + out_8(AP_WRITE_ENABLE, 0); + + for (j = 1; j < (x_word_count - 1); j++) { + *src = dest; + src += incr; + dest += incr; + } + + out_8(AP_WRITE_ENABLE, start_mask); + *src = dest; + dest += incr; + src += incr; + } else { + out_8(AP_WRITE_ENABLE, start_mask | end_mask); + *src = dest; + dest += incr; + src += incr; + } + src += (y_delta / 16); + dest += (y_delta / 16); + } + out_8(AP_CONTROL_0, NORMAL_MODE); +} + +/* + * Initialization + */ + +static int __devinit dnfb_probe(struct device *device) +{ + struct platform_device *dev = to_platform_device(device); + struct fb_info *info; + int err = 0; + + info = framebuffer_alloc(0, &dev->dev); + if (!info) + return -ENOMEM; + + info->fbops = &dn_fb_ops; + info->fix = dnfb_fix; + info->var = dnfb_var; + info->var.red.length = 1; + info->var.red.offset = 0; + info->var.green = info->var.blue = info->var.red; + info->screen_base = (u_char *) info->fix.smem_start; + + err = fb_alloc_cmap(&info->cmap, 2, 0); + if (err < 0) { + framebuffer_release(info); + return err; + } + + err = register_framebuffer(info); + if (err < 0) { + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + return err; + } + dev_set_drvdata(&dev->dev, info); + + /* now we have registered we can safely setup the hardware */ + out_8(AP_CONTROL_3A, RESET_CREG); + out_be16(AP_WRITE_ENABLE, 0x0); + out_8(AP_CONTROL_0, NORMAL_MODE); + out_8(AP_CONTROL_1, (AD_BLT | DST_EQ_SRC | NORM_CREG1)); + out_8(AP_CONTROL_2, S_DATA_PLN); + out_be16(AP_ROP_1, SWAP(0x3)); + + printk("apollo frame buffer alive and kicking !\n"); + return err; +} + +static struct device_driver dnfb_driver = { + .name = "dnfb", + .bus = &platform_bus_type, + .probe = dnfb_probe, +}; + +static struct platform_device dnfb_device = { + .name = "dnfb", +}; + +int __init dnfb_init(void) +{ + int ret; + + if (fb_get_options("dnfb", NULL)) + return -ENODEV; + + ret = driver_register(&dnfb_driver); + + if (!ret) { + ret = platform_device_register(&dnfb_device); + if (ret) + driver_unregister(&dnfb_driver); + } + return ret; +} + +module_init(dnfb_init); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/edid.h b/drivers/video/edid.h new file mode 100644 index 000000000000..bd89fb3be8c2 --- /dev/null +++ b/drivers/video/edid.h @@ -0,0 +1,138 @@ +/* + * drivers/video/edid.h - EDID/DDC Header + * + * Based on: + * 1. XFree86 4.3.0, edid.h + * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> + * + * 2. John Fremlin <vii@users.sourceforge.net> and + * Ani Joshi <ajoshi@unixbox.com> + * + * DDC is a Trademark of VESA (Video Electronics Standard Association). + * + * 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 __EDID_H__ +#define __EDID_H__ + +#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 EDID_STRUCT_DISPLAY 0x14 + +#define DPMS_FLAGS 0x18 +#define ESTABLISHED_TIMING_1 0x23 +#define ESTABLISHED_TIMING_2 0x24 +#define MANUFACTURERS_TIMINGS 0x25 + +/* standard timings supported */ +#define STD_TIMING 8 +#define STD_TIMING_DESCRIPTION_SIZE 2 +#define STD_TIMING_DESCRIPTIONS_START 0x26 + +#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 )*10000) +#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 ) + +#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) + +#define V_MIN_RATE block[ 5 ] +#define V_MAX_RATE block[ 6 ] +#define H_MIN_RATE block[ 7 ] +#define H_MAX_RATE block[ 8 ] +#define MAX_PIXEL_CLOCK (((int)block[ 9 ]) * 10) +#define GTF_SUPPORT block[10] + +#define DPMS_ACTIVE_OFF (1 << 5) +#define DPMS_SUSPEND (1 << 6) +#define DPMS_STANDBY (1 << 7) + +#endif /* __EDID_H__ */ diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c new file mode 100644 index 000000000000..116e808d71cd --- /dev/null +++ b/drivers/video/epson1355fb.c @@ -0,0 +1,774 @@ +/* + * linux/drivers/video/epson1355fb.c -- Epson S1D13505 frame buffer for 2.5. + * + * Epson Research S1D13505 Embedded RAMDAC LCD/CRT Controller + * (previously known as SED1355) + * + * Cf. http://www.erd.epson.com/vdc/html/S1D13505.html + * + * + * Copyright (C) Hewlett-Packard Company. All rights reserved. + * + * Written by Christopher Hoover <ch@hpl.hp.com> + * + * Adapted from: + * + * linux/drivers/video/skeletonfb.c + * Modified to new api Jan 2001 by James Simmons (jsimmons@infradead.org) + * Created 28 Dec 1997 by Geert Uytterhoeven + * + * linux/drivers/video/epson1355fb.c (2.4 driver) + * 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. + * + * + * Noteworthy Issues + * ----------------- + * + * This driver is complicated by the fact that this is a 16-bit chip + * and, on at least one platform (ceiva), we can only do 16-bit reads + * and writes to the framebuffer. We hide this from user space + * except in the case of mmap(). + * + * + * To Do + * ----- + * + * - Test 8-bit pseudocolor mode + * - Allow setting bpp, virtual resolution + * - Implement horizontal panning + * - (maybe) Implement hardware cursor + */ + +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <asm/types.h> +#include <asm/io.h> +#include <asm/uaccess.h> + +#include <video/epson1355.h> + +struct epson1355_par { + unsigned long reg_addr; +}; + +/* ------------------------------------------------------------------------- */ + +#ifdef CONFIG_SUPERH + +static inline u8 epson1355_read_reg(int index) +{ + return ctrl_inb(par.reg_addr + index); +} + +static inline void epson1355_write_reg(u8 data, int index) +{ + ctrl_outb(data, par.reg_addr + index); +} + +#elif defined(CONFIG_ARM) + +# ifdef CONFIG_ARCH_CEIVA +# include <asm/arch/hardware.h> +# define EPSON1355FB_BASE_PHYS (CEIVA_PHYS_SED1355) +# endif + +static inline u8 epson1355_read_reg(struct epson1355_par *par, int index) +{ + return __raw_readb(par->reg_addr + index); +} + +static inline void epson1355_write_reg(struct epson1355_par *par, u8 data, int index) +{ + __raw_writeb(data, par->reg_addr + index); +} + +#else +# error "no architecture-specific epson1355_{read,write}_reg" +#endif + +#ifndef EPSON1355FB_BASE_PHYS +# error "EPSON1355FB_BASE_PHYS is not defined" +#endif + +#define EPSON1355FB_REGS_OFS (0) +#define EPSON1355FB_REGS_PHYS (EPSON1355FB_BASE_PHYS + EPSON1355FB_REGS_OFS) +#define EPSON1355FB_REGS_LEN (64) + +#define EPSON1355FB_FB_OFS (0x00200000) +#define EPSON1355FB_FB_PHYS (EPSON1355FB_BASE_PHYS + EPSON1355FB_FB_OFS) +#define EPSON1355FB_FB_LEN (2 * 1024 * 1024) + +/* ------------------------------------------------------------------------- */ + +static inline u16 epson1355_read_reg16(struct epson1355_par *par, int index) +{ + u8 lo = epson1355_read_reg(par, index); + u8 hi = epson1355_read_reg(par, index + 1); + + return (hi << 8) | lo; +} + +static inline void epson1355_write_reg16(struct epson1355_par *par, u16 data, int index) +{ + u8 lo = data & 0xff; + u8 hi = (data >> 8) & 0xff; + + epson1355_write_reg(par, lo, index); + epson1355_write_reg(par, hi, index + 1); +} + +static inline u32 epson1355_read_reg20(struct epson1355_par *par, int index) +{ + u8 b0 = epson1355_read_reg(par, index); + u8 b1 = epson1355_read_reg(par, index + 1); + u8 b2 = epson1355_read_reg(par, index + 2); + + return (b2 & 0x0f) << 16 | (b1 << 8) | b0; +} + +static inline void epson1355_write_reg20(struct epson1355_par *par, u32 data, int index) +{ + u8 b0 = data & 0xff; + u8 b1 = (data >> 8) & 0xff; + u8 b2 = (data >> 16) & 0x0f; + + epson1355_write_reg(par, b0, index); + epson1355_write_reg(par, b1, index + 1); + epson1355_write_reg(par, b2, index + 2); +} + +/* ------------------------------------------------------------------------- */ + +static void set_lut(struct epson1355_par *par, u8 index, u8 r, u8 g, u8 b) +{ + epson1355_write_reg(par, index, REG_LUT_ADDR); + epson1355_write_reg(par, r, REG_LUT_DATA); + epson1355_write_reg(par, g, REG_LUT_DATA); + epson1355_write_reg(par, b, REG_LUT_DATA); +} + + +/** + * epson1355fb_setcolreg - sets a color register. + * @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. + * @info: frame buffer info structure + * + * Returns negative errno on error, or zero on success. + */ +static int epson1355fb_setcolreg(unsigned regno, unsigned r, unsigned g, + unsigned b, unsigned transp, + struct fb_info *info) +{ + struct epson1355_par *par = info->par; + + if (info->var.grayscale) + r = g = b = (19595 * r + 38470 * g + 7471 * b) >> 16; + + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + if (regno >= 16) + return -EINVAL; + + ((u32 *) info->pseudo_palette)[regno] = + (r & 0xf800) | (g & 0xfc00) >> 5 | (b & 0xf800) >> 11; + + break; + case FB_VISUAL_PSEUDOCOLOR: + if (regno >= 256) + return -EINVAL; + + set_lut(par, regno, r >> 8, g >> 8, b >> 8); + + break; + default: + return -ENOSYS; + } + return 0; +} + +/* ------------------------------------------------------------------------- */ + +/** + * epson1355fb_pan_display - Pans the display. + * @var: frame buffer variable screen structure + * @info: frame buffer structure that represents a single frame buffer + * + * Pan (or wrap, depending on the `vmode' field) the display using the + * `xoffset' and `yoffset' fields of the `var' structure. + * If the values don't fit, return -EINVAL. + * + * Returns negative errno on error, or zero on success. + */ +static int epson1355fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct epson1355_par *par = info->par; + u32 start; + + if (var->xoffset != 0) /* not yet ... */ + return -EINVAL; + + if (var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + + start = (info->fix.line_length >> 1) * var->yoffset; + + epson1355_write_reg20(par, start, REG_SCRN1_DISP_START_ADDR0); + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static void lcd_enable(struct epson1355_par *par, int enable) +{ + u8 mode = epson1355_read_reg(par, REG_DISPLAY_MODE); + + if (enable) + mode |= 1; + else + mode &= ~1; + + epson1355_write_reg(par, mode, REG_DISPLAY_MODE); +} + +#if defined(CONFIG_ARCH_CEIVA) +static void backlight_enable(int enable) +{ + /* ### this should be protected by a spinlock ... */ + u8 pddr = clps_readb(PDDR); + if (enable) + pddr |= (1 << 5); + else + pddr &= ~(1 << 5); + clps_writeb(pddr, PDDR); +} +#else +static void backlight_enable(int enable) +{ +} +#endif + + +/** + * epson1355fb_blank - blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + * + * Blank the screen if blank_mode != 0, else unblank. Return 0 if + * blanking succeeded, != 0 if un-/blanking failed due to e.g. a + * video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + * + * Returns negative errno on error, or zero on success. + * + */ +static int epson1355fb_blank(int blank_mode, struct fb_info *info) +{ + struct epson1355_par *par = info->par; + + switch (blank_mode) { + case FB_BLANK_UNBLANKING: + case FB_BLANK_NORMAL: + lcd_enable(par, 1); + backlight_enable(1); + break; + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + backlight_enable(0); + break; + case FB_BLANK_POWERDOWN: + backlight_enable(0); + lcd_enable(par, 0); + break; + default: + return -EINVAL; + } + + /* let fbcon do a soft blank for us */ + return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; +} + +/* ------------------------------------------------------------------------- */ + +/* + * We can't use the cfb generic routines, as we have to limit + * ourselves to 16-bit or 8-bit loads and stores to this 16-bit + * chip. + */ + +static inline void epson1355fb_fb_writel(unsigned long v, unsigned long *a) +{ + u16 *p = (u16 *) a; + u16 l = v & 0xffff; + u16 h = v >> 16; + + fb_writew(l, p); + fb_writew(h, p + 1); +} + +static inline unsigned long epson1355fb_fb_readl(const unsigned long *a) +{ + const u16 *p = (u16 *) a; + u16 l = fb_readw(p); + u16 h = fb_readw(p + 1); + + return (h << 16) | l; +} + +#define FB_READL epson1355fb_fb_readl +#define FB_WRITEL epson1355fb_fb_writel + +/* ------------------------------------------------------------------------- */ + +static inline unsigned long copy_from_user16(void *to, const void *from, + unsigned long n) +{ + u16 *dst = (u16 *) to; + u16 *src = (u16 *) from; + + if (!access_ok(VERIFY_READ, from, n)) + return n; + + while (n > 1) { + u16 v; + if (__get_user(v, src)) + return n; + + fb_writew(v, dst); + + src++, dst++; + n -= 2; + } + + if (n) { + u8 v; + + if (__get_user(v, ((u8 *) src))) + return n; + + fb_writeb(v, dst); + } + return 0; +} + +static inline unsigned long copy_to_user16(void *to, const void *from, + unsigned long n) +{ + u16 *dst = (u16 *) to; + u16 *src = (u16 *) from; + + if (!access_ok(VERIFY_WRITE, to, n)) + return n; + + while (n > 1) { + u16 v = fb_readw(src); + + if (__put_user(v, dst)) + return n; + + src++, dst++; + n -= 2; + } + + if (n) { + u8 v = fb_readb(src); + + if (__put_user(v, ((u8 *) dst))) + return n; + } + return 0; +} + + +static ssize_t +epson1355fb_read(struct file *file, char *buf, size_t count, loff_t * ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + unsigned long p = *ppos; + + /* from fbmem.c except for our own copy_*_user */ + if (!info || !info->screen_base) + return -ENODEV; + + if (p >= info->fix.smem_len) + return 0; + if (count >= info->fix.smem_len) + count = info->fix.smem_len; + if (count + p > info->fix.smem_len) + count = info->fix.smem_len - p; + + if (count) { + char *base_addr; + + base_addr = info->screen_base; + count -= copy_to_user16(buf, base_addr + p, count); + if (!count) + return -EFAULT; + *ppos += count; + } + return count; +} + +static ssize_t +epson1355fb_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + unsigned long p = *ppos; + int err; + + /* from fbmem.c except for our own copy_*_user */ + if (!info || !info->screen_base) + return -ENODEV; + + /* from fbmem.c except for our own copy_*_user */ + if (p > info->fix.smem_len) + return -ENOSPC; + if (count >= info->fix.smem_len) + count = info->fix.smem_len; + err = 0; + if (count + p > info->fix.smem_len) { + count = info->fix.smem_len - p; + err = -ENOSPC; + } + + if (count) { + char *base_addr; + + base_addr = info->screen_base; + count -= copy_from_user16(base_addr + p, buf, count); + *ppos += count; + err = -EFAULT; + } + if (count) + return count; + return err; +} + +/* ------------------------------------------------------------------------- */ + +static struct fb_ops epson1355fb_fbops = { + .owner = THIS_MODULE, + .fb_setcolreg = epson1355fb_setcolreg, + .fb_pan_display = epson1355fb_pan_display, + .fb_blank = epson1355fb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_read = epson1355fb_read, + .fb_write = epson1355fb_write, + .fb_cursor = soft_cursor, +}; + +/* ------------------------------------------------------------------------- */ + +static __init unsigned int get_fb_size(struct fb_info *info) +{ + unsigned int size = 2 * 1024 * 1024; + char *p = info->screen_base; + + /* the 512k framebuffer is aliased at start + 0x80000 * n */ + fb_writeb(1, p); + fb_writeb(0, p + 0x80000); + if (!fb_readb(p)) + size = 512 * 1024; + + fb_writeb(0, p); + + return size; +} + +static int epson1355_width_tab[2][4] __initdata = + { {4, 8, 16, -1}, {9, 12, 16, -1} }; +static int epson1355_bpp_tab[8] __initdata = { 1, 2, 4, 8, 15, 16 }; + +static void __init fetch_hw_state(struct fb_info *info, struct epson1355_par *par) +{ + struct fb_var_screeninfo *var = &info->var; + struct fb_fix_screeninfo *fix = &info->fix; + u8 panel, display; + u16 offset; + u32 xres, yres; + u32 xres_virtual, yres_virtual; + int bpp, lcd_bpp; + int is_color, is_dual, is_tft; + int lcd_enabled, crt_enabled; + + fix->type = FB_TYPE_PACKED_PIXELS; + + display = epson1355_read_reg(par, REG_DISPLAY_MODE); + bpp = epson1355_bpp_tab[(display >> 2) & 7]; + + switch (bpp) { + case 8: + fix->visual = FB_VISUAL_PSEUDOCOLOR; + var->bits_per_pixel = 8; + var->red.offset = var->green.offset = var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = 8; + break; + case 16: + /* 5-6-5 RGB */ + fix->visual = FB_VISUAL_TRUECOLOR; + var->bits_per_pixel = 16; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + default: + BUG(); + } + fb_alloc_cmap(&(info->cmap), 256, 0); + + panel = epson1355_read_reg(par, REG_PANEL_TYPE); + is_color = (panel & 0x04) != 0; + is_dual = (panel & 0x02) != 0; + is_tft = (panel & 0x01) != 0; + crt_enabled = (display & 0x02) != 0; + lcd_enabled = (display & 0x01) != 0; + lcd_bpp = epson1355_width_tab[is_tft][(panel >> 4) & 3]; + + xres = (epson1355_read_reg(par, REG_HORZ_DISP_WIDTH) + 1) * 8; + yres = (epson1355_read_reg16(par, REG_VERT_DISP_HEIGHT0) + 1) * + ((is_dual && !crt_enabled) ? 2 : 1); + offset = epson1355_read_reg16(par, REG_MEM_ADDR_OFFSET0) & 0x7ff; + xres_virtual = offset * 16 / bpp; + yres_virtual = fix->smem_len / (offset * 2); + + var->xres = xres; + var->yres = yres; + var->xres_virtual = xres_virtual; + var->yres_virtual = yres_virtual; + var->xoffset = var->yoffset = 0; + + fix->line_length = offset * 2; + + fix->xpanstep = 0; /* no pan yet */ + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->accel = FB_ACCEL_NONE; + + var->grayscale = !is_color; + +#ifdef DEBUG + printk(KERN_INFO + "epson1355fb: xres=%d, yres=%d, " + "is_color=%d, is_dual=%d, is_tft=%d\n", + xres, yres, is_color, is_dual, is_tft); + printk(KERN_INFO + "epson1355fb: bpp=%d, lcd_bpp=%d, " + "crt_enabled=%d, lcd_enabled=%d\n", + bpp, lcd_bpp, crt_enabled, lcd_enabled); +#endif +} + + +static void clearfb16(struct fb_info *info) +{ + u16 *dst = (u16 *) info->screen_base; + unsigned long n = info->fix.smem_len; + + while (n > 1) { + fb_writew(0, dst); + dst++, n -= 2; + } + + if (n) + fb_writeb(0, dst); +} + +static void epson1355fb_platform_release(struct device *device) +{ +} + +static int epson1355fb_remove(struct device *device) +{ + struct fb_info *info = dev_get_drvdata(device); + struct epson1355_par *par = info->par; + + backlight_enable(0); + if (par) { + lcd_enable(par, 0); + if (par && par->reg_addr) + iounmap((void *) par->reg_addr); + } + + if (info) { + fb_dealloc_cmap(&info->cmap); + if (info->screen_base) + iounmap(info->screen_base); + framebuffer_release(info); + } + release_mem_region(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN); + release_mem_region(EPSON1355FB_REGS_PHYS, EPSON1355FB_REGS_LEN); + return 0; +} + +int __init epson1355fb_probe(struct device *device) +{ + struct platform_device *dev = to_platform_device(device); + struct epson1355_par *default_par; + struct fb_info *info; + u8 revision; + int rc = 0; + + if (!request_mem_region(EPSON1355FB_REGS_PHYS, EPSON1355FB_REGS_LEN, "S1D13505 registers")) { + printk(KERN_ERR "epson1355fb: unable to reserve " + "registers at 0x%0x\n", EPSON1355FB_REGS_PHYS); + rc = -EBUSY; + goto bail; + } + + if (!request_mem_region(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN, + "S1D13505 framebuffer")) { + printk(KERN_ERR "epson1355fb: unable to reserve " + "framebuffer at 0x%0x\n", EPSON1355FB_FB_PHYS); + rc = -EBUSY; + goto bail; + } + + info = framebuffer_alloc(sizeof(struct epson1355_par) + sizeof(u32) * 256, &dev->dev); + if (!info) + rc = -ENOMEM; + goto bail; + + default_par = info->par; + default_par->reg_addr = (unsigned long) ioremap(EPSON1355FB_REGS_PHYS, EPSON1355FB_REGS_LEN); + if (!default_par->reg_addr) { + printk(KERN_ERR "epson1355fb: unable to map registers\n"); + rc = -ENOMEM; + goto bail; + } + info->pseudo_palette = (void *)(default_par + 1); + + info->screen_base = ioremap(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN); + if (!info->screen_base) { + printk(KERN_ERR "epson1355fb: unable to map framebuffer\n"); + rc = -ENOMEM; + goto bail; + } + + revision = epson1355_read_reg(default_par, REG_REVISION_CODE); + if ((revision >> 2) != 3) { + printk(KERN_INFO "epson1355fb: epson1355 not found\n"); + rc = -ENODEV; + goto bail; + } + + info->fix.mmio_start = EPSON1355FB_REGS_PHYS; + info->fix.mmio_len = EPSON1355FB_REGS_LEN; + info->fix.smem_start = EPSON1355FB_FB_PHYS; + info->fix.smem_len = get_fb_size(info); + + printk(KERN_INFO "epson1355fb: regs mapped at 0x%lx, fb %d KiB mapped at 0x%p\n", + default_par->reg_addr, info->fix.smem_len / 1024, info->screen_base); + + strcpy(info->fix.id, "S1D13505"); + info->par = default_par; + info->fbops = &epson1355fb_fbops; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + + /* we expect the boot loader to have initialized the chip + with appropriate parameters from which we can determinte + the flavor of lcd panel attached */ + fetch_hw_state(info, default_par); + + /* turn this puppy on ... */ + clearfb16(info); + backlight_enable(1); + lcd_enable(default_par, 1); + + if (register_framebuffer(info) < 0) { + rc = -EINVAL; + goto bail; + } + /* + * Our driver data. + */ + dev_set_drvdata(&dev->dev, info); + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + info->node, info->fix.id); + + return 0; + + bail: + epson1355fb_remove(device); + return rc; +} + +static struct device_driver epson1355fb_driver = { + .name = "epson1355fb", + .bus = &platform_bus_type, + .probe = epson1355fb_probe, + .remove = epson1355fb_remove, +}; + +static struct platform_device epson1355fb_device = { + .name = "epson1355fb", + .id = 0, + .dev = { + .release = epson1355fb_platform_release, + } +}; + +int __init epson1355fb_init(void) +{ + int ret = 0; + + if (fb_get_options("epson1355fb", NULL)) + return -ENODEV; + + ret = driver_register(&epson1355fb_driver); + if (!ret) { + ret = platform_device_register(&epson1355fb_device); + if (ret) + driver_unregister(&epson1355fb_driver); + } + return ret; +} + +module_init(epson1355fb_init); + +#ifdef MODULE +static void __exit epson1355fb_exit(void) +{ + platform_device_unregister(&epson1355fb_device); + driver_unregister(&epson1355fb_driver); +} + +/* ------------------------------------------------------------------------- */ + +module_exit(epson1355fb_exit); +#endif + +MODULE_AUTHOR("Christopher Hoover <ch@hpl.hp.com>"); +MODULE_DESCRIPTION("Framebuffer driver for Epson S1D13505"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c new file mode 100644 index 000000000000..c51f8fb5c1de --- /dev/null +++ b/drivers/video/fbcmap.c @@ -0,0 +1,337 @@ +/* + * linux/drivers/video/fbcmap.c -- Colormap handling for frame buffer devices + * + * Created 15 Jun 1997 by Geert Uytterhoeven + * + * 2001 - Documented with DocBook + * - Brad Douglas <brad@neruo.com> + * + * 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/string.h> +#include <linux/module.h> +#include <linux/tty.h> +#include <linux/fb.h> +#include <linux/slab.h> + +#include <asm/uaccess.h> + +static u16 red2[] = { + 0x0000, 0xaaaa +}; +static u16 green2[] = { + 0x0000, 0xaaaa +}; +static u16 blue2[] = { + 0x0000, 0xaaaa +}; + +static u16 red4[] = { + 0x0000, 0xaaaa, 0x5555, 0xffff +}; +static u16 green4[] = { + 0x0000, 0xaaaa, 0x5555, 0xffff +}; +static u16 blue4[] = { + 0x0000, 0xaaaa, 0x5555, 0xffff +}; + +static u16 red8[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa +}; +static u16 green8[] = { + 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa +}; +static u16 blue8[] = { + 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa +}; + +static u16 red16[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, + 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff +}; +static u16 green16[] = { + 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa, + 0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff +}; +static u16 blue16[] = { + 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, + 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff +}; + +static struct fb_cmap default_2_colors = { + 0, 2, red2, green2, blue2, NULL +}; +static struct fb_cmap default_8_colors = { + 0, 8, red8, green8, blue8, NULL +}; +static struct fb_cmap default_4_colors = { + 0, 4, red4, green4, blue4, NULL +}; +static struct fb_cmap default_16_colors = { + 0, 16, red16, green16, blue16, NULL +}; + + +/** + * fb_alloc_cmap - allocate a colormap + * @cmap: frame buffer colormap structure + * @len: length of @cmap + * @transp: boolean, 1 if there is transparency, 0 otherwise + * + * Allocates memory for a colormap @cmap. @len is the + * number of entries in the palette. + * + * Returns -1 errno on error, or zero on success. + * + */ + +int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp) +{ + int size = len*sizeof(u16); + + if (cmap->len != len) { + fb_dealloc_cmap(cmap); + if (!len) + return 0; + if (!(cmap->red = kmalloc(size, GFP_ATOMIC))) + goto fail; + if (!(cmap->green = kmalloc(size, GFP_ATOMIC))) + goto fail; + if (!(cmap->blue = kmalloc(size, GFP_ATOMIC))) + goto fail; + if (transp) { + if (!(cmap->transp = kmalloc(size, GFP_ATOMIC))) + goto fail; + } else + cmap->transp = NULL; + } + cmap->start = 0; + cmap->len = len; + fb_copy_cmap(fb_default_cmap(len), cmap); + return 0; + +fail: + fb_dealloc_cmap(cmap); + return -1; +} + +/** + * fb_dealloc_cmap - deallocate a colormap + * @cmap: frame buffer colormap structure + * + * Deallocates a colormap that was previously allocated with + * fb_alloc_cmap(). + * + */ + +void fb_dealloc_cmap(struct fb_cmap *cmap) +{ + kfree(cmap->red); + kfree(cmap->green); + kfree(cmap->blue); + kfree(cmap->transp); + + cmap->red = cmap->green = cmap->blue = cmap->transp = NULL; + cmap->len = 0; +} + +/** + * fb_copy_cmap - copy a colormap + * @from: frame buffer colormap structure + * @to: frame buffer colormap structure + * + * Copy contents of colormap from @from to @to. + */ + +int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to) +{ + int tooff = 0, fromoff = 0; + int size; + + if (to->start > from->start) + fromoff = to->start - from->start; + else + tooff = from->start - to->start; + size = to->len - tooff; + if (size > (int) (from->len - fromoff)) + size = from->len - fromoff; + if (size <= 0) + return -EINVAL; + size *= sizeof(u16); + + memcpy(to->red+tooff, from->red+fromoff, size); + memcpy(to->green+tooff, from->green+fromoff, size); + memcpy(to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + memcpy(to->transp+tooff, from->transp+fromoff, size); + return 0; +} + +int fb_cmap_to_user(struct fb_cmap *from, struct fb_cmap_user *to) +{ + int tooff = 0, fromoff = 0; + int size; + + if (to->start > from->start) + fromoff = to->start - from->start; + else + tooff = from->start - to->start; + size = to->len - tooff; + if (size > (int) (from->len - fromoff)) + size = from->len - fromoff; + if (size <= 0) + return -EINVAL; + size *= sizeof(u16); + + if (copy_to_user(to->red+tooff, from->red+fromoff, size)) + return -EFAULT; + if (copy_to_user(to->green+tooff, from->green+fromoff, size)) + return -EFAULT; + if (copy_to_user(to->blue+tooff, from->blue+fromoff, size)) + return -EFAULT; + if (from->transp && to->transp) + if (copy_to_user(to->transp+tooff, from->transp+fromoff, size)) + return -EFAULT; + return 0; +} + +/** + * fb_set_cmap - set the colormap + * @cmap: frame buffer colormap structure + * @info: frame buffer info structure + * + * Sets the colormap @cmap for a screen of device @info. + * + * Returns negative errno on error, or zero on success. + * + */ + +int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info) +{ + int i, start; + u16 *red, *green, *blue, *transp; + u_int hred, hgreen, hblue, htransp = 0xffff; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + + if (start < 0 || !info->fbops->fb_setcolreg) + return -EINVAL; + for (i = 0; i < cmap->len; i++) { + hred = *red++; + hgreen = *green++; + hblue = *blue++; + if (transp) + htransp = *transp++; + if (info->fbops->fb_setcolreg(start++, + hred, hgreen, hblue, htransp, + info)) + break; + } + return 0; +} + +int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info) +{ + int i, start; + u16 __user *red, *green, *blue, *transp; + u_int hred, hgreen, hblue, htransp = 0xffff; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + + if (start < 0 || !info->fbops->fb_setcolreg) + return -EINVAL; + for (i = 0; i < cmap->len; i++, red++, blue++, green++) { + if (get_user(hred, red) || + get_user(hgreen, green) || + get_user(hblue, blue) || + (transp && get_user(htransp, transp))) + return -EFAULT; + if (info->fbops->fb_setcolreg(start++, + hred, hgreen, hblue, htransp, + info)) + return 0; + if (transp) + transp++; + } + return 0; +} + +/** + * fb_default_cmap - get default colormap + * @len: size of palette for a depth + * + * Gets the default colormap for a specific screen depth. @len + * is the size of the palette for a particular screen depth. + * + * Returns pointer to a frame buffer colormap structure. + * + */ + +struct fb_cmap *fb_default_cmap(int len) +{ + if (len <= 2) + return &default_2_colors; + if (len <= 4) + return &default_4_colors; + if (len <= 8) + return &default_8_colors; + return &default_16_colors; +} + + +/** + * fb_invert_cmaps - invert all defaults colormaps + * + * Invert all default colormaps. + * + */ + +void fb_invert_cmaps(void) +{ + u_int i; + + for (i = 0; i < 2; i++) { + red2[i] = ~red2[i]; + green2[i] = ~green2[i]; + blue2[i] = ~blue2[i]; + } + for (i = 0; i < 4; i++) { + red4[i] = ~red4[i]; + green4[i] = ~green4[i]; + blue4[i] = ~blue4[i]; + } + for (i = 0; i < 8; i++) { + red8[i] = ~red8[i]; + green8[i] = ~green8[i]; + blue8[i] = ~blue8[i]; + } + for (i = 0; i < 16; i++) { + red16[i] = ~red16[i]; + green16[i] = ~green16[i]; + blue16[i] = ~blue16[i]; + } +} + + + /* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(fb_alloc_cmap); +EXPORT_SYMBOL(fb_dealloc_cmap); +EXPORT_SYMBOL(fb_copy_cmap); +EXPORT_SYMBOL(fb_set_cmap); +EXPORT_SYMBOL(fb_default_cmap); +EXPORT_SYMBOL(fb_invert_cmaps); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c new file mode 100644 index 000000000000..25f460ca0daf --- /dev/null +++ b/drivers/video/fbmem.c @@ -0,0 +1,1371 @@ +/* + * linux/drivers/video/fbmem.c + * + * Copyright (C) 1994 Martin Schaller + * + * 2001 - Documented with DocBook + * - Brad Douglas <brad@neruo.com> + * + * 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/config.h> +#include <linux/module.h> + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/tty.h> +#include <linux/init.h> +#include <linux/linux_logo.h> +#include <linux/proc_fs.h> +#include <linux/console.h> +#ifdef CONFIG_KMOD +#include <linux/kmod.h> +#endif +#include <linux/devfs_fs_kernel.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/efi.h> + +#if defined(__mc68000__) || defined(CONFIG_APUS) +#include <asm/setup.h> +#endif + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +#include <linux/fb.h> + + /* + * Frame buffer device initialization and setup routines + */ + +#define FBPIXMAPSIZE (1024 * 8) + +static struct notifier_block *fb_notifier_list; +struct fb_info *registered_fb[FB_MAX]; +int num_registered_fb; + +/* + * Helpers + */ + +int fb_get_color_depth(struct fb_var_screeninfo *var) +{ + if (var->green.length == var->blue.length && + var->green.length == var->red.length && + !var->green.offset && !var->blue.offset && + !var->red.offset) + return var->green.length; + else + return (var->green.length + var->red.length + + var->blue.length); +} +EXPORT_SYMBOL(fb_get_color_depth); + +/* + * Drawing helpers. + */ +void fb_iomove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, + u32 height) +{ + int i; + + for (i = height; i--; ) { + buf->outbuf(info, dst, src, s_pitch); + src += s_pitch; + dst += d_pitch; + } +} + +void fb_sysmove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, + u32 height) +{ + int i, j; + + for (i = height; i--; ) { + for (j = 0; j < s_pitch; j++) + dst[j] = src[j]; + src += s_pitch; + dst += d_pitch; + } +} + +void fb_iomove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 idx, + u32 height, u32 shift_high, u32 shift_low, + u32 mod) +{ + u8 mask = (u8) (0xfff << shift_high), tmp; + int i, j; + + for (i = height; i--; ) { + for (j = 0; j < idx; j++) { + tmp = buf->inbuf(info, dst+j); + tmp &= mask; + tmp |= *src >> shift_low; + buf->outbuf(info, dst+j, &tmp, 1); + tmp = *src << shift_high; + buf->outbuf(info, dst+j+1, &tmp, 1); + src++; + } + tmp = buf->inbuf(info, dst+idx); + tmp &= mask; + tmp |= *src >> shift_low; + buf->outbuf(info, dst+idx, &tmp, 1); + if (shift_high < mod) { + tmp = *src << shift_high; + buf->outbuf(info, dst+idx+1, &tmp, 1); + } + src++; + dst += d_pitch; + } +} + +void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 idx, + u32 height, u32 shift_high, u32 shift_low, + u32 mod) +{ + u8 mask = (u8) (0xfff << shift_high), tmp; + int i, j; + + for (i = height; i--; ) { + for (j = 0; j < idx; j++) { + tmp = dst[j]; + tmp &= mask; + tmp |= *src >> shift_low; + dst[j] = tmp; + tmp = *src << shift_high; + dst[j+1] = tmp; + src++; + } + tmp = dst[idx]; + tmp &= mask; + tmp |= *src >> shift_low; + dst[idx] = tmp; + if (shift_high < mod) { + tmp = *src << shift_high; + dst[idx+1] = tmp; + } + src++; + dst += d_pitch; + } +} + +/* + * we need to lock this section since fb_cursor + * may use fb_imageblit() + */ +char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size) +{ + u32 align = buf->buf_align - 1, offset; + char *addr = buf->addr; + + /* If IO mapped, we need to sync before access, no sharing of + * the pixmap is done + */ + if (buf->flags & FB_PIXMAP_IO) { + if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) + info->fbops->fb_sync(info); + return addr; + } + + /* See if we fit in the remaining pixmap space */ + offset = buf->offset + align; + offset &= ~align; + if (offset + size > buf->size) { + /* We do not fit. In order to be able to re-use the buffer, + * we must ensure no asynchronous DMA'ing or whatever operation + * is in progress, we sync for that. + */ + if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) + info->fbops->fb_sync(info); + offset = 0; + } + buf->offset = offset + size; + addr += offset; + + return addr; +} + +#ifdef CONFIG_LOGO +#include <linux/linux_logo.h> + +static inline unsigned safe_shift(unsigned d, int n) +{ + return n < 0 ? d >> -n : d << n; +} + +static void fb_set_logocmap(struct fb_info *info, + const struct linux_logo *logo) +{ + struct fb_cmap palette_cmap; + u16 palette_green[16]; + u16 palette_blue[16]; + u16 palette_red[16]; + int i, j, n; + const unsigned char *clut = logo->clut; + + palette_cmap.start = 0; + palette_cmap.len = 16; + palette_cmap.red = palette_red; + palette_cmap.green = palette_green; + palette_cmap.blue = palette_blue; + palette_cmap.transp = NULL; + + for (i = 0; i < logo->clutsize; i += n) { + n = logo->clutsize - 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] = clut[0] << 8 | clut[0]; + palette_cmap.green[j] = clut[1] << 8 | clut[1]; + palette_cmap.blue[j] = clut[2] << 8 | clut[2]; + clut += 3; + } + fb_set_cmap(&palette_cmap, info); + } +} + +static void fb_set_logo_truepalette(struct fb_info *info, + const struct linux_logo *logo, + 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; + const unsigned char *clut = logo->clut; + + /* + * 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 < logo->clutsize; i++) { + palette[i+32] = (safe_shift((clut[0] & redmask), redshift) | + safe_shift((clut[1] & greenmask), greenshift) | + safe_shift((clut[2] & bluemask), blueshift)); + clut += 3; + } +} + +static void fb_set_logo_directpalette(struct fb_info *info, + const struct linux_logo *logo, + 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 < logo->clutsize; i++) + palette[i] = i << redshift | i << greenshift | i << blueshift; +} + +static void fb_set_logo(struct fb_info *info, + const struct linux_logo *logo, u8 *dst, + int depth) +{ + int i, j, k, fg = 1; + const u8 *src = logo->data; + u8 d, xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0; + + if (fb_get_color_depth(&info->var) == 3) + fg = 7; + + switch (depth) { + case 4: + for (i = 0; i < logo->height; i++) + for (j = 0; j < logo->width; src++) { + *dst++ = *src >> 4; + j++; + if (j < logo->width) { + *dst++ = *src & 0x0f; + j++; + } + } + break; + case 1: + for (i = 0; i < logo->height; i++) { + for (j = 0; j < logo->width; src++) { + d = *src ^ xor; + for (k = 7; k >= 0; k--) { + *dst++ = ((d >> k) & 1) ? fg : 0; + j++; + } + } + } + break; + } +} + +/* + * Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors), + * linux_logo_vga16 (16 colors) and linux_logo_mono (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_clut224: + * 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_vga16: + * 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 "depth" flag will be set to 4. + * + * Case 3 - linux_logo_mono: + * This is similar with Case 2. Each byte contains information for 8 pixels. + * We isolate each bit and expand each into a byte. The "depth" flag will + * be set to 1. + */ +static struct logo_data { + int depth; + int needs_directpalette; + int needs_truepalette; + int needs_cmapreset; + const struct linux_logo *logo; +} fb_logo; + +int fb_prepare_logo(struct fb_info *info) +{ + int depth = fb_get_color_depth(&info->var); + + memset(&fb_logo, 0, sizeof(struct logo_data)); + + if (info->flags & FBINFO_MISC_TILEBLITTING) + return 0; + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + depth = info->var.blue.length; + if (info->var.red.length < depth) + depth = info->var.red.length; + if (info->var.green.length < depth) + depth = info->var.green.length; + } + + if (depth >= 8) { + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + fb_logo.needs_truepalette = 1; + break; + case FB_VISUAL_DIRECTCOLOR: + fb_logo.needs_directpalette = 1; + fb_logo.needs_cmapreset = 1; + break; + case FB_VISUAL_PSEUDOCOLOR: + fb_logo.needs_cmapreset = 1; + break; + } + } + + /* Return if no suitable logo was found */ + fb_logo.logo = fb_find_logo(depth); + + if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) { + fb_logo.logo = NULL; + return 0; + } + /* What depth we asked for might be different from what we get */ + if (fb_logo.logo->type == LINUX_LOGO_CLUT224) + fb_logo.depth = 8; + else if (fb_logo.logo->type == LINUX_LOGO_VGA16) + fb_logo.depth = 4; + else + fb_logo.depth = 1; + return fb_logo.logo->height; +} + +int fb_show_logo(struct fb_info *info) +{ + u32 *palette = NULL, *saved_pseudo_palette = NULL; + unsigned char *logo_new = NULL; + struct fb_image image; + int x; + + /* Return if the frame buffer is not mapped or suspended */ + if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING) + return 0; + + image.depth = 8; + image.data = fb_logo.logo->data; + + if (fb_logo.needs_cmapreset) + fb_set_logocmap(info, fb_logo.logo); + + if (fb_logo.needs_truepalette || + fb_logo.needs_directpalette) { + palette = kmalloc(256 * 4, GFP_KERNEL); + if (palette == NULL) + return 0; + + if (fb_logo.needs_truepalette) + fb_set_logo_truepalette(info, fb_logo.logo, palette); + else + fb_set_logo_directpalette(info, fb_logo.logo, palette); + + saved_pseudo_palette = info->pseudo_palette; + info->pseudo_palette = palette; + } + + if (fb_logo.depth <= 4) { + logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height, + GFP_KERNEL); + if (logo_new == NULL) { + kfree(palette); + if (saved_pseudo_palette) + info->pseudo_palette = saved_pseudo_palette; + return 0; + } + image.data = logo_new; + fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth); + } + + image.width = fb_logo.logo->width; + image.height = fb_logo.logo->height; + image.dy = 0; + + for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) && + x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) { + image.dx = x; + info->fbops->fb_imageblit(info, &image); + } + + kfree(palette); + if (saved_pseudo_palette != NULL) + info->pseudo_palette = saved_pseudo_palette; + kfree(logo_new); + return fb_logo.logo->height; +} +#else +int fb_prepare_logo(struct fb_info *info) { return 0; } +int fb_show_logo(struct fb_info *info) { return 0; } +#endif /* CONFIG_LOGO */ + +static int fbmem_read_proc(char *buf, char **start, off_t offset, + int len, int *eof, void *private) +{ + struct fb_info **fi; + int clen; + + clen = 0; + for (fi = registered_fb; fi < ®istered_fb[FB_MAX] && len < 4000; fi++) + if (*fi) + clen += sprintf(buf + clen, "%d %s\n", + (*fi)->node, + (*fi)->fix.id); + *start = buf + offset; + if (clen > offset) + clen -= offset; + else + clen = 0; + return clen < len ? clen : len; +} + +static ssize_t +fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + struct inode *inode = file->f_dentry->d_inode; + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + u32 *buffer, *dst; + u32 __iomem *src; + int c, i, cnt = 0, err = 0; + unsigned long total_size; + + if (!info || ! info->screen_base) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + if (info->fbops->fb_read) + return info->fbops->fb_read(file, buf, count, ppos); + + total_size = info->screen_size; + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p >= total_size) + return 0; + if (count >= total_size) + count = total_size; + if (count + p > total_size) + count = total_size - p; + + cnt = 0; + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, + GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + src = (u32 __iomem *) (info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + while (count) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + dst = buffer; + for (i = c >> 2; i--; ) + *dst++ = fb_readl(src++); + if (c & 3) { + u8 *dst8 = (u8 *) dst; + u8 __iomem *src8 = (u8 __iomem *) src; + + for (i = c & 3; i--;) + *dst8++ = fb_readb(src8++); + + src = (u32 __iomem *) src8; + } + + if (copy_to_user(buf, buffer, c)) { + err = -EFAULT; + break; + } + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + + kfree(buffer); + return (err) ? err : cnt; +} + +static ssize_t +fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + struct inode *inode = file->f_dentry->d_inode; + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + u32 *buffer, *src; + u32 __iomem *dst; + int c, i, cnt = 0, err; + unsigned long total_size; + + if (!info || !info->screen_base) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + if (info->fbops->fb_write) + return info->fbops->fb_write(file, buf, count, ppos); + + total_size = info->screen_size; + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p > total_size) + return -ENOSPC; + if (count >= total_size) + count = total_size; + err = 0; + if (count + p > total_size) { + count = total_size - p; + err = -ENOSPC; + } + cnt = 0; + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, + GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + dst = (u32 __iomem *) (info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + while (count) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + src = buffer; + if (copy_from_user(src, buf, c)) { + err = -EFAULT; + break; + } + for (i = c >> 2; i--; ) + fb_writel(*src++, dst++); + if (c & 3) { + u8 *src8 = (u8 *) src; + u8 __iomem *dst8 = (u8 __iomem *) dst; + + for (i = c & 3; i--; ) + fb_writeb(*src8++, dst8++); + + dst = (u32 __iomem *) dst8; + } + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + kfree(buffer); + + return (err) ? err : cnt; +} + +#ifdef CONFIG_KMOD +static void try_to_load(int fb) +{ + request_module("fb%d", fb); +} +#endif /* CONFIG_KMOD */ + +int +fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) +{ + int xoffset = var->xoffset; + int yoffset = var->yoffset; + int err; + + 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 ((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) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; +} + +int +fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) +{ + int err; + + if (var->activate & FB_ACTIVATE_INV_MODE) { + struct fb_videomode mode1, mode2; + int ret = 0; + + fb_var_to_videomode(&mode1, var); + fb_var_to_videomode(&mode2, &info->var); + /* make sure we don't delete the videomode of current var */ + ret = fb_mode_is_equal(&mode1, &mode2); + + if (!ret) { + struct fb_event event; + + event.info = info; + event.data = &mode1; + ret = notifier_call_chain(&fb_notifier_list, + FB_EVENT_MODE_DELETE, &event); + } + + if (!ret) + fb_delete_videomode(&mode1, &info->modelist); + + return ret; + } + + if ((var->activate & FB_ACTIVATE_FORCE) || + memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { + if (!info->fbops->fb_check_var) { + *var = info->var; + return 0; + } + + if ((err = info->fbops->fb_check_var(var, info))) + return err; + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + struct fb_videomode mode; + int err = 0; + + info->var = *var; + if (info->fbops->fb_set_par) + info->fbops->fb_set_par(info); + + fb_pan_display(info, &info->var); + + fb_set_cmap(&info->cmap, info); + + fb_var_to_videomode(&mode, &info->var); + + if (info->modelist.prev && info->modelist.next && + !list_empty(&info->modelist)) + err = fb_add_videomode(&mode, &info->modelist); + + if (!err && info->flags & FBINFO_MISC_USEREVENT) { + struct fb_event event; + + info->flags &= ~FBINFO_MISC_USEREVENT; + event.info = info; + notifier_call_chain(&fb_notifier_list, + FB_EVENT_MODE_CHANGE, + &event); + } + } + } + return 0; +} + +int +fb_blank(struct fb_info *info, int blank) +{ + int ret = -EINVAL; + + if (blank > FB_BLANK_POWERDOWN) + blank = FB_BLANK_POWERDOWN; + + if (info->fbops->fb_blank) + ret = info->fbops->fb_blank(blank, info); + + if (!ret) { + struct fb_event event; + + event.info = info; + event.data = ␣ + notifier_call_chain(&fb_notifier_list, FB_EVENT_BLANK, &event); + } + + return ret; +} + +static int +fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + struct fb_ops *fb = info->fbops; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct fb_con2fbmap con2fb; + struct fb_cmap_user cmap; + struct fb_event event; + void __user *argp = (void __user *)arg; + int i; + + if (!fb) + return -ENODEV; + switch (cmd) { + case FBIOGET_VSCREENINFO: + return copy_to_user(argp, &info->var, + sizeof(var)) ? -EFAULT : 0; + case FBIOPUT_VSCREENINFO: + if (copy_from_user(&var, argp, sizeof(var))) + return -EFAULT; + acquire_console_sem(); + info->flags |= FBINFO_MISC_USEREVENT; + i = fb_set_var(info, &var); + info->flags &= ~FBINFO_MISC_USEREVENT; + release_console_sem(); + if (i) return i; + if (copy_to_user(argp, &var, sizeof(var))) + return -EFAULT; + return 0; + case FBIOGET_FSCREENINFO: + return copy_to_user(argp, &info->fix, + sizeof(fix)) ? -EFAULT : 0; + case FBIOPUTCMAP: + if (copy_from_user(&cmap, argp, sizeof(cmap))) + return -EFAULT; + return (fb_set_user_cmap(&cmap, info)); + case FBIOGETCMAP: + if (copy_from_user(&cmap, argp, sizeof(cmap))) + return -EFAULT; + return fb_cmap_to_user(&info->cmap, &cmap); + case FBIOPAN_DISPLAY: + if (copy_from_user(&var, argp, sizeof(var))) + return -EFAULT; + acquire_console_sem(); + i = fb_pan_display(info, &var); + release_console_sem(); + if (i) + return i; + if (copy_to_user(argp, &var, sizeof(var))) + return -EFAULT; + return 0; + case FBIO_CURSOR: + return -EINVAL; + case FBIOGET_CON2FBMAP: + if (copy_from_user(&con2fb, argp, sizeof(con2fb))) + return -EFAULT; + if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) + return -EINVAL; + con2fb.framebuffer = -1; + event.info = info; + event.data = &con2fb; + notifier_call_chain(&fb_notifier_list, + FB_EVENT_GET_CONSOLE_MAP, &event); + return copy_to_user(argp, &con2fb, + sizeof(con2fb)) ? -EFAULT : 0; + case FBIOPUT_CON2FBMAP: + if (copy_from_user(&con2fb, argp, sizeof(con2fb))) + return - EFAULT; + if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES) + return -EINVAL; + if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) + return -EINVAL; +#ifdef CONFIG_KMOD + if (!registered_fb[con2fb.framebuffer]) + try_to_load(con2fb.framebuffer); +#endif /* CONFIG_KMOD */ + if (!registered_fb[con2fb.framebuffer]) + return -EINVAL; + event.info = info; + event.data = &con2fb; + return notifier_call_chain(&fb_notifier_list, + FB_EVENT_SET_CONSOLE_MAP, + &event); + case FBIOBLANK: + acquire_console_sem(); + info->flags |= FBINFO_MISC_USEREVENT; + i = fb_blank(info, arg); + info->flags &= ~FBINFO_MISC_USEREVENT; + release_console_sem(); + return i; + default: + if (fb->fb_ioctl == NULL) + return -EINVAL; + return fb->fb_ioctl(inode, file, cmd, arg, info); + } +} + +#ifdef CONFIG_COMPAT +static long +fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int fbidx = iminor(file->f_dentry->d_inode); + struct fb_info *info = registered_fb[fbidx]; + struct fb_ops *fb = info->fbops; + long ret; + + if (fb->fb_compat_ioctl == NULL) + return -ENOIOCTLCMD; + lock_kernel(); + ret = fb->fb_compat_ioctl(file, cmd, arg, info); + unlock_kernel(); + return ret; +} +#endif + +static int +fb_mmap(struct file *file, struct vm_area_struct * vma) +{ + int fbidx = iminor(file->f_dentry->d_inode); + struct fb_info *info = registered_fb[fbidx]; + struct fb_ops *fb = info->fbops; + unsigned long off; +#if !defined(__sparc__) || defined(__sparc_v9__) + unsigned long start; + u32 len; +#endif + + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + off = vma->vm_pgoff << PAGE_SHIFT; + if (!fb) + return -ENODEV; + if (fb->fb_mmap) { + int res; + lock_kernel(); + res = fb->fb_mmap(info, file, vma); + unlock_kernel(); + return res; + } + +#if defined(__sparc__) && !defined(__sparc_v9__) + /* Should never get here, all fb drivers should have their own + mmap routines */ + return -EINVAL; +#else + /* !sparc32... */ + lock_kernel(); + + /* frame buffer memory */ + start = info->fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); + if (off >= len) { + /* memory mapped io */ + off -= len; + if (info->var.accel_flags) { + unlock_kernel(); + return -EINVAL; + } + start = info->fix.mmio_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); + } + unlock_kernel(); + start &= PAGE_MASK; + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + off += start; + vma->vm_pgoff = off >> PAGE_SHIFT; + /* This is an IO map - tell maydump to skip this VMA */ + vma->vm_flags |= VM_IO | VM_RESERVED; +#if defined(__sparc_v9__) + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; +#else +#if defined(__mc68000__) +#if defined(CONFIG_SUN3) + pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE; +#elif defined(CONFIG_MMU) + if (CPU_IS_020_OR_030) + pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030; + if (CPU_IS_040_OR_060) { + pgprot_val(vma->vm_page_prot) &= _CACHEMASK040; + /* Use no-cache mode, serialized */ + pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S; + } +#endif +#elif defined(__powerpc__) + vma->vm_page_prot = phys_mem_access_prot(file, off, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +#elif defined(__alpha__) + /* Caching is off in the I/O space quadrant by design. */ +#elif defined(__i386__) || defined(__x86_64__) + if (boot_cpu_data.x86 > 3) + pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; +#elif defined(__mips__) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +#elif defined(__hppa__) + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; +#elif defined(__arm__) || defined(__sh__) || defined(__m32r__) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +#elif defined(__ia64__) + if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +#else +#warning What do we have to do here?? +#endif + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; +#endif /* !__sparc_v9__ */ + return 0; +#endif /* !sparc32 */ +} + +static int +fb_open(struct inode *inode, struct file *file) +{ + int fbidx = iminor(inode); + struct fb_info *info; + int res = 0; + + if (fbidx >= FB_MAX) + return -ENODEV; +#ifdef CONFIG_KMOD + if (!(info = registered_fb[fbidx])) + try_to_load(fbidx); +#endif /* CONFIG_KMOD */ + if (!(info = registered_fb[fbidx])) + return -ENODEV; + if (!try_module_get(info->fbops->owner)) + return -ENODEV; + if (info->fbops->fb_open) { + res = info->fbops->fb_open(info,1); + if (res) + module_put(info->fbops->owner); + } + return res; +} + +static int +fb_release(struct inode *inode, struct file *file) +{ + int fbidx = iminor(inode); + struct fb_info *info; + + lock_kernel(); + info = registered_fb[fbidx]; + if (info->fbops->fb_release) + info->fbops->fb_release(info,1); + module_put(info->fbops->owner); + unlock_kernel(); + return 0; +} + +static struct file_operations fb_fops = { + .owner = THIS_MODULE, + .read = fb_read, + .write = fb_write, + .ioctl = fb_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = fb_compat_ioctl, +#endif + .mmap = fb_mmap, + .open = fb_open, + .release = fb_release, +#ifdef HAVE_ARCH_FB_UNMAPPED_AREA + .get_unmapped_area = get_fb_unmapped_area, +#endif +}; + +static struct class_simple *fb_class; + +/** + * register_framebuffer - registers a frame buffer device + * @fb_info: frame buffer info structure + * + * Registers a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + */ + +int +register_framebuffer(struct fb_info *fb_info) +{ + int i; + struct fb_event event; + + if (num_registered_fb == FB_MAX) + return -ENXIO; + num_registered_fb++; + for (i = 0 ; i < FB_MAX; i++) + if (!registered_fb[i]) + break; + fb_info->node = i; + + fb_info->class_device = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i), + fb_info->device, "fb%d", i); + if (IS_ERR(fb_info->class_device)) { + /* Not fatal */ + printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->class_device)); + fb_info->class_device = NULL; + } else + fb_init_class_device(fb_info); + + if (fb_info->pixmap.addr == NULL) { + fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL); + if (fb_info->pixmap.addr) { + fb_info->pixmap.size = FBPIXMAPSIZE; + fb_info->pixmap.buf_align = 1; + fb_info->pixmap.scan_align = 1; + fb_info->pixmap.access_align = 4; + fb_info->pixmap.flags = FB_PIXMAP_DEFAULT; + } + } + fb_info->pixmap.offset = 0; + + if (!fb_info->modelist.prev || + !fb_info->modelist.next || + list_empty(&fb_info->modelist)) { + struct fb_videomode mode; + + INIT_LIST_HEAD(&fb_info->modelist); + fb_var_to_videomode(&mode, &fb_info->var); + fb_add_videomode(&mode, &fb_info->modelist); + } + + registered_fb[i] = fb_info; + + devfs_mk_cdev(MKDEV(FB_MAJOR, i), + S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i); + event.info = fb_info; + notifier_call_chain(&fb_notifier_list, + FB_EVENT_FB_REGISTERED, &event); + return 0; +} + + +/** + * unregister_framebuffer - releases a frame buffer device + * @fb_info: frame buffer info structure + * + * Unregisters a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + */ + +int +unregister_framebuffer(struct fb_info *fb_info) +{ + int i; + + i = fb_info->node; + if (!registered_fb[i]) + return -EINVAL; + devfs_remove("fb/%d", i); + + if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) + kfree(fb_info->pixmap.addr); + fb_destroy_modelist(&fb_info->modelist); + registered_fb[i]=NULL; + num_registered_fb--; + fb_cleanup_class_device(fb_info); + class_simple_device_remove(MKDEV(FB_MAJOR, i)); + return 0; +} + +/** + * fb_register_client - register a client notifier + * @nb: notifier block to callback on events + */ +int fb_register_client(struct notifier_block *nb) +{ + return notifier_chain_register(&fb_notifier_list, nb); +} + +/** + * fb_unregister_client - unregister a client notifier + * @nb: notifier block to callback on events + */ +int fb_unregister_client(struct notifier_block *nb) +{ + return notifier_chain_unregister(&fb_notifier_list, nb); +} + +/** + * fb_set_suspend - low level driver signals suspend + * @info: framebuffer affected + * @state: 0 = resuming, !=0 = suspending + * + * This is meant to be used by low level drivers to + * signal suspend/resume to the core & clients. + * It must be called with the console semaphore held + */ +void fb_set_suspend(struct fb_info *info, int state) +{ + struct fb_event event; + + event.info = info; + if (state) { + notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, &event); + info->state = FBINFO_STATE_SUSPENDED; + } else { + info->state = FBINFO_STATE_RUNNING; + notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, &event); + } +} + +/** + * fbmem_init - init frame buffer subsystem + * + * Initialize the frame buffer subsystem. + * + * NOTE: This function is _only_ to be called by drivers/char/mem.c. + * + */ + +static int __init +fbmem_init(void) +{ + create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL); + + devfs_mk_dir("fb"); + if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) + printk("unable to get major %d for fb devs\n", FB_MAJOR); + + fb_class = class_simple_create(THIS_MODULE, "graphics"); + if (IS_ERR(fb_class)) { + printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class)); + fb_class = NULL; + } + return 0; +} + +#ifdef MODULE +module_init(fbmem_init); +static void __exit +fbmem_exit(void) +{ + class_simple_destroy(fb_class); +} + +module_exit(fbmem_exit); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Framebuffer base"); +#else +subsys_initcall(fbmem_init); +#endif + +int fb_new_modelist(struct fb_info *info) +{ + struct fb_event event; + struct fb_var_screeninfo var = info->var; + struct list_head *pos, *n; + struct fb_modelist *modelist; + struct fb_videomode *m, mode; + int err = 1; + + list_for_each_safe(pos, n, &info->modelist) { + modelist = list_entry(pos, struct fb_modelist, list); + m = &modelist->mode; + fb_videomode_to_var(&var, m); + var.activate = FB_ACTIVATE_TEST; + err = fb_set_var(info, &var); + fb_var_to_videomode(&mode, &var); + if (err || !fb_mode_is_equal(m, &mode)) { + list_del(pos); + kfree(pos); + } + } + + err = 1; + + if (!list_empty(&info->modelist)) { + event.info = info; + err = notifier_call_chain(&fb_notifier_list, + FB_EVENT_NEW_MODELIST, + &event); + } + + return err; +} + +static char *video_options[FB_MAX]; +static int ofonly; + +/** + * fb_get_options - get kernel boot parameters + * @name: framebuffer name as it would appear in + * the boot parameter line + * (video=<name>:<options>) + * @option: the option will be stored here + * + * NOTE: Needed to maintain backwards compatibility + */ +int fb_get_options(char *name, char **option) +{ + char *opt, *options = NULL; + int opt_len, retval = 0; + int name_len = strlen(name), i; + + if (name_len && ofonly && strncmp(name, "offb", 4)) + retval = 1; + + if (name_len && !retval) { + for (i = 0; i < FB_MAX; i++) { + if (video_options[i] == NULL) + continue; + opt_len = strlen(video_options[i]); + if (!opt_len) + continue; + opt = video_options[i]; + if (!strncmp(name, opt, name_len) && + opt[name_len] == ':') + options = opt + name_len + 1; + } + } + if (options && !strncmp(options, "off", 3)) + retval = 1; + + if (option) + *option = options; + + return retval; +} + + +extern const char *global_mode_option; + +/** + * video_setup - process command line options + * @options: string of options + * + * Process command line options for frame buffer subsystem. + * + * NOTE: This function is a __setup and __init function. + * It only stores the options. Drivers have to call + * fb_get_options() as necessary. + * + * Returns zero. + * + */ +int __init video_setup(char *options) +{ + int i, global = 0; + + if (!options || !*options) + global = 1; + + if (!global && !strncmp(options, "ofonly", 6)) { + ofonly = 1; + global = 1; + } + + if (!global && !strstr(options, "fb:")) { + global_mode_option = options; + global = 1; + } + + if (!global) { + for (i = 0; i < FB_MAX; i++) { + if (video_options[i] == NULL) { + video_options[i] = options; + break; + } + + } + } + + return 0; +} +__setup("video=", video_setup); + + /* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(register_framebuffer); +EXPORT_SYMBOL(unregister_framebuffer); +EXPORT_SYMBOL(num_registered_fb); +EXPORT_SYMBOL(registered_fb); +EXPORT_SYMBOL(fb_prepare_logo); +EXPORT_SYMBOL(fb_show_logo); +EXPORT_SYMBOL(fb_set_var); +EXPORT_SYMBOL(fb_blank); +EXPORT_SYMBOL(fb_pan_display); +EXPORT_SYMBOL(fb_get_buffer_offset); +EXPORT_SYMBOL(fb_iomove_buf_unaligned); +EXPORT_SYMBOL(fb_iomove_buf_aligned); +EXPORT_SYMBOL(fb_sysmove_buf_unaligned); +EXPORT_SYMBOL(fb_sysmove_buf_aligned); +EXPORT_SYMBOL(fb_set_suspend); +EXPORT_SYMBOL(fb_register_client); +EXPORT_SYMBOL(fb_unregister_client); +EXPORT_SYMBOL(fb_get_options); +EXPORT_SYMBOL(fb_new_modelist); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c new file mode 100644 index 000000000000..978def013587 --- /dev/null +++ b/drivers/video/fbmon.c @@ -0,0 +1,1258 @@ +/* + * linux/drivers/video/fbmon.c + * + * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net> + * + * Credits: + * + * The EDID Parser is a conglomeration from the following sources: + * + * 1. SciTech SNAP Graphics Architecture + * Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved. + * + * 2. XFree86 4.3.0, interpret_edid.c + * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> + * + * 3. John Fremlin <vii@users.sourceforge.net> and + * Ani Joshi <ajoshi@unixbox.com> + * + * Generalized Timing Formula is derived from: + * + * GTF Spreadsheet by Andy Morrish (1/5/97) + * available at http://www.vesa.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/tty.h> +#include <linux/fb.h> +#include <linux/module.h> +#ifdef CONFIG_PPC_OF +#include <linux/pci.h> +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#endif +#include <video/edid.h> +#include "edid.h" + +/* + * EDID parser + */ + +#undef DEBUG /* define this for verbose EDID parsing output */ + +#ifdef DEBUG +#define DPRINTK(fmt, args...) printk(fmt,## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#define FBMON_FIX_HEADER 1 +#define FBMON_FIX_INPUT 2 + +#ifdef CONFIG_FB_MODE_HELPERS +struct broken_edid { + u8 manufacturer[4]; + u32 model; + u32 fix; +}; + +static struct broken_edid brokendb[] = { + /* DEC FR-PCXAV-YZ */ + { + .manufacturer = "DEC", + .model = 0x073a, + .fix = FBMON_FIX_HEADER, + }, + /* ViewSonic PF775a */ + { + .manufacturer = "VSC", + .model = 0x5a44, + .fix = FBMON_FIX_INPUT, + }, +}; + +static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00 +}; + +static void copy_string(unsigned char *c, unsigned char *s) +{ + int i; + c = c + 5; + for (i = 0; (i < 13 && *c != 0x0A); i++) + *(s++) = *(c++); + *s = 0; + while (i-- && (*--s == 0x20)) *s = 0; +} + +static int check_edid(unsigned char *edid) +{ + unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4]; + unsigned char *b; + u32 model; + int i, fix = 0, ret = 0; + + manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@'; + manufacturer[1] = ((block[0] & 0x03) << 3) + + ((block[1] & 0xe0) >> 5) + '@'; + manufacturer[2] = (block[1] & 0x1f) + '@'; + manufacturer[3] = 0; + model = block[2] + (block[3] << 8); + + for (i = 0; i < ARRAY_SIZE(brokendb); i++) { + if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) && + brokendb[i].model == model) { + printk("fbmon: The EDID Block of " + "Manufacturer: %s Model: 0x%x is known to " + "be broken,\n", manufacturer, model); + fix = brokendb[i].fix; + break; + } + } + + switch (fix) { + case FBMON_FIX_HEADER: + for (i = 0; i < 8; i++) { + if (edid[i] != edid_v1_header[i]) + ret = fix; + } + break; + case FBMON_FIX_INPUT: + b = edid + EDID_STRUCT_DISPLAY; + /* Only if display is GTF capable will + the input type be reset to analog */ + if (b[4] & 0x01 && b[0] & 0x80) + ret = fix; + break; + } + + return ret; +} + +static void fix_edid(unsigned char *edid, int fix) +{ + unsigned char *b; + + switch (fix) { + case FBMON_FIX_HEADER: + printk("fbmon: trying a header reconstruct\n"); + memcpy(edid, edid_v1_header, 8); + break; + case FBMON_FIX_INPUT: + printk("fbmon: trying to fix input type\n"); + b = edid + EDID_STRUCT_DISPLAY; + b[0] &= ~0x80; + edid[127] += 0x80; + } +} + +static int edid_checksum(unsigned char *edid) +{ + unsigned char i, csum = 0, all_null = 0; + int err = 0, fix = check_edid(edid); + + if (fix) + fix_edid(edid, fix); + + for (i = 0; i < EDID_LENGTH; i++) { + csum += edid[i]; + all_null |= edid[i]; + } + + if (csum == 0x00 && all_null) { + /* checksum passed, everything's good */ + err = 1; + } + + return err; +} + +static int edid_check_header(unsigned char *edid) +{ + int i, err = 1, fix = check_edid(edid); + + if (fix) + fix_edid(edid, fix); + + for (i = 0; i < 8; i++) { + if (edid[i] != edid_v1_header[i]) + err = 0; + } + + return err; +} + +static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs) +{ + specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@'; + specs->manufacturer[1] = ((block[0] & 0x03) << 3) + + ((block[1] & 0xe0) >> 5) + '@'; + specs->manufacturer[2] = (block[1] & 0x1f) + '@'; + specs->manufacturer[3] = 0; + specs->model = block[2] + (block[3] << 8); + specs->serial = block[4] + (block[5] << 8) + + (block[6] << 16) + (block[7] << 24); + specs->year = block[9] + 1990; + specs->week = block[8]; + DPRINTK(" Manufacturer: %s\n", specs->manufacturer); + DPRINTK(" Model: %x\n", specs->model); + DPRINTK(" Serial#: %u\n", specs->serial); + DPRINTK(" Year: %u Week %u\n", specs->year, specs->week); +} + +static void get_dpms_capabilities(unsigned char flags, + struct fb_monspecs *specs) +{ + specs->dpms = 0; + if (flags & DPMS_ACTIVE_OFF) + specs->dpms |= FB_DPMS_ACTIVE_OFF; + if (flags & DPMS_SUSPEND) + specs->dpms |= FB_DPMS_SUSPEND; + if (flags & DPMS_STANDBY) + specs->dpms |= FB_DPMS_STANDBY; + DPRINTK(" DPMS: Active %s, Suspend %s, Standby %s\n", + (flags & DPMS_ACTIVE_OFF) ? "yes" : "no", + (flags & DPMS_SUSPEND) ? "yes" : "no", + (flags & DPMS_STANDBY) ? "yes" : "no"); +} + +static void get_chroma(unsigned char *block, struct fb_monspecs *specs) +{ + int tmp; + + DPRINTK(" Chroma\n"); + /* Chromaticity data */ + tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2); + tmp *= 1000; + tmp += 512; + specs->chroma.redx = tmp/1024; + DPRINTK(" RedX: 0.%03d ", specs->chroma.redx); + + tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2); + tmp *= 1000; + tmp += 512; + specs->chroma.redy = tmp/1024; + DPRINTK("RedY: 0.%03d\n", specs->chroma.redy); + + tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2); + tmp *= 1000; + tmp += 512; + specs->chroma.greenx = tmp/1024; + DPRINTK(" GreenX: 0.%03d ", specs->chroma.greenx); + + tmp = (block[5] & 3) | (block[0xa] << 2); + tmp *= 1000; + tmp += 512; + specs->chroma.greeny = tmp/1024; + DPRINTK("GreenY: 0.%03d\n", specs->chroma.greeny); + + tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2); + tmp *= 1000; + tmp += 512; + specs->chroma.bluex = tmp/1024; + DPRINTK(" BlueX: 0.%03d ", specs->chroma.bluex); + + tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2); + tmp *= 1000; + tmp += 512; + specs->chroma.bluey = tmp/1024; + DPRINTK("BlueY: 0.%03d\n", specs->chroma.bluey); + + tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2); + tmp *= 1000; + tmp += 512; + specs->chroma.whitex = tmp/1024; + DPRINTK(" WhiteX: 0.%03d ", specs->chroma.whitex); + + tmp = (block[6] & 3) | (block[0xe] << 2); + tmp *= 1000; + tmp += 512; + specs->chroma.whitey = tmp/1024; + DPRINTK("WhiteY: 0.%03d\n", specs->chroma.whitey); +} + +static int edid_is_serial_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && + (block[2] == 0x00) && (block[3] == 0xff) && + (block[4] == 0x00)) + return 1; + else + return 0; +} + +static int edid_is_ascii_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && + (block[2] == 0x00) && (block[3] == 0xfe) && + (block[4] == 0x00)) + return 1; + else + return 0; +} + +static int edid_is_limits_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && + (block[2] == 0x00) && (block[3] == 0xfd) && + (block[4] == 0x00)) + return 1; + else + return 0; +} + +static int edid_is_monitor_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && + (block[2] == 0x00) && (block[3] == 0xfc) && + (block[4] == 0x00)) + return 1; + else + return 0; +} + +static void calc_mode_timings(int xres, int yres, int refresh, struct fb_videomode *mode) +{ + struct fb_var_screeninfo var; + struct fb_info info; + + var.xres = xres; + var.yres = yres; + fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, + refresh, &var, &info); + mode->xres = xres; + mode->yres = yres; + mode->pixclock = var.pixclock; + mode->refresh = refresh; + mode->left_margin = var.left_margin; + mode->right_margin = var.right_margin; + mode->upper_margin = var.upper_margin; + mode->lower_margin = var.lower_margin; + mode->hsync_len = var.hsync_len; + mode->vsync_len = var.vsync_len; + mode->vmode = 0; + mode->sync = 0; +} + +static int get_est_timing(unsigned char *block, struct fb_videomode *mode) +{ + int num = 0; + unsigned char c; + + c = block[0]; + if (c&0x80) { + calc_mode_timings(720, 400, 70, &mode[num]); + mode[num++].flag = FB_MODE_IS_CALCULATED; + DPRINTK(" 720x400@70Hz\n"); + } + if (c&0x40) { + calc_mode_timings(720, 400, 88, &mode[num]); + mode[num++].flag = FB_MODE_IS_CALCULATED; + DPRINTK(" 720x400@88Hz\n"); + } + if (c&0x20) { + mode[num++] = vesa_modes[3]; + DPRINTK(" 640x480@60Hz\n"); + } + if (c&0x10) { + calc_mode_timings(640, 480, 67, &mode[num]); + mode[num++].flag = FB_MODE_IS_CALCULATED; + DPRINTK(" 640x480@67Hz\n"); + } + if (c&0x08) { + mode[num++] = vesa_modes[4]; + DPRINTK(" 640x480@72Hz\n"); + } + if (c&0x04) { + mode[num++] = vesa_modes[5]; + DPRINTK(" 640x480@75Hz\n"); + } + if (c&0x02) { + mode[num++] = vesa_modes[7]; + DPRINTK(" 800x600@56Hz\n"); + } + if (c&0x01) { + mode[num++] = vesa_modes[8]; + DPRINTK(" 800x600@60Hz\n"); + } + + c = block[1]; + if (c&0x80) { + mode[num++] = vesa_modes[9]; + DPRINTK(" 800x600@72Hz\n"); + } + if (c&0x40) { + mode[num++] = vesa_modes[10]; + DPRINTK(" 800x600@75Hz\n"); + } + if (c&0x20) { + calc_mode_timings(832, 624, 75, &mode[num]); + mode[num++].flag = FB_MODE_IS_CALCULATED; + DPRINTK(" 832x624@75Hz\n"); + } + if (c&0x10) { + mode[num++] = vesa_modes[12]; + DPRINTK(" 1024x768@87Hz Interlaced\n"); + } + if (c&0x08) { + mode[num++] = vesa_modes[13]; + DPRINTK(" 1024x768@60Hz\n"); + } + if (c&0x04) { + mode[num++] = vesa_modes[14]; + DPRINTK(" 1024x768@70Hz\n"); + } + if (c&0x02) { + mode[num++] = vesa_modes[15]; + DPRINTK(" 1024x768@75Hz\n"); + } + if (c&0x01) { + mode[num++] = vesa_modes[21]; + DPRINTK(" 1280x1024@75Hz\n"); + } + c = block[2]; + if (c&0x80) { + mode[num++] = vesa_modes[17]; + DPRINTK(" 1152x870@75Hz\n"); + } + DPRINTK(" Manufacturer's mask: %x\n",c&0x7F); + return num; +} + +static int get_std_timing(unsigned char *block, struct fb_videomode *mode) +{ + int xres, yres = 0, refresh, ratio, i; + + xres = (block[0] + 31) * 8; + if (xres <= 256) + return 0; + + ratio = (block[1] & 0xc0) >> 6; + switch (ratio) { + case 0: + yres = xres; + break; + case 1: + yres = (xres * 3)/4; + break; + case 2: + yres = (xres * 4)/5; + break; + case 3: + yres = (xres * 9)/16; + break; + } + refresh = (block[1] & 0x3f) + 60; + + DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh); + for (i = 0; i < VESA_MODEDB_SIZE; i++) { + if (vesa_modes[i].xres == xres && + vesa_modes[i].yres == yres && + vesa_modes[i].refresh == refresh) { + *mode = vesa_modes[i]; + mode->flag |= FB_MODE_IS_STANDARD; + return 1; + } + } + calc_mode_timings(xres, yres, refresh, mode); + return 1; +} + +static int get_dst_timing(unsigned char *block, + struct fb_videomode *mode) +{ + int j, num = 0; + + for (j = 0; j < 6; j++, block+= STD_TIMING_DESCRIPTION_SIZE) + num += get_std_timing(block, &mode[num]); + + return num; +} + +static void get_detailed_timing(unsigned char *block, + struct fb_videomode *mode) +{ + mode->xres = H_ACTIVE; + mode->yres = V_ACTIVE; + mode->pixclock = PIXEL_CLOCK; + mode->pixclock /= 1000; + mode->pixclock = KHZ2PICOS(mode->pixclock); + mode->right_margin = H_SYNC_OFFSET; + mode->left_margin = (H_ACTIVE + H_BLANKING) - + (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); + mode->upper_margin = V_BLANKING - V_SYNC_OFFSET - + V_SYNC_WIDTH; + mode->lower_margin = V_SYNC_OFFSET; + mode->hsync_len = H_SYNC_WIDTH; + mode->vsync_len = V_SYNC_WIDTH; + if (HSYNC_POSITIVE) + mode->sync |= FB_SYNC_HOR_HIGH_ACT; + if (VSYNC_POSITIVE) + mode->sync |= FB_SYNC_VERT_HIGH_ACT; + mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) * + (V_ACTIVE + V_BLANKING)); + mode->vmode = 0; + mode->flag = FB_MODE_IS_DETAILED; + + DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000); + DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET, + H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING); + DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET, + V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING); + DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-", + (VSYNC_POSITIVE) ? "+" : "-"); +} + +/** + * fb_create_modedb - create video mode database + * @edid: EDID data + * @dbsize: database size + * + * RETURNS: struct fb_videomode, @dbsize contains length of database + * + * DESCRIPTION: + * This function builds a mode database using the contents of the EDID + * data + */ +static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) +{ + struct fb_videomode *mode, *m; + unsigned char *block; + int num = 0, i; + + mode = kmalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); + if (mode == NULL) + return NULL; + memset(mode, 0, 50 * sizeof(struct fb_videomode)); + + if (edid == NULL || !edid_checksum(edid) || + !edid_check_header(edid)) { + kfree(mode); + return NULL; + } + + *dbsize = 0; + + DPRINTK(" Supported VESA Modes\n"); + block = edid + ESTABLISHED_TIMING_1; + num += get_est_timing(block, &mode[num]); + + DPRINTK(" Standard Timings\n"); + block = edid + STD_TIMING_DESCRIPTIONS_START; + for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) + num += get_std_timing(block, &mode[num]); + + DPRINTK(" Detailed Timings\n"); + block = edid + DETAILED_TIMING_DESCRIPTIONS_START; + for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { + int first = 1; + + if (block[0] == 0x00 && block[1] == 0x00) { + if (block[3] == 0xfa) { + num += get_dst_timing(block + 5, &mode[num]); + } + } else { + get_detailed_timing(block, &mode[num]); + if (first) { + mode[num].flag |= FB_MODE_IS_FIRST; + first = 0; + } + num++; + } + } + + /* Yikes, EDID data is totally useless */ + if (!num) { + kfree(mode); + return NULL; + } + + *dbsize = num; + m = kmalloc(num * sizeof(struct fb_videomode), GFP_KERNEL); + if (!m) + return mode; + memmove(m, mode, num * sizeof(struct fb_videomode)); + kfree(mode); + return m; +} + +/** + * fb_destroy_modedb - destroys mode database + * @modedb: mode database to destroy + * + * DESCRIPTION: + * Destroy mode database created by fb_create_modedb + */ +void fb_destroy_modedb(struct fb_videomode *modedb) +{ + kfree(modedb); +} + +static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) +{ + int i, retval = 1; + unsigned char *block; + + block = edid + DETAILED_TIMING_DESCRIPTIONS_START; + + DPRINTK(" Monitor Operating Limits: "); + for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { + if (edid_is_limits_block(block)) { + specs->hfmin = H_MIN_RATE * 1000; + specs->hfmax = H_MAX_RATE * 1000; + specs->vfmin = V_MIN_RATE; + specs->vfmax = V_MAX_RATE; + specs->dclkmax = MAX_PIXEL_CLOCK * 1000000; + specs->gtf = (GTF_SUPPORT) ? 1 : 0; + retval = 0; + DPRINTK("From EDID\n"); + break; + } + } + + /* estimate monitor limits based on modes supported */ + if (retval) { + struct fb_videomode *modes; + int num_modes, i, hz, hscan, pixclock; + + modes = fb_create_modedb(edid, &num_modes); + if (!modes) { + DPRINTK("None Available\n"); + return 1; + } + + retval = 0; + for (i = 0; i < num_modes; i++) { + hz = modes[i].refresh; + pixclock = PICOS2KHZ(modes[i].pixclock) * 1000; + hscan = (modes[i].yres * 105 * hz + 5000)/100; + + if (specs->dclkmax == 0 || specs->dclkmax < pixclock) + specs->dclkmax = pixclock; + if (specs->dclkmin == 0 || specs->dclkmin > pixclock) + specs->dclkmin = pixclock; + if (specs->hfmax == 0 || specs->hfmax < hscan) + specs->hfmax = hscan; + if (specs->hfmin == 0 || specs->hfmin > hscan) + specs->hfmin = hscan; + if (specs->vfmax == 0 || specs->vfmax < hz) + specs->vfmax = hz; + if (specs->vfmin == 0 || specs->vfmin > hz) + specs->vfmin = hz; + } + DPRINTK("Extrapolated\n"); + fb_destroy_modedb(modes); + } + DPRINTK(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n", + specs->hfmin/1000, specs->hfmax/1000, specs->vfmin, + specs->vfmax, specs->dclkmax/1000000); + return retval; +} + +static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs) +{ + unsigned char c, *block; + + block = edid + EDID_STRUCT_DISPLAY; + + fb_get_monitor_limits(edid, specs); + + c = block[0] & 0x80; + specs->input = 0; + if (c) { + specs->input |= FB_DISP_DDI; + DPRINTK(" Digital Display Input"); + } else { + DPRINTK(" Analog Display Input: Input Voltage - "); + switch ((block[0] & 0x60) >> 5) { + case 0: + DPRINTK("0.700V/0.300V"); + specs->input |= FB_DISP_ANA_700_300; + break; + case 1: + DPRINTK("0.714V/0.286V"); + specs->input |= FB_DISP_ANA_714_286; + break; + case 2: + DPRINTK("1.000V/0.400V"); + specs->input |= FB_DISP_ANA_1000_400; + break; + case 3: + DPRINTK("0.700V/0.000V"); + specs->input |= FB_DISP_ANA_700_000; + break; + } + } + DPRINTK("\n Sync: "); + c = block[0] & 0x10; + if (c) + DPRINTK(" Configurable signal level\n"); + c = block[0] & 0x0f; + specs->signal = 0; + if (c & 0x10) { + DPRINTK("Blank to Blank "); + specs->signal |= FB_SIGNAL_BLANK_BLANK; + } + if (c & 0x08) { + DPRINTK("Separate "); + specs->signal |= FB_SIGNAL_SEPARATE; + } + if (c & 0x04) { + DPRINTK("Composite "); + specs->signal |= FB_SIGNAL_COMPOSITE; + } + if (c & 0x02) { + DPRINTK("Sync on Green "); + specs->signal |= FB_SIGNAL_SYNC_ON_GREEN; + } + if (c & 0x01) { + DPRINTK("Serration on "); + specs->signal |= FB_SIGNAL_SERRATION_ON; + } + DPRINTK("\n"); + specs->max_x = block[1]; + specs->max_y = block[2]; + DPRINTK(" Max H-size in cm: "); + if (specs->max_x) + DPRINTK("%d\n", specs->max_x); + else + DPRINTK("variable\n"); + DPRINTK(" Max V-size in cm: "); + if (specs->max_y) + DPRINTK("%d\n", specs->max_y); + else + DPRINTK("variable\n"); + + c = block[3]; + specs->gamma = c+100; + DPRINTK(" Gamma: "); + DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100); + + get_dpms_capabilities(block[4], specs); + + switch ((block[4] & 0x18) >> 3) { + case 0: + DPRINTK(" Monochrome/Grayscale\n"); + specs->input |= FB_DISP_MONO; + break; + case 1: + DPRINTK(" RGB Color Display\n"); + specs->input |= FB_DISP_RGB; + break; + case 2: + DPRINTK(" Non-RGB Multicolor Display\n"); + specs->input |= FB_DISP_MULTI; + break; + default: + DPRINTK(" Unknown\n"); + specs->input |= FB_DISP_UNKNOWN; + break; + } + + get_chroma(block, specs); + + specs->misc = 0; + c = block[4] & 0x7; + if (c & 0x04) { + DPRINTK(" Default color format is primary\n"); + specs->misc |= FB_MISC_PRIM_COLOR; + } + if (c & 0x02) { + DPRINTK(" First DETAILED Timing is preferred\n"); + specs->misc |= FB_MISC_1ST_DETAIL; + } + if (c & 0x01) { + printk(" Display is GTF capable\n"); + specs->gtf = 1; + } +} + +static int edid_is_timing_block(unsigned char *block) +{ + if ((block[0] != 0x00) || (block[1] != 0x00) || + (block[2] != 0x00) || (block[4] != 0x00)) + return 1; + else + return 0; +} + +int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) +{ + int i; + unsigned char *block; + + if (edid == NULL || var == NULL) + return 1; + + if (!(edid_checksum(edid))) + return 1; + + if (!(edid_check_header(edid))) + return 1; + + block = edid + DETAILED_TIMING_DESCRIPTIONS_START; + + for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { + if (edid_is_timing_block(block)) { + 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; + return 0; + } + } + return 1; +} + +void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) +{ + unsigned char *block; + int i; + + if (edid == NULL) + return; + + if (!(edid_checksum(edid))) + return; + + if (!(edid_check_header(edid))) + return; + + memset(specs, 0, sizeof(struct fb_monspecs)); + + specs->version = edid[EDID_STRUCT_VERSION]; + specs->revision = edid[EDID_STRUCT_REVISION]; + + DPRINTK("========================================\n"); + DPRINTK("Display Information (EDID)\n"); + DPRINTK("========================================\n"); + DPRINTK(" EDID Version %d.%d\n", (int) specs->version, + (int) specs->revision); + + parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs); + + block = edid + DETAILED_TIMING_DESCRIPTIONS_START; + for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { + if (edid_is_serial_block(block)) { + copy_string(block, specs->serial_no); + DPRINTK(" Serial Number: %s\n", specs->serial_no); + } else if (edid_is_ascii_block(block)) { + copy_string(block, specs->ascii); + DPRINTK(" ASCII Block: %s\n", specs->ascii); + } else if (edid_is_monitor_block(block)) { + copy_string(block, specs->monitor); + DPRINTK(" Monitor Name: %s\n", specs->monitor); + } + } + + DPRINTK(" Display Characteristics:\n"); + get_monspecs(edid, specs); + + specs->modedb = fb_create_modedb(edid, &specs->modedb_len); + DPRINTK("========================================\n"); +} + +/* + * VESA Generalized Timing Formula (GTF) + */ + +#define FLYBACK 550 +#define V_FRONTPORCH 1 +#define H_OFFSET 40 +#define H_SCALEFACTOR 20 +#define H_BLANKSCALE 128 +#define H_GRADIENT 600 +#define C_VAL 30 +#define M_VAL 300 + +struct __fb_timings { + u32 dclk; + u32 hfreq; + u32 vfreq; + u32 hactive; + u32 vactive; + u32 hblank; + u32 vblank; + u32 htotal; + u32 vtotal; +}; + +/** + * fb_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 + */ +static u32 fb_get_vblank(u32 hfreq) +{ + u32 vblank; + + vblank = (hfreq * FLYBACK)/1000; + vblank = (vblank + 500)/1000; + return (vblank + V_FRONTPORCH); +} + +/** + * fb_get_hblank_by_freq - get horizontal blank time given hfreq + * @hfreq: horizontal freq + * @xres: horizontal resolution in pixels + * + * DESCRIPTION: + * + * xres * duty_cycle + * hblank = ------------------ + * 100 - duty_cycle + * + * duty cycle = 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 + * + */ +static u32 fb_get_hblank_by_hfreq(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); + return (hblank); +} + +/** + * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock + * @dclk: pixelclock in Hz + * @xres: horizontal resolution in pixels + * + * DESCRIPTION: + * + * xres * duty_cycle + * hblank = ------------------ + * 100 - duty_cycle + * + * duty cycle = percent of htotal assigned to inactive display + * duty cycle = C - (M * h_period) + * + * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100 + * ----------------------------------------------- + * 2 * M + * M = 300; + * C = 30; + + */ +static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres) +{ + u32 duty_cycle, h_period, hblank; + + dclk /= 1000; + h_period = 100 - C_VAL; + h_period *= h_period; + h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk); + h_period *=10000; + + h_period = int_sqrt(h_period); + h_period -= (100 - C_VAL) * 100; + h_period *= 1000; + h_period /= 2 * M_VAL; + + duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100; + hblank = (xres * duty_cycle)/(100000 - duty_cycle) + 8; + hblank &= ~15; + return (hblank); +} + +/** + * fb_get_hfreq - estimate hsync + * @vfreq: vertical refresh rate + * @yres: vertical resolution + * + * DESCRIPTION: + * + * (yres + front_port) * vfreq * 1000000 + * hfreq = ------------------------------------- + * (1000000 - (vfreq * FLYBACK) + * + */ + +static u32 fb_get_hfreq(u32 vfreq, u32 yres) +{ + u32 divisor, hfreq; + + divisor = (1000000 - (vfreq * FLYBACK))/1000; + hfreq = (yres + V_FRONTPORCH) * vfreq * 1000; + return (hfreq/divisor); +} + +static void fb_timings_vfreq(struct __fb_timings *timings) +{ + timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive); + timings->vblank = fb_get_vblank(timings->hfreq); + timings->vtotal = timings->vactive + timings->vblank; + timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, + timings->hactive); + timings->htotal = timings->hactive + timings->hblank; + timings->dclk = timings->htotal * timings->hfreq; +} + +static void fb_timings_hfreq(struct __fb_timings *timings) +{ + timings->vblank = fb_get_vblank(timings->hfreq); + timings->vtotal = timings->vactive + timings->vblank; + timings->vfreq = timings->hfreq/timings->vtotal; + timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, + timings->hactive); + timings->htotal = timings->hactive + timings->hblank; + timings->dclk = timings->htotal * timings->hfreq; +} + +static void fb_timings_dclk(struct __fb_timings *timings) +{ + timings->hblank = fb_get_hblank_by_dclk(timings->dclk, + timings->hactive); + timings->htotal = timings->hactive + timings->hblank; + timings->hfreq = timings->dclk/timings->htotal; + timings->vblank = fb_get_vblank(timings->hfreq); + timings->vtotal = timings->vactive + timings->vblank; + timings->vfreq = timings->hfreq/timings->vtotal; +} + +/* + * fb_get_mode - calculates video mode using VESA GTF + * @flags: if: 0 - maximize vertical refresh rate + * 1 - vrefresh-driven calculation; + * 2 - hscan-driven calculation; + * 3 - pixelclock-driven calculation; + * @val: depending on @flags, ignored, vrefresh, hsync or pixelclock + * @var: pointer to fb_var_screeninfo + * @info: pointer to fb_info + * + * DESCRIPTION: + * Calculates video mode based on monitor specs using VESA GTF. + * The GTF is best for VESA GTF compliant monitors but is + * specifically formulated to work for older monitors as well. + * + * If @flag==0, the function will attempt to maximize the + * refresh rate. Otherwise, it will calculate timings based on + * the flag and accompanying value. + * + * If FB_IGNOREMON bit is set in @flags, monitor specs will be + * ignored and @var will be filled with the calculated timings. + * + * All calculations are based on the VESA GTF Spreadsheet + * available at VESA's public ftp (http://www.vesa.org). + * + * NOTES: + * The timings generated by the GTF will be different from VESA + * DMT. It might be a good idea to keep a table of standard + * VESA modes as well. The GTF may also not work for some displays, + * such as, and especially, analog TV. + * + * REQUIRES: + * A valid info->monspecs, otherwise 'safe numbers' will be used. + */ +int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct __fb_timings timings; + u32 interlace = 1, dscan = 1; + u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax; + + /* + * If monspecs are invalid, use values that are enough + * for 640x480@60 + */ + if (!info->monspecs.hfmax || !info->monspecs.vfmax || + !info->monspecs.dclkmax || + info->monspecs.hfmax < info->monspecs.hfmin || + info->monspecs.vfmax < info->monspecs.vfmin || + info->monspecs.dclkmax < info->monspecs.dclkmin) { + hfmin = 29000; hfmax = 30000; + vfmin = 60; vfmax = 60; + dclkmin = 0; dclkmax = 25000000; + } else { + hfmin = info->monspecs.hfmin; + hfmax = info->monspecs.hfmax; + vfmin = info->monspecs.vfmin; + vfmax = info->monspecs.vfmax; + dclkmin = info->monspecs.dclkmin; + dclkmax = info->monspecs.dclkmax; + } + + memset(&timings, 0, sizeof(struct __fb_timings)); + timings.hactive = var->xres; + timings.vactive = var->yres; + if (var->vmode & FB_VMODE_INTERLACED) { + timings.vactive /= 2; + interlace = 2; + } + if (var->vmode & FB_VMODE_DOUBLE) { + timings.vactive *= 2; + dscan = 2; + } + + switch (flags & ~FB_IGNOREMON) { + case FB_MAXTIMINGS: /* maximize refresh rate */ + timings.hfreq = hfmax; + fb_timings_hfreq(&timings); + if (timings.vfreq > vfmax) { + timings.vfreq = vfmax; + fb_timings_vfreq(&timings); + } + if (timings.dclk > dclkmax) { + timings.dclk = dclkmax; + fb_timings_dclk(&timings); + } + break; + case FB_VSYNCTIMINGS: /* vrefresh driven */ + timings.vfreq = val; + fb_timings_vfreq(&timings); + break; + case FB_HSYNCTIMINGS: /* hsync driven */ + timings.hfreq = val; + fb_timings_hfreq(&timings); + break; + case FB_DCLKTIMINGS: /* pixelclock driven */ + timings.dclk = PICOS2KHZ(val) * 1000; + fb_timings_dclk(&timings); + break; + default: + return -EINVAL; + + } + + if (!(flags & FB_IGNOREMON) && + (timings.vfreq < vfmin || timings.vfreq > vfmax || + timings.hfreq < hfmin || timings.hfreq > hfmax || + timings.dclk < dclkmin || timings.dclk > dclkmax)) + return -EINVAL; + + var->pixclock = KHZ2PICOS(timings.dclk/1000); + var->hsync_len = (timings.htotal * 8)/100; + var->right_margin = (timings.hblank/2) - var->hsync_len; + var->left_margin = timings.hblank - var->right_margin - var->hsync_len; + + var->vsync_len = (3 * interlace)/dscan; + var->lower_margin = (1 * interlace)/dscan; + var->upper_margin = (timings.vblank * interlace)/dscan - + (var->vsync_len + var->lower_margin); + + return 0; +} +#else +int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) +{ + return 1; +} +void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) +{ + specs = NULL; +} +void fb_destroy_modedb(struct fb_videomode *modedb) +{ +} +int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, + struct fb_info *info) +{ + return -EINVAL; +} +#endif /* CONFIG_FB_MODE_HELPERS */ + +/* + * fb_validate_mode - validates var against monitor capabilities + * @var: pointer to fb_var_screeninfo + * @info: pointer to fb_info + * + * DESCRIPTION: + * Validates video mode against monitor capabilities specified in + * info->monspecs. + * + * REQUIRES: + * A valid info->monspecs. + */ +int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) +{ + u32 hfreq, vfreq, htotal, vtotal, pixclock; + u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax; + + /* + * If monspecs are invalid, use values that are enough + * for 640x480@60 + */ + if (!info->monspecs.hfmax || !info->monspecs.vfmax || + !info->monspecs.dclkmax || + info->monspecs.hfmax < info->monspecs.hfmin || + info->monspecs.vfmax < info->monspecs.vfmin || + info->monspecs.dclkmax < info->monspecs.dclkmin) { + hfmin = 29000; hfmax = 30000; + vfmin = 60; vfmax = 60; + dclkmin = 0; dclkmax = 25000000; + } else { + hfmin = info->monspecs.hfmin; + hfmax = info->monspecs.hfmax; + vfmin = info->monspecs.vfmin; + vfmax = info->monspecs.vfmax; + dclkmin = info->monspecs.dclkmin; + dclkmax = info->monspecs.dclkmax; + } + + if (!var->pixclock) + return -EINVAL; + pixclock = PICOS2KHZ(var->pixclock) * 1000; + + htotal = var->xres + var->right_margin + var->hsync_len + + var->left_margin; + vtotal = var->yres + var->lower_margin + var->vsync_len + + var->upper_margin; + + if (var->vmode & FB_VMODE_INTERLACED) + vtotal /= 2; + if (var->vmode & FB_VMODE_DOUBLE) + vtotal *= 2; + + hfreq = pixclock/htotal; + vfreq = hfreq/vtotal; + + return (vfreq < vfmin || vfreq > vfmax || + hfreq < hfmin || hfreq > hfmax || + pixclock < dclkmin || pixclock > dclkmax) ? + -EINVAL : 0; +} + +EXPORT_SYMBOL(fb_parse_edid); +EXPORT_SYMBOL(fb_edid_to_monspecs); + +EXPORT_SYMBOL(fb_get_mode); +EXPORT_SYMBOL(fb_validate_mode); +EXPORT_SYMBOL(fb_destroy_modedb); diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c new file mode 100644 index 000000000000..2bdda4010b81 --- /dev/null +++ b/drivers/video/fbsysfs.c @@ -0,0 +1,389 @@ +/* + * fbsysfs.c - framebuffer device class and attributes + * + * Copyright (c) 2004 James Simmons <jsimmons@infradead.org> + * + * This program is free software you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* + * Note: currently there's only stubs for framebuffer_alloc and + * framebuffer_release here. The reson for that is that until all drivers + * are converted to use it a sysfsification will open OOPSable races. + */ + +#include <linux/kernel.h> +#include <linux/fb.h> +#include <linux/console.h> + +/** + * framebuffer_alloc - creates a new frame buffer info structure + * + * @size: size of driver private data, can be zero + * @dev: pointer to the device for this fb, this can be NULL + * + * Creates a new frame buffer info structure. Also reserves @size bytes + * for driver private data (info->par). info->par (if any) will be + * aligned to sizeof(long). + * + * Returns the new structure, or NULL if an error occured. + * + */ +struct fb_info *framebuffer_alloc(size_t size, struct device *dev) +{ +#define BYTES_PER_LONG (BITS_PER_LONG/8) +#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG)) + int fb_info_size = sizeof(struct fb_info); + struct fb_info *info; + char *p; + + if (size) + fb_info_size += PADDING; + + p = kmalloc(fb_info_size + size, GFP_KERNEL); + if (!p) + return NULL; + memset(p, 0, fb_info_size + size); + info = (struct fb_info *) p; + + if (size) + info->par = p + fb_info_size; + + info->device = dev; + + return info; +#undef PADDING +#undef BYTES_PER_LONG +} +EXPORT_SYMBOL(framebuffer_alloc); + +/** + * framebuffer_release - marks the structure available for freeing + * + * @info: frame buffer info structure + * + * Drop the reference count of the class_device embedded in the + * framebuffer info structure. + * + */ +void framebuffer_release(struct fb_info *info) +{ + kfree(info); +} +EXPORT_SYMBOL(framebuffer_release); + +static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var) +{ + int err; + + var->activate |= FB_ACTIVATE_FORCE; + acquire_console_sem(); + fb_info->flags |= FBINFO_MISC_USEREVENT; + err = fb_set_var(fb_info, var); + fb_info->flags &= ~FBINFO_MISC_USEREVENT; + release_console_sem(); + if (err) + return err; + return 0; +} + +static int mode_string(char *buf, unsigned int offset, + const struct fb_videomode *mode) +{ + char m = 'U'; + if (mode->flag & FB_MODE_IS_DETAILED) + m = 'D'; + if (mode->flag & FB_MODE_IS_VESA) + m = 'V'; + if (mode->flag & FB_MODE_IS_STANDARD) + m = 'S'; + return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d-%d\n", m, mode->xres, mode->yres, mode->refresh); +} + +static ssize_t store_mode(struct class_device *class_device, const char * buf, + size_t count) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + char mstr[100]; + struct fb_var_screeninfo var; + struct fb_modelist *modelist; + struct fb_videomode *mode; + struct list_head *pos; + size_t i; + int err; + + memset(&var, 0, sizeof(var)); + + list_for_each(pos, &fb_info->modelist) { + modelist = list_entry(pos, struct fb_modelist, list); + mode = &modelist->mode; + i = mode_string(mstr, 0, mode); + if (strncmp(mstr, buf, max(count, i)) == 0) { + + var = fb_info->var; + fb_videomode_to_var(&var, mode); + if ((err = activate(fb_info, &var))) + return err; + fb_info->mode = mode; + return count; + } + } + return -EINVAL; +} + +static ssize_t show_mode(struct class_device *class_device, char *buf) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + + if (!fb_info->mode) + return 0; + + return mode_string(buf, 0, fb_info->mode); +} + +static ssize_t store_modes(struct class_device *class_device, const char * buf, + size_t count) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + LIST_HEAD(old_list); + int i = count / sizeof(struct fb_videomode); + + if (i * sizeof(struct fb_videomode) != count) + return -EINVAL; + + acquire_console_sem(); + list_splice(&fb_info->modelist, &old_list); + fb_videomode_to_modelist((struct fb_videomode *)buf, i, + &fb_info->modelist); + if (fb_new_modelist(fb_info)) { + fb_destroy_modelist(&fb_info->modelist); + list_splice(&old_list, &fb_info->modelist); + } else + fb_destroy_modelist(&old_list); + + release_console_sem(); + + return 0; +} + +static ssize_t show_modes(struct class_device *class_device, char *buf) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + unsigned int i; + struct list_head *pos; + struct fb_modelist *modelist; + const struct fb_videomode *mode; + + i = 0; + list_for_each(pos, &fb_info->modelist) { + modelist = list_entry(pos, struct fb_modelist, list); + mode = &modelist->mode; + i += mode_string(buf, i, mode); + } + return i; +} + +static ssize_t store_bpp(struct class_device *class_device, const char * buf, + size_t count) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + struct fb_var_screeninfo var; + char ** last = NULL; + int err; + + var = fb_info->var; + var.bits_per_pixel = simple_strtoul(buf, last, 0); + if ((err = activate(fb_info, &var))) + return err; + return count; +} + +static ssize_t show_bpp(struct class_device *class_device, char *buf) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel); +} + +static ssize_t store_virtual(struct class_device *class_device, + const char * buf, size_t count) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + struct fb_var_screeninfo var; + char *last = NULL; + int err; + + var = fb_info->var; + var.xres_virtual = simple_strtoul(buf, &last, 0); + last++; + if (last - buf >= count) + return -EINVAL; + var.yres_virtual = simple_strtoul(last, &last, 0); + printk(KERN_ERR "fb: xres %d yres %d\n", var.xres_virtual, + var.yres_virtual); + + if ((err = activate(fb_info, &var))) + return err; + return count; +} + +static ssize_t show_virtual(struct class_device *class_device, char *buf) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xres_virtual, + fb_info->var.xres_virtual); +} + +static ssize_t store_cmap(struct class_device *class_device, const char * buf, + size_t count) +{ +// struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device); + return 0; +} + +static ssize_t show_cmap(struct class_device *class_device, char *buf) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + unsigned int offset = 0, i; + + if (!fb_info->cmap.red || !fb_info->cmap.blue || + fb_info->cmap.green || fb_info->cmap.transp) + return -EINVAL; + + for (i = 0; i < fb_info->cmap.len; i++) { + offset += snprintf(buf, PAGE_SIZE - offset, + "%d,%d,%d,%d,%d\n", i + fb_info->cmap.start, + fb_info->cmap.red[i], fb_info->cmap.blue[i], + fb_info->cmap.green[i], + fb_info->cmap.transp[i]); + } + return offset; +} + +static ssize_t store_blank(struct class_device *class_device, const char * buf, + size_t count) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + char *last = NULL; + int err; + + acquire_console_sem(); + fb_info->flags |= FBINFO_MISC_USEREVENT; + err = fb_blank(fb_info, simple_strtoul(buf, &last, 0)); + fb_info->flags &= ~FBINFO_MISC_USEREVENT; + release_console_sem(); + if (err < 0) + return err; + return count; +} + +static ssize_t show_blank(struct class_device *class_device, char *buf) +{ +// struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device); + return 0; +} + +static ssize_t store_console(struct class_device *class_device, + const char * buf, size_t count) +{ +// struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device); + return 0; +} + +static ssize_t show_console(struct class_device *class_device, char *buf) +{ +// struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device); + return 0; +} + +static ssize_t store_cursor(struct class_device *class_device, + const char * buf, size_t count) +{ +// struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device); + return 0; +} + +static ssize_t show_cursor(struct class_device *class_device, char *buf) +{ +// struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device); + return 0; +} + +static ssize_t store_pan(struct class_device *class_device, const char * buf, + size_t count) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + struct fb_var_screeninfo var; + char *last = NULL; + int err; + + var = fb_info->var; + var.xoffset = simple_strtoul(buf, &last, 0); + last++; + if (last - buf >= count) + return -EINVAL; + var.yoffset = simple_strtoul(last, &last, 0); + + acquire_console_sem(); + err = fb_pan_display(fb_info, &var); + release_console_sem(); + + if (err < 0) + return err; + return count; +} + +static ssize_t show_pan(struct class_device *class_device, char *buf) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset, + fb_info->var.xoffset); +} + +struct class_device_attribute class_device_attrs[] = { + __ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp), + __ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank), + __ATTR(color_map, S_IRUGO|S_IWUSR, show_cmap, store_cmap), + __ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console), + __ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor), + __ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode), + __ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes), + __ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan), + __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual), +}; + +int fb_init_class_device(struct fb_info *fb_info) +{ + unsigned int i; + class_set_devdata(fb_info->class_device, fb_info); + + for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) + class_device_create_file(fb_info->class_device, + &class_device_attrs[i]); + return 0; +} + +void fb_cleanup_class_device(struct fb_info *fb_info) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) + class_device_remove_file(fb_info->class_device, + &class_device_attrs[i]); +} + + diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c new file mode 100644 index 000000000000..10cd05059fe9 --- /dev/null +++ b/drivers/video/ffb.c @@ -0,0 +1,1092 @@ +/* ffb.c: Creator/Elite3D frame buffer driver + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz) + * + * Driver layout based loosely on tgafb.c, see that file for credits. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <linux/mm.h> +#include <linux/timer.h> + +#include <asm/io.h> +#include <asm/upa.h> +#include <asm/oplib.h> +#include <asm/fbio.h> + +#include "sbuslib.h" + +/* + * Local functions. + */ + +static int ffb_setcolreg(unsigned, unsigned, unsigned, unsigned, + unsigned, struct fb_info *); +static int ffb_blank(int, struct fb_info *); +static void ffb_init_fix(struct fb_info *); + +static void ffb_imageblit(struct fb_info *, const struct fb_image *); +static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *); +static void ffb_copyarea(struct fb_info *, const struct fb_copyarea *); +static int ffb_sync(struct fb_info *); +static int ffb_mmap(struct fb_info *, struct file *, struct vm_area_struct *); +static int ffb_ioctl(struct inode *, struct file *, unsigned int, + unsigned long, struct fb_info *); +static int ffb_pan_display(struct fb_var_screeninfo *, struct fb_info *); + +/* + * Frame buffer operations + */ + +static struct fb_ops ffb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = ffb_setcolreg, + .fb_blank = ffb_blank, + .fb_pan_display = ffb_pan_display, + .fb_fillrect = ffb_fillrect, + .fb_copyarea = ffb_copyarea, + .fb_imageblit = ffb_imageblit, + .fb_sync = ffb_sync, + .fb_mmap = ffb_mmap, + .fb_ioctl = ffb_ioctl, + + /* XXX Use FFB hw cursor once fb cursor API is better understood... */ + .fb_cursor = soft_cursor, +}; + +/* Register layout and definitions */ +#define FFB_SFB8R_VOFF 0x00000000 +#define FFB_SFB8G_VOFF 0x00400000 +#define FFB_SFB8B_VOFF 0x00800000 +#define FFB_SFB8X_VOFF 0x00c00000 +#define FFB_SFB32_VOFF 0x01000000 +#define FFB_SFB64_VOFF 0x02000000 +#define FFB_FBC_REGS_VOFF 0x04000000 +#define FFB_BM_FBC_REGS_VOFF 0x04002000 +#define FFB_DFB8R_VOFF 0x04004000 +#define FFB_DFB8G_VOFF 0x04404000 +#define FFB_DFB8B_VOFF 0x04804000 +#define FFB_DFB8X_VOFF 0x04c04000 +#define FFB_DFB24_VOFF 0x05004000 +#define FFB_DFB32_VOFF 0x06004000 +#define FFB_DFB422A_VOFF 0x07004000 /* DFB 422 mode write to A */ +#define FFB_DFB422AD_VOFF 0x07804000 /* DFB 422 mode with line doubling */ +#define FFB_DFB24B_VOFF 0x08004000 /* DFB 24bit mode write to B */ +#define FFB_DFB422B_VOFF 0x09004000 /* DFB 422 mode write to B */ +#define FFB_DFB422BD_VOFF 0x09804000 /* DFB 422 mode with line doubling */ +#define FFB_SFB16Z_VOFF 0x0a004000 /* 16bit mode Z planes */ +#define FFB_SFB8Z_VOFF 0x0a404000 /* 8bit mode Z planes */ +#define FFB_SFB422_VOFF 0x0ac04000 /* SFB 422 mode write to A/B */ +#define FFB_SFB422D_VOFF 0x0b404000 /* SFB 422 mode with line doubling */ +#define FFB_FBC_KREGS_VOFF 0x0bc04000 +#define FFB_DAC_VOFF 0x0bc06000 +#define FFB_PROM_VOFF 0x0bc08000 +#define FFB_EXP_VOFF 0x0bc18000 + +#define FFB_SFB8R_POFF 0x04000000UL +#define FFB_SFB8G_POFF 0x04400000UL +#define FFB_SFB8B_POFF 0x04800000UL +#define FFB_SFB8X_POFF 0x04c00000UL +#define FFB_SFB32_POFF 0x05000000UL +#define FFB_SFB64_POFF 0x06000000UL +#define FFB_FBC_REGS_POFF 0x00600000UL +#define FFB_BM_FBC_REGS_POFF 0x00600000UL +#define FFB_DFB8R_POFF 0x01000000UL +#define FFB_DFB8G_POFF 0x01400000UL +#define FFB_DFB8B_POFF 0x01800000UL +#define FFB_DFB8X_POFF 0x01c00000UL +#define FFB_DFB24_POFF 0x02000000UL +#define FFB_DFB32_POFF 0x03000000UL +#define FFB_FBC_KREGS_POFF 0x00610000UL +#define FFB_DAC_POFF 0x00400000UL +#define FFB_PROM_POFF 0x00000000UL +#define FFB_EXP_POFF 0x00200000UL +#define FFB_DFB422A_POFF 0x09000000UL +#define FFB_DFB422AD_POFF 0x09800000UL +#define FFB_DFB24B_POFF 0x0a000000UL +#define FFB_DFB422B_POFF 0x0b000000UL +#define FFB_DFB422BD_POFF 0x0b800000UL +#define FFB_SFB16Z_POFF 0x0c800000UL +#define FFB_SFB8Z_POFF 0x0c000000UL +#define FFB_SFB422_POFF 0x0d000000UL +#define FFB_SFB422D_POFF 0x0d800000UL + +/* Draw operations */ +#define FFB_DRAWOP_DOT 0x00 +#define FFB_DRAWOP_AADOT 0x01 +#define FFB_DRAWOP_BRLINECAP 0x02 +#define FFB_DRAWOP_BRLINEOPEN 0x03 +#define FFB_DRAWOP_DDLINE 0x04 +#define FFB_DRAWOP_AALINE 0x05 +#define FFB_DRAWOP_TRIANGLE 0x06 +#define FFB_DRAWOP_POLYGON 0x07 +#define FFB_DRAWOP_RECTANGLE 0x08 +#define FFB_DRAWOP_FASTFILL 0x09 +#define FFB_DRAWOP_BCOPY 0x0a +#define FFB_DRAWOP_VSCROLL 0x0b + +/* Pixel processor control */ +/* Force WID */ +#define FFB_PPC_FW_DISABLE 0x800000 +#define FFB_PPC_FW_ENABLE 0xc00000 +/* Auxiliary clip */ +#define FFB_PPC_ACE_DISABLE 0x040000 +#define FFB_PPC_ACE_AUX_SUB 0x080000 +#define FFB_PPC_ACE_AUX_ADD 0x0c0000 +/* Depth cue */ +#define FFB_PPC_DCE_DISABLE 0x020000 +#define FFB_PPC_DCE_ENABLE 0x030000 +/* Alpha blend */ +#define FFB_PPC_ABE_DISABLE 0x008000 +#define FFB_PPC_ABE_ENABLE 0x00c000 +/* View clip */ +#define FFB_PPC_VCE_DISABLE 0x001000 +#define FFB_PPC_VCE_2D 0x002000 +#define FFB_PPC_VCE_3D 0x003000 +/* Area pattern */ +#define FFB_PPC_APE_DISABLE 0x000800 +#define FFB_PPC_APE_ENABLE 0x000c00 +/* Transparent background */ +#define FFB_PPC_TBE_OPAQUE 0x000200 +#define FFB_PPC_TBE_TRANSPARENT 0x000300 +/* Z source */ +#define FFB_PPC_ZS_VAR 0x000080 +#define FFB_PPC_ZS_CONST 0x0000c0 +/* Y source */ +#define FFB_PPC_YS_VAR 0x000020 +#define FFB_PPC_YS_CONST 0x000030 +/* X source */ +#define FFB_PPC_XS_WID 0x000004 +#define FFB_PPC_XS_VAR 0x000008 +#define FFB_PPC_XS_CONST 0x00000c +/* Color (BGR) source */ +#define FFB_PPC_CS_VAR 0x000002 +#define FFB_PPC_CS_CONST 0x000003 + +#define FFB_ROP_NEW 0x83 +#define FFB_ROP_OLD 0x85 +#define FFB_ROP_NEW_XOR_OLD 0x86 + +#define FFB_UCSR_FIFO_MASK 0x00000fff +#define FFB_UCSR_FB_BUSY 0x01000000 +#define FFB_UCSR_RP_BUSY 0x02000000 +#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY) +#define FFB_UCSR_READ_ERR 0x40000000 +#define FFB_UCSR_FIFO_OVFL 0x80000000 +#define FFB_UCSR_ALL_ERRORS (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL) + +struct ffb_fbc { + /* Next vertex registers */ + u32 xxx1[3]; + volatile u32 alpha; + volatile u32 red; + volatile u32 green; + volatile u32 blue; + volatile u32 depth; + volatile u32 y; + volatile u32 x; + u32 xxx2[2]; + volatile u32 ryf; + volatile u32 rxf; + u32 xxx3[2]; + + volatile u32 dmyf; + volatile u32 dmxf; + u32 xxx4[2]; + volatile u32 ebyi; + volatile u32 ebxi; + u32 xxx5[2]; + volatile u32 by; + volatile u32 bx; + u32 dy; + u32 dx; + volatile u32 bh; + volatile u32 bw; + u32 xxx6[2]; + + u32 xxx7[32]; + + /* Setup unit vertex state register */ + volatile u32 suvtx; + u32 xxx8[63]; + + /* Control registers */ + volatile u32 ppc; + volatile u32 wid; + volatile u32 fg; + volatile u32 bg; + volatile u32 consty; + volatile u32 constz; + volatile u32 xclip; + volatile u32 dcss; + volatile u32 vclipmin; + volatile u32 vclipmax; + volatile u32 vclipzmin; + volatile u32 vclipzmax; + volatile u32 dcsf; + volatile u32 dcsb; + volatile u32 dczf; + volatile u32 dczb; + + u32 xxx9; + volatile u32 blendc; + volatile u32 blendc1; + volatile u32 blendc2; + volatile u32 fbramitc; + volatile u32 fbc; + volatile u32 rop; + volatile u32 cmp; + volatile u32 matchab; + volatile u32 matchc; + volatile u32 magnab; + volatile u32 magnc; + volatile u32 fbcfg0; + volatile u32 fbcfg1; + volatile u32 fbcfg2; + volatile u32 fbcfg3; + + u32 ppcfg; + volatile u32 pick; + volatile u32 fillmode; + volatile u32 fbramwac; + volatile u32 pmask; + volatile u32 xpmask; + volatile u32 ypmask; + volatile u32 zpmask; + volatile u32 clip0min; + volatile u32 clip0max; + volatile u32 clip1min; + volatile u32 clip1max; + volatile u32 clip2min; + volatile u32 clip2max; + volatile u32 clip3min; + volatile u32 clip3max; + + /* New 3dRAM III support regs */ + volatile u32 rawblend2; + volatile u32 rawpreblend; + volatile u32 rawstencil; + volatile u32 rawstencilctl; + volatile u32 threedram1; + volatile u32 threedram2; + volatile u32 passin; + volatile u32 rawclrdepth; + volatile u32 rawpmask; + volatile u32 rawcsrc; + volatile u32 rawmatch; + volatile u32 rawmagn; + volatile u32 rawropblend; + volatile u32 rawcmp; + volatile u32 rawwac; + volatile u32 fbramid; + + volatile u32 drawop; + u32 xxx10[2]; + volatile u32 fontlpat; + u32 xxx11; + volatile u32 fontxy; + volatile u32 fontw; + volatile u32 fontinc; + volatile u32 font; + u32 xxx12[3]; + volatile u32 blend2; + volatile u32 preblend; + volatile u32 stencil; + volatile u32 stencilctl; + + u32 xxx13[4]; + volatile u32 dcss1; + volatile u32 dcss2; + volatile u32 dcss3; + volatile u32 widpmask; + volatile u32 dcs2; + volatile u32 dcs3; + volatile u32 dcs4; + u32 xxx14; + volatile u32 dcd2; + volatile u32 dcd3; + volatile u32 dcd4; + u32 xxx15; + + volatile u32 pattern[32]; + + u32 xxx16[256]; + + volatile u32 devid; + u32 xxx17[63]; + + volatile u32 ucsr; + u32 xxx18[31]; + + volatile u32 mer; +}; + +struct ffb_dac { + volatile u32 type; + volatile u32 value; + volatile u32 type2; + volatile u32 value2; +}; + +struct ffb_par { + spinlock_t lock; + struct ffb_fbc *fbc; + struct ffb_dac *dac; + + u32 flags; +#define FFB_FLAG_AFB 0x00000001 +#define FFB_FLAG_BLANKED 0x00000002 + + u32 fg_cache __attribute__((aligned (8))); + u32 bg_cache; + u32 rop_cache; + + int fifo_cache; + + unsigned long physbase; + unsigned long fbsize; + + char name[64]; + int prom_node; + int prom_parent_node; + int dac_rev; + int board_type; + struct list_head list; +}; + +static void FFBFifo(struct ffb_par *par, int n) +{ + struct ffb_fbc *fbc; + int cache = par->fifo_cache; + + if (cache - n < 0) { + fbc = par->fbc; + do { cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK) - 8; + } while (cache - n < 0); + } + par->fifo_cache = cache - n; +} + +static void FFBWait(struct ffb_par *par) +{ + struct ffb_fbc *fbc; + int limit = 10000; + + fbc = par->fbc; + do { + if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_BUSY) == 0) + break; + if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) { + upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr); + } + udelay(10); + } while(--limit > 0); +} + +static int ffb_sync(struct fb_info *p) +{ + struct ffb_par *par = (struct ffb_par *) p->par; + + FFBWait(par); + return 0; +} + +static __inline__ void ffb_rop(struct ffb_par *par, u32 rop) +{ + if (par->rop_cache != rop) { + FFBFifo(par, 1); + upa_writel(rop, &par->fbc->rop); + par->rop_cache = rop; + } +} + +static void ffb_switch_from_graph(struct ffb_par *par) +{ + struct ffb_fbc *fbc = par->fbc; + struct ffb_dac *dac = par->dac; + unsigned long flags; + + spin_lock_irqsave(&par->lock, flags); + FFBWait(par); + par->fifo_cache = 0; + FFBFifo(par, 7); + upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE| + FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST, + &fbc->ppc); + upa_writel(0x2000707f, &fbc->fbc); + upa_writel(par->rop_cache, &fbc->rop); + upa_writel(0xffffffff, &fbc->pmask); + upa_writel((1 << 16) | (0 << 0), &fbc->fontinc); + upa_writel(par->fg_cache, &fbc->fg); + upa_writel(par->bg_cache, &fbc->bg); + FFBWait(par); + + /* Disable cursor. */ + upa_writel(0x100, &dac->type2); + if (par->dac_rev <= 2) + upa_writel(0, &dac->value2); + else + upa_writel(3, &dac->value2); + + spin_unlock_irqrestore(&par->lock, flags); +} + +static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct ffb_par *par = (struct ffb_par *) info->par; + + /* We just use this to catch switches out of + * graphics mode. + */ + ffb_switch_from_graph(par); + + if (var->xoffset || var->yoffset || var->vmode) + return -EINVAL; + return 0; +} + +/** + * ffb_fillrect - REQUIRED function. Can use generic routines if + * non acclerated hardware and packed pixel based. + * Draws a rectangle on the screen. + * + * @info: frame buffer structure that represents a single frame buffer + * @rect: structure defining the rectagle and operation. + */ +static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct ffb_par *par = (struct ffb_par *) info->par; + struct ffb_fbc *fbc = par->fbc; + unsigned long flags; + u32 fg; + + if (rect->rop != ROP_COPY && rect->rop != ROP_XOR) + BUG(); + + fg = ((u32 *)info->pseudo_palette)[rect->color]; + + spin_lock_irqsave(&par->lock, flags); + + if (fg != par->fg_cache) { + FFBFifo(par, 1); + upa_writel(fg, &fbc->fg); + par->fg_cache = fg; + } + + ffb_rop(par, (rect->rop == ROP_COPY ? + FFB_ROP_NEW : + FFB_ROP_NEW_XOR_OLD)); + + FFBFifo(par, 5); + upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop); + upa_writel(rect->dy, &fbc->by); + upa_writel(rect->dx, &fbc->bx); + upa_writel(rect->height, &fbc->bh); + upa_writel(rect->width, &fbc->bw); + + spin_unlock_irqrestore(&par->lock, flags); +} + +/** + * ffb_copyarea - REQUIRED function. Can use generic routines if + * non acclerated hardware and packed pixel based. + * Copies on area of the screen to another area. + * + * @info: frame buffer structure that represents a single frame buffer + * @area: structure defining the source and destination. + */ + +static void +ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct ffb_par *par = (struct ffb_par *) info->par; + struct ffb_fbc *fbc = par->fbc; + unsigned long flags; + + if (area->dx != area->sx || + area->dy == area->sy) { + cfb_copyarea(info, area); + return; + } + + spin_lock_irqsave(&par->lock, flags); + + ffb_rop(par, FFB_ROP_OLD); + + FFBFifo(par, 7); + upa_writel(FFB_DRAWOP_VSCROLL, &fbc->drawop); + upa_writel(area->sy, &fbc->by); + upa_writel(area->sx, &fbc->bx); + upa_writel(area->dy, &fbc->dy); + upa_writel(area->dx, &fbc->dx); + upa_writel(area->height, &fbc->bh); + upa_writel(area->width, &fbc->bw); + + spin_unlock_irqrestore(&par->lock, flags); +} + +/** + * ffb_imageblit - REQUIRED function. Can use generic routines if + * non acclerated hardware and packed pixel based. + * Copies a image from system memory to the screen. + * + * @info: frame buffer structure that represents a single frame buffer + * @image: structure defining the image. + */ +static void ffb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct ffb_par *par = (struct ffb_par *) info->par; + struct ffb_fbc *fbc = par->fbc; + const u8 *data = image->data; + unsigned long flags; + u32 fg, bg, xy; + u64 fgbg; + int i, width, stride; + + if (image->depth > 1) { + cfb_imageblit(info, image); + return; + } + + fg = ((u32 *)info->pseudo_palette)[image->fg_color]; + bg = ((u32 *)info->pseudo_palette)[image->bg_color]; + fgbg = ((u64) fg << 32) | (u64) bg; + xy = (image->dy << 16) | image->dx; + width = image->width; + stride = ((width + 7) >> 3); + + spin_lock_irqsave(&par->lock, flags); + + if (fgbg != *(u64 *)&par->fg_cache) { + FFBFifo(par, 2); + upa_writeq(fgbg, &fbc->fg); + *(u64 *)&par->fg_cache = fgbg; + } + + if (width >= 32) { + FFBFifo(par, 1); + upa_writel(32, &fbc->fontw); + } + + while (width >= 32) { + const u8 *next_data = data + 4; + + FFBFifo(par, 1); + upa_writel(xy, &fbc->fontxy); + xy += (32 << 0); + + for (i = 0; i < image->height; i++) { + u32 val = (((u32)data[0] << 24) | + ((u32)data[1] << 16) | + ((u32)data[2] << 8) | + ((u32)data[3] << 0)); + FFBFifo(par, 1); + upa_writel(val, &fbc->font); + + data += stride; + } + + data = next_data; + width -= 32; + } + + if (width) { + FFBFifo(par, 2); + upa_writel(width, &fbc->fontw); + upa_writel(xy, &fbc->fontxy); + + for (i = 0; i < image->height; i++) { + u32 val = (((u32)data[0] << 24) | + ((u32)data[1] << 16) | + ((u32)data[2] << 8) | + ((u32)data[3] << 0)); + FFBFifo(par, 1); + upa_writel(val, &fbc->font); + + data += stride; + } + } + + spin_unlock_irqrestore(&par->lock, flags); +} + +static void ffb_fixup_var_rgb(struct fb_var_screeninfo *var) +{ + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; +} + +/** + * ffb_setcolreg - Optional function. Sets a color register. + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @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. + * @info: frame buffer info structure + */ +static int ffb_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + u32 value; + + if (regno >= 256) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + value = (blue << 16) | (green << 8) | red; + ((u32 *)info->pseudo_palette)[regno] = value; + + return 0; +} + +/** + * ffb_blank - Optional function. Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + */ +static int +ffb_blank(int blank, struct fb_info *info) +{ + struct ffb_par *par = (struct ffb_par *) info->par; + struct ffb_dac *dac = par->dac; + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&par->lock, flags); + + FFBWait(par); + + switch (blank) { + case FB_BLANK_UNBLANK: /* Unblanking */ + upa_writel(0x6000, &dac->type); + tmp = (upa_readl(&dac->value) | 0x1); + upa_writel(0x6000, &dac->type); + upa_writel(tmp, &dac->value); + par->flags &= ~FFB_FLAG_BLANKED; + break; + + case FB_BLANK_NORMAL: /* Normal blanking */ + case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ + case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ + case FB_BLANK_POWERDOWN: /* Poweroff */ + upa_writel(0x6000, &dac->type); + tmp = (upa_readl(&dac->value) & ~0x1); + upa_writel(0x6000, &dac->type); + upa_writel(tmp, &dac->value); + par->flags |= FFB_FLAG_BLANKED; + break; + } + + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +static struct sbus_mmap_map ffb_mmap_map[] = { + { + .voff = FFB_SFB8R_VOFF, + .poff = FFB_SFB8R_POFF, + .size = 0x0400000 + }, + { + .voff = FFB_SFB8G_VOFF, + .poff = FFB_SFB8G_POFF, + .size = 0x0400000 + }, + { + .voff = FFB_SFB8B_VOFF, + .poff = FFB_SFB8B_POFF, + .size = 0x0400000 + }, + { + .voff = FFB_SFB8X_VOFF, + .poff = FFB_SFB8X_POFF, + .size = 0x0400000 + }, + { + .voff = FFB_SFB32_VOFF, + .poff = FFB_SFB32_POFF, + .size = 0x1000000 + }, + { + .voff = FFB_SFB64_VOFF, + .poff = FFB_SFB64_POFF, + .size = 0x2000000 + }, + { + .voff = FFB_FBC_REGS_VOFF, + .poff = FFB_FBC_REGS_POFF, + .size = 0x0002000 + }, + { + .voff = FFB_BM_FBC_REGS_VOFF, + .poff = FFB_BM_FBC_REGS_POFF, + .size = 0x0002000 + }, + { + .voff = FFB_DFB8R_VOFF, + .poff = FFB_DFB8R_POFF, + .size = 0x0400000 + }, + { + .voff = FFB_DFB8G_VOFF, + .poff = FFB_DFB8G_POFF, + .size = 0x0400000 + }, + { + .voff = FFB_DFB8B_VOFF, + .poff = FFB_DFB8B_POFF, + .size = 0x0400000 + }, + { + .voff = FFB_DFB8X_VOFF, + .poff = FFB_DFB8X_POFF, + .size = 0x0400000 + }, + { + .voff = FFB_DFB24_VOFF, + .poff = FFB_DFB24_POFF, + .size = 0x1000000 + }, + { + .voff = FFB_DFB32_VOFF, + .poff = FFB_DFB32_POFF, + .size = 0x1000000 + }, + { + .voff = FFB_FBC_KREGS_VOFF, + .poff = FFB_FBC_KREGS_POFF, + .size = 0x0002000 + }, + { + .voff = FFB_DAC_VOFF, + .poff = FFB_DAC_POFF, + .size = 0x0002000 + }, + { + .voff = FFB_PROM_VOFF, + .poff = FFB_PROM_POFF, + .size = 0x0010000 + }, + { + .voff = FFB_EXP_VOFF, + .poff = FFB_EXP_POFF, + .size = 0x0002000 + }, + { + .voff = FFB_DFB422A_VOFF, + .poff = FFB_DFB422A_POFF, + .size = 0x0800000 + }, + { + .voff = FFB_DFB422AD_VOFF, + .poff = FFB_DFB422AD_POFF, + .size = 0x0800000 + }, + { + .voff = FFB_DFB24B_VOFF, + .poff = FFB_DFB24B_POFF, + .size = 0x1000000 + }, + { + .voff = FFB_DFB422B_VOFF, + .poff = FFB_DFB422B_POFF, + .size = 0x0800000 + }, + { + .voff = FFB_DFB422BD_VOFF, + .poff = FFB_DFB422BD_POFF, + .size = 0x0800000 + }, + { + .voff = FFB_SFB16Z_VOFF, + .poff = FFB_SFB16Z_POFF, + .size = 0x0800000 + }, + { + .voff = FFB_SFB8Z_VOFF, + .poff = FFB_SFB8Z_POFF, + .size = 0x0800000 + }, + { + .voff = FFB_SFB422_VOFF, + .poff = FFB_SFB422_POFF, + .size = 0x0800000 + }, + { + .voff = FFB_SFB422D_VOFF, + .poff = FFB_SFB422D_POFF, + .size = 0x0800000 + }, + { .size = 0 } +}; + +static int ffb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) +{ + struct ffb_par *par = (struct ffb_par *)info->par; + + return sbusfb_mmap_helper(ffb_mmap_map, + par->physbase, par->fbsize, + 0, vma); +} + +static int ffb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *info) +{ + struct ffb_par *par = (struct ffb_par *) info->par; + + return sbusfb_ioctl_helper(cmd, arg, info, + FBTYPE_CREATOR, 24, par->fbsize); +} + +/* + * Initialisation + */ + +static void +ffb_init_fix(struct fb_info *info) +{ + struct ffb_par *par = (struct ffb_par *)info->par; + const char *ffb_type_name; + + if (!(par->flags & FFB_FLAG_AFB)) { + if ((par->board_type & 0x7) == 0x3) + ffb_type_name = "Creator 3D"; + else + ffb_type_name = "Creator"; + } else + ffb_type_name = "Elite 3D"; + + strlcpy(info->fix.id, ffb_type_name, sizeof(info->fix.id)); + + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + + /* Framebuffer length is the same regardless of resolution. */ + info->fix.line_length = 8192; + + info->fix.accel = FB_ACCEL_SUN_CREATOR; +} + +static int ffb_apply_upa_parent_ranges(int parent, + struct linux_prom64_registers *regs) +{ + struct linux_prom64_ranges ranges[PROMREG_MAX]; + char name[128]; + int len, i; + + prom_getproperty(parent, "name", name, sizeof(name)); + if (strcmp(name, "upa") != 0) + return 0; + + len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges)); + if (len <= 0) + return 1; + + len /= sizeof(struct linux_prom64_ranges); + for (i = 0; i < len; i++) { + struct linux_prom64_ranges *rng = &ranges[i]; + u64 phys_addr = regs->phys_addr; + + if (phys_addr >= rng->ot_child_base && + phys_addr < (rng->ot_child_base + rng->or_size)) { + regs->phys_addr -= rng->ot_child_base; + regs->phys_addr += rng->ot_parent_base; + return 0; + } + } + + return 1; +} + +struct all_info { + struct fb_info info; + struct ffb_par par; + u32 pseudo_palette[256]; + struct list_head list; +}; +static LIST_HEAD(ffb_list); + +static void ffb_init_one(int node, int parent) +{ + struct linux_prom64_registers regs[2*PROMREG_MAX]; + struct ffb_fbc *fbc; + struct ffb_dac *dac; + struct all_info *all; + + if (prom_getproperty(node, "reg", (void *) regs, sizeof(regs)) <= 0) { + printk("ffb: Cannot get reg device node property.\n"); + return; + } + + if (ffb_apply_upa_parent_ranges(parent, ®s[0])) { + printk("ffb: Cannot apply parent ranges to regs.\n"); + return; + } + + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "ffb: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); + + INIT_LIST_HEAD(&all->list); + + spin_lock_init(&all->par.lock); + all->par.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF); + all->par.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF); + all->par.rop_cache = FFB_ROP_NEW; + all->par.physbase = regs[0].phys_addr; + all->par.prom_node = node; + all->par.prom_parent_node = parent; + + /* Don't mention copyarea, so SCROLL_REDRAW is always + * used. It is the fastest on this chip. + */ + all->info.flags = (FBINFO_DEFAULT | + /* FBINFO_HWACCEL_COPYAREA | */ + FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_IMAGEBLIT); + all->info.fbops = &ffb_ops; + all->info.screen_base = (char *) all->par.physbase + FFB_DFB24_POFF; + all->info.par = &all->par; + all->info.pseudo_palette = all->pseudo_palette; + + sbusfb_fill_var(&all->info.var, all->par.prom_node, 32); + all->par.fbsize = PAGE_ALIGN(all->info.var.xres * + all->info.var.yres * + 4); + ffb_fixup_var_rgb(&all->info.var); + + all->info.var.accel_flags = FB_ACCELF_TEXT; + + prom_getstring(node, "name", all->par.name, sizeof(all->par.name)); + if (!strcmp(all->par.name, "SUNW,afb")) + all->par.flags |= FFB_FLAG_AFB; + + all->par.board_type = prom_getintdefault(node, "board_type", 0); + + fbc = all->par.fbc; + if((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) + upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr); + + ffb_switch_from_graph(&all->par); + + dac = all->par.dac; + upa_writel(0x8000, &dac->type); + all->par.dac_rev = upa_readl(&dac->value) >> 0x1c; + + /* Elite3D has different DAC revision numbering, and no DAC revisions + * have the reversed meaning of cursor enable. + */ + if (all->par.flags & FFB_FLAG_AFB) + all->par.dac_rev = 10; + + /* Unblank it just to be sure. When there are multiple + * FFB/AFB cards in the system, or it is not the OBP + * chosen console, it will have video outputs off in + * the DAC. + */ + ffb_blank(0, &all->info); + + if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { + printk(KERN_ERR "ffb: Could not allocate color map.\n"); + kfree(all); + return; + } + + ffb_init_fix(&all->info); + + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "ffb: Could not register framebuffer.\n"); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + return; + } + + list_add(&all->list, &ffb_list); + + printk("ffb: %s at %016lx type %d DAC %d\n", + ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), + regs[0].phys_addr, all->par.board_type, all->par.dac_rev); +} + +static void ffb_scan_siblings(int root) +{ + int node, child; + + child = prom_getchild(root); + for (node = prom_searchsiblings(child, "SUNW,ffb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) + ffb_init_one(node, root); + for (node = prom_searchsiblings(child, "SUNW,afb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,afb")) + ffb_init_one(node, root); +} + +int __init ffb_init(void) +{ + int root; + + if (fb_get_options("ffb", NULL)) + return -ENODEV; + + ffb_scan_siblings(prom_root_node); + + root = prom_getchild(prom_root_node); + for (root = prom_searchsiblings(root, "upa"); root; + root = prom_searchsiblings(prom_getsibling(root), "upa")) + ffb_scan_siblings(root); + + return 0; +} + +void __exit ffb_exit(void) +{ + struct list_head *pos, *tmp; + + list_for_each_safe(pos, tmp, &ffb_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } +} + +int __init +ffb_setup(char *arg) +{ + /* No cmdline options yet... */ + return 0; +} + +module_init(ffb_init); + +#ifdef MODULE +module_exit(ffb_exit); +#endif + +MODULE_DESCRIPTION("framebuffer driver for Creator/Elite3D chipsets"); +MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c new file mode 100644 index 000000000000..a0763283d776 --- /dev/null +++ b/drivers/video/fm2fb.c @@ -0,0 +1,322 @@ +/* + * linux/drivers/video/fm2fb.c -- BSC FrameMaster II/Rainbow II frame buffer + * device + * + * Copyright (C) 1998 Steffen A. Mork (linux-dev@morknet.de) + * Copyright (C) 1999 Geert Uytterhoeven + * + * Written for 2.0.x by Steffen A. Mork + * Ported to 2.1.x by Geert Uytterhoeven + * Ported to new api by James Simmons + * + * 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/mm.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/zorro.h> +#include <asm/io.h> + +/* + * Some technical notes: + * + * The BSC FrameMaster II (or Rainbow II) is a simple very dumb + * frame buffer which allows to display 24 bit true color images. + * Each pixel is 32 bit width so it's very easy to maintain the + * frame buffer. One long word has the following layout: + * AARRGGBB which means: AA the alpha channel byte, RR the red + * channel, GG the green channel and BB the blue channel. + * + * The FrameMaster II supports the following video modes. + * - PAL/NTSC + * - interlaced/non interlaced + * - composite sync/sync/sync over green + * + * The resolution is to the following both ones: + * - 768x576 (PAL) + * - 768x480 (NTSC) + * + * This means that pixel access per line is fixed due to the + * fixed line width. In case of maximal resolution the frame + * buffer needs an amount of memory of 1.769.472 bytes which + * is near to 2 MByte (the allocated address space of Zorro2). + * The memory is channel interleaved. That means every channel + * owns four VRAMs. Unfortunatly most FrameMasters II are + * not assembled with memory for the alpha channel. In this + * case it could be possible to add the frame buffer into the + * normal memory pool. + * + * At relative address 0x1ffff8 of the frame buffers base address + * there exists a control register with the number of + * four control bits. They have the following meaning: + * bit value meaning + * + * 0 1 0=interlaced/1=non interlaced + * 1 2 0=video out disabled/1=video out enabled + * 2 4 0=normal mode as jumpered via JP8/1=complement mode + * 3 8 0=read onboard ROM/1 normal operation (required) + * + * As mentioned above there are several jumper. I think there + * is not very much information about the FrameMaster II in + * the world so I add these information for completeness. + * + * JP1 interlace selection (1-2 non interlaced/2-3 interlaced) + * JP2 wait state creation (leave as is!) + * JP3 wait state creation (leave as is!) + * JP4 modulate composite sync on green output (1-2 composite + * sync on green channel/2-3 normal composite sync) + * JP5 create test signal, shorting this jumper will create + * a white screen + * JP6 sync creation (1-2 composite sync/2-3 H-sync output) + * JP8 video mode (1-2 PAL/2-3 NTSC) + * + * With the following jumpering table you can connect the + * FrameMaster II to a normal TV via SCART connector: + * JP1: 2-3 + * JP4: 2-3 + * JP6: 2-3 + * JP8: 1-2 (means PAL for Europe) + * + * NOTE: + * There is no other possibility to change the video timings + * except the interlaced/non interlaced, sync control and the + * video mode PAL (50 Hz)/NTSC (60 Hz). Inside this + * FrameMaster II driver are assumed values to avoid anomalies + * to a future X server. Except the pixel clock is really + * constant at 30 MHz. + * + * 9 pin female video connector: + * + * 1 analog red 0.7 Vss + * 2 analog green 0.7 Vss + * 3 analog blue 0.7 Vss + * 4 H-sync TTL + * 5 V-sync TTL + * 6 ground + * 7 ground + * 8 ground + * 9 ground + * + * Some performance notes: + * The FrameMaster II was not designed to display a console + * this driver would do! It was designed to display still true + * color images. Imagine: When scroll up a text line there + * must copied ca. 1.7 MBytes to another place inside this + * frame buffer. This means 1.7 MByte read and 1.7 MByte write + * over the slow 16 bit wide Zorro2 bus! A scroll of one + * line needs 1 second so do not expect to much from this + * driver - he is at the limit! + * + */ + +/* + * definitions + */ + +#define FRAMEMASTER_SIZE 0x200000 +#define FRAMEMASTER_REG 0x1ffff8 + +#define FRAMEMASTER_NOLACE 1 +#define FRAMEMASTER_ENABLE 2 +#define FRAMEMASTER_COMPL 4 +#define FRAMEMASTER_ROM 8 + +static volatile unsigned char *fm2fb_reg; + +static struct fb_fix_screeninfo fb_fix __devinitdata = { + .smem_len = FRAMEMASTER_REG, + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .line_length = (768 << 2), + .mmio_len = (8), + .accel = FB_ACCEL_NONE, +}; + +static int fm2fb_mode __devinitdata = -1; + +#define FM2FB_MODE_PAL 0 +#define FM2FB_MODE_NTSC 1 + +static struct fb_var_screeninfo fb_var_modes[] __devinitdata = { + { + /* 768 x 576, 32 bpp (PAL) */ + 768, 576, 768, 576, 0, 0, 32, 0, + { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 8, 0 }, + 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCEL_NONE, + 33333, 10, 102, 10, 5, 80, 34, FB_SYNC_COMP_HIGH_ACT, 0 + }, { + /* 768 x 480, 32 bpp (NTSC - not supported yet */ + 768, 480, 768, 480, 0, 0, 32, 0, + { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 8, 0 }, + 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCEL_NONE, + 33333, 10, 102, 10, 5, 80, 34, FB_SYNC_COMP_HIGH_ACT, 0 + } +}; + + /* + * Interface used by the world + */ + +static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int fm2fb_blank(int blank, struct fb_info *info); + +static struct fb_ops fm2fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = fm2fb_setcolreg, + .fb_blank = fm2fb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + + /* + * Blank the display. + */ +static int fm2fb_blank(int blank, struct fb_info *info) +{ + unsigned char t = FRAMEMASTER_ROM; + + if (!blank) + t |= FRAMEMASTER_ENABLE | FRAMEMASTER_NOLACE; + fm2fb_reg[0] = t; + return 0; +} + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ +static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + if (regno > info->cmap.len) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + + ((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue; + return 0; +} + + /* + * Initialisation + */ + +static int __devinit fm2fb_probe(struct zorro_dev *z, + const struct zorro_device_id *id); + +static struct zorro_device_id fm2fb_devices[] __devinitdata = { + { ZORRO_PROD_BSC_FRAMEMASTER_II }, + { ZORRO_PROD_HELFRICH_RAINBOW_II }, + { 0 } +}; + +static struct zorro_driver fm2fb_driver = { + .name = "fm2fb", + .id_table = fm2fb_devices, + .probe = fm2fb_probe, +}; + +static int __devinit fm2fb_probe(struct zorro_dev *z, + const struct zorro_device_id *id) +{ + struct fb_info *info; + unsigned long *ptr; + int is_fm; + int x, y; + + is_fm = z->id == ZORRO_PROD_BSC_FRAMEMASTER_II; + + if (!zorro_request_device(z,"fm2fb")) + return -ENXIO; + + info = framebuffer_alloc(256 * sizeof(u32), &z->dev); + if (!info) { + zorro_release_device(z); + return -ENOMEM; + } + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + framebuffer_release(info); + zorro_release_device(z); + return -ENOMEM; + } + + /* assigning memory to kernel space */ + fb_fix.smem_start = zorro_resource_start(z); + info->screen_base = ioremap(fb_fix.smem_start, FRAMEMASTER_SIZE); + fb_fix.mmio_start = fb_fix.smem_start + FRAMEMASTER_REG; + fm2fb_reg = (unsigned char *)(info->screen_base+FRAMEMASTER_REG); + + strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II"); + + /* make EBU color bars on display */ + ptr = (unsigned long *)fb_fix.smem_start; + for (y = 0; y < 576; y++) { + for (x = 0; x < 96; x++) *ptr++ = 0xffffff;/* white */ + for (x = 0; x < 96; x++) *ptr++ = 0xffff00;/* yellow */ + for (x = 0; x < 96; x++) *ptr++ = 0x00ffff;/* cyan */ + for (x = 0; x < 96; x++) *ptr++ = 0x00ff00;/* green */ + for (x = 0; x < 96; x++) *ptr++ = 0xff00ff;/* magenta */ + for (x = 0; x < 96; x++) *ptr++ = 0xff0000;/* red */ + for (x = 0; x < 96; x++) *ptr++ = 0x0000ff;/* blue */ + for (x = 0; x < 96; x++) *ptr++ = 0x000000;/* black */ + } + fm2fb_blank(0, info); + + if (fm2fb_mode == -1) + fm2fb_mode = FM2FB_MODE_PAL; + + info->fbops = &fm2fb_ops; + info->var = fb_var_modes[fm2fb_mode]; + info->pseudo_palette = info->par; + info->par = NULL; + info->fix = fb_fix; + info->flags = FBINFO_DEFAULT; + + if (register_framebuffer(info) < 0) { + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + zorro_release_device(z); + return -EINVAL; + } + printk("fb%d: %s frame buffer device\n", info->node, fb_fix.id); + return 0; +} + +int __init fm2fb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "pal", 3)) + fm2fb_mode = FM2FB_MODE_PAL; + else if (!strncmp(this_opt, "ntsc", 4)) + fm2fb_mode = FM2FB_MODE_NTSC; + } + return 0; +} + +int __init fm2fb_init(void) +{ + char *option = NULL; + + if (fb_get_options("fm2fb", &option)) + return -ENODEV; + fm2fb_setup(option); + return zorro_register_driver(&fm2fb_driver); +} + +module_init(fm2fb_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/g364fb.c b/drivers/video/g364fb.c new file mode 100644 index 000000000000..605d1a132020 --- /dev/null +++ b/drivers/video/g364fb.c @@ -0,0 +1,258 @@ +/* $Id: g364fb.c,v 1.3 1998/08/28 22:43:00 tsbogend Exp $ + * + * linux/drivers/video/g364fb.c -- Mips Magnum frame buffer device + * + * (C) 1998 Thomas Bogendoerfer + * + * This driver is based on tgafb.c + * + * Copyright (C) 1997 Geert Uytterhoeven + * Copyright (C) 1995 Jay Estabrook + * + * 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/console.h> +#include <linux/sched.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <asm/io.h> +#include <asm/jazz.h> + +/* + * Various defines for the G364 + */ +#define G364_MEM_BASE 0xe4400000 +#define G364_PORT_BASE 0xe4000000 +#define ID_REG 0xe4000000 /* Read only */ +#define BOOT_REG 0xe4080000 +#define TIMING_REG 0xe4080108 /* to 0x080170 - DON'T TOUCH! */ +#define DISPLAY_REG 0xe4080118 +#define VDISPLAY_REG 0xe4080150 +#define MASK_REG 0xe4080200 +#define CTLA_REG 0xe4080300 +#define CURS_TOGGLE 0x800000 +#define BIT_PER_PIX 0x700000 /* bits 22 to 20 of Control A */ +#define DELAY_SAMPLE 0x080000 +#define PORT_INTER 0x040000 +#define PIX_PIPE_DEL 0x030000 /* bits 17 and 16 of Control A */ +#define PIX_PIPE_DEL2 0x008000 /* same as above - don't ask me why */ +#define TR_CYCLE_TOG 0x004000 +#define VRAM_ADR_INC 0x003000 /* bits 13 and 12 of Control A */ +#define BLANK_OFF 0x000800 +#define FORCE_BLANK 0x000400 +#define BLK_FUN_SWTCH 0x000200 +#define BLANK_IO 0x000100 +#define BLANK_LEVEL 0x000080 +#define A_VID_FORM 0x000040 +#define D_SYNC_FORM 0x000020 +#define FRAME_FLY_PAT 0x000010 +#define OP_MODE 0x000008 +#define INTL_STAND 0x000004 +#define SCRN_FORM 0x000002 +#define ENABLE_VTG 0x000001 +#define TOP_REG 0xe4080400 +#define CURS_PAL_REG 0xe4080508 /* to 0x080518 */ +#define CHKSUM_REG 0xe4080600 /* to 0x080610 - unused */ +#define CURS_POS_REG 0xe4080638 +#define CLR_PAL_REG 0xe4080800 /* to 0x080ff8 */ +#define CURS_PAT_REG 0xe4081000 /* to 0x081ff8 */ +#define MON_ID_REG 0xe4100000 /* unused */ +#define RESET_REG 0xe4180000 /* Write only */ + +static struct fb_info fb_info; + +static struct fb_fix_screeninfo fb_fix __initdata = { + .id = "G364 8plane", + .smem_start = 0x40000000, /* physical address */ + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .ypanstep = 1, + .accel = FB_ACCEL_NONE, +}; + +static struct fb_var_screeninfo fb_var __initdata = { + .bits_per_pixel = 8, + .red = { 0, 8, 0 }, + .green = { 0, 8, 0 }, + .blue = { 0, 8, 0 }, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .pixclock = 39722, + .left_margin = 40, + .right_margin = 24, + .upper_margin = 32, + .lower_margin = 11, + .hsync_len = 96, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED, +}; + +/* + * Interface used by the world + */ +int g364fb_init(void); + +static int g364fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +static int g364fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info); +static int g364fb_cursor(struct fb_info *info, struct fb_cursor *cursor); +static int g364fb_blank(int blank, struct fb_info *info); + +static struct fb_ops g364fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = g364fb_setcolreg, + .fb_pan_display = g364fb_pan_display, + .fb_blank = g364fb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = g364fb_cursor, +}; + +int g364fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + + switch (cursor->enable) { + case CM_ERASE: + *(unsigned int *) CTLA_REG |= CURS_TOGGLE; + break; + + case CM_MOVE: + case CM_DRAW: + *(unsigned int *) CTLA_REG &= ~CURS_TOGGLE; + *(unsigned int *) CURS_POS_REG = + ((x * fontwidth(p)) << 12) | ((y * fontheight(p)) - + info->var.yoffset); + break; + } + return 0; +} + +/* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ +static int g364fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if (var->xoffset || var->yoffset + var->yres > var->yres_virtual) + return -EINVAL; + + *(unsigned int *) TOP_REG = var->yoffset * var->xres; + return 0; +} + +/* + * Blank the display. + */ +static int g364fb_blank(int blank, struct fb_info *info) +{ + if (blank) + *(unsigned int *) CTLA_REG |= FORCE_BLANK; + else + *(unsigned int *) CTLA_REG &= ~FORCE_BLANK; + return 0; +} + +/* + * Set a single color register. Return != 0 for invalid regno. + */ +static int g364fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, struct fb_info *info) +{ + volatile unsigned int *ptr = (volatile unsigned int *) CLR_PAL_REG; + + if (regno > 255) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + ptr[regno << 1] = (red << 16) | (green << 8) | blue; + + return 0; +} + +/* + * Initialisation + */ +int __init g364fb_init(void) +{ + volatile unsigned int *pal_ptr = + (volatile unsigned int *) CLR_PAL_REG; + volatile unsigned int *curs_pal_ptr = + (volatile unsigned int *) CURS_PAL_REG; + int mem, i, j; + + if (fb_get_options("g364fb", NULL)) + return -ENODEV; + + /* TBD: G364 detection */ + + /* get the resolution set by ARC console */ + *(volatile unsigned int *) CTLA_REG &= ~ENABLE_VTG; + fb_var.xres = + (*((volatile unsigned int *) DISPLAY_REG) & 0x00ffffff) * 4; + fb_var.yres = + (*((volatile unsigned int *) VDISPLAY_REG) & 0x00ffffff) / 2; + *(volatile unsigned int *) CTLA_REG |= ENABLE_VTG; + + /* setup cursor */ + curs_pal_ptr[0] |= 0x00ffffff; + curs_pal_ptr[2] |= 0x00ffffff; + curs_pal_ptr[4] |= 0x00ffffff; + + /* + * first set the whole cursor to transparent + */ + for (i = 0; i < 512; i++) + *(unsigned short *) (CURS_PAT_REG + i * 8) = 0; + + /* + * switch the last two lines to cursor palette 3 + * we assume here, that FONTSIZE_X is 8 + */ + *(unsigned short *) (CURS_PAT_REG + 14 * 64) = 0xffff; + *(unsigned short *) (CURS_PAT_REG + 15 * 64) = 0xffff; + fb_var.xres_virtual = fbvar.xres; + fb_fix.line_length = (xres / 8) * fb_var.bits_per_pixel; + fb_fix.smem_start = 0x40000000; /* physical address */ + /* get size of video memory; this is special for the JAZZ hardware */ + mem = (r4030_read_reg32(JAZZ_R4030_CONFIG) >> 8) & 3; + fb_fix.smem_len = (1 << (mem * 2)) * 512 * 1024; + fb_var.yres_virtual = fb_fix.smem_len / fb_var.xres; + + fb_info.fbops = &g364fb_ops; + fb_info.screen_base = (char *) G364_MEM_BASE; /* virtual kernel address */ + fb_info.var = fb_var; + fb_info.fix = fb_fix; + fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + + fb_alloc_cmap(&fb_info.cmap, 255, 0); + + if (register_framebuffer(&fb_info) < 0) + return -EINVAL; + return 0; +} + +module_init(g364fb_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c new file mode 100644 index 000000000000..2a023282d7a3 --- /dev/null +++ b/drivers/video/gbefb.c @@ -0,0 +1,1280 @@ +/* + * SGI GBE frame buffer driver + * + * Copyright (C) 1999 Silicon Graphics, Inc. - Jeffrey Newquist + * Copyright (C) 2002 Vivien Chappelier <vivien.chappelier@linux-mips.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/config.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> + +#ifdef CONFIG_X86 +#include <asm/mtrr.h> +#endif +#ifdef CONFIG_MIPS +#include <asm/addrspace.h> +#endif +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/tlbflush.h> + +#include <video/gbe.h> + +static struct sgi_gbe *gbe; + +struct gbefb_par { + struct fb_var_screeninfo var; + struct gbe_timing_info timing; + int valid; +}; + +#ifdef CONFIG_SGI_IP32 +#define GBE_BASE 0x16000000 /* SGI O2 */ +#endif + +#ifdef CONFIG_X86_VISWS +#define GBE_BASE 0xd0000000 /* SGI Visual Workstation */ +#endif + +/* macro for fastest write-though access to the framebuffer */ +#ifdef CONFIG_MIPS +#ifdef CONFIG_CPU_R10000 +#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED_ACCELERATED) +#else +#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA) +#endif +#endif +#ifdef CONFIG_X86 +#define pgprot_fb(_prot) ((_prot) | _PAGE_PCD) +#endif + +/* + * RAM we reserve for the frame buffer. This defines the maximum screen + * size + */ +#if CONFIG_FB_GBE_MEM > 8 +#error GBE Framebuffer cannot use more than 8MB of memory +#endif + +#define TILE_SHIFT 16 +#define TILE_SIZE (1 << TILE_SHIFT) +#define TILE_MASK (TILE_SIZE - 1) + +static unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024; +static void *gbe_mem; +static dma_addr_t gbe_dma_addr; +unsigned long gbe_mem_phys; + +static struct { + uint16_t *cpu; + dma_addr_t dma; +} gbe_tiles; + +static int gbe_revision; + +static int ypan, ywrap; + +static uint32_t pseudo_palette[256]; + +static char *mode_option __initdata = NULL; + +/* default CRT mode */ +static struct fb_var_screeninfo default_var_CRT __initdata = { + /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ + .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 = 39722, /* picoseconds */ + .left_margin = 48, + .right_margin = 16, + .upper_margin = 33, + .lower_margin = 10, + .hsync_len = 96, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, +}; + +/* default LCD mode */ +static struct fb_var_screeninfo default_var_LCD __initdata = { + /* 1600x1024, 8 bpp */ + .xres = 1600, + .yres = 1024, + .xres_virtual = 1600, + .yres_virtual = 1024, + .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 = 9353, + .left_margin = 20, + .right_margin = 30, + .upper_margin = 37, + .lower_margin = 3, + .hsync_len = 20, + .vsync_len = 3, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED +}; + +/* default modedb mode */ +/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ +static struct fb_videomode default_mode_CRT __initdata = { + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39722, + .left_margin = 48, + .right_margin = 16, + .upper_margin = 33, + .lower_margin = 10, + .hsync_len = 96, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, +}; +/* 1600x1024 SGI flatpanel 1600sw */ +static struct fb_videomode default_mode_LCD __initdata = { + /* 1600x1024, 8 bpp */ + .xres = 1600, + .yres = 1024, + .pixclock = 9353, + .left_margin = 20, + .right_margin = 30, + .upper_margin = 37, + .lower_margin = 3, + .hsync_len = 20, + .vsync_len = 3, + .vmode = FB_VMODE_NONINTERLACED, +}; + +struct fb_videomode *default_mode = &default_mode_CRT; +struct fb_var_screeninfo *default_var = &default_var_CRT; + +static int flat_panel_enabled = 0; + +static void gbe_reset(void) +{ + /* Turn on dotclock PLL */ + gbe->ctrlstat = 0x300aa000; +} + + +/* + * Function: gbe_turn_off + * Parameters: (None) + * Description: This should turn off the monitor and gbe. This is used + * when switching between the serial console and the graphics + * console. + */ + +void gbe_turn_off(void) +{ + int i; + unsigned int val, x, y, vpixen_off; + + /* check if pixel counter is on */ + val = gbe->vt_xy; + if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1) + return; + + /* turn off DMA */ + val = gbe->ovr_control; + SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, val, 0); + gbe->ovr_control = val; + udelay(1000); + val = gbe->frm_control; + SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0); + gbe->frm_control = val; + udelay(1000); + val = gbe->did_control; + SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, val, 0); + gbe->did_control = val; + udelay(1000); + + /* We have to wait through two vertical retrace periods before + * the pixel DMA is turned off for sure. */ + for (i = 0; i < 10000; i++) { + val = gbe->frm_inhwctrl; + if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val)) { + udelay(10); + } else { + val = gbe->ovr_inhwctrl; + if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, val)) { + udelay(10); + } else { + val = gbe->did_inhwctrl; + if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, val)) { + udelay(10); + } else + break; + } + } + } + if (i == 10000) + printk(KERN_ERR "gbefb: turn off DMA timed out\n"); + + /* wait for vpixen_off */ + val = gbe->vt_vpixen; + vpixen_off = GET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val); + + for (i = 0; i < 100000; i++) { + val = gbe->vt_xy; + x = GET_GBE_FIELD(VT_XY, X, val); + y = GET_GBE_FIELD(VT_XY, Y, val); + if (y < vpixen_off) + break; + udelay(1); + } + if (i == 100000) + printk(KERN_ERR + "gbefb: wait for vpixen_off timed out\n"); + for (i = 0; i < 10000; i++) { + val = gbe->vt_xy; + x = GET_GBE_FIELD(VT_XY, X, val); + y = GET_GBE_FIELD(VT_XY, Y, val); + if (y > vpixen_off) + break; + udelay(1); + } + if (i == 10000) + printk(KERN_ERR "gbefb: wait for vpixen_off timed out\n"); + + /* turn off pixel counter */ + val = 0; + SET_GBE_FIELD(VT_XY, FREEZE, val, 1); + gbe->vt_xy = val; + udelay(10000); + for (i = 0; i < 10000; i++) { + val = gbe->vt_xy; + if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1) + udelay(10); + else + break; + } + if (i == 10000) + printk(KERN_ERR "gbefb: turn off pixel clock timed out\n"); + + /* turn off dot clock */ + val = gbe->dotclock; + SET_GBE_FIELD(DOTCLK, RUN, val, 0); + gbe->dotclock = val; + udelay(10000); + for (i = 0; i < 10000; i++) { + val = gbe->dotclock; + if (GET_GBE_FIELD(DOTCLK, RUN, val)) + udelay(10); + else + break; + } + if (i == 10000) + printk(KERN_ERR "gbefb: turn off dotclock timed out\n"); + + /* reset the frame DMA FIFO */ + val = gbe->frm_size_tile; + SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 1); + gbe->frm_size_tile = val; + SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 0); + gbe->frm_size_tile = val; +} + +static void gbe_turn_on(void) +{ + unsigned int val, i; + + /* + * Check if pixel counter is off, for unknown reason this + * code hangs Visual Workstations + */ + if (gbe_revision < 2) { + val = gbe->vt_xy; + if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 0) + return; + } + + /* turn on dot clock */ + val = gbe->dotclock; + SET_GBE_FIELD(DOTCLK, RUN, val, 1); + gbe->dotclock = val; + udelay(10000); + for (i = 0; i < 10000; i++) { + val = gbe->dotclock; + if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1) + udelay(10); + else + break; + } + if (i == 10000) + printk(KERN_ERR "gbefb: turn on dotclock timed out\n"); + + /* turn on pixel counter */ + val = 0; + SET_GBE_FIELD(VT_XY, FREEZE, val, 0); + gbe->vt_xy = val; + udelay(10000); + for (i = 0; i < 10000; i++) { + val = gbe->vt_xy; + if (GET_GBE_FIELD(VT_XY, FREEZE, val)) + udelay(10); + else + break; + } + if (i == 10000) + printk(KERN_ERR "gbefb: turn on pixel clock timed out\n"); + + /* turn on DMA */ + val = gbe->frm_control; + SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 1); + gbe->frm_control = val; + udelay(1000); + for (i = 0; i < 10000; i++) { + val = gbe->frm_inhwctrl; + if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val) != 1) + udelay(10); + else + break; + } + if (i == 10000) + printk(KERN_ERR "gbefb: turn on DMA timed out\n"); +} + +/* + * Blank the display. + */ +static int gbefb_blank(int blank, struct fb_info *info) +{ + /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ + switch (blank) { + case FB_BLANK_UNBLANK: /* unblank */ + gbe_turn_on(); + break; + + case FB_BLANK_NORMAL: /* blank */ + gbe_turn_off(); + break; + + default: + /* Nothing */ + break; + } + return 0; +} + +/* + * Setup flatpanel related registers. + */ +static void gbefb_setup_flatpanel(struct gbe_timing_info *timing) +{ + int fp_wid, fp_hgt, fp_vbs, fp_vbe; + u32 outputVal = 0; + + SET_GBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal, + (timing->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1); + SET_GBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal, + (timing->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1); + gbe->vt_flags = outputVal; + + /* Turn on the flat panel */ + fp_wid = 1600; + fp_hgt = 1024; + fp_vbs = 0; + fp_vbe = 1600; + timing->pll_m = 4; + timing->pll_n = 1; + timing->pll_p = 0; + + outputVal = 0; + SET_GBE_FIELD(FP_DE, ON, outputVal, fp_vbs); + SET_GBE_FIELD(FP_DE, OFF, outputVal, fp_vbe); + gbe->fp_de = outputVal; + outputVal = 0; + SET_GBE_FIELD(FP_HDRV, OFF, outputVal, fp_wid); + gbe->fp_hdrv = outputVal; + outputVal = 0; + SET_GBE_FIELD(FP_VDRV, ON, outputVal, 1); + SET_GBE_FIELD(FP_VDRV, OFF, outputVal, fp_hgt + 1); + gbe->fp_vdrv = outputVal; +} + +struct gbe_pll_info { + int clock_rate; + int fvco_min; + int fvco_max; +}; + +static struct gbe_pll_info gbe_pll_table[2] = { + { 20, 80, 220 }, + { 27, 80, 220 }, +}; + +static int compute_gbe_timing(struct fb_var_screeninfo *var, + struct gbe_timing_info *timing) +{ + int pll_m, pll_n, pll_p, error, best_m, best_n, best_p, best_error; + int pixclock; + struct gbe_pll_info *gbe_pll; + + if (gbe_revision < 2) + gbe_pll = &gbe_pll_table[0]; + else + gbe_pll = &gbe_pll_table[1]; + + /* Determine valid resolution and timing + * GBE crystal runs at 20Mhz or 27Mhz + * pll_m, pll_n, pll_p define the following frequencies + * fvco = pll_m * 20Mhz / pll_n + * fout = fvco / (2**pll_p) */ + best_error = 1000000000; + best_n = best_m = best_p = 0; + for (pll_p = 0; pll_p < 4; pll_p++) + for (pll_m = 1; pll_m < 256; pll_m++) + for (pll_n = 1; pll_n < 64; pll_n++) { + pixclock = (1000000 / gbe_pll->clock_rate) * + (pll_n << pll_p) / pll_m; + + error = var->pixclock - pixclock; + + if (error < 0) + error = -error; + + if (error < best_error && + pll_m / pll_n > + gbe_pll->fvco_min / gbe_pll->clock_rate && + pll_m / pll_n < + gbe_pll->fvco_max / gbe_pll->clock_rate) { + best_error = error; + best_m = pll_m; + best_n = pll_n; + best_p = pll_p; + } + } + + if (!best_n || !best_m) + return -EINVAL; /* Resolution to high */ + + pixclock = (1000000 / gbe_pll->clock_rate) * + (best_n << best_p) / best_m; + + /* set video timing information */ + if (timing) { + timing->width = var->xres; + timing->height = var->yres; + timing->pll_m = best_m; + timing->pll_n = best_n; + timing->pll_p = best_p; + timing->cfreq = gbe_pll->clock_rate * 1000 * timing->pll_m / + (timing->pll_n << timing->pll_p); + timing->htotal = var->left_margin + var->xres + + var->right_margin + var->hsync_len; + timing->vtotal = var->upper_margin + var->yres + + var->lower_margin + var->vsync_len; + timing->fields_sec = 1000 * timing->cfreq / timing->htotal * + 1000 / timing->vtotal; + timing->hblank_start = var->xres; + timing->vblank_start = var->yres; + timing->hblank_end = timing->htotal; + timing->hsync_start = var->xres + var->right_margin + 1; + timing->hsync_end = timing->hsync_start + var->hsync_len; + timing->vblank_end = timing->vtotal; + timing->vsync_start = var->yres + var->lower_margin + 1; + timing->vsync_end = timing->vsync_start + var->vsync_len; + } + + return pixclock; +} + +static void gbe_set_timing_info(struct gbe_timing_info *timing) +{ + int temp; + unsigned int val; + + /* setup dot clock PLL */ + val = 0; + SET_GBE_FIELD(DOTCLK, M, val, timing->pll_m - 1); + SET_GBE_FIELD(DOTCLK, N, val, timing->pll_n - 1); + SET_GBE_FIELD(DOTCLK, P, val, timing->pll_p); + SET_GBE_FIELD(DOTCLK, RUN, val, 0); /* do not start yet */ + gbe->dotclock = val; + udelay(10000); + + /* setup pixel counter */ + val = 0; + SET_GBE_FIELD(VT_XYMAX, MAXX, val, timing->htotal); + SET_GBE_FIELD(VT_XYMAX, MAXY, val, timing->vtotal); + gbe->vt_xymax = val; + + /* setup video timing signals */ + val = 0; + SET_GBE_FIELD(VT_VSYNC, VSYNC_ON, val, timing->vsync_start); + SET_GBE_FIELD(VT_VSYNC, VSYNC_OFF, val, timing->vsync_end); + gbe->vt_vsync = val; + val = 0; + SET_GBE_FIELD(VT_HSYNC, HSYNC_ON, val, timing->hsync_start); + SET_GBE_FIELD(VT_HSYNC, HSYNC_OFF, val, timing->hsync_end); + gbe->vt_hsync = val; + val = 0; + SET_GBE_FIELD(VT_VBLANK, VBLANK_ON, val, timing->vblank_start); + SET_GBE_FIELD(VT_VBLANK, VBLANK_OFF, val, timing->vblank_end); + gbe->vt_vblank = val; + val = 0; + SET_GBE_FIELD(VT_HBLANK, HBLANK_ON, val, + timing->hblank_start - 5); + SET_GBE_FIELD(VT_HBLANK, HBLANK_OFF, val, + timing->hblank_end - 3); + gbe->vt_hblank = val; + + /* setup internal timing signals */ + val = 0; + SET_GBE_FIELD(VT_VCMAP, VCMAP_ON, val, timing->vblank_start); + SET_GBE_FIELD(VT_VCMAP, VCMAP_OFF, val, timing->vblank_end); + gbe->vt_vcmap = val; + val = 0; + SET_GBE_FIELD(VT_HCMAP, HCMAP_ON, val, timing->hblank_start); + SET_GBE_FIELD(VT_HCMAP, HCMAP_OFF, val, timing->hblank_end); + gbe->vt_hcmap = val; + + val = 0; + temp = timing->vblank_start - timing->vblank_end - 1; + if (temp > 0) + temp = -temp; + + if (flat_panel_enabled) + gbefb_setup_flatpanel(timing); + + SET_GBE_FIELD(DID_START_XY, DID_STARTY, val, (u32) temp); + if (timing->hblank_end >= 20) + SET_GBE_FIELD(DID_START_XY, DID_STARTX, val, + timing->hblank_end - 20); + else + SET_GBE_FIELD(DID_START_XY, DID_STARTX, val, + timing->htotal - (20 - timing->hblank_end)); + gbe->did_start_xy = val; + + val = 0; + SET_GBE_FIELD(CRS_START_XY, CRS_STARTY, val, (u32) (temp + 1)); + if (timing->hblank_end >= GBE_CRS_MAGIC) + SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val, + timing->hblank_end - GBE_CRS_MAGIC); + else + SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val, + timing->htotal - (GBE_CRS_MAGIC - + timing->hblank_end)); + gbe->crs_start_xy = val; + + val = 0; + SET_GBE_FIELD(VC_START_XY, VC_STARTY, val, (u32) temp); + SET_GBE_FIELD(VC_START_XY, VC_STARTX, val, timing->hblank_end - 4); + gbe->vc_start_xy = val; + + val = 0; + temp = timing->hblank_end - GBE_PIXEN_MAGIC_ON; + if (temp < 0) + temp += timing->htotal; /* allow blank to wrap around */ + + SET_GBE_FIELD(VT_HPIXEN, HPIXEN_ON, val, temp); + SET_GBE_FIELD(VT_HPIXEN, HPIXEN_OFF, val, + ((temp + timing->width - + GBE_PIXEN_MAGIC_OFF) % timing->htotal)); + gbe->vt_hpixen = val; + + val = 0; + SET_GBE_FIELD(VT_VPIXEN, VPIXEN_ON, val, timing->vblank_end); + SET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val, timing->vblank_start); + gbe->vt_vpixen = val; + + /* turn off sync on green */ + val = 0; + SET_GBE_FIELD(VT_FLAGS, SYNC_LOW, val, 1); + gbe->vt_flags = val; +} + +/* + * Set the hardware according to 'par'. + */ + +static int gbefb_set_par(struct fb_info *info) +{ + int i; + unsigned int val; + int wholeTilesX, partTilesX, maxPixelsPerTileX; + int height_pix; + int xpmax, ypmax; /* Monitor resolution */ + int bytesPerPixel; /* Bytes per pixel */ + struct gbefb_par *par = (struct gbefb_par *) info->par; + + compute_gbe_timing(&info->var, &par->timing); + + bytesPerPixel = info->var.bits_per_pixel / 8; + info->fix.line_length = info->var.xres_virtual * bytesPerPixel; + xpmax = par->timing.width; + ypmax = par->timing.height; + + /* turn off GBE */ + gbe_turn_off(); + + /* set timing info */ + gbe_set_timing_info(&par->timing); + + /* initialize DIDs */ + val = 0; + switch (bytesPerPixel) { + case 1: + SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_I8); + break; + case 2: + SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_ARGB5); + break; + case 4: + SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_RGB8); + break; + } + SET_GBE_FIELD(WID, BUF, val, GBE_BMODE_BOTH); + + for (i = 0; i < 32; i++) + gbe->mode_regs[i] = val; + + /* Initialize interrupts */ + gbe->vt_intr01 = 0xffffffff; + gbe->vt_intr23 = 0xffffffff; + + /* HACK: + The GBE hardware uses a tiled memory to screen mapping. Tiles are + blocks of 512x128, 256x128 or 128x128 pixels, respectively for 8bit, + 16bit and 32 bit modes (64 kB). They cover the screen with partial + tiles on the right and/or bottom of the screen if needed. + For exemple in 640x480 8 bit mode the mapping is: + + <-------- 640 -----> + <---- 512 ----><128|384 offscreen> + ^ ^ + | 128 [tile 0] [tile 1] + | v + ^ + 4 128 [tile 2] [tile 3] + 8 v + 0 ^ + 128 [tile 4] [tile 5] + | v + | ^ + v 96 [tile 6] [tile 7] + 32 offscreen + + Tiles have the advantage that they can be allocated individually in + memory. However, this mapping is not linear at all, which is not + really convienient. In order to support linear addressing, the GBE + DMA hardware is fooled into thinking the screen is only one tile + large and but has a greater height, so that the DMA transfer covers + the same region. + Tiles are still allocated as independent chunks of 64KB of + continuous physical memory and remapped so that the kernel sees the + framebuffer as a continuous virtual memory. The GBE tile table is + set up so that each tile references one of these 64k blocks: + + GBE -> tile list framebuffer TLB <------------ CPU + [ tile 0 ] -> [ 64KB ] <- [ 16x 4KB page entries ] ^ + ... ... ... linear virtual FB + [ tile n ] -> [ 64KB ] <- [ 16x 4KB page entries ] v + + + The GBE hardware is then told that the buffer is 512*tweaked_height, + with tweaked_height = real_width*real_height/pixels_per_tile. + Thus the GBE hardware will scan the first tile, filing the first 64k + covered region of the screen, and then will proceed to the next + tile, until the whole screen is covered. + + Here is what would happen at 640x480 8bit: + + normal tiling linear + ^ 11111111111111112222 11111111111111111111 ^ + 128 11111111111111112222 11111111111111111111 102 lines + 11111111111111112222 11111111111111111111 v + V 11111111111111112222 11111111222222222222 + 33333333333333334444 22222222222222222222 + 33333333333333334444 22222222222222222222 + < 512 > < 256 > 102*640+256 = 64k + + NOTE: The only mode for which this is not working is 800x600 8bit, + as 800*600/512 = 937.5 which is not integer and thus causes + flickering. + I guess this is not so important as one can use 640x480 8bit or + 800x600 16bit anyway. + */ + + /* Tell gbe about the tiles table location */ + /* tile_ptr -> [ tile 1 ] -> FB mem */ + /* [ tile 2 ] -> FB mem */ + /* ... */ + val = 0; + SET_GBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, val, gbe_tiles.dma >> 9); + SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0); /* do not start */ + SET_GBE_FIELD(FRM_CONTROL, FRM_LINEAR, val, 0); + gbe->frm_control = val; + + maxPixelsPerTileX = 512 / bytesPerPixel; + wholeTilesX = 1; + partTilesX = 0; + + /* Initialize the framebuffer */ + val = 0; + SET_GBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, val, wholeTilesX); + SET_GBE_FIELD(FRM_SIZE_TILE, FRM_RHS, val, partTilesX); + + switch (bytesPerPixel) { + case 1: + SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val, + GBE_FRM_DEPTH_8); + break; + case 2: + SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val, + GBE_FRM_DEPTH_16); + break; + case 4: + SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val, + GBE_FRM_DEPTH_32); + break; + } + gbe->frm_size_tile = val; + + /* compute tweaked height */ + height_pix = xpmax * ypmax / maxPixelsPerTileX; + + val = 0; + SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, val, height_pix); + gbe->frm_size_pixel = val; + + /* turn off DID and overlay DMA */ + gbe->did_control = 0; + gbe->ovr_width_tile = 0; + + /* Turn off mouse cursor */ + gbe->crs_ctl = 0; + + /* Turn on GBE */ + gbe_turn_on(); + + /* Initialize the gamma map */ + udelay(10); + for (i = 0; i < 256; i++) + gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8); + + /* Initialize the color map */ + for (i = 0; i < 256; i++) { + int j; + + for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++) + udelay(10); + if (j == 1000) + printk(KERN_ERR "gbefb: cmap FIFO timeout\n"); + + gbe->cmap[i] = (i << 8) | (i << 16) | (i << 24); + } + + return 0; +} + +static void gbefb_encode_fix(struct fb_fix_screeninfo *fix, + struct fb_var_screeninfo *var) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "SGI GBE"); + fix->smem_start = (unsigned long) gbe_mem; + fix->smem_len = gbe_mem_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->accel = FB_ACCEL_NONE; + switch (var->bits_per_pixel) { + case 8: + fix->visual = FB_VISUAL_PSEUDOCOLOR; + break; + default: + fix->visual = FB_VISUAL_TRUECOLOR; + break; + } + fix->ywrapstep = 0; + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; + fix->mmio_start = GBE_BASE; + fix->mmio_len = sizeof(struct sgi_gbe); +} + +/* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + int i; + + if (regno > 255) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + + switch (info->var.bits_per_pixel) { + case 8: + /* wait for the color map FIFO to have a free entry */ + for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++) + udelay(10); + if (i == 1000) { + printk(KERN_ERR "gbefb: cmap FIFO timeout\n"); + return 1; + } + gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); + break; + case 15: + case 16: + red >>= 3; + green >>= 3; + blue >>= 3; + pseudo_palette[regno] = + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + break; + case 32: + pseudo_palette[regno] = + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + break; + } + + return 0; +} + +/* + * Check video mode validity, eventually modify var to best match. + */ +static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + unsigned int line_length; + struct gbe_timing_info timing; + + /* Limit bpp to 8, 16, and 32 */ + if (var->bits_per_pixel <= 8) + var->bits_per_pixel = 8; + else if (var->bits_per_pixel <= 16) + var->bits_per_pixel = 16; + else if (var->bits_per_pixel <= 32) + var->bits_per_pixel = 32; + else + return -EINVAL; + + /* Check the mode can be mapped linearly with the tile table trick. */ + /* This requires width x height x bytes/pixel be a multiple of 512 */ + if ((var->xres * var->yres * var->bits_per_pixel) & 4095) + return -EINVAL; + + var->grayscale = 0; /* No grayscale for now */ + + if ((var->pixclock = compute_gbe_timing(var, &timing)) < 0) + return(-EINVAL); + + /* Adjust virtual resolution, if necessary */ + if (var->xres > var->xres_virtual || (!ywrap && !ypan)) + var->xres_virtual = var->xres; + if (var->yres > var->yres_virtual || (!ywrap && !ypan)) + var->yres_virtual = var->yres; + + if (var->vmode & FB_VMODE_CONUPDATE) { + var->vmode |= FB_VMODE_YWRAP; + var->xoffset = info->var.xoffset; + var->yoffset = info->var.yoffset; + } + + /* No grayscale for now */ + var->grayscale = 0; + + /* Memory limit */ + line_length = var->xres_virtual * var->bits_per_pixel / 8; + if (line_length * var->yres_virtual > gbe_mem_size) + return -ENOMEM; /* Virtual resolution too high */ + + switch (var->bits_per_pixel) { + case 8: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 16: /* RGB 1555 */ + 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 = 0; + var->transp.length = 0; + break; + case 32: /* RGB 8888 */ + var->red.offset = 24; + var->red.length = 8; + var->green.offset = 16; + var->green.length = 8; + var->blue.offset = 8; + var->blue.length = 8; + var->transp.offset = 0; + 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; + + var->left_margin = timing.htotal - timing.hsync_end; + var->right_margin = timing.hsync_start - timing.width; + var->upper_margin = timing.vtotal - timing.vsync_end; + var->lower_margin = timing.vsync_start - timing.height; + var->hsync_len = timing.hsync_end - timing.hsync_start; + var->vsync_len = timing.vsync_end - timing.vsync_start; + + return 0; +} + +static int gbefb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long addr; + unsigned long phys_addr, phys_size; + u16 *tile; + + /* check range */ + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + if (offset + size > gbe_mem_size) + return -EINVAL; + + /* remap using the fastest write-through mode on architecture */ + /* try not polluting the cache when possible */ + pgprot_val(vma->vm_page_prot) = + pgprot_fb(pgprot_val(vma->vm_page_prot)); + + vma->vm_flags |= VM_IO | VM_RESERVED; + vma->vm_file = file; + + /* look for the starting tile */ + tile = &gbe_tiles.cpu[offset >> TILE_SHIFT]; + addr = vma->vm_start; + offset &= TILE_MASK; + + /* remap each tile separately */ + do { + phys_addr = (((unsigned long) (*tile)) << TILE_SHIFT) + offset; + if ((offset + size) < TILE_SIZE) + phys_size = size; + else + phys_size = TILE_SIZE - offset; + + if (remap_pfn_range(vma, addr, phys_addr >> PAGE_SHIFT, + phys_size, vma->vm_page_prot)) + return -EAGAIN; + + offset = 0; + size -= phys_size; + addr += phys_size; + tile++; + } while (size); + + return 0; +} + +static struct fb_ops gbefb_ops = { + .owner = THIS_MODULE, + .fb_check_var = gbefb_check_var, + .fb_set_par = gbefb_set_par, + .fb_setcolreg = gbefb_setcolreg, + .fb_mmap = gbefb_mmap, + .fb_blank = gbefb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +/* + * sysfs + */ + +static ssize_t gbefb_show_memsize(struct device *dev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", gbe_mem_size); +} + +static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL); + +static ssize_t gbefb_show_rev(struct device *device, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", gbe_revision); +} + +static DEVICE_ATTR(revision, S_IRUGO, gbefb_show_rev, NULL); + +static void __devexit gbefb_remove_sysfs(struct device *dev) +{ + device_remove_file(dev, &dev_attr_size); + device_remove_file(dev, &dev_attr_revision); +} + +static void gbefb_create_sysfs(struct device *dev) +{ + device_create_file(dev, &dev_attr_size); + device_create_file(dev, &dev_attr_revision); +} + +/* + * Initialization + */ + +int __init gbefb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "monitor:", 8)) { + if (!strncmp(this_opt + 8, "crt", 3)) { + flat_panel_enabled = 0; + default_var = &default_var_CRT; + default_mode = &default_mode_CRT; + } else if (!strncmp(this_opt + 8, "1600sw", 6) || + !strncmp(this_opt + 8, "lcd", 3)) { + flat_panel_enabled = 1; + default_var = &default_var_LCD; + default_mode = &default_mode_LCD; + } + } else if (!strncmp(this_opt, "mem:", 4)) { + gbe_mem_size = memparse(this_opt + 4, &this_opt); + if (gbe_mem_size > CONFIG_FB_GBE_MEM * 1024 * 1024) + gbe_mem_size = CONFIG_FB_GBE_MEM * 1024 * 1024; + if (gbe_mem_size < TILE_SIZE) + gbe_mem_size = TILE_SIZE; + } else + mode_option = this_opt; + } + return 0; +} + +static int __init gbefb_probe(struct device *dev) +{ + int i, ret = 0; + struct fb_info *info; + struct gbefb_par *par; + struct platform_device *p_dev = to_platform_device(dev); +#ifndef MODULE + char *options = NULL; +#endif + + info = framebuffer_alloc(sizeof(struct gbefb_par), &p_dev->dev); + if (!info) + return -ENOMEM; + +#ifndef MODULE + if (fb_get_options("gbefb", &options)) + return -ENODEV; + gbefb_setup(options); +#endif + + if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) { + printk(KERN_ERR "gbefb: couldn't reserve mmio region\n"); + ret = -EBUSY; + goto out_release_framebuffer; + } + + gbe = (struct sgi_gbe *) ioremap(GBE_BASE, sizeof(struct sgi_gbe)); + if (!gbe) { + printk(KERN_ERR "gbefb: couldn't map mmio region\n"); + ret = -ENXIO; + goto out_release_mem_region; + } + gbe_revision = gbe->ctrlstat & 15; + + gbe_tiles.cpu = + dma_alloc_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t), + &gbe_tiles.dma, GFP_KERNEL); + if (!gbe_tiles.cpu) { + printk(KERN_ERR "gbefb: couldn't allocate tiles table\n"); + ret = -ENOMEM; + goto out_unmap; + } + + if (gbe_mem_phys) { + /* memory was allocated at boot time */ + gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size); + gbe_dma_addr = 0; + } else { + /* try to allocate memory with the classical allocator + * this has high chance to fail on low memory machines */ + gbe_mem = dma_alloc_coherent(NULL, gbe_mem_size, &gbe_dma_addr, + GFP_KERNEL); + gbe_mem_phys = (unsigned long) gbe_dma_addr; + } + +#ifdef CONFIG_X86 + mtrr_add(gbe_mem_phys, gbe_mem_size, MTRR_TYPE_WRCOMB, 1); +#endif + + if (!gbe_mem) { + printk(KERN_ERR "gbefb: couldn't map framebuffer\n"); + ret = -ENXIO; + goto out_tiles_free; + } + + /* map framebuffer memory into tiles table */ + for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++) + gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i; + + info->fbops = &gbefb_ops; + info->pseudo_palette = pseudo_palette; + info->flags = FBINFO_DEFAULT; + info->screen_base = gbe_mem; + fb_alloc_cmap(&info->cmap, 256, 0); + + /* reset GBE */ + gbe_reset(); + + par = info->par; + /* turn on default video mode */ + if (fb_find_mode(&par->var, info, mode_option, NULL, 0, + default_mode, 8) == 0) + par->var = *default_var; + info->var = par->var; + gbefb_check_var(&par->var, info); + gbefb_encode_fix(&info->fix, &info->var); + + if (register_framebuffer(info) < 0) { + printk(KERN_ERR "gbefb: couldn't register framebuffer\n"); + ret = -ENXIO; + goto out_gbe_unmap; + } + + dev_set_drvdata(&p_dev->dev, info); + gbefb_create_sysfs(dev); + + printk(KERN_INFO "fb%d: %s rev %d @ 0x%08x using %dkB memory\n", + info->node, info->fix.id, gbe_revision, (unsigned) GBE_BASE, + gbe_mem_size >> 10); + + return 0; + +out_gbe_unmap: + if (gbe_dma_addr) + dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys); + else + iounmap(gbe_mem); +out_tiles_free: + dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t), + (void *)gbe_tiles.cpu, gbe_tiles.dma); +out_unmap: + iounmap(gbe); +out_release_mem_region: + release_mem_region(GBE_BASE, sizeof(struct sgi_gbe)); +out_release_framebuffer: + framebuffer_release(info); + + return ret; +} + +static int __devexit gbefb_remove(struct device* dev) +{ + struct platform_device *p_dev = to_platform_device(dev); + struct fb_info *info = dev_get_drvdata(&p_dev->dev); + + unregister_framebuffer(info); + gbe_turn_off(); + if (gbe_dma_addr) + dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys); + else + iounmap(gbe_mem); + dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t), + (void *)gbe_tiles.cpu, gbe_tiles.dma); + release_mem_region(GBE_BASE, sizeof(struct sgi_gbe)); + iounmap(gbe); + gbefb_remove_sysfs(dev); + framebuffer_release(info); + + return 0; +} + +static struct device_driver gbefb_driver = { + .name = "gbefb", + .bus = &platform_bus_type, + .probe = gbefb_probe, + .remove = __devexit_p(gbefb_remove), +}; + +static struct platform_device gbefb_device = { + .name = "gbefb", +}; + +int __init gbefb_init(void) +{ + int ret = driver_register(&gbefb_driver); + if (!ret) { + ret = platform_device_register(&gbefb_device); + if (ret) + driver_unregister(&gbefb_driver); + } + return ret; +} + +void __exit gbefb_exit(void) +{ + driver_unregister(&gbefb_driver); +} + +module_init(gbefb_init); +module_exit(gbefb_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig new file mode 100644 index 000000000000..b075fd02de31 --- /dev/null +++ b/drivers/video/geode/Kconfig @@ -0,0 +1,29 @@ +# +# Geode family framebuffer configuration +# +config FB_GEODE + bool "AMD Geode family framebuffer support (EXPERIMENTAL)" + default n + depends on FB && EXPERIMENTAL && X86 + ---help--- + Say 'Y' here to allow you to select framebuffer drivers for + the AMD Geode family of processors. + +config FB_GEODE_GX1 + tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)" + default n + depends on FB_GEODE && EXPERIMENTAL + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + ---help--- + Framebuffer driver for the display controller integrated into the + AMD Geode GX1 processor. + + This 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 gx1fb. If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. + + If unsure, say N. diff --git a/drivers/video/geode/Makefile b/drivers/video/geode/Makefile new file mode 100644 index 000000000000..13ad501ea990 --- /dev/null +++ b/drivers/video/geode/Makefile @@ -0,0 +1,5 @@ +# Makefile for the Geode family framebuffer drivers + +obj-$(CONFIG_FB_GEODE_GX1) += gx1fb.o + +gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o diff --git a/drivers/video/geode/display_gx1.c b/drivers/video/geode/display_gx1.c new file mode 100644 index 000000000000..f4983879fcc4 --- /dev/null +++ b/drivers/video/geode/display_gx1.c @@ -0,0 +1,214 @@ +/* + * drivers/video/geode/display_gx1.c + * -- Geode GX1 display controller + * + * Copyright (C) 2005 Arcom Control Systems Ltd. + * + * Based on AMD's original 2.4 driver: + * Copyright (C) 2004 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include <linux/spinlock.h> +#include <linux/fb.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/div64.h> +#include <asm/delay.h> + +#include "geodefb.h" +#include "display_gx1.h" + +static spinlock_t gx1_conf_reg_lock = SPIN_LOCK_UNLOCKED; + +static u8 gx1_read_conf_reg(u8 reg) +{ + u8 val, ccr3; + unsigned long flags; + + spin_lock_irqsave(&gx1_conf_reg_lock, flags); + + outb(CONFIG_CCR3, 0x22); + ccr3 = inb(0x23); + outb(CONFIG_CCR3, 0x22); + outb(ccr3 | CONFIG_CCR3_MAPEN, 0x23); + outb(reg, 0x22); + val = inb(0x23); + outb(CONFIG_CCR3, 0x22); + outb(ccr3, 0x23); + + spin_unlock_irqrestore(&gx1_conf_reg_lock, flags); + + return val; +} + +unsigned gx1_gx_base(void) +{ + return (gx1_read_conf_reg(CONFIG_GCR) & 0x03) << 30; +} + +int gx1_frame_buffer_size(void) +{ + void __iomem *mc_regs; + u32 bank_cfg; + int d; + unsigned dram_size = 0, fb_base; + + mc_regs = ioremap(gx1_gx_base() + 0x8400, 0x100); + if (!mc_regs) + return -ENOMEM; + + + /* Calculate the total size of both DIMM0 and DIMM1. */ + bank_cfg = readl(mc_regs + MC_BANK_CFG); + + for (d = 0; d < 2; d++) { + if ((bank_cfg & MC_BCFG_DIMM0_PG_SZ_MASK) != MC_BCFG_DIMM0_PG_SZ_NO_DIMM) + dram_size += 0x400000 << ((bank_cfg & MC_BCFG_DIMM0_SZ_MASK) >> 8); + bank_cfg >>= 16; /* look at DIMM1 next */ + } + + fb_base = (readl(mc_regs + MC_GBASE_ADD) & MC_GADD_GBADD_MASK) << 19; + + iounmap(mc_regs); + + return dram_size - fb_base; +} + +static void gx1_set_mode(struct fb_info *info) +{ + struct geodefb_par *par = info->par; + u32 gcfg, tcfg, ocfg, dclk_div, val; + int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal; + int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; + + /* Unlock the display controller registers. */ + readl(par->dc_regs + DC_UNLOCK); + writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); + + gcfg = readl(par->dc_regs + DC_GENERAL_CFG); + tcfg = readl(par->dc_regs + DC_TIMING_CFG); + + /* Blank the display and disable the timing generator. */ + tcfg &= ~(DC_TCFG_BLKE | DC_TCFG_TGEN); + writel(tcfg, par->dc_regs + DC_TIMING_CFG); + + /* Wait for pending memory requests before disabling the FIFO load. */ + udelay(100); + + /* Disable FIFO load and compression. */ + gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE); + writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + + /* Setup DCLK and its divisor. */ + gcfg &= ~DC_GCFG_DCLK_MASK; + writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + + par->vid_ops->set_dclk(info); + + dclk_div = DC_GCFG_DCLK_DIV_1; /* FIXME: may need to divide DCLK by 2 sometimes? */ + gcfg |= dclk_div; + writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + + /* Wait for the clock generatation to settle. This is needed since + * some of the register writes that follow require that clock to be + * present. */ + udelay(1000); /* FIXME: seems a little long */ + + /* + * Setup new mode. + */ + + /* Clear all unused feature bits. */ + gcfg = DC_GCFG_VRDY | dclk_div; + + /* Set FIFO priority (default 6/5) and enable. */ + /* FIXME: increase fifo priority for 1280x1024 modes? */ + gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE; + + /* FIXME: Set pixel and line double bits if necessary. */ + + /* Framebuffer start offset. */ + writel(0, par->dc_regs + DC_FB_ST_OFFSET); + + /* Line delta and line buffer length. */ + writel(info->fix.line_length >> 2, par->dc_regs + DC_LINE_DELTA); + writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2, + par->dc_regs + DC_BUF_SIZE); + + /* Output configuration. Enable panel data, set pixel format. */ + ocfg = DC_OCFG_PCKE | DC_OCFG_PDEL | DC_OCFG_PDEH; + if (info->var.bits_per_pixel == 8) ocfg |= DC_OCFG_8BPP; + + /* Enable timing generator, sync and FP data. */ + tcfg = DC_TCFG_FPPE | DC_TCFG_HSYE | DC_TCFG_VSYE | DC_TCFG_BLKE + | DC_TCFG_TGEN; + + /* Horizontal and vertical timings. */ + hactive = info->var.xres; + hblankstart = hactive; + hsyncstart = hblankstart + info->var.right_margin; + hsyncend = hsyncstart + info->var.hsync_len; + hblankend = hsyncend + info->var.left_margin; + htotal = hblankend; + + vactive = info->var.yres; + vblankstart = vactive; + vsyncstart = vblankstart + info->var.lower_margin; + vsyncend = vsyncstart + info->var.vsync_len; + vblankend = vsyncend + info->var.upper_margin; + vtotal = vblankend; + + val = (hactive - 1) | ((htotal - 1) << 16); + writel(val, par->dc_regs + DC_H_TIMING_1); + val = (hblankstart - 1) | ((hblankend - 1) << 16); + writel(val, par->dc_regs + DC_H_TIMING_2); + val = (hsyncstart - 1) | ((hsyncend - 1) << 16); + writel(val, par->dc_regs + DC_H_TIMING_3); + writel(val, par->dc_regs + DC_FP_H_TIMING); + val = (vactive - 1) | ((vtotal - 1) << 16); + writel(val, par->dc_regs + DC_V_TIMING_1); + val = (vblankstart - 1) | ((vblankend - 1) << 16); + writel(val, par->dc_regs + DC_V_TIMING_2); + val = (vsyncstart - 1) | ((vsyncend - 1) << 16); + writel(val, par->dc_regs + DC_V_TIMING_3); + val = (vsyncstart - 2) | ((vsyncend - 2) << 16); + writel(val, par->dc_regs + DC_FP_V_TIMING); + + /* Write final register values. */ + writel(ocfg, par->dc_regs + DC_OUTPUT_CFG); + writel(tcfg, par->dc_regs + DC_TIMING_CFG); + udelay(1000); /* delay after TIMING_CFG. FIXME: perhaps a little long */ + writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + + par->vid_ops->configure_display(info); + + /* Relock display controller registers */ + writel(0, par->dc_regs + DC_UNLOCK); + + /* FIXME: write line_length and bpp to Graphics Pipeline GP_BLT_STATUS + * register. */ +} + +static void gx1_set_hw_palette_reg(struct fb_info *info, unsigned regno, + unsigned red, unsigned green, unsigned blue) +{ + struct geodefb_par *par = info->par; + int val; + + /* Hardware palette is in RGB 6-6-6 format. */ + val = (red << 2) & 0x3f000; + val |= (green >> 4) & 0x00fc0; + val |= (blue >> 10) & 0x0003f; + + writel(regno, par->dc_regs + DC_PAL_ADDRESS); + writel(val, par->dc_regs + DC_PAL_DATA); +} + +struct geode_dc_ops gx1_dc_ops = { + .set_mode = gx1_set_mode, + .set_palette_reg = gx1_set_hw_palette_reg, +}; diff --git a/drivers/video/geode/display_gx1.h b/drivers/video/geode/display_gx1.h new file mode 100644 index 000000000000..671c05558c79 --- /dev/null +++ b/drivers/video/geode/display_gx1.h @@ -0,0 +1,154 @@ +/* + * drivers/video/geode/display_gx1.h + * -- Geode GX1 display controller + * + * Copyright (C) 2005 Arcom Control Systems Ltd. + * + * Based on AMD's original 2.4 driver: + * Copyright (C) 2004 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __DISPLAY_GX1_H__ +#define __DISPLAY_GX1_H__ + +unsigned gx1_gx_base(void); +int gx1_frame_buffer_size(void); + +extern struct geode_dc_ops gx1_dc_ops; + +/* GX1 configuration I/O registers */ + +#define CONFIG_CCR3 0xc3 +# define CONFIG_CCR3_MAPEN 0x10 +#define CONFIG_GCR 0xb8 + +/* Memory controller registers */ + +#define MC_BANK_CFG 0x08 +# define MC_BCFG_DIMM0_SZ_MASK 0x00000700 +# define MC_BCFG_DIMM0_PG_SZ_MASK 0x00000070 +# define MC_BCFG_DIMM0_PG_SZ_NO_DIMM 0x00000070 + +#define MC_GBASE_ADD 0x14 +# define MC_GADD_GBADD_MASK 0x000003ff + +/* Display controller registers */ + +#define DC_PAL_ADDRESS 0x70 +#define DC_PAL_DATA 0x74 + +#define DC_UNLOCK 0x00 +# define DC_UNLOCK_CODE 0x00004758 + +#define DC_GENERAL_CFG 0x04 +# define DC_GCFG_DFLE 0x00000001 +# define DC_GCFG_CURE 0x00000002 +# define DC_GCFG_VCLK_DIV 0x00000004 +# define DC_GCFG_PLNO 0x00000004 +# define DC_GCFG_PPC 0x00000008 +# define DC_GCFG_CMPE 0x00000010 +# define DC_GCFG_DECE 0x00000020 +# define DC_GCFG_DCLK_MASK 0x000000C0 +# define DC_GCFG_DCLK_DIV_1 0x00000080 +# define DC_GCFG_DFHPSL_MASK 0x00000F00 +# define DC_GCFG_DFHPSL_POS 8 +# define DC_GCFG_DFHPEL_MASK 0x0000F000 +# define DC_GCFG_DFHPEL_POS 12 +# define DC_GCFG_CIM_MASK 0x00030000 +# define DC_GCFG_CIM_POS 16 +# define DC_GCFG_FDTY 0x00040000 +# define DC_GCFG_RTPM 0x00080000 +# define DC_GCFG_DAC_RS_MASK 0x00700000 +# define DC_GCFG_DAC_RS_POS 20 +# define DC_GCFG_CKWR 0x00800000 +# define DC_GCFG_LDBL 0x01000000 +# define DC_GCFG_DIAG 0x02000000 +# define DC_GCFG_CH4S 0x04000000 +# define DC_GCFG_SSLC 0x08000000 +# define DC_GCFG_VIDE 0x10000000 +# define DC_GCFG_VRDY 0x20000000 +# define DC_GCFG_DPCK 0x40000000 +# define DC_GCFG_DDCK 0x80000000 + +#define DC_TIMING_CFG 0x08 +# define DC_TCFG_FPPE 0x00000001 +# define DC_TCFG_HSYE 0x00000002 +# define DC_TCFG_VSYE 0x00000004 +# define DC_TCFG_BLKE 0x00000008 +# define DC_TCFG_DDCK 0x00000010 +# define DC_TCFG_TGEN 0x00000020 +# define DC_TCFG_VIEN 0x00000040 +# define DC_TCFG_BLNK 0x00000080 +# define DC_TCFG_CHSP 0x00000100 +# define DC_TCFG_CVSP 0x00000200 +# define DC_TCFG_FHSP 0x00000400 +# define DC_TCFG_FVSP 0x00000800 +# define DC_TCFG_FCEN 0x00001000 +# define DC_TCFG_CDCE 0x00002000 +# define DC_TCFG_PLNR 0x00002000 +# define DC_TCFG_INTL 0x00004000 +# define DC_TCFG_PXDB 0x00008000 +# define DC_TCFG_BKRT 0x00010000 +# define DC_TCFG_PSD_MASK 0x000E0000 +# define DC_TCFG_PSD_POS 17 +# define DC_TCFG_DDCI 0x08000000 +# define DC_TCFG_SENS 0x10000000 +# define DC_TCFG_DNA 0x20000000 +# define DC_TCFG_VNA 0x40000000 +# define DC_TCFG_VINT 0x80000000 + +#define DC_OUTPUT_CFG 0x0C +# define DC_OCFG_8BPP 0x00000001 +# define DC_OCFG_555 0x00000002 +# define DC_OCFG_PCKE 0x00000004 +# define DC_OCFG_FRME 0x00000008 +# define DC_OCFG_DITE 0x00000010 +# define DC_OCFG_2PXE 0x00000020 +# define DC_OCFG_2XCK 0x00000040 +# define DC_OCFG_2IND 0x00000080 +# define DC_OCFG_34ADD 0x00000100 +# define DC_OCFG_FRMS 0x00000200 +# define DC_OCFG_CKSL 0x00000400 +# define DC_OCFG_PRMP 0x00000800 +# define DC_OCFG_PDEL 0x00001000 +# define DC_OCFG_PDEH 0x00002000 +# define DC_OCFG_CFRW 0x00004000 +# define DC_OCFG_DIAG 0x00008000 + +#define DC_FB_ST_OFFSET 0x10 +#define DC_CB_ST_OFFSET 0x14 +#define DC_CURS_ST_OFFSET 0x18 +#define DC_ICON_ST_OFFSET 0x1C +#define DC_VID_ST_OFFSET 0x20 +#define DC_LINE_DELTA 0x24 +#define DC_BUF_SIZE 0x28 + +#define DC_H_TIMING_1 0x30 +#define DC_H_TIMING_2 0x34 +#define DC_H_TIMING_3 0x38 +#define DC_FP_H_TIMING 0x3C + +#define DC_V_TIMING_1 0x40 +#define DC_V_TIMING_2 0x44 +#define DC_V_TIMING_3 0x48 +#define DC_FP_V_TIMING 0x4C + +#define DC_CURSOR_X 0x50 +#define DC_ICON_X 0x54 +#define DC_V_LINE_CNT 0x54 +#define DC_CURSOR_Y 0x58 +#define DC_ICON_Y 0x5C +#define DC_SS_LINE_CMP 0x5C +#define DC_CURSOR_COLOR 0x60 +#define DC_ICON_COLOR 0x64 +#define DC_BORDER_COLOR 0x68 +#define DC_PAL_ADDRESS 0x70 +#define DC_PAL_DATA 0x74 +#define DC_DFIFO_DIAG 0x78 +#define DC_CFIFO_DIAG 0x7C + +#endif /* !__DISPLAY_GX1_H__ */ diff --git a/drivers/video/geode/geodefb.h b/drivers/video/geode/geodefb.h new file mode 100644 index 000000000000..b7bac0a526b3 --- /dev/null +++ b/drivers/video/geode/geodefb.h @@ -0,0 +1,39 @@ +/* + * drivers/video/geode/geodefb.h + * -- Geode framebuffer driver + * + * Copyright (C) 2005 Arcom Control Systems Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __GEODEFB_H__ +#define __GEODEFB_H__ + +struct geodefb_info; + +struct geode_dc_ops { + void (*set_mode)(struct fb_info *); + void (*set_palette_reg)(struct fb_info *, unsigned, unsigned, unsigned, unsigned); +}; + +struct geode_vid_ops { + void (*set_dclk)(struct fb_info *); + void (*configure_display)(struct fb_info *); + int (*blank_display)(struct fb_info *, int blank_mode); +}; + +struct geodefb_par { + int enable_crt; + int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */ + int panel_y; + struct pci_dev *vid_dev; + void __iomem *dc_regs; + void __iomem *vid_regs; + struct geode_dc_ops *dc_ops; + struct geode_vid_ops *vid_ops; +}; + +#endif /* !__GEODEFB_H__ */ diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c new file mode 100644 index 000000000000..83830d24bcda --- /dev/null +++ b/drivers/video/geode/gx1fb_core.c @@ -0,0 +1,359 @@ +/* + * drivers/video/geode/gx1fb_core.c + * -- Geode GX1 framebuffer driver + * + * Copyright (C) 2005 Arcom Control Systems Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include "geodefb.h" +#include "display_gx1.h" +#include "video_cs5530.h" + +static char mode_option[32] = "640x480-16@60"; +static int crt_option = 1; +static char panel_option[32] = ""; + +static int gx1_line_delta(int xres, int bpp) +{ + int line_delta = xres * (bpp >> 3); + + if (line_delta > 2048) + line_delta = 4096; + else if (line_delta > 1024) + line_delta = 2048; + else + line_delta = 1024; + return line_delta; +} + +static int gx1fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct geodefb_par *par = info->par; + + printk(KERN_DEBUG "%s()\n", __FUNCTION__); + + /* Maximum resolution is 1280x1024. */ + if (var->xres > 1280 || var->yres > 1024) + return -EINVAL; + + if (par->panel_x && (var->xres > par->panel_x || var->yres > par->panel_y)) + return -EINVAL; + + /* Only 16 bpp and 8 bpp is supported by the hardware. */ + if (var->bits_per_pixel == 16) { + 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; + } else if (var->bits_per_pixel == 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; + } else + return -EINVAL; + + /* Enough video memory? */ + if (gx1_line_delta(var->xres, var->bits_per_pixel) * var->yres > info->fix.smem_len) + return -EINVAL; + + /* FIXME: Check timing parameters here? */ + + return 0; +} + +static int gx1fb_set_par(struct fb_info *info) +{ + struct geodefb_par *par = info->par; + + if (info->var.bits_per_pixel == 16) { + info->fix.visual = FB_VISUAL_TRUECOLOR; + fb_dealloc_cmap(&info->cmap); + } else { + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0); + } + + info->fix.line_length = gx1_line_delta(info->var.xres, info->var.bits_per_pixel); + + par->dc_ops->set_mode(info); + + return 0; +} + +static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int gx1fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct geodefb_par *par = info->par; + + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + /* Truecolor has hardware independent palette */ + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 *pal = info->pseudo_palette; + u32 v; + + if (regno >= 16) + return -EINVAL; + + v = chan_to_field(red, &info->var.red); + v |= chan_to_field(green, &info->var.green); + v |= chan_to_field(blue, &info->var.blue); + + pal[regno] = v; + } else { + if (regno >= 256) + return -EINVAL; + + par->dc_ops->set_palette_reg(info, regno, red, green, blue); + } + + return 0; +} + +static int gx1fb_blank(int blank_mode, struct fb_info *info) +{ + struct geodefb_par *par = info->par; + + return par->vid_ops->blank_display(info, blank_mode); +} + +static int __init gx1fb_map_video_memory(struct fb_info *info) +{ + struct geodefb_par *par = info->par; + unsigned gx_base; + int fb_len; + + gx_base = gx1_gx_base(); + if (!gx_base) + return -ENODEV; + + par->vid_dev = pci_get_device(PCI_VENDOR_ID_CYRIX, + PCI_DEVICE_ID_CYRIX_5530_VIDEO, NULL); + if (!par->vid_dev) + return -ENODEV; + + par->vid_regs = ioremap(pci_resource_start(par->vid_dev, 1), + pci_resource_len(par->vid_dev, 1)); + if (!par->vid_regs) + return -ENOMEM; + + par->dc_regs = ioremap(gx_base + 0x8300, 0x100); + if (!par->dc_regs) + return -ENOMEM; + + info->fix.smem_start = gx_base + 0x800000; + if ((fb_len = gx1_frame_buffer_size()) < 0) + return -ENOMEM; + info->fix.smem_len = fb_len; + info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); + if (!info->screen_base) + return -ENOMEM; + + printk(KERN_INFO "%s: %d Kibyte of video memory at 0x%lx\n", + info->fix.id, info->fix.smem_len / 1024, info->fix.smem_start); + + return 0; +} + +static int parse_panel_option(struct fb_info *info) +{ + struct geodefb_par *par = info->par; + + if (strcmp(panel_option, "") != 0) { + int x, y; + char *s; + x = simple_strtol(panel_option, &s, 10); + if (!x) + return -EINVAL; + y = simple_strtol(s + 1, NULL, 10); + if (!y) + return -EINVAL; + par->panel_x = x; + par->panel_y = y; + } + return 0; +} + +static struct fb_ops gx1fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = gx1fb_check_var, + .fb_set_par = gx1fb_set_par, + .fb_setcolreg = gx1fb_setcolreg, + .fb_blank = gx1fb_blank, + /* No HW acceleration for now. */ + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +static struct fb_info * __init gx1fb_init_fbinfo(void) +{ + struct fb_info *info; + struct geodefb_par *par; + + /* Alloc enough space for the pseudo palette. */ + info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, NULL); + if (!info) + return NULL; + + par = info->par; + + strcpy(info->fix.id, "GX1"); + + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + info->fix.xpanstep = 0; + info->fix.ypanstep = 0; + info->fix.ywrapstep = 0; + info->fix.accel = FB_ACCEL_NONE; + + info->var.nonstd = 0; + info->var.activate = FB_ACTIVATE_NOW; + info->var.height = -1; + info->var.width = -1; + info->var.accel_flags = 0; + info->var.vmode = FB_VMODE_NONINTERLACED; + + info->fbops = &gx1fb_ops; + info->flags = FBINFO_DEFAULT; + info->node = -1; + + info->pseudo_palette = (void *)par + sizeof(struct geodefb_par); + + info->var.grayscale = 0; + + /* CRT and panel options */ + par->enable_crt = crt_option; + if (parse_panel_option(info) < 0) + printk(KERN_WARNING "%s: invalid 'panel' option -- disabling flat panel\n", + info->fix.id); + if (!par->panel_x) + par->enable_crt = 1; /* fall back to CRT if no panel is specified */ + + return info; +} + + +static struct fb_info *gx1fb_info; + +static int __init gx1fb_init(void) +{ + struct fb_info *info; + struct geodefb_par *par; + int ret; + +#ifndef MODULE + if (fb_get_options("gx1fb", NULL)) + return -ENODEV; +#endif + + info = gx1fb_init_fbinfo(); + if (!info) + return -ENOMEM; + gx1fb_info = info; + + par = info->par; + + /* GX1 display controller and CS5530 video device */ + par->dc_ops = &gx1_dc_ops; + par->vid_ops = &cs5530_vid_ops; + + if ((ret = gx1fb_map_video_memory(info)) < 0) { + printk(KERN_ERR "%s: gx1fb_map_video_memory() failed\n", info->fix.id); + goto err; + } + + ret = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16); + if (ret == 0 || ret == 4) { + printk(KERN_ERR "%s: could not find valid video mode\n", info->fix.id); + ret = -EINVAL; + goto err; + } + + /* Clear the frame buffer of garbage. */ + memset_io(info->screen_base, 0, info->fix.smem_len); + + gx1fb_check_var(&info->var, info); + gx1fb_set_par(info); + + if (register_framebuffer(info) < 0) { + ret = -EINVAL; + goto err; + } + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); + return 0; + + err: + if (info->screen_base) + iounmap(info->screen_base); + if (par->vid_regs) + iounmap(par->vid_regs); + if (par->dc_regs) + iounmap(par->dc_regs); + if (par->vid_dev) + pci_dev_put(par->vid_dev); + if (info) + framebuffer_release(info); + return ret; +} + +static void __exit gx1fb_cleanup(void) +{ + struct fb_info *info = gx1fb_info; + struct geodefb_par *par = gx1fb_info->par; + + unregister_framebuffer(info); + + iounmap((void __iomem *)info->screen_base); + iounmap(par->vid_regs); + iounmap(par->dc_regs); + + pci_dev_put(par->vid_dev); + + framebuffer_release(info); +} + +module_init(gx1fb_init); +module_exit(gx1fb_cleanup); + +module_param_string(mode, mode_option, sizeof(mode_option), 0444); +MODULE_PARM_DESC(mode, "video mode (<x>x<y>[-<bpp>][@<refr>])"); + +module_param_named(crt, crt_option, int, 0444); +MODULE_PARM_DESC(crt, "enable CRT output. 0 = off, 1 = on (default)"); + +module_param_string(panel, panel_option, sizeof(panel_option), 0444); +MODULE_PARM_DESC(panel, "size of attached flat panel (<x>x<y>)"); + +MODULE_DESCRIPTION("framebuffer driver for the AMD Geode GX1"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/geode/video_cs5530.c b/drivers/video/geode/video_cs5530.c new file mode 100644 index 000000000000..d3764acf8443 --- /dev/null +++ b/drivers/video/geode/video_cs5530.c @@ -0,0 +1,195 @@ +/* + * drivers/video/geode/video_cs5530.c + * -- CS5530 video device + * + * Copyright (C) 2005 Arcom Control Systems Ltd. + * + * Based on AMD's original 2.4 driver: + * Copyright (C) 2004 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include <linux/fb.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/delay.h> + +#include "geodefb.h" +#include "video_cs5530.h" + +/* + * CS5530 PLL table. This maps pixclocks to the appropriate PLL register + * value. + */ +struct cs5530_pll_entry { + long pixclock; /* ps */ + u32 pll_value; +}; + +static const struct cs5530_pll_entry cs5530_pll_table[] = { + { 39721, 0x31C45801, }, /* 25.1750 MHz */ + { 35308, 0x20E36802, }, /* 28.3220 */ + { 31746, 0x33915801, }, /* 31.5000 */ + { 27777, 0x31EC4801, }, /* 36.0000 */ + { 26666, 0x21E22801, }, /* 37.5000 */ + { 25000, 0x33088801, }, /* 40.0000 */ + { 22271, 0x33E22801, }, /* 44.9000 */ + { 20202, 0x336C4801, }, /* 49.5000 */ + { 20000, 0x23088801, }, /* 50.0000 */ + { 19860, 0x23088801, }, /* 50.3500 */ + { 18518, 0x3708A801, }, /* 54.0000 */ + { 17777, 0x23E36802, }, /* 56.2500 */ + { 17733, 0x23E36802, }, /* 56.3916 */ + { 17653, 0x23E36802, }, /* 56.6444 */ + { 16949, 0x37C45801, }, /* 59.0000 */ + { 15873, 0x23EC4801, }, /* 63.0000 */ + { 15384, 0x37911801, }, /* 65.0000 */ + { 14814, 0x37963803, }, /* 67.5000 */ + { 14124, 0x37058803, }, /* 70.8000 */ + { 13888, 0x3710C805, }, /* 72.0000 */ + { 13333, 0x37E22801, }, /* 75.0000 */ + { 12698, 0x27915801, }, /* 78.7500 */ + { 12500, 0x37D8D802, }, /* 80.0000 */ + { 11135, 0x27588802, }, /* 89.8000 */ + { 10582, 0x27EC4802, }, /* 94.5000 */ + { 10101, 0x27AC6803, }, /* 99.0000 */ + { 10000, 0x27088801, }, /* 100.0000 */ + { 9259, 0x2710C805, }, /* 108.0000 */ + { 8888, 0x27E36802, }, /* 112.5000 */ + { 7692, 0x27C58803, }, /* 130.0000 */ + { 7407, 0x27316803, }, /* 135.0000 */ + { 6349, 0x2F915801, }, /* 157.5000 */ + { 6172, 0x2F08A801, }, /* 162.0000 */ + { 5714, 0x2FB11802, }, /* 175.0000 */ + { 5291, 0x2FEC4802, }, /* 189.0000 */ + { 4950, 0x2F963803, }, /* 202.0000 */ + { 4310, 0x2FB1B802, }, /* 232.0000 */ +}; + +#define NUM_CS5530_FREQUENCIES sizeof(cs5530_pll_table)/sizeof(struct cs5530_pll_entry) + +static void cs5530_set_dclk_frequency(struct fb_info *info) +{ + struct geodefb_par *par = info->par; + int i; + u32 value; + long min, diff; + + /* Search the table for the closest pixclock. */ + value = cs5530_pll_table[0].pll_value; + min = cs5530_pll_table[0].pixclock - info->var.pixclock; + if (min < 0) min = -min; + for (i = 1; i < NUM_CS5530_FREQUENCIES; i++) { + diff = cs5530_pll_table[i].pixclock - info->var.pixclock; + if (diff < 0L) diff = -diff; + if (diff < min) { + min = diff; + value = cs5530_pll_table[i].pll_value; + } + } + + writel(value, par->vid_regs + CS5530_DOT_CLK_CONFIG); + writel(value | 0x80000100, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* set reset and bypass */ + udelay(500); /* wait for PLL to settle */ + writel(value & 0x7FFFFFFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear reset */ + writel(value & 0x7FFFFEFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear bypass */ +} + +static void cs5530_configure_display(struct fb_info *info) +{ + struct geodefb_par *par = info->par; + u32 dcfg; + + dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG); + + /* Clear bits from existing mode. */ + dcfg &= ~(CS5530_DCFG_CRT_SYNC_SKW_MASK | CS5530_DCFG_PWR_SEQ_DLY_MASK + | CS5530_DCFG_CRT_HSYNC_POL | CS5530_DCFG_CRT_VSYNC_POL + | CS5530_DCFG_FP_PWR_EN | CS5530_DCFG_FP_DATA_EN + | CS5530_DCFG_DAC_PWR_EN | CS5530_DCFG_VSYNC_EN + | CS5530_DCFG_HSYNC_EN); + + /* Set default sync skew and power sequence delays. */ + dcfg |= (CS5530_DCFG_CRT_SYNC_SKW_INIT | CS5530_DCFG_PWR_SEQ_DLY_INIT + | CS5530_DCFG_GV_PAL_BYP); + + /* Enable DACs, hsync and vsync for CRTs */ + if (par->enable_crt) { + dcfg |= CS5530_DCFG_DAC_PWR_EN; + dcfg |= CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN; + } + /* Enable panel power and data if using a flat panel. */ + if (par->panel_x > 0) { + dcfg |= CS5530_DCFG_FP_PWR_EN; + dcfg |= CS5530_DCFG_FP_DATA_EN; + } + + /* Sync polarities. */ + if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) + dcfg |= CS5530_DCFG_CRT_HSYNC_POL; + if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) + dcfg |= CS5530_DCFG_CRT_VSYNC_POL; + + writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG); +} + +static int cs5530_blank_display(struct fb_info *info, int blank_mode) +{ + struct geodefb_par *par = info->par; + u32 dcfg; + int blank, hsync, vsync; + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + blank = 0; hsync = 1; vsync = 1; + break; + case FB_BLANK_NORMAL: + blank = 1; hsync = 1; vsync = 1; + break; + case FB_BLANK_VSYNC_SUSPEND: + blank = 1; hsync = 1; vsync = 0; + break; + case FB_BLANK_HSYNC_SUSPEND: + blank = 1; hsync = 0; vsync = 1; + break; + case FB_BLANK_POWERDOWN: + blank = 1; hsync = 0; vsync = 0; + break; + default: + return -EINVAL; + } + + dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG); + + dcfg &= ~(CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN + | CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN + | CS5530_DCFG_FP_DATA_EN | CS5530_DCFG_FP_PWR_EN); + + if (par->enable_crt) { + if (!blank) + dcfg |= CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN; + if (hsync) + dcfg |= CS5530_DCFG_HSYNC_EN; + if (vsync) + dcfg |= CS5530_DCFG_VSYNC_EN; + } + if (par->panel_x > 0) { + if (!blank) + dcfg |= CS5530_DCFG_FP_DATA_EN; + if (hsync && vsync) + dcfg |= CS5530_DCFG_FP_PWR_EN; + } + + writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG); + + return 0; +} + +struct geode_vid_ops cs5530_vid_ops = { + .set_dclk = cs5530_set_dclk_frequency, + .configure_display = cs5530_configure_display, + .blank_display = cs5530_blank_display, +}; diff --git a/drivers/video/geode/video_cs5530.h b/drivers/video/geode/video_cs5530.h new file mode 100644 index 000000000000..56cecca7f1ce --- /dev/null +++ b/drivers/video/geode/video_cs5530.h @@ -0,0 +1,75 @@ +/* + * drivers/video/geode/video_cs5530.h + * -- CS5530 video device + * + * Copyright (C) 2005 Arcom Control Systems Ltd. + * + * Based on AMD's original 2.4 driver: + * Copyright (C) 2004 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __VIDEO_CS5530_H__ +#define __VIDEO_CS5530_H__ + +extern struct geode_vid_ops cs5530_vid_ops; + +/* CS5530 Video device registers */ + +#define CS5530_VIDEO_CONFIG 0x0000 +# define CS5530_VCFG_VID_EN 0x00000001 +# define CS5530_VCFG_VID_REG_UPDATE 0x00000002 +# define CS5530_VCFG_VID_INP_FORMAT 0x0000000C +# define CS5530_VCFG_8_BIT_4_2_0 0x00000004 +# define CS5530_VCFG_16_BIT_4_2_0 0x00000008 +# define CS5530_VCFG_GV_SEL 0x00000010 +# define CS5530_VCFG_CSC_BYPASS 0x00000020 +# define CS5530_VCFG_X_FILTER_EN 0x00000040 +# define CS5530_VCFG_Y_FILTER_EN 0x00000080 +# define CS5530_VCFG_LINE_SIZE_LOWER_MASK 0x0000FF00 +# define CS5530_VCFG_INIT_READ_MASK 0x01FF0000 +# define CS5530_VCFG_EARLY_VID_RDY 0x02000000 +# define CS5530_VCFG_LINE_SIZE_UPPER 0x08000000 +# define CS5530_VCFG_4_2_0_MODE 0x10000000 +# define CS5530_VCFG_16_BIT_EN 0x20000000 +# define CS5530_VCFG_HIGH_SPD_INT 0x40000000 + +#define CS5530_DISPLAY_CONFIG 0x0004 +# define CS5530_DCFG_DIS_EN 0x00000001 +# define CS5530_DCFG_HSYNC_EN 0x00000002 +# define CS5530_DCFG_VSYNC_EN 0x00000004 +# define CS5530_DCFG_DAC_BL_EN 0x00000008 +# define CS5530_DCFG_DAC_PWR_EN 0x00000020 +# define CS5530_DCFG_FP_PWR_EN 0x00000040 +# define CS5530_DCFG_FP_DATA_EN 0x00000080 +# define CS5530_DCFG_CRT_HSYNC_POL 0x00000100 +# define CS5530_DCFG_CRT_VSYNC_POL 0x00000200 +# define CS5530_DCFG_FP_HSYNC_POL 0x00000400 +# define CS5530_DCFG_FP_VSYNC_POL 0x00000800 +# define CS5530_DCFG_XGA_FP 0x00001000 +# define CS5530_DCFG_FP_DITH_EN 0x00002000 +# define CS5530_DCFG_CRT_SYNC_SKW_MASK 0x0001C000 +# define CS5530_DCFG_CRT_SYNC_SKW_INIT 0x00010000 +# define CS5530_DCFG_PWR_SEQ_DLY_MASK 0x000E0000 +# define CS5530_DCFG_PWR_SEQ_DLY_INIT 0x00080000 +# define CS5530_DCFG_VG_CK 0x00100000 +# define CS5530_DCFG_GV_PAL_BYP 0x00200000 +# define CS5530_DCFG_DDC_SCL 0x00400000 +# define CS5530_DCFG_DDC_SDA 0x00800000 +# define CS5530_DCFG_DDC_OE 0x01000000 +# define CS5530_DCFG_16_BIT_EN 0x02000000 + +#define CS5530_VIDEO_X_POS 0x0008 +#define CS5530_VIDEO_Y_POS 0x000C +#define CS5530_VIDEO_SCALE 0x0010 +#define CS5530_VIDEO_COLOR_KEY 0x0014 +#define CS5530_VIDEO_COLOR_MASK 0x0018 +#define CS5530_PALETTE_ADDRESS 0x001C +#define CS5530_PALETTE_DATA 0x0020 +#define CS5530_DOT_CLK_CONFIG 0x0024 +#define CS5530_CRCSIG_TFT_TV 0x0028 + +#endif /* !__VIDEO_CS5530_H__ */ diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c new file mode 100644 index 000000000000..b37cea7d1094 --- /dev/null +++ b/drivers/video/hgafb.c @@ -0,0 +1,619 @@ +/* + * linux/drivers/video/hgafb.c -- Hercules graphics adaptor frame buffer device + * + * Created 25 Nov 1999 by Ferenc Bakonyi (fero@drama.obuda.kando.hu) + * Based on skeletonfb.c by Geert Uytterhoeven and + * mdacon.c by Andrew Apted + * + * History: + * + * - Revision 0.1.8 (23 Oct 2002): Ported to new framebuffer api. + * + * - Revision 0.1.7 (23 Jan 2001): fix crash resulting from MDA only cards + * being detected as Hercules. (Paul G.) + * - Revision 0.1.6 (17 Aug 2000): new style structs + * documentation + * - Revision 0.1.5 (13 Mar 2000): spinlocks instead of saveflags();cli();etc + * minor fixes + * - Revision 0.1.4 (24 Jan 2000): fixed a bug in hga_card_detect() for + * HGA-only systems + * - Revision 0.1.3 (22 Jan 2000): modified for the new fb_info structure + * screen is cleared after rmmod + * virtual resolutions + * module parameter 'nologo={0|1}' + * the most important: boot logo :) + * - Revision 0.1.0 (6 Dec 1999): faster scrolling and minor fixes + * - First release (25 Nov 1999) + * + * 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/kernel.h> +#include <linux/errno.h> +#include <linux/spinlock.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/ioport.h> +#include <asm/io.h> +#include <asm/vga.h> + +#if 0 +#define DPRINTK(args...) printk(KERN_DEBUG __FILE__": " ##args) +#else +#define DPRINTK(args...) +#endif + +#if 0 +#define CHKINFO(ret) if (info != &fb_info) { printk(KERN_DEBUG __FILE__": This should never happen, line:%d \n", __LINE__); return ret; } +#else +#define CHKINFO(ret) +#endif + +/* Description of the hardware layout */ + +static void __iomem *hga_vram; /* Base of video memory */ +static unsigned long hga_vram_len; /* Size of video memory */ + +#define HGA_ROWADDR(row) ((row%4)*8192 + (row>>2)*90) +#define HGA_TXT 0 +#define HGA_GFX 1 + +static inline u8 __iomem * rowaddr(struct fb_info *info, u_int row) +{ + return info->screen_base + HGA_ROWADDR(row); +} + +static int hga_mode = -1; /* 0 = txt, 1 = gfx mode */ + +static enum { TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } hga_type; +static char *hga_type_name; + +#define HGA_INDEX_PORT 0x3b4 /* Register select port */ +#define HGA_VALUE_PORT 0x3b5 /* Register value port */ +#define HGA_MODE_PORT 0x3b8 /* Mode control port */ +#define HGA_STATUS_PORT 0x3ba /* Status and Config port */ +#define HGA_GFX_PORT 0x3bf /* Graphics control port */ + +/* HGA register values */ + +#define HGA_CURSOR_BLINKING 0x00 +#define HGA_CURSOR_OFF 0x20 +#define HGA_CURSOR_SLOWBLINK 0x60 + +#define HGA_MODE_GRAPHICS 0x02 +#define HGA_MODE_VIDEO_EN 0x08 +#define HGA_MODE_BLINK_EN 0x20 +#define HGA_MODE_GFX_PAGE1 0x80 + +#define HGA_STATUS_HSYNC 0x01 +#define HGA_STATUS_VSYNC 0x80 +#define HGA_STATUS_VIDEO 0x08 + +#define HGA_CONFIG_COL132 0x08 +#define HGA_GFX_MODE_EN 0x01 +#define HGA_GFX_PAGE_EN 0x02 + +/* Global locks */ + +static DEFINE_SPINLOCK(hga_reg_lock); + +/* Framebuffer driver structures */ + +static struct fb_var_screeninfo hga_default_var = { + .xres = 720, + .yres = 348, + .xres_virtual = 720, + .yres_virtual = 348, + .bits_per_pixel = 1, + .red = {0, 1, 0}, + .green = {0, 1, 0}, + .blue = {0, 1, 0}, + .transp = {0, 0, 0}, + .height = -1, + .width = -1, +}; + +static struct fb_fix_screeninfo hga_fix = { + .id = "HGA", + .type = FB_TYPE_PACKED_PIXELS, /* (not sure) */ + .visual = FB_VISUAL_MONO10, + .xpanstep = 8, + .ypanstep = 8, + .line_length = 90, + .accel = FB_ACCEL_NONE +}; + +static struct fb_info fb_info; + +/* Don't assume that tty1 will be the initial current console. */ +static int release_io_port = 0; +static int release_io_ports = 0; +static int nologo = 0; + +/* ------------------------------------------------------------------------- + * + * Low level hardware functions + * + * ------------------------------------------------------------------------- */ + +static void write_hga_b(unsigned int val, unsigned char reg) +{ + outb_p(reg, HGA_INDEX_PORT); + outb_p(val, HGA_VALUE_PORT); +} + +static void write_hga_w(unsigned int val, unsigned char reg) +{ + outb_p(reg, HGA_INDEX_PORT); outb_p(val >> 8, HGA_VALUE_PORT); + outb_p(reg+1, HGA_INDEX_PORT); outb_p(val & 0xff, HGA_VALUE_PORT); +} + +static int test_hga_b(unsigned char val, unsigned char reg) +{ + outb_p(reg, HGA_INDEX_PORT); + outb (val, HGA_VALUE_PORT); + udelay(20); val = (inb_p(HGA_VALUE_PORT) == val); + return val; +} + +static void hga_clear_screen(void) +{ + unsigned char fillchar = 0xbf; /* magic */ + unsigned long flags; + + spin_lock_irqsave(&hga_reg_lock, flags); + if (hga_mode == HGA_TXT) + fillchar = ' '; + else if (hga_mode == HGA_GFX) + fillchar = 0x00; + spin_unlock_irqrestore(&hga_reg_lock, flags); + if (fillchar != 0xbf) + memset_io(hga_vram, fillchar, hga_vram_len); +} + +static void hga_txt_mode(void) +{ + unsigned long flags; + + spin_lock_irqsave(&hga_reg_lock, flags); + outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_BLINK_EN, HGA_MODE_PORT); + outb_p(0x00, HGA_GFX_PORT); + outb_p(0x00, HGA_STATUS_PORT); + + write_hga_b(0x61, 0x00); /* horizontal total */ + write_hga_b(0x50, 0x01); /* horizontal displayed */ + write_hga_b(0x52, 0x02); /* horizontal sync pos */ + write_hga_b(0x0f, 0x03); /* horizontal sync width */ + + write_hga_b(0x19, 0x04); /* vertical total */ + write_hga_b(0x06, 0x05); /* vertical total adjust */ + write_hga_b(0x19, 0x06); /* vertical displayed */ + write_hga_b(0x19, 0x07); /* vertical sync pos */ + + write_hga_b(0x02, 0x08); /* interlace mode */ + write_hga_b(0x0d, 0x09); /* maximum scanline */ + write_hga_b(0x0c, 0x0a); /* cursor start */ + write_hga_b(0x0d, 0x0b); /* cursor end */ + + write_hga_w(0x0000, 0x0c); /* start address */ + write_hga_w(0x0000, 0x0e); /* cursor location */ + + hga_mode = HGA_TXT; + spin_unlock_irqrestore(&hga_reg_lock, flags); +} + +static void hga_gfx_mode(void) +{ + unsigned long flags; + + spin_lock_irqsave(&hga_reg_lock, flags); + outb_p(0x00, HGA_STATUS_PORT); + outb_p(HGA_GFX_MODE_EN, HGA_GFX_PORT); + outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT); + + write_hga_b(0x35, 0x00); /* horizontal total */ + write_hga_b(0x2d, 0x01); /* horizontal displayed */ + write_hga_b(0x2e, 0x02); /* horizontal sync pos */ + write_hga_b(0x07, 0x03); /* horizontal sync width */ + + write_hga_b(0x5b, 0x04); /* vertical total */ + write_hga_b(0x02, 0x05); /* vertical total adjust */ + write_hga_b(0x57, 0x06); /* vertical displayed */ + write_hga_b(0x57, 0x07); /* vertical sync pos */ + + write_hga_b(0x02, 0x08); /* interlace mode */ + write_hga_b(0x03, 0x09); /* maximum scanline */ + write_hga_b(0x00, 0x0a); /* cursor start */ + write_hga_b(0x00, 0x0b); /* cursor end */ + + write_hga_w(0x0000, 0x0c); /* start address */ + write_hga_w(0x0000, 0x0e); /* cursor location */ + + hga_mode = HGA_GFX; + spin_unlock_irqrestore(&hga_reg_lock, flags); +} + +static void hga_show_logo(struct fb_info *info) +{ +/* + void __iomem *dest = hga_vram; + char *logo = linux_logo_bw; + int x, y; + + for (y = 134; y < 134 + 80 ; y++) * this needs some cleanup * + for (x = 0; x < 10 ; x++) + writeb(~*(logo++),(dest + HGA_ROWADDR(y) + x + 40)); +*/ +} + +static void hga_pan(unsigned int xoffset, unsigned int yoffset) +{ + unsigned int base; + unsigned long flags; + + base = (yoffset / 8) * 90 + xoffset; + spin_lock_irqsave(&hga_reg_lock, flags); + write_hga_w(base, 0x0c); /* start address */ + spin_unlock_irqrestore(&hga_reg_lock, flags); + DPRINTK("hga_pan: base:%d\n", base); +} + +static void hga_blank(int blank_mode) +{ + unsigned long flags; + + spin_lock_irqsave(&hga_reg_lock, flags); + if (blank_mode) { + outb_p(0x00, HGA_MODE_PORT); /* disable video */ + } else { + outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT); + } + spin_unlock_irqrestore(&hga_reg_lock, flags); +} + +static int __init hga_card_detect(void) +{ + int count=0; + void __iomem *p, *q; + unsigned short p_save, q_save; + + hga_vram_len = 0x08000; + + hga_vram = ioremap(0xb0000, hga_vram_len); + + if (request_region(0x3b0, 12, "hgafb")) + release_io_ports = 1; + if (request_region(0x3bf, 1, "hgafb")) + release_io_port = 1; + + /* do a memory check */ + + p = hga_vram; + q = hga_vram + 0x01000; + + p_save = readw(p); q_save = readw(q); + + writew(0xaa55, p); if (readw(p) == 0xaa55) count++; + writew(0x55aa, p); if (readw(p) == 0x55aa) count++; + writew(p_save, p); + + if (count != 2) { + return 0; + } + + /* Ok, there is definitely a card registering at the correct + * memory location, so now we do an I/O port test. + */ + + if (!test_hga_b(0x66, 0x0f)) { /* cursor low register */ + return 0; + } + if (!test_hga_b(0x99, 0x0f)) { /* cursor low register */ + return 0; + } + + /* See if the card is a Hercules, by checking whether the vsync + * bit of the status register is changing. This test lasts for + * approximately 1/10th of a second. + */ + + p_save = q_save = inb_p(HGA_STATUS_PORT) & HGA_STATUS_VSYNC; + + for (count=0; count < 50000 && p_save == q_save; count++) { + q_save = inb(HGA_STATUS_PORT) & HGA_STATUS_VSYNC; + udelay(2); + } + + if (p_save == q_save) + return 0; + + switch (inb_p(HGA_STATUS_PORT) & 0x70) { + case 0x10: + hga_type = TYPE_HERCPLUS; + hga_type_name = "HerculesPlus"; + break; + case 0x50: + hga_type = TYPE_HERCCOLOR; + hga_type_name = "HerculesColor"; + break; + default: + hga_type = TYPE_HERC; + hga_type_name = "Hercules"; + break; + } + return 1; +} + +/** + * hgafb_open - open the framebuffer device + * @info:pointer to fb_info object containing info for current hga board + * @int:open by console system or userland. + */ + +static int hgafb_open(struct fb_info *info, int init) +{ + hga_gfx_mode(); + hga_clear_screen(); + if (!nologo) hga_show_logo(info); + return 0; +} + +/** + * hgafb_open - open the framebuffer device + * @info:pointer to fb_info object containing info for current hga board + * @int:open by console system or userland. + */ + +static int hgafb_release(struct fb_info *info, int init) +{ + hga_txt_mode(); + hga_clear_screen(); + return 0; +} + +/** + * hgafb_setcolreg - set color registers + * @regno:register index to set + * @red:red value, unused + * @green:green value, unused + * @blue:blue value, unused + * @transp:transparency value, unused + * @info:unused + * + * This callback function is used to set the color registers of a HGA + * board. Since we have only two fixed colors only @regno is checked. + * A zero is returned on success and 1 for failure. + */ + +static int hgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + if (regno > 1) + return 1; + return 0; +} + +/** + * hga_pan_display - pan or wrap the display + * @var:contains new xoffset, yoffset and vmode values + * @info:pointer to fb_info object containing info for current hga board + * + * This function looks only at xoffset, yoffset and the %FB_VMODE_YWRAP + * flag in @var. If input parameters are correct it calls hga_pan() to + * program the hardware. @info->var is updated to the new values. + * A zero is returned on success and %-EINVAL for failure. + */ + +static int hgafb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset < 0 || + var->yoffset >= info->var.yres_virtual || + var->xoffset) + return -EINVAL; + } else { + if (var->xoffset + var->xres > info->var.xres_virtual + || var->yoffset + var->yres > info->var.yres_virtual + || var->yoffset % 8) + return -EINVAL; + } + + hga_pan(var->xoffset, var->yoffset); + return 0; +} + +/** + * hgafb_blank - (un)blank the screen + * @blank_mode:blanking method to use + * @info:unused + * + * Blank the screen if blank_mode != 0, else unblank. + * Implements VESA suspend and powerdown modes on hardware that supports + * disabling hsync/vsync: + * @blank_mode == 2 means suspend vsync, + * @blank_mode == 3 means suspend hsync, + * @blank_mode == 4 means powerdown. + */ + +static int hgafb_blank(int blank_mode, struct fb_info *info) +{ + hga_blank(blank_mode); + return 0; +} + +/* + * Accel functions + */ +#ifdef CONFIG_FB_HGA_ACCEL +static void hgafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + u_int rows, y; + u8 __iomem *dest; + + y = rect->dy; + + for (rows = rect->height; rows--; y++) { + dest = rowaddr(info, y) + (rect->dx >> 3); + switch (rect->rop) { + case ROP_COPY: + //fb_memset(dest, rect->color, (rect->width >> 3)); + break; + case ROP_XOR: + fb_writeb(~(fb_readb(dest)), dest); + break; + } + } +} + +static void hgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + u_int rows, y1, y2; + u8 __iomem *src; + u8 __iomem *dest; + + if (area->dy <= area->sy) { + y1 = area->sy; + y2 = area->dy; + + for (rows = area->height; rows--; ) { + src = rowaddr(info, y1) + (area->sx >> 3); + dest = rowaddr(info, y2) + (area->dx >> 3); + //fb_memmove(dest, src, (area->width >> 3)); + y1++; + y2++; + } + } else { + y1 = area->sy + area->height - 1; + y2 = area->dy + area->height - 1; + + for (rows = area->height; rows--;) { + src = rowaddr(info, y1) + (area->sx >> 3); + dest = rowaddr(info, y2) + (area->dx >> 3); + //fb_memmove(dest, src, (area->width >> 3)); + y1--; + y2--; + } + } +} + +static void hgafb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + u8 __iomem *dest; + u8 *cdat = (u8 *) image->data; + u_int rows, y = image->dy; + u8 d; + + for (rows = image->height; rows--; y++) { + d = *cdat++; + dest = rowaddr(info, y) + (image->dx >> 3); + fb_writeb(d, dest); + } +} +#else /* !CONFIG_FB_HGA_ACCEL */ +#define hgafb_fillrect cfb_fillrect +#define hgafb_copyarea cfb_copyarea +#define hgafb_imageblit cfb_imageblit +#endif /* CONFIG_FB_HGA_ACCEL */ + + +static struct fb_ops hgafb_ops = { + .owner = THIS_MODULE, + .fb_open = hgafb_open, + .fb_release = hgafb_release, + .fb_setcolreg = hgafb_setcolreg, + .fb_pan_display = hgafb_pan_display, + .fb_blank = hgafb_blank, + .fb_fillrect = hgafb_fillrect, + .fb_copyarea = hgafb_copyarea, + .fb_imageblit = hgafb_imageblit, +}; + +/* ------------------------------------------------------------------------- * + * + * Functions in fb_info + * + * ------------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------------- */ + + /* + * Initialization + */ + +static int __init hgafb_init(void) +{ + if (fb_get_options("hgafb", NULL)) + return -ENODEV; + + if (! hga_card_detect()) { + printk(KERN_INFO "hgafb: HGA card not detected.\n"); + if (hga_vram) + iounmap(hga_vram); + return -EINVAL; + } + + printk(KERN_INFO "hgafb: %s with %ldK of memory detected.\n", + hga_type_name, hga_vram_len/1024); + + hga_fix.smem_start = (unsigned long)hga_vram; + hga_fix.smem_len = hga_vram_len; + + fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + fb_info.var = hga_default_var; + fb_info.fix = hga_fix; + fb_info.monspecs.hfmin = 0; + fb_info.monspecs.hfmax = 0; + fb_info.monspecs.vfmin = 10000; + fb_info.monspecs.vfmax = 10000; + fb_info.monspecs.dpms = 0; + fb_info.fbops = &hgafb_ops; + fb_info.screen_base = hga_vram; + + if (register_framebuffer(&fb_info) < 0) { + iounmap(hga_vram); + return -EINVAL; + } + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + fb_info.node, fb_info.fix.id); + return 0; +} + +#ifdef MODULE +static void __exit hgafb_exit(void) +{ + hga_txt_mode(); + hga_clear_screen(); + unregister_framebuffer(&fb_info); + iounmap(hga_vram); + if (release_io_ports) release_region(0x3b0, 12); + if (release_io_port) release_region(0x3bf, 1); +} +#endif + +/* ------------------------------------------------------------------------- + * + * Modularization + * + * ------------------------------------------------------------------------- */ + +MODULE_AUTHOR("Ferenc Bakonyi (fero@drama.obuda.kando.hu)"); +MODULE_DESCRIPTION("FBDev driver for Hercules Graphics Adaptor"); +MODULE_LICENSE("GPL"); + +module_param(nologo, bool, 0); +MODULE_PARM_DESC(nologo, "Disables startup logo if != 0 (default=0)"); +module_init(hgafb_init); + +#ifdef MODULE +module_exit(hgafb_exit); +#endif diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c new file mode 100644 index 000000000000..0d376ba54814 --- /dev/null +++ b/drivers/video/hitfb.c @@ -0,0 +1,350 @@ +/* + * linux/drivers/video/hitfb.c -- Hitachi LCD frame buffer device + * + * (C) 1999 Mihai Spatar + * (C) 2000 YAEGASHI Takeshi + * (C) 2003, 2004 Paul Mundt + * (C) 2003, 2004 Andriy Skulysh + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#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/init.h> +#include <linux/fb.h> + +#include <asm/machvec.h> +#include <asm/uaccess.h> +#include <asm/pgtable.h> +#include <asm/io.h> +#include <asm/hd64461/hd64461.h> + +#ifdef MACH_HP600 +#include <asm/cpu/dac.h> +#include <asm/hp6xx/hp6xx.h> +#endif + +#define WIDTH 640 + +static struct fb_var_screeninfo hitfb_var __initdata = { + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo hitfb_fix __initdata = { + .id = "Hitachi HD64461", + .type = FB_TYPE_PACKED_PIXELS, + .ypanstep = 8, + .accel = FB_ACCEL_NONE, +}; + +static u32 pseudo_palette[16]; +static struct fb_info fb_info; + +static inline void hitfb_accel_wait(void) +{ + while (fb_readw(HD64461_GRCFGR) & HD64461_GRCFGR_ACCSTATUS) ; +} + +static inline void hitfb_accel_start(int truecolor) +{ + if (truecolor) { + fb_writew(6, HD64461_GRCFGR); + } else { + fb_writew(7, HD64461_GRCFGR); + } +} + +static inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy, + u16 width, u16 height) +{ + u32 saddr = WIDTH * dy + dx; + if (truecolor) + saddr <<= 1; + + fb_writew(width, HD64461_BBTDWR); + fb_writew(height, HD64461_BBTDHR); + + fb_writew(saddr & 0xffff, HD64461_BBTDSARL); + fb_writew(saddr >> 16, HD64461_BBTDSARH); + +} + +static inline void hitfb_accel_solidfill(int truecolor, u16 dx, u16 dy, + u16 width, u16 height, u16 color) +{ + hitfb_accel_set_dest(truecolor, dx, dy, width, height); + + fb_writew(0x00f0, HD64461_BBTROPR); + fb_writew(16, HD64461_BBTMDR); + fb_writew(color, HD64461_GRSCR); + + hitfb_accel_start(truecolor); +} + +static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx, + u16 dy, u16 width, u16 height, u16 rop, + u32 mask_addr) +{ + u32 saddr, daddr; + u32 maddr = 0; + + fb_writew(rop, HD64461_BBTROPR); + if ((sy < dy) || ((sy == dy) && (sx <= dx))) { + saddr = WIDTH * (sy + height) + sx + width; + daddr = WIDTH * (dy + height) + dx + width; + if (mask_addr) { + if (truecolor) + maddr = ((width >> 3) + 1) * (height + 1) - 1; + else + maddr = + (((width >> 4) + 1) * (height + 1) - 1) * 2; + + fb_writew((1 << 5) | 1, HD64461_BBTMDR); + } else + fb_writew(1, HD64461_BBTMDR); + } else { + saddr = WIDTH * sy + sx; + daddr = WIDTH * dy + dx; + if (mask_addr) { + fb_writew((1 << 5), HD64461_BBTMDR); + } else { + fb_writew(0, HD64461_BBTMDR); + } + } + if (truecolor) { + saddr <<= 1; + daddr <<= 1; + } + fb_writew(width, HD64461_BBTDWR); + fb_writew(height, HD64461_BBTDHR); + fb_writew(saddr & 0xffff, HD64461_BBTSSARL); + fb_writew(saddr >> 16, HD64461_BBTSSARH); + fb_writew(daddr & 0xffff, HD64461_BBTDSARL); + fb_writew(daddr >> 16, HD64461_BBTDSARH); + if (mask_addr) { + maddr += mask_addr; + fb_writew(maddr & 0xffff, HD64461_BBTMARL); + fb_writew(maddr >> 16, HD64461_BBTMARH); + } + hitfb_accel_start(truecolor); +} + +static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) +{ + if (rect->rop != ROP_COPY) + cfb_fillrect(p, rect); + else { + fb_writew(0x00f0, HD64461_BBTROPR); + fb_writew(16, HD64461_BBTMDR); + + if (p->var.bits_per_pixel == 16) { + fb_writew(((u32 *) (p->pseudo_palette))[rect->color], + HD64461_GRSCR); + hitfb_accel_set_dest(1, rect->dx, rect->dy, rect->width, + rect->height); + hitfb_accel_start(1); + } else { + fb_writew(rect->color, HD64461_GRSCR); + hitfb_accel_set_dest(0, rect->dx, rect->dy, rect->width, + rect->height); + hitfb_accel_start(0); + } + hitfb_accel_wait(); + } +} + +static void hitfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) +{ + hitfb_accel_bitblt(p->var.bits_per_pixel == 16, area->sx, area->sy, + area->dx, area->dy, area->width, area->height, + 0x00cc, 0); + hitfb_accel_wait(); +} + +static int hitfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int xoffset = var->xoffset; + int yoffset = var->yoffset; + + if (xoffset != 0) + return -EINVAL; + + fb_writew(yoffset, HD64461_LCDCBAR); + + return 0; +} + +int hitfb_blank(int blank_mode, struct fb_info *info) +{ + unsigned short v; + + if (blank_mode) { +#ifdef MACH_HP600 + sh_dac_disable(DAC_LCD_BRIGHTNESS); + v = fb_readw(HD64461_GPBDR); + v |= HD64461_GPBDR_LCDOFF; + fb_writew(v, HD64461_GPBDR); +#endif + v = fb_readw(HD64461_LDR1); + v &= ~HD64461_LDR1_DON; + fb_writew(v, HD64461_LDR1); + + v = fb_readw(HD64461_LCDCCR); + v |= HD64461_LCDCCR_MOFF; + fb_writew(v, HD64461_LCDCCR); + + v = fb_readw(HD64461_STBCR); + v |= HD64461_STBCR_SLCDST; + fb_writew(v, HD64461_STBCR); + } else { + v = fb_readw(HD64461_STBCR); + v &= ~HD64461_STBCR_SLCDST; + fb_writew(v, HD64461_STBCR); +#ifdef MACH_HP600 + sh_dac_enable(DAC_LCD_BRIGHTNESS); + v = fb_readw(HD64461_GPBDR); + v &= ~HD64461_GPBDR_LCDOFF; + fb_writew(v, HD64461_GPBDR); +#endif + v = fb_readw(HD64461_LDR1); + v |= HD64461_LDR1_DON; + fb_writew(v, HD64461_LDR1); + + v = fb_readw(HD64461_LCDCCR); + v &= ~HD64461_LCDCCR_MOFF; + fb_writew(v, HD64461_LCDCCR); + } + return 0; +} + +static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + if (regno >= info->cmap.len) + return 1; + + switch (info->var.bits_per_pixel) { + case 8: + fb_writew(regno << 8, HD64461_CPTWAR); + fb_writew(red >> 10, HD64461_CPTWDR); + fb_writew(green >> 10, HD64461_CPTWDR); + fb_writew(blue >> 10, HD64461_CPTWDR); + break; + case 16: + ((u32 *) (info->pseudo_palette))[regno] = + ((red & 0xf800)) | + ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); + break; + } + return 0; +} + +static struct fb_ops hitfb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = hitfb_setcolreg, + .fb_blank = hitfb_blank, + .fb_pan_display = hitfb_pan_display, + .fb_fillrect = hitfb_fillrect, + .fb_copyarea = hitfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +int __init hitfb_init(void) +{ + unsigned short lcdclor, ldr3, ldvndr; + int size; + + if (fb_get_options("hitfb", NULL)) + return -ENODEV; + + hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000; + hitfb_fix.smem_len = (MACH_HP690) ? 1024 * 1024 : 512 * 1024; + + lcdclor = fb_readw(HD64461_LCDCLOR); + ldvndr = fb_readw(HD64461_LDVNDR); + ldr3 = fb_readw(HD64461_LDR3); + + switch (ldr3 & 15) { + default: + case 4: + hitfb_var.bits_per_pixel = 8; + hitfb_var.xres = lcdclor; + break; + case 8: + hitfb_var.bits_per_pixel = 16; + hitfb_var.xres = lcdclor / 2; + break; + } + hitfb_fix.line_length = lcdclor; + hitfb_fix.visual = (hitfb_var.bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + hitfb_var.yres = ldvndr + 1; + hitfb_var.xres_virtual = hitfb_var.xres; + hitfb_var.yres_virtual = hitfb_fix.smem_len / lcdclor; + switch (hitfb_var.bits_per_pixel) { + case 8: + hitfb_var.red.offset = 0; + hitfb_var.red.length = 8; + hitfb_var.green.offset = 0; + hitfb_var.green.length = 8; + hitfb_var.blue.offset = 0; + hitfb_var.blue.length = 8; + hitfb_var.transp.offset = 0; + hitfb_var.transp.length = 0; + break; + case 16: /* RGB 565 */ + hitfb_var.red.offset = 11; + hitfb_var.red.length = 5; + hitfb_var.green.offset = 5; + hitfb_var.green.length = 6; + hitfb_var.blue.offset = 0; + hitfb_var.blue.length = 5; + hitfb_var.transp.offset = 0; + hitfb_var.transp.length = 0; + break; + } + + fb_info.fbops = &hitfb_ops; + fb_info.var = hitfb_var; + fb_info.fix = hitfb_fix; + fb_info.pseudo_palette = pseudo_palette; + fb_info.flags = FBINFO_DEFAULT; + + fb_info.screen_base = (void *)hitfb_fix.smem_start; + + size = (fb_info.var.bits_per_pixel == 8) ? 256 : 16; + fb_alloc_cmap(&fb_info.cmap, size, 0); + + if (register_framebuffer(&fb_info) < 0) + return -EINVAL; + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + fb_info.node, fb_info.fix.id); + return 0; +} + +static void __exit hitfb_exit(void) +{ + unregister_framebuffer(&fb_info); +} + +module_init(hitfb_init); +module_exit(hitfb_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c new file mode 100644 index 000000000000..e97fe8481d59 --- /dev/null +++ b/drivers/video/hpfb.c @@ -0,0 +1,416 @@ +/* + * HP300 Topcat framebuffer support (derived from macfb of all things) + * Phil Blundell <philb@gnu.org> 1998 + * DIO-II, colour map and Catseye support by + * Kars de Jong <jongk@linux-m68k.org>, May 2004. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#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/init.h> +#include <linux/fb.h> +#include <linux/dio.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +static struct fb_info fb_info = { + .fix = { + .id = "HP300 ", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .accel = FB_ACCEL_NONE, + } +}; + +static unsigned long fb_regs; +static unsigned char fb_bitmask; + +#define TC_NBLANK 0x4080 +#define TC_WEN 0x4088 +#define TC_REN 0x408c +#define TC_FBEN 0x4090 +#define TC_PRR 0x40ea + +/* These defines match the X window system */ +#define RR_CLEAR 0x0 +#define RR_COPY 0x3 +#define RR_NOOP 0x5 +#define RR_XOR 0x6 +#define RR_INVERT 0xa +#define RR_COPYINVERTED 0xc +#define RR_SET 0xf + +/* blitter regs */ +#define BUSY 0x4044 +#define WMRR 0x40ef +#define SOURCE_X 0x40f2 +#define SOURCE_Y 0x40f6 +#define DEST_X 0x40fa +#define DEST_Y 0x40fe +#define WHEIGHT 0x4106 +#define WWIDTH 0x4102 +#define WMOVE 0x409c + +static struct fb_var_screeninfo hpfb_defined = { + .red = { + .length = 8, + }, + .green = { + .length = 8, + }, + .blue = { + .length = 8, + }, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static int hpfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + /* use MSBs */ + unsigned char _red =red>>8; + unsigned char _green=green>>8; + unsigned char _blue =blue>>8; + unsigned char _regno=regno; + + /* + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return + * != 0 for invalid regno. + */ + + if (regno >= info->cmap.len) + return 1; + + while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1); + + out_be16(fb_regs + 0x60ba, 0xff); + + out_be16(fb_regs + 0x60b2, _red); + out_be16(fb_regs + 0x60b4, _green); + out_be16(fb_regs + 0x60b6, _blue); + out_be16(fb_regs + 0x60b8, ~_regno); + out_be16(fb_regs + 0x60f0, 0xff); + + udelay(100); + + while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1); + out_be16(fb_regs + 0x60b2, 0); + out_be16(fb_regs + 0x60b4, 0); + out_be16(fb_regs + 0x60b6, 0); + out_be16(fb_regs + 0x60b8, 0); + + return 0; +} + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ + +static int hpfb_blank(int blank, struct fb_info *info) +{ + out_8(fb_regs + TC_NBLANK, (blank ? 0x00 : fb_bitmask)); + + return 0; +} + +static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h, int rr) +{ + if (rr >= 0) { + while (in_8(fb_regs + BUSY) & fb_bitmask) + ; + } + out_8(fb_regs + TC_FBEN, fb_bitmask); + if (rr >= 0) { + out_8(fb_regs + TC_WEN, fb_bitmask); + out_8(fb_regs + WMRR, rr); + } + out_be16(fb_regs + SOURCE_X, x0); + out_be16(fb_regs + SOURCE_Y, y0); + out_be16(fb_regs + DEST_X, x1); + out_be16(fb_regs + DEST_Y, y1); + out_be16(fb_regs + WWIDTH, w); + out_be16(fb_regs + WHEIGHT, h); + out_8(fb_regs + WMOVE, fb_bitmask); +} + +static void hpfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + topcat_blit(area->sx, area->sy, area->dx, area->dy, area->width, area->height, RR_COPY); +} + +static void hpfb_fillrect(struct fb_info *p, const struct fb_fillrect *region) +{ + u8 clr; + + clr = region->color & 0xff; + + while (in_8(fb_regs + BUSY) & fb_bitmask) + ; + + /* Foreground */ + out_8(fb_regs + TC_WEN, fb_bitmask & clr); + out_8(fb_regs + WMRR, (region->rop == ROP_COPY ? RR_SET : RR_INVERT)); + + /* Background */ + out_8(fb_regs + TC_WEN, fb_bitmask & ~clr); + out_8(fb_regs + WMRR, (region->rop == ROP_COPY ? RR_CLEAR : RR_NOOP)); + + topcat_blit(region->dx, region->dy, region->dx, region->dy, region->width, region->height, -1); +} + +static int hpfb_sync(struct fb_info *info) +{ + /* + * Since we also access the framebuffer directly, we have to wait + * until the block mover is finished + */ + while (in_8(fb_regs + BUSY) & fb_bitmask) + ; + + out_8(fb_regs + TC_WEN, fb_bitmask); + out_8(fb_regs + TC_PRR, RR_COPY); + out_8(fb_regs + TC_FBEN, fb_bitmask); + + return 0; +} + +static struct fb_ops hpfb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = hpfb_setcolreg, + .fb_blank = hpfb_blank, + .fb_fillrect = hpfb_fillrect, + .fb_copyarea = hpfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + .fb_sync = hpfb_sync, +}; + +/* Common to all HP framebuffers */ +#define HPFB_FBWMSB 0x05 /* Frame buffer width */ +#define HPFB_FBWLSB 0x07 +#define HPFB_FBHMSB 0x09 /* Frame buffer height */ +#define HPFB_FBHLSB 0x0b +#define HPFB_DWMSB 0x0d /* Display width */ +#define HPFB_DWLSB 0x0f +#define HPFB_DHMSB 0x11 /* Display height */ +#define HPFB_DHLSB 0x13 +#define HPFB_NUMPLANES 0x5b /* Number of colour planes */ +#define HPFB_FBOMSB 0x5d /* Frame buffer offset */ +#define HPFB_FBOLSB 0x5f + +static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base) +{ + unsigned long fboff, fb_width, fb_height, fb_start; + + fb_regs = virt_base; + fboff = (in_8(fb_regs + HPFB_FBOMSB) << 8) | in_8(fb_regs + HPFB_FBOLSB); + + fb_info.fix.smem_start = (in_8(fb_regs + fboff) << 16); + + if (phys_base >= DIOII_BASE) { + fb_info.fix.smem_start += phys_base; + } + + if (DIO_SECID(fb_regs) != DIO_ID2_TOPCAT) { + /* This is the magic incantation the HP X server uses to make Catseye boards work. */ + while (in_be16(fb_regs+0x4800) & 1) + ; + out_be16(fb_regs+0x4800, 0); /* Catseye status */ + out_be16(fb_regs+0x4510, 0); /* VB */ + out_be16(fb_regs+0x4512, 0); /* TCNTRL */ + out_be16(fb_regs+0x4514, 0); /* ACNTRL */ + out_be16(fb_regs+0x4516, 0); /* PNCNTRL */ + out_be16(fb_regs+0x4206, 0x90); /* RUG Command/Status */ + out_be16(fb_regs+0x60a2, 0); /* Overlay Mask */ + out_be16(fb_regs+0x60bc, 0); /* Ram Select */ + } + + /* + * Fill in the available video resolution + */ + fb_width = (in_8(fb_regs + HPFB_FBWMSB) << 8) | in_8(fb_regs + HPFB_FBWLSB); + fb_info.fix.line_length = fb_width; + fb_height = (in_8(fb_regs + HPFB_FBHMSB) << 8) | in_8(fb_regs + HPFB_FBHLSB); + fb_info.fix.smem_len = fb_width * fb_height; + fb_start = (unsigned long)ioremap_writethrough(fb_info.fix.smem_start, + fb_info.fix.smem_len); + hpfb_defined.xres = (in_8(fb_regs + HPFB_DWMSB) << 8) | in_8(fb_regs + HPFB_DWLSB); + hpfb_defined.yres = (in_8(fb_regs + HPFB_DHMSB) << 8) | in_8(fb_regs + HPFB_DHLSB); + hpfb_defined.xres_virtual = hpfb_defined.xres; + hpfb_defined.yres_virtual = hpfb_defined.yres; + hpfb_defined.bits_per_pixel = in_8(fb_regs + HPFB_NUMPLANES); + + printk(KERN_INFO "hpfb: framebuffer at 0x%lx, mapped to 0x%lx, size %dk\n", + fb_info.fix.smem_start, fb_start, fb_info.fix.smem_len/1024); + printk(KERN_INFO "hpfb: mode is %dx%dx%d, linelength=%d\n", + hpfb_defined.xres, hpfb_defined.yres, hpfb_defined.bits_per_pixel, fb_info.fix.line_length); + + /* + * Give the hardware a bit of a prod and work out how many bits per + * pixel are supported. + */ + out_8(fb_regs + TC_WEN, 0xff); + out_8(fb_regs + TC_PRR, RR_COPY); + out_8(fb_regs + TC_FBEN, 0xff); + out_8(fb_start, 0xff); + fb_bitmask = in_8(fb_start); + out_8(fb_start, 0); + + /* + * Enable reading/writing of all the planes. + */ + out_8(fb_regs + TC_WEN, fb_bitmask); + out_8(fb_regs + TC_PRR, RR_COPY); + out_8(fb_regs + TC_REN, fb_bitmask); + out_8(fb_regs + TC_FBEN, fb_bitmask); + + /* + * Clear the screen. + */ + topcat_blit(0, 0, 0, 0, fb_width, fb_height, RR_CLEAR); + + /* + * Let there be consoles.. + */ + if (DIO_SECID(fb_regs) == DIO_ID2_TOPCAT) + strcat(fb_info.fix.id, "Topcat"); + else + strcat(fb_info.fix.id, "Catseye"); + fb_info.fbops = &hpfb_ops; + fb_info.flags = FBINFO_DEFAULT; + fb_info.var = hpfb_defined; + fb_info.screen_base = (char *)fb_start; + + fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0); + + if (register_framebuffer(&fb_info) < 0) { + fb_dealloc_cmap(&fb_info.cmap); + return 1; + } + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + fb_info.node, fb_info.fix.id); + + return 0; +} + +/* + * Check that the secondary ID indicates that we have some hope of working with this + * framebuffer. The catseye boards are pretty much like topcats and we can muddle through. + */ + +#define topcat_sid_ok(x) (((x) == DIO_ID2_LRCATSEYE) || ((x) == DIO_ID2_HRCCATSEYE) \ + || ((x) == DIO_ID2_HRMCATSEYE) || ((x) == DIO_ID2_TOPCAT)) + +/* + * Initialise the framebuffer + */ +static int __devinit hpfb_dio_probe(struct dio_dev * d, const struct dio_device_id * ent) +{ + unsigned long paddr, vaddr; + + paddr = d->resource.start; + if (!request_mem_region(d->resource.start, d->resource.end - d->resource.start, d->name)) + return -EBUSY; + + if (d->scode >= DIOII_SCBASE) { + vaddr = (unsigned long)ioremap(paddr, d->resource.end - d->resource.start); + } else { + vaddr = paddr + DIO_VIRADDRBASE; + } + printk(KERN_INFO "Topcat found at DIO select code %d " + "(secondary id %02x)\n", d->scode, (d->id >> 8) & 0xff); + if (hpfb_init_one(paddr, vaddr)) { + if (d->scode >= DIOII_SCBASE) + iounmap((void *)vaddr); + return -ENOMEM; + } + return 0; +} + +static void __devexit hpfb_remove_one(struct dio_dev *d) +{ + unregister_framebuffer(&fb_info); + if (d->scode >= DIOII_SCBASE) + iounmap((void *)fb_regs); + release_mem_region(d->resource.start, d->resource.end - d->resource.start); +} + +static struct dio_device_id hpfb_dio_tbl[] = { + { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_LRCATSEYE) }, + { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRCCATSEYE) }, + { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRMCATSEYE) }, + { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_TOPCAT) }, + { 0 } +}; + +static struct dio_driver hpfb_driver = { + .name = "hpfb", + .id_table = hpfb_dio_tbl, + .probe = hpfb_dio_probe, + .remove = __devexit_p(hpfb_remove_one), +}; + +int __init hpfb_init(void) +{ + unsigned int sid; + mm_segment_t fs; + unsigned char i; + int err; + + /* Topcats can be on the internal IO bus or real DIO devices. + * The internal variant sits at 0x560000; it has primary + * and secondary ID registers just like the DIO version. + * So we merge the two detection routines. + * + * Perhaps this #define should be in a global header file: + * I believe it's common to all internal fbs, not just topcat. + */ +#define INTFBVADDR 0xf0560000 +#define INTFBPADDR 0x560000 + + if (!MACH_IS_HP300) + return -ENXIO; + + if (fb_get_options("hpfb", NULL)) + return -ENODEV; + + dio_module_init(&hpfb_driver); + + fs = get_fs(); + set_fs(KERNEL_DS); + err = get_user(i, (unsigned char *)INTFBVADDR + DIO_IDOFF); + set_fs(fs); + + if (!err && (i == DIO_ID_FBUFFER) && topcat_sid_ok(sid = DIO_SECID(INTFBVADDR))) { + if (!request_mem_region(INTFBPADDR, DIO_DEVSIZE, "Internal Topcat")) + return -EBUSY; + printk(KERN_INFO "Internal Topcat found (secondary id %02x)\n", sid); + if (hpfb_init_one(INTFBPADDR, INTFBVADDR)) { + return -ENOMEM; + } + } + return 0; +} + +void __exit hpfb_cleanup_module(void) +{ + dio_unregister_driver(&hpfb_driver); +} + +module_init(hpfb_init); +module_exit(hpfb_cleanup_module); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/i810/Makefile b/drivers/video/i810/Makefile new file mode 100644 index 000000000000..794ae76c7c4b --- /dev/null +++ b/drivers/video/i810/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the Intel 810/815 framebuffer driver +# + +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 diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h new file mode 100644 index 000000000000..fe3b75794756 --- /dev/null +++ b/drivers/video/i810/i810.h @@ -0,0 +1,285 @@ +/*-*- 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 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 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 +#define USE_HWCUR 16 + +struct gtt_data { + struct agp_memory *i810_fb_memory; + struct agp_memory *i810_cursor_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 __iomem *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 vgastate state; + atomic_t use_count; + u32 pseudo_palette[17]; + unsigned long mmio_start_phys; + u8 __iomem *mmio_start_virtual; + 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; + u32 cur_state; + 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..64cd1c827cf0 --- /dev/null +++ b/drivers/video/i810/i810_accel.c @@ -0,0 +1,449 @@ +/*-*- 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/string.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 void flush_cache(void); + +/************************************************************/ + +/* BLT Engine Routines */ +static inline void i810_report_error(u8 __iomem *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 fb_info *info, u32 space) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u32 head, count = WAIT_COUNT, tail; + u8 __iomem *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; + info->pixmap.scan_align = 1; + 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 fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u8 __iomem *mmio = par->mmio_start_virtual; + int count = WAIT_COUNT; + + if (wait_for_space(info, par->iring.size)) /* flush */ + return 1; + + 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; + info->pixmap.scan_align = 1; + 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 fb_info *info, u32 space) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + + if (par->dev_flags & ALWAYS_SYNC) + wait_for_engine_idle(info); + return wait_for_space(info, 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 __iomem *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 fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + + if (begin_iring(info, 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 fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + + if (begin_iring(info, 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 fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + + if (begin_iring(info, 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); + while (dsize--) + PUT_RING(*src++); + + end_iring(par); +} + +static inline void load_front(int offset, struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + + if (begin_iring(info, 8 + IRING_PAD)) return; + + PUT_RING(PARSER | FLUSH); + PUT_RING(NOP); + + end_iring(par); + + if (begin_iring(info, 8 + IRING_PAD)) return; + + PUT_RING(PARSER | FRONT_BUFFER | ((par->pitch >> 3) << 8)); + PUT_RING((par->fb.offset << 12) + offset); + + end_iring(par); +} + +/** + * 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 __iomem *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 *info, const struct fb_fillrect *rect) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u32 dx, dy, width, height, dest, rop = 0, color = 0; + + if (!info->var.accel_flags || par->dev_flags & LOCKUP || + par->depth == 4) + return cfb_fillrect(info, rect); + + if (par->depth == 1) + color = rect->color; + else + color = ((u32 *) (info->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 = info->fix.smem_start + (dy * info->fix.line_length) + dx; + color_blit(width, height, info->fix.line_length, dest, rop, color, + par->blit_bpp, info); +} + +void i810fb_copyarea(struct fb_info *info, const struct fb_copyarea *region) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u32 sx, sy, dx, dy, pitch, width, height, src, dest, xdir; + + if (!info->var.accel_flags || par->dev_flags & LOCKUP || + par->depth == 4) + return cfb_copyarea(info, region); + + 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 = info->fix.line_length; + } + else { + pitch = (-(info->fix.line_length)) & 0xFFFF; + sy += height - 1; + dy += height - 1; + } + src = info->fix.smem_start + (sy * info->fix.line_length) + sx; + dest = info->fix.smem_start + (dy * info->fix.line_length) + dx; + + source_copy_blit(width, height, pitch, xdir, src, dest, + PAT_COPY_ROP, par->blit_bpp, info); +} + +void i810fb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u32 fg = 0, bg = 0, size, dst; + + if (!info->var.accel_flags || par->dev_flags & LOCKUP || + par->depth == 4 || image->depth != 1) + return cfb_imageblit(info, image); + + switch (info->var.bits_per_pixel) { + case 8: + fg = image->fg_color; + bg = image->bg_color; + break; + case 16: + case 24: + fg = ((u32 *)(info->pseudo_palette))[image->fg_color]; + bg = ((u32 *)(info->pseudo_palette))[image->bg_color]; + break; + } + + dst = info->fix.smem_start + (image->dy * info->fix.line_length) + + (image->dx * par->depth); + + size = (image->width+7)/8 + 1; + size &= ~1; + size *= image->height; + size += 7; + size &= ~7; + mono_src_copy_imm_blit(image->width * par->depth, + image->height, info->fix.line_length, + size/4, par->blit_bpp, + PAT_COPY_ROP, dst, (u32 *) image->data, + bg, fg, info); +} + +int i810fb_sync(struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + + if (!info->var.accel_flags || par->dev_flags & LOCKUP) + return 0; + + return wait_for_engine_idle(info); +} + +void i810fb_load_front(u32 offset, struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u8 __iomem *mmio = par->mmio_start_virtual; + + if (!info->var.accel_flags || par->dev_flags & LOCKUP) + i810_writel(DPLYBASE, mmio, par->fb.physical + offset); + else + load_front(offset, info); +} + +/** + * 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 fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u32 tmp1, tmp2; + u8 __iomem *mmio = par->mmio_start_virtual; + + wait_for_engine_idle(info); + 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..27fa703a2e0a --- /dev/null +++ b/drivers/video/i810/i810_dvt.c @@ -0,0 +1,307 @@ +/*-*- 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 <= 640) + *xres = 640; + else if (*xres <= 800) + *xres = 800; + else if (*xres <= 1024) + *xres = 1024; + else if (*xres <= 1152) + *xres = 1152; + else if (*xres <= 1280) + *xres = 1280; + else + *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..64f087a4466b --- /dev/null +++ b/drivers/video/i810/i810_gtf.c @@ -0,0 +1,275 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810_main.h -- Intel 810 Non-discrete 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; +}; + +static 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 }, +}; + +static 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 }, +}; + +static 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 }, +}; + +static 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 }, +}; + +static 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 }, +}; + +static 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 __iomem *mmio = par->mmio_start_virtual; + u8 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: + * Gets 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 = NULL; + 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..9ec8781794c0 --- /dev/null +++ b/drivers/video/i810/i810_main.c @@ -0,0 +1,2062 @@ + /*-*- 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" + +/* 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[] = { + { 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 }, + { 0 }, +}; + +static struct pci_driver i810fb_driver = { + .name = "i810fb", + .id_table = i810fb_pci_tbl, + .probe = i810fb_init_pci, + .remove = __exit_p(i810fb_remove_pci), + .suspend = i810fb_suspend, + .resume = i810fb_resume, +}; + +static int vram __initdata = 4; +static int bpp __initdata = 8; +static int mtrr __initdata = 0; +static int accel __initdata = 0; +static int hsync1 __initdata = 0; +static int hsync2 __initdata = 0; +static int vsync1 __initdata = 0; +static int vsync2 __initdata = 0; +static int xres __initdata = 640; +static int yres __initdata = 480; +static int vyres __initdata = 0; +static int sync __initdata = 0; +static int ext_vga __initdata = 0; +static int dcolor __initdata = 0; + +/*------------------------------------------------------------*/ + +/************************************************************** + * 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 __iomem *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 __iomem *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 __iomem *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 __iomem *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 __iomem *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 __iomem *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; + u8 __iomem *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 __iomem *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; + u8 __iomem *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 __iomem *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 __iomem *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 __iomem *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 __iomem *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 __iomem *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 __iomem *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; + u8 __iomem *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; + u8 __iomem *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; + u8 __iomem *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 __iomem *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 __iomem *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; + u8 __iomem *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; + u8 __iomem *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 __iomem *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. + */ +static 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); +} + +/************************************************************* + * 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 + */ +static void i810_enable_cursor(u8 __iomem *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 __iomem *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 __iomem *addr = par->cursor_heap.virtual; + int i, j, w = width/8; + int mod = width % 8, t_mask, d_mask; + + t_mask = 0xff >> mod; + d_mask = ~(0xff >> mod); + for (i = height; i--; ) { + for (j = 0; j < w; j++) { + i810_writeb(j+0, addr, 0x00); + i810_writeb(j+8, addr, *data++); + } + if (mod) { + i810_writeb(j+0, addr, t_mask); + i810_writeb(j+8, addr, *data++ & d_mask); + } + 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 __iomem *mmio = par->mmio_start_virtual; + u8 red, green, blue, trans, temp; + + 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 __iomem *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: + var->green.length = (var->green.length == 5) ? 5 : 6; + var->red.length = 5; + var->blue.length = 5; + var->transp.length = 6 - var->green.length; + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 5 + var->green.length; + var->transp.offset = (5 + var->red.offset) & 15; + 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; + var->transp.length = var->bits_per_pixel - 24; + var->transp.offset = (var->transp.length) ? 24 : 0; + 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 + */ + switch (var->bits_per_pixel) { + case 8: + info->monspecs.dclkmax = 234000000; + break; + case 16: + info->monspecs.dclkmax = 229000000; + break; + case 24: + case 32: + info->monspecs.dclkmax = 204000000; + break; + } + info->monspecs.dclkmin = 15000000; + + if (fb_validate_mode(var, info)) { + if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) + 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, "I810"); + 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 = par->pitch; + 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 + * + * 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) +{ + 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 __iomem *mmio = par->mmio_start_virtual; + u8 temp; + + 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 = 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 __iomem *mmio = par->mmio_start_virtual; + u8 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) { + u8 r, g, b; + + if (regno < 32) { + for (i = 0; i < 8; i++) + i810_write_dac((u8) (regno * 8) + i, + (u8) red, (u8) green, + (u8) blue, mmio); + } + i810_read_dac((u8) (regno*4), &r, &g, &b, mmio); + for (i = 0; i < 4; i++) + i810_write_dac((u8) (regno*4) + i, r, (u8) green, + b, mmio); + } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { + 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; + + total = var->xoffset * par->depth + + var->yoffset * info->fix.line_length; + i810fb_load_front(total, info); + + return 0; +} + +static int i810fb_blank (int blank_mode, struct fb_info *info) +{ + struct i810fb_par *par = (struct i810fb_par *) info->par; + u8 __iomem *mmio = par->mmio_start_virtual; + int mode = 0, pwr, scr_off = 0; + + pwr = i810_readl(PWR_CLKC, mmio); + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + mode = POWERON; + pwr |= 1; + scr_off = ON; + break; + case FB_BLANK_NORMAL: + mode = POWERON; + pwr |= 1; + scr_off = OFF; + break; + case FB_BLANK_VSYNC_SUSPEND: + mode = STANDBY; + pwr |= 1; + scr_off = OFF; + break; + case FB_BLANK_HSYNC_SUSPEND: + mode = SUSPEND; + pwr |= 1; + scr_off = OFF; + break; + case FB_BLANK_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; + + decode_var(&info->var, par); + i810_load_regs(par); + i810_init_cursor(par); + + encode_fix(&info->fix, info); + + if (info->var.accel_flags && !(par->dev_flags & LOCKUP)) { + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_IMAGEBLIT; + info->pixmap.scan_align = 2; + } else { + info->pixmap.scan_align = 1; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + } + return 0; +} + +static int i810fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + 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); + return 0; +} + +static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct i810fb_par *par = (struct i810fb_par *)info->par; + u8 __iomem *mmio = par->mmio_start_virtual; + + if (!(par->dev_flags & USE_HWCUR) || !info->var.accel_flags || + par->dev_flags & LOCKUP) + return soft_cursor(info, cursor); + + if (cursor->image.width > 64 || cursor->image.height > 64) + return -ENXIO; + + if ((i810_readl(CURBASE, mmio) & 0xf) != par->cursor_heap.physical) { + i810_init_cursor(par); + cursor->set |= FB_CUR_SETALL; + } + + i810_enable_cursor(mmio, OFF); + + if (cursor->set & FB_CUR_SETPOS) { + u32 tmp; + + tmp = (cursor->image.dx - info->var.xoffset) & 0xffff; + tmp |= (cursor->image.dy - info->var.yoffset) << 16; + i810_writel(CURPOS, mmio, tmp); + } + + if (cursor->set & FB_CUR_SETSIZE) + i810_reset_cursor_image(par); + + if (cursor->set & FB_CUR_SETCMAP) + i810_load_cursor_colors(cursor->image.fg_color, + cursor->image.bg_color, + info); + + if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { + int size = ((cursor->image.width + 7) >> 3) * + cursor->image.height; + int i; + u8 *data = kmalloc(64 * 8, GFP_KERNEL); + + if (data == NULL) + return -ENOMEM; + + switch (cursor->rop) { + case ROP_XOR: + for (i = 0; i < size; i++) + data[i] = cursor->image.data[i] ^ cursor->mask[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); + kfree(data); + } + + if (cursor->enable) + i810_enable_cursor(mmio, ON); + + return 0; +} + +static struct fb_ops i810fb_ops __devinitdata = { + .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, + .fb_sync = i810fb_sync, +}; + +/*********************************************************************** + * Power Management * + ***********************************************************************/ +static int i810fb_suspend(struct pci_dev *dev, pm_message_t state) +{ + struct fb_info *info = pci_get_drvdata(dev); + struct i810fb_par *par = (struct i810fb_par *) info->par; + int blank = 0, prev_state = par->cur_state; + + if (state == prev_state) + return 0; + + par->cur_state = state; + + switch (state) { + case 1: + blank = VESA_VSYNC_SUSPEND; + break; + case 2: + blank = VESA_HSYNC_SUSPEND; + break; + case 3: + blank = VESA_POWERDOWN; + break; + default: + return -EINVAL; + } + info->fbops->fb_blank(blank, info); + + if (!prev_state) { + agp_unbind_memory(par->i810_gtt.i810_fb_memory); + agp_unbind_memory(par->i810_gtt.i810_cursor_memory); + pci_disable_device(dev); + } + pci_save_state(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); + + return 0; +} + +static int i810fb_resume(struct pci_dev *dev) +{ + struct fb_info *info = pci_get_drvdata(dev); + struct i810fb_par *par = (struct i810fb_par *) info->par; + + if (par->cur_state == 0) + return 0; + + pci_restore_state(dev); + pci_set_power_state(dev, PCI_D0); + pci_enable_device(dev); + agp_bind_memory(par->i810_gtt.i810_fb_memory, + par->fb.offset); + agp_bind_memory(par->i810_gtt.i810_cursor_memory, + par->cursor_heap.offset); + + info->fbops->fb_blank(VESA_NO_BLANKING, info); + + par->cur_state = 0; + + return 0; +} +/*********************************************************************** + * 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); +} + +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->cursor_heap.offset = par->iring.offset + (RINGBUFFER_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; + struct agp_bridge_data *bridge; + + i810_fix_offsets(par); + size = par->fb.size + par->iring.size; + + if (!(bridge = agp_backend_acquire(par->dev))) { + printk("i810fb_alloc_fbmem: cannot acquire agpgart\n"); + return -ENODEV; + } + if (!(par->i810_gtt.i810_fb_memory = + agp_allocate_memory(bridge, size >> 12, AGP_NORMAL_MEMORY))) { + printk("i810fb_alloc_fbmem: can't allocate framebuffer " + "memory\n"); + agp_backend_release(bridge); + return -ENOMEM; + } + if (agp_bind_memory(par->i810_gtt.i810_fb_memory, + par->fb.offset)) { + printk("i810fb_alloc_fbmem: can't bind framebuffer memory\n"); + agp_backend_release(bridge); + return -EBUSY; + } + + if (!(par->i810_gtt.i810_cursor_memory = + agp_allocate_memory(bridge, par->cursor_heap.size >> 12, + AGP_PHYSICAL_MEMORY))) { + printk("i810fb_alloc_cursormem: can't allocate" + "cursor memory\n"); + agp_backend_release(bridge); + return -ENOMEM; + } + if (agp_bind_memory(par->i810_gtt.i810_cursor_memory, + par->cursor_heap.offset)) { + printk("i810fb_alloc_cursormem: cannot bind cursor memory\n"); + agp_backend_release(bridge); + return -EBUSY; + } + + par->cursor_heap.physical = par->i810_gtt.i810_cursor_memory->physical; + + i810_fix_pointers(par); + + agp_backend_release(bridge); + + 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; + if (!info->monspecs.hfmax) + info->monspecs.hfmax = hsync2; + if (!info->monspecs.hfmin) + 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; + if (!info->monspecs.vfmax) + info->monspecs.vfmax = vsync2; + if (!info->monspecs.vfmin) + 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; + info->var.xres = xres; + info->var.yres = yres; + info->var.yres_virtual = vyres; + info->var.bits_per_pixel = bpp; + + if (dcolor) + info->var.nonstd = 1; + + if (par->dev_flags & HAS_ACCELERATION) + info->var.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; + u8 __iomem *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; + +} + +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_nocache(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; +} + +#ifndef MODULE +static int __init i810fb_setup(char *options) +{ + char *this_opt, *suffix = NULL; + + 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; +} +#endif + +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 i, err = -1, vfreq, hfreq, pixclock; + + i = 0; + + info = framebuffer_alloc(sizeof(struct i810fb_par), &dev->dev); + if (!info) + return -ENOMEM; + + par = (struct i810fb_par *) info->par; + par->dev = dev; + + if (!(info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL))) { + i810fb_release_resource(info, par); + return -ENOMEM; + } + memset(info->pixmap.addr, 0, 8*1024); + info->pixmap.size = 8*1024; + info->pixmap.buf_align = 8; + info->pixmap.flags = FB_PIXMAP_SYSTEM; + + 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->fbops = &par->i810fb_ops; + info->pseudo_palette = par->pseudo_palette; + fb_alloc_cmap(&info->cmap, 256, 0); + + if ((err = info->fbops->fb_check_var(&info->var, info))) { + i810fb_release_resource(info, par); + return err; + } + encode_fix(&info->fix, info); + + i810fb_init_ringbuffer(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("I810FB: fb%d : %s v%d.%d.%d%s\n" + "I810FB: Video RAM : %dK\n" + "I810FB: Monitor : H: %d-%d KHz V: %d-%d Hz\n" + "I810FB: Mode : %dx%d-%dbpp@%dHz\n", + info->node, + i810_pci_list[entry->driver_data], + VERSION_MAJOR, VERSION_MINOR, VERSION_TEENIE, BRANCH_VERSION, + (int) par->fb.size>>10, info->monspecs.hfmin/1000, + info->monspecs.hfmax/1000, info->monspecs.vfmin, + info->monspecs.vfmax, info->var.xres, + info->var.yres, info->var.bits_per_pixel, vfreq); + return 0; +} + +/*************************************************************** + * De-initialization * + ***************************************************************/ + +static void i810fb_release_resource(struct fb_info *info, + struct i810fb_par *par) +{ + struct gtt_data *gtt = &par->i810_gtt; + unset_mtrr(par); + + 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); + + 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); + + framebuffer_release(info); + +} + +static void __exit 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 +static int __init i810fb_init(void) +{ + char *option = NULL; + + if (fb_get_options("i810fb", &option)) + return -ENODEV; + i810fb_setup(option); + + return pci_register_driver(&i810fb_driver); +} +#endif + +/********************************************************************* + * Modularization * + *********************************************************************/ + +#ifdef MODULE + +static int __init i810fb_init(void) +{ + hsync1 *= 1000; + hsync2 *= 1000; + + return pci_register_driver(&i810fb_driver); +} + +module_param(vram, int, 0); +MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB" + " (default=4)"); +module_param(voffset, int, 0); +MODULE_PARM_DESC(voffset, "at what offset to place start of framebuffer " + "memory (0 to maximum aperture size), in MiB (default = 48)"); +module_param(bpp, int, 0); +MODULE_PARM_DESC(bpp, "Color depth for display in bits per pixel" + " (default = 8)"); +module_param(xres, int, 0); +MODULE_PARM_DESC(xres, "Horizontal resolution in pixels (default = 640)"); +module_param(yres, int, 0); +MODULE_PARM_DESC(yres, "Vertical resolution in scanlines (default = 480)"); +module_param(vyres,int, 0); +MODULE_PARM_DESC(vyres, "Virtual vertical resolution in scanlines" + " (default = 480)"); +module_param(hsync1, int, 0); +MODULE_PARM_DESC(hsync1, "Minimum horizontal frequency of monitor in KHz" + " (default = 31)"); +module_param(hsync2, int, 0); +MODULE_PARM_DESC(hsync2, "Maximum horizontal frequency of monitor in KHz" + " (default = 31)"); +module_param(vsync1, int, 0); +MODULE_PARM_DESC(vsync1, "Minimum vertical frequency of monitor in Hz" + " (default = 50)"); +module_param(vsync2, int, 0); +MODULE_PARM_DESC(vsync2, "Maximum vertical frequency of monitor in Hz" + " (default = 60)"); +module_param(accel, bool, 0); +MODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)"); +module_param(mtrr, bool, 0); +MODULE_PARM_DESC(mtrr, "Use MTRR (default = 0)"); +module_param(ext_vga, bool, 0); +MODULE_PARM_DESC(ext_vga, "Enable external VGA connector (default = 0)"); +module_param(sync, bool, 0); +MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing" + " (default = 0)"); +module_param(dcolor, bool, 0); +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_exit(i810fb_exit); + +#endif /* MODULE */ + +module_init(i810fb_init); diff --git a/drivers/video/i810/i810_main.h b/drivers/video/i810/i810_main.h new file mode 100644 index 000000000000..43b4297b4d48 --- /dev/null +++ b/drivers/video/i810/i810_main.h @@ -0,0 +1,127 @@ +/*-*- 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__ + +static int __devinit i810fb_init_pci (struct pci_dev *dev, + const struct pci_device_id *entry); +static void __exit i810fb_remove_pci(struct pci_dev *dev); +static int i810fb_resume(struct pci_dev *dev); +static int i810fb_suspend(struct pci_dev *dev, pm_message_t state); + +/* + * 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 __initdata; /* For 32 MiB Aper size, 8 should be the default */ +static u32 voffset __initdata = 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); + + +/* 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, + const struct fb_fillrect *rect); +extern void i810fb_copyarea (struct fb_info *p, + const struct fb_copyarea *region); +extern void i810fb_imageblit(struct fb_info *p, const struct fb_image *image); +extern int i810fb_sync (struct fb_info *p); + +extern void i810fb_init_ringbuffer(struct fb_info *info); +extern void i810fb_load_front (u32 offset, struct fb_info *info); + +/* Conditionals */ +#ifdef CONFIG_X86 +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(KERN_ERR "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 new file mode 100644 index 000000000000..e326f44f652d --- /dev/null +++ b/drivers/video/igafb.c @@ -0,0 +1,579 @@ +/* + * linux/drivers/video/igafb.c -- Frame buffer device for IGA 1682 + * + * Copyright (C) 1998 Vladimir Roganov and Gleb Raiko + * + * This driver is partly based on the Frame buffer device for ATI Mach64 + * and partially on VESA-related code. + * + * Copyright (C) 1997-1998 Geert Uytterhoeven + * Copyright (C) 1998 Bernd Harries + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * + * 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: + Despite of IGA Card has advanced graphic acceleration, + initial version is almost dummy and does not support it. + Support for video modes and acceleration must be added + together with accelerated X-Windows driver implementation. + + Most important thing at this moment is that we have working + JavaEngine1 console & X with new console interface. + +******************************************************************************/ + +#include <linux/module.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/nvram.h> + +#include <asm/io.h> + +#ifdef __sparc__ +#include <asm/pbm.h> +#include <asm/pcic.h> +#endif + +#include <video/iga.h> + +struct pci_mmap_map { + unsigned long voff; + unsigned long poff; + unsigned long size; + unsigned long prot_flag; + unsigned long prot_mask; +}; + +struct iga_par { + struct pci_mmap_map *mmap_map; + unsigned long frame_buffer_phys; + unsigned long io_base; +}; + +struct fb_info fb_info; + +struct fb_fix_screeninfo igafb_fix __initdata = { + .id = "IGA 1682", + .type = FB_TYPE_PACKED_PIXELS, + .mmio_len = 1000 +}; + +struct fb_var_screeninfo default_var = { + /* 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) */ + .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) */ + .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) */ + .xres = 1280, + .yres = 1024, + .xres_virtual = 1280, + .yres_virtual = 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 +}; + +/* + * Memory-mapped I/O functions for Sparc PCI + * + * On sparc we happen to access I/O with memory mapped functions too. + */ +#define pci_inb(par, reg) readb(par->io_base+(reg)) +#define pci_outb(par, val, reg) writeb(val, par->io_base+(reg)) + +static inline unsigned int iga_inb(struct iga_par *par, unsigned int reg, + unsigned int idx) +{ + pci_outb(par, idx, reg); + return pci_inb(par, reg + 1); +} + +static inline void iga_outb(struct iga_par *par, unsigned char val, + unsigned int reg, unsigned int idx ) +{ + pci_outb(par, idx, reg); + pci_outb(par, val, reg+1); +} + +#endif /* __sparc__ */ + +/* + * Very important functionality for the JavaEngine1 computer: + * make screen border black (usign special IGA registers) + */ +static void iga_blank_border(struct iga_par *par) +{ + int i; +#if 0 + /* + * PROM does this for us, so keep this code as a reminder + * about required read from 0x3DA and writing of 0x20 in the end. + */ + (void) pci_inb(par, 0x3DA); /* required for every access */ + pci_outb(par, IGA_IDX_VGA_OVERSCAN, IGA_ATTR_CTL); + (void) pci_inb(par, IGA_ATTR_CTL+1); + pci_outb(par, 0x38, IGA_ATTR_CTL); + pci_outb(par, 0x20, IGA_ATTR_CTL); /* re-enable visual */ +#endif + /* + * This does not work as it was designed because the overscan + * color is looked up in the palette. Therefore, under X11 + * overscan changes color. + */ + for (i=0; i < 3; i++) + iga_outb(par, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i); +} + +#ifdef __sparc__ +static int igafb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + struct iga_par *par = (struct iga_par *)info->par; + unsigned int size, page, map_size = 0; + unsigned long map_offset = 0; + int i; + + if (!par->mmap_map) + return -ENXIO; + + size = vma->vm_end - vma->vm_start; + + /* To stop the swapper from even considering these pages. */ + vma->vm_flags |= (VM_SHM | VM_LOCKED); + + /* Each page, see which map applies */ + for (page = 0; page < size; ) { + map_size = 0; + for (i = 0; par->mmap_map[i].size; i++) { + unsigned long start = par->mmap_map[i].voff; + unsigned long end = start + par->mmap_map[i].size; + unsigned long offset = (vma->vm_pgoff << PAGE_SHIFT) + page; + + if (start > offset) + continue; + if (offset >= end) + continue; + + map_size = par->mmap_map[i].size - (offset - start); + map_offset = par->mmap_map[i].poff + (offset - start); + break; + } + if (!map_size) { + page += PAGE_SIZE; + continue; + } + if (page + map_size > size) + map_size = size - page; + + pgprot_val(vma->vm_page_prot) &= ~(par->mmap_map[i].prot_mask); + pgprot_val(vma->vm_page_prot) |= par->mmap_map[i].prot_flag; + + if (remap_pfn_range(vma, vma->vm_start + page, + map_offset >> PAGE_SHIFT, map_size, vma->vm_page_prot)) + return -EAGAIN; + + page += map_size; + } + + if (!map_size) + return -EINVAL; + + vma->vm_flags |= VM_IO; + return 0; +} +#endif /* __sparc__ */ + +static int igafb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + /* + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return + * != 0 for invalid regno. + */ + struct iga_par *par = (struct iga_par *)info->par; + + if (regno >= info->cmap.len) + return 1; + + pci_outb(par, regno, DAC_W_INDEX); + pci_outb(par, red, DAC_DATA); + pci_outb(par, green, DAC_DATA); + pci_outb(par, blue, DAC_DATA); + + if (regno < 16) { + switch (info->var.bits_per_pixel) { + case 16: + ((u16*)(info->pseudo_palette))[regno] = + (regno << 10) | (regno << 5) | regno; + break; + case 24: + ((u32*)(info->pseudo_palette))[regno] = + (regno << 16) | (regno << 8) | regno; + break; + case 32: + { int i; + i = (regno << 8) | regno; + ((u32*)(info->pseudo_palette))[regno] = (i << 16) | i; + } + break; + } + } + return 0; +} + +/* + * Framebuffer option structure + */ +static struct fb_ops igafb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = igafb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +#ifdef __sparc__ + .fb_mmap = igafb_mmap, +#endif +}; + +static int __init iga_init(struct fb_info *info, struct iga_par *par) +{ + char vramsz = iga_inb(par, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL) + & MEM_SIZE_ALIAS; + int video_cmap_len; + + switch (vramsz) { + case MEM_SIZE_1M: + info->fix.smem_len = 0x100000; + break; + case MEM_SIZE_2M: + info->fix.smem_len = 0x200000; + break; + case MEM_SIZE_4M: + case MEM_SIZE_RESERVED: + info->fix.smem_len = 0x400000; + break; + } + + if (info->var.bits_per_pixel > 8) + video_cmap_len = 16; + else + video_cmap_len = 256; + + info->fbops = &igafb_ops; + info->flags = FBINFO_DEFAULT; + + fb_alloc_cmap(&info->cmap, video_cmap_len, 0); + + if (register_framebuffer(info) < 0) + return 0; + + printk("fb%d: %s frame buffer device at 0x%08lx [%dMB VRAM]\n", + info->node, info->fix.id, + par->frame_buffer_phys, info->fix.smem_len >> 20); + + iga_blank_border(par); + return 1; +} + +int __init igafb_init(void) +{ + extern int con_is_present(void); + struct fb_info *info; + struct pci_dev *pdev; + struct iga_par *par; + unsigned long addr; + int size, iga2000 = 0; + + if (fb_get_options("igafb", NULL)) + return -ENODEV; + + /* Do not attach when we have a serial console. */ + if (!con_is_present()) + return -ENXIO; + + pdev = pci_find_device(PCI_VENDOR_ID_INTERG, + PCI_DEVICE_ID_INTERG_1682, 0); + if (pdev == NULL) { + /* + * XXX We tried to use cyber2000fb.c for IGS 2000. + * But it does not initialize the chip in JavaStation-E, alas. + */ + pdev = pci_find_device(PCI_VENDOR_ID_INTERG, 0x2000, 0); + if(pdev == NULL) { + return -ENXIO; + } + iga2000 = 1; + } + + size = sizeof(struct fb_info) + sizeof(struct iga_par) + sizeof(u32)*16; + + info = kmalloc(size, GFP_ATOMIC); + if (!info) { + printk("igafb_init: can't alloc fb_info\n"); + return -ENOMEM; + } + memset(info, 0, size); + + par = (struct iga_par *) (info + 1); + + + if ((addr = pdev->resource[0].start) == 0) { + printk("igafb_init: no memory start\n"); + kfree(info); + return -ENXIO; + } + + if ((info->screen_base = ioremap(addr, 1024*1024*2)) == 0) { + printk("igafb_init: can't remap %lx[2M]\n", addr); + kfree(info); + return -ENXIO; + } + + par->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK; + +#ifdef __sparc__ + /* + * The following is sparc specific and this is why: + * + * IGS2000 has its I/O memory mapped and we want + * to generate memory cycles on PCI, e.g. do ioremap(), + * then readb/writeb() as in Documentation/IO-mapping.txt. + * + * IGS1682 is more traditional, it responds to PCI I/O + * cycles, so we want to access it with inb()/outb(). + * + * On sparc, PCIC converts CPU memory access within + * phys window 0x3000xxxx into PCI I/O cycles. Therefore + * we may use readb/writeb to access them with IGS1682. + * + * We do not take io_base_phys from resource[n].start + * on IGS1682 because that chip is BROKEN. It does not + * have a base register for I/O. We just "know" what its + * I/O addresses are. + */ + if (iga2000) { + igafb_fix.mmio_start = par->frame_buffer_phys | 0x00800000; + } else { + igafb_fix.mmio_start = 0x30000000; /* XXX */ + } + if ((par->io_base = (int) ioremap(igafb_fix.mmio_start, igafb_fix.smem_len)) == 0) { + printk("igafb_init: can't remap %lx[4K]\n", igafb_fix.mmio_start); + iounmap((void *)info->screen_base); + kfree(info); + return -ENXIO; + } + + /* + * Figure mmap addresses from PCI config space. + * We need two regions: for video memory and for I/O ports. + * Later one can add region for video coprocessor registers. + * However, mmap routine loops until size != 0, so we put + * one additional region with size == 0. + */ + + par->mmap_map = kmalloc(4 * sizeof(*par->mmap_map), GFP_ATOMIC); + if (!par->mmap_map) { + printk("igafb_init: can't alloc mmap_map\n"); + iounmap((void *)par->io_base); + iounmap(info->screen_base); + kfree(info); + return -ENOMEM; + } + + memset(par->mmap_map, 0, 4 * sizeof(*par->mmap_map)); + + /* + * Set default vmode and cmode from PROM properties. + */ + { + struct pcidev_cookie *cookie = pdev->sysdata; + int node = cookie->prom_node; + int width = prom_getintdefault(node, "width", 1024); + int height = prom_getintdefault(node, "height", 768); + int depth = prom_getintdefault(node, "depth", 8); + switch (width) { + case 1024: + if (height == 768) + default_var = default_var_1024x768; + break; + case 1152: + if (height == 900) + default_var = default_var_1152x900; + break; + case 1280: + if (height == 1024) + default_var = default_var_1280x1024; + break; + default: + break; + } + + switch (depth) { + case 8: + default_var.bits_per_pixel = 8; + break; + case 16: + default_var.bits_per_pixel = 16; + break; + case 24: + default_var.bits_per_pixel = 24; + break; + case 32: + default_var.bits_per_pixel = 32; + break; + default: + break; + } + } + +#endif + igafb_fix.smem_start = (unsigned long) info->screen_base; + igafb_fix.line_length = default_var.xres*(default_var.bits_per_pixel/8); + igafb_fix.visual = default_var.bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + + info->var = default_var; + info->fix = igafb_fix; + info->pseudo_palette = (void *)(par + 1); + info->device = &pdev->dev; + + if (!iga_init(info, par)) { + iounmap((void *)par->io_base); + iounmap(info->screen_base); + kfree(par->mmap_map); + kfree(info); + } + +#ifdef __sparc__ + /* + * Add /dev/fb mmap values. + */ + + /* First region is for video memory */ + par->mmap_map[0].voff = 0x0; + par->mmap_map[0].poff = par->frame_buffer_phys & PAGE_MASK; + par->mmap_map[0].size = info->fix.smem_len & PAGE_MASK; + par->mmap_map[0].prot_mask = SRMMU_CACHE; + par->mmap_map[0].prot_flag = SRMMU_WRITE; + + /* Second region is for I/O ports */ + par->mmap_map[1].voff = par->frame_buffer_phys & PAGE_MASK; + par->mmap_map[1].poff = info->fix.smem_start & PAGE_MASK; + par->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */ + par->mmap_map[1].prot_mask = SRMMU_CACHE; + par->mmap_map[1].prot_flag = SRMMU_WRITE; +#endif /* __sparc__ */ + + return 0; +} + +int __init igafb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + } + return 0; +} + +module_init(igafb_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c new file mode 100644 index 000000000000..5a72ca3c0138 --- /dev/null +++ b/drivers/video/imsttfb.c @@ -0,0 +1,1626 @@ +/* + * drivers/video/imsttfb.c -- frame buffer device for IMS TwinTurbo + * + * This file is derived from the powermac console "imstt" driver: + * Copyright (C) 1997 Sigurdur Asgeirsson + * With additional hacking by Jeffrey Kuskin (jsk@mojave.stanford.edu) + * Modified by Danilo Beuche 1998 + * Some register values added by Damien Doligez, INRIA Rocquencourt + * Various cleanups by Paul Mundt (lethal@chaoticdreams.org) + * + * This file was written by Ryan Nielsen (ran@krazynet.com) + * Most of the frame buffer device stuff was copied from atyfb.c + * + * 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/config.h> +#include <linux/module.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <asm/io.h> +#include <asm/uaccess.h> + +#if defined(CONFIG_PPC) +#include <linux/nvram.h> +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#include "macmodes.h" +#endif + +#ifndef __powerpc__ +#define eieio() /* Enforce In-order Execution of I/O */ +#endif + +/* TwinTurbo (Cosmo) registers */ +enum { + S1SA = 0, /* 0x00 */ + S2SA = 1, /* 0x04 */ + SP = 2, /* 0x08 */ + DSA = 3, /* 0x0C */ + CNT = 4, /* 0x10 */ + DP_OCTL = 5, /* 0x14 */ + CLR = 6, /* 0x18 */ + BI = 8, /* 0x20 */ + MBC = 9, /* 0x24 */ + BLTCTL = 10, /* 0x28 */ + + /* Scan Timing Generator Registers */ + HES = 12, /* 0x30 */ + HEB = 13, /* 0x34 */ + HSB = 14, /* 0x38 */ + HT = 15, /* 0x3C */ + VES = 16, /* 0x40 */ + VEB = 17, /* 0x44 */ + VSB = 18, /* 0x48 */ + VT = 19, /* 0x4C */ + HCIV = 20, /* 0x50 */ + VCIV = 21, /* 0x54 */ + TCDR = 22, /* 0x58 */ + VIL = 23, /* 0x5C */ + STGCTL = 24, /* 0x60 */ + + /* Screen Refresh Generator Registers */ + SSR = 25, /* 0x64 */ + HRIR = 26, /* 0x68 */ + SPR = 27, /* 0x6C */ + CMR = 28, /* 0x70 */ + SRGCTL = 29, /* 0x74 */ + + /* RAM Refresh Generator Registers */ + RRCIV = 30, /* 0x78 */ + RRSC = 31, /* 0x7C */ + RRCR = 34, /* 0x88 */ + + /* System Registers */ + GIOE = 32, /* 0x80 */ + GIO = 33, /* 0x84 */ + SCR = 35, /* 0x8C */ + SSTATUS = 36, /* 0x90 */ + PRC = 37, /* 0x94 */ + +#if 0 + /* PCI Registers */ + DVID = 0x00000000L, + SC = 0x00000004L, + CCR = 0x00000008L, + OG = 0x0000000CL, + BARM = 0x00000010L, + BARER = 0x00000030L, +#endif +}; + +/* IBM 624 RAMDAC Direct Registers */ +enum { + PADDRW = 0x00, + PDATA = 0x04, + PPMASK = 0x08, + PADDRR = 0x0c, + PIDXLO = 0x10, + PIDXHI = 0x14, + PIDXDATA= 0x18, + PIDXCTL = 0x1c +}; + +/* IBM 624 RAMDAC Indirect Registers */ +enum { + CLKCTL = 0x02, /* (0x01) Miscellaneous Clock Control */ + SYNCCTL = 0x03, /* (0x00) Sync Control */ + HSYNCPOS = 0x04, /* (0x00) Horizontal Sync Position */ + PWRMNGMT = 0x05, /* (0x00) Power Management */ + DACOP = 0x06, /* (0x02) DAC Operation */ + PALETCTL = 0x07, /* (0x00) Palette Control */ + SYSCLKCTL = 0x08, /* (0x01) System Clock Control */ + PIXFMT = 0x0a, /* () Pixel Format [bpp >> 3 + 2] */ + BPP8 = 0x0b, /* () 8 Bits/Pixel Control */ + BPP16 = 0x0c, /* () 16 Bits/Pixel Control [bit 1=1 for 565] */ + BPP24 = 0x0d, /* () 24 Bits/Pixel Control */ + BPP32 = 0x0e, /* () 32 Bits/Pixel Control */ + PIXCTL1 = 0x10, /* (0x05) Pixel PLL Control 1 */ + PIXCTL2 = 0x11, /* (0x00) Pixel PLL Control 2 */ + SYSCLKN = 0x15, /* () System Clock N (System PLL Reference Divider) */ + SYSCLKM = 0x16, /* () System Clock M (System PLL VCO Divider) */ + SYSCLKP = 0x17, /* () System Clock P */ + SYSCLKC = 0x18, /* () System Clock C */ + /* + * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1) + * c is charge pump bias which depends on the VCO frequency + */ + PIXM0 = 0x20, /* () Pixel M 0 */ + PIXN0 = 0x21, /* () Pixel N 0 */ + PIXP0 = 0x22, /* () Pixel P 0 */ + PIXC0 = 0x23, /* () Pixel C 0 */ + CURSCTL = 0x30, /* (0x00) Cursor Control */ + CURSXLO = 0x31, /* () Cursor X position, low 8 bits */ + CURSXHI = 0x32, /* () Cursor X position, high 8 bits */ + CURSYLO = 0x33, /* () Cursor Y position, low 8 bits */ + CURSYHI = 0x34, /* () Cursor Y position, high 8 bits */ + CURSHOTX = 0x35, /* () Cursor Hot Spot X */ + CURSHOTY = 0x36, /* () Cursor Hot Spot Y */ + CURSACCTL = 0x37, /* () Advanced Cursor Control Enable */ + CURSACATTR = 0x38, /* () Advanced Cursor Attribute */ + CURS1R = 0x40, /* () Cursor 1 Red */ + CURS1G = 0x41, /* () Cursor 1 Green */ + CURS1B = 0x42, /* () Cursor 1 Blue */ + CURS2R = 0x43, /* () Cursor 2 Red */ + CURS2G = 0x44, /* () Cursor 2 Green */ + CURS2B = 0x45, /* () Cursor 2 Blue */ + CURS3R = 0x46, /* () Cursor 3 Red */ + CURS3G = 0x47, /* () Cursor 3 Green */ + CURS3B = 0x48, /* () Cursor 3 Blue */ + BORDR = 0x60, /* () Border Color Red */ + BORDG = 0x61, /* () Border Color Green */ + BORDB = 0x62, /* () Border Color Blue */ + MISCTL1 = 0x70, /* (0x00) Miscellaneous Control 1 */ + MISCTL2 = 0x71, /* (0x00) Miscellaneous Control 2 */ + MISCTL3 = 0x72, /* (0x00) Miscellaneous Control 3 */ + KEYCTL = 0x78 /* (0x00) Key Control/DB Operation */ +}; + +/* TI TVP 3030 RAMDAC Direct Registers */ +enum { + TVPADDRW = 0x00, /* 0 Palette/Cursor RAM Write Address/Index */ + TVPPDATA = 0x04, /* 1 Palette Data RAM Data */ + TVPPMASK = 0x08, /* 2 Pixel Read-Mask */ + TVPPADRR = 0x0c, /* 3 Palette/Cursor RAM Read Address */ + TVPCADRW = 0x10, /* 4 Cursor/Overscan Color Write Address */ + TVPCDATA = 0x14, /* 5 Cursor/Overscan Color Data */ + /* 6 reserved */ + TVPCADRR = 0x1c, /* 7 Cursor/Overscan Color Read Address */ + /* 8 reserved */ + TVPDCCTL = 0x24, /* 9 Direct Cursor Control */ + TVPIDATA = 0x28, /* 10 Index Data */ + TVPCRDAT = 0x2c, /* 11 Cursor RAM Data */ + TVPCXPOL = 0x30, /* 12 Cursor-Position X LSB */ + TVPCXPOH = 0x34, /* 13 Cursor-Position X MSB */ + TVPCYPOL = 0x38, /* 14 Cursor-Position Y LSB */ + TVPCYPOH = 0x3c, /* 15 Cursor-Position Y MSB */ +}; + +/* TI TVP 3030 RAMDAC Indirect Registers */ +enum { + TVPIRREV = 0x01, /* Silicon Revision [RO] */ + TVPIRICC = 0x06, /* Indirect Cursor Control (0x00) */ + TVPIRBRC = 0x07, /* Byte Router Control (0xe4) */ + TVPIRLAC = 0x0f, /* Latch Control (0x06) */ + TVPIRTCC = 0x18, /* True Color Control (0x80) */ + TVPIRMXC = 0x19, /* Multiplex Control (0x98) */ + TVPIRCLS = 0x1a, /* Clock Selection (0x07) */ + TVPIRPPG = 0x1c, /* Palette Page (0x00) */ + TVPIRGEC = 0x1d, /* General Control (0x00) */ + TVPIRMIC = 0x1e, /* Miscellaneous Control (0x00) */ + TVPIRPLA = 0x2c, /* PLL Address */ + TVPIRPPD = 0x2d, /* Pixel Clock PLL Data */ + TVPIRMPD = 0x2e, /* Memory Clock PLL Data */ + TVPIRLPD = 0x2f, /* Loop Clock PLL Data */ + TVPIRCKL = 0x30, /* Color-Key Overlay Low */ + TVPIRCKH = 0x31, /* Color-Key Overlay High */ + TVPIRCRL = 0x32, /* Color-Key Red Low */ + TVPIRCRH = 0x33, /* Color-Key Red High */ + TVPIRCGL = 0x34, /* Color-Key Green Low */ + TVPIRCGH = 0x35, /* Color-Key Green High */ + TVPIRCBL = 0x36, /* Color-Key Blue Low */ + TVPIRCBH = 0x37, /* Color-Key Blue High */ + TVPIRCKC = 0x38, /* Color-Key Control (0x00) */ + TVPIRMLC = 0x39, /* MCLK/Loop Clock Control (0x18) */ + TVPIRSEN = 0x3a, /* Sense Test (0x00) */ + TVPIRTMD = 0x3b, /* Test Mode Data */ + TVPIRRML = 0x3c, /* CRC Remainder LSB [RO] */ + TVPIRRMM = 0x3d, /* CRC Remainder MSB [RO] */ + TVPIRRMS = 0x3e, /* CRC Bit Select [WO] */ + TVPIRDID = 0x3f, /* Device ID [RO] (0x30) */ + TVPIRRES = 0xff /* Software Reset [WO] */ +}; + +struct initvalues { + __u8 addr, value; +}; + +static struct initvalues ibm_initregs[] __devinitdata = { + { CLKCTL, 0x21 }, + { SYNCCTL, 0x00 }, + { HSYNCPOS, 0x00 }, + { PWRMNGMT, 0x00 }, + { DACOP, 0x02 }, + { PALETCTL, 0x00 }, + { SYSCLKCTL, 0x01 }, + + /* + * Note that colors in X are correct only if all video data is + * passed through the palette in the DAC. That is, "indirect + * color" must be configured. This is the case for the IBM DAC + * used in the 2MB and 4MB cards, at least. + */ + { BPP8, 0x00 }, + { BPP16, 0x01 }, + { BPP24, 0x00 }, + { BPP32, 0x00 }, + + { PIXCTL1, 0x05 }, + { PIXCTL2, 0x00 }, + { SYSCLKN, 0x08 }, + { SYSCLKM, 0x4f }, + { SYSCLKP, 0x00 }, + { SYSCLKC, 0x00 }, + { CURSCTL, 0x00 }, + { CURSACCTL, 0x01 }, + { CURSACATTR, 0xa8 }, + { CURS1R, 0xff }, + { CURS1G, 0xff }, + { CURS1B, 0xff }, + { CURS2R, 0xff }, + { CURS2G, 0xff }, + { CURS2B, 0xff }, + { CURS3R, 0xff }, + { CURS3G, 0xff }, + { CURS3B, 0xff }, + { BORDR, 0xff }, + { BORDG, 0xff }, + { BORDB, 0xff }, + { MISCTL1, 0x01 }, + { MISCTL2, 0x45 }, + { MISCTL3, 0x00 }, + { KEYCTL, 0x00 } +}; + +static struct initvalues tvp_initregs[] __devinitdata = { + { TVPIRICC, 0x00 }, + { TVPIRBRC, 0xe4 }, + { TVPIRLAC, 0x06 }, + { TVPIRTCC, 0x80 }, + { TVPIRMXC, 0x4d }, + { TVPIRCLS, 0x05 }, + { TVPIRPPG, 0x00 }, + { TVPIRGEC, 0x00 }, + { TVPIRMIC, 0x08 }, + { TVPIRCKL, 0xff }, + { TVPIRCKH, 0xff }, + { TVPIRCRL, 0xff }, + { TVPIRCRH, 0xff }, + { TVPIRCGL, 0xff }, + { TVPIRCGH, 0xff }, + { TVPIRCBL, 0xff }, + { TVPIRCBH, 0xff }, + { TVPIRCKC, 0x00 }, + { TVPIRPLA, 0x00 }, + { TVPIRPPD, 0xc0 }, + { TVPIRPPD, 0xd5 }, + { TVPIRPPD, 0xea }, + { TVPIRPLA, 0x00 }, + { TVPIRMPD, 0xb9 }, + { TVPIRMPD, 0x3a }, + { TVPIRMPD, 0xb1 }, + { TVPIRPLA, 0x00 }, + { TVPIRLPD, 0xc1 }, + { TVPIRLPD, 0x3d }, + { TVPIRLPD, 0xf3 }, +}; + +struct imstt_regvals { + __u32 pitch; + __u16 hes, heb, hsb, ht, ves, veb, vsb, vt, vil; + __u8 pclk_m, pclk_n, pclk_p; + /* Values of the tvp which change depending on colormode x resolution */ + __u8 mlc[3]; /* Memory Loop Config 0x39 */ + __u8 lckl_p[3]; /* P value of LCKL PLL */ +}; + +struct imstt_par { + struct imstt_regvals init; + __u32 __iomem *dc_regs; + unsigned long cmap_regs_phys; + __u8 *cmap_regs; + __u32 ramdac; +}; + +enum { + IBM = 0, + TVP = 1 +}; + +#define USE_NV_MODES 1 +#define INIT_BPP 8 +#define INIT_XRES 640 +#define INIT_YRES 480 + +static int inverse = 0; +static char fontname[40] __initdata = { 0 }; +#if defined(CONFIG_PPC) +static signed char init_vmode __devinitdata = -1, init_cmode __devinitdata = -1; +#endif + +static struct imstt_regvals tvp_reg_init_2 = { + 512, + 0x0002, 0x0006, 0x0026, 0x0028, 0x0003, 0x0016, 0x0196, 0x0197, 0x0196, + 0xec, 0x2a, 0xf3, + { 0x3c, 0x3b, 0x39 }, { 0xf3, 0xf3, 0xf3 } +}; + +static struct imstt_regvals tvp_reg_init_6 = { + 640, + 0x0004, 0x0009, 0x0031, 0x0036, 0x0003, 0x002a, 0x020a, 0x020d, 0x020a, + 0xef, 0x2e, 0xb2, + { 0x39, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 } +}; + +static struct imstt_regvals tvp_reg_init_12 = { + 800, + 0x0005, 0x000e, 0x0040, 0x0042, 0x0003, 0x018, 0x270, 0x271, 0x270, + 0xf6, 0x2e, 0xf2, + { 0x3a, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 } +}; + +static struct imstt_regvals tvp_reg_init_13 = { + 832, + 0x0004, 0x0011, 0x0045, 0x0048, 0x0003, 0x002a, 0x029a, 0x029b, 0x0000, + 0xfe, 0x3e, 0xf1, + { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 } +}; + +static struct imstt_regvals tvp_reg_init_17 = { + 1024, + 0x0006, 0x0210, 0x0250, 0x0053, 0x1003, 0x0021, 0x0321, 0x0324, 0x0000, + 0xfc, 0x3a, 0xf1, + { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 } +}; + +static struct imstt_regvals tvp_reg_init_18 = { + 1152, + 0x0009, 0x0011, 0x059, 0x5b, 0x0003, 0x0031, 0x0397, 0x039a, 0x0000, + 0xfd, 0x3a, 0xf1, + { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 } +}; + +static struct imstt_regvals tvp_reg_init_19 = { + 1280, + 0x0009, 0x0016, 0x0066, 0x0069, 0x0003, 0x0027, 0x03e7, 0x03e8, 0x03e7, + 0xf7, 0x36, 0xf0, + { 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 } +}; + +static struct imstt_regvals tvp_reg_init_20 = { + 1280, + 0x0009, 0x0018, 0x0068, 0x006a, 0x0003, 0x0029, 0x0429, 0x042a, 0x0000, + 0xf0, 0x2d, 0xf0, + { 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 } +}; + +/* + * PCI driver prototypes + */ +static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +static void imsttfb_remove(struct pci_dev *pdev); + +/* + * Register access + */ +static inline u32 read_reg_le32(volatile u32 __iomem *base, int regindex) +{ +#ifdef __powerpc__ + return in_le32(base + regindex); +#else + return readl(base + regindex); +#endif +} + +static inline void write_reg_le32(volatile u32 __iomem *base, int regindex, u32 val) +{ +#ifdef __powerpc__ + out_le32(base + regindex, val); +#else + writel(val, base + regindex); +#endif +} + +static __u32 +getclkMHz(struct imstt_par *par) +{ + __u32 clk_m, clk_n, clk_p; + + clk_m = par->init.pclk_m; + clk_n = par->init.pclk_n; + clk_p = par->init.pclk_p; + + return 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1)); +} + +static void +setclkMHz(struct imstt_par *par, __u32 MHz) +{ + __u32 clk_m, clk_n, clk_p, x, stage, spilled; + + clk_m = clk_n = clk_p = 0; + stage = spilled = 0; + for (;;) { + switch (stage) { + case 0: + clk_m++; + break; + case 1: + clk_n++; + break; + } + x = 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1)); + if (x == MHz) + break; + if (x > MHz) { + spilled = 1; + stage = 1; + } else if (spilled && x < MHz) { + stage = 0; + } + } + + par->init.pclk_m = clk_m; + par->init.pclk_n = clk_n; + par->init.pclk_p = clk_p; +} + +static struct imstt_regvals * +compute_imstt_regvals_ibm(struct imstt_par *par, int xres, int yres) +{ + struct imstt_regvals *init = &par->init; + __u32 MHz, hes, heb, veb, htp, vtp; + + switch (xres) { + case 640: + hes = 0x0008; heb = 0x0012; veb = 0x002a; htp = 10; vtp = 2; + MHz = 30 /* .25 */ ; + break; + case 832: + hes = 0x0005; heb = 0x0020; veb = 0x0028; htp = 8; vtp = 3; + MHz = 57 /* .27_ */ ; + break; + case 1024: + hes = 0x000a; heb = 0x001c; veb = 0x0020; htp = 8; vtp = 3; + MHz = 80; + break; + case 1152: + hes = 0x0012; heb = 0x0022; veb = 0x0031; htp = 4; vtp = 3; + MHz = 101 /* .6_ */ ; + break; + case 1280: + hes = 0x0012; heb = 0x002f; veb = 0x0029; htp = 4; vtp = 1; + MHz = yres == 960 ? 126 : 135; + break; + case 1600: + hes = 0x0018; heb = 0x0040; veb = 0x002a; htp = 4; vtp = 3; + MHz = 200; + break; + default: + return NULL; + } + + setclkMHz(par, MHz); + + init->hes = hes; + init->heb = heb; + init->hsb = init->heb + (xres >> 3); + init->ht = init->hsb + htp; + init->ves = 0x0003; + init->veb = veb; + init->vsb = init->veb + yres; + init->vt = init->vsb + vtp; + init->vil = init->vsb; + + init->pitch = xres; + return init; +} + +static struct imstt_regvals * +compute_imstt_regvals_tvp(struct imstt_par *par, int xres, int yres) +{ + struct imstt_regvals *init; + + switch (xres) { + case 512: + init = &tvp_reg_init_2; + break; + case 640: + init = &tvp_reg_init_6; + break; + case 800: + init = &tvp_reg_init_12; + break; + case 832: + init = &tvp_reg_init_13; + break; + case 1024: + init = &tvp_reg_init_17; + break; + case 1152: + init = &tvp_reg_init_18; + break; + case 1280: + init = yres == 960 ? &tvp_reg_init_19 : &tvp_reg_init_20; + break; + default: + return NULL; + } + par->init = *init; + return init; +} + +static struct imstt_regvals * +compute_imstt_regvals (struct imstt_par *par, u_int xres, u_int yres) +{ + if (par->ramdac == IBM) + return compute_imstt_regvals_ibm(par, xres, yres); + else + return compute_imstt_regvals_tvp(par, xres, yres); +} + +static void +set_imstt_regvals_ibm (struct imstt_par *par, u_int bpp) +{ + struct imstt_regvals *init = &par->init; + __u8 pformat = (bpp >> 3) + 2; + + par->cmap_regs[PIDXHI] = 0; eieio(); + par->cmap_regs[PIDXLO] = PIXM0; eieio(); + par->cmap_regs[PIDXDATA] = init->pclk_m;eieio(); + par->cmap_regs[PIDXLO] = PIXN0; eieio(); + par->cmap_regs[PIDXDATA] = init->pclk_n;eieio(); + par->cmap_regs[PIDXLO] = PIXP0; eieio(); + par->cmap_regs[PIDXDATA] = init->pclk_p;eieio(); + par->cmap_regs[PIDXLO] = PIXC0; eieio(); + par->cmap_regs[PIDXDATA] = 0x02; eieio(); + + par->cmap_regs[PIDXLO] = PIXFMT; eieio(); + par->cmap_regs[PIDXDATA] = pformat; eieio(); +} + +static void +set_imstt_regvals_tvp (struct imstt_par *par, u_int bpp) +{ + struct imstt_regvals *init = &par->init; + __u8 tcc, mxc, lckl_n, mic; + __u8 mlc, lckl_p; + + switch (bpp) { + default: + case 8: + tcc = 0x80; + mxc = 0x4d; + lckl_n = 0xc1; + mlc = init->mlc[0]; + lckl_p = init->lckl_p[0]; + break; + case 16: + tcc = 0x44; + mxc = 0x55; + lckl_n = 0xe1; + mlc = init->mlc[1]; + lckl_p = init->lckl_p[1]; + break; + case 24: + tcc = 0x5e; + mxc = 0x5d; + lckl_n = 0xf1; + mlc = init->mlc[2]; + lckl_p = init->lckl_p[2]; + break; + case 32: + tcc = 0x46; + mxc = 0x5d; + lckl_n = 0xf1; + mlc = init->mlc[2]; + lckl_p = init->lckl_p[2]; + break; + } + mic = 0x08; + + par->cmap_regs[TVPADDRW] = TVPIRPLA; eieio(); + par->cmap_regs[TVPIDATA] = 0x00; eieio(); + par->cmap_regs[TVPADDRW] = TVPIRPPD; eieio(); + par->cmap_regs[TVPIDATA] = init->pclk_m; eieio(); + par->cmap_regs[TVPADDRW] = TVPIRPPD; eieio(); + par->cmap_regs[TVPIDATA] = init->pclk_n; eieio(); + par->cmap_regs[TVPADDRW] = TVPIRPPD; eieio(); + par->cmap_regs[TVPIDATA] = init->pclk_p; eieio(); + + par->cmap_regs[TVPADDRW] = TVPIRTCC; eieio(); + par->cmap_regs[TVPIDATA] = tcc; eieio(); + par->cmap_regs[TVPADDRW] = TVPIRMXC; eieio(); + par->cmap_regs[TVPIDATA] = mxc; eieio(); + par->cmap_regs[TVPADDRW] = TVPIRMIC; eieio(); + par->cmap_regs[TVPIDATA] = mic; eieio(); + + par->cmap_regs[TVPADDRW] = TVPIRPLA; eieio(); + par->cmap_regs[TVPIDATA] = 0x00; eieio(); + par->cmap_regs[TVPADDRW] = TVPIRLPD; eieio(); + par->cmap_regs[TVPIDATA] = lckl_n; eieio(); + + par->cmap_regs[TVPADDRW] = TVPIRPLA; eieio(); + par->cmap_regs[TVPIDATA] = 0x15; eieio(); + par->cmap_regs[TVPADDRW] = TVPIRMLC; eieio(); + par->cmap_regs[TVPIDATA] = mlc; eieio(); + + par->cmap_regs[TVPADDRW] = TVPIRPLA; eieio(); + par->cmap_regs[TVPIDATA] = 0x2a; eieio(); + par->cmap_regs[TVPADDRW] = TVPIRLPD; eieio(); + par->cmap_regs[TVPIDATA] = lckl_p; eieio(); +} + +static void +set_imstt_regvals (struct fb_info *info, u_int bpp) +{ + struct imstt_par *par = (struct imstt_par *) info->par; + struct imstt_regvals *init = &par->init; + __u32 ctl, pitch, byteswap, scr; + + if (par->ramdac == IBM) + set_imstt_regvals_ibm(par, bpp); + else + set_imstt_regvals_tvp(par, bpp); + + /* + * From what I (jsk) can gather poking around with MacsBug, + * bits 8 and 9 in the SCR register control endianness + * correction (byte swapping). These bits must be set according + * to the color depth as follows: + * Color depth Bit 9 Bit 8 + * ========== ===== ===== + * 8bpp 0 0 + * 16bpp 0 1 + * 32bpp 1 1 + */ + switch (bpp) { + default: + case 8: + ctl = 0x17b1; + pitch = init->pitch >> 2; + byteswap = 0x000; + break; + case 16: + ctl = 0x17b3; + pitch = init->pitch >> 1; + byteswap = 0x100; + break; + case 24: + ctl = 0x17b9; + pitch = init->pitch - (init->pitch >> 2); + byteswap = 0x200; + break; + case 32: + ctl = 0x17b5; + pitch = init->pitch; + byteswap = 0x300; + break; + } + if (par->ramdac == TVP) + ctl -= 0x30; + + write_reg_le32(par->dc_regs, HES, init->hes); + write_reg_le32(par->dc_regs, HEB, init->heb); + write_reg_le32(par->dc_regs, HSB, init->hsb); + write_reg_le32(par->dc_regs, HT, init->ht); + write_reg_le32(par->dc_regs, VES, init->ves); + write_reg_le32(par->dc_regs, VEB, init->veb); + write_reg_le32(par->dc_regs, VSB, init->vsb); + write_reg_le32(par->dc_regs, VT, init->vt); + write_reg_le32(par->dc_regs, VIL, init->vil); + write_reg_le32(par->dc_regs, HCIV, 1); + write_reg_le32(par->dc_regs, VCIV, 1); + write_reg_le32(par->dc_regs, TCDR, 4); + write_reg_le32(par->dc_regs, RRCIV, 1); + write_reg_le32(par->dc_regs, RRSC, 0x980); + write_reg_le32(par->dc_regs, RRCR, 0x11); + + if (par->ramdac == IBM) { + write_reg_le32(par->dc_regs, HRIR, 0x0100); + write_reg_le32(par->dc_regs, CMR, 0x00ff); + write_reg_le32(par->dc_regs, SRGCTL, 0x0073); + } else { + write_reg_le32(par->dc_regs, HRIR, 0x0200); + write_reg_le32(par->dc_regs, CMR, 0x01ff); + write_reg_le32(par->dc_regs, SRGCTL, 0x0003); + } + + switch (info->fix.smem_len) { + case 0x200000: + scr = 0x059d | byteswap; + break; + /* case 0x400000: + case 0x800000: */ + default: + pitch >>= 1; + scr = 0x150dd | byteswap; + break; + } + + write_reg_le32(par->dc_regs, SCR, scr); + write_reg_le32(par->dc_regs, SPR, pitch); + write_reg_le32(par->dc_regs, STGCTL, ctl); +} + +static inline void +set_offset (struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct imstt_par *par = (struct imstt_par *) info->par; + __u32 off = var->yoffset * (info->fix.line_length >> 3) + + ((var->xoffset * (var->bits_per_pixel >> 3)) >> 3); + write_reg_le32(par->dc_regs, SSR, off); +} + +static inline void +set_555 (struct imstt_par *par) +{ + if (par->ramdac == IBM) { + par->cmap_regs[PIDXHI] = 0; eieio(); + par->cmap_regs[PIDXLO] = BPP16; eieio(); + par->cmap_regs[PIDXDATA] = 0x01; eieio(); + } else { + par->cmap_regs[TVPADDRW] = TVPIRTCC; eieio(); + par->cmap_regs[TVPIDATA] = 0x44; eieio(); + } +} + +static inline void +set_565 (struct imstt_par *par) +{ + if (par->ramdac == IBM) { + par->cmap_regs[PIDXHI] = 0; eieio(); + par->cmap_regs[PIDXLO] = BPP16; eieio(); + par->cmap_regs[PIDXDATA] = 0x03; eieio(); + } else { + par->cmap_regs[TVPADDRW] = TVPIRTCC; eieio(); + par->cmap_regs[TVPIDATA] = 0x45; eieio(); + } +} + +static int +imsttfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + if ((var->bits_per_pixel != 8 && var->bits_per_pixel != 16 + && var->bits_per_pixel != 24 && var->bits_per_pixel != 32) + || var->xres_virtual < var->xres || var->yres_virtual < var->yres + || var->nonstd + || (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + return -EINVAL; + + if ((var->xres * var->yres) * (var->bits_per_pixel >> 3) > info->fix.smem_len + || (var->xres_virtual * var->yres_virtual) * (var->bits_per_pixel >> 3) > info->fix.smem_len) + return -EINVAL; + + switch (var->bits_per_pixel) { + case 8: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 16: /* RGB 555 or 565 */ + if (var->green.length != 6) + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + if (var->green.length != 6) + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 24: /* RGB 888 */ + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + 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; + var->transp.offset = 24; + var->transp.length = 8; + break; + } + + if (var->yres == var->yres_virtual) { + __u32 vram = (info->fix.smem_len - (PAGE_SIZE << 2)); + var->yres_virtual = ((vram << 3) / var->bits_per_pixel) / var->xres_virtual; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + } + + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + var->height = -1; + var->width = -1; + var->vmode = FB_VMODE_NONINTERLACED; + var->left_margin = var->right_margin = 16; + var->upper_margin = var->lower_margin = 16; + var->hsync_len = var->vsync_len = 8; + return 0; +} + +static int +imsttfb_set_par(struct fb_info *info) +{ + struct imstt_par *par = (struct imstt_par *) info->par; + + if (!compute_imstt_regvals(par, info->var.xres, info->var.yres)) + return -EINVAL; + + if (info->var.green.length == 6) + set_565(par); + else + set_555(par); + set_imstt_regvals(info, info->var.bits_per_pixel); + info->var.pixclock = 1000000 / getclkMHz(par); + return 0; +} + +static int +imsttfb_setcolreg (u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct imstt_par *par = (struct imstt_par *) info->par; + u_int bpp = info->var.bits_per_pixel; + + if (regno > 255) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + /* PADDRW/PDATA are the same as TVPPADDRW/TVPPDATA */ + if (0 && bpp == 16) /* screws up X */ + par->cmap_regs[PADDRW] = regno << 3; + else + par->cmap_regs[PADDRW] = regno; + eieio(); + + par->cmap_regs[PDATA] = red; eieio(); + par->cmap_regs[PDATA] = green; eieio(); + par->cmap_regs[PDATA] = blue; eieio(); + + if (regno < 16) + switch (bpp) { + case 16: + ((u16 *)info->pseudo_palette)[regno] = (regno << (info->var.green.length == 5 ? 10 : 11)) | (regno << 5) | regno; + break; + case 24: + ((u32 *)info->pseudo_palette)[regno] = (regno << 16) | (regno << 8) | regno; + break; + case 32: { + int i = (regno << 8) | regno; + ((u32 *)info->pseudo_palette)[regno] = (i << 16) | i; + break; + } + } + return 0; +} + +static int +imsttfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + if (var->xoffset + info->var.xres > info->var.xres_virtual + || var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + set_offset(var, info); + return 0; +} + +static int +imsttfb_blank(int blank, struct fb_info *info) +{ + struct imstt_par *par = (struct imstt_par *) info->par; + __u32 ctrl; + + ctrl = read_reg_le32(par->dc_regs, STGCTL); + if (blank > 0) { + switch (blank) { + case FB_BLANK_NORMAL: + case FB_BLANK_POWERDOWN: + ctrl &= ~0x00000380; + if (par->ramdac == IBM) { + par->cmap_regs[PIDXHI] = 0; eieio(); + par->cmap_regs[PIDXLO] = MISCTL2; eieio(); + par->cmap_regs[PIDXDATA] = 0x55; eieio(); + par->cmap_regs[PIDXLO] = MISCTL1; eieio(); + par->cmap_regs[PIDXDATA] = 0x11; eieio(); + par->cmap_regs[PIDXLO] = SYNCCTL; eieio(); + par->cmap_regs[PIDXDATA] = 0x0f; eieio(); + par->cmap_regs[PIDXLO] = PWRMNGMT; eieio(); + par->cmap_regs[PIDXDATA] = 0x1f; eieio(); + par->cmap_regs[PIDXLO] = CLKCTL; eieio(); + par->cmap_regs[PIDXDATA] = 0xc0; + } + break; + case FB_BLANK_VSYNC_SUSPEND: + ctrl &= ~0x00000020; + break; + case FB_BLANK_HSYNC_SUSPEND: + ctrl &= ~0x00000010; + break; + } + } else { + if (par->ramdac == IBM) { + ctrl |= 0x000017b0; + par->cmap_regs[PIDXHI] = 0; eieio(); + par->cmap_regs[PIDXLO] = CLKCTL; eieio(); + par->cmap_regs[PIDXDATA] = 0x01; eieio(); + par->cmap_regs[PIDXLO] = PWRMNGMT; eieio(); + par->cmap_regs[PIDXDATA] = 0x00; eieio(); + par->cmap_regs[PIDXLO] = SYNCCTL; eieio(); + par->cmap_regs[PIDXDATA] = 0x00; eieio(); + par->cmap_regs[PIDXLO] = MISCTL1; eieio(); + par->cmap_regs[PIDXDATA] = 0x01; eieio(); + par->cmap_regs[PIDXLO] = MISCTL2; eieio(); + par->cmap_regs[PIDXDATA] = 0x45; eieio(); + } else + ctrl |= 0x00001780; + } + write_reg_le32(par->dc_regs, STGCTL, ctrl); + return 0; +} + +static void +imsttfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct imstt_par *par = (struct imstt_par *) info->par; + __u32 Bpp, line_pitch, bgc, dx, dy, width, height; + + bgc = rect->color; + bgc |= (bgc << 8); + bgc |= (bgc << 16); + + Bpp = info->var.bits_per_pixel >> 3, + line_pitch = info->fix.line_length; + + dy = rect->dy * line_pitch; + dx = rect->dx * Bpp; + height = rect->height; + height--; + width = rect->width * Bpp; + width--; + + if (rect->rop == ROP_COPY) { + while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80); + write_reg_le32(par->dc_regs, DSA, dy + dx); + write_reg_le32(par->dc_regs, CNT, (height << 16) | width); + write_reg_le32(par->dc_regs, DP_OCTL, line_pitch); + write_reg_le32(par->dc_regs, BI, 0xffffffff); + write_reg_le32(par->dc_regs, MBC, 0xffffffff); + write_reg_le32(par->dc_regs, CLR, bgc); + write_reg_le32(par->dc_regs, BLTCTL, 0x840); /* 0x200000 */ + while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80); + while(read_reg_le32(par->dc_regs, SSTATUS) & 0x40); + } else { + while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80); + write_reg_le32(par->dc_regs, DSA, dy + dx); + write_reg_le32(par->dc_regs, S1SA, dy + dx); + write_reg_le32(par->dc_regs, CNT, (height << 16) | width); + write_reg_le32(par->dc_regs, DP_OCTL, line_pitch); + write_reg_le32(par->dc_regs, SP, line_pitch); + write_reg_le32(par->dc_regs, BLTCTL, 0x40005); + while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80); + while(read_reg_le32(par->dc_regs, SSTATUS) & 0x40); + } +} + +static void +imsttfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct imstt_par *par = (struct imstt_par *) info->par; + __u32 Bpp, line_pitch, fb_offset_old, fb_offset_new, sp, dp_octl; + __u32 cnt, bltctl, sx, sy, dx, dy, height, width; + + Bpp = info->var.bits_per_pixel >> 3, + + sx = area->sx * Bpp; + sy = area->sy; + dx = area->dx * Bpp; + dy = area->dy; + height = area->height; + height--; + width = area->width * Bpp; + width--; + + line_pitch = info->fix.line_length; + bltctl = 0x05; + sp = line_pitch << 16; + cnt = height << 16; + + if (sy < dy) { + sy += height; + dy += height; + sp |= -(line_pitch) & 0xffff; + dp_octl = -(line_pitch) & 0xffff; + } else { + sp |= line_pitch; + dp_octl = line_pitch; + } + if (sx < dx) { + sx += width; + dx += width; + bltctl |= 0x80; + cnt |= -(width) & 0xffff; + } else { + cnt |= width; + } + fb_offset_old = sy * line_pitch + sx; + fb_offset_new = dy * line_pitch + dx; + + while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80); + write_reg_le32(par->dc_regs, S1SA, fb_offset_old); + write_reg_le32(par->dc_regs, SP, sp); + write_reg_le32(par->dc_regs, DSA, fb_offset_new); + write_reg_le32(par->dc_regs, CNT, cnt); + write_reg_le32(par->dc_regs, DP_OCTL, dp_octl); + write_reg_le32(par->dc_regs, BLTCTL, bltctl); + while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80); + while(read_reg_le32(par->dc_regs, SSTATUS) & 0x40); +} + +#if 0 +static int +imsttfb_load_cursor_image(struct imstt_par *par, int width, int height, __u8 fgc) +{ + u_int x, y; + + if (width > 32 || height > 32) + return -EINVAL; + + if (par->ramdac == IBM) { + par->cmap_regs[PIDXHI] = 1; eieio(); + for (x = 0; x < 0x100; x++) { + par->cmap_regs[PIDXLO] = x; eieio(); + par->cmap_regs[PIDXDATA] = 0x00; eieio(); + } + par->cmap_regs[PIDXHI] = 1; eieio(); + for (y = 0; y < height; y++) + for (x = 0; x < width >> 2; x++) { + par->cmap_regs[PIDXLO] = x + y * 8; eieio(); + par->cmap_regs[PIDXDATA] = 0xff; eieio(); + } + par->cmap_regs[PIDXHI] = 0; eieio(); + par->cmap_regs[PIDXLO] = CURS1R; eieio(); + par->cmap_regs[PIDXDATA] = fgc; eieio(); + par->cmap_regs[PIDXLO] = CURS1G; eieio(); + par->cmap_regs[PIDXDATA] = fgc; eieio(); + par->cmap_regs[PIDXLO] = CURS1B; eieio(); + par->cmap_regs[PIDXDATA] = fgc; eieio(); + par->cmap_regs[PIDXLO] = CURS2R; eieio(); + par->cmap_regs[PIDXDATA] = fgc; eieio(); + par->cmap_regs[PIDXLO] = CURS2G; eieio(); + par->cmap_regs[PIDXDATA] = fgc; eieio(); + par->cmap_regs[PIDXLO] = CURS2B; eieio(); + par->cmap_regs[PIDXDATA] = fgc; eieio(); + par->cmap_regs[PIDXLO] = CURS3R; eieio(); + par->cmap_regs[PIDXDATA] = fgc; eieio(); + par->cmap_regs[PIDXLO] = CURS3G; eieio(); + par->cmap_regs[PIDXDATA] = fgc; eieio(); + par->cmap_regs[PIDXLO] = CURS3B; eieio(); + par->cmap_regs[PIDXDATA] = fgc; eieio(); + } else { + par->cmap_regs[TVPADDRW] = TVPIRICC; eieio(); + par->cmap_regs[TVPIDATA] &= 0x03; eieio(); + par->cmap_regs[TVPADDRW] = 0; eieio(); + for (x = 0; x < 0x200; x++) { + par->cmap_regs[TVPCRDAT] = 0x00; eieio(); + } + for (x = 0; x < 0x200; x++) { + par->cmap_regs[TVPCRDAT] = 0xff; eieio(); + } + par->cmap_regs[TVPADDRW] = TVPIRICC; eieio(); + par->cmap_regs[TVPIDATA] &= 0x03; eieio(); + for (y = 0; y < height; y++) + for (x = 0; x < width >> 3; x++) { + par->cmap_regs[TVPADDRW] = x + y * 8; eieio(); + par->cmap_regs[TVPCRDAT] = 0xff; eieio(); + } + par->cmap_regs[TVPADDRW] = TVPIRICC; eieio(); + par->cmap_regs[TVPIDATA] |= 0x08; eieio(); + for (y = 0; y < height; y++) + for (x = 0; x < width >> 3; x++) { + par->cmap_regs[TVPADDRW] = x + y * 8; eieio(); + par->cmap_regs[TVPCRDAT] = 0xff; eieio(); + } + par->cmap_regs[TVPCADRW] = 0x00; eieio(); + for (x = 0; x < 12; x++) + par->cmap_regs[TVPCDATA] = fgc; eieio(); + } + return 1; +} + +static void +imstt_set_cursor(struct imstt_par *par, struct fb_image *d, int on) +{ + if (par->ramdac == IBM) { + par->cmap_regs[PIDXHI] = 0; eieio(); + if (!on) { + par->cmap_regs[PIDXLO] = CURSCTL; eieio(); + par->cmap_regs[PIDXDATA] = 0x00; eieio(); + } else { + par->cmap_regs[PIDXLO] = CURSXHI; eieio(); + par->cmap_regs[PIDXDATA] = d->dx >> 8; eieio(); + par->cmap_regs[PIDXLO] = CURSXLO; eieio(); + par->cmap_regs[PIDXDATA] = d->dx & 0xff;eieio(); + par->cmap_regs[PIDXLO] = CURSYHI; eieio(); + par->cmap_regs[PIDXDATA] = d->dy >> 8; eieio(); + par->cmap_regs[PIDXLO] = CURSYLO; eieio(); + par->cmap_regs[PIDXDATA] = d->dy & 0xff;eieio(); + par->cmap_regs[PIDXLO] = CURSCTL; eieio(); + par->cmap_regs[PIDXDATA] = 0x02; eieio(); + } + } else { + if (!on) { + par->cmap_regs[TVPADDRW] = TVPIRICC; eieio(); + par->cmap_regs[TVPIDATA] = 0x00; eieio(); + } else { + __u16 x = d->dx + 0x40, y = d->dy + 0x40; + + par->cmap_regs[TVPCXPOH] = x >> 8; eieio(); + par->cmap_regs[TVPCXPOL] = x & 0xff; eieio(); + par->cmap_regs[TVPCYPOH] = y >> 8; eieio(); + par->cmap_regs[TVPCYPOL] = y & 0xff; eieio(); + par->cmap_regs[TVPADDRW] = TVPIRICC; eieio(); + par->cmap_regs[TVPIDATA] = 0x02; eieio(); + } + } +} + +static int +imsttfb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct imstt_par *par = (struct imstt_par *) info->par; + u32 flags = cursor->set, fg, bg, xx, yy; + + if (cursor->dest == NULL && cursor->rop == ROP_XOR) + return 1; + + imstt_set_cursor(info, cursor, 0); + + if (flags & FB_CUR_SETPOS) { + xx = cursor->image.dx - info->var.xoffset; + yy = cursor->image.dy - info->var.yoffset; + } + + if (flags & FB_CUR_SETSIZE) { + } + + if (flags & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP)) { + int fg_idx = cursor->image.fg_color; + int width = (cursor->image.width+7)/8; + u8 *dat = (u8 *) cursor->image.data; + u8 *dst = (u8 *) cursor->dest; + u8 *msk = (u8 *) cursor->mask; + + switch (cursor->rop) { + case ROP_XOR: + for (i = 0; i < cursor->image.height; i++) { + for (j = 0; j < width; j++) { + d_idx = i * MAX_CURS/8 + j; + data[d_idx] = byte_rev[dat[s_idx] ^ + dst[s_idx]]; + mask[d_idx] = byte_rev[msk[s_idx]]; + s_idx++; + } + } + break; + case ROP_COPY: + default: + for (i = 0; i < cursor->image.height; i++) { + for (j = 0; j < width; j++) { + d_idx = i * MAX_CURS/8 + j; + data[d_idx] = byte_rev[dat[s_idx]]; + mask[d_idx] = byte_rev[msk[s_idx]]; + s_idx++; + } + } + break; + } + + fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) | + ((info->cmap.green[fg_idx] & 0xf8) << 2) | + ((info->cmap.blue[fg_idx] & 0xf8) >> 3) | 1 << 15; + + imsttfb_load_cursor_image(par, xx, yy, fgc); + } + if (cursor->enable) + imstt_set_cursor(info, cursor, 1); + return 0; +} +#endif + +#define FBIMSTT_SETREG 0x545401 +#define FBIMSTT_GETREG 0x545402 +#define FBIMSTT_SETCMAPREG 0x545403 +#define FBIMSTT_GETCMAPREG 0x545404 +#define FBIMSTT_SETIDXREG 0x545405 +#define FBIMSTT_GETIDXREG 0x545406 + +static int +imsttfb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, struct fb_info *info) +{ + struct imstt_par *par = (struct imstt_par *) info->par; + void __user *argp = (void __user *)arg; + __u32 reg[2]; + __u8 idx[2]; + + switch (cmd) { + case FBIMSTT_SETREG: + if (copy_from_user(reg, argp, 8) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0])) + return -EFAULT; + write_reg_le32(par->dc_regs, reg[0], reg[1]); + return 0; + case FBIMSTT_GETREG: + if (copy_from_user(reg, argp, 4) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0])) + return -EFAULT; + reg[1] = read_reg_le32(par->dc_regs, reg[0]); + if (copy_to_user((void __user *)(arg + 4), ®[1], 4)) + return -EFAULT; + return 0; + case FBIMSTT_SETCMAPREG: + if (copy_from_user(reg, argp, 8) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0])) + return -EFAULT; + write_reg_le32(((u_int *)par->cmap_regs), reg[0], reg[1]); + return 0; + case FBIMSTT_GETCMAPREG: + if (copy_from_user(reg, argp, 4) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0])) + return -EFAULT; + reg[1] = read_reg_le32(((u_int *)par->cmap_regs), reg[0]); + if (copy_to_user((void __user *)(arg + 4), ®[1], 4)) + return -EFAULT; + return 0; + case FBIMSTT_SETIDXREG: + if (copy_from_user(idx, argp, 2)) + return -EFAULT; + par->cmap_regs[PIDXHI] = 0; eieio(); + par->cmap_regs[PIDXLO] = idx[0]; eieio(); + par->cmap_regs[PIDXDATA] = idx[1]; eieio(); + return 0; + case FBIMSTT_GETIDXREG: + if (copy_from_user(idx, argp, 1)) + return -EFAULT; + par->cmap_regs[PIDXHI] = 0; eieio(); + par->cmap_regs[PIDXLO] = idx[0]; eieio(); + idx[1] = par->cmap_regs[PIDXDATA]; + if (copy_to_user((void __user *)(arg + 1), &idx[1], 1)) + return -EFAULT; + return 0; + default: + return -ENOIOCTLCMD; + } +} + +static struct pci_device_id imsttfb_pci_tbl[] = { + { PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_TT128, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, IBM }, + { PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_TT3D, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, TVP }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, imsttfb_pci_tbl); + +static struct pci_driver imsttfb_pci_driver = { + .name = "imsttfb", + .id_table = imsttfb_pci_tbl, + .probe = imsttfb_probe, + .remove = __devexit_p(imsttfb_remove), +}; + +static struct fb_ops imsttfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = imsttfb_check_var, + .fb_set_par = imsttfb_set_par, + .fb_setcolreg = imsttfb_setcolreg, + .fb_pan_display = imsttfb_pan_display, + .fb_blank = imsttfb_blank, + .fb_fillrect = imsttfb_fillrect, + .fb_copyarea = imsttfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + .fb_ioctl = imsttfb_ioctl, +}; + +static void __devinit +init_imstt(struct fb_info *info) +{ + struct imstt_par *par = (struct imstt_par *) info->par; + __u32 i, tmp, *ip, *end; + + tmp = read_reg_le32(par->dc_regs, PRC); + if (par->ramdac == IBM) + info->fix.smem_len = (tmp & 0x0004) ? 0x400000 : 0x200000; + else + info->fix.smem_len = 0x800000; + + ip = (__u32 *)info->screen_base; + end = (__u32 *)(info->screen_base + info->fix.smem_len); + while (ip < end) + *ip++ = 0; + + /* initialize the card */ + tmp = read_reg_le32(par->dc_regs, STGCTL); + write_reg_le32(par->dc_regs, STGCTL, tmp & ~0x1); + write_reg_le32(par->dc_regs, SSR, 0); + + /* set default values for DAC registers */ + if (par->ramdac == IBM) { + par->cmap_regs[PPMASK] = 0xff; eieio(); + par->cmap_regs[PIDXHI] = 0; eieio(); + for (i = 0; i < sizeof(ibm_initregs) / sizeof(*ibm_initregs); i++) { + par->cmap_regs[PIDXLO] = ibm_initregs[i].addr; eieio(); + par->cmap_regs[PIDXDATA] = ibm_initregs[i].value; eieio(); + } + } else { + for (i = 0; i < sizeof(tvp_initregs) / sizeof(*tvp_initregs); i++) { + par->cmap_regs[TVPADDRW] = tvp_initregs[i].addr; eieio(); + par->cmap_regs[TVPIDATA] = tvp_initregs[i].value; eieio(); + } + } + +#if USE_NV_MODES && defined(CONFIG_PPC) + { + int vmode = init_vmode, cmode = init_cmode; + + if (vmode == -1) { + vmode = nvram_read_byte(NV_VMODE); + if (vmode <= 0 || vmode > VMODE_MAX) + vmode = VMODE_640_480_67; + } + if (cmode == -1) { + cmode = nvram_read_byte(NV_CMODE); + if (cmode < CMODE_8 || cmode > CMODE_32) + cmode = CMODE_8; + } + if (mac_vmode_to_var(vmode, cmode, &info->var)) { + info->var.xres = info->var.xres_virtual = INIT_XRES; + info->var.yres = info->var.yres_virtual = INIT_YRES; + info->var.bits_per_pixel = INIT_BPP; + } + } +#else + info->var.xres = info->var.xres_virtual = INIT_XRES; + info->var.yres = info->var.yres_virtual = INIT_YRES; + info->var.bits_per_pixel = INIT_BPP; +#endif + + if ((info->var.xres * info->var.yres) * (info->var.bits_per_pixel >> 3) > info->fix.smem_len + || !(compute_imstt_regvals(par, info->var.xres, info->var.yres))) { + printk("imsttfb: %ux%ux%u not supported\n", info->var.xres, info->var.yres, info->var.bits_per_pixel); + kfree(info); + return; + } + + sprintf(info->fix.id, "IMS TT (%s)", par->ramdac == IBM ? "IBM" : "TVP"); + info->fix.mmio_len = 0x1000; + info->fix.accel = FB_ACCEL_IMS_TWINTURBO; + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = info->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_DIRECTCOLOR; + info->fix.line_length = info->var.xres * (info->var.bits_per_pixel >> 3); + info->fix.xpanstep = 8; + info->fix.ypanstep = 1; + info->fix.ywrapstep = 0; + + info->var.accel_flags = FB_ACCELF_TEXT; + +// if (par->ramdac == IBM) +// imstt_cursor_init(info); + if (info->var.green.length == 6) + set_565(par); + else + set_555(par); + set_imstt_regvals(info, info->var.bits_per_pixel); + + info->var.pixclock = 1000000 / getclkMHz(par); + + info->fbops = &imsttfb_ops; + info->flags = FBINFO_DEFAULT | + FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_YPAN; + + fb_alloc_cmap(&info->cmap, 0, 0); + + if (register_framebuffer(info) < 0) { + kfree(info); + return; + } + + tmp = (read_reg_le32(par->dc_regs, SSTATUS) & 0x0f00) >> 8; + printk("fb%u: %s frame buffer; %uMB vram; chip version %u\n", + info->node, info->fix.id, info->fix.smem_len >> 20, tmp); +} + +static int __devinit +imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + unsigned long addr, size; + struct imstt_par *par; + struct fb_info *info; +#ifdef CONFIG_PPC_OF + struct device_node *dp; + + dp = pci_device_to_OF_node(pdev); + if(dp) + printk(KERN_INFO "%s: OF name %s\n",__FUNCTION__, dp->name); + else + printk(KERN_ERR "imsttfb: no OF node for pci device\n"); +#endif /* CONFIG_PPC_OF */ + + size = sizeof(struct fb_info) + sizeof(struct imstt_par) + + sizeof(u32) * 16; + + info = kmalloc(size, GFP_KERNEL); + + if (!info) { + printk(KERN_ERR "imsttfb: Can't allocate memory\n"); + return -ENOMEM; + } + + memset(info, 0, size); + + par = (struct imstt_par *) (info + 1); + + addr = pci_resource_start (pdev, 0); + size = pci_resource_len (pdev, 0); + + if (!request_mem_region(addr, size, "imsttfb")) { + printk(KERN_ERR "imsttfb: Can't reserve memory region\n"); + kfree(info); + return -ENODEV; + } + + switch (pdev->device) { + case PCI_DEVICE_ID_IMS_TT128: /* IMS,tt128mbA */ + par->ramdac = IBM; +#ifdef CONFIG_PPC_OF + if (dp && ((strcmp(dp->name, "IMS,tt128mb8") == 0) || + (strcmp(dp->name, "IMS,tt128mb8A") == 0))) + par->ramdac = TVP; +#endif /* CONFIG_PPC_OF */ + break; + case PCI_DEVICE_ID_IMS_TT3D: /* IMS,tt3d */ + par->ramdac = TVP; + break; + default: + printk(KERN_INFO "imsttfb: Device 0x%x unknown, " + "contact maintainer.\n", pdev->device); + return -ENODEV; + } + + info->fix.smem_start = addr; + info->screen_base = (__u8 *)ioremap(addr, par->ramdac == IBM ? 0x400000 : 0x800000); + info->fix.mmio_start = addr + 0x800000; + par->dc_regs = ioremap(addr + 0x800000, 0x1000); + par->cmap_regs_phys = addr + 0x840000; + par->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000); + info->par = par; + info->pseudo_palette = (void *) (par + 1); + info->device = &pdev->dev; + init_imstt(info); + + pci_set_drvdata(pdev, info); + return 0; +} + +static void __devexit +imsttfb_remove(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct imstt_par *par = (struct imstt_par *) info->par; + int size = pci_resource_len(pdev, 0); + + unregister_framebuffer(info); + iounmap(par->cmap_regs); + iounmap(par->dc_regs); + iounmap(info->screen_base); + release_mem_region(info->fix.smem_start, size); + kfree(info); +} + +#ifndef MODULE +static int __init +imsttfb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "font:", 5)) { + char *p; + int i; + + p = this_opt + 5; + for (i = 0; i < sizeof(fontname) - 1; i++) + if (!*p || *p == ' ' || *p == ',') + break; + memcpy(fontname, this_opt + 5, i); + fontname[i] = 0; + } else if (!strncmp(this_opt, "inverse", 7)) { + inverse = 1; + fb_invert_cmaps(); + } +#if defined(CONFIG_PPC) + else if (!strncmp(this_opt, "vmode:", 6)) { + int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + init_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + int cmode = simple_strtoul(this_opt+6, NULL, 0); + switch (cmode) { + case CMODE_8: + case 8: + init_cmode = CMODE_8; + break; + case CMODE_16: + case 15: + case 16: + init_cmode = CMODE_16; + break; + case CMODE_32: + case 24: + case 32: + init_cmode = CMODE_32; + break; + } + } +#endif + } + return 0; +} + +#endif /* MODULE */ + +static int __init imsttfb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("imsttfb", &option)) + return -ENODEV; + + imsttfb_setup(option); +#endif + return pci_register_driver(&imsttfb_pci_driver); +} + +static void __exit imsttfb_exit(void) +{ + pci_unregister_driver(&imsttfb_pci_driver); +} + +MODULE_LICENSE("GPL"); + +module_init(imsttfb_init); +module_exit(imsttfb_exit); + diff --git a/drivers/video/intelfb/Makefile b/drivers/video/intelfb/Makefile new file mode 100644 index 000000000000..722d21d6e5cd --- /dev/null +++ b/drivers/video/intelfb/Makefile @@ -0,0 +1,8 @@ +obj-$(CONFIG_FB_INTEL) += intelfb.o + +intelfb-objs := intelfbdrv.o intelfbhw.o + +ifdef CONFIG_FB_INTEL_DEBUG +#EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP +EXTRA_CFLAGS += -DDEBUG -DREGDUMP +endif diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h new file mode 100644 index 000000000000..6680ec9ba69e --- /dev/null +++ b/drivers/video/intelfb/intelfb.h @@ -0,0 +1,280 @@ +#ifndef _INTELFB_H +#define _INTELFB_H + +/* $DHD: intelfb/intelfb.h,v 1.40 2003/06/27 15:06:25 dawes Exp $ */ + +#include <linux/agp_backend.h> +#include <linux/fb.h> + + +/*** Version/name ***/ +#define INTELFB_VERSION "0.9.2" +#define INTELFB_MODULE_NAME "intelfb" +#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G" + + +/*** Debug/feature defines ***/ + +#ifndef DEBUG +#define DEBUG 0 +#endif + +#ifndef VERBOSE +#define VERBOSE 0 +#endif + +#ifndef REGDUMP +#define REGDUMP 0 +#endif + +#ifndef DETECT_VGA_CLASS_ONLY +#define DETECT_VGA_CLASS_ONLY 1 +#endif + +#ifndef ALLOCATE_FOR_PANNING +#define ALLOCATE_FOR_PANNING 1 +#endif + +#ifndef PREFERRED_MODE +#define PREFERRED_MODE "1024x768-32@70" +#endif + +/*** hw-related values ***/ + +/* PCI ids for supported devices */ +#define PCI_DEVICE_ID_INTEL_830M 0x3577 +#define PCI_DEVICE_ID_INTEL_845G 0x2562 +#define PCI_DEVICE_ID_INTEL_85XGM 0x3582 +#define PCI_DEVICE_ID_INTEL_865G 0x2572 +#define PCI_DEVICE_ID_INTEL_915G 0x2582 + +/* Size of MMIO region */ +#define INTEL_REG_SIZE 0x80000 + +#define STRIDE_ALIGNMENT 16 + +#define PALETTE_8_ENTRIES 256 + + +/*** Macros ***/ + +/* basic arithmetic */ +#define KB(x) ((x) * 1024) +#define MB(x) ((x) * 1024 * 1024) +#define BtoKB(x) ((x) / 1024) +#define BtoMB(x) ((x) / 1024 / 1024) + +#define GTT_PAGE_SIZE KB(4) + +#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) +#define ROUND_DOWN_TO(x, y) ((x) / (y) * (y)) +#define ROUND_UP_TO_PAGE(x) ROUND_UP_TO((x), GTT_PAGE_SIZE) +#define ROUND_DOWN_TO_PAGE(x) ROUND_DOWN_TO((x), GTT_PAGE_SIZE) + +/* messages */ +#define PFX INTELFB_MODULE_NAME ": " + +#define ERR_MSG(fmt, args...) printk(KERN_ERR PFX fmt, ## args) +#define WRN_MSG(fmt, args...) printk(KERN_WARNING PFX fmt, ## args) +#define NOT_MSG(fmt, args...) printk(KERN_NOTICE PFX fmt, ## args) +#define INF_MSG(fmt, args...) printk(KERN_INFO PFX fmt, ## args) +#if DEBUG +#define DBG_MSG(fmt, args...) printk(KERN_DEBUG PFX fmt, ## args) +#else +#define DBG_MSG(fmt, args...) while (0) printk(fmt, ## args) +#endif + +/* get commonly used pointers */ +#define GET_DINFO(info) (info)->par + +/* misc macros */ +#define ACCEL(d, i) \ + ((d)->accel && !(d)->ring_lockup && \ + ((i)->var.accel_flags & FB_ACCELF_TEXT)) + +/*#define NOACCEL_CHIPSET(d) \ + ((d)->chipset != INTEL_865G)*/ +#define NOACCEL_CHIPSET(d) \ + (0) + +#define FIXED_MODE(d) ((d)->fixed_mode) + +/*** Driver paramters ***/ + +#define RINGBUFFER_SIZE KB(64) +#define HW_CURSOR_SIZE KB(4) + +/* Intel agpgart driver */ +#define AGP_PHYSICAL_MEMORY 2 + +/*** Data Types ***/ + +/* supported chipsets */ +enum intel_chips { + INTEL_830M, + INTEL_845G, + INTEL_85XGM, + INTEL_852GM, + INTEL_852GME, + INTEL_855GM, + INTEL_855GME, + INTEL_865G, + INTEL_915G +}; + +struct intelfb_hwstate { + u32 vga0_divisor; + u32 vga1_divisor; + u32 vga_pd; + u32 dpll_a; + u32 dpll_b; + u32 fpa0; + u32 fpa1; + u32 fpb0; + u32 fpb1; + u32 palette_a[PALETTE_8_ENTRIES]; + u32 palette_b[PALETTE_8_ENTRIES]; + u32 htotal_a; + u32 hblank_a; + u32 hsync_a; + u32 vtotal_a; + u32 vblank_a; + u32 vsync_a; + u32 src_size_a; + u32 bclrpat_a; + u32 htotal_b; + u32 hblank_b; + u32 hsync_b; + u32 vtotal_b; + u32 vblank_b; + u32 vsync_b; + u32 src_size_b; + u32 bclrpat_b; + u32 adpa; + u32 dvoa; + u32 dvob; + u32 dvoc; + u32 dvoa_srcdim; + u32 dvob_srcdim; + u32 dvoc_srcdim; + u32 lvds; + u32 pipe_a_conf; + u32 pipe_b_conf; + u32 disp_arb; + u32 cursor_a_control; + u32 cursor_b_control; + u32 cursor_a_base; + u32 cursor_b_base; + u32 cursor_size; + u32 disp_a_ctrl; + u32 disp_b_ctrl; + u32 disp_a_base; + u32 disp_b_base; + u32 cursor_a_palette[4]; + u32 cursor_b_palette[4]; + u32 disp_a_stride; + u32 disp_b_stride; + u32 vgacntrl; + u32 add_id; + u32 swf0x[7]; + u32 swf1x[7]; + u32 swf3x[3]; + u32 fence[8]; + u32 instpm; + u32 mem_mode; + u32 fw_blc_0; + u32 fw_blc_1; +}; + +struct intelfb_heap_data { + u32 physical; + u8 __iomem *virtual; + u32 offset; // in GATT pages + u32 size; // in bytes +}; + +struct intelfb_info { + struct fb_info *info; + struct fb_ops *fbops; + struct pci_dev *pdev; + + struct intelfb_hwstate save_state; + + /* agpgart structs */ + struct agp_memory *gtt_fb_mem; // use all stolen memory or vram + struct agp_memory *gtt_ring_mem; // ring buffer + struct agp_memory *gtt_cursor_mem; // hw cursor + + /* use a gart reserved fb mem */ + u8 fbmem_gart; + + /* mtrr support */ + u32 mtrr_reg; + u32 has_mtrr; + + /* heap data */ + struct intelfb_heap_data aperture; + struct intelfb_heap_data fb; + struct intelfb_heap_data ring; + struct intelfb_heap_data cursor; + + /* mmio regs */ + u32 mmio_base_phys; + u8 __iomem *mmio_base; + + /* fb start offset (in bytes) */ + u32 fb_start; + + /* ring buffer */ + u8 __iomem *ring_head; + u32 ring_tail; + u32 ring_tail_mask; + u32 ring_space; + u32 ring_lockup; + + /* palette */ + u32 pseudo_palette[17]; + struct { u8 red, green, blue, pad; } palette[256]; + + /* chip info */ + int pci_chipset; + int chipset; + const char *name; + int mobile; + + /* current mode */ + int bpp, depth; + u32 visual; + int xres, yres, pitch; + int pixclock; + + /* current pipe */ + int pipe; + + /* some flags */ + int accel; + int hwcursor; + int fixed_mode; + int ring_active; + + /* hw cursor */ + int cursor_on; + int cursor_blanked; + u8 cursor_src[64]; + + /* initial parameters */ + int initial_vga; + struct fb_var_screeninfo initial_var; + u32 initial_fb_base; + u32 initial_video_ram; + u32 initial_pitch; + + /* driver registered */ + int registered; +}; + +/*** function prototypes ***/ + +extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); + +#endif /* _INTELFB_H */ diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c new file mode 100644 index 000000000000..6a05b7000830 --- /dev/null +++ b/drivers/video/intelfb/intelfbdrv.c @@ -0,0 +1,1570 @@ +/* + * intelfb + * + * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G + * integrated graphics chips. + * + * Copyright 2002, 2003 David Dawes <dawes@xfree86.org> + * 2004 Sylvain Meyer + * + * This driver consists of two parts. The first part (intelfbdrv.c) provides + * the basic fbdev interfaces, is derived in part from the radeonfb and + * vesafb drivers, and is covered by the GPL. The second part (intelfbhw.c) + * provides the code to program the hardware. Most of it is derived from + * the i810/i830 XFree86 driver. The HW-specific code is covered here + * under a dual license (GPL and MIT/XFree86 license). + * + * Author: David Dawes + * + */ + +/* $DHD: intelfb/intelfbdrv.c,v 1.20 2003/06/27 15:17:40 dawes Exp $ */ + +/* + * Changes: + * 01/2003 - Initial driver (0.1.0), no mode switching, no acceleration. + * This initial version is a basic core that works a lot like + * the vesafb driver. It must be built-in to the kernel, + * and the initial video mode must be set with vga=XXX at + * boot time. (David Dawes) + * + * 01/2003 - Version 0.2.0: Mode switching added, colormap support + * implemented, Y panning, and soft screen blanking implemented. + * No acceleration yet. (David Dawes) + * + * 01/2003 - Version 0.3.0: fbcon acceleration support added. Module + * option handling added. (David Dawes) + * + * 01/2003 - Version 0.4.0: fbcon HW cursor support added. (David Dawes) + * + * 01/2003 - Version 0.4.1: Add auto-generation of built-in modes. + * (David Dawes) + * + * 02/2003 - Version 0.4.2: Add check for active non-CRT devices, and + * mode validation checks. (David Dawes) + * + * 02/2003 - Version 0.4.3: Check when the VC is in graphics mode so that + * acceleration is disabled while an XFree86 server is running. + * (David Dawes) + * + * 02/2003 - Version 0.4.4: Monitor DPMS support. (David Dawes) + * + * 02/2003 - Version 0.4.5: Basic XFree86 + fbdev working. (David Dawes) + * + * 02/2003 - Version 0.5.0: Modify to work with the 2.5.32 kernel as well + * as 2.4.x kernels. (David Dawes) + * + * 02/2003 - Version 0.6.0: Split out HW-specifics into a separate file. + * (David Dawes) + * + * 02/2003 - Version 0.7.0: Test on 852GM/855GM. Acceleration and HW + * cursor are disabled on this platform. (David Dawes) + * + * 02/2003 - Version 0.7.1: Test on 845G. Acceleration is disabled + * on this platform. (David Dawes) + * + * 02/2003 - Version 0.7.2: Test on 830M. Acceleration and HW + * cursor are disabled on this platform. (David Dawes) + * + * 02/2003 - Version 0.7.3: Fix 8-bit modes for mobile platforms + * (David Dawes) + * + * 02/2003 - Version 0.7.4: Add checks for FB and FBCON_HAS_CFB* configured + * in the kernel, and add mode bpp verification and default + * bpp selection based on which FBCON_HAS_CFB* are configured. + * (David Dawes) + * + * 02/2003 - Version 0.7.5: Add basic package/install scripts based on the + * DRI packaging scripts. (David Dawes) + * + * 04/2003 - Version 0.7.6: Fix typo that affects builds with SMP-enabled + * kernels. (David Dawes, reported by Anupam). + * + * 06/2003 - Version 0.7.7: + * Fix Makefile.kernel build problem (Tsutomu Yasuda). + * Fix mis-placed #endif (2.4.21 kernel). + * + * 09/2004 - Version 0.9.0 - by Sylvain Meyer + * Port to linux 2.6 kernel fbdev + * Fix HW accel and HW cursor on i845G + * Use of agpgart for fb memory reservation + * Add mtrr support + * + * 10/2004 - Version 0.9.1 + * Use module_param instead of old MODULE_PARM + * Some cleanup + * + * 11/2004 - Version 0.9.2 + * Add vram option to reserve more memory than stolen by BIOS + * Fix intelfbhw_pan_display typo + * Add __initdata annotations + * + * TODO: + * + * + * Wish List: + * + * + */ + +#include <linux/config.h> +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/console.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/vmalloc.h> +#include <linux/kd.h> +#include <linux/vt_kern.h> +#include <linux/pagemap.h> +#include <linux/version.h> + +#include <asm/io.h> + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include "intelfb.h" +#include "intelfbdrv.h" +#include "intelfbhw.h" + +/* + * Limiting the class to PCI_CLASS_DISPLAY_VGA prevents function 1 of the + * mobile chipsets from being registered. + */ +#if DETECT_VGA_CLASS_ONLY +#define INTELFB_CLASS_MASK ~0 << 8 +#else +#define INTELFB_CLASS_MASK 0 +#endif + +static struct pci_device_id intelfb_pci_table[] __devinitdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_830M, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_830M }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_845G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_845G }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_85XGM }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G }, + { 0, } +}; + +/* Global data */ +static int num_registered = 0; + +/* fb ops */ +static struct fb_ops intel_fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = intelfb_check_var, + .fb_set_par = intelfb_set_par, + .fb_setcolreg = intelfb_setcolreg, + .fb_blank = intelfb_blank, + .fb_pan_display = intelfb_pan_display, + .fb_fillrect = intelfb_fillrect, + .fb_copyarea = intelfb_copyarea, + .fb_imageblit = intelfb_imageblit, + .fb_cursor = intelfb_cursor, + .fb_sync = intelfb_sync, + .fb_ioctl = intelfb_ioctl +}; + +/* PCI driver module table */ +static struct pci_driver intelfb_driver = { + .name = "Intel(R) " SUPPORTED_CHIPSETS " Framebuffer Driver", + .id_table = intelfb_pci_table, + .probe = intelfb_pci_register, + .remove = __devexit_p(intelfb_pci_unregister) +}; + +/* Module description/parameters */ +MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>, " + "Sylvain Meyer <sylvain.meyer@worldonline.fr>"); +MODULE_DESCRIPTION( + "Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS " chipsets"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DEVICE_TABLE(pci, intelfb_pci_table); + +static int accel __initdata = 1; +static int vram __initdata = 4; +static int hwcursor __initdata = 1; +static int mtrr __initdata = 1; +static int fixed __initdata = 0; +static int noinit __initdata = 0; +static int noregister __initdata = 0; +static int probeonly __initdata = 0; +static int idonly __initdata = 0; +static int bailearly __initdata = 0; +static char *mode __initdata = NULL; + +module_param(accel, bool, S_IRUGO); +MODULE_PARM_DESC(accel, "Enable console acceleration"); +module_param(vram, int, S_IRUGO); +MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB"); +module_param(hwcursor, bool, S_IRUGO); +MODULE_PARM_DESC(hwcursor, "Enable HW cursor"); +module_param(mtrr, bool, S_IRUGO); +MODULE_PARM_DESC(mtrr, "Enable MTRR support"); +module_param(fixed, bool, S_IRUGO); +MODULE_PARM_DESC(fixed, "Disable mode switching"); +module_param(noinit, bool, 0); +MODULE_PARM_DESC(noinit, "Don't initialise graphics mode when loading"); +module_param(noregister, bool, 0); +MODULE_PARM_DESC(noregister, "Don't register, just probe and exit (debug)"); +module_param(probeonly, bool, 0); +MODULE_PARM_DESC(probeonly, "Do a minimal probe (debug)"); +module_param(idonly, bool, 0); +MODULE_PARM_DESC(idonly, "Just identify without doing anything else (debug)"); +module_param(bailearly, bool, 0); +MODULE_PARM_DESC(bailearly, "Bail out early, depending on value (debug)"); +module_param(mode, charp, S_IRUGO); +MODULE_PARM_DESC(mode, + "Initial video mode \"<xres>x<yres>[-<depth>][@<refresh>]\""); + +#ifndef MODULE +#define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name))) +#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name), NULL, 0) +#define OPT_STRVAL(opt, name) (opt + strlen(name)) + +static __inline__ char * +get_opt_string(const char *this_opt, const char *name) +{ + const char *p; + int i; + char *ret; + + p = OPT_STRVAL(this_opt, name); + i = 0; + while (p[i] && p[i] != ' ' && p[i] != ',') + i++; + ret = kmalloc(i + 1, GFP_KERNEL); + if (ret) { + strncpy(ret, p, i); + ret[i] = '\0'; + } + return ret; +} + +static __inline__ int +get_opt_int(const char *this_opt, const char *name, int *ret) +{ + if (!ret) + return 0; + + if (!OPT_EQUAL(this_opt, name)) + return 0; + + *ret = OPT_INTVAL(this_opt, name); + return 1; +} + +static __inline__ int +get_opt_bool(const char *this_opt, const char *name, int *ret) +{ + if (!ret) + return 0; + + if (OPT_EQUAL(this_opt, name)) { + if (this_opt[strlen(name)] == '=') + *ret = simple_strtoul(this_opt + strlen(name) + 1, + NULL, 0); + else + *ret = 1; + } else { + if (OPT_EQUAL(this_opt, "no") && OPT_EQUAL(this_opt + 2, name)) + *ret = 0; + else + return 0; + } + return 1; +} + +static int __init +intelfb_setup(char *options) +{ + char *this_opt; + + DBG_MSG("intelfb_setup\n"); + + if (!options || !*options) { + DBG_MSG("no options\n"); + return 0; + } else + DBG_MSG("options: %s\n", options); + + /* + * These are the built-in options analogous to the module parameters + * defined above. + * + * The syntax is: + * + * video=intelfb:[mode][,<param>=<val>] ... + * + * e.g., + * + * video=intelfb:1024x768-16@75,accel=0 + */ + + while ((this_opt = strsep(&options, ","))) { + if (!*this_opt) + continue; + if (get_opt_bool(this_opt, "accel", &accel)) + ; + else if (get_opt_int(this_opt, "vram", &vram)) + ; + else if (get_opt_bool(this_opt, "hwcursor", &hwcursor)) + ; + else if (get_opt_bool(this_opt, "mtrr", &mtrr)) + ; + else if (get_opt_bool(this_opt, "fixed", &fixed)) + ; + else if (get_opt_bool(this_opt, "init", &noinit)) + noinit = !noinit; + else if (OPT_EQUAL(this_opt, "mode=")) + mode = get_opt_string(this_opt, "mode="); + else + mode = this_opt; + } + + return 0; +} + +#endif + +static int __init +intelfb_init(void) +{ +#ifndef MODULE + char *option = NULL; +#endif + + DBG_MSG("intelfb_init\n"); + + INF_MSG("Framebuffer driver for " + "Intel(R) " SUPPORTED_CHIPSETS " chipsets\n"); + INF_MSG("Version " INTELFB_VERSION "\n"); + + if (idonly) + return -ENODEV; + +#ifndef MODULE + if (fb_get_options("intelfb", &option)) + return -ENODEV; + intelfb_setup(option); +#endif + + return pci_register_driver(&intelfb_driver); +} + +static void __exit +intelfb_exit(void) +{ + DBG_MSG("intelfb_exit\n"); + pci_unregister_driver(&intelfb_driver); +} + +module_init(intelfb_init); +module_exit(intelfb_exit); + +/*************************************************************** + * mtrr support functions * + ***************************************************************/ + +#ifdef CONFIG_MTRR +static inline void __devinit set_mtrr(struct intelfb_info *dinfo) +{ + dinfo->mtrr_reg = mtrr_add(dinfo->aperture.physical, + dinfo->aperture.size, MTRR_TYPE_WRCOMB, 1); + if (dinfo->mtrr_reg < 0) { + ERR_MSG("unable to set MTRR\n"); + return; + } + dinfo->has_mtrr = 1; +} +static inline void unset_mtrr(struct intelfb_info *dinfo) +{ + if (dinfo->has_mtrr) + mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical, + dinfo->aperture.size); +} +#else +#define set_mtrr(x) WRN_MSG("MTRR is disabled in the kernel\n") + +#define unset_mtrr(x) do { } while (0) +#endif /* CONFIG_MTRR */ + +/*************************************************************** + * driver init / cleanup * + ***************************************************************/ + +static void +cleanup(struct intelfb_info *dinfo) +{ + DBG_MSG("cleanup\n"); + + if (!dinfo) + return; + + fb_dealloc_cmap(&dinfo->info->cmap); + kfree(dinfo->info->pixmap.addr); + + if (dinfo->registered) + unregister_framebuffer(dinfo->info); + + unset_mtrr(dinfo); + + if (dinfo->fbmem_gart && dinfo->gtt_fb_mem) { + agp_unbind_memory(dinfo->gtt_fb_mem); + agp_free_memory(dinfo->gtt_fb_mem); + } + if (dinfo->gtt_cursor_mem) { + agp_unbind_memory(dinfo->gtt_cursor_mem); + agp_free_memory(dinfo->gtt_cursor_mem); + } + if (dinfo->gtt_ring_mem) { + agp_unbind_memory(dinfo->gtt_ring_mem); + agp_free_memory(dinfo->gtt_ring_mem); + } + + if (dinfo->mmio_base) + iounmap((void __iomem *)dinfo->mmio_base); + if (dinfo->aperture.virtual) + iounmap((void __iomem *)dinfo->aperture.virtual); + + if (dinfo->mmio_base_phys) + release_mem_region(dinfo->mmio_base_phys, INTEL_REG_SIZE); + if (dinfo->aperture.physical) + release_mem_region(dinfo->aperture.physical, + dinfo->aperture.size); + framebuffer_release(dinfo->info); +} + +#define bailout(dinfo) do { \ + DBG_MSG("bailout\n"); \ + cleanup(dinfo); \ + INF_MSG("Not going to register framebuffer, exiting...\n"); \ + return -ENODEV; \ +} while (0) + + +static int __devinit +intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct fb_info *info; + struct intelfb_info *dinfo; + int i, j, err, dvo; + int aperture_size, stolen_size; + struct agp_kern_info gtt_info; + int agp_memtype; + const char *s; + struct agp_bridge_data *bridge; + int aperture_bar = 0; + int mmio_bar = 1; + + DBG_MSG("intelfb_pci_register\n"); + + num_registered++; + if (num_registered != 1) { + ERR_MSG("Attempted to register %d devices " + "(should be only 1).\n", num_registered); + return -ENODEV; + } + + info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev); + if (!info) { + ERR_MSG("Could not allocate memory for intelfb_info.\n"); + return -ENODEV; + } + if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) { + ERR_MSG("Could not allocate cmap for intelfb_info.\n"); + goto err_out_cmap; + return -ENODEV; + } + + dinfo = info->par; + dinfo->info = info; + dinfo->fbops = &intel_fb_ops; + dinfo->pdev = pdev; + + /* Reserve pixmap space. */ + info->pixmap.addr = kmalloc(64 * 1024, GFP_KERNEL); + if (info->pixmap.addr == NULL) { + ERR_MSG("Cannot reserve pixmap memory.\n"); + goto err_out_pixmap; + } + memset(info->pixmap.addr, 0, 64 * 1024); + + /* set early this option because it could be changed by tv encoder + driver */ + dinfo->fixed_mode = fixed; + + /* Enable device. */ + if ((err = pci_enable_device(pdev))) { + ERR_MSG("Cannot enable device.\n"); + cleanup(dinfo); + return -ENODEV; + } + + /* Set base addresses. */ + if (ent->device == PCI_DEVICE_ID_INTEL_915G) { + aperture_bar = 2; + mmio_bar = 0; + /* Disable HW cursor on 915G (not implemented yet) */ + hwcursor = 0; + } + dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar); + dinfo->aperture.size = pci_resource_len(pdev, aperture_bar); + dinfo->mmio_base_phys = pci_resource_start(pdev, mmio_bar); + DBG_MSG("fb aperture: 0x%llx/0x%llx, MMIO region: 0x%llx/0x%llx\n", + (unsigned long long)pci_resource_start(pdev, aperture_bar), + (unsigned long long)pci_resource_len(pdev, aperture_bar), + (unsigned long long)pci_resource_start(pdev, mmio_bar), + (unsigned long long)pci_resource_len(pdev, mmio_bar)); + + /* Reserve the fb and MMIO regions */ + if (!request_mem_region(dinfo->aperture.physical, dinfo->aperture.size, + INTELFB_MODULE_NAME)) { + ERR_MSG("Cannot reserve FB region.\n"); + cleanup(dinfo); + return -ENODEV; + } + if (!request_mem_region(dinfo->mmio_base_phys, + INTEL_REG_SIZE, + INTELFB_MODULE_NAME)) { + ERR_MSG("Cannot reserve MMIO region.\n"); + cleanup(dinfo); + return -ENODEV; + } + + /* Map the fb and MMIO regions */ + dinfo->aperture.virtual = (u8 __iomem *)ioremap_nocache + (dinfo->aperture.physical, dinfo->aperture.size); + if (!dinfo->aperture.virtual) { + ERR_MSG("Cannot remap FB region.\n"); + cleanup(dinfo); + return -ENODEV; + } + dinfo->mmio_base = + (u8 __iomem *)ioremap_nocache(dinfo->mmio_base_phys, + INTEL_REG_SIZE); + if (!dinfo->mmio_base) { + ERR_MSG("Cannot remap MMIO region.\n"); + cleanup(dinfo); + return -ENODEV; + } + + /* Get the chipset info. */ + dinfo->pci_chipset = pdev->device; + + if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset, + &dinfo->mobile)) { + cleanup(dinfo); + return -ENODEV; + } + + if (intelfbhw_get_memory(pdev, &aperture_size,&stolen_size)) { + cleanup(dinfo); + return -ENODEV; + } + + INF_MSG("%02x:%02x.%d: %s, aperture size %dMB, " + "stolen memory %dkB\n", + pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), dinfo->name, + BtoMB(aperture_size), BtoKB(stolen_size)); + + /* Set these from the options. */ + dinfo->accel = accel; + dinfo->hwcursor = hwcursor; + + if (NOACCEL_CHIPSET(dinfo) && dinfo->accel == 1) { + INF_MSG("Acceleration is not supported for the %s chipset.\n", + dinfo->name); + dinfo->accel = 0; + } + + /* Framebuffer parameters - Use all the stolen memory if >= vram */ + if (ROUND_UP_TO_PAGE(stolen_size) >= MB(vram)) { + dinfo->fb.size = ROUND_UP_TO_PAGE(stolen_size); + dinfo->fbmem_gart = 0; + } else { + dinfo->fb.size = MB(vram); + dinfo->fbmem_gart = 1; + } + + /* Allocate space for the ring buffer and HW cursor if enabled. */ + if (dinfo->accel) { + dinfo->ring.size = RINGBUFFER_SIZE; + dinfo->ring_tail_mask = dinfo->ring.size - 1; + } + if (dinfo->hwcursor) { + dinfo->cursor.size = HW_CURSOR_SIZE; + } + + /* Use agpgart to manage the GATT */ + if (!(bridge = agp_backend_acquire(pdev))) { + ERR_MSG("cannot acquire agp\n"); + cleanup(dinfo); + return -ENODEV; + } + + /* get the current gatt info */ + if (agp_copy_info(bridge, >t_info)) { + ERR_MSG("cannot get agp info\n"); + agp_backend_release(bridge); + cleanup(dinfo); + return -ENODEV; + } + + /* set the mem offsets - set them after the already used pages */ + if (dinfo->accel) { + dinfo->ring.offset = (stolen_size >> 12) + + gtt_info.current_memory; + } + if (dinfo->hwcursor) { + dinfo->cursor.offset = (stolen_size >> 12) + + + gtt_info.current_memory + (dinfo->ring.size >> 12); + } + if (dinfo->fbmem_gart) { + dinfo->fb.offset = (stolen_size >> 12) + + + gtt_info.current_memory + (dinfo->ring.size >> 12) + + (dinfo->cursor.size >> 12); + } + + /* Allocate memories (which aren't stolen) */ + if (dinfo->accel) { + if (!(dinfo->gtt_ring_mem = + agp_allocate_memory(bridge, dinfo->ring.size >> 12, + AGP_NORMAL_MEMORY))) { + ERR_MSG("cannot allocate ring buffer memory\n"); + agp_backend_release(bridge); + cleanup(dinfo); + return -ENOMEM; + } + if (agp_bind_memory(dinfo->gtt_ring_mem, + dinfo->ring.offset)) { + ERR_MSG("cannot bind ring buffer memory\n"); + agp_backend_release(bridge); + cleanup(dinfo); + return -EBUSY; + } + dinfo->ring.physical = dinfo->aperture.physical + + (dinfo->ring.offset << 12); + dinfo->ring.virtual = dinfo->aperture.virtual + + (dinfo->ring.offset << 12); + dinfo->ring_head = dinfo->ring.virtual; + } + if (dinfo->hwcursor) { + agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY + : AGP_NORMAL_MEMORY; + if (!(dinfo->gtt_cursor_mem = + agp_allocate_memory(bridge, dinfo->cursor.size >> 12, + agp_memtype))) { + ERR_MSG("cannot allocate cursor memory\n"); + agp_backend_release(bridge); + cleanup(dinfo); + return -ENOMEM; + } + if (agp_bind_memory(dinfo->gtt_cursor_mem, + dinfo->cursor.offset)) { + ERR_MSG("cannot bind cursor memory\n"); + agp_backend_release(bridge); + cleanup(dinfo); + return -EBUSY; + } + if (dinfo->mobile) + dinfo->cursor.physical + = dinfo->gtt_cursor_mem->physical; + else + dinfo->cursor.physical = dinfo->aperture.physical + + (dinfo->cursor.offset << 12); + dinfo->cursor.virtual = dinfo->aperture.virtual + + (dinfo->cursor.offset << 12); + } + if (dinfo->fbmem_gart) { + if (!(dinfo->gtt_fb_mem = + agp_allocate_memory(bridge, dinfo->fb.size >> 12, + AGP_NORMAL_MEMORY))) { + WRN_MSG("cannot allocate framebuffer memory - use " + "the stolen one\n"); + dinfo->fbmem_gart = 0; + } + if (agp_bind_memory(dinfo->gtt_fb_mem, + dinfo->fb.offset)) { + WRN_MSG("cannot bind framebuffer memory - use " + "the stolen one\n"); + dinfo->fbmem_gart = 0; + } + } + + /* update framebuffer memory parameters */ + if (!dinfo->fbmem_gart) + dinfo->fb.offset = 0; /* starts at offset 0 */ + dinfo->fb.physical = dinfo->aperture.physical + + (dinfo->fb.offset << 12); + dinfo->fb.virtual = dinfo->aperture.virtual + (dinfo->fb.offset << 12); + dinfo->fb_start = dinfo->fb.offset << 12; + + /* release agpgart */ + agp_backend_release(bridge); + + if (mtrr) + set_mtrr(dinfo); + + DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%x)\n", + dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size, + (u32 __iomem ) dinfo->fb.virtual); + DBG_MSG("MMIO: 0x%x/0x%x (0x%x)\n", + dinfo->mmio_base_phys, INTEL_REG_SIZE, + (u32 __iomem) dinfo->mmio_base); + DBG_MSG("ring buffer: 0x%x/0x%x (0x%x)\n", + dinfo->ring.physical, dinfo->ring.size, + (u32 __iomem ) dinfo->ring.virtual); + DBG_MSG("HW cursor: 0x%x/0x%x (0x%x) (offset 0x%x) (phys 0x%x)\n", + dinfo->cursor.physical, dinfo->cursor.size, + (u32 __iomem ) dinfo->cursor.virtual, dinfo->cursor.offset, + dinfo->cursor.physical); + + DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, " + "noinit = %d\n", vram, accel, hwcursor, fixed, noinit); + DBG_MSG("options: mode = \"%s\"\n", mode ? mode : ""); + + if (probeonly) + bailout(dinfo); + + /* + * Check if the LVDS port or any DVO ports are enabled. If so, + * don't allow mode switching + */ + dvo = intelfbhw_check_non_crt(dinfo); + if (dvo) { + dinfo->fixed_mode = 1; + WRN_MSG("Non-CRT device is enabled ( "); + i = 0; + while (dvo) { + if (dvo & 1) { + s = intelfbhw_dvo_to_string(1 << i); + if (s) + printk("%s ", s); + } + dvo >>= 1; + ++i; + } + printk("). Disabling mode switching.\n"); + } + + if (bailearly == 1) + bailout(dinfo); + + if (FIXED_MODE(dinfo) && ORIG_VIDEO_ISVGA != VIDEO_TYPE_VLFB) { + ERR_MSG("Video mode must be programmed at boot time.\n"); + cleanup(dinfo); + return -ENODEV; + } + + if (bailearly == 2) + bailout(dinfo); + + /* Initialise dinfo and related data. */ + /* If an initial mode was programmed at boot time, get its details. */ + if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) + get_initial_mode(dinfo); + + if (bailearly == 3) + bailout(dinfo); + + if (FIXED_MODE(dinfo)) { + /* remap fb address */ + update_dinfo(dinfo, &dinfo->initial_var); + } + + if (bailearly == 4) + bailout(dinfo); + + + if (intelfb_set_fbinfo(dinfo)) { + cleanup(dinfo); + return -ENODEV; + } + + if (bailearly == 5) + bailout(dinfo); + + for (i = 0; i < 16; i++) { + j = color_table[i]; + dinfo->palette[i].red = default_red[j]; + dinfo->palette[i].green = default_grn[j]; + dinfo->palette[i].blue = default_blu[j]; + } + + if (bailearly == 6) + bailout(dinfo); + + pci_set_drvdata(pdev, dinfo); + + /* Save the initial register state. */ + i = intelfbhw_read_hw_state(dinfo, &dinfo->save_state, + bailearly > 6 ? bailearly - 6 : 0); + if (i != 0) { + DBG_MSG("intelfbhw_read_hw_state returned %d\n", i); + bailout(dinfo); + } + + intelfbhw_print_hw_state(dinfo, &dinfo->save_state); + + if (bailearly == 18) + bailout(dinfo); + + /* Cursor initialisation */ + if (dinfo->hwcursor) { + intelfbhw_cursor_init(dinfo); + intelfbhw_cursor_reset(dinfo); + } + + if (bailearly == 19) + bailout(dinfo); + + /* 2d acceleration init */ + if (dinfo->accel) + intelfbhw_2d_start(dinfo); + + if (bailearly == 20) + bailout(dinfo); + + if (noregister) + bailout(dinfo); + + if (register_framebuffer(dinfo->info) < 0) { + ERR_MSG("Cannot register framebuffer.\n"); + cleanup(dinfo); + return -ENODEV; + } + + dinfo->registered = 1; + + return 0; + +err_out_pixmap: + fb_dealloc_cmap(&info->cmap); +err_out_cmap: + framebuffer_release(info); + return -ENODEV; +} + +static void __devexit +intelfb_pci_unregister(struct pci_dev *pdev) +{ + struct intelfb_info *dinfo = pci_get_drvdata(pdev); + + DBG_MSG("intelfb_pci_unregister\n"); + + if (!dinfo) + return; + + cleanup(dinfo); + + pci_set_drvdata(pdev, NULL); +} + +/*************************************************************** + * helper functions * + ***************************************************************/ + +int __inline__ +intelfb_var_to_depth(const struct fb_var_screeninfo *var) +{ + DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n", + var->bits_per_pixel, var->green.length); + + switch (var->bits_per_pixel) { + case 16: + return (var->green.length == 6) ? 16 : 15; + case 32: + return 24; + default: + return var->bits_per_pixel; + } +} + + +static __inline__ int +var_to_refresh(const struct fb_var_screeninfo *var) +{ + int xtot = var->xres + var->left_margin + var->right_margin + + var->hsync_len; + int ytot = var->yres + var->upper_margin + var->lower_margin + + var->vsync_len; + + return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot; +} + +/*************************************************************** + * Various intialisation functions * + ***************************************************************/ + +static void __devinit +get_initial_mode(struct intelfb_info *dinfo) +{ + struct fb_var_screeninfo *var; + int xtot, ytot; + + DBG_MSG("get_initial_mode\n"); + + dinfo->initial_vga = 1; + dinfo->initial_fb_base = screen_info.lfb_base; + dinfo->initial_video_ram = screen_info.lfb_size * KB(64); + dinfo->initial_pitch = screen_info.lfb_linelength; + + var = &dinfo->initial_var; + memset(var, 0, sizeof(*var)); + var->xres = screen_info.lfb_width; + var->yres = screen_info.lfb_height; + var->bits_per_pixel = screen_info.lfb_depth; + switch (screen_info.lfb_depth) { + case 15: + var->bits_per_pixel = 16; + break; + case 24: + var->bits_per_pixel = 32; + break; + } + + DBG_MSG("Initial info: FB is 0x%x/0x%x (%d kByte)\n", + dinfo->initial_fb_base, dinfo->initial_video_ram, + BtoKB(dinfo->initial_video_ram)); + + DBG_MSG("Initial info: mode is %dx%d-%d (%d)\n", + var->xres, var->yres, var->bits_per_pixel, + dinfo->initial_pitch); + + /* Dummy timing values (assume 60Hz) */ + var->left_margin = (var->xres / 8) & 0xf8; + var->right_margin = 32; + var->upper_margin = 16; + var->lower_margin = 4; + var->hsync_len = (var->xres / 8) & 0xf8; + var->vsync_len = 4; + + xtot = var->xres + var->left_margin + + var->right_margin + var->hsync_len; + ytot = var->yres + var->upper_margin + + var->lower_margin + var->vsync_len; + var->pixclock = 10000000 / xtot * 1000 / ytot * 100 / 60; + + var->height = -1; + var->width = -1; + + if (var->bits_per_pixel > 8) { + var->red.offset = screen_info.red_pos; + var->red.length = screen_info.red_size; + var->green.offset = screen_info.green_pos; + var->green.length = screen_info.green_size; + var->blue.offset = screen_info.blue_pos; + var->blue.length = screen_info.blue_size; + var->transp.offset = screen_info.rsvd_pos; + var->transp.length = screen_info.rsvd_size; + } else { + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + } +} + +static int __devinit +intelfb_init_var(struct intelfb_info *dinfo) +{ + struct fb_var_screeninfo *var; + int msrc = 0; + + DBG_MSG("intelfb_init_var\n"); + + var = &dinfo->info->var; + if (FIXED_MODE(dinfo)) { + memcpy(var, &dinfo->initial_var, + sizeof(struct fb_var_screeninfo)); + msrc = 5; + } else { + if (mode) { + msrc = fb_find_mode(var, dinfo->info, mode, + vesa_modes, VESA_MODEDB_SIZE, + NULL, 0); + if (msrc) + msrc |= 8; + } + if (!msrc) { + msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE, + vesa_modes, VESA_MODEDB_SIZE, + NULL, 0); + } + } + + if (!msrc) { + ERR_MSG("Cannot find a suitable video mode.\n"); + return 1; + } + + INF_MSG("Initial video mode is %dx%d-%d@%d.\n", var->xres, var->yres, + var->bits_per_pixel, var_to_refresh(var)); + + DBG_MSG("Initial video mode is from %d.\n", msrc); + +#if ALLOCATE_FOR_PANNING + /* Allow use of half of the video ram for panning */ + var->xres_virtual = var->xres; + var->yres_virtual = + dinfo->fb.size / 2 / (var->bits_per_pixel * var->xres); + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; +#else + var->yres_virtual = var->yres; +#endif + + if (dinfo->accel) + var->accel_flags |= FB_ACCELF_TEXT; + else + var->accel_flags &= ~FB_ACCELF_TEXT; + + return 0; +} + +static int __devinit +intelfb_set_fbinfo(struct intelfb_info *dinfo) +{ + struct fb_info *info = dinfo->info; + + DBG_MSG("intelfb_set_fbinfo\n"); + + info->flags = FBINFO_FLAG_DEFAULT; + info->fbops = &intel_fb_ops; + info->pseudo_palette = dinfo->pseudo_palette; + + info->pixmap.size = 64*1024; + info->pixmap.buf_align = 8; + info->pixmap.flags = FB_PIXMAP_SYSTEM; + + if (intelfb_init_var(dinfo)) + return 1; + + info->pixmap.scan_align = 1; + + update_dinfo(dinfo, &info->var); + + return 0; +} + +/* Update dinfo to match the active video mode. */ +static void +update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var) +{ + DBG_MSG("update_dinfo\n"); + + dinfo->bpp = var->bits_per_pixel; + dinfo->depth = intelfb_var_to_depth(var); + dinfo->xres = var->xres; + dinfo->yres = var->xres; + dinfo->pixclock = var->pixclock; + + intelfb_get_fix(&dinfo->info->fix, dinfo->info); + + switch (dinfo->bpp) { + case 8: + dinfo->visual = FB_VISUAL_PSEUDOCOLOR; + dinfo->pitch = var->xres_virtual; + break; + case 16: + dinfo->visual = FB_VISUAL_TRUECOLOR; + dinfo->pitch = var->xres_virtual * 2; + break; + case 32: + dinfo->visual = FB_VISUAL_TRUECOLOR; + dinfo->pitch = var->xres_virtual * 4; + break; + } + + /* Make sure the line length is a aligned correctly. */ + dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT); + + if (FIXED_MODE(dinfo)) + dinfo->pitch = dinfo->initial_pitch; + + dinfo->info->screen_base = (char __iomem *)dinfo->fb.virtual; + dinfo->info->fix.line_length = dinfo->pitch; + dinfo->info->fix.visual = dinfo->visual; +} + +/* fbops functions */ + +static int +intelfb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + + DBG_MSG("intelfb_get_fix\n"); + + memset(fix, 0, sizeof(*fix)); + strcpy(fix->id, dinfo->name); + fix->smem_start = dinfo->fb.physical; + fix->smem_len = dinfo->fb.size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->visual = dinfo->visual; + fix->xpanstep = 8; + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = dinfo->pitch; + fix->mmio_start = dinfo->mmio_base_phys; + fix->mmio_len = INTEL_REG_SIZE; + fix->accel = FB_ACCEL_I830; + return 0; +} + +/*************************************************************** + * fbdev interface * + ***************************************************************/ + +static int +intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + int change_var = 0; + struct fb_var_screeninfo v; + struct intelfb_info *dinfo; + static int first = 1; + + DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags); + + dinfo = GET_DINFO(info); + + if (intelfbhw_validate_mode(dinfo, var) != 0) + return -EINVAL; + + v = *var; + + /* Check for a supported bpp. */ + if (v.bits_per_pixel <= 8) { + v.bits_per_pixel = 8; + } else if (v.bits_per_pixel <= 16) { + if (v.bits_per_pixel == 16) + v.green.length = 6; + v.bits_per_pixel = 16; + } else if (v.bits_per_pixel <= 32) { + v.bits_per_pixel = 32; + } else + return -EINVAL; + + change_var = ((info->var.xres != var->xres) || + (info->var.yres != var->yres) || + (info->var.xres_virtual != var->xres_virtual) || + (info->var.yres_virtual != var->yres_virtual) || + (info->var.bits_per_pixel != var->bits_per_pixel) || + memcmp(&info->var.red, &var->red, sizeof(var->red)) || + memcmp(&info->var.green, &var->green, + sizeof(var->green)) || + memcmp(&info->var.blue, &var->blue, sizeof(var->blue))); + + if (FIXED_MODE(dinfo) && + (change_var || + var->yres_virtual > dinfo->initial_var.yres_virtual || + var->yres_virtual < dinfo->initial_var.yres || + var->xoffset || var->nonstd)) { + if (first) { + ERR_MSG("Changing the video mode is not supported.\n"); + first = 0; + } + return -EINVAL; + } + + switch (intelfb_var_to_depth(&v)) { + case 8: + v.red.offset = v.green.offset = v.blue.offset = 0; + v.red.length = v.green.length = v.blue.length = 8; + v.transp.offset = v.transp.length = 0; + break; + case 15: + v.red.offset = 10; + v.green.offset = 5; + v.blue.offset = 0; + v.red.length = v.green.length = v.blue.length = 5; + v.transp.offset = v.transp.length = 0; + break; + case 16: + v.red.offset = 11; + v.green.offset = 5; + v.blue.offset = 0; + v.red.length = 5; + v.green.length = 6; + v.blue.length = 5; + v.transp.offset = v.transp.length = 0; + break; + case 24: + v.red.offset = 16; + v.green.offset = 8; + v.blue.offset = 0; + v.red.length = v.green.length = v.blue.length = 8; + v.transp.offset = v.transp.length = 0; + break; + case 32: + v.red.offset = 16; + v.green.offset = 8; + v.blue.offset = 0; + v.red.length = v.green.length = v.blue.length = 8; + v.transp.offset = 24; + v.transp.length = 8; + break; + } + + if (v.xoffset < 0) + v.xoffset = 0; + if (v.yoffset < 0) + v.yoffset = 0; + + if (v.xoffset > v.xres_virtual - v.xres) + v.xoffset = v.xres_virtual - v.xres; + if (v.yoffset > v.yres_virtual - v.yres) + v.yoffset = v.yres_virtual - v.yres; + + v.red.msb_right = v.green.msb_right = v.blue.msb_right = + v.transp.msb_right = 0; + + *var = v; + + return 0; +} + +static int +intelfb_set_par(struct fb_info *info) +{ + struct intelfb_hwstate *hw; + struct intelfb_info *dinfo = GET_DINFO(info); + + if (FIXED_MODE(dinfo)) { + ERR_MSG("Changing the video mode is not supported.\n"); + return -EINVAL; + } + + hw = kmalloc(sizeof(*hw), GFP_ATOMIC); + if (!hw) + return -ENOMEM; + + DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres, + info->var.yres, info->var.bits_per_pixel); + + intelfb_blank(FB_BLANK_POWERDOWN, info); + + if (dinfo->accel) + intelfbhw_2d_stop(dinfo); + + memcpy(hw, &dinfo->save_state, sizeof(*hw)); + if (intelfbhw_mode_to_hw(dinfo, hw, &info->var)) + goto invalid_mode; + if (intelfbhw_program_mode(dinfo, hw, 0)) + goto invalid_mode; + +#if REGDUMP > 0 + intelfbhw_read_hw_state(dinfo, hw, 0); + intelfbhw_print_hw_state(dinfo, hw); +#endif + + update_dinfo(dinfo, &info->var); + + if (dinfo->accel) + intelfbhw_2d_start(dinfo); + + intelfb_pan_display(&info->var, info); + + intelfb_blank(FB_BLANK_UNBLANK, info); + + if (ACCEL(dinfo, info)) { + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_IMAGEBLIT; + } else { + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + } + kfree(hw); + return 0; +invalid_mode: + kfree(hw); + return -EINVAL; +} + +static int +intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + +#if VERBOSE > 0 + DBG_MSG("intelfb_setcolreg: regno %d, depth %d\n", regno, dinfo->depth); +#endif + + if (regno > 255) + return 1; + + switch (dinfo->depth) { + case 8: + { + red >>= 8; + green >>= 8; + blue >>= 8; + + dinfo->palette[regno].red = red; + dinfo->palette[regno].green = green; + dinfo->palette[regno].blue = blue; + + intelfbhw_setcolreg(dinfo, regno, red, green, blue, + transp); + } + break; + case 15: + dinfo->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 16: + dinfo->pseudo_palette[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + dinfo->pseudo_palette[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + return 0; +} + +static int +intelfb_blank(int blank, struct fb_info *info) +{ + intelfbhw_do_blank(blank, info); + return 0; +} + +static int +intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + intelfbhw_pan_display(var, info); + return 0; +} + +/* When/if we have our own ioctls. */ +static int +intelfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *info) +{ + int retval = 0; + + return retval; +} + +static void +intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + u32 rop, color; + +#if VERBOSE > 0 + DBG_MSG("intelfb_fillrect\n"); +#endif + + if (!ACCEL(dinfo, info) || dinfo->depth == 4) + return cfb_fillrect(info, rect); + + if (rect->rop == ROP_COPY) + rop = PAT_ROP_GXCOPY; + else // ROP_XOR + rop = PAT_ROP_GXXOR; + + if (dinfo->depth != 8) + color = dinfo->pseudo_palette[rect->color]; + else + color = rect->color; + + intelfbhw_do_fillrect(dinfo, rect->dx, rect->dy, + rect->width, rect->height, color, + dinfo->pitch, info->var.bits_per_pixel, + rop); +} + +static void +intelfb_copyarea(struct fb_info *info, const struct fb_copyarea *region) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + +#if VERBOSE > 0 + DBG_MSG("intelfb_copyarea\n"); +#endif + + if (!ACCEL(dinfo, info) || dinfo->depth == 4) + return cfb_copyarea(info, region); + + intelfbhw_do_bitblt(dinfo, region->sx, region->sy, region->dx, + region->dy, region->width, region->height, + dinfo->pitch, info->var.bits_per_pixel); +} + +static void +intelfb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + u32 fgcolor, bgcolor; + +#if VERBOSE > 0 + DBG_MSG("intelfb_imageblit\n"); +#endif + + if (!ACCEL(dinfo, info) || dinfo->depth == 4 + || image->depth != 1) + return cfb_imageblit(info, image); + + if (dinfo->depth != 8) { + fgcolor = dinfo->pseudo_palette[image->fg_color]; + bgcolor = dinfo->pseudo_palette[image->bg_color]; + } else { + fgcolor = image->fg_color; + bgcolor = image->bg_color; + } + + if (!intelfbhw_do_drawglyph(dinfo, fgcolor, bgcolor, image->width, + image->height, image->data, + image->dx, image->dy, + dinfo->pitch, info->var.bits_per_pixel)) + return cfb_imageblit(info, image); +} + +static int +intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + +#if VERBOSE > 0 + DBG_MSG("intelfb_cursor\n"); +#endif + + if (!dinfo->hwcursor) + return soft_cursor(info, cursor); + + intelfbhw_cursor_hide(dinfo); + + /* If XFree killed the cursor - restore it */ + if (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.offset << 12) { + u32 fg, bg; + + DBG_MSG("the cursor was killed - restore it !!\n"); + DBG_MSG("size %d, %d pos %d, %d\n", + cursor->image.width, cursor->image.height, + cursor->image.dx, cursor->image.dy); + + intelfbhw_cursor_init(dinfo); + intelfbhw_cursor_reset(dinfo); + intelfbhw_cursor_setpos(dinfo, cursor->image.dx, + cursor->image.dy); + + if (dinfo->depth != 8) { + fg =dinfo->pseudo_palette[cursor->image.fg_color]; + bg =dinfo->pseudo_palette[cursor->image.bg_color]; + } else { + fg = cursor->image.fg_color; + bg = cursor->image.bg_color; + } + intelfbhw_cursor_setcolor(dinfo, bg, fg); + intelfbhw_cursor_load(dinfo, cursor->image.width, + cursor->image.height, + dinfo->cursor_src); + + if (cursor->enable) + intelfbhw_cursor_show(dinfo); + return 0; + } + + if (cursor->set & FB_CUR_SETPOS) { + u32 dx, dy; + + dx = cursor->image.dx - info->var.xoffset; + dy = cursor->image.dy - info->var.yoffset; + + intelfbhw_cursor_setpos(dinfo, dx, dy); + } + + if (cursor->set & FB_CUR_SETSIZE) { + if (cursor->image.width > 64 || cursor->image.height > 64) + return -ENXIO; + + intelfbhw_cursor_reset(dinfo); + } + + if (cursor->set & FB_CUR_SETCMAP) { + u32 fg, bg; + + if (dinfo->depth != 8) { + fg = dinfo->pseudo_palette[cursor->image.fg_color]; + bg = dinfo->pseudo_palette[cursor->image.bg_color]; + } else { + fg = cursor->image.fg_color; + bg = cursor->image.bg_color; + } + + intelfbhw_cursor_setcolor(dinfo, bg, fg); + } + + if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { + u32 s_pitch = (ROUND_UP_TO(cursor->image.width, 8) / 8); + u32 size = s_pitch * cursor->image.height; + u8 *dat = (u8 *) cursor->image.data; + u8 *msk = (u8 *) cursor->mask; + u8 src[64]; + u32 i; + + if (cursor->image.depth != 1) + return -ENXIO; + + switch (cursor->rop) { + case ROP_XOR: + for (i = 0; i < size; i++) + src[i] = dat[i] ^ msk[i]; + break; + case ROP_COPY: + default: + for (i = 0; i < size; i++) + src[i] = dat[i] & msk[i]; + break; + } + + /* save the bitmap to restore it when XFree will + make the cursor dirty */ + memcpy(dinfo->cursor_src, src, size); + + intelfbhw_cursor_load(dinfo, cursor->image.width, + cursor->image.height, src); + } + + if (cursor->enable) + intelfbhw_cursor_show(dinfo); + + return 0; +} + +static int +intelfb_sync(struct fb_info *info) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + +#if VERBOSE > 0 + DBG_MSG("intelfb_sync\n"); +#endif + + if (dinfo->ring_lockup) + return 0; + + intelfbhw_do_sync(dinfo); + return 0; +} + diff --git a/drivers/video/intelfb/intelfbdrv.h b/drivers/video/intelfb/intelfbdrv.h new file mode 100644 index 000000000000..cc3058128884 --- /dev/null +++ b/drivers/video/intelfb/intelfbdrv.h @@ -0,0 +1,68 @@ +#ifndef _INTELFBDRV_H +#define _INTELFBDRV_H + +/* + ****************************************************************************** + * intelfb + * + * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G + * integrated graphics chips. + * + * Copyright 2004 Sylvain Meyer + * + * Author: Sylvain Meyer + * + ****************************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +static void __devinit get_initial_mode(struct intelfb_info *dinfo); +static void update_dinfo(struct intelfb_info *dinfo, + struct fb_var_screeninfo *var); +static int intelfb_get_fix(struct fb_fix_screeninfo *fix, + struct fb_info *info); + +static int intelfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int intelfb_set_par(struct fb_info *info); +static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info); + +static int intelfb_blank(int blank, struct fb_info *info); +static int intelfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); + +static void intelfb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect); +static void intelfb_copyarea(struct fb_info *info, + const struct fb_copyarea *region); +static void intelfb_imageblit(struct fb_info *info, + const struct fb_image *image); +static int intelfb_cursor(struct fb_info *info, + struct fb_cursor *cursor); + +static int intelfb_sync(struct fb_info *info); + +static int intelfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + struct fb_info *info); + +static int __devinit intelfb_pci_register(struct pci_dev *pdev, + const struct pci_device_id *ent); +static void __devexit intelfb_pci_unregister(struct pci_dev *pdev); +static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo); + +#endif diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c new file mode 100644 index 000000000000..f5bed581dc45 --- /dev/null +++ b/drivers/video/intelfb/intelfbhw.c @@ -0,0 +1,1780 @@ +/* + * intelfb + * + * Linux framebuffer driver for Intel(R) 865G integrated graphics chips. + * + * Copyright 2002, 2003 David Dawes <dawes@xfree86.org> + * 2004 Sylvain Meyer + * + * This driver consists of two parts. The first part (intelfbdrv.c) provides + * the basic fbdev interfaces, is derived in part from the radeonfb and + * vesafb drivers, and is covered by the GPL. The second part (intelfbhw.c) + * provides the code to program the hardware. Most of it is derived from + * the i810/i830 XFree86 driver. The HW-specific code is covered here + * under a dual license (GPL and MIT/XFree86 license). + * + * Author: David Dawes + * + */ + +/* $DHD: intelfb/intelfbhw.c,v 1.9 2003/06/27 15:06:25 dawes Exp $ */ + +#include <linux/config.h> +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/console.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/vmalloc.h> +#include <linux/kd.h> +#include <linux/vt_kern.h> +#include <linux/pagemap.h> +#include <linux/version.h> + +#include <asm/io.h> + +#include "intelfb.h" +#include "intelfbhw.h" + +int +intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset, + int *mobile) +{ + u32 tmp; + + if (!pdev || !name || !chipset || !mobile) + return 1; + + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_830M: + *name = "Intel(R) 830M"; + *chipset = INTEL_830M; + *mobile = 1; + return 0; + case PCI_DEVICE_ID_INTEL_845G: + *name = "Intel(R) 845G"; + *chipset = INTEL_845G; + *mobile = 0; + return 0; + case PCI_DEVICE_ID_INTEL_85XGM: + tmp = 0; + *mobile = 1; + pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp); + switch ((tmp >> INTEL_85X_VARIANT_SHIFT) & + INTEL_85X_VARIANT_MASK) { + case INTEL_VAR_855GME: + *name = "Intel(R) 855GME"; + *chipset = INTEL_855GME; + return 0; + case INTEL_VAR_855GM: + *name = "Intel(R) 855GM"; + *chipset = INTEL_855GM; + return 0; + case INTEL_VAR_852GME: + *name = "Intel(R) 852GME"; + *chipset = INTEL_852GME; + return 0; + case INTEL_VAR_852GM: + *name = "Intel(R) 852GM"; + *chipset = INTEL_852GM; + return 0; + default: + *name = "Intel(R) 852GM/855GM"; + *chipset = INTEL_85XGM; + return 0; + } + break; + case PCI_DEVICE_ID_INTEL_865G: + *name = "Intel(R) 865G"; + *chipset = INTEL_865G; + *mobile = 0; + return 0; + case PCI_DEVICE_ID_INTEL_915G: + *name = "Intel(R) 915G"; + *chipset = INTEL_915G; + *mobile = 0; + return 0; + default: + return 1; + } +} + +int +intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, + int *stolen_size) +{ + struct pci_dev *bridge_dev; + u16 tmp; + + if (!pdev || !aperture_size || !stolen_size) + return 1; + + /* Find the bridge device. It is always 0:0.0 */ + if (!(bridge_dev = pci_find_slot(0, PCI_DEVFN(0, 0)))) { + ERR_MSG("cannot find bridge device\n"); + return 1; + } + + /* Get the fb aperture size and "stolen" memory amount. */ + tmp = 0; + pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp); + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_830M: + case PCI_DEVICE_ID_INTEL_845G: + if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M) + *aperture_size = MB(64); + else + *aperture_size = MB(128); + switch (tmp & INTEL_830_GMCH_GMS_MASK) { + case INTEL_830_GMCH_GMS_STOLEN_512: + *stolen_size = KB(512) - KB(132); + return 0; + case INTEL_830_GMCH_GMS_STOLEN_1024: + *stolen_size = MB(1) - KB(132); + return 0; + case INTEL_830_GMCH_GMS_STOLEN_8192: + *stolen_size = MB(8) - KB(132); + return 0; + case INTEL_830_GMCH_GMS_LOCAL: + ERR_MSG("only local memory found\n"); + return 1; + case INTEL_830_GMCH_GMS_DISABLED: + ERR_MSG("video memory is disabled\n"); + return 1; + default: + ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n", + tmp & INTEL_830_GMCH_GMS_MASK); + return 1; + } + break; + default: + *aperture_size = MB(128); + switch (tmp & INTEL_855_GMCH_GMS_MASK) { + case INTEL_855_GMCH_GMS_STOLEN_1M: + *stolen_size = MB(1) - KB(132); + return 0; + case INTEL_855_GMCH_GMS_STOLEN_4M: + *stolen_size = MB(4) - KB(132); + return 0; + case INTEL_855_GMCH_GMS_STOLEN_8M: + *stolen_size = MB(8) - KB(132); + return 0; + case INTEL_855_GMCH_GMS_STOLEN_16M: + *stolen_size = MB(16) - KB(132); + return 0; + case INTEL_855_GMCH_GMS_STOLEN_32M: + *stolen_size = MB(32) - KB(132); + return 0; + case INTEL_915G_GMCH_GMS_STOLEN_48M: + *stolen_size = MB(48) - KB(132); + return 0; + case INTEL_915G_GMCH_GMS_STOLEN_64M: + *stolen_size = MB(64) - KB(132); + return 0; + case INTEL_855_GMCH_GMS_DISABLED: + ERR_MSG("video memory is disabled\n"); + return 0; + default: + ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n", + tmp & INTEL_855_GMCH_GMS_MASK); + return 1; + } + } +} + +int +intelfbhw_check_non_crt(struct intelfb_info *dinfo) +{ + int dvo = 0; + + if (INREG(LVDS) & PORT_ENABLE) + dvo |= LVDS_PORT; + if (INREG(DVOA) & PORT_ENABLE) + dvo |= DVOA_PORT; + if (INREG(DVOB) & PORT_ENABLE) + dvo |= DVOB_PORT; + if (INREG(DVOC) & PORT_ENABLE) + dvo |= DVOC_PORT; + + return dvo; +} + +const char * +intelfbhw_dvo_to_string(int dvo) +{ + if (dvo & DVOA_PORT) + return "DVO port A"; + else if (dvo & DVOB_PORT) + return "DVO port B"; + else if (dvo & DVOC_PORT) + return "DVO port C"; + else if (dvo & LVDS_PORT) + return "LVDS port"; + else + return NULL; +} + + +int +intelfbhw_validate_mode(struct intelfb_info *dinfo, + struct fb_var_screeninfo *var) +{ + int bytes_per_pixel; + int tmp; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_validate_mode\n"); +#endif + + bytes_per_pixel = var->bits_per_pixel / 8; + if (bytes_per_pixel == 3) + bytes_per_pixel = 4; + + /* Check if enough video memory. */ + tmp = var->yres_virtual * var->xres_virtual * bytes_per_pixel; + if (tmp > dinfo->fb.size) { + WRN_MSG("Not enough video ram for mode " + "(%d KByte vs %d KByte).\n", + BtoKB(tmp), BtoKB(dinfo->fb.size)); + return 1; + } + + /* Check if x/y limits are OK. */ + if (var->xres - 1 > HACTIVE_MASK) { + WRN_MSG("X resolution too large (%d vs %d).\n", + var->xres, HACTIVE_MASK + 1); + return 1; + } + if (var->yres - 1 > VACTIVE_MASK) { + WRN_MSG("Y resolution too large (%d vs %d).\n", + var->yres, VACTIVE_MASK + 1); + return 1; + } + + /* Check for interlaced/doublescan modes. */ + if (var->vmode & FB_VMODE_INTERLACED) { + WRN_MSG("Mode is interlaced.\n"); + return 1; + } + if (var->vmode & FB_VMODE_DOUBLE) { + WRN_MSG("Mode is double-scan.\n"); + return 1; + } + + /* Check if clock is OK. */ + tmp = 1000000000 / var->pixclock; + if (tmp < MIN_CLOCK) { + WRN_MSG("Pixel clock is too low (%d MHz vs %d MHz).\n", + (tmp + 500) / 1000, MIN_CLOCK / 1000); + return 1; + } + if (tmp > MAX_CLOCK) { + WRN_MSG("Pixel clock is too high (%d MHz vs %d MHz).\n", + (tmp + 500) / 1000, MAX_CLOCK / 1000); + return 1; + } + + return 0; +} + +int +intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + u32 offset, xoffset, yoffset; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_pan_display\n"); +#endif + + xoffset = ROUND_DOWN_TO(var->xoffset, 8); + yoffset = var->yoffset; + + if ((xoffset + var->xres > var->xres_virtual) || + (yoffset + var->yres > var->yres_virtual)) + return -EINVAL; + + offset = (yoffset * dinfo->pitch) + + (xoffset * var->bits_per_pixel) / 8; + + offset += dinfo->fb.offset << 12; + + OUTREG(DSPABASE, offset); + + return 0; +} + +/* Blank the screen. */ +void +intelfbhw_do_blank(int blank, struct fb_info *info) +{ + struct intelfb_info *dinfo = GET_DINFO(info); + u32 tmp; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_do_blank: blank is %d\n", blank); +#endif + + /* Turn plane A on or off */ + tmp = INREG(DSPACNTR); + if (blank) + tmp &= ~DISPPLANE_PLANE_ENABLE; + else + tmp |= DISPPLANE_PLANE_ENABLE; + OUTREG(DSPACNTR, tmp); + /* Flush */ + tmp = INREG(DSPABASE); + OUTREG(DSPABASE, tmp); + + /* Turn off/on the HW cursor */ +#if VERBOSE > 0 + DBG_MSG("cursor_on is %d\n", dinfo->cursor_on); +#endif + if (dinfo->cursor_on) { + if (blank) { + intelfbhw_cursor_hide(dinfo); + } else { + intelfbhw_cursor_show(dinfo); + } + dinfo->cursor_on = 1; + } + dinfo->cursor_blanked = blank; + + /* Set DPMS level */ + tmp = INREG(ADPA) & ~ADPA_DPMS_CONTROL_MASK; + switch (blank) { + case FB_BLANK_UNBLANK: + case FB_BLANK_NORMAL: + tmp |= ADPA_DPMS_D0; + break; + case FB_BLANK_VSYNC_SUSPEND: + tmp |= ADPA_DPMS_D1; + break; + case FB_BLANK_HSYNC_SUSPEND: + tmp |= ADPA_DPMS_D2; + break; + case FB_BLANK_POWERDOWN: + tmp |= ADPA_DPMS_D3; + break; + } + OUTREG(ADPA, tmp); + + return; +} + + +void +intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp) +{ +#if VERBOSE > 0 + DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n", + regno, red, green, blue); +#endif + + u32 palette_reg = (dinfo->pipe == PIPE_A) ? + PALETTE_A : PALETTE_B; + + OUTREG(palette_reg + (regno << 2), + (red << PALETTE_8_RED_SHIFT) | + (green << PALETTE_8_GREEN_SHIFT) | + (blue << PALETTE_8_BLUE_SHIFT)); +} + + +int +intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, + int flag) +{ + int i; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_read_hw_state\n"); +#endif + + if (!hw || !dinfo) + return -1; + + /* Read in as much of the HW state as possible. */ + hw->vga0_divisor = INREG(VGA0_DIVISOR); + hw->vga1_divisor = INREG(VGA1_DIVISOR); + hw->vga_pd = INREG(VGAPD); + hw->dpll_a = INREG(DPLL_A); + hw->dpll_b = INREG(DPLL_B); + hw->fpa0 = INREG(FPA0); + hw->fpa1 = INREG(FPA1); + hw->fpb0 = INREG(FPB0); + hw->fpb1 = INREG(FPB1); + + if (flag == 1) + return flag; + +#if 0 + /* This seems to be a problem with the 852GM/855GM */ + for (i = 0; i < PALETTE_8_ENTRIES; i++) { + hw->palette_a[i] = INREG(PALETTE_A + (i << 2)); + hw->palette_b[i] = INREG(PALETTE_B + (i << 2)); + } +#endif + + if (flag == 2) + return flag; + + hw->htotal_a = INREG(HTOTAL_A); + hw->hblank_a = INREG(HBLANK_A); + hw->hsync_a = INREG(HSYNC_A); + hw->vtotal_a = INREG(VTOTAL_A); + hw->vblank_a = INREG(VBLANK_A); + hw->vsync_a = INREG(VSYNC_A); + hw->src_size_a = INREG(SRC_SIZE_A); + hw->bclrpat_a = INREG(BCLRPAT_A); + hw->htotal_b = INREG(HTOTAL_B); + hw->hblank_b = INREG(HBLANK_B); + hw->hsync_b = INREG(HSYNC_B); + hw->vtotal_b = INREG(VTOTAL_B); + hw->vblank_b = INREG(VBLANK_B); + hw->vsync_b = INREG(VSYNC_B); + hw->src_size_b = INREG(SRC_SIZE_B); + hw->bclrpat_b = INREG(BCLRPAT_B); + + if (flag == 3) + return flag; + + hw->adpa = INREG(ADPA); + hw->dvoa = INREG(DVOA); + hw->dvob = INREG(DVOB); + hw->dvoc = INREG(DVOC); + hw->dvoa_srcdim = INREG(DVOA_SRCDIM); + hw->dvob_srcdim = INREG(DVOB_SRCDIM); + hw->dvoc_srcdim = INREG(DVOC_SRCDIM); + hw->lvds = INREG(LVDS); + + if (flag == 4) + return flag; + + hw->pipe_a_conf = INREG(PIPEACONF); + hw->pipe_b_conf = INREG(PIPEBCONF); + hw->disp_arb = INREG(DISPARB); + + if (flag == 5) + return flag; + + hw->cursor_a_control = INREG(CURSOR_A_CONTROL); + hw->cursor_b_control = INREG(CURSOR_B_CONTROL); + hw->cursor_a_base = INREG(CURSOR_A_BASEADDR); + hw->cursor_b_base = INREG(CURSOR_B_BASEADDR); + + if (flag == 6) + return flag; + + for (i = 0; i < 4; i++) { + hw->cursor_a_palette[i] = INREG(CURSOR_A_PALETTE0 + (i << 2)); + hw->cursor_b_palette[i] = INREG(CURSOR_B_PALETTE0 + (i << 2)); + } + + if (flag == 7) + return flag; + + hw->cursor_size = INREG(CURSOR_SIZE); + + if (flag == 8) + return flag; + + hw->disp_a_ctrl = INREG(DSPACNTR); + hw->disp_b_ctrl = INREG(DSPBCNTR); + hw->disp_a_base = INREG(DSPABASE); + hw->disp_b_base = INREG(DSPBBASE); + hw->disp_a_stride = INREG(DSPASTRIDE); + hw->disp_b_stride = INREG(DSPBSTRIDE); + + if (flag == 9) + return flag; + + hw->vgacntrl = INREG(VGACNTRL); + + if (flag == 10) + return flag; + + hw->add_id = INREG(ADD_ID); + + if (flag == 11) + return flag; + + for (i = 0; i < 7; i++) { + hw->swf0x[i] = INREG(SWF00 + (i << 2)); + hw->swf1x[i] = INREG(SWF10 + (i << 2)); + if (i < 3) + hw->swf3x[i] = INREG(SWF30 + (i << 2)); + } + + for (i = 0; i < 8; i++) + hw->fence[i] = INREG(FENCE + (i << 2)); + + hw->instpm = INREG(INSTPM); + hw->mem_mode = INREG(MEM_MODE); + hw->fw_blc_0 = INREG(FW_BLC_0); + hw->fw_blc_1 = INREG(FW_BLC_1); + + return 0; +} + + +void +intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) +{ +#if REGDUMP + int i, m1, m2, n, p1, p2; + + DBG_MSG("intelfbhw_print_hw_state\n"); + + if (!hw || !dinfo) + return; + /* Read in as much of the HW state as possible. */ + printk("hw state dump start\n"); + printk(" VGA0_DIVISOR: 0x%08x\n", hw->vga0_divisor); + printk(" VGA1_DIVISOR: 0x%08x\n", hw->vga1_divisor); + printk(" VGAPD: 0x%08x\n", hw->vga_pd); + n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; + m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; + m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; + if (hw->vga_pd & VGAPD_0_P1_FORCE_DIV2) + p1 = 0; + else + p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK; + p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK; + printk(" VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", + m1, m2, n, p1, p2); + printk(" VGA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); + + n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; + m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; + m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; + if (hw->vga_pd & VGAPD_1_P1_FORCE_DIV2) + p1 = 0; + else + p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK; + p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK; + printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", + m1, m2, n, p1, p2); + printk(" VGA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); + + printk(" DPLL_A: 0x%08x\n", hw->dpll_a); + printk(" DPLL_B: 0x%08x\n", hw->dpll_b); + printk(" FPA0: 0x%08x\n", hw->fpa0); + printk(" FPA1: 0x%08x\n", hw->fpa1); + printk(" FPB0: 0x%08x\n", hw->fpb0); + printk(" FPB1: 0x%08x\n", hw->fpb1); + + n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; + m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; + m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; + if (hw->dpll_a & DPLL_P1_FORCE_DIV2) + p1 = 0; + else + p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK; + p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK; + printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", + m1, m2, n, p1, p2); + printk(" PLLA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); + + n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; + m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; + m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; + if (hw->dpll_a & DPLL_P1_FORCE_DIV2) + p1 = 0; + else + p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK; + p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK; + printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", + m1, m2, n, p1, p2); + printk(" PLLA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); + +#if 0 + printk(" PALETTE_A:\n"); + for (i = 0; i < PALETTE_8_ENTRIES) + printk(" %3d: 0x%08x\n", i, hw->palette_a[i]; + printk(" PALETTE_B:\n"); + for (i = 0; i < PALETTE_8_ENTRIES) + printk(" %3d: 0x%08x\n", i, hw->palette_b[i]; +#endif + + printk(" HTOTAL_A: 0x%08x\n", hw->htotal_a); + printk(" HBLANK_A: 0x%08x\n", hw->hblank_a); + printk(" HSYNC_A: 0x%08x\n", hw->hsync_a); + printk(" VTOTAL_A: 0x%08x\n", hw->vtotal_a); + printk(" VBLANK_A: 0x%08x\n", hw->vblank_a); + printk(" VSYNC_A: 0x%08x\n", hw->vsync_a); + printk(" SRC_SIZE_A: 0x%08x\n", hw->src_size_a); + printk(" BCLRPAT_A: 0x%08x\n", hw->bclrpat_a); + printk(" HTOTAL_B: 0x%08x\n", hw->htotal_b); + printk(" HBLANK_B: 0x%08x\n", hw->hblank_b); + printk(" HSYNC_B: 0x%08x\n", hw->hsync_b); + printk(" VTOTAL_B: 0x%08x\n", hw->vtotal_b); + printk(" VBLANK_B: 0x%08x\n", hw->vblank_b); + printk(" VSYNC_B: 0x%08x\n", hw->vsync_b); + printk(" SRC_SIZE_B: 0x%08x\n", hw->src_size_b); + printk(" BCLRPAT_B: 0x%08x\n", hw->bclrpat_b); + + printk(" ADPA: 0x%08x\n", hw->adpa); + printk(" DVOA: 0x%08x\n", hw->dvoa); + printk(" DVOB: 0x%08x\n", hw->dvob); + printk(" DVOC: 0x%08x\n", hw->dvoc); + printk(" DVOA_SRCDIM: 0x%08x\n", hw->dvoa_srcdim); + printk(" DVOB_SRCDIM: 0x%08x\n", hw->dvob_srcdim); + printk(" DVOC_SRCDIM: 0x%08x\n", hw->dvoc_srcdim); + printk(" LVDS: 0x%08x\n", hw->lvds); + + printk(" PIPEACONF: 0x%08x\n", hw->pipe_a_conf); + printk(" PIPEBCONF: 0x%08x\n", hw->pipe_b_conf); + printk(" DISPARB: 0x%08x\n", hw->disp_arb); + + printk(" CURSOR_A_CONTROL: 0x%08x\n", hw->cursor_a_control); + printk(" CURSOR_B_CONTROL: 0x%08x\n", hw->cursor_b_control); + printk(" CURSOR_A_BASEADDR: 0x%08x\n", hw->cursor_a_base); + printk(" CURSOR_B_BASEADDR: 0x%08x\n", hw->cursor_b_base); + + printk(" CURSOR_A_PALETTE: "); + for (i = 0; i < 4; i++) { + printk("0x%08x", hw->cursor_a_palette[i]); + if (i < 3) + printk(", "); + } + printk("\n"); + printk(" CURSOR_B_PALETTE: "); + for (i = 0; i < 4; i++) { + printk("0x%08x", hw->cursor_b_palette[i]); + if (i < 3) + printk(", "); + } + printk("\n"); + + printk(" CURSOR_SIZE: 0x%08x\n", hw->cursor_size); + + printk(" DSPACNTR: 0x%08x\n", hw->disp_a_ctrl); + printk(" DSPBCNTR: 0x%08x\n", hw->disp_b_ctrl); + printk(" DSPABASE: 0x%08x\n", hw->disp_a_base); + printk(" DSPBBASE: 0x%08x\n", hw->disp_b_base); + printk(" DSPASTRIDE: 0x%08x\n", hw->disp_a_stride); + printk(" DSPBSTRIDE: 0x%08x\n", hw->disp_b_stride); + + printk(" VGACNTRL: 0x%08x\n", hw->vgacntrl); + printk(" ADD_ID: 0x%08x\n", hw->add_id); + + for (i = 0; i < 7; i++) { + printk(" SWF0%d 0x%08x\n", i, + hw->swf0x[i]); + } + for (i = 0; i < 7; i++) { + printk(" SWF1%d 0x%08x\n", i, + hw->swf1x[i]); + } + for (i = 0; i < 3; i++) { + printk(" SWF3%d 0x%08x\n", i, + hw->swf3x[i]); + } + for (i = 0; i < 8; i++) + printk(" FENCE%d 0x%08x\n", i, + hw->fence[i]); + + printk(" INSTPM 0x%08x\n", hw->instpm); + printk(" MEM_MODE 0x%08x\n", hw->mem_mode); + printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0); + printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1); + + printk("hw state dump end\n"); +#endif +} + +/* Split the M parameter into M1 and M2. */ +static int +splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2) +{ + int m1, m2; + + m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2; + if (m1 < MIN_M1) + m1 = MIN_M1; + if (m1 > MAX_M1) + m1 = MAX_M1; + m2 = m - 5 * (m1 + 2) - 2; + if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) { + return 1; + } else { + *retm1 = (unsigned int)m1; + *retm2 = (unsigned int)m2; + return 0; + } +} + +/* Split the P parameter into P1 and P2. */ +static int +splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2) +{ + int p1, p2; + + if (p % 4 == 0) + p2 = 1; + else + p2 = 0; + p1 = (p / (1 << (p2 + 1))) - 2; + if (p % 4 == 0 && p1 < MIN_P1) { + p2 = 0; + p1 = (p / (1 << (p2 + 1))) - 2; + } + if (p1 < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) { + return 1; + } else { + *retp1 = (unsigned int)p1; + *retp2 = (unsigned int)p2; + return 0; + } +} + +static int +calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1, + u32 *retp2, u32 *retclock) +{ + u32 m1, m2, n, p1, p2, n1; + u32 f_vco, p, p_best = 0, m, f_out; + u32 err_max, err_target, err_best = 10000000; + u32 n_best = 0, m_best = 0, f_best, f_err; + u32 p_min, p_max, p_inc, div_min, div_max; + + /* Accept 0.5% difference, but aim for 0.1% */ + err_max = 5 * clock / 1000; + err_target = clock / 1000; + + DBG_MSG("Clock is %d\n", clock); + + div_max = MAX_VCO_FREQ / clock; + div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock; + + if (clock <= P_TRANSITION_CLOCK) + p_inc = 4; + else + p_inc = 2; + p_min = ROUND_UP_TO(div_min, p_inc); + p_max = ROUND_DOWN_TO(div_max, p_inc); + if (p_min < MIN_P) + p_min = 4; + if (p_max > MAX_P) + p_max = 128; + + DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc); + + p = p_min; + do { + if (splitp(p, &p1, &p2)) { + WRN_MSG("cannot split p = %d\n", p); + p += p_inc; + continue; + } + n = MIN_N; + f_vco = clock * p; + + do { + m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK; + if (m < MIN_M) + m = MIN_M; + if (m > MAX_M) + m = MAX_M; + f_out = CALC_VCLOCK3(m, n, p); + if (splitm(m, &m1, &m2)) { + WRN_MSG("cannot split m = %d\n", m); + n++; + continue; + } + if (clock > f_out) + f_err = clock - f_out; + else + f_err = f_out - clock; + + if (f_err < err_best) { + m_best = m; + n_best = n; + p_best = p; + f_best = f_out; + err_best = f_err; + } + n++; + } while ((n <= MAX_N) && (f_out >= clock)); + p += p_inc; + } while ((p <= p_max)); + + if (!m_best) { + WRN_MSG("cannot find parameters for clock %d\n", clock); + return 1; + } + m = m_best; + n = n_best; + p = p_best; + splitm(m, &m1, &m2); + splitp(p, &p1, &p2); + n1 = n - 2; + + DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), " + "f: %d (%d), VCO: %d\n", + m, m1, m2, n, n1, p, p1, p2, + CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2), + CALC_VCLOCK3(m, n, p) * p); + *retm1 = m1; + *retm2 = m2; + *retn = n1; + *retp1 = p1; + *retp2 = p2; + *retclock = CALC_VCLOCK(m1, m2, n1, p1, p2); + + return 0; +} + +static __inline__ int +check_overflow(u32 value, u32 limit, const char *description) +{ + if (value > limit) { + WRN_MSG("%s value %d exceeds limit %d\n", + description, value, limit); + return 1; + } + return 0; +} + +/* It is assumed that hw is filled in with the initial state information. */ +int +intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, + struct fb_var_screeninfo *var) +{ + int pipe = PIPE_A; + u32 *dpll, *fp0, *fp1; + u32 m1, m2, n, p1, p2, clock_target, clock; + u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive; + u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive; + u32 vsync_pol, hsync_pol; + u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf; + + DBG_MSG("intelfbhw_mode_to_hw\n"); + + /* Disable VGA */ + hw->vgacntrl |= VGA_DISABLE; + + /* Check whether pipe A or pipe B is enabled. */ + if (hw->pipe_a_conf & PIPECONF_ENABLE) + pipe = PIPE_A; + else if (hw->pipe_b_conf & PIPECONF_ENABLE) + pipe = PIPE_B; + + /* Set which pipe's registers will be set. */ + if (pipe == PIPE_B) { + dpll = &hw->dpll_b; + fp0 = &hw->fpb0; + fp1 = &hw->fpb1; + hs = &hw->hsync_b; + hb = &hw->hblank_b; + ht = &hw->htotal_b; + vs = &hw->vsync_b; + vb = &hw->vblank_b; + vt = &hw->vtotal_b; + ss = &hw->src_size_b; + pipe_conf = &hw->pipe_b_conf; + } else { + dpll = &hw->dpll_a; + fp0 = &hw->fpa0; + fp1 = &hw->fpa1; + hs = &hw->hsync_a; + hb = &hw->hblank_a; + ht = &hw->htotal_a; + vs = &hw->vsync_a; + vb = &hw->vblank_a; + vt = &hw->vtotal_a; + ss = &hw->src_size_a; + pipe_conf = &hw->pipe_a_conf; + } + + /* Use ADPA register for sync control. */ + hw->adpa &= ~ADPA_USE_VGA_HVPOLARITY; + + /* sync polarity */ + hsync_pol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? + ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW; + vsync_pol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? + ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW; + hw->adpa &= ~((ADPA_SYNC_ACTIVE_MASK << ADPA_VSYNC_ACTIVE_SHIFT) | + (ADPA_SYNC_ACTIVE_MASK << ADPA_HSYNC_ACTIVE_SHIFT)); + hw->adpa |= (hsync_pol << ADPA_HSYNC_ACTIVE_SHIFT) | + (vsync_pol << ADPA_VSYNC_ACTIVE_SHIFT); + + /* Connect correct pipe to the analog port DAC */ + hw->adpa &= ~(PIPE_MASK << ADPA_PIPE_SELECT_SHIFT); + hw->adpa |= (pipe << ADPA_PIPE_SELECT_SHIFT); + + /* Set DPMS state to D0 (on) */ + hw->adpa &= ~ADPA_DPMS_CONTROL_MASK; + hw->adpa |= ADPA_DPMS_D0; + + hw->adpa |= ADPA_DAC_ENABLE; + + *dpll |= (DPLL_VCO_ENABLE | DPLL_VGA_MODE_DISABLE); + *dpll &= ~(DPLL_RATE_SELECT_MASK | DPLL_REFERENCE_SELECT_MASK); + *dpll |= (DPLL_REFERENCE_DEFAULT | DPLL_RATE_SELECT_FP0); + + /* Desired clock in kHz */ + clock_target = 1000000000 / var->pixclock; + + if (calc_pll_params(clock_target, &m1, &m2, &n, &p1, &p2, &clock)) { + WRN_MSG("calc_pll_params failed\n"); + return 1; + } + + /* Check for overflow. */ + if (check_overflow(p1, DPLL_P1_MASK, "PLL P1 parameter")) + return 1; + if (check_overflow(p2, DPLL_P2_MASK, "PLL P2 parameter")) + return 1; + if (check_overflow(m1, FP_DIVISOR_MASK, "PLL M1 parameter")) + return 1; + if (check_overflow(m2, FP_DIVISOR_MASK, "PLL M2 parameter")) + return 1; + if (check_overflow(n, FP_DIVISOR_MASK, "PLL N parameter")) + return 1; + + *dpll &= ~DPLL_P1_FORCE_DIV2; + *dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) | + (DPLL_P1_MASK << DPLL_P1_SHIFT)); + *dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT); + *fp0 = (n << FP_N_DIVISOR_SHIFT) | + (m1 << FP_M1_DIVISOR_SHIFT) | + (m2 << FP_M2_DIVISOR_SHIFT); + *fp1 = *fp0; + + hw->dvob &= ~PORT_ENABLE; + hw->dvoc &= ~PORT_ENABLE; + + /* Use display plane A. */ + hw->disp_a_ctrl |= DISPPLANE_PLANE_ENABLE; + hw->disp_a_ctrl &= ~DISPPLANE_GAMMA_ENABLE; + hw->disp_a_ctrl &= ~DISPPLANE_PIXFORMAT_MASK; + switch (intelfb_var_to_depth(var)) { + case 8: + hw->disp_a_ctrl |= DISPPLANE_8BPP | DISPPLANE_GAMMA_ENABLE; + break; + case 15: + hw->disp_a_ctrl |= DISPPLANE_15_16BPP; + break; + case 16: + hw->disp_a_ctrl |= DISPPLANE_16BPP; + break; + case 24: + hw->disp_a_ctrl |= DISPPLANE_32BPP_NO_ALPHA; + break; + } + hw->disp_a_ctrl &= ~(PIPE_MASK << DISPPLANE_SEL_PIPE_SHIFT); + hw->disp_a_ctrl |= (pipe << DISPPLANE_SEL_PIPE_SHIFT); + + /* Set CRTC registers. */ + hactive = var->xres; + hsync_start = hactive + var->right_margin; + hsync_end = hsync_start + var->hsync_len; + htotal = hsync_end + var->left_margin; + hblank_start = hactive; + hblank_end = htotal; + + DBG_MSG("H: act %d, ss %d, se %d, tot %d bs %d, be %d\n", + hactive, hsync_start, hsync_end, htotal, hblank_start, + hblank_end); + + vactive = var->yres; + vsync_start = vactive + var->lower_margin; + vsync_end = vsync_start + var->vsync_len; + vtotal = vsync_end + var->upper_margin; + vblank_start = vactive; + vblank_end = vtotal; + vblank_end = vsync_end + 1; + + DBG_MSG("V: act %d, ss %d, se %d, tot %d bs %d, be %d\n", + vactive, vsync_start, vsync_end, vtotal, vblank_start, + vblank_end); + + /* Adjust for register values, and check for overflow. */ + hactive--; + if (check_overflow(hactive, HACTIVE_MASK, "CRTC hactive")) + return 1; + hsync_start--; + if (check_overflow(hsync_start, HSYNCSTART_MASK, "CRTC hsync_start")) + return 1; + hsync_end--; + if (check_overflow(hsync_end, HSYNCEND_MASK, "CRTC hsync_end")) + return 1; + htotal--; + if (check_overflow(htotal, HTOTAL_MASK, "CRTC htotal")) + return 1; + hblank_start--; + if (check_overflow(hblank_start, HBLANKSTART_MASK, "CRTC hblank_start")) + return 1; + hblank_end--; + if (check_overflow(hblank_end, HBLANKEND_MASK, "CRTC hblank_end")) + return 1; + + vactive--; + if (check_overflow(vactive, VACTIVE_MASK, "CRTC vactive")) + return 1; + vsync_start--; + if (check_overflow(vsync_start, VSYNCSTART_MASK, "CRTC vsync_start")) + return 1; + vsync_end--; + if (check_overflow(vsync_end, VSYNCEND_MASK, "CRTC vsync_end")) + return 1; + vtotal--; + if (check_overflow(vtotal, VTOTAL_MASK, "CRTC vtotal")) + return 1; + vblank_start--; + if (check_overflow(vblank_start, VBLANKSTART_MASK, "CRTC vblank_start")) + return 1; + vblank_end--; + if (check_overflow(vblank_end, VBLANKEND_MASK, "CRTC vblank_end")) + return 1; + + *ht = (htotal << HTOTAL_SHIFT) | (hactive << HACTIVE_SHIFT); + *hb = (hblank_start << HBLANKSTART_SHIFT) | + (hblank_end << HSYNCEND_SHIFT); + *hs = (hsync_start << HSYNCSTART_SHIFT) | (hsync_end << HSYNCEND_SHIFT); + + *vt = (vtotal << VTOTAL_SHIFT) | (vactive << VACTIVE_SHIFT); + *vb = (vblank_start << VBLANKSTART_SHIFT) | + (vblank_end << VSYNCEND_SHIFT); + *vs = (vsync_start << VSYNCSTART_SHIFT) | (vsync_end << VSYNCEND_SHIFT); + *ss = (hactive << SRC_SIZE_HORIZ_SHIFT) | + (vactive << SRC_SIZE_VERT_SHIFT); + + hw->disp_a_stride = var->xres_virtual * var->bits_per_pixel / 8; + DBG_MSG("pitch is %d\n", hw->disp_a_stride); + + hw->disp_a_base = hw->disp_a_stride * var->yoffset + + var->xoffset * var->bits_per_pixel / 8; + + hw->disp_a_base += dinfo->fb.offset << 12; + + /* Check stride alignment. */ + if (hw->disp_a_stride % STRIDE_ALIGNMENT != 0) { + WRN_MSG("display stride %d has bad alignment %d\n", + hw->disp_a_stride, STRIDE_ALIGNMENT); + return 1; + } + + /* Set the palette to 8-bit mode. */ + *pipe_conf &= ~PIPECONF_GAMMA; + return 0; +} + +/* Program a (non-VGA) video mode. */ +int +intelfbhw_program_mode(struct intelfb_info *dinfo, + const struct intelfb_hwstate *hw, int blank) +{ + int pipe = PIPE_A; + u32 tmp; + const u32 *dpll, *fp0, *fp1, *pipe_conf; + const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; + u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg; + u32 hsync_reg, htotal_reg, hblank_reg; + u32 vsync_reg, vtotal_reg, vblank_reg; + u32 src_size_reg; + + /* Assume single pipe, display plane A, analog CRT. */ + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_program_mode\n"); +#endif + + /* Disable VGA */ + tmp = INREG(VGACNTRL); + tmp |= VGA_DISABLE; + OUTREG(VGACNTRL, tmp); + + /* Check whether pipe A or pipe B is enabled. */ + if (hw->pipe_a_conf & PIPECONF_ENABLE) + pipe = PIPE_A; + else if (hw->pipe_b_conf & PIPECONF_ENABLE) + pipe = PIPE_B; + + dinfo->pipe = pipe; + + if (pipe == PIPE_B) { + dpll = &hw->dpll_b; + fp0 = &hw->fpb0; + fp1 = &hw->fpb1; + pipe_conf = &hw->pipe_b_conf; + hs = &hw->hsync_b; + hb = &hw->hblank_b; + ht = &hw->htotal_b; + vs = &hw->vsync_b; + vb = &hw->vblank_b; + vt = &hw->vtotal_b; + ss = &hw->src_size_b; + dpll_reg = DPLL_B; + fp0_reg = FPB0; + fp1_reg = FPB1; + pipe_conf_reg = PIPEBCONF; + hsync_reg = HSYNC_B; + htotal_reg = HTOTAL_B; + hblank_reg = HBLANK_B; + vsync_reg = VSYNC_B; + vtotal_reg = VTOTAL_B; + vblank_reg = VBLANK_B; + src_size_reg = SRC_SIZE_B; + } else { + dpll = &hw->dpll_a; + fp0 = &hw->fpa0; + fp1 = &hw->fpa1; + pipe_conf = &hw->pipe_a_conf; + hs = &hw->hsync_a; + hb = &hw->hblank_a; + ht = &hw->htotal_a; + vs = &hw->vsync_a; + vb = &hw->vblank_a; + vt = &hw->vtotal_a; + ss = &hw->src_size_a; + dpll_reg = DPLL_A; + fp0_reg = FPA0; + fp1_reg = FPA1; + pipe_conf_reg = PIPEACONF; + hsync_reg = HSYNC_A; + htotal_reg = HTOTAL_A; + hblank_reg = HBLANK_A; + vsync_reg = VSYNC_A; + vtotal_reg = VTOTAL_A; + vblank_reg = VBLANK_A; + src_size_reg = SRC_SIZE_A; + } + + /* Disable planes A and B. */ + tmp = INREG(DSPACNTR); + tmp &= ~DISPPLANE_PLANE_ENABLE; + OUTREG(DSPACNTR, tmp); + tmp = INREG(DSPBCNTR); + tmp &= ~DISPPLANE_PLANE_ENABLE; + OUTREG(DSPBCNTR, tmp); + + /* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */ + mdelay(20); + + /* Disable Sync */ + tmp = INREG(ADPA); + tmp &= ~ADPA_DPMS_CONTROL_MASK; + tmp |= ADPA_DPMS_D3; + OUTREG(ADPA, tmp); + + /* turn off pipe */ + tmp = INREG(pipe_conf_reg); + tmp &= ~PIPECONF_ENABLE; + OUTREG(pipe_conf_reg, tmp); + + /* turn off PLL */ + tmp = INREG(dpll_reg); + dpll_reg &= ~DPLL_VCO_ENABLE; + OUTREG(dpll_reg, tmp); + + /* Set PLL parameters */ + OUTREG(dpll_reg, *dpll & ~DPLL_VCO_ENABLE); + OUTREG(fp0_reg, *fp0); + OUTREG(fp1_reg, *fp1); + + /* Set pipe parameters */ + OUTREG(hsync_reg, *hs); + OUTREG(hblank_reg, *hb); + OUTREG(htotal_reg, *ht); + OUTREG(vsync_reg, *vs); + OUTREG(vblank_reg, *vb); + OUTREG(vtotal_reg, *vt); + OUTREG(src_size_reg, *ss); + + /* Set DVOs B/C */ + OUTREG(DVOB, hw->dvob); + OUTREG(DVOC, hw->dvoc); + + /* Set ADPA */ + OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3); + + /* Enable PLL */ + tmp = INREG(dpll_reg); + tmp |= DPLL_VCO_ENABLE; + OUTREG(dpll_reg, tmp); + + /* Enable pipe */ + OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); + + /* Enable sync */ + tmp = INREG(ADPA); + tmp &= ~ADPA_DPMS_CONTROL_MASK; + tmp |= ADPA_DPMS_D0; + OUTREG(ADPA, tmp); + + /* setup display plane */ + if (dinfo->pdev->device == PCI_DEVICE_ID_INTEL_830M) { + /* + * i830M errata: the display plane must be enabled + * to allow writes to the other bits in the plane + * control register. + */ + tmp = INREG(DSPACNTR); + if ((tmp & DISPPLANE_PLANE_ENABLE) != DISPPLANE_PLANE_ENABLE) { + tmp |= DISPPLANE_PLANE_ENABLE; + OUTREG(DSPACNTR, tmp); + OUTREG(DSPACNTR, + hw->disp_a_ctrl|DISPPLANE_PLANE_ENABLE); + mdelay(1); + } + } + + OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE); + OUTREG(DSPASTRIDE, hw->disp_a_stride); + OUTREG(DSPABASE, hw->disp_a_base); + + /* Enable plane */ + if (!blank) { + tmp = INREG(DSPACNTR); + tmp |= DISPPLANE_PLANE_ENABLE; + OUTREG(DSPACNTR, tmp); + OUTREG(DSPABASE, hw->disp_a_base); + } + + return 0; +} + +/* forward declarations */ +static void refresh_ring(struct intelfb_info *dinfo); +static void reset_state(struct intelfb_info *dinfo); +static void do_flush(struct intelfb_info *dinfo); + +static int +wait_ring(struct intelfb_info *dinfo, int n) +{ + int i = 0; + unsigned long end; + u32 last_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK; + +#if VERBOSE > 0 + DBG_MSG("wait_ring: %d\n", n); +#endif + + end = jiffies + (HZ * 3); + while (dinfo->ring_space < n) { + dinfo->ring_head = (u8 __iomem *)(INREG(PRI_RING_HEAD) & + RING_HEAD_MASK); + if (dinfo->ring_tail + RING_MIN_FREE < + (u32 __iomem) dinfo->ring_head) + dinfo->ring_space = (u32 __iomem) dinfo->ring_head + - (dinfo->ring_tail + RING_MIN_FREE); + else + dinfo->ring_space = (dinfo->ring.size + + (u32 __iomem) dinfo->ring_head) + - (dinfo->ring_tail + RING_MIN_FREE); + if ((u32 __iomem) dinfo->ring_head != last_head) { + end = jiffies + (HZ * 3); + last_head = (u32 __iomem) dinfo->ring_head; + } + i++; + if (time_before(end, jiffies)) { + if (!i) { + /* Try again */ + reset_state(dinfo); + refresh_ring(dinfo); + do_flush(dinfo); + end = jiffies + (HZ * 3); + i = 1; + } else { + WRN_MSG("ring buffer : space: %d wanted %d\n", + dinfo->ring_space, n); + WRN_MSG("lockup - turning off hardware " + "acceleration\n"); + dinfo->ring_lockup = 1; + break; + } + } + udelay(1); + } + return i; +} + +static void +do_flush(struct intelfb_info *dinfo) { + START_RING(2); + OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE); + OUT_RING(MI_NOOP); + ADVANCE_RING(); +} + +void +intelfbhw_do_sync(struct intelfb_info *dinfo) +{ +#if VERBOSE > 0 + DBG_MSG("intelfbhw_do_sync\n"); +#endif + + if (!dinfo->accel) + return; + + /* + * Send a flush, then wait until the ring is empty. This is what + * the XFree86 driver does, and actually it doesn't seem a lot worse + * than the recommended method (both have problems). + */ + do_flush(dinfo); + wait_ring(dinfo, dinfo->ring.size - RING_MIN_FREE); + dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE; +} + +static void +refresh_ring(struct intelfb_info *dinfo) +{ +#if VERBOSE > 0 + DBG_MSG("refresh_ring\n"); +#endif + + dinfo->ring_head = (u8 __iomem *) (INREG(PRI_RING_HEAD) & + RING_HEAD_MASK); + dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK; + if (dinfo->ring_tail + RING_MIN_FREE < (u32 __iomem)dinfo->ring_head) + dinfo->ring_space = (u32 __iomem) dinfo->ring_head + - (dinfo->ring_tail + RING_MIN_FREE); + else + dinfo->ring_space = (dinfo->ring.size + + (u32 __iomem) dinfo->ring_head) + - (dinfo->ring_tail + RING_MIN_FREE); +} + +static void +reset_state(struct intelfb_info *dinfo) +{ + int i; + u32 tmp; + +#if VERBOSE > 0 + DBG_MSG("reset_state\n"); +#endif + + for (i = 0; i < FENCE_NUM; i++) + OUTREG(FENCE + (i << 2), 0); + + /* Flush the ring buffer if it's enabled. */ + tmp = INREG(PRI_RING_LENGTH); + if (tmp & RING_ENABLE) { +#if VERBOSE > 0 + DBG_MSG("reset_state: ring was enabled\n"); +#endif + refresh_ring(dinfo); + intelfbhw_do_sync(dinfo); + DO_RING_IDLE(); + } + + OUTREG(PRI_RING_LENGTH, 0); + OUTREG(PRI_RING_HEAD, 0); + OUTREG(PRI_RING_TAIL, 0); + OUTREG(PRI_RING_START, 0); +} + +/* Stop the 2D engine, and turn off the ring buffer. */ +void +intelfbhw_2d_stop(struct intelfb_info *dinfo) +{ +#if VERBOSE > 0 + DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel, + dinfo->ring_active); +#endif + + if (!dinfo->accel) + return; + + dinfo->ring_active = 0; + reset_state(dinfo); +} + +/* + * Enable the ring buffer, and initialise the 2D engine. + * It is assumed that the graphics engine has been stopped by previously + * calling intelfb_2d_stop(). + */ +void +intelfbhw_2d_start(struct intelfb_info *dinfo) +{ +#if VERBOSE > 0 + DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n", + dinfo->accel, dinfo->ring_active); +#endif + + if (!dinfo->accel) + return; + + /* Initialise the primary ring buffer. */ + OUTREG(PRI_RING_LENGTH, 0); + OUTREG(PRI_RING_TAIL, 0); + OUTREG(PRI_RING_HEAD, 0); + + OUTREG(PRI_RING_START, dinfo->ring.physical & RING_START_MASK); + OUTREG(PRI_RING_LENGTH, + ((dinfo->ring.size - GTT_PAGE_SIZE) & RING_LENGTH_MASK) | + RING_NO_REPORT | RING_ENABLE); + refresh_ring(dinfo); + dinfo->ring_active = 1; +} + +/* 2D fillrect (solid fill or invert) */ +void +intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, u32 h, + u32 color, u32 pitch, u32 bpp, u32 rop) +{ + u32 br00, br09, br13, br14, br16; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_do_fillrect: (%d,%d) %dx%d, c 0x%06x, p %d bpp %d, " + "rop 0x%02x\n", x, y, w, h, color, pitch, bpp, rop); +#endif + + br00 = COLOR_BLT_CMD; + br09 = dinfo->fb_start + (y * pitch + x * (bpp / 8)); + br13 = (rop << ROP_SHIFT) | pitch; + br14 = (h << HEIGHT_SHIFT) | ((w * (bpp / 8)) << WIDTH_SHIFT); + br16 = color; + + switch (bpp) { + case 8: + br13 |= COLOR_DEPTH_8; + break; + case 16: + br13 |= COLOR_DEPTH_16; + break; + case 32: + br13 |= COLOR_DEPTH_32; + br00 |= WRITE_ALPHA | WRITE_RGB; + break; + } + + START_RING(6); + OUT_RING(br00); + OUT_RING(br13); + OUT_RING(br14); + OUT_RING(br09); + OUT_RING(br16); + OUT_RING(MI_NOOP); + ADVANCE_RING(); + +#if VERBOSE > 0 + DBG_MSG("ring = 0x%08x, 0x%08x (%d)\n", dinfo->ring_head, + dinfo->ring_tail, dinfo->ring_space); +#endif +} + +void +intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury, + u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch, u32 bpp) +{ + u32 br00, br09, br11, br12, br13, br22, br23, br26; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_do_bitblt: (%d,%d)->(%d,%d) %dx%d, p %d bpp %d\n", + curx, cury, dstx, dsty, w, h, pitch, bpp); +#endif + + br00 = XY_SRC_COPY_BLT_CMD; + br09 = dinfo->fb_start; + br11 = (pitch << PITCH_SHIFT); + br12 = dinfo->fb_start; + br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT); + br22 = (dstx << WIDTH_SHIFT) | (dsty << HEIGHT_SHIFT); + br23 = ((dstx + w) << WIDTH_SHIFT) | + ((dsty + h) << HEIGHT_SHIFT); + br26 = (curx << WIDTH_SHIFT) | (cury << HEIGHT_SHIFT); + + switch (bpp) { + case 8: + br13 |= COLOR_DEPTH_8; + break; + case 16: + br13 |= COLOR_DEPTH_16; + break; + case 32: + br13 |= COLOR_DEPTH_32; + br00 |= WRITE_ALPHA | WRITE_RGB; + break; + } + + START_RING(8); + OUT_RING(br00); + OUT_RING(br13); + OUT_RING(br22); + OUT_RING(br23); + OUT_RING(br09); + OUT_RING(br26); + OUT_RING(br11); + OUT_RING(br12); + ADVANCE_RING(); +} + +int +intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w, + u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp) +{ + int nbytes, ndwords, pad, tmp; + u32 br00, br09, br13, br18, br19, br22, br23; + int dat, ix, iy, iw; + int i, j; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_do_drawglyph: (%d,%d) %dx%d\n", x, y, w, h); +#endif + + /* size in bytes of a padded scanline */ + nbytes = ROUND_UP_TO(w, 16) / 8; + + /* Total bytes of padded scanline data to write out. */ + nbytes = nbytes * h; + + /* + * Check if the glyph data exceeds the immediate mode limit. + * It would take a large font (1K pixels) to hit this limit. + */ + if (nbytes > MAX_MONO_IMM_SIZE) + return 0; + + /* Src data is packaged a dword (32-bit) at a time. */ + ndwords = ROUND_UP_TO(nbytes, 4) / 4; + + /* + * Ring has to be padded to a quad word. But because the command starts + with 7 bytes, pad only if there is an even number of ndwords + */ + pad = !(ndwords % 2); + + tmp = (XY_MONO_SRC_IMM_BLT_CMD & DW_LENGTH_MASK) + ndwords; + br00 = (XY_MONO_SRC_IMM_BLT_CMD & ~DW_LENGTH_MASK) | tmp; + br09 = dinfo->fb_start; + br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT); + br18 = bg; + br19 = fg; + br22 = (x << WIDTH_SHIFT) | (y << HEIGHT_SHIFT); + br23 = ((x + w) << WIDTH_SHIFT) | ((y + h) << HEIGHT_SHIFT); + + switch (bpp) { + case 8: + br13 |= COLOR_DEPTH_8; + break; + case 16: + br13 |= COLOR_DEPTH_16; + break; + case 32: + br13 |= COLOR_DEPTH_32; + br00 |= WRITE_ALPHA | WRITE_RGB; + break; + } + + START_RING(8 + ndwords); + OUT_RING(br00); + OUT_RING(br13); + OUT_RING(br22); + OUT_RING(br23); + OUT_RING(br09); + OUT_RING(br18); + OUT_RING(br19); + ix = iy = 0; + iw = ROUND_UP_TO(w, 8) / 8; + while (ndwords--) { + dat = 0; + for (j = 0; j < 2; ++j) { + for (i = 0; i < 2; ++i) { + if (ix != iw || i == 0) + dat |= cdat[iy*iw + ix++] << (i+j*2)*8; + } + if (ix == iw && iy != (h-1)) { + ix = 0; + ++iy; + } + } + OUT_RING(dat); + } + if (pad) + OUT_RING(MI_NOOP); + ADVANCE_RING(); + + return 1; +} + +/* HW cursor functions. */ +void +intelfbhw_cursor_init(struct intelfb_info *dinfo) +{ + u32 tmp; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_cursor_init\n"); +#endif + + if (dinfo->mobile) { + if (!dinfo->cursor.physical) + return; + tmp = INREG(CURSOR_A_CONTROL); + tmp &= ~(CURSOR_MODE_MASK | CURSOR_MOBILE_GAMMA_ENABLE | + CURSOR_MEM_TYPE_LOCAL | + (1 << CURSOR_PIPE_SELECT_SHIFT)); + tmp |= CURSOR_MODE_DISABLE; + OUTREG(CURSOR_A_CONTROL, tmp); + OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical); + } else { + tmp = INREG(CURSOR_CONTROL); + tmp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE | + CURSOR_ENABLE | CURSOR_STRIDE_MASK); + tmp = CURSOR_FORMAT_3C; + OUTREG(CURSOR_CONTROL, tmp); + OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.offset << 12); + tmp = (64 << CURSOR_SIZE_H_SHIFT) | + (64 << CURSOR_SIZE_V_SHIFT); + OUTREG(CURSOR_SIZE, tmp); + } +} + +void +intelfbhw_cursor_hide(struct intelfb_info *dinfo) +{ + u32 tmp; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_cursor_hide\n"); +#endif + + dinfo->cursor_on = 0; + if (dinfo->mobile) { + if (!dinfo->cursor.physical) + return; + tmp = INREG(CURSOR_A_CONTROL); + tmp &= ~CURSOR_MODE_MASK; + tmp |= CURSOR_MODE_DISABLE; + OUTREG(CURSOR_A_CONTROL, tmp); + /* Flush changes */ + OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical); + } else { + tmp = INREG(CURSOR_CONTROL); + tmp &= ~CURSOR_ENABLE; + OUTREG(CURSOR_CONTROL, tmp); + } +} + +void +intelfbhw_cursor_show(struct intelfb_info *dinfo) +{ + u32 tmp; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_cursor_show\n"); +#endif + + dinfo->cursor_on = 1; + + if (dinfo->cursor_blanked) + return; + + if (dinfo->mobile) { + if (!dinfo->cursor.physical) + return; + tmp = INREG(CURSOR_A_CONTROL); + tmp &= ~CURSOR_MODE_MASK; + tmp |= CURSOR_MODE_64_4C_AX; + OUTREG(CURSOR_A_CONTROL, tmp); + /* Flush changes */ + OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical); + } else { + tmp = INREG(CURSOR_CONTROL); + tmp |= CURSOR_ENABLE; + OUTREG(CURSOR_CONTROL, tmp); + } +} + +void +intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y) +{ + u32 tmp; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_cursor_setpos: (%d, %d)\n", x, y); +#endif + + /* + * Sets the position. The coordinates are assumed to already + * have any offset adjusted. Assume that the cursor is never + * completely off-screen, and that x, y are always >= 0. + */ + + tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) | + ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); + OUTREG(CURSOR_A_POSITION, tmp); +} + +void +intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg) +{ +#if VERBOSE > 0 + DBG_MSG("intelfbhw_cursor_setcolor\n"); +#endif + + OUTREG(CURSOR_A_PALETTE0, bg & CURSOR_PALETTE_MASK); + OUTREG(CURSOR_A_PALETTE1, fg & CURSOR_PALETTE_MASK); + OUTREG(CURSOR_A_PALETTE2, fg & CURSOR_PALETTE_MASK); + OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK); +} + +void +intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, + u8 *data) +{ + u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; + int i, j, w = width / 8; + int mod = width % 8, t_mask, d_mask; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_cursor_load\n"); +#endif + + if (!dinfo->cursor.virtual) + return; + + t_mask = 0xff >> mod; + d_mask = ~(0xff >> mod); + for (i = height; i--; ) { + for (j = 0; j < w; j++) { + writeb(0x00, addr + j); + writeb(*(data++), addr + j+8); + } + if (mod) { + writeb(t_mask, addr + j); + writeb(*(data++) & d_mask, addr + j+8); + } + addr += 16; + } +} + +void +intelfbhw_cursor_reset(struct intelfb_info *dinfo) { + u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; + int i, j; + +#if VERBOSE > 0 + DBG_MSG("intelfbhw_cursor_reset\n"); +#endif + + if (!dinfo->cursor.virtual) + return; + + for (i = 64; i--; ) { + for (j = 0; j < 8; j++) { + writeb(0xff, addr + j+0); + writeb(0x00, addr + j+8); + } + addr += 16; + } +} diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h new file mode 100644 index 000000000000..ba1920159f52 --- /dev/null +++ b/drivers/video/intelfb/intelfbhw.h @@ -0,0 +1,570 @@ +#ifndef _INTELFBHW_H +#define _INTELFBHW_H + +/* $DHD: intelfb/intelfbhw.h,v 1.5 2003/06/27 15:06:25 dawes Exp $ */ + + +/*** HW-specific data ***/ + +/* Information about the 852GM/855GM variants */ +#define INTEL_85X_CAPID 0x44 +#define INTEL_85X_VARIANT_MASK 0x7 +#define INTEL_85X_VARIANT_SHIFT 5 +#define INTEL_VAR_855GME 0x0 +#define INTEL_VAR_855GM 0x4 +#define INTEL_VAR_852GME 0x2 +#define INTEL_VAR_852GM 0x5 + +/* Information about DVO/LVDS Ports */ +#define DVOA_PORT 0x1 +#define DVOB_PORT 0x2 +#define DVOC_PORT 0x4 +#define LVDS_PORT 0x8 + +/* + * The Bridge device's PCI config space has information about the + * fb aperture size and the amount of pre-reserved memory. + */ +#define INTEL_GMCH_CTRL 0x52 +#define INTEL_GMCH_ENABLED 0x4 +#define INTEL_GMCH_MEM_MASK 0x1 +#define INTEL_GMCH_MEM_64M 0x1 +#define INTEL_GMCH_MEM_128M 0 + +#define INTEL_830_GMCH_GMS_MASK (0x7 << 4) +#define INTEL_830_GMCH_GMS_DISABLED (0x0 << 4) +#define INTEL_830_GMCH_GMS_LOCAL (0x1 << 4) +#define INTEL_830_GMCH_GMS_STOLEN_512 (0x2 << 4) +#define INTEL_830_GMCH_GMS_STOLEN_1024 (0x3 << 4) +#define INTEL_830_GMCH_GMS_STOLEN_8192 (0x4 << 4) + +#define INTEL_855_GMCH_GMS_MASK (0x7 << 4) +#define INTEL_855_GMCH_GMS_DISABLED (0x0 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_1M (0x1 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_4M (0x2 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_8M (0x3 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_16M (0x4 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_32M (0x5 << 4) + +#define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4) +#define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4) + +/* HW registers */ + +/* Fence registers */ +#define FENCE 0x2000 +#define FENCE_NUM 8 + +/* Primary ring buffer */ +#define PRI_RING_TAIL 0x2030 +#define RING_TAIL_MASK 0x001ffff8 +#define RING_INUSE 0x1 + +#define PRI_RING_HEAD 0x2034 +#define RING_HEAD_WRAP_MASK 0x7ff +#define RING_HEAD_WRAP_SHIFT 21 +#define RING_HEAD_MASK 0x001ffffc + +#define PRI_RING_START 0x2038 +#define RING_START_MASK 0xfffff000 + +#define PRI_RING_LENGTH 0x203c +#define RING_LENGTH_MASK 0x001ff000 +#define RING_REPORT_MASK (0x3 << 1) +#define RING_NO_REPORT (0x0 << 1) +#define RING_REPORT_64K (0x1 << 1) +#define RING_REPORT_4K (0x2 << 1) +#define RING_REPORT_128K (0x3 << 1) +#define RING_ENABLE 0x1 + +/* + * Tail can't wrap to any closer than RING_MIN_FREE bytes of the head, + * and the last RING_MIN_FREE bytes need to be padded with MI_NOOP + */ +#define RING_MIN_FREE 64 + +#define IPEHR 0x2088 + +#define INSTDONE 0x2090 +#define PRI_RING_EMPTY 1 + +#define INSTPM 0x20c0 +#define SYNC_FLUSH_ENABLE (1 << 5) + +#define INSTPS 0x20c4 + +#define MEM_MODE 0x20cc + +#define MASK_SHIFT 16 + +#define FW_BLC_0 0x20d8 +#define FW_DISPA_WM_SHIFT 0 +#define FW_DISPA_WM_MASK 0x3f +#define FW_DISPA_BL_SHIFT 8 +#define FW_DISPA_BL_MASK 0xf +#define FW_DISPB_WM_SHIFT 16 +#define FW_DISPB_WM_MASK 0x1f +#define FW_DISPB_BL_SHIFT 24 +#define FW_DISPB_BL_MASK 0x7 + +#define FW_BLC_1 0x20dc +#define FW_DISPC_WM_SHIFT 0 +#define FW_DISPC_WM_MASK 0x1f +#define FW_DISPC_BL_SHIFT 8 +#define FW_DISPC_BL_MASK 0x7 + + +/* PLL registers */ +#define VGA0_DIVISOR 0x06000 +#define VGA1_DIVISOR 0x06004 +#define VGAPD 0x06010 +#define VGAPD_0_P1_SHIFT 0 +#define VGAPD_0_P1_FORCE_DIV2 (1 << 5) +#define VGAPD_0_P2_SHIFT 7 +#define VGAPD_1_P1_SHIFT 8 +#define VGAPD_1_P1_FORCE_DIV2 (1 << 13) +#define VGAPD_1_P2_SHIFT 15 + +#define DPLL_A 0x06014 +#define DPLL_B 0x06018 +#define DPLL_VCO_ENABLE (1 << 31) +#define DPLL_2X_CLOCK_ENABLE (1 << 30) +#define DPLL_SYNCLOCK_ENABLE (1 << 29) +#define DPLL_VGA_MODE_DISABLE (1 << 28) +#define DPLL_P2_MASK 1 +#define DPLL_P2_SHIFT 23 +#define DPLL_P1_FORCE_DIV2 (1 << 21) +#define DPLL_P1_MASK 0x1f +#define DPLL_P1_SHIFT 16 +#define DPLL_REFERENCE_SELECT_MASK (0x3 << 13) +#define DPLL_REFERENCE_DEFAULT (0x0 << 13) +#define DPLL_REFERENCE_TVCLK (0x2 << 13) +#define DPLL_RATE_SELECT_MASK (1 << 8) +#define DPLL_RATE_SELECT_FP0 (0 << 8) +#define DPLL_RATE_SELECT_FP1 (1 << 8) + +#define FPA0 0x06040 +#define FPA1 0x06044 +#define FPB0 0x06048 +#define FPB1 0x0604c +#define FP_DIVISOR_MASK 0x3f +#define FP_N_DIVISOR_SHIFT 16 +#define FP_M1_DIVISOR_SHIFT 8 +#define FP_M2_DIVISOR_SHIFT 0 + +/* PLL parameters (these are for 852GM/855GM/865G, check earlier chips). */ +/* Clock values are in units of kHz */ +#define PLL_REFCLK 48000 +#define MIN_VCO_FREQ 930000 +#define MAX_VCO_FREQ 1400000 +#define MIN_CLOCK 25000 +#define MAX_CLOCK 350000 +#define P_TRANSITION_CLOCK 165000 +#define MIN_M 108 +#define MAX_M 140 +#define MIN_M1 18 +#define MAX_M1 26 +#define MIN_M2 6 +#define MAX_M2 16 +#define MIN_P 4 +#define MAX_P 128 +#define MIN_P1 0 +#define MAX_P1 31 +#define MIN_N 3 +#define MAX_N 16 + +#define CALC_VCLOCK(m1, m2, n, p1, p2) \ + ((PLL_REFCLK * (5 * ((m1) + 2) + ((m2) + 2)) / ((n) + 2)) / \ + (((p1) + 2) * (1 << (p2 + 1)))) + +#define CALC_VCLOCK3(m, n, p) ((PLL_REFCLK * (m) / (n)) / (p)) + +/* Two pipes */ +#define PIPE_A 0 +#define PIPE_B 1 +#define PIPE_MASK 1 + +/* palette registers */ +#define PALETTE_A 0x0a000 +#define PALETTE_B 0x0a800 +#ifndef PALETTE_8_ENTRIES +#define PALETTE_8_ENTRIES 256 +#endif +#define PALETTE_8_SIZE (PALETTE_8_ENTRIES * 4) +#define PALETTE_10_ENTRIES 128 +#define PALETTE_10_SIZE (PALETTE_10_ENTRIES * 8) +#define PALETTE_8_MASK 0xff +#define PALETTE_8_RED_SHIFT 16 +#define PALETTE_8_GREEN_SHIFT 8 +#define PALETTE_8_BLUE_SHIFT 0 + +/* CRTC registers */ +#define HTOTAL_A 0x60000 +#define HBLANK_A 0x60004 +#define HSYNC_A 0x60008 +#define VTOTAL_A 0x6000c +#define VBLANK_A 0x60010 +#define VSYNC_A 0x60014 +#define SRC_SIZE_A 0x6001c +#define BCLRPAT_A 0x60020 + +#define HTOTAL_B 0x61000 +#define HBLANK_B 0x61004 +#define HSYNC_B 0x61008 +#define VTOTAL_B 0x6100c +#define VBLANK_B 0x61010 +#define VSYNC_B 0x61014 +#define SRC_SIZE_B 0x6101c +#define BCLRPAT_B 0x61020 + +#define HTOTAL_MASK 0xfff +#define HTOTAL_SHIFT 16 +#define HACTIVE_MASK 0x7ff +#define HACTIVE_SHIFT 0 +#define HBLANKEND_MASK 0xfff +#define HBLANKEND_SHIFT 16 +#define HBLANKSTART_MASK 0xfff +#define HBLANKSTART_SHIFT 0 +#define HSYNCEND_MASK 0xfff +#define HSYNCEND_SHIFT 16 +#define HSYNCSTART_MASK 0xfff +#define HSYNCSTART_SHIFT 0 +#define VTOTAL_MASK 0xfff +#define VTOTAL_SHIFT 16 +#define VACTIVE_MASK 0x7ff +#define VACTIVE_SHIFT 0 +#define VBLANKEND_MASK 0xfff +#define VBLANKEND_SHIFT 16 +#define VBLANKSTART_MASK 0xfff +#define VBLANKSTART_SHIFT 0 +#define VSYNCEND_MASK 0xfff +#define VSYNCEND_SHIFT 16 +#define VSYNCSTART_MASK 0xfff +#define VSYNCSTART_SHIFT 0 +#define SRC_SIZE_HORIZ_MASK 0x7ff +#define SRC_SIZE_HORIZ_SHIFT 16 +#define SRC_SIZE_VERT_MASK 0x7ff +#define SRC_SIZE_VERT_SHIFT 0 + +#define ADPA 0x61100 +#define ADPA_DAC_ENABLE (1 << 31) +#define ADPA_DAC_DISABLE 0 +#define ADPA_PIPE_SELECT_SHIFT 30 +#define ADPA_USE_VGA_HVPOLARITY (1 << 15) +#define ADPA_SETS_HVPOLARITY 0 +#define ADPA_DPMS_CONTROL_MASK (0x3 << 10) +#define ADPA_DPMS_D0 (0x0 << 10) +#define ADPA_DPMS_D2 (0x1 << 10) +#define ADPA_DPMS_D1 (0x2 << 10) +#define ADPA_DPMS_D3 (0x3 << 10) +#define ADPA_VSYNC_ACTIVE_SHIFT 4 +#define ADPA_HSYNC_ACTIVE_SHIFT 3 +#define ADPA_SYNC_ACTIVE_MASK 1 +#define ADPA_SYNC_ACTIVE_HIGH 1 +#define ADPA_SYNC_ACTIVE_LOW 0 + +#define DVOA 0x61120 +#define DVOB 0x61140 +#define DVOC 0x61160 +#define LVDS 0x61180 +#define PORT_ENABLE (1 << 31) +#define PORT_PIPE_SELECT_SHIFT 30 +#define PORT_TV_FLAGS_MASK 0xFF +#define PORT_TV_FLAGS 0xC4 // ripped from my BIOS + // to understand and correct + +#define DVOA_SRCDIM 0x61124 +#define DVOB_SRCDIM 0x61144 +#define DVOC_SRCDIM 0x61164 + +#define PIPEACONF 0x70008 +#define PIPEBCONF 0x71008 +#define PIPECONF_ENABLE (1 << 31) +#define PIPECONF_DISABLE 0 +#define PIPECONF_DOUBLE_WIDE (1 << 30) +#define PIPECONF_SINGLE_WIDE 0 +#define PIPECONF_LOCKED (1 << 25) +#define PIPECONF_UNLOCKED 0 +#define PIPECONF_GAMMA (1 << 24) +#define PIPECONF_PALETTE 0 + +#define DISPARB 0x70030 +#define DISPARB_AEND_MASK 0x1ff +#define DISPARB_AEND_SHIFT 0 +#define DISPARB_BEND_MASK 0x3ff +#define DISPARB_BEND_SHIFT 9 + +/* Desktop HW cursor */ +#define CURSOR_CONTROL 0x70080 +#define CURSOR_ENABLE (1 << 31) +#define CURSOR_GAMMA_ENABLE (1 << 30) +#define CURSOR_STRIDE_MASK (0x3 << 28) +#define CURSOR_STRIDE_256 (0x0 << 28) +#define CURSOR_STRIDE_512 (0x1 << 28) +#define CURSOR_STRIDE_1K (0x2 << 28) +#define CURSOR_STRIDE_2K (0x3 << 28) +#define CURSOR_FORMAT_MASK (0x7 << 24) +#define CURSOR_FORMAT_2C (0x0 << 24) +#define CURSOR_FORMAT_3C (0x1 << 24) +#define CURSOR_FORMAT_4C (0x2 << 24) +#define CURSOR_FORMAT_ARGB (0x4 << 24) +#define CURSOR_FORMAT_XRGB (0x5 << 24) + +/* Mobile HW cursor (and i810) */ +#define CURSOR_A_CONTROL CURSOR_CONTROL +#define CURSOR_B_CONTROL 0x700c0 +#define CURSOR_MODE_MASK 0x27 +#define CURSOR_MODE_DISABLE 0 +#define CURSOR_MODE_64_3C 0x04 +#define CURSOR_MODE_64_4C_AX 0x05 +#define CURSOR_MODE_64_4C 0x06 +#define CURSOR_MODE_64_32B_AX 0x07 +#define CURSOR_MODE_64_ARGB_AX 0x27 +#define CURSOR_PIPE_SELECT_SHIFT 28 +#define CURSOR_MOBILE_GAMMA_ENABLE (1 << 26) +#define CURSOR_MEM_TYPE_LOCAL (1 << 25) + +/* All platforms (desktop has no pipe B) */ +#define CURSOR_A_BASEADDR 0x70084 +#define CURSOR_B_BASEADDR 0x700c4 +#define CURSOR_BASE_MASK 0xffffff00 + +#define CURSOR_A_POSITION 0x70088 +#define CURSOR_B_POSITION 0x700c8 +#define CURSOR_POS_SIGN (1 << 15) +#define CURSOR_POS_MASK 0x7ff +#define CURSOR_X_SHIFT 0 +#define CURSOR_Y_SHIFT 16 + +#define CURSOR_A_PALETTE0 0x70090 +#define CURSOR_A_PALETTE1 0x70094 +#define CURSOR_A_PALETTE2 0x70098 +#define CURSOR_A_PALETTE3 0x7009c +#define CURSOR_B_PALETTE0 0x700d0 +#define CURSOR_B_PALETTE1 0x700d4 +#define CURSOR_B_PALETTE2 0x700d8 +#define CURSOR_B_PALETTE3 0x700dc +#define CURSOR_COLOR_MASK 0xff +#define CURSOR_RED_SHIFT 16 +#define CURSOR_GREEN_SHIFT 8 +#define CURSOR_BLUE_SHIFT 0 +#define CURSOR_PALETTE_MASK 0xffffff + +/* Desktop only */ +#define CURSOR_SIZE 0x700a0 +#define CURSOR_SIZE_MASK 0x3ff +#define CURSOR_SIZE_H_SHIFT 0 +#define CURSOR_SIZE_V_SHIFT 12 + +#define DSPACNTR 0x70180 +#define DSPBCNTR 0x71180 +#define DISPPLANE_PLANE_ENABLE (1 << 31) +#define DISPPLANE_PLANE_DISABLE 0 +#define DISPPLANE_GAMMA_ENABLE (1<<30) +#define DISPPLANE_GAMMA_DISABLE 0 +#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) +#define DISPPLANE_8BPP (0x2<<26) +#define DISPPLANE_15_16BPP (0x4<<26) +#define DISPPLANE_16BPP (0x5<<26) +#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) +#define DISPPLANE_32BPP (0x7<<26) +#define DISPPLANE_STEREO_ENABLE (1<<25) +#define DISPPLANE_STEREO_DISABLE 0 +#define DISPPLANE_SEL_PIPE_SHIFT 24 +#define DISPPLANE_SRC_KEY_ENABLE (1<<22) +#define DISPPLANE_SRC_KEY_DISABLE 0 +#define DISPPLANE_LINE_DOUBLE (1<<20) +#define DISPPLANE_NO_LINE_DOUBLE 0 +#define DISPPLANE_STEREO_POLARITY_FIRST 0 +#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) +/* plane B only */ +#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) +#define DISPPLANE_ALPHA_TRANS_DISABLE 0 +#define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0 +#define DISPPLANE_SPRITE_ABOVE_OVERLAY 1 + +#define DSPABASE 0x70184 +#define DSPASTRIDE 0x70188 + +#define DSPBBASE 0x71184 +#define DSPBSTRIDE 0x71188 + +#define VGACNTRL 0x71400 +#define VGA_DISABLE (1 << 31) +#define VGA_ENABLE 0 +#define VGA_PIPE_SELECT_SHIFT 29 +#define VGA_PALETTE_READ_SELECT 23 +#define VGA_PALETTE_A_WRITE_DISABLE (1 << 22) +#define VGA_PALETTE_B_WRITE_DISABLE (1 << 21) +#define VGA_LEGACY_PALETTE (1 << 20) +#define VGA_6BIT_DAC 0 +#define VGA_8BIT_DAC (1 << 20) + +#define ADD_ID 0x71408 +#define ADD_ID_MASK 0xff + +/* BIOS scratch area registers (830M and 845G). */ +#define SWF0 0x71410 +#define SWF1 0x71414 +#define SWF2 0x71418 +#define SWF3 0x7141c +#define SWF4 0x71420 +#define SWF5 0x71424 +#define SWF6 0x71428 + +/* BIOS scratch area registers (852GM, 855GM, 865G). */ +#define SWF00 0x70410 +#define SWF01 0x70414 +#define SWF02 0x70418 +#define SWF03 0x7041c +#define SWF04 0x70420 +#define SWF05 0x70424 +#define SWF06 0x70428 + +#define SWF10 SWF0 +#define SWF11 SWF1 +#define SWF12 SWF2 +#define SWF13 SWF3 +#define SWF14 SWF4 +#define SWF15 SWF5 +#define SWF16 SWF6 + +#define SWF30 0x72414 +#define SWF31 0x72418 +#define SWF32 0x7241c + +/* Memory Commands */ +#define MI_NOOP (0x00 << 23) +#define MI_NOOP_WRITE_ID (1 << 22) +#define MI_NOOP_ID_MASK ((1 << 22) - 1) + +#define MI_FLUSH (0x04 << 23) +#define MI_WRITE_DIRTY_STATE (1 << 4) +#define MI_END_SCENE (1 << 3) +#define MI_INHIBIT_RENDER_CACHE_FLUSH (1 << 2) +#define MI_INVALIDATE_MAP_CACHE (1 << 0) + +#define MI_STORE_DWORD_IMM ((0x20 << 23) | 1) + +/* 2D Commands */ +#define COLOR_BLT_CMD ((2 << 29) | (0x40 << 22) | 3) +#define XY_COLOR_BLT_CMD ((2 << 29) | (0x50 << 22) | 4) +#define XY_SETUP_CLIP_BLT_CMD ((2 << 29) | (0x03 << 22) | 1) +#define XY_SRC_COPY_BLT_CMD ((2 << 29) | (0x53 << 22) | 6) +#define SRC_COPY_BLT_CMD ((2 << 29) | (0x43 << 22) | 4) +#define XY_MONO_PAT_BLT_CMD ((2 << 29) | (0x52 << 22) | 7) +#define XY_MONO_SRC_BLT_CMD ((2 << 29) | (0x54 << 22) | 6) +#define XY_MONO_SRC_IMM_BLT_CMD ((2 << 29) | (0x71 << 22) | 5) +#define TXT_IMM_BLT_CMD ((2 << 29) | (0x30 << 22) | 2) +#define SETUP_BLT_CMD ((2 << 29) | (0x00 << 22) | 6) + +#define DW_LENGTH_MASK 0xff + +#define WRITE_ALPHA (1 << 21) +#define WRITE_RGB (1 << 20) +#define VERT_SEED (3 << 8) +#define HORIZ_SEED (3 << 12) + +#define COLOR_DEPTH_8 (0 << 24) +#define COLOR_DEPTH_16 (1 << 24) +#define COLOR_DEPTH_32 (3 << 24) + +#define SRC_ROP_GXCOPY 0xcc +#define SRC_ROP_GXXOR 0x66 + +#define PAT_ROP_GXCOPY 0xf0 +#define PAT_ROP_GXXOR 0x5a + +#define PITCH_SHIFT 0 +#define ROP_SHIFT 16 +#define WIDTH_SHIFT 0 +#define HEIGHT_SHIFT 16 + +/* in bytes */ +#define MAX_MONO_IMM_SIZE 128 + + +/*** Macros ***/ + +/* I/O macros */ +#define INREG8(addr) readb((u8 __iomem *)(dinfo->mmio_base + (addr))) +#define INREG(addr) readl((u32 __iomem *)(dinfo->mmio_base + (addr))) +#define OUTREG8(addr, val) writeb((val),(u8 __iomem *)(dinfo->mmio_base + \ + (addr))) +#define OUTREG(addr, val) writel((val),(u32 __iomem *)(dinfo->mmio_base + \ + (addr))) + +/* Ring buffer macros */ +#define OUT_RING(n) do { \ + writel((n), (u32 __iomem *)(dinfo->ring.virtual + dinfo->ring_tail));\ + dinfo->ring_tail += 4; \ + dinfo->ring_tail &= dinfo->ring_tail_mask; \ +} while (0) + +#define START_RING(n) do { \ + if (dinfo->ring_space < (n) * 4) \ + wait_ring(dinfo,(n) * 4); \ + dinfo->ring_space -= (n) * 4; \ +} while (0) + +#define ADVANCE_RING() do { \ + OUTREG(PRI_RING_TAIL, dinfo->ring_tail); \ +} while (0) + +#define DO_RING_IDLE() do { \ + u32 head, tail; \ + do { \ + head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK; \ + tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK; \ + udelay(10); \ + } while (head != tail); \ +} while (0) + + +/* function protoypes */ +extern int intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, + int *chipset, int *mobile); +extern int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, + int *stolen_size); +extern int intelfbhw_check_non_crt(struct intelfb_info *dinfo); +extern const char *intelfbhw_dvo_to_string(int dvo); +extern int intelfbhw_validate_mode(struct intelfb_info *dinfo, + struct fb_var_screeninfo *var); +extern int intelfbhw_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +extern void intelfbhw_do_blank(int blank, struct fb_info *info); +extern void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp); +extern int intelfbhw_read_hw_state(struct intelfb_info *dinfo, + struct intelfb_hwstate *hw, int flag); +extern void intelfbhw_print_hw_state(struct intelfb_info *dinfo, + struct intelfb_hwstate *hw); +extern int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, + struct intelfb_hwstate *hw, + struct fb_var_screeninfo *var); +extern int intelfbhw_program_mode(struct intelfb_info *dinfo, + const struct intelfb_hwstate *hw, int blank); +extern void intelfbhw_do_sync(struct intelfb_info *dinfo); +extern void intelfbhw_2d_stop(struct intelfb_info *dinfo); +extern void intelfbhw_2d_start(struct intelfb_info *dinfo); +extern void intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, + u32 w, u32 h, u32 color, u32 pitch, u32 bpp, + u32 rop); +extern void intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury, + u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch, + u32 bpp); +extern int intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, + u32 w, u32 h, const u8* cdat, u32 x, u32 y, + u32 pitch, u32 bpp); +extern void intelfbhw_cursor_init(struct intelfb_info *dinfo); +extern void intelfbhw_cursor_hide(struct intelfb_info *dinfo); +extern void intelfbhw_cursor_show(struct intelfb_info *dinfo); +extern void intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y); +extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, + u32 fg); +extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, + int height, u8 *data); +extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); + +#endif /* _INTELFBHW_H */ diff --git a/drivers/video/kyro/Makefile b/drivers/video/kyro/Makefile new file mode 100644 index 000000000000..2fd66f551bae --- /dev/null +++ b/drivers/video/kyro/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the Kyro framebuffer driver +# + +obj-$(CONFIG_FB_KYRO) += kyrofb.o + +kyrofb-objs := STG4000Ramdac.o STG4000VTG.o STG4000OverlayDevice.o \ + STG4000InitDevice.o fbdev.o diff --git a/drivers/video/kyro/STG4000InitDevice.c b/drivers/video/kyro/STG4000InitDevice.c new file mode 100644 index 000000000000..7e33cd307d47 --- /dev/null +++ b/drivers/video/kyro/STG4000InitDevice.c @@ -0,0 +1,326 @@ +/* + * linux/drivers/video/kyro/STG4000InitDevice.c + * + * Copyright (C) 2000 Imagination Technologies Ltd + * Copyright (C) 2002 STMicroelectronics + * + * 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/errno.h> +#include <linux/types.h> +#include <linux/pci.h> + +#include "STG4000Reg.h" + +/* SDRAM fixed settings */ +#define SDRAM_CFG_0 0x49A1 +#define SDRAM_CFG_1 0xA732 +#define SDRAM_CFG_2 0x31 +#define SDRAM_ARB_CFG 0xA0 +#define SDRAM_REFRESH 0x20 + +/* Reset values */ +#define PMX2_SOFTRESET_DAC_RST 0x0001 +#define PMX2_SOFTRESET_C1_RST 0x0004 +#define PMX2_SOFTRESET_C2_RST 0x0008 +#define PMX2_SOFTRESET_3D_RST 0x0010 +#define PMX2_SOFTRESET_VIDIN_RST 0x0020 +#define PMX2_SOFTRESET_TLB_RST 0x0040 +#define PMX2_SOFTRESET_SD_RST 0x0080 +#define PMX2_SOFTRESET_VGA_RST 0x0100 +#define PMX2_SOFTRESET_ROM_RST 0x0200 /* reserved bit, do not reset */ +#define PMX2_SOFTRESET_TA_RST 0x0400 +#define PMX2_SOFTRESET_REG_RST 0x4000 +#define PMX2_SOFTRESET_ALL 0x7fff + +/* Core clock freq */ +#define CORE_PLL_FREQ 1000000 + +/* Reference Clock freq */ +#define REF_FREQ 14318 + +/* PCI Registers */ +static u16 CorePllControl = 0x70; + +#define PCI_CONFIG_SUBSYS_ID 0x2e + +/* Misc */ +#define CORE_PLL_MODE_REG_0_7 3 +#define CORE_PLL_MODE_REG_8_15 2 +#define CORE_PLL_MODE_CONFIG_REG 1 +#define DAC_PLL_CONFIG_REG 0 + +#define STG_MAX_VCO 500000 +#define STG_MIN_VCO 100000 + +/* PLL Clock */ +#define STG4K3_PLL_SCALER 8 /* scale numbers by 2^8 for fixed point calc */ +#define STG4K3_PLL_MIN_R 2 /* Minimum multiplier */ +#define STG4K3_PLL_MAX_R 33 /* Max */ +#define STG4K3_PLL_MIN_F 2 /* Minimum divisor */ +#define STG4K3_PLL_MAX_F 513 /* Max */ +#define STG4K3_PLL_MIN_OD 0 /* Min output divider (shift) */ +#define STG4K3_PLL_MAX_OD 2 /* Max */ +#define STG4K3_PLL_MIN_VCO_SC (100000000 >> STG4K3_PLL_SCALER) /* Min VCO rate */ +#define STG4K3_PLL_MAX_VCO_SC (500000000 >> STG4K3_PLL_SCALER) /* Max VCO rate */ +#define STG4K3_PLL_MINR_VCO_SC (100000000 >> STG4K3_PLL_SCALER) /* Min VCO rate (restricted) */ +#define STG4K3_PLL_MAXR_VCO_SC (500000000 >> STG4K3_PLL_SCALER) /* Max VCO rate (restricted) */ +#define STG4K3_PLL_MINR_VCO 100000000 /* Min VCO rate (restricted) */ +#define STG4K3_PLL_MAX_VCO 500000000 /* Max VCO rate */ +#define STG4K3_PLL_MAXR_VCO 500000000 /* Max VCO rate (restricted) */ + +#define OS_DELAY(X) \ +{ \ +volatile u32 i,count=0; \ + for(i=0;i<X;i++) count++; \ +} + +static u32 InitSDRAMRegisters(volatile STG4000REG __iomem *pSTGReg, + u32 dwSubSysID, u32 dwRevID) +{ + u32 adwSDRAMArgCfg0[] = { 0xa0, 0x80, 0xa0, 0xa0, 0xa0 }; + u32 adwSDRAMCfg1[] = { 0x8732, 0x8732, 0xa732, 0xa732, 0x8732 }; + u32 adwSDRAMCfg2[] = { 0x87d2, 0x87d2, 0xa7d2, 0x87d2, 0xa7d2 }; + u32 adwSDRAMRsh[] = { 36, 39, 40 }; + u32 adwChipSpeed[] = { 110, 120, 125 }; + u32 dwMemTypeIdx; + u32 dwChipSpeedIdx; + + /* Get memory tpye and chip speed indexs from the SubSysDevID */ + dwMemTypeIdx = (dwSubSysID & 0x70) >> 4; + dwChipSpeedIdx = (dwSubSysID & 0x180) >> 7; + + if (dwMemTypeIdx > 4 || dwChipSpeedIdx > 2) + return 0; + + /* Program SD-RAM interface */ + STG_WRITE_REG(SDRAMArbiterConf, adwSDRAMArgCfg0[dwMemTypeIdx]); + if (dwRevID < 5) { + STG_WRITE_REG(SDRAMConf0, 0x49A1); + STG_WRITE_REG(SDRAMConf1, adwSDRAMCfg1[dwMemTypeIdx]); + } else { + STG_WRITE_REG(SDRAMConf0, 0x4DF1); + STG_WRITE_REG(SDRAMConf1, adwSDRAMCfg2[dwMemTypeIdx]); + } + + STG_WRITE_REG(SDRAMConf2, 0x31); + STG_WRITE_REG(SDRAMRefresh, adwSDRAMRsh[dwChipSpeedIdx]); + + return adwChipSpeed[dwChipSpeedIdx] * 10000; +} + +u32 ProgramClock(u32 refClock, + u32 coreClock, + u32 * FOut, u32 * ROut, u32 * POut) +{ + u32 R = 0, F = 0, OD = 0, ODIndex = 0; + u32 ulBestR = 0, ulBestF = 0, ulBestOD = 0; + u32 ulBestVCO = 0, ulBestClk = 0, ulBestScore = 0; + u32 ulScore, ulPhaseScore, ulVcoScore; + u32 ulTmp = 0, ulVCO; + u32 ulScaleClockReq, ulMinClock, ulMaxClock; + u32 ODValues[] = { 1, 2, 0 }; + + /* Translate clock in Hz */ + coreClock *= 100; /* in Hz */ + refClock *= 1000; /* in Hz */ + + /* Work out acceptable clock + * The method calculates ~ +- 0.4% (1/256) + */ + ulMinClock = coreClock - (coreClock >> 8); + ulMaxClock = coreClock + (coreClock >> 8); + + /* Scale clock required for use in calculations */ + ulScaleClockReq = coreClock >> STG4K3_PLL_SCALER; + + /* Iterate through post divider values */ + for (ODIndex = 0; ODIndex < 3; ODIndex++) { + OD = ODValues[ODIndex]; + R = STG4K3_PLL_MIN_R; + + /* loop for pre-divider from min to max */ + while (R <= STG4K3_PLL_MAX_R) { + /* estimate required feedback multiplier */ + ulTmp = R * (ulScaleClockReq << OD); + + /* F = ClkRequired * R * (2^OD) / Fref */ + F = (u32)(ulTmp / (refClock >> STG4K3_PLL_SCALER)); + + /* compensate for accuracy */ + if (F > STG4K3_PLL_MIN_F) + F--; + + + /* + * We should be close to our target frequency (if it's + * achievable with current OD & R) let's iterate + * through F for best fit + */ + while ((F >= STG4K3_PLL_MIN_F) && + (F <= STG4K3_PLL_MAX_F)) { + /* Calc VCO at full accuracy */ + ulVCO = refClock / R; + ulVCO = F * ulVCO; + + /* + * Check it's within restricted VCO range + * unless of course the desired frequency is + * above the restricted range, then test + * against VCO limit + */ + if ((ulVCO >= STG4K3_PLL_MINR_VCO) && + ((ulVCO <= STG4K3_PLL_MAXR_VCO) || + ((coreClock > STG4K3_PLL_MAXR_VCO) + && (ulVCO <= STG4K3_PLL_MAX_VCO)))) { + ulTmp = (ulVCO >> OD); /* Clock = VCO / (2^OD) */ + + /* Is this clock good enough? */ + if ((ulTmp >= ulMinClock) + && (ulTmp <= ulMaxClock)) { + ulPhaseScore = (((refClock / R) - (refClock / STG4K3_PLL_MAX_R))) / ((refClock - (refClock / STG4K3_PLL_MAX_R)) >> 10); + + ulVcoScore = ((ulVCO - STG4K3_PLL_MINR_VCO)) / ((STG4K3_PLL_MAXR_VCO - STG4K3_PLL_MINR_VCO) >> 10); + ulScore = ulPhaseScore + ulVcoScore; + + if (!ulBestScore) { + ulBestVCO = ulVCO; + ulBestOD = OD; + ulBestF = F; + ulBestR = R; + ulBestClk = ulTmp; + ulBestScore = + ulScore; + } + /* is this better, ( aim for highest Score) */ + /*-------------------------------------------------------------------------- + Here we want to use a scoring system which will take account of both the + value at the phase comparater and the VCO output + to do this we will use a cumulative score between the two + The way this ends up is that we choose the first value in the loop anyway + but we shall keep this code in case new restrictions come into play + --------------------------------------------------------------------------*/ + if ((ulScore >= ulBestScore) && (OD > 0)) { + ulBestVCO = ulVCO; + ulBestOD = OD; + ulBestF = F; + ulBestR = R; + ulBestClk = ulTmp; + ulBestScore = + ulScore; + } + } + } + F++; + } + R++; + } + } + + /* + did we find anything? + Then return RFOD + */ + if (ulBestScore) { + *ROut = ulBestR; + *FOut = ulBestF; + + if ((ulBestOD == 2) || (ulBestOD == 3)) { + *POut = 3; + } else + *POut = ulBestOD; + + } + + return (ulBestClk); +} + +int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev) +{ + u32 F, R, P; + u16 core_pll = 0, sub; + u32 ulCoreClock; + u32 tmp; + u32 ulChipSpeed; + u8 rev; + + STG_WRITE_REG(IntMask, 0xFFFF); + + /* Disable Primary Core Thread0 */ + tmp = STG_READ_REG(Thread0Enable); + CLEAR_BIT(0); + STG_WRITE_REG(Thread0Enable, tmp); + + /* Disable Primary Core Thread1 */ + tmp = STG_READ_REG(Thread1Enable); + CLEAR_BIT(0); + STG_WRITE_REG(Thread1Enable, tmp); + + STG_WRITE_REG(SoftwareReset, + PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_ROM_RST); + STG_WRITE_REG(SoftwareReset, + PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_TA_RST | + PMX2_SOFTRESET_ROM_RST); + + /* Need to play around to reset TA */ + STG_WRITE_REG(TAConfiguration, 0); + STG_WRITE_REG(SoftwareReset, + PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_ROM_RST); + STG_WRITE_REG(SoftwareReset, + PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_TA_RST | + PMX2_SOFTRESET_ROM_RST); + + pci_read_config_word(pDev, PCI_CONFIG_SUBSYS_ID, &sub); + pci_read_config_byte(pDev, PCI_REVISION_ID, &rev); + + ulChipSpeed = InitSDRAMRegisters(pSTGReg, (u32)sub, (u32)rev); + + if (ulChipSpeed == 0) + return -EINVAL; + + ulCoreClock = ProgramClock(REF_FREQ, CORE_PLL_FREQ, &F, &R, &P); + + core_pll |= ((P) | ((F - 2) << 2) | ((R - 2) << 11)); + + /* Set Core PLL Control to Core PLL Mode */ + + /* Send bits 0:7 of the Core PLL Mode register */ + tmp = ((CORE_PLL_MODE_REG_0_7 << 8) | (core_pll & 0x00FF)); + pci_write_config_word(pDev, CorePllControl, tmp); + /* Without some delay between the PCI config writes the clock does + not reliably set when the code is compiled -O3 + */ + OS_DELAY(1000000); + + tmp |= SET_BIT(14); + pci_write_config_word(pDev, CorePllControl, tmp); + OS_DELAY(1000000); + + /* Send bits 8:15 of the Core PLL Mode register */ + tmp = + ((CORE_PLL_MODE_REG_8_15 << 8) | ((core_pll & 0xFF00) >> 8)); + pci_write_config_word(pDev, CorePllControl, tmp); + OS_DELAY(1000000); + + tmp |= SET_BIT(14); + pci_write_config_word(pDev, CorePllControl, tmp); + OS_DELAY(1000000); + + STG_WRITE_REG(SoftwareReset, PMX2_SOFTRESET_ALL); + +#if 0 + /* Enable Primary Core Thread0 */ + tmp = ((STG_READ_REG(Thread0Enable)) | SET_BIT(0)); + STG_WRITE_REG(Thread0Enable, tmp); + + /* Enable Primary Core Thread1 */ + tmp = ((STG_READ_REG(Thread1Enable)) | SET_BIT(0)); + STG_WRITE_REG(Thread1Enable, tmp); +#endif + + return 0; +} diff --git a/drivers/video/kyro/STG4000Interface.h b/drivers/video/kyro/STG4000Interface.h new file mode 100644 index 000000000000..e75b3b4a4aa1 --- /dev/null +++ b/drivers/video/kyro/STG4000Interface.h @@ -0,0 +1,60 @@ +/* + * linux/drivers/video/kyro/STG4000Interface.h + * + * Copyright (C) 2002 STMicroelectronics + * + * 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 _STG4000INTERFACE_H +#define _STG4000INTERFACE_H + +struct pci_dev; + +/* + * Ramdac Setup + */ +extern int InitialiseRamdac(volatile STG4000REG __iomem *pSTGReg, u32 displayDepth, + u32 displayWidth, u32 displayHeight, + s32 HSyncPolarity, s32 VSyncPolarity, + u32 *pixelClock); + +extern void DisableRamdacOutput(volatile STG4000REG __iomem *pSTGReg); +extern void EnableRamdacOutput(volatile STG4000REG __iomem *pSTGReg); + +/* + * Timing generator setup + */ +extern void DisableVGA(volatile STG4000REG __iomem *pSTGReg); +extern void StopVTG(volatile STG4000REG __iomem *pSTGReg); +extern void StartVTG(volatile STG4000REG __iomem *pSTGReg); +extern void SetupVTG(volatile STG4000REG __iomem *pSTGReg, + const struct kyrofb_info * pTiming); + +extern u32 ProgramClock(u32 refClock, u32 coreClock, u32 *FOut, u32 *ROut, u32 *POut); +extern int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev); + +/* + * Overlay setup + */ +extern void ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg); + +extern int CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg, + u32 ulWidth, u32 ulHeight, + int bLinear, + u32 ulOverlayOffset, + u32 * retStride, u32 * retUVStride); + +extern int SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg, + OVRL_BLEND_MODE mode, + u32 ulAlpha, u32 ulColorKey); + +extern int SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg, + u32 left, u32 top, + u32 right, u32 bottom); + +extern void EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg); + +#endif /* _STG4000INTERFACE_H */ diff --git a/drivers/video/kyro/STG4000OverlayDevice.c b/drivers/video/kyro/STG4000OverlayDevice.c new file mode 100644 index 000000000000..2ae9bafacdd0 --- /dev/null +++ b/drivers/video/kyro/STG4000OverlayDevice.c @@ -0,0 +1,600 @@ +/* + * linux/drivers/video/kyro/STG4000OverlayDevice.c + * + * Copyright (C) 2000 Imagination Technologies Ltd + * Copyright (C) 2002 STMicroelectronics + * + * 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/errno.h> +#include <linux/types.h> + +#include "STG4000Reg.h" + +/* HW Defines */ + +#define STG4000_NO_SCALING 0x800 +#define STG4000_NO_DECIMATION 0xFFFFFFFF + +/* Primary surface */ +#define STG4000_PRIM_NUM_PIX 5 +#define STG4000_PRIM_ALIGN 4 +#define STG4000_PRIM_ADDR_BITS 20 + +#define STG4000_PRIM_MIN_WIDTH 640 +#define STG4000_PRIM_MAX_WIDTH 1600 +#define STG4000_PRIM_MIN_HEIGHT 480 +#define STG4000_PRIM_MAX_HEIGHT 1200 + +/* Overlay surface */ +#define STG4000_OVRL_NUM_PIX 4 +#define STG4000_OVRL_ALIGN 2 +#define STG4000_OVRL_ADDR_BITS 20 +#define STG4000_OVRL_NUM_MODES 5 + +#define STG4000_OVRL_MIN_WIDTH 0 +#define STG4000_OVRL_MAX_WIDTH 720 +#define STG4000_OVRL_MIN_HEIGHT 0 +#define STG4000_OVRL_MAX_HEIGHT 576 + +/* Decimation and Scaling */ +static u32 adwDecim8[33] = { + 0xffffffff, 0xfffeffff, 0xffdffbff, 0xfefefeff, 0xfdf7efbf, + 0xfbdf7bdf, 0xf7bbddef, 0xeeeeeeef, 0xeeddbb77, 0xedb76db7, + 0xdb6db6db, 0xdb5b5b5b, 0xdab5ad6b, 0xd5ab55ab, 0xd555aaab, + 0xaaaaaaab, 0xaaaa5555, 0xaa952a55, 0xa94a5295, 0xa5252525, + 0xa4924925, 0x92491249, 0x91224489, 0x91111111, 0x90884211, + 0x88410821, 0x88102041, 0x81010101, 0x80800801, 0x80010001, + 0x80000001, 0x00000001, 0x00000000 +}; + +typedef struct _OVRL_SRC_DEST { + /*clipped on-screen pixel position of overlay */ + u32 ulDstX1; + u32 ulDstY1; + u32 ulDstX2; + u32 ulDstY2; + + /*clipped pixel pos of source data within buffer thses need to be 128 bit word aligned */ + u32 ulSrcX1; + u32 ulSrcY1; + u32 ulSrcX2; + u32 ulSrcY2; + + /* on-screen pixel position of overlay */ + s32 lDstX1; + s32 lDstY1; + s32 lDstX2; + s32 lDstY2; +} OVRL_SRC_DEST; + +static u32 ovlWidth, ovlHeight, ovlStride; +static int ovlLinear; + +void ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg) +{ + u32 tmp; + + /* Set Overlay address to default */ + tmp = STG_READ_REG(DACOverlayAddr); + CLEAR_BITS_FRM_TO(0, 20); + CLEAR_BIT(31); + STG_WRITE_REG(DACOverlayAddr, tmp); + + /* Set Overlay U address */ + tmp = STG_READ_REG(DACOverlayUAddr); + CLEAR_BITS_FRM_TO(0, 20); + STG_WRITE_REG(DACOverlayUAddr, tmp); + + /* Set Overlay V address */ + tmp = STG_READ_REG(DACOverlayVAddr); + CLEAR_BITS_FRM_TO(0, 20); + STG_WRITE_REG(DACOverlayVAddr, tmp); + + /* Set Overlay Size */ + tmp = STG_READ_REG(DACOverlaySize); + CLEAR_BITS_FRM_TO(0, 10); + CLEAR_BITS_FRM_TO(12, 31); + STG_WRITE_REG(DACOverlaySize, tmp); + + /* Set Overlay Vt Decimation */ + tmp = STG4000_NO_DECIMATION; + STG_WRITE_REG(DACOverlayVtDec, tmp); + + /* Set Overlay format to default value */ + tmp = STG_READ_REG(DACPixelFormat); + CLEAR_BITS_FRM_TO(4, 7); + CLEAR_BITS_FRM_TO(16, 22); + STG_WRITE_REG(DACPixelFormat, tmp); + + /* Set Vertical scaling to default */ + tmp = STG_READ_REG(DACVerticalScal); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 22); + tmp |= STG4000_NO_SCALING; /* Set to no scaling */ + STG_WRITE_REG(DACVerticalScal, tmp); + + /* Set Horizontal Scaling to default */ + tmp = STG_READ_REG(DACHorizontalScal); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 17); + tmp |= STG4000_NO_SCALING; /* Set to no scaling */ + STG_WRITE_REG(DACHorizontalScal, tmp); + + /* Set Blend mode to Alpha Blend */ + /* ????? SG 08/11/2001 Surely this isn't the alpha blend mode, + hopefully its overwrite + */ + tmp = STG_READ_REG(DACBlendCtrl); + CLEAR_BITS_FRM_TO(0, 30); + tmp = (GRAPHICS_MODE << 28); + STG_WRITE_REG(DACBlendCtrl, tmp); + +} + +int CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg, + u32 inWidth, + u32 inHeight, + int bLinear, + u32 ulOverlayOffset, + u32 * retStride, u32 * retUVStride) +{ + u32 tmp; + u32 ulStride; + + if (inWidth > STG4000_OVRL_MAX_WIDTH || + inHeight > STG4000_OVRL_MAX_HEIGHT) { + return -EINVAL; + } + + /* Stride in 16 byte words - 16Bpp */ + if (bLinear) { + /* Format is 16bits so num 16 byte words is width/8 */ + if ((inWidth & 0x7) == 0) { /* inWidth % 8 */ + ulStride = (inWidth / 8); + } else { + /* Round up to next 16byte boundary */ + ulStride = ((inWidth + 8) / 8); + } + } else { + /* Y component is 8bits so num 16 byte words is width/16 */ + if ((inWidth & 0xf) == 0) { /* inWidth % 16 */ + ulStride = (inWidth / 16); + } else { + /* Round up to next 16byte boundary */ + ulStride = ((inWidth + 16) / 16); + } + } + + + /* Set Overlay address and Format mode */ + tmp = STG_READ_REG(DACOverlayAddr); + CLEAR_BITS_FRM_TO(0, 20); + if (bLinear) { + CLEAR_BIT(31); /* Overlay format to Linear */ + } else { + tmp |= SET_BIT(31); /* Overlay format to Planer */ + } + + /* Only bits 24:4 of the Overlay address */ + tmp |= (ulOverlayOffset >> 4); + STG_WRITE_REG(DACOverlayAddr, tmp); + + if (!bLinear) { + u32 uvSize = + (inWidth & 0x1) ? (inWidth + 1 / 2) : (inWidth / 2); + u32 uvStride; + u32 ulOffset; + /* Y component is 8bits so num 32 byte words is width/32 */ + if ((uvSize & 0xf) == 0) { /* inWidth % 16 */ + uvStride = (uvSize / 16); + } else { + /* Round up to next 32byte boundary */ + uvStride = ((uvSize + 16) / 16); + } + + ulOffset = ulOverlayOffset + (inHeight * (ulStride * 16)); + /* Align U,V data to 32byte boundary */ + if ((ulOffset & 0x1f) != 0) + ulOffset = (ulOffset + 32L) & 0xffffffE0L; + + tmp = STG_READ_REG(DACOverlayUAddr); + CLEAR_BITS_FRM_TO(0, 20); + tmp |= (ulOffset >> 4); + STG_WRITE_REG(DACOverlayUAddr, tmp); + + ulOffset += (inHeight / 2) * (uvStride * 16); + /* Align U,V data to 32byte boundary */ + if ((ulOffset & 0x1f) != 0) + ulOffset = (ulOffset + 32L) & 0xffffffE0L; + + tmp = STG_READ_REG(DACOverlayVAddr); + CLEAR_BITS_FRM_TO(0, 20); + tmp |= (ulOffset >> 4); + STG_WRITE_REG(DACOverlayVAddr, tmp); + + *retUVStride = uvStride * 16; + } + + + /* Set Overlay YUV pixel format + * Make sure that LUT not used - ?????? + */ + tmp = STG_READ_REG(DACPixelFormat); + /* Only support Planer or UYVY linear formats */ + CLEAR_BITS_FRM_TO(4, 9); + STG_WRITE_REG(DACPixelFormat, tmp); + + ovlWidth = inWidth; + ovlHeight = inHeight; + ovlStride = ulStride; + ovlLinear = bLinear; + *retStride = ulStride << 4; /* In bytes */ + + return 0; +} + +int SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg, + OVRL_BLEND_MODE mode, + u32 ulAlpha, u32 ulColorKey) +{ + u32 tmp; + + tmp = STG_READ_REG(DACBlendCtrl); + CLEAR_BITS_FRM_TO(28, 30); + tmp |= (mode << 28); + + switch (mode) { + case COLOR_KEY: + CLEAR_BITS_FRM_TO(0, 23); + tmp |= (ulColorKey & 0x00FFFFFF); + break; + + case GLOBAL_ALPHA: + CLEAR_BITS_FRM_TO(24, 27); + tmp |= ((ulAlpha & 0xF) << 24); + break; + + case CK_PIXEL_ALPHA: + CLEAR_BITS_FRM_TO(0, 23); + tmp |= (ulColorKey & 0x00FFFFFF); + break; + + case CK_GLOBAL_ALPHA: + CLEAR_BITS_FRM_TO(0, 23); + tmp |= (ulColorKey & 0x00FFFFFF); + CLEAR_BITS_FRM_TO(24, 27); + tmp |= ((ulAlpha & 0xF) << 24); + break; + + case GRAPHICS_MODE: + case PER_PIXEL_ALPHA: + break; + + default: + return -EINVAL; + } + + STG_WRITE_REG(DACBlendCtrl, tmp); + + return 0; +} + +void EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg) +{ + u32 tmp; + /* Enable Overlay */ + tmp = STG_READ_REG(DACPixelFormat); + tmp |= SET_BIT(7); + STG_WRITE_REG(DACPixelFormat, tmp); + + /* Set video stream control */ + tmp = STG_READ_REG(DACStreamCtrl); + tmp |= SET_BIT(1); /* video stream */ + STG_WRITE_REG(DACStreamCtrl, tmp); +} + +static u32 Overlap(u32 ulBits, u32 ulPattern) +{ + u32 ulCount = 0; + + while (ulBits) { + if (!(ulPattern & 1)) + ulCount++; + ulBits--; + ulPattern = ulPattern >> 1; + } + + return ulCount; + +} + +int SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg, + u32 left, u32 top, + u32 right, u32 bottom) +{ + OVRL_SRC_DEST srcDest; + + u32 ulSrcTop, ulSrcBottom; + u32 ulSrc, ulDest; + u32 ulFxScale, ulFxOffset; + u32 ulHeight, ulWidth; + u32 ulPattern; + u32 ulDecimate, ulDecimated; + u32 ulApplied; + u32 ulDacXScale, ulDacYScale; + u32 ulScale; + u32 ulLeft, ulRight; + u32 ulSrcLeft, ulSrcRight; + u32 ulScaleLeft, ulScaleRight; + u32 ulhDecim; + u32 ulsVal; + u32 ulVertDecFactor; + int bResult; + u32 ulClipOff = 0; + u32 ulBits = 0; + u32 ulsAdd = 0; + u32 tmp, ulStride; + u32 ulExcessPixels, ulClip, ulExtraLines; + + + srcDest.ulSrcX1 = 0; + srcDest.ulSrcY1 = 0; + srcDest.ulSrcX2 = ovlWidth - 1; + srcDest.ulSrcY2 = ovlHeight - 1; + + srcDest.ulDstX1 = left; + srcDest.ulDstY1 = top; + srcDest.ulDstX2 = right; + srcDest.ulDstY2 = bottom; + + srcDest.lDstX1 = srcDest.ulDstX1; + srcDest.lDstY1 = srcDest.ulDstY1; + srcDest.lDstX2 = srcDest.ulDstX2; + srcDest.lDstY2 = srcDest.ulDstY2; + + /************* Vertical decimation/scaling ******************/ + + /* Get Src Top and Bottom */ + ulSrcTop = srcDest.ulSrcY1; + ulSrcBottom = srcDest.ulSrcY2; + + ulSrc = ulSrcBottom - ulSrcTop; + ulDest = srcDest.lDstY2 - srcDest.lDstY1; /* on-screen overlay */ + + if (ulSrc <= 1) + return -EINVAL; + + /* First work out the position we are to display as offset from the + * source of the buffer + */ + ulFxScale = (ulDest << 11) / ulSrc; /* fixed point scale factor */ + ulFxOffset = (srcDest.lDstY2 - srcDest.ulDstY2) << 11; + + ulSrcBottom = ulSrcBottom - (ulFxOffset / ulFxScale); + ulSrc = ulSrcBottom - ulSrcTop; + ulHeight = ulSrc; + + ulDest = srcDest.ulDstY2 - (srcDest.ulDstY1 - 1); + ulPattern = adwDecim8[ulBits]; + + /* At this point ulSrc represents the input decimator */ + if (ulSrc > ulDest) { + ulDecimate = ulSrc - ulDest; + ulBits = 0; + ulApplied = ulSrc / 32; + + while (((ulBits * ulApplied) + + Overlap((ulSrc % 32), + adwDecim8[ulBits])) < ulDecimate) + ulBits++; + + ulPattern = adwDecim8[ulBits]; + ulDecimated = + (ulBits * ulApplied) + Overlap((ulSrc % 32), + ulPattern); + ulSrc = ulSrc - ulDecimated; /* the number number of lines that will go into the scaler */ + } + + if (ulBits && (ulBits != 32)) { + ulVertDecFactor = (63 - ulBits) / (32 - ulBits); /* vertical decimation factor scaled up to nearest integer */ + } else { + ulVertDecFactor = 1; + } + + ulDacYScale = ((ulSrc - 1) * 2048) / (ulDest + 1); + + tmp = STG_READ_REG(DACOverlayVtDec); /* Decimation */ + CLEAR_BITS_FRM_TO(0, 31); + tmp = ulPattern; + STG_WRITE_REG(DACOverlayVtDec, tmp); + + /***************** Horizontal decimation/scaling ***************************/ + + /* + * Now we handle the horizontal case, this is a simplified verison of + * the vertical case in that we decimate by factors of 2. as we are + * working in words we should always be able to decimate by these + * factors. as we always have to have a buffer which is aligned to a + * whole number of 128 bit words, we must align the left side to the + * lowest to the next lowest 128 bit boundary, and the right hand edge + * to the next largets boundary, (in a similar way to how we didi it in + * PMX1) as the left and right hand edges are aligned to these + * boundaries normally this only becomes an issue when we are chopping + * of one of the sides We shall work out vertical stuff first + */ + ulSrc = srcDest.ulSrcX2 - srcDest.ulSrcX1; + ulDest = srcDest.lDstX2 - srcDest.lDstX1; +#ifdef _OLDCODE + ulLeft = srcDest.ulDstX1; + ulRight = srcDest.ulDstX2; +#else + if (srcDest.ulDstX1 > 2) { + ulLeft = srcDest.ulDstX1 + 2; + ulRight = srcDest.ulDstX2 + 1; + } else { + ulLeft = srcDest.ulDstX1; + ulRight = srcDest.ulDstX2 + 1; + } +#endif + /* first work out the position we are to display as offset from the source of the buffer */ + bResult = 1; + + do { + if (ulDest == 0) + return -EINVAL; + + /* source pixels per dest pixel <<11 */ + ulFxScale = ((ulSrc - 1) << 11) / (ulDest); + + /* then number of destination pixels out we are */ + ulFxOffset = ulFxScale * ((srcDest.ulDstX1 - srcDest.lDstX1) + ulClipOff); + ulFxOffset >>= 11; + + /* this replaces the code which was making a decision as to use either ulFxOffset or ulSrcX1 */ + ulSrcLeft = srcDest.ulSrcX1 + ulFxOffset; + + /* then number of destination pixels out we are */ + ulFxOffset = ulFxScale * (srcDest.lDstX2 - srcDest.ulDstX2); + ulFxOffset >>= 11; + + ulSrcRight = srcDest.ulSrcX2 - ulFxOffset; + + /* + * we must align these to our 128 bit boundaries. we shall + * round down the pixel pos to the nearest 8 pixels. + */ + ulScaleLeft = ulSrcLeft; + ulScaleRight = ulSrcRight; + + /* shift fxscale until it is in the range of the scaler */ + ulhDecim = 0; + ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2); + + while (ulScale > 0x800) { + ulhDecim++; + ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2); + } + + /* + * to try and get the best values We first try and use + * src/dwdest for the scale factor, then we move onto src-1 + * + * we want to check to see if we will need to clip data, if so + * then we should clip our source so that we don't need to + */ + if (!ovlLinear) { + ulSrcLeft &= ~0x1f; + + /* + * we must align the right hand edge to the next 32 + * pixel` boundary, must be on a 256 boundary so u, and + * v are 128 bit aligned + */ + ulSrcRight = (ulSrcRight + 0x1f) & ~0x1f; + } else { + ulSrcLeft &= ~0x7; + + /* + * we must align the right hand edge to the next + * 8pixel` boundary + */ + ulSrcRight = (ulSrcRight + 0x7) & ~0x7; + } + + /* this is the input size line store needs to cope with */ + ulWidth = ulSrcRight - ulSrcLeft; + + /* + * use unclipped value to work out scale factror this is the + * scale factor we want we shall now work out the horizonal + * decimation and scaling + */ + ulsVal = ((ulWidth / 8) >> ulhDecim); + + if ((ulWidth != (ulsVal << ulhDecim) * 8)) + ulsAdd = 1; + + /* input pixels to scaler; */ + ulSrc = ulWidth >> ulhDecim; + + if (ulSrc <= 2) + return -EINVAL; + + ulExcessPixels = ((((ulScaleLeft - ulSrcLeft)) << (11 - ulhDecim)) / ulScale); + + ulClip = (ulSrc << 11) / ulScale; + ulClip -= (ulRight - ulLeft); + ulClip += ulExcessPixels; + + if (ulClip) + ulClip--; + + /* We may need to do more here if we really have a HW rev < 5 */ + } while (!bResult); + + ulExtraLines = (1 << ulhDecim) * ulVertDecFactor; + ulExtraLines += 64; + ulHeight += ulExtraLines; + + ulDacXScale = ulScale; + + + tmp = STG_READ_REG(DACVerticalScal); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 22); /* Vertical Scaling */ + + /* Calculate new output line stride, this is always the number of 422 + words in the line buffer, so it doesn't matter if the + mode is 420. Then set the vertical scale register. + */ + ulStride = (ulWidth >> (ulhDecim + 3)) + ulsAdd; + tmp |= ((ulStride << 16) | (ulDacYScale)); /* DAC_LS_CTRL = stride */ + STG_WRITE_REG(DACVerticalScal, tmp); + + /* Now set up the overlay size using the modified width and height + from decimate and scaling calculations + */ + tmp = STG_READ_REG(DACOverlaySize); + CLEAR_BITS_FRM_TO(0, 10); + CLEAR_BITS_FRM_TO(12, 31); + + if (ovlLinear) { + tmp |= + (ovlStride | ((ulHeight + 1) << 12) | + (((ulWidth / 8) - 1) << 23)); + } else { + tmp |= + (ovlStride | ((ulHeight + 1) << 12) | + (((ulWidth / 32) - 1) << 23)); + } + + STG_WRITE_REG(DACOverlaySize, tmp); + + /* Set Video Window Start */ + tmp = ((ulLeft << 16)) | (srcDest.ulDstY1); + STG_WRITE_REG(DACVidWinStart, tmp); + + /* Set Video Window End */ + tmp = ((ulRight) << 16) | (srcDest.ulDstY2); + STG_WRITE_REG(DACVidWinEnd, tmp); + + /* Finally set up the rest of the overlay regs in the order + done in the IMG driver + */ + tmp = STG_READ_REG(DACPixelFormat); + tmp = ((ulExcessPixels << 16) | tmp) & 0x7fffffff; + STG_WRITE_REG(DACPixelFormat, tmp); + + tmp = STG_READ_REG(DACHorizontalScal); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 17); + tmp |= ((ulhDecim << 16) | (ulDacXScale)); + STG_WRITE_REG(DACHorizontalScal, tmp); + + return 0; +} diff --git a/drivers/video/kyro/STG4000Ramdac.c b/drivers/video/kyro/STG4000Ramdac.c new file mode 100644 index 000000000000..e6ad037e4396 --- /dev/null +++ b/drivers/video/kyro/STG4000Ramdac.c @@ -0,0 +1,163 @@ +/* + * linux/drivers/video/kyro/STG4000Ramdac.c + * + * Copyright (C) 2002 STMicroelectronics + * + * 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/errno.h> +#include <linux/types.h> +#include <video/kyro.h> + +#include "STG4000Reg.h" +#include "STG4000Interface.h" + +static u32 STG_PIXEL_BUS_WIDTH = 128; /* 128 bit bus width */ +static u32 REF_CLOCK = 14318; + +int InitialiseRamdac(volatile STG4000REG __iomem * pSTGReg, + u32 displayDepth, + u32 displayWidth, + u32 displayHeight, + s32 HSyncPolarity, + s32 VSyncPolarity, u32 * pixelClock) +{ + u32 tmp = 0; + u32 F = 0, R = 0, P = 0; + u32 stride = 0; + u32 ulPdiv = 0; + u32 physicalPixelDepth = 0; + /* Make sure DAC is in Reset */ + tmp = STG_READ_REG(SoftwareReset); + + if (tmp & 0x1) { + CLEAR_BIT(1); + STG_WRITE_REG(SoftwareReset, tmp); + } + + /* Set Pixel Format */ + tmp = STG_READ_REG(DACPixelFormat); + CLEAR_BITS_FRM_TO(0, 2); + + /* Set LUT not used from 16bpp to 32 bpp ??? */ + CLEAR_BITS_FRM_TO(8, 9); + + switch (displayDepth) { + case 16: + { + physicalPixelDepth = 16; + tmp |= _16BPP; + break; + } + case 32: + { + /* Set for 32 bits per pixel */ + physicalPixelDepth = 32; + tmp |= _32BPP; + break; + } + default: + return -EINVAL; + } + + STG_WRITE_REG(DACPixelFormat, tmp); + + /* Workout Bus transfer bandwidth according to pixel format */ + ulPdiv = STG_PIXEL_BUS_WIDTH / physicalPixelDepth; + + /* Get Screen Stride in pixels */ + stride = displayWidth; + + /* Set Primary size info */ + tmp = STG_READ_REG(DACPrimSize); + CLEAR_BITS_FRM_TO(0, 10); + CLEAR_BITS_FRM_TO(12, 31); + tmp |= + ((((displayHeight - 1) << 12) | (((displayWidth / ulPdiv) - + 1) << 23)) + | (stride / ulPdiv)); + STG_WRITE_REG(DACPrimSize, tmp); + + + /* Set Pixel Clock */ + *pixelClock = ProgramClock(REF_CLOCK, *pixelClock, &F, &R, &P); + + /* Set DAC PLL Mode */ + tmp = STG_READ_REG(DACPLLMode); + CLEAR_BITS_FRM_TO(0, 15); + /* tmp |= ((P-1) | ((F-2) << 2) | ((R-2) << 11)); */ + tmp |= ((P) | ((F - 2) << 2) | ((R - 2) << 11)); + STG_WRITE_REG(DACPLLMode, tmp); + + /* Set Prim Address */ + tmp = STG_READ_REG(DACPrimAddress); + CLEAR_BITS_FRM_TO(0, 20); + CLEAR_BITS_FRM_TO(20, 31); + STG_WRITE_REG(DACPrimAddress, tmp); + + /* Set Cursor details with HW Cursor disabled */ + tmp = STG_READ_REG(DACCursorCtrl); + tmp &= ~SET_BIT(31); + STG_WRITE_REG(DACCursorCtrl, tmp); + + tmp = STG_READ_REG(DACCursorAddr); + CLEAR_BITS_FRM_TO(0, 20); + STG_WRITE_REG(DACCursorAddr, tmp); + + /* Set Video Window */ + tmp = STG_READ_REG(DACVidWinStart); + CLEAR_BITS_FRM_TO(0, 10); + CLEAR_BITS_FRM_TO(16, 26); + STG_WRITE_REG(DACVidWinStart, tmp); + + tmp = STG_READ_REG(DACVidWinEnd); + CLEAR_BITS_FRM_TO(0, 10); + CLEAR_BITS_FRM_TO(16, 26); + STG_WRITE_REG(DACVidWinEnd, tmp); + + /* Set DAC Border Color to default */ + tmp = STG_READ_REG(DACBorderColor); + CLEAR_BITS_FRM_TO(0, 23); + STG_WRITE_REG(DACBorderColor, tmp); + + /* Set Graphics and Overlay Burst Control */ + STG_WRITE_REG(DACBurstCtrl, 0x0404); + + /* Set CRC Trigger to default */ + tmp = STG_READ_REG(DACCrcTrigger); + CLEAR_BIT(0); + STG_WRITE_REG(DACCrcTrigger, tmp); + + /* Set Video Port Control to default */ + tmp = STG_READ_REG(DigVidPortCtrl); + CLEAR_BIT(8); + CLEAR_BITS_FRM_TO(16, 27); + CLEAR_BITS_FRM_TO(1, 3); + CLEAR_BITS_FRM_TO(10, 11); + STG_WRITE_REG(DigVidPortCtrl, tmp); + + return 0; +} + +/* Ramdac control, turning output to the screen on and off */ +void DisableRamdacOutput(volatile STG4000REG __iomem * pSTGReg) +{ + u32 tmp; + + /* Disable DAC for Graphics Stream Control */ + tmp = (STG_READ_REG(DACStreamCtrl)) & ~SET_BIT(0); + STG_WRITE_REG(DACStreamCtrl, tmp); +} + +void EnableRamdacOutput(volatile STG4000REG __iomem * pSTGReg) +{ + u32 tmp; + + /* Enable DAC for Graphics Stream Control */ + tmp = (STG_READ_REG(DACStreamCtrl)) | SET_BIT(0); + STG_WRITE_REG(DACStreamCtrl, tmp); +} diff --git a/drivers/video/kyro/STG4000Reg.h b/drivers/video/kyro/STG4000Reg.h new file mode 100644 index 000000000000..244549e61368 --- /dev/null +++ b/drivers/video/kyro/STG4000Reg.h @@ -0,0 +1,283 @@ +/* + * linux/drivers/video/kyro/STG4000Reg.h + * + * Copyright (C) 2002 STMicroelectronics + * + * 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 _STG4000REG_H +#define _STG4000REG_H + +#define DWFILL unsigned long :32 +#define WFILL unsigned short :16 + +/* + * Macros that access memory mapped card registers in PCI space + * Add an appropraite section for your OS or processor architecture. + */ +#if defined(__KERNEL__) +#include <asm/page.h> +#include <asm/io.h> +#define STG_WRITE_REG(reg,data) (writel(data,&pSTGReg->reg)) +#define STG_READ_REG(reg) (readl(&pSTGReg->reg)) +#else +#define STG_WRITE_REG(reg,data) (pSTGReg->reg = data) +#define STG_READ_REG(reg) (pSTGReg->reg) +#endif /* __KERNEL__ */ + +#define SET_BIT(n) (1<<(n)) +#define CLEAR_BIT(n) (tmp &= ~(1<<n)) +#define CLEAR_BITS_FRM_TO(frm, to) \ +{\ +int i; \ + for(i = frm; i<= to; i++) \ + { \ + tmp &= ~(1<<i); \ + } \ +} + +#define CLEAR_BIT_2(n) (usTemp &= ~(1<<n)) +#define CLEAR_BITS_FRM_TO_2(frm, to) \ +{\ +int i; \ + for(i = frm; i<= to; i++) \ + { \ + usTemp &= ~(1<<i); \ + } \ +} + +/* LUT select */ +typedef enum _LUT_USES { + NO_LUT = 0, RESERVED, GRAPHICS, OVERLAY +} LUT_USES; + +/* Primary surface pixel format select */ +typedef enum _PIXEL_FORMAT { + _8BPP = 0, _15BPP, _16BPP, _24BPP, _32BPP +} PIXEL_FORMAT; + +/* Overlay blending mode select */ +typedef enum _BLEND_MODE { + GRAPHICS_MODE = 0, COLOR_KEY, PER_PIXEL_ALPHA, GLOBAL_ALPHA, + CK_PIXEL_ALPHA, CK_GLOBAL_ALPHA +} OVRL_BLEND_MODE; + +/* Overlay Pixel format select */ +typedef enum _OVRL_PIX_FORMAT { + UYVY, VYUY, YUYV, YVYU +} OVRL_PIX_FORMAT; + +/* Register Table */ +typedef struct { + /* 0h */ + volatile unsigned long Thread0Enable; /* 0x0000 */ + volatile unsigned long Thread1Enable; /* 0x0004 */ + volatile unsigned long Thread0Recover; /* 0x0008 */ + volatile unsigned long Thread1Recover; /* 0x000C */ + volatile unsigned long Thread0Step; /* 0x0010 */ + volatile unsigned long Thread1Step; /* 0x0014 */ + volatile unsigned long VideoInStatus; /* 0x0018 */ + volatile unsigned long Core2InSignStart; /* 0x001C */ + volatile unsigned long Core1ResetVector; /* 0x0020 */ + volatile unsigned long Core1ROMOffset; /* 0x0024 */ + volatile unsigned long Core1ArbiterPriority; /* 0x0028 */ + volatile unsigned long VideoInControl; /* 0x002C */ + volatile unsigned long VideoInReg0CtrlA; /* 0x0030 */ + volatile unsigned long VideoInReg0CtrlB; /* 0x0034 */ + volatile unsigned long VideoInReg1CtrlA; /* 0x0038 */ + volatile unsigned long VideoInReg1CtrlB; /* 0x003C */ + volatile unsigned long Thread0Kicker; /* 0x0040 */ + volatile unsigned long Core2InputSign; /* 0x0044 */ + volatile unsigned long Thread0ProgCtr; /* 0x0048 */ + volatile unsigned long Thread1ProgCtr; /* 0x004C */ + volatile unsigned long Thread1Kicker; /* 0x0050 */ + volatile unsigned long GPRegister1; /* 0x0054 */ + volatile unsigned long GPRegister2; /* 0x0058 */ + volatile unsigned long GPRegister3; /* 0x005C */ + volatile unsigned long GPRegister4; /* 0x0060 */ + volatile unsigned long SerialIntA; /* 0x0064 */ + + volatile unsigned long Fill0[6]; /* GAP 0x0068 - 0x007C */ + + volatile unsigned long SoftwareReset; /* 0x0080 */ + volatile unsigned long SerialIntB; /* 0x0084 */ + + volatile unsigned long Fill1[37]; /* GAP 0x0088 - 0x011C */ + + volatile unsigned long ROMELQV; /* 0x011C */ + volatile unsigned long WLWH; /* 0x0120 */ + volatile unsigned long ROMELWL; /* 0x0124 */ + + volatile unsigned long dwFill_1; /* GAP 0x0128 */ + + volatile unsigned long IntStatus; /* 0x012C */ + volatile unsigned long IntMask; /* 0x0130 */ + volatile unsigned long IntClear; /* 0x0134 */ + + volatile unsigned long Fill2[6]; /* GAP 0x0138 - 0x014C */ + + volatile unsigned long ROMGPIOA; /* 0x0150 */ + volatile unsigned long ROMGPIOB; /* 0x0154 */ + volatile unsigned long ROMGPIOC; /* 0x0158 */ + volatile unsigned long ROMGPIOD; /* 0x015C */ + + volatile unsigned long Fill3[2]; /* GAP 0x0160 - 0x0168 */ + + volatile unsigned long AGPIntID; /* 0x0168 */ + volatile unsigned long AGPIntClassCode; /* 0x016C */ + volatile unsigned long AGPIntBIST; /* 0x0170 */ + volatile unsigned long AGPIntSSID; /* 0x0174 */ + volatile unsigned long AGPIntPMCSR; /* 0x0178 */ + volatile unsigned long VGAFrameBufBase; /* 0x017C */ + volatile unsigned long VGANotify; /* 0x0180 */ + volatile unsigned long DACPLLMode; /* 0x0184 */ + volatile unsigned long Core1VideoClockDiv; /* 0x0188 */ + volatile unsigned long AGPIntStat; /* 0x018C */ + + /* + volatile unsigned long Fill4[0x0400/4 - 0x0190/4]; //GAP 0x0190 - 0x0400 + volatile unsigned long Fill5[0x05FC/4 - 0x0400/4]; //GAP 0x0400 - 0x05FC Fog Table + volatile unsigned long Fill6[0x0604/4 - 0x0600/4]; //GAP 0x0600 - 0x0604 + volatile unsigned long Fill7[0x0680/4 - 0x0608/4]; //GAP 0x0608 - 0x0680 + volatile unsigned long Fill8[0x07FC/4 - 0x0684/4]; //GAP 0x0684 - 0x07FC + */ + volatile unsigned long Fill4[412]; /* 0x0190 - 0x07FC */ + + volatile unsigned long TACtrlStreamBase; /* 0x0800 */ + volatile unsigned long TAObjDataBase; /* 0x0804 */ + volatile unsigned long TAPtrDataBase; /* 0x0808 */ + volatile unsigned long TARegionDataBase; /* 0x080C */ + volatile unsigned long TATailPtrBase; /* 0x0810 */ + volatile unsigned long TAPtrRegionSize; /* 0x0814 */ + volatile unsigned long TAConfiguration; /* 0x0818 */ + volatile unsigned long TAObjDataStartAddr; /* 0x081C */ + volatile unsigned long TAObjDataEndAddr; /* 0x0820 */ + volatile unsigned long TAXScreenClip; /* 0x0824 */ + volatile unsigned long TAYScreenClip; /* 0x0828 */ + volatile unsigned long TARHWClamp; /* 0x082C */ + volatile unsigned long TARHWCompare; /* 0x0830 */ + volatile unsigned long TAStart; /* 0x0834 */ + volatile unsigned long TAObjReStart; /* 0x0838 */ + volatile unsigned long TAPtrReStart; /* 0x083C */ + volatile unsigned long TAStatus1; /* 0x0840 */ + volatile unsigned long TAStatus2; /* 0x0844 */ + volatile unsigned long TAIntStatus; /* 0x0848 */ + volatile unsigned long TAIntMask; /* 0x084C */ + + volatile unsigned long Fill5[235]; /* GAP 0x0850 - 0x0BF8 */ + + volatile unsigned long TextureAddrThresh; /* 0x0BFC */ + volatile unsigned long Core1Translation; /* 0x0C00 */ + volatile unsigned long TextureAddrReMap; /* 0x0C04 */ + volatile unsigned long RenderOutAGPRemap; /* 0x0C08 */ + volatile unsigned long _3DRegionReadTrans; /* 0x0C0C */ + volatile unsigned long _3DPtrReadTrans; /* 0x0C10 */ + volatile unsigned long _3DParamReadTrans; /* 0x0C14 */ + volatile unsigned long _3DRegionReadThresh; /* 0x0C18 */ + volatile unsigned long _3DPtrReadThresh; /* 0x0C1C */ + volatile unsigned long _3DParamReadThresh; /* 0x0C20 */ + volatile unsigned long _3DRegionReadAGPRemap; /* 0x0C24 */ + volatile unsigned long _3DPtrReadAGPRemap; /* 0x0C28 */ + volatile unsigned long _3DParamReadAGPRemap; /* 0x0C2C */ + volatile unsigned long ZBufferAGPRemap; /* 0x0C30 */ + volatile unsigned long TAIndexAGPRemap; /* 0x0C34 */ + volatile unsigned long TAVertexAGPRemap; /* 0x0C38 */ + volatile unsigned long TAUVAddrTrans; /* 0x0C3C */ + volatile unsigned long TATailPtrCacheTrans; /* 0x0C40 */ + volatile unsigned long TAParamWriteTrans; /* 0x0C44 */ + volatile unsigned long TAPtrWriteTrans; /* 0x0C48 */ + volatile unsigned long TAParamWriteThresh; /* 0x0C4C */ + volatile unsigned long TAPtrWriteThresh; /* 0x0C50 */ + volatile unsigned long TATailPtrCacheAGPRe; /* 0x0C54 */ + volatile unsigned long TAParamWriteAGPRe; /* 0x0C58 */ + volatile unsigned long TAPtrWriteAGPRe; /* 0x0C5C */ + volatile unsigned long SDRAMArbiterConf; /* 0x0C60 */ + volatile unsigned long SDRAMConf0; /* 0x0C64 */ + volatile unsigned long SDRAMConf1; /* 0x0C68 */ + volatile unsigned long SDRAMConf2; /* 0x0C6C */ + volatile unsigned long SDRAMRefresh; /* 0x0C70 */ + volatile unsigned long SDRAMPowerStat; /* 0x0C74 */ + + volatile unsigned long Fill6[2]; /* GAP 0x0C78 - 0x0C7C */ + + volatile unsigned long RAMBistData; /* 0x0C80 */ + volatile unsigned long RAMBistCtrl; /* 0x0C84 */ + volatile unsigned long FIFOBistKey; /* 0x0C88 */ + volatile unsigned long RAMBistResult; /* 0x0C8C */ + volatile unsigned long FIFOBistResult; /* 0x0C90 */ + + /* + volatile unsigned long Fill11[0x0CBC/4 - 0x0C94/4]; //GAP 0x0C94 - 0x0CBC + volatile unsigned long Fill12[0x0CD0/4 - 0x0CC0/4]; //GAP 0x0CC0 - 0x0CD0 3DRegisters + */ + + volatile unsigned long Fill7[16]; /* 0x0c94 - 0x0cd0 */ + + volatile unsigned long SDRAMAddrSign; /* 0x0CD4 */ + volatile unsigned long SDRAMDataSign; /* 0x0CD8 */ + volatile unsigned long SDRAMSignConf; /* 0x0CDC */ + + /* DWFILL; //GAP 0x0CE0 */ + volatile unsigned long dwFill_2; + + volatile unsigned long ISPSignature; /* 0x0CE4 */ + + volatile unsigned long Fill8[454]; /*GAP 0x0CE8 - 0x13FC */ + + volatile unsigned long DACPrimAddress; /* 0x1400 */ + volatile unsigned long DACPrimSize; /* 0x1404 */ + volatile unsigned long DACCursorAddr; /* 0x1408 */ + volatile unsigned long DACCursorCtrl; /* 0x140C */ + volatile unsigned long DACOverlayAddr; /* 0x1410 */ + volatile unsigned long DACOverlayUAddr; /* 0x1414 */ + volatile unsigned long DACOverlayVAddr; /* 0x1418 */ + volatile unsigned long DACOverlaySize; /* 0x141C */ + volatile unsigned long DACOverlayVtDec; /* 0x1420 */ + + volatile unsigned long Fill9[9]; /* GAP 0x1424 - 0x1444 */ + + volatile unsigned long DACVerticalScal; /* 0x1448 */ + volatile unsigned long DACPixelFormat; /* 0x144C */ + volatile unsigned long DACHorizontalScal; /* 0x1450 */ + volatile unsigned long DACVidWinStart; /* 0x1454 */ + volatile unsigned long DACVidWinEnd; /* 0x1458 */ + volatile unsigned long DACBlendCtrl; /* 0x145C */ + volatile unsigned long DACHorTim1; /* 0x1460 */ + volatile unsigned long DACHorTim2; /* 0x1464 */ + volatile unsigned long DACHorTim3; /* 0x1468 */ + volatile unsigned long DACVerTim1; /* 0x146C */ + volatile unsigned long DACVerTim2; /* 0x1470 */ + volatile unsigned long DACVerTim3; /* 0x1474 */ + volatile unsigned long DACBorderColor; /* 0x1478 */ + volatile unsigned long DACSyncCtrl; /* 0x147C */ + volatile unsigned long DACStreamCtrl; /* 0x1480 */ + volatile unsigned long DACLUTAddress; /* 0x1484 */ + volatile unsigned long DACLUTData; /* 0x1488 */ + volatile unsigned long DACBurstCtrl; /* 0x148C */ + volatile unsigned long DACCrcTrigger; /* 0x1490 */ + volatile unsigned long DACCrcDone; /* 0x1494 */ + volatile unsigned long DACCrcResult1; /* 0x1498 */ + volatile unsigned long DACCrcResult2; /* 0x149C */ + volatile unsigned long DACLinecount; /* 0x14A0 */ + + volatile unsigned long Fill10[151]; /*GAP 0x14A4 - 0x16FC */ + + volatile unsigned long DigVidPortCtrl; /* 0x1700 */ + volatile unsigned long DigVidPortStat; /* 0x1704 */ + + /* + volatile unsigned long Fill11[0x1FFC/4 - 0x1708/4]; //GAP 0x1708 - 0x1FFC + volatile unsigned long Fill17[0x3000/4 - 0x2FFC/4]; //GAP 0x2000 - 0x2FFC ALUT + */ + + volatile unsigned long Fill11[1598]; + + /* DWFILL; //GAP 0x3000 ALUT 256MB offset */ + volatile unsigned long Fill_3; + +} STG4000REG; + +#endif /* _STG4000REG_H */ diff --git a/drivers/video/kyro/STG4000VTG.c b/drivers/video/kyro/STG4000VTG.c new file mode 100644 index 000000000000..3690b04190af --- /dev/null +++ b/drivers/video/kyro/STG4000VTG.c @@ -0,0 +1,170 @@ +/* + * linux/drivers/video/kyro/STG4000VTG.c + * + * Copyright (C) 2002 STMicroelectronics + * + * 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/types.h> +#include <video/kyro.h> + +#include "STG4000Reg.h" +#include "STG4000Interface.h" + +void DisableVGA(volatile STG4000REG __iomem *pSTGReg) +{ + u32 tmp; + volatile u32 count, i; + + /* Reset the VGA registers */ + tmp = STG_READ_REG(SoftwareReset); + CLEAR_BIT(8); + STG_WRITE_REG(SoftwareReset, tmp); + + /* Just for Delay */ + for (i = 0; i < 1000; i++) { + count++; + } + + /* Pull-out the VGA registers from reset */ + tmp = STG_READ_REG(SoftwareReset); + tmp |= SET_BIT(8); + STG_WRITE_REG(SoftwareReset, tmp); +} + +void StopVTG(volatile STG4000REG __iomem *pSTGReg) +{ + u32 tmp = 0; + + /* Stop Ver and Hor Sync Generator */ + tmp = (STG_READ_REG(DACSyncCtrl)) | SET_BIT(0) | SET_BIT(2); + CLEAR_BIT(31); + STG_WRITE_REG(DACSyncCtrl, tmp); +} + +void StartVTG(volatile STG4000REG __iomem *pSTGReg) +{ + u32 tmp = 0; + + /* Start Ver and Hor Sync Generator */ + tmp = ((STG_READ_REG(DACSyncCtrl)) | SET_BIT(31)); + CLEAR_BIT(0); + CLEAR_BIT(2); + STG_WRITE_REG(DACSyncCtrl, tmp); +} + +void SetupVTG(volatile STG4000REG __iomem *pSTGReg, + const struct kyrofb_info * pTiming) +{ + u32 tmp = 0; + u32 margins = 0; + u32 ulBorder; + u32 xRes = pTiming->XRES; + u32 yRes = pTiming->YRES; + + /* Horizontal */ + u32 HAddrTime, HRightBorder, HLeftBorder; + u32 HBackPorcStrt, HFrontPorchStrt, HTotal, + HLeftBorderStrt, HRightBorderStrt, HDisplayStrt; + + /* Vertical */ + u32 VDisplayStrt, VBottomBorder, VTopBorder; + u32 VBackPorchStrt, VTotal, VTopBorderStrt, + VFrontPorchStrt, VBottomBorderStrt, VAddrTime; + + /* Need to calculate the right border */ + if ((xRes == 640) && (yRes == 480)) { + if ((pTiming->VFREQ == 60) || (pTiming->VFREQ == 72)) { + margins = 8; + } + } + + /* Work out the Border */ + ulBorder = + (pTiming->HTot - + (pTiming->HST + (pTiming->HBP - margins) + xRes + + (pTiming->HFP - margins))) >> 1; + + /* Border the same for Vertical and Horizontal */ + VBottomBorder = HLeftBorder = VTopBorder = HRightBorder = ulBorder; + + /************ Get Timing values for Horizontal ******************/ + HAddrTime = xRes; + HBackPorcStrt = pTiming->HST; + HTotal = pTiming->HTot; + HDisplayStrt = + pTiming->HST + (pTiming->HBP - margins) + HLeftBorder; + HLeftBorderStrt = HDisplayStrt - HLeftBorder; + HFrontPorchStrt = + pTiming->HST + (pTiming->HBP - margins) + HLeftBorder + + HAddrTime + HRightBorder; + HRightBorderStrt = HFrontPorchStrt - HRightBorder; + + /************ Get Timing values for Vertical ******************/ + VAddrTime = yRes; + VBackPorchStrt = pTiming->VST; + VTotal = pTiming->VTot; + VDisplayStrt = + pTiming->VST + (pTiming->VBP - margins) + VTopBorder; + VTopBorderStrt = VDisplayStrt - VTopBorder; + VFrontPorchStrt = + pTiming->VST + (pTiming->VBP - margins) + VTopBorder + + VAddrTime + VBottomBorder; + VBottomBorderStrt = VFrontPorchStrt - VBottomBorder; + + /* Set Hor Timing 1, 2, 3 */ + tmp = STG_READ_REG(DACHorTim1); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 27); + tmp |= (HTotal) | (HBackPorcStrt << 16); + STG_WRITE_REG(DACHorTim1, tmp); + + tmp = STG_READ_REG(DACHorTim2); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 27); + tmp |= (HDisplayStrt << 16) | HLeftBorderStrt; + STG_WRITE_REG(DACHorTim2, tmp); + + tmp = STG_READ_REG(DACHorTim3); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 27); + tmp |= (HFrontPorchStrt << 16) | HRightBorderStrt; + STG_WRITE_REG(DACHorTim3, tmp); + + /* Set Ver Timing 1, 2, 3 */ + tmp = STG_READ_REG(DACVerTim1); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 27); + tmp |= (VBackPorchStrt << 16) | (VTotal); + STG_WRITE_REG(DACVerTim1, tmp); + + tmp = STG_READ_REG(DACVerTim2); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 27); + tmp |= (VDisplayStrt << 16) | VTopBorderStrt; + STG_WRITE_REG(DACVerTim2, tmp); + + tmp = STG_READ_REG(DACVerTim3); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 27); + tmp |= (VFrontPorchStrt << 16) | VBottomBorderStrt; + STG_WRITE_REG(DACVerTim3, tmp); + + /* Set Verical and Horizontal Polarity */ + tmp = STG_READ_REG(DACSyncCtrl) | SET_BIT(3) | SET_BIT(1); + + if ((pTiming->HSP > 0) && (pTiming->VSP < 0)) { /* +hsync -vsync */ + tmp &= ~0x8; + } else if ((pTiming->HSP < 0) && (pTiming->VSP > 0)) { /* -hsync +vsync */ + tmp &= ~0x2; + } else if ((pTiming->HSP < 0) && (pTiming->VSP < 0)) { /* -hsync -vsync */ + tmp &= ~0xA; + } else if ((pTiming->HSP > 0) && (pTiming->VSP > 0)) { /* +hsync -vsync */ + tmp &= ~0x0; + } + + STG_WRITE_REG(DACSyncCtrl, tmp); +} diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c new file mode 100644 index 000000000000..d8bac9e97842 --- /dev/null +++ b/drivers/video/kyro/fbdev.c @@ -0,0 +1,820 @@ +/* + * linux/drivers/video/kyro/fbdev.c + * + * Copyright (C) 2002 STMicroelectronics + * Copyright (C) 2003, 2004 Paul Mundt + * + * 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/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/tty.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/ioctl.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include <video/kyro.h> + +#include "STG4000Reg.h" +#include "STG4000Interface.h" + +/* + * PCI Definitions + */ +#define PCI_VENDOR_ID_ST 0x104a +#define PCI_DEVICE_ID_STG4000 0x0010 + +#define KHZ2PICOS(a) (1000000000UL/(a)) + +/****************************************************************************/ +static struct fb_fix_screeninfo kyro_fix __devinitdata = { + .id = "ST Kyro", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .accel = FB_ACCEL_NONE, +}; + +static struct fb_var_screeninfo kyro_var __devinitdata = { + /* 640x480, 16bpp @ 60 Hz */ + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 480, + .bits_per_pixel = 16, + .red = { 11, 5, 0 }, + .green = { 5, 6, 0 }, + .blue = { 0, 5, 0 }, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .pixclock = KHZ2PICOS(25175), + .left_margin = 48, + .right_margin = 16, + .upper_margin = 33, + .lower_margin = 10, + .hsync_len = 96, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct kyrofb_info *currentpar; + +typedef struct { + STG4000REG __iomem *pSTGReg; /* Virtual address of PCI register region */ + u32 ulNextFreeVidMem; /* Offset from start of vid mem to next free region */ + u32 ulOverlayOffset; /* Offset from start of vid mem to overlay */ + u32 ulOverlayStride; /* Interleaved YUV and 422 mode Y stride */ + u32 ulOverlayUVStride; /* 422 mode U & V stride */ +} device_info_t; + +/* global graphics card info structure (one per card) */ +static device_info_t deviceInfo; + +static char *mode_option __devinitdata = NULL; +static int nopan __devinitdata = 0; +static int nowrap __devinitdata = 1; +#ifdef CONFIG_MTRR +static int nomtrr __devinitdata = 0; +#endif + +/* PCI driver prototypes */ +static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +static void kyrofb_remove(struct pci_dev *pdev); + +static struct fb_videomode kyro_modedb[] __devinitdata = { + { + /* 640x350 @ 85Hz */ + NULL, 85, 640, 350, KHZ2PICOS(31500), + 96, 32, 60, 32, 64, 3, + FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 640x400 @ 85Hz */ + NULL, 85, 640, 400, KHZ2PICOS(31500), + 96, 32, 41, 1, 64, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 720x400 @ 85Hz */ + NULL, 85, 720, 400, KHZ2PICOS(35500), + 108, 36, 42, 1, 72, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 60Hz */ + NULL, 60, 640, 480, KHZ2PICOS(25175), + 48, 16, 33, 10, 96, 2, + 0, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 72Hz */ + NULL, 72, 640, 480, KHZ2PICOS(31500), + 128, 24, 28, 9, 40, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 75Hz */ + NULL, 75, 640, 480, KHZ2PICOS(31500), + 120, 16, 16, 1, 64, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 85Hz */ + NULL, 85, 640, 480, KHZ2PICOS(36000), + 80, 56, 25, 1, 56, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 56Hz */ + NULL, 56, 800, 600, KHZ2PICOS(36000), + 128, 24, 22, 1, 72, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 60Hz */ + NULL, 60, 800, 600, KHZ2PICOS(40000), + 88, 40, 23, 1, 128, 4, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 72Hz */ + NULL, 72, 800, 600, KHZ2PICOS(50000), + 64, 56, 23, 37, 120, 6, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 75Hz */ + NULL, 75, 800, 600, KHZ2PICOS(49500), + 160, 16, 21, 1, 80, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 85Hz */ + NULL, 85, 800, 600, KHZ2PICOS(56250), + 152, 32, 27, 1, 64, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 60Hz */ + NULL, 60, 1024, 768, KHZ2PICOS(65000), + 160, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 70Hz */ + NULL, 70, 1024, 768, KHZ2PICOS(75000), + 144, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 75Hz */ + NULL, 75, 1024, 768, KHZ2PICOS(78750), + 176, 16, 28, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 85Hz */ + NULL, 85, 1024, 768, KHZ2PICOS(94500), + 208, 48, 36, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 75Hz */ + NULL, 75, 1152, 864, KHZ2PICOS(108000), + 256, 64, 32, 1, 128, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1280x960 @ 60Hz */ + NULL, 60, 1280, 960, KHZ2PICOS(108000), + 312, 96, 36, 1, 112, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1280x960 @ 85Hz */ + NULL, 85, 1280, 960, KHZ2PICOS(148500), + 224, 64, 47, 1, 160, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 60Hz */ + NULL, 60, 1280, 1024, KHZ2PICOS(108000), + 248, 48, 38, 1, 112, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 75Hz */ + NULL, 75, 1280, 1024, KHZ2PICOS(135000), + 248, 16, 38, 1, 144, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 85Hz */ + NULL, 85, 1280, 1024, KHZ2PICOS(157500), + 224, 64, 44, 1, 160, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 60Hz */ + NULL, 60, 1600, 1200, KHZ2PICOS(162000), + 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 65Hz */ + NULL, 65, 1600, 1200, KHZ2PICOS(175500), + 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 70Hz */ + NULL, 70, 1600, 1200, KHZ2PICOS(189000), + 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 75Hz */ + NULL, 75, 1600, 1200, KHZ2PICOS(202500), + 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 85Hz */ + NULL, 85, 1600, 1200, KHZ2PICOS(229500), + 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1792x1344 @ 60Hz */ + NULL, 60, 1792, 1344, KHZ2PICOS(204750), + 328, 128, 46, 1, 200, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1792x1344 @ 75Hz */ + NULL, 75, 1792, 1344, KHZ2PICOS(261000), + 352, 96, 69, 1, 216, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1856x1392 @ 60Hz */ + NULL, 60, 1856, 1392, KHZ2PICOS(218250), + 352, 96, 43, 1, 224, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1856x1392 @ 75Hz */ + NULL, 75, 1856, 1392, KHZ2PICOS(288000), + 352, 128, 104, 1, 224, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1920x1440 @ 60Hz */ + NULL, 60, 1920, 1440, KHZ2PICOS(234000), + 344, 128, 56, 1, 208, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1920x1440 @ 75Hz */ + NULL, 75, 1920, 1440, KHZ2PICOS(297000), + 352, 144, 56, 1, 224, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, +}; +#define NUM_TOTAL_MODES ARRAY_SIZE(kyro_modedb) + +/* + * This needs to be kept ordered corresponding to kyro_modedb. + */ +enum { + VMODE_640_350_85, + VMODE_640_400_85, + VMODE_720_400_85, + VMODE_640_480_60, + VMODE_640_480_72, + VMODE_640_480_75, + VMODE_640_480_85, + VMODE_800_600_56, + VMODE_800_600_60, + VMODE_800_600_72, + VMODE_800_600_75, + VMODE_800_600_85, + VMODE_1024_768_60, + VMODE_1024_768_70, + VMODE_1024_768_75, + VMODE_1024_768_85, + VMODE_1152_864_75, + VMODE_1280_960_60, + VMODE_1280_960_85, + VMODE_1280_1024_60, + VMODE_1280_1024_75, + VMODE_1280_1024_85, + VMODE_1600_1200_60, + VMODE_1600_1200_65, + VMODE_1600_1200_70, + VMODE_1600_1200_75, + VMODE_1600_1200_85, + VMODE_1792_1344_60, + VMODE_1792_1344_75, + VMODE_1856_1392_60, + VMODE_1856_1392_75, + VMODE_1920_1440_60, + VMODE_1920_1440_75, +}; + +/* Accessors */ +static int kyro_dev_video_mode_set(struct fb_info *info) +{ + struct kyrofb_info *par = (struct kyrofb_info *)info->par; + + /* Turn off display */ + StopVTG(deviceInfo.pSTGReg); + DisableRamdacOutput(deviceInfo.pSTGReg); + + /* Bring us out of VGA and into Hi-Res mode, if not already. */ + DisableVGA(deviceInfo.pSTGReg); + + if (InitialiseRamdac(deviceInfo.pSTGReg, + info->var.bits_per_pixel, + info->var.xres, info->var.yres, + par->HSP, par->VSP, &par->PIXCLK) < 0) + return -EINVAL; + + SetupVTG(deviceInfo.pSTGReg, par); + + ResetOverlayRegisters(deviceInfo.pSTGReg); + + /* Turn on display in new mode */ + EnableRamdacOutput(deviceInfo.pSTGReg); + StartVTG(deviceInfo.pSTGReg); + + deviceInfo.ulNextFreeVidMem = info->var.xres * info->var.yres * + info->var.bits_per_pixel; + deviceInfo.ulOverlayOffset = 0; + + return 0; +} + +static int kyro_dev_overlay_create(u32 ulWidth, + u32 ulHeight, int bLinear) +{ + u32 offset; + u32 stride, uvStride; + + if (deviceInfo.ulOverlayOffset != 0) + /* + * Can only create one overlay without resetting the card or + * changing display mode + */ + return -EINVAL; + + ResetOverlayRegisters(deviceInfo.pSTGReg); + + /* Overlays are addressed in multiples of 16bytes or 32bytes, so make + * sure the start offset is on an appropriate boundary. + */ + offset = deviceInfo.ulNextFreeVidMem; + if ((offset & 0x1f) != 0) { + offset = (offset + 32L) & 0xffffffE0L; + } + + if (CreateOverlaySurface(deviceInfo.pSTGReg, ulWidth, ulHeight, + bLinear, offset, &stride, &uvStride) < 0) + return -EINVAL; + + deviceInfo.ulOverlayOffset = offset; + deviceInfo.ulOverlayStride = stride; + deviceInfo.ulOverlayUVStride = uvStride; + deviceInfo.ulNextFreeVidMem = offset + (ulHeight * stride) + (ulHeight * 2 * uvStride); + + SetOverlayBlendMode(deviceInfo.pSTGReg, GLOBAL_ALPHA, 0xf, 0x0); + + return 0; +} + +static int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 ulHeight) +{ + if (deviceInfo.ulOverlayOffset == 0) + /* probably haven't called CreateOverlay yet */ + return -EINVAL; + + /* Stop Ramdac Output */ + DisableRamdacOutput(deviceInfo.pSTGReg); + + SetOverlayViewPort(deviceInfo.pSTGReg, + x, y, x + ulWidth - 1, y + ulHeight - 1); + + EnableOverlayPlane(deviceInfo.pSTGReg); + /* Start Ramdac Output */ + EnableRamdacOutput(deviceInfo.pSTGReg); + + return 0; +} + +static inline unsigned long get_line_length(int x, int bpp) +{ + return (unsigned long)((((x*bpp)+31)&~31) >> 3); +} + +static int kyrofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct kyrofb_info *par = (struct kyrofb_info *)info->par; + + if (var->bits_per_pixel != 16 && var->bits_per_pixel != 32) { + printk(KERN_WARNING "kyrofb: depth not supported: %u\n", var->bits_per_pixel); + return -EINVAL; + } + + switch (var->bits_per_pixel) { + case 16: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.length = 5; + break; + case 32: + var->transp.offset = 24; + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 8; + break; + } + + /* Height/Width of picture in mm */ + var->height = var->width = -1; + + /* Timing information. All values are in picoseconds */ + + /* par->PIXCLK is in 100Hz units. Convert to picoseconds - + * ensuring we do not exceed 32 bit precision + */ + /* + * XXX: Enabling this really screws over the pixclock value when we + * read it back with fbset. As such, leaving this commented out appears + * to do the right thing (at least for now) .. bearing in mind that we + * have infact already done the KHZ2PICOS conversion in both the modedb + * and kyro_var. -- PFM. + */ +// var->pixclock = 1000000000 / (par->PIXCLK / 10); + + /* the header file claims we should use picoseconds + * - nobody else does though, the all use pixels and lines + * of h and v sizes. Both options here. + */ + + /* + * If we're being called by __fb_try_mode(), then we don't want to + * override any of the var settings that we've already parsed + * from our modedb. -- PFM. + */ + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST) + return 0; + + var->left_margin = par->HBP; + var->hsync_len = par->HST; + var->right_margin = par->HFP; + + var->upper_margin = par->VBP; + var->vsync_len = par->VST; + var->lower_margin = par->VFP; + + if (par->HSP == 1) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (par->VSP == 1) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + + return 0; +} + +static int kyrofb_set_par(struct fb_info *info) +{ + struct kyrofb_info *par = (struct kyrofb_info *)info->par; + unsigned long lineclock; + unsigned long frameclock; + + /* Actual resolution */ + par->XRES = info->var.xres; + par->YRES = info->var.yres; + + /* pixel depth */ + par->PIXDEPTH = info->var.bits_per_pixel; + + /* Refresh rate */ + /* time for a line in ns */ + lineclock = (info->var.pixclock * (info->var.xres + + info->var.right_margin + + info->var.hsync_len + + info->var.left_margin)) / 1000; + + + /* time for a frame in ns (precision in 32bpp) */ + frameclock = lineclock * (info->var.yres + + info->var.lower_margin + + info->var.vsync_len + + info->var.upper_margin); + + /* Calculate refresh rate and horrizontal clocks */ + par->VFREQ = (1000000000 + (frameclock / 2)) / frameclock; + par->HCLK = (1000000000 + (lineclock / 2)) / lineclock; + par->PIXCLK = ((1000000000 + (info->var.pixclock / 2)) + / info->var.pixclock) * 10; + + /* calculate horizontal timings */ + par->HFP = info->var.right_margin; + par->HST = info->var.hsync_len; + par->HBP = info->var.left_margin; + par->HTot = par->XRES + par->HBP + par->HST + par->HFP; + + /* calculate vertical timings */ + par->VFP = info->var.lower_margin; + par->VST = info->var.vsync_len; + par->VBP = info->var.upper_margin; + par->VTot = par->YRES + par->VBP + par->VST + par->VFP; + + par->HSP = (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 1 : 0; + par->VSP = (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 1 : 0; + + kyro_dev_video_mode_set(info); + + /* length of a line in bytes */ + info->fix.line_length = get_line_length(par->XRES, par->PIXDEPTH); + info->fix.visual = FB_VISUAL_TRUECOLOR; + + return 0; +} + +static int kyrofb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, struct fb_info *info) +{ + if (regno > 255) + return 1; /* Invalid register */ + + if (regno < 16) { + switch (info->var.bits_per_pixel) { + case 16: + ((u16*)(info->pseudo_palette))[regno] = + (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 32: + red >>= 8; green >>= 8; blue >>= 8; transp >>= 8; + ((u32*)(info->pseudo_palette))[regno] = + (transp << 24) | (red << 16) | (green << 8) | blue; + break; + } + } + + return 0; +} + +#ifndef MODULE +static int __init kyrofb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ","))) { + if (!*this_opt) + continue; + if (strcmp(this_opt, "nopan") == 0) { + nopan = 1; + } else if (strcmp(this_opt, "nowrap") == 0) { + nowrap = 1; +#ifdef CONFIG_MTRR + } else if (strcmp(this_opt, "nomtrr") == 0) { + nomtrr = 1; +#endif + } else { + mode_option = this_opt; + } + } + + return 0; +} +#endif + +static int kyrofb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + struct fb_info *info) +{ + overlay_create ol_create; + overlay_viewport_set ol_viewport_set; + void __user *argp = (void __user *)arg; + + switch (cmd) { + case KYRO_IOCTL_OVERLAY_CREATE: + if (copy_from_user(&ol_create, argp, sizeof(overlay_create))) + return -EFAULT; + + if (kyro_dev_overlay_create(ol_create.ulWidth, + ol_create.ulHeight, 0) < 0) { + printk(KERN_ERR "Kyro FB: failed to create overlay surface.\n"); + + return -EINVAL; + } + break; + case KYRO_IOCTL_OVERLAY_VIEWPORT_SET: + if (copy_from_user(&ol_viewport_set, argp, + sizeof(overlay_viewport_set))) + return -EFAULT; + + if (kyro_dev_overlay_viewport_set(ol_viewport_set.xOrgin, + ol_viewport_set.yOrgin, + ol_viewport_set.xSize, + ol_viewport_set.ySize) != 0) + { + printk(KERN_ERR "Kyro FB: failed to create overlay viewport.\n"); + return -EINVAL; + } + break; + case KYRO_IOCTL_SET_VIDEO_MODE: + { + printk(KERN_ERR "Kyro FB: KYRO_IOCTL_SET_VIDEO_MODE is" + "obsolete, use the appropriate fb_ioctl()" + "command instead.\n"); + return -EINVAL; + } + break; + case KYRO_IOCTL_UVSTRIDE: + if (copy_to_user(argp, &deviceInfo.ulOverlayUVStride, sizeof(unsigned long))) + return -EFAULT; + break; + case KYRO_IOCTL_STRIDE: + if (copy_to_user(argp, &deviceInfo.ulOverlayStride, sizeof(unsigned long))) + return -EFAULT; + break; + case KYRO_IOCTL_OVERLAY_OFFSET: + if (copy_to_user(argp, &deviceInfo.ulOverlayOffset, sizeof(unsigned long))) + return -EFAULT; + break; + } + + return 0; +} + +static struct pci_device_id kyrofb_pci_tbl[] = { + { PCI_VENDOR_ID_ST, PCI_DEVICE_ID_STG4000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, kyrofb_pci_tbl); + +static struct pci_driver kyrofb_pci_driver = { + .name = "kyrofb", + .id_table = kyrofb_pci_tbl, + .probe = kyrofb_probe, + .remove = __devexit_p(kyrofb_remove), +}; + +static struct fb_ops kyrofb_ops = { + .owner = THIS_MODULE, + .fb_check_var = kyrofb_check_var, + .fb_set_par = kyrofb_set_par, + .fb_setcolreg = kyrofb_setcolreg, + .fb_ioctl = kyrofb_ioctl, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +static int __devinit kyrofb_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct fb_info *info; + unsigned long size; + int err; + + if ((err = pci_enable_device(pdev))) { + printk(KERN_WARNING "kyrofb: Can't enable pdev: %d\n", err); + return err; + } + + size = sizeof(struct fb_info) + sizeof(struct kyrofb_info) + 16 * sizeof(u32); + info = kmalloc(size, GFP_KERNEL); + if (!info) + return -ENOMEM; + + memset(info, 0, size); + + currentpar = (struct kyrofb_info *)(info + 1); + + kyro_fix.smem_start = pci_resource_start(pdev, 0); + kyro_fix.smem_len = pci_resource_len(pdev, 0); + kyro_fix.mmio_start = pci_resource_start(pdev, 1); + kyro_fix.mmio_len = pci_resource_len(pdev, 1); + + currentpar->regbase = deviceInfo.pSTGReg = + ioremap_nocache(kyro_fix.mmio_start, kyro_fix.mmio_len); + + info->screen_base = ioremap_nocache(kyro_fix.smem_start, + kyro_fix.smem_len); + +#ifdef CONFIG_MTRR + if (!nomtrr) + currentpar->mtrr_handle = + mtrr_add(kyro_fix.smem_start, + kyro_fix.smem_len, + MTRR_TYPE_WRCOMB, 1); +#endif + + kyro_fix.ypanstep = nopan ? 0 : 1; + kyro_fix.ywrapstep = nowrap ? 0 : 1; + + info->fbops = &kyrofb_ops; + info->fix = kyro_fix; + info->par = currentpar; + info->pseudo_palette = (void *)(currentpar + 1); + info->flags = FBINFO_DEFAULT; + + SetCoreClockPLL(deviceInfo.pSTGReg, pdev); + + deviceInfo.ulNextFreeVidMem = 0; + deviceInfo.ulOverlayOffset = 0; + + /* This should give a reasonable default video mode */ + if (!fb_find_mode(&info->var, info, mode_option, kyro_modedb, + NUM_TOTAL_MODES, &kyro_modedb[VMODE_1024_768_75], 32)) + info->var = kyro_var; + + fb_alloc_cmap(&info->cmap, 256, 0); + + kyrofb_set_par(info); + kyrofb_check_var(&info->var, info); + + size = get_line_length(info->var.xres_virtual, + info->var.bits_per_pixel); + size *= info->var.yres_virtual; + + fb_memset(info->screen_base, 0, size); + + info->device = &pdev->dev; + if (register_framebuffer(info) < 0) + goto out_unmap; + + printk("fb%d: %s frame buffer device, at %dx%d@%d using %ldk/%ldk of VRAM\n", + info->node, info->fix.id, info->var.xres, + info->var.yres, info->var.bits_per_pixel, size >> 10, + (unsigned long)info->fix.smem_len >> 10); + + pci_set_drvdata(pdev, info); + + return 0; + +out_unmap: + iounmap(currentpar->regbase); + iounmap(info->screen_base); + kfree(info); + + return -EINVAL; +} + +static void __devexit kyrofb_remove(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct kyrofb_info *par = (struct kyrofb_info *)info->par; + + /* Reset the board */ + StopVTG(deviceInfo.pSTGReg); + DisableRamdacOutput(deviceInfo.pSTGReg); + + /* Sync up the PLL */ + SetCoreClockPLL(deviceInfo.pSTGReg, pdev); + + deviceInfo.ulNextFreeVidMem = 0; + deviceInfo.ulOverlayOffset = 0; + + iounmap(info->screen_base); + iounmap(par->regbase); + +#ifdef CONFIG_MTRR + if (par->mtrr_handle) + mtrr_del(par->mtrr_handle, + info->fix.smem_start, + info->fix.smem_len); +#endif + + unregister_framebuffer(info); + pci_set_drvdata(pdev, NULL); + kfree(info); +} + +static int __init kyrofb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("kyrofb", &option)) + return -ENODEV; + kyrofb_setup(option); +#endif + return pci_register_driver(&kyrofb_pci_driver); +} + +static void __exit kyrofb_exit(void) +{ + pci_unregister_driver(&kyrofb_pci_driver); +} + +module_init(kyrofb_init); + +#ifdef MODULE +module_exit(kyrofb_exit); +#endif + +MODULE_AUTHOR("STMicroelectronics; Paul Mundt <lethal@linux-sh.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/leo.c b/drivers/video/leo.c new file mode 100644 index 000000000000..7e1e7fb168bd --- /dev/null +++ b/drivers/video/leo.c @@ -0,0 +1,666 @@ +/* leo.c: LEO frame buffer driver + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz) + * + * Driver layout based loosely on tgafb.c, see that file for credits. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <linux/mm.h> + +#include <asm/io.h> +#include <asm/sbus.h> +#include <asm/oplib.h> +#include <asm/fbio.h> + +#include "sbuslib.h" + +/* + * Local functions. + */ + +static int leo_setcolreg(unsigned, unsigned, unsigned, unsigned, + unsigned, struct fb_info *); +static int leo_blank(int, struct fb_info *); + +static int leo_mmap(struct fb_info *, struct file *, struct vm_area_struct *); +static int leo_ioctl(struct inode *, struct file *, unsigned int, + unsigned long, struct fb_info *); +static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *); + +/* + * Frame buffer operations + */ + +static struct fb_ops leo_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = leo_setcolreg, + .fb_blank = leo_blank, + .fb_pan_display = leo_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = leo_mmap, + .fb_ioctl = leo_ioctl, + .fb_cursor = soft_cursor, +}; + +#define LEO_OFF_LC_SS0_KRN 0x00200000UL +#define LEO_OFF_LC_SS0_USR 0x00201000UL +#define LEO_OFF_LC_SS1_KRN 0x01200000UL +#define LEO_OFF_LC_SS1_USR 0x01201000UL +#define LEO_OFF_LD_SS0 0x00400000UL +#define LEO_OFF_LD_SS1 0x01400000UL +#define LEO_OFF_LD_GBL 0x00401000UL +#define LEO_OFF_LX_KRN 0x00600000UL +#define LEO_OFF_LX_CURSOR 0x00601000UL +#define LEO_OFF_SS0 0x00800000UL +#define LEO_OFF_SS1 0x01800000UL +#define LEO_OFF_UNK 0x00602000UL +#define LEO_OFF_UNK2 0x00000000UL + +#define LEO_CUR_ENABLE 0x00000080 +#define LEO_CUR_UPDATE 0x00000030 +#define LEO_CUR_PROGRESS 0x00000006 +#define LEO_CUR_UPDATECMAP 0x00000003 + +#define LEO_CUR_TYPE_MASK 0x00000000 +#define LEO_CUR_TYPE_IMAGE 0x00000020 +#define LEO_CUR_TYPE_CMAP 0x00000050 + +struct leo_cursor { + u8 xxx0[16]; + volatile u32 cur_type; + volatile u32 cur_misc; + volatile u32 cur_cursxy; + volatile u32 cur_data; +}; + +#define LEO_KRN_TYPE_CLUT0 0x00001000 +#define LEO_KRN_TYPE_CLUT1 0x00001001 +#define LEO_KRN_TYPE_CLUT2 0x00001002 +#define LEO_KRN_TYPE_WID 0x00001003 +#define LEO_KRN_TYPE_UNK 0x00001006 +#define LEO_KRN_TYPE_VIDEO 0x00002003 +#define LEO_KRN_TYPE_CLUTDATA 0x00004000 +#define LEO_KRN_CSR_ENABLE 0x00000008 +#define LEO_KRN_CSR_PROGRESS 0x00000004 +#define LEO_KRN_CSR_UNK 0x00000002 +#define LEO_KRN_CSR_UNK2 0x00000001 + +struct leo_lx_krn { + volatile u32 krn_type; + volatile u32 krn_csr; + volatile u32 krn_value; +}; + +struct leo_lc_ss0_krn { + volatile u32 misc; + u8 xxx0[0x800-4]; + volatile u32 rev; +}; + +struct leo_lc_ss0_usr { + volatile u32 csr; + volatile u32 addrspace; + volatile u32 fontmsk; + volatile u32 fontt; + volatile u32 extent; + volatile u32 src; + u32 dst; + volatile u32 copy; + volatile u32 fill; +}; + +struct leo_lc_ss1_krn { + u8 unknown; +}; + +struct leo_lc_ss1_usr { + u8 unknown; +}; + +struct leo_ld { + u8 xxx0[0xe00]; + volatile u32 csr; + volatile u32 wid; + volatile u32 wmask; + volatile u32 widclip; + volatile u32 vclipmin; + volatile u32 vclipmax; + volatile u32 pickmin; /* SS1 only */ + volatile u32 pickmax; /* SS1 only */ + volatile u32 fg; + volatile u32 bg; + volatile u32 src; /* Copy/Scroll (SS0 only) */ + volatile u32 dst; /* Copy/Scroll/Fill (SS0 only) */ + volatile u32 extent; /* Copy/Scroll/Fill size (SS0 only) */ + u32 xxx1[3]; + volatile u32 setsem; /* SS1 only */ + volatile u32 clrsem; /* SS1 only */ + volatile u32 clrpick; /* SS1 only */ + volatile u32 clrdat; /* SS1 only */ + volatile u32 alpha; /* SS1 only */ + u8 xxx2[0x2c]; + volatile u32 winbg; + volatile u32 planemask; + volatile u32 rop; + volatile u32 z; + volatile u32 dczf; /* SS1 only */ + volatile u32 dczb; /* SS1 only */ + volatile u32 dcs; /* SS1 only */ + volatile u32 dczs; /* SS1 only */ + volatile u32 pickfb; /* SS1 only */ + volatile u32 pickbb; /* SS1 only */ + volatile u32 dcfc; /* SS1 only */ + volatile u32 forcecol; /* SS1 only */ + volatile u32 door[8]; /* SS1 only */ + volatile u32 pick[5]; /* SS1 only */ +}; + +#define LEO_SS1_MISC_ENABLE 0x00000001 +#define LEO_SS1_MISC_STEREO 0x00000002 +struct leo_ld_ss1 { + u8 xxx0[0xef4]; + volatile u32 ss1_misc; +}; + +struct leo_ld_gbl { + u8 unknown; +}; + +struct leo_par { + spinlock_t lock; + struct leo_lx_krn __iomem *lx_krn; + struct leo_lc_ss0_usr __iomem *lc_ss0_usr; + struct leo_ld_ss0 __iomem *ld_ss0; + struct leo_ld_ss1 __iomem *ld_ss1; + struct leo_cursor __iomem *cursor; + u32 extent; + u32 clut_data[256]; + + u32 flags; +#define LEO_FLAG_BLANKED 0x00000001 + + unsigned long physbase; + unsigned long fbsize; + + struct sbus_dev *sdev; + struct list_head list; +}; + +static void leo_wait(struct leo_lx_krn __iomem *lx_krn) +{ + int i; + + for (i = 0; + (sbus_readl(&lx_krn->krn_csr) & LEO_KRN_CSR_PROGRESS) && i < 300000; + i++) + udelay (1); /* Busy wait at most 0.3 sec */ + return; +} + +/** + * leo_setcolreg - Optional function. Sets a color register. + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @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. + * @info: frame buffer info structure + */ +static int leo_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct leo_par *par = (struct leo_par *) info->par; + struct leo_lx_krn __iomem *lx_krn = par->lx_krn; + unsigned long flags; + u32 val; + int i; + + if (regno >= 256) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + par->clut_data[regno] = red | (green << 8) | (blue << 16); + + spin_lock_irqsave(&par->lock, flags); + + leo_wait(lx_krn); + + sbus_writel(LEO_KRN_TYPE_CLUTDATA, &lx_krn->krn_type); + for (i = 0; i < 256; i++) + sbus_writel(par->clut_data[i], &lx_krn->krn_value); + sbus_writel(LEO_KRN_TYPE_CLUT0, &lx_krn->krn_type); + + val = sbus_readl(&lx_krn->krn_csr); + val |= (LEO_KRN_CSR_UNK | LEO_KRN_CSR_UNK2); + sbus_writel(val, &lx_krn->krn_csr); + + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +/** + * leo_blank - Optional function. Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + */ +static int leo_blank(int blank, struct fb_info *info) +{ + struct leo_par *par = (struct leo_par *) info->par; + struct leo_lx_krn __iomem *lx_krn = par->lx_krn; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&par->lock, flags); + + switch (blank) { + case FB_BLANK_UNBLANK: /* Unblanking */ + val = sbus_readl(&lx_krn->krn_csr); + val |= LEO_KRN_CSR_ENABLE; + sbus_writel(val, &lx_krn->krn_csr); + par->flags &= ~LEO_FLAG_BLANKED; + break; + + case FB_BLANK_NORMAL: /* Normal blanking */ + case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ + case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ + case FB_BLANK_POWERDOWN: /* Poweroff */ + val = sbus_readl(&lx_krn->krn_csr); + val &= ~LEO_KRN_CSR_ENABLE; + sbus_writel(val, &lx_krn->krn_csr); + par->flags |= LEO_FLAG_BLANKED; + break; + } + + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +static struct sbus_mmap_map leo_mmap_map[] = { + { + .voff = LEO_SS0_MAP, + .poff = LEO_OFF_SS0, + .size = 0x800000 + }, + { + .voff = LEO_LC_SS0_USR_MAP, + .poff = LEO_OFF_LC_SS0_USR, + .size = 0x1000 + }, + { + .voff = LEO_LD_SS0_MAP, + .poff = LEO_OFF_LD_SS0, + .size = 0x1000 + }, + { + .voff = LEO_LX_CURSOR_MAP, + .poff = LEO_OFF_LX_CURSOR, + .size = 0x1000 + }, + { + .voff = LEO_SS1_MAP, + .poff = LEO_OFF_SS1, + .size = 0x800000 + }, + { + .voff = LEO_LC_SS1_USR_MAP, + .poff = LEO_OFF_LC_SS1_USR, + .size = 0x1000 + }, + { + .voff = LEO_LD_SS1_MAP, + .poff = LEO_OFF_LD_SS1, + .size = 0x1000 + }, + { + .voff = LEO_UNK_MAP, + .poff = LEO_OFF_UNK, + .size = 0x1000 + }, + { + .voff = LEO_LX_KRN_MAP, + .poff = LEO_OFF_LX_KRN, + .size = 0x1000 + }, + { + .voff = LEO_LC_SS0_KRN_MAP, + .poff = LEO_OFF_LC_SS0_KRN, + .size = 0x1000 + }, + { + .voff = LEO_LC_SS1_KRN_MAP, + .poff = LEO_OFF_LC_SS1_KRN, + .size = 0x1000 + }, + { + .voff = LEO_LD_GBL_MAP, + .poff = LEO_OFF_LD_GBL, + .size = 0x1000 + }, + { + .voff = LEO_UNK2_MAP, + .poff = LEO_OFF_UNK2, + .size = 0x100000 + }, + { .size = 0 } +}; + +static int leo_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) +{ + struct leo_par *par = (struct leo_par *)info->par; + + return sbusfb_mmap_helper(leo_mmap_map, + par->physbase, par->fbsize, + par->sdev->reg_addrs[0].which_io, + vma); +} + +static int leo_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *info) +{ + struct leo_par *par = (struct leo_par *) info->par; + + return sbusfb_ioctl_helper(cmd, arg, info, + FBTYPE_SUNLEO, 32, par->fbsize); +} + +/* + * Initialisation + */ + +static void +leo_init_fix(struct fb_info *info) +{ + struct leo_par *par = (struct leo_par *)info->par; + + strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id)); + + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + + info->fix.line_length = 8192; + + info->fix.accel = FB_ACCEL_SUN_LEO; +} + +static void leo_wid_put(struct fb_info *info, struct fb_wid_list *wl) +{ + struct leo_par *par = (struct leo_par *) info->par; + struct leo_lx_krn __iomem *lx_krn = par->lx_krn; + struct fb_wid_item *wi; + unsigned long flags; + u32 val; + int i, j; + + spin_lock_irqsave(&par->lock, flags); + + leo_wait(lx_krn); + + for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) { + switch(wi->wi_type) { + case FB_WID_DBL_8: + j = (wi->wi_index & 0xf) + 0x40; + break; + + case FB_WID_DBL_24: + j = wi->wi_index & 0x3f; + break; + + default: + continue; + }; + sbus_writel(0x5800 + j, &lx_krn->krn_type); + sbus_writel(wi->wi_values[0], &lx_krn->krn_value); + } + sbus_writel(LEO_KRN_TYPE_WID, &lx_krn->krn_type); + + val = sbus_readl(&lx_krn->krn_csr); + val |= (LEO_KRN_CSR_UNK | LEO_KRN_CSR_UNK2); + sbus_writel(val, &lx_krn->krn_csr); + + spin_unlock_irqrestore(&par->lock, flags); +} + +static void leo_init_wids(struct fb_info *info) +{ + struct fb_wid_item wi; + struct fb_wid_list wl; + + wl.wl_count = 1; + wl.wl_list = &wi; + wi.wi_type = FB_WID_DBL_8; + wi.wi_index = 0; + wi.wi_values [0] = 0x2c0; + leo_wid_put(info, &wl); + wi.wi_index = 1; + wi.wi_values [0] = 0x30; + leo_wid_put(info, &wl); + wi.wi_index = 2; + wi.wi_values [0] = 0x20; + leo_wid_put(info, &wl); + wi.wi_type = FB_WID_DBL_24; + wi.wi_index = 1; + wi.wi_values [0] = 0x30; + leo_wid_put(info, &wl); + +} + +static void leo_switch_from_graph(struct fb_info *info) +{ + struct leo_par *par = (struct leo_par *) info->par; + struct leo_ld __iomem *ss = (struct leo_ld __iomem *) par->ld_ss0; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&par->lock, flags); + + par->extent = ((info->var.xres - 1) | + ((info->var.yres - 1) << 16)); + + sbus_writel(0xffffffff, &ss->wid); + sbus_writel(0xffff, &ss->wmask); + sbus_writel(0, &ss->vclipmin); + sbus_writel(par->extent, &ss->vclipmax); + sbus_writel(0, &ss->fg); + sbus_writel(0xff000000, &ss->planemask); + sbus_writel(0x310850, &ss->rop); + sbus_writel(0, &ss->widclip); + sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11), + &par->lc_ss0_usr->extent); + sbus_writel(4, &par->lc_ss0_usr->addrspace); + sbus_writel(0x80000000, &par->lc_ss0_usr->fill); + sbus_writel(0, &par->lc_ss0_usr->fontt); + do { + val = sbus_readl(&par->lc_ss0_usr->csr); + } while (val & 0x20000000); + + spin_unlock_irqrestore(&par->lock, flags); +} + +static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + /* We just use this to catch switches out of + * graphics mode. + */ + leo_switch_from_graph(info); + + if (var->xoffset || var->yoffset || var->vmode) + return -EINVAL; + return 0; +} + +static void leo_init_hw(struct fb_info *info) +{ + struct leo_par *par = (struct leo_par *) info->par; + u32 val; + + val = sbus_readl(&par->ld_ss1->ss1_misc); + val |= LEO_SS1_MISC_ENABLE; + sbus_writel(val, &par->ld_ss1->ss1_misc); + + leo_switch_from_graph(info); +} + +static void leo_fixup_var_rgb(struct fb_var_screeninfo *var) +{ + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; +} + +struct all_info { + struct fb_info info; + struct leo_par par; + struct list_head list; +}; +static LIST_HEAD(leo_list); + +static void leo_init_one(struct sbus_dev *sdev) +{ + struct all_info *all; + int linebytes; + + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "leo: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); + + INIT_LIST_HEAD(&all->list); + + spin_lock_init(&all->par.lock); + all->par.sdev = sdev; + + all->par.physbase = sdev->reg_addrs[0].phys_addr; + + sbusfb_fill_var(&all->info.var, sdev->prom_node, 32); + leo_fixup_var_rgb(&all->info.var); + + linebytes = prom_getintdefault(sdev->prom_node, "linebytes", + all->info.var.xres); + all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + +#ifdef CONFIG_SPARC32 + all->info.screen_base = (char __iomem *) + prom_getintdefault(sdev->prom_node, "address", 0); +#endif + if (!all->info.screen_base) + all->info.screen_base = + sbus_ioremap(&sdev->resource[0], LEO_OFF_SS0, + 0x800000, "leo ram"); + + all->par.lc_ss0_usr = + sbus_ioremap(&sdev->resource[0], LEO_OFF_LC_SS0_USR, + 0x1000, "leolc ss0usr"); + all->par.ld_ss0 = + sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS0, + 0x1000, "leold ss0"); + all->par.ld_ss1 = + sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS1, + 0x1000, "leold ss1"); + all->par.lx_krn = + sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_KRN, + 0x1000, "leolx krn"); + all->par.cursor = + sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_CURSOR, + sizeof(struct leo_cursor), "leolx cursor"); + + all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + all->info.fbops = &leo_ops; + all->info.par = &all->par; + + leo_init_wids(&all->info); + leo_init_hw(&all->info); + + leo_blank(0, &all->info); + + if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { + printk(KERN_ERR "leo: Could not allocate color map.\n"); + kfree(all); + return; + } + + leo_init_fix(&all->info); + + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "leo: Could not register framebuffer.\n"); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + return; + } + + list_add(&all->list, &leo_list); + + printk("leo: %s at %lx:%lx\n", + sdev->prom_name, + (long) sdev->reg_addrs[0].which_io, + (long) sdev->reg_addrs[0].phys_addr); +} + +int __init leo_init(void) +{ + struct sbus_bus *sbus; + struct sbus_dev *sdev; + + if (fb_get_options("leofb", NULL)) + return -ENODEV; + + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "leo")) + leo_init_one(sdev); + } + + return 0; +} + +void __exit leo_exit(void) +{ + struct list_head *pos, *tmp; + + list_for_each_safe(pos, tmp, &leo_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } +} + +int __init +leo_setup(char *arg) +{ + /* No cmdline options yet... */ + return 0; +} + +module_init(leo_init); +#ifdef MODULE +module_exit(leo_exit); +#endif + +MODULE_DESCRIPTION("framebuffer driver for LEO chipsets"); +MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig new file mode 100644 index 000000000000..849b47b210ec --- /dev/null +++ b/drivers/video/logo/Kconfig @@ -0,0 +1,67 @@ +# +# Logo configuration +# + +menu "Logo configuration" + +config LOGO + bool "Bootup logo" + depends on FB || SGI_NEWPORT_CONSOLE + +config LOGO_LINUX_MONO + bool "Standard black and white Linux logo" + depends on LOGO + default y + +config LOGO_LINUX_VGA16 + bool "Standard 16-color Linux logo" + depends on LOGO + default y + +config LOGO_LINUX_CLUT224 + bool "Standard 224-color Linux logo" + depends on LOGO + default y + +config LOGO_DEC_CLUT224 + bool "224-color Digital Equipment Corporation Linux logo" + depends on LOGO && (MACH_DECSTATION || ALPHA) + default y + +config LOGO_MAC_CLUT224 + bool "224-color Macintosh Linux logo" + depends on LOGO && MAC + default y + +config LOGO_PARISC_CLUT224 + bool "224-color PA-RISC Linux logo" + depends on LOGO && PARISC + default y + +config LOGO_SGI_CLUT224 + bool "224-color SGI Linux logo" + depends on LOGO && (SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS) + default y + +config LOGO_SUN_CLUT224 + bool "224-color Sun Linux logo" + depends on LOGO && (SPARC || SPARC64) + default y + +config LOGO_SUPERH_MONO + bool "Black and white SuperH Linux logo" + depends on LOGO && SUPERH + default y + +config LOGO_SUPERH_VGA16 + bool "16-color SuperH Linux logo" + depends on LOGO && SUPERH + default y + +config LOGO_SUPERH_CLUT224 + bool "224-color SuperH Linux logo" + depends on LOGO && SUPERH + default y + +endmenu + diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile new file mode 100644 index 000000000000..b0d995020bd1 --- /dev/null +++ b/drivers/video/logo/Makefile @@ -0,0 +1,54 @@ +# Makefile for the Linux logos + +obj-$(CONFIG_LOGO) += logo.o +obj-$(CONFIG_LOGO_LINUX_MONO) += logo_linux_mono.o +obj-$(CONFIG_LOGO_LINUX_VGA16) += logo_linux_vga16.o +obj-$(CONFIG_LOGO_LINUX_CLUT224) += logo_linux_clut224.o +obj-$(CONFIG_LOGO_DEC_CLUT224) += logo_dec_clut224.o +obj-$(CONFIG_LOGO_MAC_CLUT224) += logo_mac_clut224.o +obj-$(CONFIG_LOGO_PARISC_CLUT224) += logo_parisc_clut224.o +obj-$(CONFIG_LOGO_SGI_CLUT224) += logo_sgi_clut224.o +obj-$(CONFIG_LOGO_SUN_CLUT224) += logo_sun_clut224.o +obj-$(CONFIG_LOGO_SUPERH_MONO) += logo_superh_mono.o +obj-$(CONFIG_LOGO_SUPERH_VGA16) += logo_superh_vga16.o +obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o + +# How to generate logo's + +# Use logo-cfiles to retreive list of .c files to be built +logo-cfiles = $(notdir $(patsubst %.$(2), %.c, \ + $(wildcard $(srctree)/$(src)/*$(1).$(2)))) + + +# Mono logos +extra-y += $(call logo-cfiles,_mono,pbm) + +# VGA16 logos +extra-y += $(call logo-cfiles,_vga16,ppm) + +# 224 Logos +extra-y += $(call logo-cfiles,_clut224,ppm) + +# Gray 256 +extra-y += $(call logo-cfiles,_gray256,pgm) + +# Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..." +quiet_cmd_logo = LOGO $@ + cmd_logo = scripts/pnmtologo \ + -t $(patsubst $*_%,%,$(notdir $(basename $<))) \ + -n $(notdir $(basename $<)) -o $@ $< + +$(obj)/%_mono.c: $(src)/%_mono.pbm FORCE + $(call if_changed,logo) + +$(obj)/%_vga16.c: $(src)/%_vga16.ppm FORCE + $(call if_changed,logo) + +$(obj)/%_clut224.c: $(src)/%_clut224.ppm FORCE + $(call if_changed,logo) + +$(obj)/%_gray256.c: $(src)/%_gray256.pgm FORCE + $(call if_changed,logo) + +# Files generated that shall be removed upon make clean +clean-files := *.o *_mono.c *_vga16.c *_clut224.c *_gray256.c diff --git a/drivers/video/logo/clut_vga16.ppm b/drivers/video/logo/clut_vga16.ppm new file mode 100644 index 000000000000..aaf7c38d4c8d --- /dev/null +++ b/drivers/video/logo/clut_vga16.ppm @@ -0,0 +1,20 @@ +P3 +# Standard console colors +16 1 +255 + 0 0 0 + 0 0 170 + 0 170 0 + 0 170 170 +170 0 0 +170 0 170 +170 85 0 +170 170 170 + 85 85 85 + 85 85 255 + 85 255 85 + 85 255 255 +255 85 85 +255 85 255 +255 255 85 +255 255 255 diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c new file mode 100644 index 000000000000..77b622075001 --- /dev/null +++ b/drivers/video/logo/logo.c @@ -0,0 +1,103 @@ + +/* + * Linux logo to be displayed on boot + * + * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu) + * Copyright (C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 2001 Greg Banks <gnb@alphalink.com.au> + * Copyright (C) 2001 Jan-Benedict Glaw <jbglaw@lug-owl.de> + * Copyright (C) 2003 Geert Uytterhoeven <geert@linux-m68k.org> + */ + +#include <linux/config.h> +#include <linux/linux_logo.h> +#include <linux/stddef.h> +#include <linux/module.h> + +#ifdef CONFIG_M68K +#include <asm/setup.h> +#endif + +#ifdef CONFIG_MIPS +#include <asm/bootinfo.h> +#endif + +extern const struct linux_logo logo_linux_mono; +extern const struct linux_logo logo_linux_vga16; +extern const struct linux_logo logo_linux_clut224; +extern const struct linux_logo logo_dec_clut224; +extern const struct linux_logo logo_mac_clut224; +extern const struct linux_logo logo_parisc_clut224; +extern const struct linux_logo logo_sgi_clut224; +extern const struct linux_logo logo_sun_clut224; +extern const struct linux_logo logo_superh_mono; +extern const struct linux_logo logo_superh_vga16; +extern const struct linux_logo logo_superh_clut224; + + +const struct linux_logo *fb_find_logo(int depth) +{ + const struct linux_logo *logo = NULL; + + if (depth >= 1) { +#ifdef CONFIG_LOGO_LINUX_MONO + /* Generic Linux logo */ + logo = &logo_linux_mono; +#endif +#ifdef CONFIG_LOGO_SUPERH_MONO + /* SuperH Linux logo */ + logo = &logo_superh_mono; +#endif + } + + if (depth >= 4) { +#ifdef CONFIG_LOGO_LINUX_VGA16 + /* Generic Linux logo */ + logo = &logo_linux_vga16; +#endif +#ifdef CONFIG_LOGO_SUPERH_VGA16 + /* SuperH Linux logo */ + logo = &logo_superh_vga16; +#endif + } + + if (depth >= 8) { +#ifdef CONFIG_LOGO_LINUX_CLUT224 + /* Generic Linux logo */ + logo = &logo_linux_clut224; +#endif +#ifdef CONFIG_LOGO_DEC_CLUT224 + /* DEC Linux logo on MIPS/MIPS64 or ALPHA */ +#ifndef CONFIG_ALPHA + if (mips_machgroup == MACH_GROUP_DEC) +#endif + logo = &logo_dec_clut224; +#endif +#ifdef CONFIG_LOGO_MAC_CLUT224 + /* Macintosh Linux logo on m68k */ + if (MACH_IS_MAC) + logo = &logo_mac_clut224; +#endif +#ifdef CONFIG_LOGO_PARISC_CLUT224 + /* PA-RISC Linux logo */ + logo = &logo_parisc_clut224; +#endif +#ifdef CONFIG_LOGO_SGI_CLUT224 + /* SGI Linux logo on MIPS/MIPS64 and VISWS */ +#ifndef CONFIG_X86_VISWS + if (mips_machgroup == MACH_GROUP_SGI) +#endif + logo = &logo_sgi_clut224; +#endif +#ifdef CONFIG_LOGO_SUN_CLUT224 + /* Sun Linux logo */ + logo = &logo_sun_clut224; +#endif +#ifdef CONFIG_LOGO_SUPERH_CLUT224 + /* SuperH Linux logo */ + logo = &logo_superh_clut224; +#endif + } + return logo; +} +EXPORT_SYMBOL_GPL(fb_find_logo); diff --git a/drivers/video/logo/logo_dec_clut224.ppm b/drivers/video/logo/logo_dec_clut224.ppm new file mode 100644 index 000000000000..fd921ad5be50 --- /dev/null +++ b/drivers/video/logo/logo_dec_clut224.ppm @@ -0,0 +1,1604 @@ +P3 +# 224-color Digital Equipment Corporation Linux logo +80 80 +255 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 6 6 6 10 10 10 10 10 10 + 10 10 10 6 6 6 6 6 6 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 10 10 10 14 14 14 + 22 22 22 26 26 26 30 30 30 34 34 34 + 30 30 30 30 30 30 26 26 26 18 18 18 + 14 14 14 10 10 10 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 26 26 26 42 42 42 + 54 54 54 66 66 66 78 78 78 78 78 78 + 78 78 78 74 74 74 66 66 66 54 54 54 + 42 42 42 26 26 26 18 18 18 10 10 10 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 22 22 22 42 42 42 66 66 66 86 86 86 + 66 66 66 38 38 38 38 38 38 22 22 22 + 26 26 26 34 34 34 54 54 54 66 66 66 + 86 86 86 70 70 70 46 46 46 26 26 26 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 26 26 26 + 50 50 50 82 82 82 58 58 58 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 54 54 54 86 86 86 66 66 66 + 38 38 38 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 22 22 22 50 50 50 + 78 78 78 34 34 34 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 6 6 6 70 70 70 + 78 78 78 46 46 46 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 42 42 42 82 82 82 + 26 26 26 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 14 14 14 + 46 46 46 34 34 34 6 6 6 2 2 6 + 42 42 42 78 78 78 42 42 42 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 30 30 30 66 66 66 58 58 58 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 26 26 26 + 86 86 86 101 101 101 46 46 46 10 10 10 + 2 2 6 58 58 58 70 70 70 34 34 34 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 42 42 42 86 86 86 10 10 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 30 30 30 + 94 94 94 94 94 94 58 58 58 26 26 26 + 2 2 6 6 6 6 78 78 78 54 54 54 + 22 22 22 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 62 62 62 62 62 62 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 26 26 26 + 54 54 54 38 38 38 18 18 18 10 10 10 + 2 2 6 2 2 6 34 34 34 82 82 82 + 38 38 38 14 14 14 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 30 30 30 78 78 78 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 10 10 10 + 10 10 10 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 78 78 78 + 50 50 50 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 14 14 14 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 54 54 54 + 66 66 66 26 26 26 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 82 82 82 2 2 6 2 2 6 + 2 2 6 6 6 6 10 10 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 6 6 6 + 14 14 14 10 10 10 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 18 18 18 + 82 82 82 34 34 34 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 2 2 6 + 6 6 6 6 6 6 22 22 22 34 34 34 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 34 34 34 + 10 10 10 50 50 50 22 22 22 2 2 6 + 2 2 6 2 2 6 2 2 6 10 10 10 + 86 86 86 42 42 42 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 2 2 6 + 38 38 38 116 116 116 94 94 94 22 22 22 + 22 22 22 2 2 6 2 2 6 2 2 6 + 14 14 14 86 86 86 138 138 138 162 162 162 +154 154 154 38 38 38 26 26 26 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 86 86 86 46 46 46 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 14 14 14 +134 134 134 198 198 198 195 195 195 116 116 116 + 10 10 10 2 2 6 2 2 6 6 6 6 +101 98 89 187 187 187 210 210 210 218 218 218 +214 214 214 134 134 134 14 14 14 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 86 86 86 50 50 50 18 18 18 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 54 54 54 +218 218 218 195 195 195 226 226 226 246 246 246 + 58 58 58 2 2 6 2 2 6 30 30 30 +210 210 210 253 253 253 174 174 174 123 123 123 +221 221 221 234 234 234 74 74 74 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 82 82 82 2 2 6 106 106 106 +170 170 170 26 26 26 86 86 86 226 226 226 +123 123 123 10 10 10 14 14 14 46 46 46 +231 231 231 190 190 190 6 6 6 70 70 70 + 90 90 90 238 238 238 158 158 158 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 86 86 86 6 6 6 116 116 116 +106 106 106 6 6 6 70 70 70 149 149 149 +128 128 128 18 18 18 38 38 38 54 54 54 +221 221 221 106 106 106 2 2 6 14 14 14 + 46 46 46 190 190 190 198 198 198 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 62 62 62 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 94 94 94 14 14 14 101 101 101 +128 128 128 2 2 6 18 18 18 116 116 116 +118 98 46 121 92 8 121 92 8 98 78 10 +162 162 162 106 106 106 2 2 6 2 2 6 + 2 2 6 195 195 195 195 195 195 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 62 62 62 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 1 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 90 90 90 14 14 14 58 58 58 +210 210 210 26 26 26 54 38 6 154 114 10 +226 170 11 236 186 11 225 175 15 184 144 12 +215 174 15 175 146 61 37 26 9 2 2 6 + 70 70 70 246 246 246 138 138 138 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 66 66 66 26 26 26 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 14 14 14 10 10 10 +195 195 195 188 164 115 192 133 9 225 175 15 +239 182 13 234 190 10 232 195 16 232 200 30 +245 207 45 241 208 19 232 195 16 184 144 12 +218 194 134 211 206 186 42 42 42 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 50 50 50 74 74 74 30 30 30 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 86 86 86 14 14 14 2 2 6 +121 87 25 192 133 9 219 162 10 239 182 13 +236 186 11 232 195 16 241 208 19 244 214 54 +246 218 60 246 218 38 246 215 20 241 208 19 +241 208 19 226 184 13 121 87 25 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 50 50 50 82 82 82 34 34 34 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 82 82 82 30 30 30 61 42 6 +180 123 7 206 145 10 230 174 11 239 182 13 +234 190 10 238 202 15 241 208 19 246 218 74 +246 218 38 246 215 20 246 215 20 246 215 20 +226 184 13 215 174 15 184 144 12 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 26 26 26 94 94 94 42 42 42 14 14 14 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 50 50 50 104 69 6 +192 133 9 216 158 10 236 178 12 236 186 11 +232 195 16 241 208 19 244 214 54 245 215 43 +246 215 20 246 215 20 241 208 19 198 155 10 +200 144 11 216 158 10 156 118 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 90 90 90 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 46 46 46 22 22 22 +137 92 6 210 162 10 239 182 13 238 190 10 +238 202 15 241 208 19 246 215 20 246 215 20 +241 208 19 203 166 17 185 133 11 210 150 10 +216 158 10 210 150 10 102 78 10 2 2 6 + 6 6 6 54 54 54 14 14 14 2 2 6 + 2 2 6 62 62 62 74 74 74 30 30 30 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 78 78 78 50 50 50 6 6 6 + 94 70 30 139 102 15 190 146 13 226 184 13 +232 200 30 232 195 16 215 174 15 190 146 13 +168 122 10 192 133 9 210 150 10 213 154 11 +202 150 34 182 157 106 101 98 89 2 2 6 + 2 2 6 78 78 78 116 116 116 58 58 58 + 2 2 6 22 22 22 90 90 90 46 46 46 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 50 50 50 6 6 6 +128 128 128 174 154 114 156 107 11 168 122 10 +198 155 10 184 144 12 197 138 11 200 144 11 +206 145 10 206 145 10 197 138 11 188 164 115 +195 195 195 198 198 198 174 174 174 14 14 14 + 2 2 6 22 22 22 116 116 116 116 116 116 + 22 22 22 2 2 6 74 74 74 70 70 70 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 101 101 101 26 26 26 10 10 10 +138 138 138 190 190 190 174 154 114 156 107 11 +197 138 11 200 144 11 197 138 11 192 133 9 +180 123 7 190 142 34 190 178 144 187 187 187 +202 202 202 221 221 221 214 214 214 66 66 66 + 2 2 6 2 2 6 50 50 50 62 62 62 + 6 6 6 2 2 6 10 10 10 90 90 90 + 50 50 50 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 34 34 34 + 74 74 74 74 74 74 2 2 6 6 6 6 +144 144 144 198 198 198 190 190 190 178 166 146 +154 121 60 156 107 11 156 107 11 168 124 44 +174 154 114 187 187 187 190 190 190 210 210 210 +246 246 246 253 253 253 253 253 253 182 182 182 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 62 62 62 + 74 74 74 34 34 34 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 10 10 10 22 22 22 54 54 54 + 94 94 94 18 18 18 2 2 6 46 46 46 +234 234 234 221 221 221 190 190 190 190 190 190 +190 190 190 187 187 187 187 187 187 190 190 190 +190 190 190 195 195 195 214 214 214 242 242 242 +253 253 253 253 253 253 253 253 253 253 253 253 + 82 82 82 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 14 14 14 + 86 86 86 54 54 54 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 46 46 46 90 90 90 + 46 46 46 18 18 18 6 6 6 182 182 182 +253 253 253 246 246 246 206 206 206 190 190 190 +190 190 190 190 190 190 190 190 190 190 190 190 +206 206 206 231 231 231 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +202 202 202 14 14 14 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 42 42 42 86 86 86 42 42 42 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 14 14 14 38 38 38 74 74 74 66 66 66 + 2 2 6 6 6 6 90 90 90 250 250 250 +253 253 253 253 253 253 238 238 238 198 198 198 +190 190 190 190 190 190 195 195 195 221 221 221 +246 246 246 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 82 82 82 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 78 78 78 70 70 70 34 34 34 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 34 34 34 66 66 66 78 78 78 6 6 6 + 2 2 6 18 18 18 218 218 218 253 253 253 +253 253 253 253 253 253 253 253 253 246 246 246 +226 226 226 231 231 231 246 246 246 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 178 178 178 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 18 18 18 90 90 90 62 62 62 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 26 26 26 + 58 58 58 90 90 90 18 18 18 2 2 6 + 2 2 6 110 110 110 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 231 231 231 18 18 18 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 94 94 94 + 54 54 54 26 26 26 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 22 22 22 50 50 50 + 90 90 90 26 26 26 2 2 6 2 2 6 + 14 14 14 195 195 195 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 242 242 242 54 54 54 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 38 38 38 + 86 86 86 50 50 50 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 38 38 38 82 82 82 + 34 34 34 2 2 6 2 2 6 2 2 6 + 42 42 42 195 195 195 246 246 246 253 253 253 +253 253 253 253 253 253 253 253 253 250 250 250 +242 242 242 242 242 242 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 250 250 250 246 246 246 238 238 238 +226 226 226 231 231 231 101 101 101 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 38 38 38 82 82 82 42 42 42 14 14 14 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 26 26 26 62 62 62 66 66 66 + 2 2 6 2 2 6 2 2 6 6 6 6 + 70 70 70 170 170 170 206 206 206 234 234 234 +246 246 246 250 250 250 250 250 250 238 238 238 +226 226 226 231 231 231 238 238 238 250 250 250 +250 250 250 250 250 250 246 246 246 231 231 231 +214 214 214 206 206 206 202 202 202 202 202 202 +198 198 198 202 202 202 182 182 182 18 18 18 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 62 62 62 66 66 66 30 30 30 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 42 42 42 82 82 82 18 18 18 + 2 2 6 2 2 6 2 2 6 10 10 10 + 94 94 94 182 182 182 218 218 218 242 242 242 +250 250 250 253 253 253 253 253 253 250 250 250 +234 234 234 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 246 246 246 +238 238 238 226 226 226 210 210 210 202 202 202 +195 195 195 195 195 195 210 210 210 158 158 158 + 6 6 6 14 14 14 50 50 50 14 14 14 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 86 86 86 46 46 46 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 54 54 54 70 70 70 2 2 6 + 2 2 6 10 10 10 2 2 6 22 22 22 +166 166 166 231 231 231 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 250 250 250 +242 242 242 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 246 246 246 +231 231 231 206 206 206 198 198 198 226 226 226 + 94 94 94 2 2 6 6 6 6 38 38 38 + 30 30 30 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 62 62 62 66 66 66 + 26 26 26 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 74 74 74 50 50 50 2 2 6 + 26 26 26 26 26 26 2 2 6 106 106 106 +238 238 238 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 246 246 246 218 218 218 202 202 202 +210 210 210 14 14 14 2 2 6 2 2 6 + 30 30 30 22 22 22 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 86 86 86 + 42 42 42 14 14 14 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 90 90 90 22 22 22 2 2 6 + 42 42 42 2 2 6 18 18 18 218 218 218 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 250 250 250 221 221 221 +218 218 218 101 101 101 2 2 6 14 14 14 + 18 18 18 38 38 38 10 10 10 2 2 6 + 2 2 6 2 2 6 2 2 6 78 78 78 + 58 58 58 22 22 22 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 54 54 54 82 82 82 2 2 6 26 26 26 + 22 22 22 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 253 253 253 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 253 253 253 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 253 253 253 6 6 6 38 38 38 + 58 58 58 26 26 26 38 38 38 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 78 78 78 30 30 30 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 30 30 30 + 74 74 74 58 58 58 2 2 6 42 42 42 + 2 2 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 253 253 253 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 253 253 253 46 46 46 38 38 38 + 42 42 42 14 14 14 38 38 38 14 14 14 + 2 2 6 2 2 6 2 2 6 6 6 6 + 86 86 86 46 46 46 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 42 42 42 + 90 90 90 18 18 18 18 18 18 26 26 26 + 2 2 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 253 253 253 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 253 253 253 94 94 94 6 6 6 + 2 2 6 2 2 6 10 10 10 34 34 34 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 10 10 10 26 26 26 66 66 66 + 82 82 82 2 2 6 38 38 38 6 6 6 + 14 14 14 175 118 6 175 118 6 175 118 6 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +253 253 253 175 118 6 175 118 6 253 253 253 +175 118 6 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 175 118 6 +175 118 6 253 253 253 144 144 144 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 2 2 6 2 2 6 2 2 6 2 2 6 + 42 42 42 74 74 74 30 30 30 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 42 42 42 90 90 90 + 26 26 26 6 6 6 42 42 42 2 2 6 + 74 74 74 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 175 118 6 +175 118 6 253 253 253 182 182 182 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 2 2 6 2 2 6 2 2 6 2 2 6 + 10 10 10 86 86 86 38 38 38 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 26 26 26 66 66 66 82 82 82 + 2 2 6 22 22 22 18 18 18 2 2 6 +149 149 149 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 253 253 253 175 118 6 +253 253 253 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 206 206 206 2 2 6 + 2 2 6 2 2 6 2 2 6 38 38 38 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 86 86 86 46 46 46 14 14 14 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 18 18 18 46 46 46 86 86 86 18 18 18 + 2 2 6 34 34 34 10 10 10 6 6 6 +210 210 210 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 253 253 253 175 118 6 +253 253 253 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 221 221 221 6 6 6 + 2 2 6 2 2 6 6 6 6 30 30 30 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 82 82 82 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 26 26 26 66 66 66 62 62 62 2 2 6 + 2 2 6 38 38 38 10 10 10 26 26 26 +238 238 238 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 231 231 231 6 6 6 + 2 2 6 2 2 6 10 10 10 30 30 30 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 58 58 58 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 78 78 78 6 6 6 2 2 6 + 2 2 6 46 46 46 14 14 14 42 42 42 +246 246 246 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 253 253 253 234 234 234 10 10 10 + 2 2 6 2 2 6 22 22 22 14 14 14 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 62 62 62 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 74 74 74 2 2 6 2 2 6 + 14 14 14 70 70 70 34 34 34 62 62 62 +250 250 250 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 253 253 253 175 118 6 +175 118 6 175 118 6 175 118 6 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 253 253 253 234 234 234 14 14 14 + 2 2 6 2 2 6 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 62 62 62 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 54 54 54 62 62 62 2 2 6 2 2 6 + 2 2 6 30 30 30 46 46 46 70 70 70 +250 250 250 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 253 253 253 175 118 6 +253 253 253 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 226 226 226 10 10 10 + 2 2 6 6 6 6 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 58 58 58 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 58 58 58 62 62 62 2 2 6 2 2 6 + 2 2 6 2 2 6 30 30 30 78 78 78 +250 250 250 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 253 253 253 175 118 6 +253 253 253 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 206 206 206 2 2 6 + 22 22 22 34 34 34 18 14 6 22 22 22 + 26 26 26 18 18 18 6 6 6 2 2 6 + 2 2 6 82 82 82 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 26 26 26 + 62 62 62 106 106 106 74 54 14 185 133 11 +210 162 10 121 92 8 6 6 6 62 62 62 +238 238 238 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 253 253 253 175 118 6 +253 253 253 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +175 118 6 253 253 253 158 158 158 18 18 18 + 14 14 14 2 2 6 2 2 6 2 2 6 + 6 6 6 18 18 18 66 66 66 38 38 38 + 6 6 6 94 94 94 50 50 50 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 10 10 10 10 10 10 18 18 18 38 38 38 + 78 78 78 142 134 106 216 158 10 242 186 14 +246 190 14 246 190 14 156 118 10 10 10 10 + 90 90 90 175 118 6 175 118 6 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +175 118 6 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +175 118 6 175 118 6 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 175 118 6 +175 118 6 253 253 253 181 142 44 37 26 9 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 38 38 38 46 46 46 + 26 26 26 106 106 106 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 22 22 22 + 30 30 30 38 38 38 50 50 50 70 70 70 +106 106 106 190 142 34 226 170 11 242 186 14 +246 190 14 246 190 14 246 190 14 154 114 10 + 6 6 6 175 118 6 175 118 6 175 118 6 +253 253 253 253 253 253 175 118 6 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +175 118 6 175 118 6 253 253 253 253 253 253 +253 253 253 253 253 253 175 118 6 253 253 253 +175 118 6 175 118 6 253 253 253 253 253 253 +253 253 253 253 253 253 175 118 6 175 118 6 +175 118 6 253 253 253 232 195 16 38 30 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 30 30 30 26 26 26 +203 166 17 154 142 90 66 66 66 26 26 26 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 38 38 38 58 58 58 + 78 78 78 86 86 86 101 101 101 123 123 123 +175 146 61 210 150 10 234 174 13 246 186 14 +246 190 14 246 190 14 246 190 14 238 190 10 +102 78 10 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 253 253 253 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 253 253 253 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 253 253 253 210 166 10 22 18 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 6 6 6 121 92 8 +238 202 15 232 195 16 82 82 82 34 34 34 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 38 38 38 70 70 70 154 122 46 +190 142 34 200 144 11 197 138 11 197 138 11 +213 154 11 226 170 11 242 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +225 175 15 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 253 253 253 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 253 253 253 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 175 118 6 175 118 6 175 118 6 +175 118 6 253 253 253 213 154 11 46 32 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 61 42 6 225 175 15 +238 190 10 236 186 11 112 100 78 42 42 42 + 14 14 14 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 54 54 54 154 122 46 213 154 11 +226 170 11 230 174 11 226 170 11 226 170 11 +236 178 12 242 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +241 196 14 184 144 12 10 10 10 2 2 6 + 6 6 6 116 116 116 242 242 242 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 231 231 231 198 198 198 214 170 54 +236 178 12 236 178 12 210 150 10 137 92 6 + 18 14 6 2 2 6 2 2 6 2 2 6 + 6 6 6 70 47 6 200 144 11 236 178 12 +239 182 13 239 182 13 124 112 88 58 58 58 + 22 22 22 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 70 70 70 180 133 36 226 170 11 +239 182 13 242 186 14 242 186 14 246 186 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 232 195 16 98 70 6 2 2 6 + 2 2 6 2 2 6 66 66 66 221 221 221 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 206 206 206 198 198 198 214 166 58 +230 174 11 230 174 11 216 158 10 192 133 9 +163 110 8 116 81 8 102 78 10 116 81 8 +167 114 7 197 138 11 226 170 11 239 182 13 +242 186 14 242 186 14 162 146 94 78 78 78 + 34 34 34 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 30 30 30 78 78 78 190 142 34 226 170 11 +239 182 13 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 241 196 14 203 166 17 22 18 6 + 2 2 6 2 2 6 2 2 6 38 38 38 +218 218 218 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 206 206 206 198 198 198 202 162 69 +226 170 11 236 178 12 224 166 10 210 150 10 +200 144 11 197 138 11 192 133 9 197 138 11 +210 150 10 226 170 11 242 186 14 246 190 14 +246 190 14 246 186 14 225 175 15 124 112 88 + 62 62 62 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 174 135 50 224 166 10 +239 182 13 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 241 196 14 139 102 15 + 2 2 6 2 2 6 2 2 6 2 2 6 + 78 78 78 250 250 250 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 214 214 214 198 198 198 190 150 46 +219 162 10 236 178 12 234 174 13 224 166 10 +216 158 10 213 154 11 213 154 11 216 158 10 +226 170 11 239 182 13 246 190 14 246 190 14 +246 190 14 246 190 14 242 186 14 206 162 42 +101 101 101 58 58 58 30 30 30 14 14 14 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 74 74 74 174 135 50 216 158 10 +236 178 12 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 241 196 14 226 184 13 + 61 42 6 2 2 6 2 2 6 2 2 6 + 22 22 22 238 238 238 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 226 226 226 187 187 187 180 133 36 +216 158 10 236 178 12 239 182 13 236 178 12 +230 174 11 226 170 11 226 170 11 230 174 11 +236 178 12 242 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 186 14 239 182 13 +206 162 42 106 106 106 66 66 66 34 34 34 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 26 26 26 70 70 70 163 133 67 213 154 11 +236 178 12 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 241 196 14 +190 146 13 18 14 6 2 2 6 2 2 6 + 46 46 46 246 246 246 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 221 221 221 86 86 86 156 107 11 +216 158 10 236 178 12 242 186 14 246 186 14 +242 186 14 239 182 13 239 182 13 242 186 14 +242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +242 186 14 225 175 15 142 122 72 66 66 66 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 26 26 26 70 70 70 163 133 67 210 150 10 +236 178 12 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +232 195 16 121 92 8 34 34 34 106 106 106 +221 221 221 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +242 242 242 82 82 82 18 14 6 163 110 8 +216 158 10 236 178 12 242 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 242 186 14 163 133 67 + 46 46 46 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 163 133 67 210 150 10 +236 178 12 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +241 196 14 215 174 15 190 178 144 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 218 218 218 + 58 58 58 2 2 6 22 18 6 167 114 7 +216 158 10 236 178 12 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 186 14 242 186 14 190 150 46 + 54 54 54 22 22 22 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 38 38 38 86 86 86 180 133 36 213 154 11 +236 178 12 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 232 195 16 190 146 13 214 214 214 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 250 250 250 170 170 170 26 26 26 + 2 2 6 2 2 6 37 26 9 163 110 8 +219 162 10 239 182 13 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 236 178 12 224 166 10 142 122 72 + 46 46 46 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 109 106 95 192 133 9 224 166 10 +242 186 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +242 186 14 226 184 13 210 162 10 142 110 46 +226 226 226 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +198 198 198 66 66 66 2 2 6 2 2 6 + 2 2 6 2 2 6 50 34 6 156 107 11 +219 162 10 239 182 13 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 242 186 14 +234 174 13 213 154 11 154 122 46 66 66 66 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 58 58 58 154 121 60 206 145 10 234 174 13 +242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 236 178 12 210 162 10 163 110 8 + 61 42 6 138 138 138 218 218 218 250 250 250 +253 253 253 253 253 253 253 253 253 250 250 250 +242 242 242 210 210 210 144 144 144 66 66 66 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 61 42 6 163 110 8 +216 158 10 236 178 12 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 239 182 13 230 174 11 216 158 10 +190 142 34 124 112 88 70 70 70 38 38 38 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 62 62 62 168 124 44 206 145 10 224 166 10 +236 178 12 239 182 13 242 186 14 242 186 14 +246 186 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 236 178 12 216 158 10 175 118 6 + 80 54 7 2 2 6 6 6 6 30 30 30 + 54 54 54 62 62 62 50 50 50 38 38 38 + 14 14 14 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 80 54 7 167 114 7 +213 154 11 236 178 12 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 242 186 14 239 182 13 239 182 13 +230 174 11 210 150 10 174 135 50 124 112 88 + 82 82 82 54 54 54 34 34 34 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 158 118 36 192 133 9 200 144 11 +216 158 10 219 162 10 224 166 10 226 170 11 +230 174 11 236 178 12 239 182 13 239 182 13 +242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 230 174 11 210 150 10 163 110 8 +104 69 6 10 10 10 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 91 60 6 167 114 7 +206 145 10 230 174 11 242 186 14 246 190 14 +246 190 14 246 190 14 246 186 14 242 186 14 +239 182 13 230 174 11 224 166 10 213 154 11 +180 133 36 124 112 88 86 86 86 58 58 58 + 38 38 38 22 22 22 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 34 34 34 70 70 70 138 110 50 158 118 36 +167 114 7 180 123 7 192 133 9 197 138 11 +200 144 11 206 145 10 213 154 11 219 162 10 +224 166 10 230 174 11 239 182 13 242 186 14 +246 186 14 246 186 14 246 186 14 246 186 14 +239 182 13 216 158 10 185 133 11 152 99 6 +104 69 6 18 14 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 80 54 7 152 99 6 +192 133 9 219 162 10 236 178 12 239 182 13 +246 186 14 242 186 14 239 182 13 236 178 12 +224 166 10 206 145 10 192 133 9 154 121 60 + 94 94 94 62 62 62 42 42 42 22 22 22 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 18 18 18 34 34 34 58 58 58 78 78 78 +101 98 89 124 112 88 142 110 46 156 107 11 +163 110 8 167 114 7 175 118 6 180 123 7 +185 133 11 197 138 11 210 150 10 219 162 10 +226 170 11 236 178 12 236 178 12 234 174 13 +219 162 10 197 138 11 163 110 8 130 83 6 + 91 60 6 10 10 10 2 2 6 2 2 6 + 18 18 18 38 38 38 38 38 38 38 38 38 + 38 38 38 38 38 38 38 38 38 38 38 38 + 38 38 38 38 38 38 26 26 26 2 2 6 + 2 2 6 6 6 6 70 47 6 137 92 6 +175 118 6 200 144 11 219 162 10 230 174 11 +234 174 13 230 174 11 219 162 10 210 150 10 +192 133 9 163 110 8 124 112 88 82 82 82 + 50 50 50 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 22 22 22 34 34 34 + 42 42 42 58 58 58 74 74 74 86 86 86 +101 98 89 122 102 70 130 98 46 121 87 25 +137 92 6 152 99 6 163 110 8 180 123 7 +185 133 11 197 138 11 206 145 10 200 144 11 +180 123 7 156 107 11 130 83 6 104 69 6 + 50 34 6 54 54 54 110 110 110 101 98 89 + 86 86 86 82 82 82 78 78 78 78 78 78 + 78 78 78 78 78 78 78 78 78 78 78 78 + 78 78 78 82 82 82 86 86 86 94 94 94 +106 106 106 101 101 101 86 66 34 124 80 6 +156 107 11 180 123 7 192 133 9 200 144 11 +206 145 10 200 144 11 192 133 9 175 118 6 +139 102 15 109 106 95 70 70 70 42 42 42 + 22 22 22 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 10 10 10 + 14 14 14 22 22 22 30 30 30 38 38 38 + 50 50 50 62 62 62 74 74 74 90 90 90 +101 98 89 112 100 78 121 87 25 124 80 6 +137 92 6 152 99 6 152 99 6 152 99 6 +138 86 6 124 80 6 98 70 6 86 66 30 +101 98 89 82 82 82 58 58 58 46 46 46 + 38 38 38 34 34 34 34 34 34 34 34 34 + 34 34 34 34 34 34 34 34 34 34 34 34 + 34 34 34 34 34 34 38 38 38 42 42 42 + 54 54 54 82 82 82 94 86 76 91 60 6 +134 86 6 156 107 11 167 114 7 175 118 6 +175 118 6 167 114 7 152 99 6 121 87 25 +101 98 89 62 62 62 34 34 34 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 6 6 6 10 10 10 + 18 18 18 22 22 22 30 30 30 42 42 42 + 50 50 50 66 66 66 86 86 86 101 98 89 +106 86 58 98 70 6 104 69 6 104 69 6 +104 69 6 91 60 6 82 62 34 90 90 90 + 62 62 62 38 38 38 22 22 22 14 14 14 + 10 10 10 10 10 10 10 10 10 10 10 10 + 10 10 10 10 10 10 6 6 6 10 10 10 + 10 10 10 10 10 10 10 10 10 14 14 14 + 22 22 22 42 42 42 70 70 70 89 81 66 + 80 54 7 104 69 6 124 80 6 137 92 6 +134 86 6 116 81 8 100 82 52 86 86 86 + 58 58 58 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 10 10 10 14 14 14 + 18 18 18 26 26 26 38 38 38 54 54 54 + 70 70 70 86 86 86 94 86 76 89 81 66 + 89 81 66 86 86 86 74 74 74 50 50 50 + 30 30 30 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 34 34 34 58 58 58 + 82 82 82 89 81 66 89 81 66 89 81 66 + 94 86 66 94 86 76 74 74 74 50 50 50 + 26 26 26 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 6 6 6 14 14 14 18 18 18 + 30 30 30 38 38 38 46 46 46 54 54 54 + 50 50 50 42 42 42 30 30 30 18 18 18 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 26 26 26 + 38 38 38 50 50 50 58 58 58 58 58 58 + 54 54 54 42 42 42 30 30 30 18 18 18 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 6 6 6 10 10 10 14 14 14 18 18 18 + 18 18 18 14 14 14 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 14 14 14 18 18 18 22 22 22 22 22 22 + 18 18 18 14 14 14 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/drivers/video/logo/logo_linux_clut224.ppm b/drivers/video/logo/logo_linux_clut224.ppm new file mode 100644 index 000000000000..3c14e43b82fe --- /dev/null +++ b/drivers/video/logo/logo_linux_clut224.ppm @@ -0,0 +1,1604 @@ +P3 +# Standard 224-color Linux logo +80 80 +255 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 6 6 6 10 10 10 10 10 10 + 10 10 10 6 6 6 6 6 6 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 10 10 10 14 14 14 + 22 22 22 26 26 26 30 30 30 34 34 34 + 30 30 30 30 30 30 26 26 26 18 18 18 + 14 14 14 10 10 10 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 26 26 26 42 42 42 + 54 54 54 66 66 66 78 78 78 78 78 78 + 78 78 78 74 74 74 66 66 66 54 54 54 + 42 42 42 26 26 26 18 18 18 10 10 10 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 22 22 22 42 42 42 66 66 66 86 86 86 + 66 66 66 38 38 38 38 38 38 22 22 22 + 26 26 26 34 34 34 54 54 54 66 66 66 + 86 86 86 70 70 70 46 46 46 26 26 26 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 26 26 26 + 50 50 50 82 82 82 58 58 58 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 54 54 54 86 86 86 66 66 66 + 38 38 38 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 22 22 22 50 50 50 + 78 78 78 34 34 34 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 6 6 6 70 70 70 + 78 78 78 46 46 46 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 42 42 42 82 82 82 + 26 26 26 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 14 14 14 + 46 46 46 34 34 34 6 6 6 2 2 6 + 42 42 42 78 78 78 42 42 42 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 30 30 30 66 66 66 58 58 58 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 26 26 26 + 86 86 86 101 101 101 46 46 46 10 10 10 + 2 2 6 58 58 58 70 70 70 34 34 34 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 42 42 42 86 86 86 10 10 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 30 30 30 + 94 94 94 94 94 94 58 58 58 26 26 26 + 2 2 6 6 6 6 78 78 78 54 54 54 + 22 22 22 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 62 62 62 62 62 62 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 26 26 26 + 54 54 54 38 38 38 18 18 18 10 10 10 + 2 2 6 2 2 6 34 34 34 82 82 82 + 38 38 38 14 14 14 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 30 30 30 78 78 78 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 10 10 10 + 10 10 10 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 78 78 78 + 50 50 50 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 14 14 14 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 54 54 54 + 66 66 66 26 26 26 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 82 82 82 2 2 6 2 2 6 + 2 2 6 6 6 6 10 10 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 6 6 6 + 14 14 14 10 10 10 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 18 18 18 + 82 82 82 34 34 34 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 2 2 6 + 6 6 6 6 6 6 22 22 22 34 34 34 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 34 34 34 + 10 10 10 50 50 50 22 22 22 2 2 6 + 2 2 6 2 2 6 2 2 6 10 10 10 + 86 86 86 42 42 42 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 2 2 6 + 38 38 38 116 116 116 94 94 94 22 22 22 + 22 22 22 2 2 6 2 2 6 2 2 6 + 14 14 14 86 86 86 138 138 138 162 162 162 +154 154 154 38 38 38 26 26 26 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 86 86 86 46 46 46 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 14 14 14 +134 134 134 198 198 198 195 195 195 116 116 116 + 10 10 10 2 2 6 2 2 6 6 6 6 +101 98 89 187 187 187 210 210 210 218 218 218 +214 214 214 134 134 134 14 14 14 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 86 86 86 50 50 50 18 18 18 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 54 54 54 +218 218 218 195 195 195 226 226 226 246 246 246 + 58 58 58 2 2 6 2 2 6 30 30 30 +210 210 210 253 253 253 174 174 174 123 123 123 +221 221 221 234 234 234 74 74 74 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 82 82 82 2 2 6 106 106 106 +170 170 170 26 26 26 86 86 86 226 226 226 +123 123 123 10 10 10 14 14 14 46 46 46 +231 231 231 190 190 190 6 6 6 70 70 70 + 90 90 90 238 238 238 158 158 158 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 86 86 86 6 6 6 116 116 116 +106 106 106 6 6 6 70 70 70 149 149 149 +128 128 128 18 18 18 38 38 38 54 54 54 +221 221 221 106 106 106 2 2 6 14 14 14 + 46 46 46 190 190 190 198 198 198 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 62 62 62 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 94 94 94 14 14 14 101 101 101 +128 128 128 2 2 6 18 18 18 116 116 116 +118 98 46 121 92 8 121 92 8 98 78 10 +162 162 162 106 106 106 2 2 6 2 2 6 + 2 2 6 195 195 195 195 195 195 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 62 62 62 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 1 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 90 90 90 14 14 14 58 58 58 +210 210 210 26 26 26 54 38 6 154 114 10 +226 170 11 236 186 11 225 175 15 184 144 12 +215 174 15 175 146 61 37 26 9 2 2 6 + 70 70 70 246 246 246 138 138 138 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 66 66 66 26 26 26 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 14 14 14 10 10 10 +195 195 195 188 164 115 192 133 9 225 175 15 +239 182 13 234 190 10 232 195 16 232 200 30 +245 207 45 241 208 19 232 195 16 184 144 12 +218 194 134 211 206 186 42 42 42 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 50 50 50 74 74 74 30 30 30 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 86 86 86 14 14 14 2 2 6 +121 87 25 192 133 9 219 162 10 239 182 13 +236 186 11 232 195 16 241 208 19 244 214 54 +246 218 60 246 218 38 246 215 20 241 208 19 +241 208 19 226 184 13 121 87 25 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 50 50 50 82 82 82 34 34 34 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 82 82 82 30 30 30 61 42 6 +180 123 7 206 145 10 230 174 11 239 182 13 +234 190 10 238 202 15 241 208 19 246 218 74 +246 218 38 246 215 20 246 215 20 246 215 20 +226 184 13 215 174 15 184 144 12 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 26 26 26 94 94 94 42 42 42 14 14 14 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 50 50 50 104 69 6 +192 133 9 216 158 10 236 178 12 236 186 11 +232 195 16 241 208 19 244 214 54 245 215 43 +246 215 20 246 215 20 241 208 19 198 155 10 +200 144 11 216 158 10 156 118 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 90 90 90 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 46 46 46 22 22 22 +137 92 6 210 162 10 239 182 13 238 190 10 +238 202 15 241 208 19 246 215 20 246 215 20 +241 208 19 203 166 17 185 133 11 210 150 10 +216 158 10 210 150 10 102 78 10 2 2 6 + 6 6 6 54 54 54 14 14 14 2 2 6 + 2 2 6 62 62 62 74 74 74 30 30 30 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 78 78 78 50 50 50 6 6 6 + 94 70 30 139 102 15 190 146 13 226 184 13 +232 200 30 232 195 16 215 174 15 190 146 13 +168 122 10 192 133 9 210 150 10 213 154 11 +202 150 34 182 157 106 101 98 89 2 2 6 + 2 2 6 78 78 78 116 116 116 58 58 58 + 2 2 6 22 22 22 90 90 90 46 46 46 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 50 50 50 6 6 6 +128 128 128 174 154 114 156 107 11 168 122 10 +198 155 10 184 144 12 197 138 11 200 144 11 +206 145 10 206 145 10 197 138 11 188 164 115 +195 195 195 198 198 198 174 174 174 14 14 14 + 2 2 6 22 22 22 116 116 116 116 116 116 + 22 22 22 2 2 6 74 74 74 70 70 70 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 101 101 101 26 26 26 10 10 10 +138 138 138 190 190 190 174 154 114 156 107 11 +197 138 11 200 144 11 197 138 11 192 133 9 +180 123 7 190 142 34 190 178 144 187 187 187 +202 202 202 221 221 221 214 214 214 66 66 66 + 2 2 6 2 2 6 50 50 50 62 62 62 + 6 6 6 2 2 6 10 10 10 90 90 90 + 50 50 50 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 34 34 34 + 74 74 74 74 74 74 2 2 6 6 6 6 +144 144 144 198 198 198 190 190 190 178 166 146 +154 121 60 156 107 11 156 107 11 168 124 44 +174 154 114 187 187 187 190 190 190 210 210 210 +246 246 246 253 253 253 253 253 253 182 182 182 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 62 62 62 + 74 74 74 34 34 34 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 10 10 10 22 22 22 54 54 54 + 94 94 94 18 18 18 2 2 6 46 46 46 +234 234 234 221 221 221 190 190 190 190 190 190 +190 190 190 187 187 187 187 187 187 190 190 190 +190 190 190 195 195 195 214 214 214 242 242 242 +253 253 253 253 253 253 253 253 253 253 253 253 + 82 82 82 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 14 14 14 + 86 86 86 54 54 54 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 46 46 46 90 90 90 + 46 46 46 18 18 18 6 6 6 182 182 182 +253 253 253 246 246 246 206 206 206 190 190 190 +190 190 190 190 190 190 190 190 190 190 190 190 +206 206 206 231 231 231 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +202 202 202 14 14 14 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 42 42 42 86 86 86 42 42 42 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 14 14 14 38 38 38 74 74 74 66 66 66 + 2 2 6 6 6 6 90 90 90 250 250 250 +253 253 253 253 253 253 238 238 238 198 198 198 +190 190 190 190 190 190 195 195 195 221 221 221 +246 246 246 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 82 82 82 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 78 78 78 70 70 70 34 34 34 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 34 34 34 66 66 66 78 78 78 6 6 6 + 2 2 6 18 18 18 218 218 218 253 253 253 +253 253 253 253 253 253 253 253 253 246 246 246 +226 226 226 231 231 231 246 246 246 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 178 178 178 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 18 18 18 90 90 90 62 62 62 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 26 26 26 + 58 58 58 90 90 90 18 18 18 2 2 6 + 2 2 6 110 110 110 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 231 231 231 18 18 18 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 94 94 94 + 54 54 54 26 26 26 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 22 22 22 50 50 50 + 90 90 90 26 26 26 2 2 6 2 2 6 + 14 14 14 195 195 195 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 242 242 242 54 54 54 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 38 38 38 + 86 86 86 50 50 50 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 38 38 38 82 82 82 + 34 34 34 2 2 6 2 2 6 2 2 6 + 42 42 42 195 195 195 246 246 246 253 253 253 +253 253 253 253 253 253 253 253 253 250 250 250 +242 242 242 242 242 242 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 250 250 250 246 246 246 238 238 238 +226 226 226 231 231 231 101 101 101 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 38 38 38 82 82 82 42 42 42 14 14 14 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 26 26 26 62 62 62 66 66 66 + 2 2 6 2 2 6 2 2 6 6 6 6 + 70 70 70 170 170 170 206 206 206 234 234 234 +246 246 246 250 250 250 250 250 250 238 238 238 +226 226 226 231 231 231 238 238 238 250 250 250 +250 250 250 250 250 250 246 246 246 231 231 231 +214 214 214 206 206 206 202 202 202 202 202 202 +198 198 198 202 202 202 182 182 182 18 18 18 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 62 62 62 66 66 66 30 30 30 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 42 42 42 82 82 82 18 18 18 + 2 2 6 2 2 6 2 2 6 10 10 10 + 94 94 94 182 182 182 218 218 218 242 242 242 +250 250 250 253 253 253 253 253 253 250 250 250 +234 234 234 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 246 246 246 +238 238 238 226 226 226 210 210 210 202 202 202 +195 195 195 195 195 195 210 210 210 158 158 158 + 6 6 6 14 14 14 50 50 50 14 14 14 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 86 86 86 46 46 46 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 54 54 54 70 70 70 2 2 6 + 2 2 6 10 10 10 2 2 6 22 22 22 +166 166 166 231 231 231 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 250 250 250 +242 242 242 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 246 246 246 +231 231 231 206 206 206 198 198 198 226 226 226 + 94 94 94 2 2 6 6 6 6 38 38 38 + 30 30 30 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 62 62 62 66 66 66 + 26 26 26 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 74 74 74 50 50 50 2 2 6 + 26 26 26 26 26 26 2 2 6 106 106 106 +238 238 238 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 246 246 246 218 218 218 202 202 202 +210 210 210 14 14 14 2 2 6 2 2 6 + 30 30 30 22 22 22 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 86 86 86 + 42 42 42 14 14 14 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 90 90 90 22 22 22 2 2 6 + 42 42 42 2 2 6 18 18 18 218 218 218 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 250 250 250 221 221 221 +218 218 218 101 101 101 2 2 6 14 14 14 + 18 18 18 38 38 38 10 10 10 2 2 6 + 2 2 6 2 2 6 2 2 6 78 78 78 + 58 58 58 22 22 22 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 54 54 54 82 82 82 2 2 6 26 26 26 + 22 22 22 2 2 6 123 123 123 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 250 250 250 +238 238 238 198 198 198 6 6 6 38 38 38 + 58 58 58 26 26 26 38 38 38 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 78 78 78 30 30 30 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 30 30 30 + 74 74 74 58 58 58 2 2 6 42 42 42 + 2 2 6 22 22 22 231 231 231 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 250 250 250 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 246 246 246 46 46 46 38 38 38 + 42 42 42 14 14 14 38 38 38 14 14 14 + 2 2 6 2 2 6 2 2 6 6 6 6 + 86 86 86 46 46 46 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 42 42 42 + 90 90 90 18 18 18 18 18 18 26 26 26 + 2 2 6 116 116 116 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 250 250 250 238 238 238 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 94 94 94 6 6 6 + 2 2 6 2 2 6 10 10 10 34 34 34 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 10 10 10 26 26 26 66 66 66 + 82 82 82 2 2 6 38 38 38 6 6 6 + 14 14 14 210 210 210 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 246 246 246 242 242 242 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 144 144 144 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 2 2 6 2 2 6 2 2 6 2 2 6 + 42 42 42 74 74 74 30 30 30 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 42 42 42 90 90 90 + 26 26 26 6 6 6 42 42 42 2 2 6 + 74 74 74 250 250 250 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 242 242 242 242 242 242 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 182 182 182 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 2 2 6 2 2 6 2 2 6 2 2 6 + 10 10 10 86 86 86 38 38 38 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 26 26 26 66 66 66 82 82 82 + 2 2 6 22 22 22 18 18 18 2 2 6 +149 149 149 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 234 234 234 242 242 242 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 206 206 206 2 2 6 + 2 2 6 2 2 6 2 2 6 38 38 38 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 86 86 86 46 46 46 14 14 14 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 18 18 18 46 46 46 86 86 86 18 18 18 + 2 2 6 34 34 34 10 10 10 6 6 6 +210 210 210 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 234 234 234 242 242 242 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 221 221 221 6 6 6 + 2 2 6 2 2 6 6 6 6 30 30 30 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 82 82 82 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 26 26 26 66 66 66 62 62 62 2 2 6 + 2 2 6 38 38 38 10 10 10 26 26 26 +238 238 238 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 231 231 231 238 238 238 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 231 231 231 6 6 6 + 2 2 6 2 2 6 10 10 10 30 30 30 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 58 58 58 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 78 78 78 6 6 6 2 2 6 + 2 2 6 46 46 46 14 14 14 42 42 42 +246 246 246 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 231 231 231 242 242 242 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 234 234 234 10 10 10 + 2 2 6 2 2 6 22 22 22 14 14 14 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 62 62 62 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 74 74 74 2 2 6 2 2 6 + 14 14 14 70 70 70 34 34 34 62 62 62 +250 250 250 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 231 231 231 246 246 246 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 234 234 234 14 14 14 + 2 2 6 2 2 6 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 62 62 62 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 54 54 54 62 62 62 2 2 6 2 2 6 + 2 2 6 30 30 30 46 46 46 70 70 70 +250 250 250 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 231 231 231 246 246 246 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 226 226 226 10 10 10 + 2 2 6 6 6 6 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 58 58 58 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 58 58 58 62 62 62 2 2 6 2 2 6 + 2 2 6 2 2 6 30 30 30 78 78 78 +250 250 250 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 231 231 231 246 246 246 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 206 206 206 2 2 6 + 22 22 22 34 34 34 18 14 6 22 22 22 + 26 26 26 18 18 18 6 6 6 2 2 6 + 2 2 6 82 82 82 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 26 26 26 + 62 62 62 106 106 106 74 54 14 185 133 11 +210 162 10 121 92 8 6 6 6 62 62 62 +238 238 238 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 231 231 231 246 246 246 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 158 158 158 18 18 18 + 14 14 14 2 2 6 2 2 6 2 2 6 + 6 6 6 18 18 18 66 66 66 38 38 38 + 6 6 6 94 94 94 50 50 50 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 10 10 10 10 10 10 18 18 18 38 38 38 + 78 78 78 142 134 106 216 158 10 242 186 14 +246 190 14 246 190 14 156 118 10 10 10 10 + 90 90 90 238 238 238 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 231 231 231 250 250 250 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 246 230 190 +238 204 91 238 204 91 181 142 44 37 26 9 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 38 38 38 46 46 46 + 26 26 26 106 106 106 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 22 22 22 + 30 30 30 38 38 38 50 50 50 70 70 70 +106 106 106 190 142 34 226 170 11 242 186 14 +246 190 14 246 190 14 246 190 14 154 114 10 + 6 6 6 74 74 74 226 226 226 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 231 231 231 250 250 250 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 228 184 62 +241 196 14 241 208 19 232 195 16 38 30 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 30 30 30 26 26 26 +203 166 17 154 142 90 66 66 66 26 26 26 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 38 38 38 58 58 58 + 78 78 78 86 86 86 101 101 101 123 123 123 +175 146 61 210 150 10 234 174 13 246 186 14 +246 190 14 246 190 14 246 190 14 238 190 10 +102 78 10 2 2 6 46 46 46 198 198 198 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 234 234 234 242 242 242 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 224 178 62 +242 186 14 241 196 14 210 166 10 22 18 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 6 6 6 121 92 8 +238 202 15 232 195 16 82 82 82 34 34 34 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 38 38 38 70 70 70 154 122 46 +190 142 34 200 144 11 197 138 11 197 138 11 +213 154 11 226 170 11 242 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +225 175 15 46 32 6 2 2 6 22 22 22 +158 158 158 250 250 250 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 250 250 250 242 242 242 224 178 62 +239 182 13 236 186 11 213 154 11 46 32 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 61 42 6 225 175 15 +238 190 10 236 186 11 112 100 78 42 42 42 + 14 14 14 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 54 54 54 154 122 46 213 154 11 +226 170 11 230 174 11 226 170 11 226 170 11 +236 178 12 242 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +241 196 14 184 144 12 10 10 10 2 2 6 + 6 6 6 116 116 116 242 242 242 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 231 231 231 198 198 198 214 170 54 +236 178 12 236 178 12 210 150 10 137 92 6 + 18 14 6 2 2 6 2 2 6 2 2 6 + 6 6 6 70 47 6 200 144 11 236 178 12 +239 182 13 239 182 13 124 112 88 58 58 58 + 22 22 22 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 70 70 70 180 133 36 226 170 11 +239 182 13 242 186 14 242 186 14 246 186 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 232 195 16 98 70 6 2 2 6 + 2 2 6 2 2 6 66 66 66 221 221 221 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 206 206 206 198 198 198 214 166 58 +230 174 11 230 174 11 216 158 10 192 133 9 +163 110 8 116 81 8 102 78 10 116 81 8 +167 114 7 197 138 11 226 170 11 239 182 13 +242 186 14 242 186 14 162 146 94 78 78 78 + 34 34 34 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 30 30 30 78 78 78 190 142 34 226 170 11 +239 182 13 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 241 196 14 203 166 17 22 18 6 + 2 2 6 2 2 6 2 2 6 38 38 38 +218 218 218 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 206 206 206 198 198 198 202 162 69 +226 170 11 236 178 12 224 166 10 210 150 10 +200 144 11 197 138 11 192 133 9 197 138 11 +210 150 10 226 170 11 242 186 14 246 190 14 +246 190 14 246 186 14 225 175 15 124 112 88 + 62 62 62 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 174 135 50 224 166 10 +239 182 13 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 241 196 14 139 102 15 + 2 2 6 2 2 6 2 2 6 2 2 6 + 78 78 78 250 250 250 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 214 214 214 198 198 198 190 150 46 +219 162 10 236 178 12 234 174 13 224 166 10 +216 158 10 213 154 11 213 154 11 216 158 10 +226 170 11 239 182 13 246 190 14 246 190 14 +246 190 14 246 190 14 242 186 14 206 162 42 +101 101 101 58 58 58 30 30 30 14 14 14 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 74 74 74 174 135 50 216 158 10 +236 178 12 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 241 196 14 226 184 13 + 61 42 6 2 2 6 2 2 6 2 2 6 + 22 22 22 238 238 238 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 226 226 226 187 187 187 180 133 36 +216 158 10 236 178 12 239 182 13 236 178 12 +230 174 11 226 170 11 226 170 11 230 174 11 +236 178 12 242 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 186 14 239 182 13 +206 162 42 106 106 106 66 66 66 34 34 34 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 26 26 26 70 70 70 163 133 67 213 154 11 +236 178 12 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 241 196 14 +190 146 13 18 14 6 2 2 6 2 2 6 + 46 46 46 246 246 246 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 221 221 221 86 86 86 156 107 11 +216 158 10 236 178 12 242 186 14 246 186 14 +242 186 14 239 182 13 239 182 13 242 186 14 +242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +242 186 14 225 175 15 142 122 72 66 66 66 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 26 26 26 70 70 70 163 133 67 210 150 10 +236 178 12 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +232 195 16 121 92 8 34 34 34 106 106 106 +221 221 221 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +242 242 242 82 82 82 18 14 6 163 110 8 +216 158 10 236 178 12 242 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 242 186 14 163 133 67 + 46 46 46 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 163 133 67 210 150 10 +236 178 12 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +241 196 14 215 174 15 190 178 144 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 218 218 218 + 58 58 58 2 2 6 22 18 6 167 114 7 +216 158 10 236 178 12 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 186 14 242 186 14 190 150 46 + 54 54 54 22 22 22 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 38 38 38 86 86 86 180 133 36 213 154 11 +236 178 12 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 232 195 16 190 146 13 214 214 214 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 250 250 250 170 170 170 26 26 26 + 2 2 6 2 2 6 37 26 9 163 110 8 +219 162 10 239 182 13 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 236 178 12 224 166 10 142 122 72 + 46 46 46 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 109 106 95 192 133 9 224 166 10 +242 186 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +242 186 14 226 184 13 210 162 10 142 110 46 +226 226 226 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +198 198 198 66 66 66 2 2 6 2 2 6 + 2 2 6 2 2 6 50 34 6 156 107 11 +219 162 10 239 182 13 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 242 186 14 +234 174 13 213 154 11 154 122 46 66 66 66 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 58 58 58 154 121 60 206 145 10 234 174 13 +242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 236 178 12 210 162 10 163 110 8 + 61 42 6 138 138 138 218 218 218 250 250 250 +253 253 253 253 253 253 253 253 253 250 250 250 +242 242 242 210 210 210 144 144 144 66 66 66 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 61 42 6 163 110 8 +216 158 10 236 178 12 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 239 182 13 230 174 11 216 158 10 +190 142 34 124 112 88 70 70 70 38 38 38 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 62 62 62 168 124 44 206 145 10 224 166 10 +236 178 12 239 182 13 242 186 14 242 186 14 +246 186 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 236 178 12 216 158 10 175 118 6 + 80 54 7 2 2 6 6 6 6 30 30 30 + 54 54 54 62 62 62 50 50 50 38 38 38 + 14 14 14 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 80 54 7 167 114 7 +213 154 11 236 178 12 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 242 186 14 239 182 13 239 182 13 +230 174 11 210 150 10 174 135 50 124 112 88 + 82 82 82 54 54 54 34 34 34 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 158 118 36 192 133 9 200 144 11 +216 158 10 219 162 10 224 166 10 226 170 11 +230 174 11 236 178 12 239 182 13 239 182 13 +242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 230 174 11 210 150 10 163 110 8 +104 69 6 10 10 10 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 91 60 6 167 114 7 +206 145 10 230 174 11 242 186 14 246 190 14 +246 190 14 246 190 14 246 186 14 242 186 14 +239 182 13 230 174 11 224 166 10 213 154 11 +180 133 36 124 112 88 86 86 86 58 58 58 + 38 38 38 22 22 22 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 34 34 34 70 70 70 138 110 50 158 118 36 +167 114 7 180 123 7 192 133 9 197 138 11 +200 144 11 206 145 10 213 154 11 219 162 10 +224 166 10 230 174 11 239 182 13 242 186 14 +246 186 14 246 186 14 246 186 14 246 186 14 +239 182 13 216 158 10 185 133 11 152 99 6 +104 69 6 18 14 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 80 54 7 152 99 6 +192 133 9 219 162 10 236 178 12 239 182 13 +246 186 14 242 186 14 239 182 13 236 178 12 +224 166 10 206 145 10 192 133 9 154 121 60 + 94 94 94 62 62 62 42 42 42 22 22 22 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 18 18 18 34 34 34 58 58 58 78 78 78 +101 98 89 124 112 88 142 110 46 156 107 11 +163 110 8 167 114 7 175 118 6 180 123 7 +185 133 11 197 138 11 210 150 10 219 162 10 +226 170 11 236 178 12 236 178 12 234 174 13 +219 162 10 197 138 11 163 110 8 130 83 6 + 91 60 6 10 10 10 2 2 6 2 2 6 + 18 18 18 38 38 38 38 38 38 38 38 38 + 38 38 38 38 38 38 38 38 38 38 38 38 + 38 38 38 38 38 38 26 26 26 2 2 6 + 2 2 6 6 6 6 70 47 6 137 92 6 +175 118 6 200 144 11 219 162 10 230 174 11 +234 174 13 230 174 11 219 162 10 210 150 10 +192 133 9 163 110 8 124 112 88 82 82 82 + 50 50 50 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 22 22 22 34 34 34 + 42 42 42 58 58 58 74 74 74 86 86 86 +101 98 89 122 102 70 130 98 46 121 87 25 +137 92 6 152 99 6 163 110 8 180 123 7 +185 133 11 197 138 11 206 145 10 200 144 11 +180 123 7 156 107 11 130 83 6 104 69 6 + 50 34 6 54 54 54 110 110 110 101 98 89 + 86 86 86 82 82 82 78 78 78 78 78 78 + 78 78 78 78 78 78 78 78 78 78 78 78 + 78 78 78 82 82 82 86 86 86 94 94 94 +106 106 106 101 101 101 86 66 34 124 80 6 +156 107 11 180 123 7 192 133 9 200 144 11 +206 145 10 200 144 11 192 133 9 175 118 6 +139 102 15 109 106 95 70 70 70 42 42 42 + 22 22 22 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 10 10 10 + 14 14 14 22 22 22 30 30 30 38 38 38 + 50 50 50 62 62 62 74 74 74 90 90 90 +101 98 89 112 100 78 121 87 25 124 80 6 +137 92 6 152 99 6 152 99 6 152 99 6 +138 86 6 124 80 6 98 70 6 86 66 30 +101 98 89 82 82 82 58 58 58 46 46 46 + 38 38 38 34 34 34 34 34 34 34 34 34 + 34 34 34 34 34 34 34 34 34 34 34 34 + 34 34 34 34 34 34 38 38 38 42 42 42 + 54 54 54 82 82 82 94 86 76 91 60 6 +134 86 6 156 107 11 167 114 7 175 118 6 +175 118 6 167 114 7 152 99 6 121 87 25 +101 98 89 62 62 62 34 34 34 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 6 6 6 10 10 10 + 18 18 18 22 22 22 30 30 30 42 42 42 + 50 50 50 66 66 66 86 86 86 101 98 89 +106 86 58 98 70 6 104 69 6 104 69 6 +104 69 6 91 60 6 82 62 34 90 90 90 + 62 62 62 38 38 38 22 22 22 14 14 14 + 10 10 10 10 10 10 10 10 10 10 10 10 + 10 10 10 10 10 10 6 6 6 10 10 10 + 10 10 10 10 10 10 10 10 10 14 14 14 + 22 22 22 42 42 42 70 70 70 89 81 66 + 80 54 7 104 69 6 124 80 6 137 92 6 +134 86 6 116 81 8 100 82 52 86 86 86 + 58 58 58 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 10 10 10 14 14 14 + 18 18 18 26 26 26 38 38 38 54 54 54 + 70 70 70 86 86 86 94 86 76 89 81 66 + 89 81 66 86 86 86 74 74 74 50 50 50 + 30 30 30 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 34 34 34 58 58 58 + 82 82 82 89 81 66 89 81 66 89 81 66 + 94 86 66 94 86 76 74 74 74 50 50 50 + 26 26 26 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 6 6 6 14 14 14 18 18 18 + 30 30 30 38 38 38 46 46 46 54 54 54 + 50 50 50 42 42 42 30 30 30 18 18 18 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 26 26 26 + 38 38 38 50 50 50 58 58 58 58 58 58 + 54 54 54 42 42 42 30 30 30 18 18 18 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 6 6 6 10 10 10 14 14 14 18 18 18 + 18 18 18 14 14 14 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 14 14 14 18 18 18 22 22 22 22 22 22 + 18 18 18 14 14 14 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/drivers/video/logo/logo_linux_mono.pbm b/drivers/video/logo/logo_linux_mono.pbm new file mode 100644 index 000000000000..2f14d9fedf6c --- /dev/null +++ b/drivers/video/logo/logo_linux_mono.pbm @@ -0,0 +1,203 @@ +P1 +# Standard black and white Linux logo +80 80 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 +1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 +1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 1 1 +1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +0 1 1 0 0 1 1 1 0 0 1 1 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 1 1 1 0 1 1 1 1 0 0 1 +1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 1 1 1 0 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 +1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +0 1 1 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 1 0 0 1 0 0 0 0 0 1 1 1 +1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 +1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 0 1 1 0 0 0 0 1 1 +1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 1 1 1 1 1 1 1 0 0 0 0 1 1 0 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 +1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 +0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 +1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 +0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 +1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1 +0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 +1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 +1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 +1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 +1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 +1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 1 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1 1 1 1 0 +0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 1 0 0 0 +0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 +1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 diff --git a/drivers/video/logo/logo_linux_vga16.ppm b/drivers/video/logo/logo_linux_vga16.ppm new file mode 100644 index 000000000000..1850c15e6feb --- /dev/null +++ b/drivers/video/logo/logo_linux_vga16.ppm @@ -0,0 +1,1604 @@ +P3 +# Standard 16-color Linux logo +80 80 +255 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 85 85 85 85 85 85 85 85 85 + 85 85 85 85 85 85 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 85 85 85 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 85 85 85 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 170 170 170 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 170 170 170 170 170 85 85 85 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 170 170 170 170 170 +170 170 170 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 85 85 85 170 170 170 170 170 170 170 170 170 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 170 170 170 255 255 255 255 255 255 +255 255 255 170 170 170 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 +170 170 170 170 170 170 255 255 255 255 255 255 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 170 170 255 255 255 170 170 170 170 170 170 +255 255 255 170 170 170 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 +170 170 170 0 0 0 0 0 0 255 255 255 + 85 85 85 0 0 0 0 0 0 0 0 0 +255 255 255 170 170 170 0 0 0 85 85 85 +170 170 170 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 + 85 85 85 0 0 0 0 0 0 170 170 170 + 85 85 85 0 0 0 0 0 0 0 0 0 +255 255 255 85 85 85 0 0 0 0 0 0 + 85 85 85 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 +170 170 170 0 0 0 0 0 0 170 170 170 + 85 85 85 85 85 85 85 85 85 85 85 85 +255 255 255 85 85 85 0 0 0 0 0 0 + 85 85 85 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 +255 255 255 0 0 0 0 0 0 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 0 0 0 0 0 0 + 85 85 85 255 255 255 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 +170 170 170 170 170 170 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 170 170 170 170 170 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 85 85 85 0 0 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 85 85 85 0 0 0 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 170 85 0 +170 85 0 170 85 0 85 85 85 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 85 85 85 0 0 0 + 85 85 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 85 85 85 0 0 0 + 0 0 0 85 85 85 170 170 170 85 85 85 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 85 85 85 0 0 0 + 85 85 85 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 170 170 170 170 170 170 170 170 0 0 0 + 0 0 0 0 0 0 170 170 170 170 170 170 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 85 85 85 170 170 170 170 85 0 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 85 85 85 + 0 0 0 0 0 0 85 85 85 85 85 85 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 85 85 85 170 170 170 170 170 170 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 170 170 170 170 170 170 170 170 170 170 170 +255 255 255 255 255 255 255 255 255 170 170 170 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 85 85 85 +255 255 255 255 255 255 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 170 170 170 +255 255 255 255 255 255 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 85 85 85 255 255 255 +255 255 255 255 255 255 255 255 255 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 85 85 85 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 85 85 85 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 170 170 170 170 170 170 170 170 170 +255 255 255 255 255 255 255 255 255 170 170 170 +170 170 170 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 170 170 170 170 170 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 85 85 85 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 170 170 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 170 170 170 + 0 0 0 0 0 0 0 0 0 85 85 85 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 85 85 85 0 0 0 0 0 0 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 170 170 170 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 170 170 170 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 + 0 0 0 0 0 0 85 85 85 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 0 0 0 85 85 85 + 85 85 85 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 + 0 0 0 85 85 85 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 0 0 0 85 85 85 + 85 85 85 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 85 85 85 + 0 0 0 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 85 85 85 0 0 0 + 0 0 0 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 85 85 85 0 0 0 + 85 85 85 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 85 85 85 0 0 0 0 0 0 +170 170 170 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 0 0 + 85 85 85 85 85 85 85 85 85 85 85 85 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 170 85 0 +255 255 85 170 85 0 0 0 0 0 0 0 + 85 85 85 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 85 85 85 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 0 0 0 + 0 0 0 85 85 85 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 85 170 85 0 255 255 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 85 85 85 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 + 0 0 0 0 0 0 85 85 85 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 85 +170 85 0 255 255 85 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 85 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 0 0 0 0 0 0 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 170 85 0 +255 255 85 170 85 0 255 255 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 170 85 0 +255 255 85 170 85 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 0 0 0 0 0 0 0 0 0 + 85 85 85 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 85 +170 85 0 255 255 85 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 255 255 85 +170 85 0 255 255 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 0 0 0 0 0 0 + 0 0 0 85 85 85 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 255 255 85 170 85 0 +255 255 85 170 85 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 0 0 0 + 0 0 0 0 0 0 85 85 85 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 0 0 0 0 0 0 0 0 0 + 0 0 0 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 0 0 0 0 0 0 0 0 0 + 85 85 85 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 85 85 85 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 85 85 85 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 85 85 85 85 85 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 170 170 170 + 85 85 85 0 0 0 0 0 0 170 85 0 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 85 85 85 + 0 0 0 0 0 0 0 0 0 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +170 170 170 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 85 85 85 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 170 85 0 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 170 85 0 +170 85 0 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 85 85 85 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +170 85 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 170 85 0 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 170 85 0 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 170 85 0 +170 85 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +170 85 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +170 85 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 170 85 0 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 170 85 0 170 85 0 170 85 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 85 0 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 170 85 0 +170 85 0 0 0 0 0 0 0 0 0 0 + 85 85 85 85 85 85 85 85 85 85 85 85 + 85 85 85 85 85 85 85 85 85 85 85 85 + 85 85 85 85 85 85 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 170 85 0 +170 85 0 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +170 85 0 170 85 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 85 0 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 170 85 0 170 85 0 + 85 85 85 85 85 85 85 85 85 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 85 85 85 85 85 85 85 85 85 170 85 0 +170 85 0 170 85 0 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 170 85 0 +170 85 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/drivers/video/logo/logo_mac_clut224.ppm b/drivers/video/logo/logo_mac_clut224.ppm new file mode 100644 index 000000000000..4dad34baea89 --- /dev/null +++ b/drivers/video/logo/logo_mac_clut224.ppm @@ -0,0 +1,1604 @@ +P3 +# 224-color Macintosh Linux logo +80 80 +255 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 6 6 6 10 10 10 10 10 10 + 10 10 10 6 6 6 6 6 6 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 10 10 10 14 14 14 + 22 22 22 26 26 26 30 30 30 34 34 34 + 30 30 30 30 30 30 26 26 26 18 18 18 + 14 14 14 10 10 10 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 26 26 26 42 42 42 + 54 54 54 66 66 66 78 78 78 78 78 78 + 78 78 78 74 74 74 66 66 66 54 54 54 + 42 42 42 26 26 26 18 18 18 10 10 10 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 22 22 22 42 42 42 66 66 66 86 86 86 + 66 66 66 38 38 38 38 38 38 22 22 22 + 26 26 26 34 34 34 54 54 54 66 66 66 + 86 86 86 70 70 70 46 46 46 26 26 26 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 26 26 26 + 50 50 50 82 82 82 58 58 58 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 54 54 54 86 86 86 66 66 66 + 38 38 38 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 22 22 22 50 50 50 + 78 78 78 34 34 34 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 6 6 6 70 70 70 + 78 78 78 46 46 46 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 250 250 250 +250 250 250 250 250 250 250 250 250 242 242 242 +250 250 250 250 250 250 246 246 246 250 250 250 +246 246 246 242 242 242 246 246 246 231 231 231 + 46 46 46 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 14 14 14 + 46 46 46 34 34 34 6 6 6 2 2 6 + 82 82 82 242 242 242 242 242 242 246 246 246 +242 242 242 250 250 250 242 242 242 246 246 246 +242 242 242 250 250 250 242 242 242 250 250 250 +250 250 250 250 250 250 250 250 250 250 250 250 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 242 242 242 +250 250 250 250 250 250 250 250 250 250 250 250 +242 242 242 246 246 246 250 250 250 250 250 250 +250 250 250 250 250 250 242 242 242 116 116 116 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 26 26 26 + 86 86 86 101 101 101 46 46 46 10 10 10 + 2 2 6 123 123 123 242 242 242 250 250 250 +246 246 246 250 250 250 242 242 242 250 250 250 +246 246 246 250 250 250 242 242 242 250 250 250 +242 242 242 250 250 250 250 250 250 250 250 250 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 123 123 123 +234 234 234 231 231 231 234 234 234 234 234 234 +234 234 234 221 221 221 234 234 234 231 231 231 +234 234 234 234 234 234 214 214 214 10 10 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 30 30 30 + 94 94 94 94 94 94 58 58 58 26 26 26 + 2 2 6 10 10 10 190 190 190 242 242 242 +242 242 242 250 250 250 250 250 250 242 242 242 +246 246 246 250 250 250 250 250 250 242 242 242 +250 250 250 242 242 242 242 242 242 231 231 231 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 90 90 90 +234 234 234 226 226 226 226 226 226 218 218 218 +226 226 226 214 214 214 231 231 231 221 221 221 +231 231 231 221 221 221 116 116 116 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 26 26 26 + 54 54 54 38 38 38 18 18 18 10 10 10 + 2 2 6 2 2 6 58 58 58 242 242 242 +242 242 242 242 242 242 242 242 242 242 242 242 +242 242 242 242 242 242 242 242 242 242 242 242 +242 242 242 242 242 242 250 250 250 226 226 226 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 82 82 82 +234 234 234 231 231 231 242 242 242 242 242 242 +234 234 234 234 234 234 238 238 238 234 234 234 +238 238 238 238 238 238 50 50 50 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 10 10 10 + 10 10 10 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 182 182 182 +242 242 242 250 250 250 250 250 250 250 250 250 +242 242 242 250 250 250 250 250 250 250 250 250 +242 242 242 242 242 242 250 250 250 206 206 206 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 50 50 50 +250 250 250 226 226 226 234 234 234 10 10 10 + 78 78 78 66 66 66 101 98 89 90 90 90 +110 110 110 106 106 106 10 10 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 101 98 89 +210 210 210 238 238 238 226 226 226 238 238 238 +210 210 210 242 242 242 226 226 226 242 242 242 +242 242 242 234 234 234 250 250 250 198 198 198 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 82 82 82 +234 234 234 234 234 234 231 231 231 2 2 6 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 82 82 82 2 2 6 2 2 6 + 2 2 6 6 6 6 10 10 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 6 6 6 + 14 14 14 10 10 10 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 18 18 18 + 82 82 82 34 34 34 10 10 10 0 0 0 + 6 6 6 0 0 0 0 0 0 0 0 0 +144 144 144 250 250 250 242 242 242 202 202 202 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 82 82 82 +226 226 226 231 231 231 234 234 234 90 90 90 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 2 2 6 + 6 6 6 6 6 6 22 22 22 34 34 34 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 34 34 34 + 10 10 10 50 50 50 22 22 22 2 2 6 + 2 2 6 2 2 6 2 2 6 10 10 10 + 86 86 86 42 42 42 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 +158 158 158 242 242 242 234 234 234 187 187 187 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 66 66 66 +231 231 231 226 226 226 226 226 226 178 178 178 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 2 2 6 + 38 38 38 116 116 116 94 94 94 22 22 22 + 22 22 22 2 2 6 2 2 6 2 2 6 + 14 14 14 86 86 86 138 138 138 162 162 162 +154 154 154 38 38 38 26 26 26 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 86 86 86 46 46 46 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 +187 187 187 234 234 234 250 250 250 190 190 190 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 82 82 82 +226 226 226 218 218 218 234 234 234 218 218 218 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 14 14 14 +134 134 134 198 198 198 195 195 195 116 116 116 + 10 10 10 2 2 6 2 2 6 6 6 6 +101 98 89 187 187 187 210 210 210 218 218 218 +214 214 214 134 134 134 14 14 14 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 86 86 86 50 50 50 18 18 18 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 +214 214 214 226 226 226 242 242 242 187 187 187 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 74 74 74 +226 226 226 214 214 214 226 226 226 190 190 190 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 54 54 54 +218 218 218 195 195 195 226 226 226 246 246 246 + 58 58 58 2 2 6 2 2 6 30 30 30 +210 210 210 253 253 253 174 174 174 123 123 123 +221 221 221 234 234 234 74 74 74 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 +195 195 195 226 226 226 234 234 234 206 206 206 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 62 62 62 +226 226 226 218 218 218 234 234 234 226 226 226 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 82 82 82 2 2 6 106 106 106 +170 170 170 26 26 26 86 86 86 226 226 226 +123 123 123 10 10 10 14 14 14 46 46 46 +231 231 231 190 190 190 6 6 6 70 70 70 + 90 90 90 238 238 238 158 158 158 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 +182 182 182 234 234 234 242 242 242 158 158 158 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 101 98 89 +214 214 214 214 214 214 226 226 226 242 242 242 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 86 86 86 6 6 6 116 116 116 +106 106 106 6 6 6 70 70 70 149 149 149 +128 128 128 18 18 18 38 38 38 54 54 54 +221 221 221 106 106 106 2 2 6 14 14 14 + 46 46 46 190 190 190 198 198 198 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 62 62 62 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 +190 190 190 226 226 226 226 226 226 178 178 178 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 66 66 66 +210 210 210 214 214 214 210 210 210 250 250 250 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 94 94 94 14 14 14 101 101 101 +128 128 128 2 2 6 18 18 18 116 116 116 +118 98 46 121 92 8 121 92 8 98 78 10 +162 162 162 106 106 106 2 2 6 2 2 6 + 2 2 6 195 195 195 195 195 195 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 62 62 62 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 +214 214 214 226 226 226 231 231 231 149 149 149 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 1 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 42 42 42 +226 226 226 218 218 218 210 210 210 231 231 231 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 90 90 90 14 14 14 58 58 58 +210 210 210 26 26 26 54 38 6 154 114 10 +226 170 11 236 186 11 225 175 15 184 144 12 +215 174 15 175 146 61 37 26 9 2 2 6 + 70 70 70 246 246 246 138 138 138 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 66 66 66 26 26 26 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 +178 178 178 218 218 218 226 226 226 162 162 162 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 42 42 42 +214 214 214 198 198 198 210 210 210 242 242 242 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 14 14 14 10 10 10 +195 195 195 188 164 115 192 133 9 225 175 15 +239 182 13 234 190 10 232 195 16 232 200 30 +245 207 45 241 208 19 232 195 16 184 144 12 +218 194 134 211 206 186 42 42 42 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 50 50 50 74 74 74 30 30 30 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 +187 187 187 231 231 231 226 226 226 182 182 182 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 66 66 66 +218 218 218 210 210 210 210 210 210 242 242 242 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 86 86 86 14 14 14 2 2 6 +121 87 25 192 133 9 219 162 10 239 182 13 +236 186 11 232 195 16 241 208 19 244 214 54 +246 218 60 246 218 38 246 215 20 241 208 19 +241 208 19 226 184 13 121 87 25 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 50 50 50 82 82 82 34 34 34 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 +162 162 162 226 226 226 226 226 226 162 162 162 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 62 62 62 +206 206 206 206 206 206 202 202 202 250 250 250 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 82 82 82 30 30 30 61 42 6 +180 123 7 206 145 10 230 174 11 239 182 13 +234 190 10 238 202 15 241 208 19 246 218 74 +246 218 38 246 215 20 246 215 20 246 215 20 +226 184 13 215 174 15 184 144 12 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 26 26 26 94 94 94 42 42 42 14 14 14 + 0 0 0 0 0 0 0 0 0 0 0 0 +166 166 166 226 226 226 214 214 214 170 170 170 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 66 66 66 +226 226 226 218 218 218 202 202 202 242 242 242 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 50 50 50 104 69 6 +192 133 9 216 158 10 236 178 12 236 186 11 +232 195 16 241 208 19 244 214 54 245 215 43 +246 215 20 246 215 20 241 208 19 198 155 10 +200 144 11 216 158 10 156 118 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 90 90 90 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 +178 178 178 226 226 226 226 226 226 158 158 158 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 62 62 62 +214 214 214 198 198 198 202 202 202 242 242 242 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 46 46 46 22 22 22 +137 92 6 210 162 10 239 182 13 238 190 10 +238 202 15 241 208 19 246 215 20 246 215 20 +241 208 19 203 166 17 185 133 11 210 150 10 +216 158 10 210 150 10 102 78 10 2 2 6 + 6 6 6 54 54 54 14 14 14 2 2 6 + 2 2 6 62 62 62 74 74 74 30 30 30 + 10 10 10 0 0 0 0 0 0 0 0 0 +190 190 190 214 214 214 242 242 242 158 158 158 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 66 66 66 +210 210 210 202 202 202 202 202 202 242 242 242 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 78 78 78 50 50 50 6 6 6 + 94 70 30 139 102 15 190 146 13 226 184 13 +232 200 30 232 195 16 215 174 15 190 146 13 +168 122 10 192 133 9 210 150 10 213 154 11 +202 150 34 182 157 106 101 98 89 2 2 6 + 2 2 6 78 78 78 116 116 116 58 58 58 + 2 2 6 22 22 22 90 90 90 46 46 46 + 18 18 18 6 6 6 0 0 0 0 0 0 +195 195 195 214 214 214 226 226 226 162 162 162 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 82 82 82 +198 198 198 190 190 190 187 187 187 242 242 242 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 50 50 50 6 6 6 +128 128 128 174 154 114 156 107 11 168 122 10 +198 155 10 184 144 12 197 138 11 200 144 11 +206 145 10 206 145 10 197 138 11 188 164 115 +195 195 195 198 198 198 174 174 174 14 14 14 + 2 2 6 22 22 22 116 116 116 116 116 116 + 22 22 22 2 2 6 74 74 74 70 70 70 + 30 30 30 10 10 10 0 0 0 0 0 0 +178 178 178 226 226 226 226 226 226 141 141 141 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 62 62 62 +195 195 195 195 195 195 195 195 195 250 250 250 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 101 101 101 26 26 26 10 10 10 +138 138 138 190 190 190 174 154 114 156 107 11 +197 138 11 200 144 11 197 138 11 192 133 9 +180 123 7 190 142 34 190 178 144 187 187 187 +202 202 202 221 221 221 214 214 214 66 66 66 + 2 2 6 2 2 6 50 50 50 62 62 62 + 6 6 6 2 2 6 10 10 10 90 90 90 + 50 50 50 18 18 18 6 6 6 0 0 0 +190 190 190 226 226 226 250 250 250 202 202 202 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 42 42 42 +187 187 187 190 190 190 187 187 187 250 250 250 + 0 0 0 0 0 0 10 10 10 34 34 34 + 74 74 74 74 74 74 2 2 6 6 6 6 +144 144 144 198 198 198 190 190 190 178 166 146 +154 121 60 156 107 11 156 107 11 168 124 44 +174 154 114 187 187 187 190 190 190 210 210 210 +246 246 246 253 253 253 253 253 253 182 182 182 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 62 62 62 + 74 74 74 34 34 34 14 14 14 0 0 0 +174 174 174 206 206 206 242 242 242 158 158 158 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 42 42 42 +190 190 190 187 187 187 190 190 190 234 234 234 + 0 0 0 10 10 10 22 22 22 54 54 54 + 94 94 94 18 18 18 2 2 6 46 46 46 +234 234 234 221 221 221 190 190 190 190 190 190 +190 190 190 187 187 187 187 187 187 190 190 190 +190 190 190 195 195 195 214 214 214 242 242 242 +253 253 253 253 253 253 253 253 253 253 253 253 + 82 82 82 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 14 14 14 + 86 86 86 54 54 54 22 22 22 6 6 6 +195 195 195 202 202 202 234 234 234 138 138 138 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 50 50 50 +182 182 182 187 187 187 178 178 178 242 242 242 + 6 6 6 18 18 18 46 46 46 90 90 90 + 46 46 46 18 18 18 6 6 6 182 182 182 +253 253 253 246 246 246 206 206 206 190 190 190 +190 190 190 190 190 190 190 190 190 190 190 190 +206 206 206 231 231 231 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +202 202 202 14 14 14 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 42 42 42 86 86 86 42 42 42 18 18 18 +190 190 190 202 202 202 226 226 226 178 178 178 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 62 62 62 +195 195 195 182 182 182 187 187 187 250 250 250 + 14 14 14 38 38 38 74 74 74 66 66 66 + 2 2 6 6 6 6 90 90 90 250 250 250 +253 253 253 253 253 253 238 238 238 198 198 198 +190 190 190 190 190 190 195 195 195 221 221 221 +246 246 246 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 82 82 82 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 78 78 78 70 70 70 34 34 34 +202 202 202 182 182 182 242 242 242 158 158 158 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 26 26 26 +195 195 195 182 182 182 178 178 178 242 242 242 + 34 34 34 66 66 66 78 78 78 6 6 6 + 2 2 6 18 18 18 218 218 218 253 253 253 +253 253 253 253 253 253 253 253 253 246 246 246 +226 226 226 231 231 231 246 246 246 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 178 178 178 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 18 18 18 90 90 90 62 62 62 +218 218 218 198 198 198 250 250 250 141 141 141 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 42 42 42 +182 182 182 178 178 178 174 174 174 250 250 250 + 58 58 58 90 90 90 18 18 18 2 2 6 + 2 2 6 110 110 110 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 231 231 231 18 18 18 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 94 94 94 +206 206 206 198 198 198 242 242 242 162 162 162 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 42 42 42 +166 166 166 170 170 170 187 187 187 242 242 242 + 90 90 90 26 26 26 2 2 6 2 2 6 + 14 14 14 195 195 195 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 242 242 242 54 54 54 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 38 38 38 +187 187 187 214 214 214 231 231 231 134 134 134 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 50 50 50 +187 187 187 182 182 182 166 166 166 234 234 234 + 34 34 34 2 2 6 2 2 6 2 2 6 + 42 42 42 195 195 195 246 246 246 253 253 253 +253 253 253 253 253 253 253 253 253 250 250 250 +242 242 242 242 242 242 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 250 250 250 246 246 246 238 238 238 +226 226 226 231 231 231 101 101 101 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 +206 206 206 174 174 174 250 250 250 128 128 128 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 34 34 34 +178 178 178 144 144 144 170 170 170 226 226 226 + 2 2 6 2 2 6 2 2 6 6 6 6 + 70 70 70 170 170 170 206 206 206 234 234 234 +246 246 246 250 250 250 250 250 250 238 238 238 +226 226 226 231 231 231 238 238 238 250 250 250 +250 250 250 250 250 250 246 246 246 231 231 231 +214 214 214 206 206 206 202 202 202 202 202 202 +198 198 198 202 202 202 182 182 182 18 18 18 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 +202 202 202 166 166 166 214 214 214 128 128 128 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 50 50 50 +178 178 178 158 158 158 134 134 134 242 242 242 + 2 2 6 2 2 6 2 2 6 10 10 10 + 94 94 94 182 182 182 218 218 218 242 242 242 +250 250 250 253 253 253 253 253 253 250 250 250 +234 234 234 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 246 246 246 +238 238 238 226 226 226 210 210 210 202 202 202 +195 195 195 195 195 195 210 210 210 158 158 158 + 6 6 6 14 14 14 50 50 50 14 14 14 + 2 2 6 2 2 6 2 2 6 2 2 6 +198 198 198 187 187 187 246 246 246 116 116 116 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 50 50 50 +195 195 195 154 154 154 154 154 154 250 250 250 +250 250 250 250 250 250 242 242 242 242 242 242 +242 242 242 250 250 250 250 250 250 250 250 250 +250 250 250 250 250 250 242 242 242 250 250 250 +250 250 250 250 250 250 242 242 242 250 250 250 +250 250 250 250 250 250 250 250 250 246 246 246 +234 234 234 250 250 250 242 242 242 242 242 242 +242 242 242 250 250 250 242 242 242 242 242 242 +242 242 242 250 250 250 242 242 242 242 242 242 +250 250 250 242 242 242 242 242 242 250 250 250 +182 182 182 190 190 190 206 206 206 141 141 141 + 26 26 26 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 50 50 50 +170 170 170 166 166 166 128 128 128 250 250 250 +242 242 242 250 250 250 250 250 250 242 242 242 +250 250 250 242 242 242 242 242 242 250 250 250 +242 242 242 250 250 250 250 250 250 250 250 250 +250 250 250 250 250 250 242 242 242 250 250 250 +242 242 242 250 250 250 242 242 242 250 250 250 +250 250 250 242 242 242 250 250 250 250 250 250 +242 242 242 250 250 250 250 250 250 250 250 250 +242 242 242 242 242 242 250 250 250 234 234 234 +250 250 250 242 242 242 242 242 242 250 250 250 +195 195 195 195 195 195 206 206 206 128 128 128 + 42 42 42 14 14 14 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 50 50 50 +178 178 178 174 174 174 158 158 158 170 170 170 +162 162 162 170 170 170 170 170 170 162 162 162 +166 166 166 170 170 170 154 154 154 154 154 154 +178 178 178 162 162 162 166 166 166 166 166 166 +166 166 166 158 158 158 178 178 178 162 162 162 +170 170 170 174 174 174 178 178 178 178 178 178 +170 170 170 178 178 178 170 170 170 166 166 166 +170 170 170 182 182 182 187 187 187 178 178 178 +195 195 195 195 195 195 195 195 195 195 195 195 +187 187 187 195 195 195 178 178 178 195 195 195 +206 206 206 195 195 195 210 210 210 116 116 116 + 58 58 58 22 22 22 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 50 50 50 +162 162 162 162 162 162 170 170 170 158 158 158 +162 162 162 158 158 158 162 162 162 166 166 166 +158 158 158 174 174 174 162 162 162 158 158 158 +170 170 170 166 166 166 166 166 166 174 174 174 +166 166 166 174 174 174 174 174 174 174 174 174 +174 174 174 182 182 182 166 166 166 187 187 187 +182 182 182 187 187 187 174 174 174 166 166 166 +166 166 166 187 187 187 182 182 182 158 158 158 +174 174 174 174 174 174 174 174 174 182 182 182 +182 182 182 182 182 182 178 178 178 195 195 195 +178 178 178 182 182 182 174 174 174 30 30 30 + 78 78 78 30 30 30 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 34 34 34 +154 154 154 158 158 158 154 154 154 158 158 158 +154 154 154 166 166 166 162 162 162 178 178 178 +178 178 178 166 166 166 170 170 170 158 158 158 +170 170 170 178 178 178 178 178 178 187 187 187 +195 195 195 178 178 178 178 178 178 178 178 178 +162 162 162 187 187 187 166 166 166 178 178 178 +174 174 174 178 178 178 170 170 170 170 170 170 +174 174 174 170 170 170 187 187 187 178 178 178 +178 178 178 202 202 202 170 170 170 187 187 187 +178 178 178 182 182 182 174 174 174 190 190 190 +182 182 182 166 166 166 149 149 149 6 6 6 + 86 86 86 46 46 46 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 50 50 50 +166 166 166 162 162 162 149 149 149 162 162 162 +158 158 158 170 170 170 158 158 158 158 158 158 +166 166 166 170 170 170 149 149 149 170 170 170 +158 158 158 174 174 174 166 166 166 166 166 166 +166 166 166 166 166 166 182 182 182 158 158 158 +158 158 158 174 174 174 170 170 170 158 158 158 +178 178 178 166 166 166 158 158 158 174 174 174 +170 170 170 166 166 166 174 174 174 166 166 166 +174 174 174 182 182 182 174 174 174 182 182 182 +174 174 174 178 178 178 187 187 187 206 206 206 +187 187 187 178 178 178 128 128 128 2 2 6 + 74 74 74 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 10 10 10 26 26 26 42 42 42 +158 158 158 144 144 144 149 149 149 162 162 162 +149 149 149 170 170 170 170 170 170 170 170 170 +174 174 174 170 170 170 158 158 158 162 162 162 +170 170 170 162 162 162 170 170 170 170 170 170 +162 162 162 162 162 162 170 170 170 170 170 170 +170 170 170 166 166 166 154 154 154 166 166 166 +154 154 154 162 162 162 170 170 170 149 149 149 +170 170 170 144 144 144 187 187 187 170 170 170 +170 170 170 195 195 195 187 187 187 202 202 202 +198 198 198 182 182 182 202 202 202 210 210 210 +187 187 187 178 178 178 106 106 106 2 2 6 + 42 42 42 74 74 74 30 30 30 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 42 42 42 42 42 42 +158 158 158 141 141 141 162 162 162 149 149 149 +154 154 154 158 158 158 166 166 166 174 174 174 +162 162 162 158 158 158 162 162 162 158 158 158 +158 158 158 158 158 158 166 166 166 166 166 166 +158 158 158 158 158 158 158 158 158 166 166 166 +166 166 166 170 170 170 182 182 182 187 187 187 +166 166 166 174 174 174 166 166 166 154 154 154 +174 174 174 174 174 174 166 166 166 190 190 190 + 34 34 34 2 2 6 18 18 18 2 2 6 + 34 34 34 2 2 6 18 18 18 78 78 78 +182 182 182 178 178 178 78 78 78 2 2 6 + 10 10 10 86 86 86 38 38 38 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 26 26 26 66 66 66 30 30 30 +138 138 138 144 144 144 154 154 154 149 149 149 +154 154 154 154 154 154 154 154 154 166 166 166 +162 162 162 158 158 158 162 162 162 154 154 154 +170 170 170 154 154 154 178 178 178 162 162 162 +162 162 162 170 170 170 162 162 162 154 154 154 + 2 2 6 2 2 6 34 34 34 42 42 42 + 42 42 42 34 34 34 22 18 6 34 34 34 + 42 42 42 42 42 42 66 66 66 34 34 34 +128 128 128 10 10 10 10 10 10 18 18 18 + 18 18 18 10 10 10 26 26 26 174 174 174 +187 187 187 138 138 138 34 34 34 2 2 6 + 6 6 6 86 86 86 46 46 46 14 14 14 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 18 18 18 46 46 46 86 86 86 6 6 6 +110 110 110 162 162 162 149 149 149 144 144 144 +149 149 149 166 166 166 149 149 149 162 162 162 +149 149 149 162 162 162 149 149 149 158 158 158 +166 166 166 158 158 158 158 158 158 166 166 166 +166 166 166 149 149 149 158 158 158 166 166 166 +128 128 128 18 18 18 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 22 18 6 26 26 26 + 18 18 18 6 6 6 18 18 18 166 166 166 +174 174 174 110 110 110 18 18 18 2 2 6 + 2 2 6 82 82 82 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 26 26 26 66 66 66 62 62 62 2 2 6 + 46 46 46 141 141 141 166 166 166 144 144 144 +154 154 154 170 170 170 158 158 158 162 162 162 +149 149 149 162 162 162 154 154 154 154 154 154 +162 162 162 144 144 144 162 162 162 154 154 154 +170 170 170 144 144 144 154 154 154 170 170 170 +116 116 116 144 144 144 110 110 110 116 116 116 +110 110 110 144 144 144 116 116 116 128 128 128 +134 134 134 116 116 116 134 134 134 149 149 149 +158 158 158 231 231 231 234 234 234 214 214 214 +202 202 202 195 195 195 166 166 166 144 144 144 +144 144 144 34 34 34 2 2 6 2 2 6 + 2 2 6 66 66 66 58 58 58 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 78 78 78 6 6 6 2 2 6 + 14 14 14 123 123 123 138 138 138 90 90 90 +110 110 110 128 128 128 154 154 154 149 149 149 +144 144 144 149 149 149 158 158 158 149 149 149 +166 166 166 158 158 158 158 158 158 166 166 166 +158 158 158 158 158 158 158 158 158 158 158 158 +144 144 144 170 170 170 162 162 162 170 170 170 +187 187 187 174 174 174 170 170 170 170 170 170 +162 162 162 170 170 170 170 170 170 178 178 178 +187 187 187 190 190 190 170 170 170 149 149 149 +149 149 149 138 138 138 170 170 170 116 116 116 + 18 18 18 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 62 62 62 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 74 74 74 2 2 6 2 2 6 + 14 14 14 94 94 94 134 134 134 74 74 74 + 50 50 50 158 158 158 154 154 154 166 166 166 +162 162 162 170 170 170 162 162 162 178 178 178 +170 170 170 154 154 154 162 162 162 154 154 154 +154 154 154 154 154 154 170 170 170 141 141 141 +149 149 149 166 166 166 166 166 166 166 166 166 +178 178 178 174 174 174 158 158 158 174 174 174 +174 174 174 174 174 174 174 174 174 158 158 158 +166 166 166 166 166 166 170 170 170 170 170 170 +170 170 170 162 162 162 82 82 82 10 10 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 62 62 62 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 54 54 54 62 62 62 2 2 6 2 2 6 + 2 2 6 34 34 34 123 123 123 18 18 18 + 22 18 6 128 128 128 149 149 149 154 154 154 +158 158 158 158 158 158 149 149 149 166 166 166 +166 166 166 158 158 158 158 158 158 182 182 182 +158 158 158 149 149 149 149 149 149 178 178 178 +162 162 162 170 170 170 170 170 170 170 170 170 +174 174 174 178 178 178 170 170 170 178 178 178 +170 170 170 178 178 178 178 178 178 162 162 162 +174 174 174 170 170 170 166 166 166 166 166 166 +141 141 141 50 50 50 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 58 58 58 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 58 58 58 62 62 62 2 2 6 2 2 6 + 2 2 6 2 2 6 38 38 38 144 144 144 +178 178 178 162 162 162 134 134 134 154 154 154 +154 154 154 154 154 154 154 154 154 170 170 170 +154 154 154 154 154 154 162 162 162 170 170 170 +162 162 162 154 154 154 158 158 158 174 174 174 +149 149 149 166 166 166 174 174 174 178 178 178 +174 174 174 174 174 174 166 166 166 174 174 174 +166 166 166 166 166 166 166 166 166 166 166 166 +170 170 170 170 170 170 166 166 166 138 138 138 + 42 42 42 34 34 34 18 14 6 22 22 22 + 26 26 26 18 18 18 6 6 6 2 2 6 + 2 2 6 82 82 82 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 26 26 26 + 62 62 62 106 106 106 74 54 14 185 133 11 +210 162 10 121 92 8 6 6 6 78 78 78 +154 154 154 149 149 149 141 141 141 149 149 149 +149 149 149 149 149 149 158 158 158 141 141 141 +149 149 149 141 141 141 158 158 158 149 149 149 +149 149 149 149 149 149 162 162 162 170 170 170 +154 154 154 170 170 170 162 162 162 166 166 166 +170 170 170 170 170 170 170 170 170 162 162 162 +162 162 162 170 170 170 170 170 170 170 170 170 +170 170 170 162 162 162 162 162 162 38 38 38 + 14 14 14 2 2 6 2 2 6 2 2 6 + 6 6 6 18 18 18 66 66 66 38 38 38 + 6 6 6 94 94 94 50 50 50 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 10 10 10 10 10 10 18 18 18 38 38 38 + 78 78 78 142 134 106 216 158 10 242 186 14 +246 190 14 246 190 14 156 118 10 10 10 10 +116 116 116 182 182 182 138 138 138 154 154 154 +154 154 154 138 138 138 162 162 162 170 170 170 +178 178 178 138 138 138 162 162 162 162 162 162 +162 162 162 158 158 158 149 149 149 174 174 174 +134 134 134 174 174 174 170 170 170 158 158 158 +158 158 158 174 174 174 141 141 141 174 174 174 +149 149 149 166 166 166 158 158 158 174 174 174 +141 141 141 178 178 178 175 146 61 37 26 9 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 38 38 38 46 46 46 + 26 26 26 106 106 106 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 22 22 22 + 30 30 30 38 38 38 50 50 50 70 70 70 +106 106 106 190 142 34 226 170 11 242 186 14 +246 190 14 246 190 14 246 190 14 154 114 10 + 6 6 6 74 74 74 226 226 226 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 231 231 231 250 250 250 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 228 184 62 +241 196 14 241 208 19 232 195 16 38 30 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 30 30 30 26 26 26 +203 166 17 154 142 90 66 66 66 26 26 26 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 38 38 38 58 58 58 + 78 78 78 86 86 86 101 101 101 123 123 123 +175 146 61 210 150 10 234 174 13 246 186 14 +246 190 14 246 190 14 246 190 14 238 190 10 +102 78 10 2 2 6 46 46 46 198 198 198 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 234 234 234 242 242 242 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 224 178 62 +242 186 14 241 196 14 210 166 10 22 18 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 6 6 6 121 92 8 +238 202 15 232 195 16 82 82 82 34 34 34 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 38 38 38 70 70 70 154 122 46 +190 142 34 200 144 11 197 138 11 197 138 11 +213 154 11 226 170 11 242 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +225 175 15 46 32 6 2 2 6 22 22 22 +158 158 158 250 250 250 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 250 250 250 242 242 242 224 178 62 +239 182 13 236 186 11 213 154 11 46 32 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 61 42 6 225 175 15 +238 190 10 236 186 11 112 100 78 42 42 42 + 14 14 14 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 54 54 54 154 122 46 213 154 11 +226 170 11 230 174 11 226 170 11 226 170 11 +236 178 12 242 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +241 196 14 184 144 12 10 10 10 2 2 6 + 6 6 6 116 116 116 242 242 242 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 231 231 231 198 198 198 214 170 54 +236 178 12 236 178 12 210 150 10 137 92 6 + 18 14 6 2 2 6 2 2 6 2 2 6 + 6 6 6 70 47 6 200 144 11 236 178 12 +239 182 13 239 182 13 124 112 88 58 58 58 + 22 22 22 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 70 70 70 180 133 36 226 170 11 +239 182 13 242 186 14 242 186 14 246 186 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 232 195 16 98 70 6 2 2 6 + 2 2 6 2 2 6 66 66 66 221 221 221 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 206 206 206 198 198 198 214 166 58 +230 174 11 230 174 11 216 158 10 192 133 9 +163 110 8 116 81 8 102 78 10 116 81 8 +167 114 7 197 138 11 226 170 11 239 182 13 +242 186 14 242 186 14 162 146 94 78 78 78 + 34 34 34 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 30 30 30 78 78 78 190 142 34 226 170 11 +239 182 13 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 241 196 14 203 166 17 22 18 6 + 2 2 6 2 2 6 2 2 6 38 38 38 +218 218 218 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 206 206 206 198 198 198 202 162 69 +226 170 11 236 178 12 224 166 10 210 150 10 +200 144 11 197 138 11 192 133 9 197 138 11 +210 150 10 226 170 11 242 186 14 246 190 14 +246 190 14 246 186 14 225 175 15 124 112 88 + 62 62 62 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 174 135 50 224 166 10 +239 182 13 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 241 196 14 139 102 15 + 2 2 6 2 2 6 2 2 6 2 2 6 + 78 78 78 250 250 250 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 214 214 214 198 198 198 190 150 46 +219 162 10 236 178 12 234 174 13 224 166 10 +216 158 10 213 154 11 213 154 11 216 158 10 +226 170 11 239 182 13 246 190 14 246 190 14 +246 190 14 246 190 14 242 186 14 206 162 42 +101 101 101 58 58 58 30 30 30 14 14 14 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 74 74 74 174 135 50 216 158 10 +236 178 12 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 241 196 14 226 184 13 + 61 42 6 2 2 6 2 2 6 2 2 6 + 22 22 22 238 238 238 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 226 226 226 187 187 187 180 133 36 +216 158 10 236 178 12 239 182 13 236 178 12 +230 174 11 226 170 11 226 170 11 230 174 11 +236 178 12 242 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 186 14 239 182 13 +206 162 42 106 106 106 66 66 66 34 34 34 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 26 26 26 70 70 70 163 133 67 213 154 11 +236 178 12 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 241 196 14 +190 146 13 18 14 6 2 2 6 2 2 6 + 46 46 46 246 246 246 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 221 221 221 86 86 86 156 107 11 +216 158 10 236 178 12 242 186 14 246 186 14 +242 186 14 239 182 13 239 182 13 242 186 14 +242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +242 186 14 225 175 15 142 122 72 66 66 66 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 26 26 26 70 70 70 163 133 67 210 150 10 +236 178 12 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +232 195 16 121 92 8 34 34 34 106 106 106 +221 221 221 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +242 242 242 82 82 82 18 14 6 163 110 8 +216 158 10 236 178 12 242 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 242 186 14 163 133 67 + 46 46 46 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 163 133 67 210 150 10 +236 178 12 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +241 196 14 215 174 15 190 178 144 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 218 218 218 + 58 58 58 2 2 6 22 18 6 167 114 7 +216 158 10 236 178 12 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 186 14 242 186 14 190 150 46 + 54 54 54 22 22 22 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 38 38 38 86 86 86 180 133 36 213 154 11 +236 178 12 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 232 195 16 190 146 13 214 214 214 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 250 250 250 170 170 170 26 26 26 + 2 2 6 2 2 6 37 26 9 163 110 8 +219 162 10 239 182 13 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 236 178 12 224 166 10 142 122 72 + 46 46 46 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 109 106 95 192 133 9 224 166 10 +242 186 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +242 186 14 226 184 13 210 162 10 142 110 46 +226 226 226 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +198 198 198 66 66 66 2 2 6 2 2 6 + 2 2 6 2 2 6 50 34 6 156 107 11 +219 162 10 239 182 13 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 242 186 14 +234 174 13 213 154 11 154 122 46 66 66 66 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 58 58 58 154 121 60 206 145 10 234 174 13 +242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 236 178 12 210 162 10 163 110 8 + 61 42 6 138 138 138 218 218 218 250 250 250 +253 253 253 253 253 253 253 253 253 250 250 250 +242 242 242 210 210 210 144 144 144 66 66 66 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 61 42 6 163 110 8 +216 158 10 236 178 12 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 239 182 13 230 174 11 216 158 10 +190 142 34 124 112 88 70 70 70 38 38 38 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 62 62 62 168 124 44 206 145 10 224 166 10 +236 178 12 239 182 13 242 186 14 242 186 14 +246 186 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 236 178 12 216 158 10 175 118 6 + 80 54 7 2 2 6 6 6 6 30 30 30 + 54 54 54 62 62 62 50 50 50 38 38 38 + 14 14 14 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 80 54 7 167 114 7 +213 154 11 236 178 12 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 242 186 14 239 182 13 239 182 13 +230 174 11 210 150 10 174 135 50 124 112 88 + 82 82 82 54 54 54 34 34 34 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 158 118 36 192 133 9 200 144 11 +216 158 10 219 162 10 224 166 10 226 170 11 +230 174 11 236 178 12 239 182 13 239 182 13 +242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 230 174 11 210 150 10 163 110 8 +104 69 6 10 10 10 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 91 60 6 167 114 7 +206 145 10 230 174 11 242 186 14 246 190 14 +246 190 14 246 190 14 246 186 14 242 186 14 +239 182 13 230 174 11 224 166 10 213 154 11 +180 133 36 124 112 88 86 86 86 58 58 58 + 38 38 38 22 22 22 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 34 34 34 70 70 70 138 110 50 158 118 36 +167 114 7 180 123 7 192 133 9 197 138 11 +200 144 11 206 145 10 213 154 11 219 162 10 +224 166 10 230 174 11 239 182 13 242 186 14 +246 186 14 246 186 14 246 186 14 246 186 14 +239 182 13 216 158 10 185 133 11 152 99 6 +104 69 6 18 14 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 80 54 7 152 99 6 +192 133 9 219 162 10 236 178 12 239 182 13 +246 186 14 242 186 14 239 182 13 236 178 12 +224 166 10 206 145 10 192 133 9 154 121 60 + 94 94 94 62 62 62 42 42 42 22 22 22 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 18 18 18 34 34 34 58 58 58 78 78 78 +101 98 89 124 112 88 142 110 46 156 107 11 +163 110 8 167 114 7 175 118 6 180 123 7 +185 133 11 197 138 11 210 150 10 219 162 10 +226 170 11 236 178 12 236 178 12 234 174 13 +219 162 10 197 138 11 163 110 8 130 83 6 + 91 60 6 10 10 10 2 2 6 2 2 6 + 18 18 18 38 38 38 38 38 38 38 38 38 + 38 38 38 38 38 38 38 38 38 38 38 38 + 38 38 38 38 38 38 26 26 26 2 2 6 + 2 2 6 6 6 6 70 47 6 137 92 6 +175 118 6 200 144 11 219 162 10 230 174 11 +234 174 13 230 174 11 219 162 10 210 150 10 +192 133 9 163 110 8 124 112 88 82 82 82 + 50 50 50 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 22 22 22 34 34 34 + 42 42 42 58 58 58 74 74 74 86 86 86 +101 98 89 122 102 70 130 98 46 121 87 25 +137 92 6 152 99 6 163 110 8 180 123 7 +185 133 11 197 138 11 206 145 10 200 144 11 +180 123 7 156 107 11 130 83 6 104 69 6 + 50 34 6 54 54 54 110 110 110 101 98 89 + 86 86 86 82 82 82 78 78 78 78 78 78 + 78 78 78 78 78 78 78 78 78 78 78 78 + 78 78 78 82 82 82 86 86 86 94 94 94 +106 106 106 101 101 101 86 66 34 124 80 6 +156 107 11 180 123 7 192 133 9 200 144 11 +206 145 10 200 144 11 192 133 9 175 118 6 +139 102 15 109 106 95 70 70 70 42 42 42 + 22 22 22 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 10 10 10 + 14 14 14 22 22 22 30 30 30 38 38 38 + 50 50 50 62 62 62 74 74 74 90 90 90 +101 98 89 112 100 78 121 87 25 124 80 6 +137 92 6 152 99 6 152 99 6 152 99 6 +138 86 6 124 80 6 98 70 6 86 66 30 +101 98 89 82 82 82 58 58 58 46 46 46 + 38 38 38 34 34 34 34 34 34 34 34 34 + 34 34 34 34 34 34 34 34 34 34 34 34 + 34 34 34 34 34 34 38 38 38 42 42 42 + 54 54 54 82 82 82 94 86 76 91 60 6 +134 86 6 156 107 11 167 114 7 175 118 6 +175 118 6 167 114 7 152 99 6 121 87 25 +101 98 89 62 62 62 34 34 34 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 6 6 6 10 10 10 + 18 18 18 22 22 22 30 30 30 42 42 42 + 50 50 50 66 66 66 86 86 86 101 98 89 +106 86 58 98 70 6 104 69 6 104 69 6 +104 69 6 91 60 6 82 62 34 90 90 90 + 62 62 62 38 38 38 22 22 22 14 14 14 + 10 10 10 10 10 10 10 10 10 10 10 10 + 10 10 10 10 10 10 6 6 6 10 10 10 + 10 10 10 10 10 10 10 10 10 14 14 14 + 22 22 22 42 42 42 70 70 70 89 81 66 + 80 54 7 104 69 6 124 80 6 137 92 6 +134 86 6 116 81 8 100 82 52 86 86 86 + 58 58 58 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 10 10 10 14 14 14 + 18 18 18 26 26 26 38 38 38 54 54 54 + 70 70 70 86 86 86 94 86 76 89 81 66 + 89 81 66 86 86 86 74 74 74 50 50 50 + 30 30 30 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 34 34 34 58 58 58 + 82 82 82 89 81 66 89 81 66 89 81 66 + 94 86 66 94 86 76 74 74 74 50 50 50 + 26 26 26 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 6 6 6 14 14 14 18 18 18 + 30 30 30 38 38 38 46 46 46 54 54 54 + 50 50 50 42 42 42 30 30 30 18 18 18 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 26 26 26 + 38 38 38 50 50 50 58 58 58 58 58 58 + 54 54 54 42 42 42 30 30 30 18 18 18 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 6 6 6 10 10 10 14 14 14 18 18 18 + 18 18 18 14 14 14 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 14 14 14 18 18 18 22 22 22 22 22 22 + 18 18 18 14 14 14 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/drivers/video/logo/logo_parisc_clut224.ppm b/drivers/video/logo/logo_parisc_clut224.ppm new file mode 100644 index 000000000000..9bf89efbe491 --- /dev/null +++ b/drivers/video/logo/logo_parisc_clut224.ppm @@ -0,0 +1,1604 @@ +P3 +# 224-color PA-RISC Linux logo +80 80 +255 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 7 6 6 7 + 6 6 7 6 6 7 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 7 22 22 23 + 46 46 47 58 58 59 70 70 71 82 82 82 + 82 82 82 66 66 67 54 54 55 38 38 39 + 22 22 23 6 6 7 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 7 29 30 31 70 70 71 119 122 130 + 166 166 167 191 191 190 198 198 200 206 206 206 + 206 206 206 194 194 195 182 182 182 158 158 158 + 119 119 118 70 70 71 29 30 31 10 10 11 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 15 + 54 54 55 126 126 127 191 191 190 226 226 226 + 202 202 202 130 130 132 126 126 127 100 100 102 + 100 100 102 119 122 130 163 162 161 202 202 202 + 226 226 226 191 191 190 134 134 134 74 74 74 + 26 26 28 6 6 7 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 18 18 18 74 74 74 + 158 158 158 222 222 223 182 182 182 63 62 63 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 63 62 63 166 166 167 230 230 231 191 191 190 + 119 119 118 46 46 47 10 10 11 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 10 10 11 66 66 67 166 166 167 + 222 222 223 112 112 112 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 46 46 47 194 194 195 + 214 214 215 140 140 141 54 54 55 10 10 11 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 38 38 39 140 140 141 226 226 226 + 90 90 90 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 11 + 33 34 35 22 22 23 2 2 2 6 6 7 + 140 140 141 222 222 223 140 140 141 42 42 43 + 6 6 7 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 14 14 15 86 86 86 202 202 202 146 146 146 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 26 26 28 + 100 100 102 112 112 112 42 42 43 2 2 2 + 2 2 2 163 162 161 210 210 210 105 107 112 + 22 22 23 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 33 34 35 146 146 146 226 226 226 33 34 35 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 29 30 31 + 119 119 118 130 130 132 70 70 71 26 26 28 + 2 2 2 10 10 11 206 206 206 178 177 177 + 63 62 63 6 6 7 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 7 + 70 70 71 191 191 190 163 162 161 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 29 30 31 + 78 78 79 63 62 63 29 30 31 18 18 18 + 2 2 2 2 2 2 86 86 86 222 222 223 + 119 119 118 22 22 23 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 15 + 100 100 102 218 218 219 70 70 71 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 11 + 14 14 15 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 7 198 198 200 + 171 170 167 54 54 55 6 6 7 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 22 22 23 + 126 126 127 230 230 231 22 22 23 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 112 112 112 + 206 206 206 86 86 86 10 10 11 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 29 30 31 + 146 146 146 210 210 210 6 6 7 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 38 38 39 + 226 226 226 119 119 118 18 18 18 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 33 34 35 + 150 150 151 202 202 202 2 2 2 2 2 2 + 2 2 2 2 2 2 22 22 23 26 26 28 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 7 54 54 55 6 6 7 2 2 2 + 2 2 2 2 2 2 2 2 2 18 18 18 + 226 226 226 140 140 141 26 26 28 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 33 34 35 + 150 150 151 202 202 202 2 2 2 2 2 2 + 10 10 11 78 78 79 54 54 55 14 14 15 + 18 18 18 2 2 2 2 2 2 2 2 2 + 2 2 2 54 54 55 130 130 132 171 170 167 + 130 130 132 14 14 15 29 30 31 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 198 198 200 155 153 152 33 34 35 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 33 34 35 + 150 150 151 202 202 202 2 2 2 2 2 2 + 134 134 134 222 222 223 214 214 215 90 90 90 + 2 2 2 2 2 2 2 2 2 2 2 2 + 70 70 71 182 182 182 218 218 219 237 238 239 + 241 242 244 140 140 141 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 202 202 202 166 166 167 42 42 43 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 33 34 35 + 150 150 151 202 202 202 2 2 2 38 38 39 + 234 234 235 254 254 254 254 254 254 254 254 254 + 29 30 31 2 2 2 2 2 2 2 2 10 + 218 218 219 254 254 254 254 254 254 210 210 210 + 254 254 254 249 250 251 54 54 55 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 140 140 141 178 177 177 54 54 55 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 33 34 35 + 150 150 151 202 202 202 2 2 2 105 107 112 + 237 238 239 29 30 31 105 107 112 254 254 254 + 119 122 130 2 2 2 2 2 2 29 30 31 + 254 254 254 249 250 251 6 6 7 58 58 59 + 112 112 112 254 254 254 166 166 167 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 140 140 141 182 182 182 54 54 55 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 29 30 31 + 146 146 146 198 198 200 2 2 2 126 126 127 + 126 126 127 2 2 2 78 78 79 178 182 190 + 150 150 151 2 2 10 26 26 28 42 42 43 + 254 254 254 119 122 130 2 2 2 2 2 10 + 54 54 55 226 226 226 230 230 231 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 140 140 141 182 182 182 54 54 55 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 26 26 28 + 134 134 134 234 234 235 22 22 23 119 119 118 + 130 130 132 2 2 2 6 10 24 122 126 140 + 86 86 86 42 30 2 45 26 2 23 14 2 + 184 186 195 100 100 102 2 2 2 2 2 2 + 2 2 2 210 210 210 234 234 235 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 140 140 141 187 187 186 58 58 59 6 6 7 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 18 18 18 + 119 119 118 230 230 231 22 22 23 70 70 71 + 222 222 223 2 2 2 2 2 2 138 98 18 + 236 174 8 254 198 2 246 190 13 202 152 2 + 214 170 26 162 138 86 2 2 2 2 2 2 + 12 14 26 254 254 254 183 186 190 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 146 146 146 194 194 195 70 70 71 6 6 7 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 18 18 18 + 112 112 112 226 226 226 22 22 23 6 6 7 + 249 250 251 167 155 134 186 124 4 234 170 6 + 254 198 2 253 202 2 253 207 3 238 198 14 + 254 212 22 254 216 14 218 173 2 118 90 6 + 210 210 210 254 254 254 63 62 63 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 82 82 82 206 206 206 82 82 82 10 10 11 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 18 18 18 + 112 112 112 226 226 226 22 22 23 2 2 2 + 122 106 82 207 143 12 234 170 6 254 194 2 + 254 198 2 253 207 3 252 218 6 254 234 42 + 254 234 66 254 234 42 254 233 7 254 226 4 + 253 207 3 228 176 28 70 46 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 82 82 82 214 214 215 94 94 95 10 10 11 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 18 18 18 + 112 112 112 226 226 226 38 38 39 23 14 2 + 186 124 4 221 154 6 248 183 3 254 198 2 + 253 202 2 250 214 3 254 222 7 254 230 70 + 254 234 66 254 233 7 254 233 7 254 236 14 + 254 226 4 254 212 22 214 162 3 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 54 54 55 226 226 226 119 119 118 22 22 23 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 11 + 94 94 95 214 214 215 86 86 86 100 63 4 + 206 137 3 238 167 5 254 190 11 254 198 2 + 253 207 3 252 218 6 254 226 46 254 232 58 + 254 233 7 254 233 7 254 233 7 226 190 2 + 202 152 2 231 166 7 175 127 3 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 10 10 11 222 222 223 163 162 161 46 46 47 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 11 + 82 82 82 210 210 210 86 86 86 42 30 2 + 174 119 4 248 183 3 254 194 2 253 202 2 + 253 207 3 254 222 7 254 226 46 254 226 4 + 254 222 7 238 202 2 190 145 2 207 143 12 + 226 160 6 238 167 5 138 98 18 2 2 2 + 2 2 2 22 22 23 2 2 2 2 2 2 + 2 2 2 130 130 132 202 202 202 82 82 82 + 10 10 11 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 11 + 82 82 82 210 210 210 86 86 86 2 2 2 + 89 59 3 156 110 2 241 183 7 253 207 3 + 253 224 28 254 222 7 250 214 3 218 173 2 + 175 127 3 166 110 10 211 145 3 226 160 6 + 221 154 6 204 154 50 63 62 63 2 2 2 + 2 2 2 94 94 95 100 100 102 33 34 35 + 2 2 2 50 50 51 230 230 231 140 140 141 + 33 34 35 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 15 + 94 94 95 214 214 215 86 86 86 2 2 2 + 119 122 130 162 138 86 142 90 5 174 119 4 + 190 145 2 175 127 3 170 112 4 186 124 4 + 202 130 2 206 137 3 202 130 2 187 145 53 + 194 186 174 204 208 219 178 177 177 2 2 2 + 2 2 2 18 18 18 140 140 141 130 130 132 + 14 14 15 2 2 2 178 177 177 198 198 200 + 86 86 86 14 14 15 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 33 34 35 + 134 134 134 230 230 231 54 54 55 2 2 2 + 146 146 146 202 202 202 164 124 56 156 101 3 + 213 150 7 211 145 3 206 137 3 198 126 2 + 180 114 4 182 118 3 182 158 114 188 190 198 + 204 208 219 230 230 231 214 214 215 33 34 35 + 2 2 2 2 2 2 78 78 79 94 94 95 + 6 6 7 2 2 2 29 30 31 226 226 226 + 150 150 151 42 42 43 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 14 14 15 82 82 82 + 194 194 195 187 187 186 6 6 7 2 2 2 + 140 140 141 204 208 219 194 194 195 163 143 109 + 148 89 3 148 89 3 148 89 3 148 89 3 + 164 124 56 184 176 158 184 186 195 204 208 219 + 254 254 254 254 254 254 254 254 254 158 158 158 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 140 140 141 + 206 206 206 100 100 102 18 18 18 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 6 6 7 54 54 55 158 158 158 + 226 226 226 50 50 51 2 2 2 2 2 2 + 234 234 235 230 234 235 198 198 200 190 194 210 + 184 186 195 174 162 150 174 162 150 178 177 177 + 183 186 190 188 190 198 204 208 219 245 246 248 + 254 254 254 254 254 254 254 254 254 254 254 254 + 38 38 39 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 29 30 31 + 218 218 219 171 170 167 58 58 59 6 6 7 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 7 38 38 39 134 134 134 222 222 223 + 120 112 108 2 2 2 2 2 2 150 150 151 + 254 254 254 254 254 254 210 210 210 188 190 198 + 188 190 198 184 186 195 183 186 190 183 186 190 + 194 194 195 222 222 223 249 250 251 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 194 194 195 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 100 100 102 222 222 223 119 122 130 29 30 31 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 26 26 28 112 112 112 206 206 206 171 170 167 + 6 6 7 2 2 2 46 46 47 254 254 254 + 254 254 254 254 254 254 241 242 244 188 190 198 + 187 187 186 183 186 190 183 186 190 206 206 206 + 241 242 244 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 46 46 47 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 7 194 194 195 194 194 195 90 90 90 + 18 18 18 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 18 18 18 + 86 86 86 191 191 190 206 206 206 26 26 28 + 2 2 2 2 2 2 206 206 206 254 254 254 + 254 254 254 254 254 254 254 254 254 245 246 248 + 218 218 219 218 218 219 234 234 235 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 171 170 167 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 46 46 47 226 226 226 178 177 177 + 74 74 74 14 14 15 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 14 14 15 70 70 71 + 171 170 167 226 226 226 46 46 47 2 2 2 + 2 2 2 74 74 74 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 249 250 251 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 63 62 63 234 234 235 + 163 162 161 66 66 67 14 14 15 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 6 6 7 54 54 55 155 153 152 + 230 230 231 82 82 82 2 2 2 2 2 2 + 2 2 2 194 194 195 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 26 26 28 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 112 112 112 + 230 230 231 155 153 152 58 58 59 6 6 7 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 29 30 31 126 126 127 222 222 223 + 112 112 112 2 2 2 2 2 2 2 2 2 + 14 14 15 218 218 219 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 249 250 251 249 250 251 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 250 254 254 254 90 90 90 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 112 112 112 222 222 223 134 134 134 38 38 39 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 10 10 11 74 74 74 191 191 190 182 182 182 + 6 6 7 2 2 2 2 2 2 2 2 2 + 46 46 47 182 182 182 234 234 235 254 254 254 + 254 254 254 254 254 254 254 254 254 234 234 235 + 222 222 223 222 222 223 237 238 239 249 250 251 + 249 250 251 249 250 251 249 250 251 230 230 231 + 222 222 223 218 218 219 214 214 215 210 210 210 + 210 210 210 222 222 223 163 162 161 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 7 163 162 161 202 202 202 90 90 90 + 14 14 15 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 29 30 31 134 134 134 230 230 231 50 50 51 + 2 2 2 2 2 2 2 2 2 2 2 2 + 78 78 79 178 177 177 214 214 215 241 242 244 + 254 254 254 254 254 254 254 254 254 254 254 250 + 226 226 226 245 246 248 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 250 241 242 244 + 222 222 223 206 206 206 198 198 200 194 194 195 + 194 194 195 198 198 200 234 234 235 119 119 118 + 2 2 2 2 2 2 29 30 31 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 26 26 28 222 222 223 150 150 151 + 38 38 39 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 7 + 58 58 59 178 177 177 171 170 167 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 7 + 150 150 151 234 234 235 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 250 + 237 238 239 254 254 254 254 254 250 254 254 250 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 237 238 239 + 222 222 223 206 206 206 210 210 210 249 250 251 + 46 46 47 2 2 2 2 2 2 38 38 39 + 10 10 11 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 150 150 151 198 198 200 + 82 82 82 10 10 11 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 11 + 86 86 86 210 210 210 112 112 112 2 2 2 + 2 2 2 18 18 18 2 2 2 112 112 112 + 241 242 244 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 250 254 254 250 254 254 250 254 254 250 + 254 254 250 254 254 250 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 234 234 235 226 226 226 + 214 214 215 2 2 2 2 2 2 2 2 2 + 42 42 43 10 10 11 2 2 2 2 2 2 + 2 2 2 2 2 2 46 46 47 230 230 231 + 134 134 134 29 30 31 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 26 26 28 + 126 126 127 230 230 231 50 50 51 2 2 2 + 33 34 35 2 2 2 14 14 15 194 194 195 + 254 254 254 254 254 254 245 246 248 254 254 254 + 254 254 254 230 234 235 206 206 206 206 206 206 + 206 206 206 206 206 206 154 206 206 154 206 206 + 154 206 206 154 206 206 154 206 206 154 206 206 + 154 206 206 102 154 154 102 154 154 166 174 186 + 226 226 226 254 254 254 245 246 248 245 246 248 + 245 246 248 70 70 71 2 2 2 2 2 2 + 2 2 2 38 38 39 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 178 177 177 + 178 177 177 58 58 59 6 6 7 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 50 50 51 + 166 166 167 210 210 210 6 6 7 6 6 7 + 14 14 15 2 2 2 134 134 134 237 238 239 + 249 250 251 254 254 254 254 254 254 254 254 254 + 254 254 254 102 154 154 2 102 102 2 102 154 + 2 102 102 2 102 102 2 102 102 2 102 102 + 2 102 102 2 102 102 2 102 102 2 102 102 + 2 102 102 2 102 102 2 102 102 50 154 154 + 234 234 235 254 254 254 254 254 254 254 254 254 + 249 250 251 198 198 200 2 2 2 18 18 18 + 50 50 51 22 22 23 29 30 31 2 2 2 + 2 2 2 2 2 2 2 2 2 105 107 112 + 214 214 215 100 100 102 14 14 15 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 10 10 11 86 86 86 + 206 206 206 126 126 127 2 2 2 38 38 39 + 2 2 2 6 6 7 230 230 231 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 102 154 154 2 102 102 2 102 102 + 2 154 154 50 154 154 102 206 206 154 206 206 + 206 206 206 230 234 235 206 206 206 154 206 206 + 102 154 154 2 102 154 2 102 102 50 154 154 + 245 246 248 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 14 14 15 29 30 31 + 50 50 51 10 10 11 42 42 43 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 11 + 226 226 226 150 150 151 33 34 35 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 29 30 31 134 134 134 + 230 230 231 46 46 47 2 2 2 22 22 23 + 2 2 2 78 78 79 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 50 154 154 50 154 154 154 206 206 + 230 234 235 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 154 206 206 2 102 154 2 154 154 + 241 242 244 254 254 254 249 250 251 254 254 254 + 254 254 254 254 254 254 74 74 74 2 2 2 + 2 2 2 2 2 2 10 10 11 38 38 39 + 2 2 2 2 2 2 2 2 2 2 2 2 + 166 166 167 191 191 190 66 66 67 6 6 7 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 6 6 7 66 66 67 182 182 182 + 182 182 182 2 2 2 29 30 31 2 2 2 + 2 2 2 202 202 202 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 230 234 235 + 102 154 154 154 206 206 230 234 235 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 50 154 154 2 102 102 + 206 206 206 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 140 140 141 2 2 2 + 2 2 2 2 2 2 2 2 2 46 46 47 + 2 2 2 2 2 2 2 2 2 2 2 2 + 90 90 90 214 214 215 100 100 102 14 14 15 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 26 26 28 119 122 130 222 222 223 + 78 78 79 2 2 2 33 34 35 2 2 2 + 33 34 35 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 230 234 235 102 154 154 + 206 206 206 254 254 254 254 254 254 254 254 254 + 230 234 235 154 206 206 102 154 154 50 154 154 + 50 154 154 50 154 154 50 154 154 154 206 206 + 230 234 235 254 254 254 50 154 154 2 102 102 + 154 206 206 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 191 191 190 2 2 2 + 2 2 2 2 2 2 2 2 2 50 50 51 + 2 2 2 2 2 2 2 2 2 2 2 2 + 26 26 28 230 230 231 126 126 127 22 22 23 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 10 10 11 74 74 74 187 187 186 194 194 195 + 6 6 7 2 2 2 10 10 11 2 2 2 + 130 130 132 254 254 254 254 254 254 254 254 254 + 254 254 254 230 234 235 154 206 206 230 234 235 + 254 254 254 254 254 254 154 206 206 50 154 154 + 2 102 154 2 102 154 50 154 154 50 154 154 + 50 154 154 50 154 154 2 102 102 2 102 102 + 50 154 154 206 206 206 50 154 154 2 102 102 + 102 206 206 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 226 226 226 2 2 2 + 2 2 2 2 2 2 2 2 2 42 42 43 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 7 214 214 215 150 150 151 33 34 35 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 38 38 39 140 140 141 230 230 231 63 62 63 + 2 2 2 22 22 23 2 2 2 2 2 2 + 210 210 210 254 254 254 254 254 254 254 254 254 + 254 254 254 206 206 206 254 254 254 254 254 254 + 154 206 206 50 154 154 50 154 154 102 154 206 + 206 206 206 230 234 235 254 254 254 254 254 254 + 254 254 254 230 234 235 206 206 206 102 154 154 + 2 102 102 2 102 154 2 102 154 2 102 102 + 102 154 154 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 245 246 248 2 2 2 + 2 2 2 2 2 2 2 2 2 33 34 35 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 194 194 195 171 170 167 46 46 47 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 15 + 90 90 90 202 202 202 150 150 151 2 2 2 + 2 2 2 29 30 31 2 2 2 2 2 2 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 230 234 235 102 154 154 + 50 154 154 154 206 206 230 234 235 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 102 154 206 2 102 102 2 102 154 2 102 102 + 50 154 154 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 2 2 2 + 2 2 2 2 2 2 2 2 2 29 30 31 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 134 134 134 187 187 186 58 58 59 + 6 6 7 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 29 30 31 + 140 140 141 222 222 223 26 26 28 2 2 2 + 2 2 2 33 34 35 2 2 2 12 14 26 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 230 234 235 102 154 154 154 206 206 + 254 254 254 254 254 254 230 234 235 254 254 254 + 254 254 254 254 254 254 230 234 235 230 234 235 + 230 234 235 254 254 254 254 254 254 254 254 254 + 230 234 235 2 102 154 2 102 154 2 102 102 + 50 154 154 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 2 2 2 + 2 2 2 2 2 2 6 6 7 18 18 18 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 134 134 134 187 187 186 58 58 59 + 6 6 7 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 46 46 47 + 171 170 167 194 194 195 2 2 2 2 2 2 + 2 2 2 58 58 59 6 10 24 33 34 35 + 254 254 254 254 254 254 254 254 254 254 254 254 + 230 234 235 102 154 206 230 234 235 254 254 254 + 254 254 254 254 254 254 154 206 206 102 154 206 + 50 154 154 50 154 154 2 102 154 2 102 154 + 2 154 154 50 154 154 154 206 206 254 254 254 + 230 234 235 2 154 154 2 102 154 2 102 154 + 2 154 154 230 234 235 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 2 2 2 + 2 2 2 2 2 2 26 26 28 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 134 134 134 187 187 186 58 58 59 + 6 6 7 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 58 58 59 + 187 187 186 134 134 134 2 2 2 2 2 2 + 2 2 2 33 34 35 26 26 28 54 54 55 + 254 254 254 254 254 254 254 254 254 254 254 254 + 206 206 206 254 254 254 254 254 254 254 254 254 + 154 206 206 50 154 154 2 102 154 50 154 154 + 50 154 154 102 154 154 102 154 154 102 154 154 + 50 154 154 2 102 102 2 102 102 50 154 154 + 154 206 206 2 102 154 2 102 154 2 102 154 + 2 102 154 230 234 235 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 2 2 2 + 2 2 2 2 2 2 26 26 28 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 134 134 134 187 187 186 58 58 59 + 6 6 7 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 7 58 58 59 + 187 187 186 134 134 134 2 2 2 2 2 2 + 2 2 2 2 2 2 12 14 26 54 54 55 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 154 206 206 102 154 154 + 102 154 154 154 206 206 206 206 206 230 234 235 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 206 206 206 50 154 154 2 102 102 + 2 102 154 2 102 154 2 102 154 2 102 154 + 2 102 154 154 206 206 254 254 254 254 254 254 + 254 254 254 254 254 254 237 238 239 2 2 2 + 2 2 2 26 26 28 14 14 15 14 14 15 + 12 14 26 2 2 2 2 2 2 2 2 2 + 2 2 2 163 162 161 182 182 182 54 54 55 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 54 54 55 + 182 182 182 194 194 195 18 6 2 130 88 2 + 162 122 2 55 34 3 2 2 2 62 66 80 + 254 254 254 254 254 254 254 254 254 254 254 254 + 230 234 235 102 154 154 102 154 154 230 234 235 + 254 254 254 254 254 254 230 234 235 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 50 154 154 + 2 102 102 2 102 102 2 102 102 2 102 102 + 2 102 102 102 206 206 254 254 254 254 254 254 + 254 254 254 254 254 254 188 190 198 2 2 2 + 6 6 7 2 2 2 2 2 2 2 2 2 + 2 2 10 29 30 31 66 66 67 22 22 23 + 2 2 2 202 202 202 163 162 161 42 42 43 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 7 + 10 10 11 10 10 11 18 18 18 74 74 74 + 194 194 195 222 222 223 226 162 16 254 212 22 + 253 207 3 253 202 2 87 61 13 2 2 2 + 130 130 132 254 254 254 254 254 254 230 234 235 + 102 154 154 206 206 206 254 254 254 254 254 254 + 254 254 254 254 254 254 230 234 235 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 206 206 206 + 102 154 154 102 154 154 102 154 154 50 154 154 + 50 154 154 102 154 154 254 254 254 254 254 242 + 254 230 154 254 234 162 150 126 70 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 38 38 39 62 66 80 + 10 10 11 241 242 244 158 158 158 42 42 43 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 10 10 11 29 30 31 63 62 63 + 86 86 86 94 94 95 100 100 102 158 158 158 + 230 230 231 186 150 74 248 183 3 254 202 13 + 253 207 3 253 207 3 254 198 2 89 59 3 + 2 2 2 105 107 112 254 254 254 154 206 206 + 230 234 235 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 230 234 235 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 230 234 235 230 234 235 254 254 254 242 190 58 + 253 207 3 254 226 4 250 214 3 23 14 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 33 34 35 14 14 15 + 170 142 50 218 218 219 194 194 195 78 78 79 + 10 10 11 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 10 10 11 58 58 59 134 134 134 187 187 186 + 210 210 210 214 214 215 218 218 219 234 234 235 + 184 176 158 218 159 3 254 186 7 254 202 13 + 253 207 3 253 202 2 253 202 2 246 190 13 + 38 22 2 2 2 2 62 66 80 245 246 248 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 230 230 231 241 242 244 + 254 254 254 254 254 254 254 254 250 254 254 250 + 254 254 250 254 254 250 254 254 250 254 254 250 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 228 176 28 + 254 186 7 253 207 3 234 190 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 10 87 61 13 + 254 236 14 238 230 54 230 230 231 130 130 132 + 26 26 28 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 42 42 43 146 146 146 226 226 226 184 176 158 + 182 158 114 196 157 72 186 150 74 187 145 53 + 213 150 7 236 174 8 254 194 14 254 202 13 + 254 202 13 253 202 2 254 198 2 254 198 2 + 214 162 3 2 2 2 2 2 2 12 14 26 + 214 214 215 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 250 + 254 254 250 254 254 250 254 254 250 254 254 250 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 226 174 56 + 254 186 7 254 194 2 218 159 3 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 7 241 183 7 + 254 222 7 254 222 7 194 194 195 155 153 152 + 33 34 35 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 11 + 86 86 86 206 206 206 179 164 133 234 170 6 + 254 186 7 248 184 12 242 177 7 236 174 8 + 248 184 12 254 190 11 254 198 13 254 198 13 + 254 198 13 254 198 6 254 198 6 254 198 2 + 253 207 3 142 102 2 2 2 2 2 2 2 + 2 2 2 166 166 167 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 250 + 254 254 250 254 254 250 254 254 250 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 241 242 244 204 208 219 213 163 50 + 248 183 3 254 186 7 221 154 6 100 63 4 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 175 127 3 254 202 13 + 254 212 22 254 212 22 194 194 195 166 166 167 + 42 42 43 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 18 18 18 + 119 119 118 230 230 231 213 163 50 254 186 7 + 254 202 13 254 202 13 254 198 13 254 194 14 + 254 198 13 254 198 13 254 198 13 254 198 13 + 254 198 13 254 198 13 254 198 6 254 194 9 + 254 198 2 242 198 2 38 22 2 2 2 2 + 2 2 2 2 2 2 100 100 102 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 250 + 254 254 250 254 254 250 254 254 250 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 204 208 219 190 194 210 213 163 50 + 242 177 7 242 177 7 226 160 6 186 124 4 + 118 76 2 55 34 3 45 26 2 55 34 3 + 118 76 2 194 134 10 242 177 7 254 198 13 + 254 206 18 254 206 18 191 191 190 198 198 200 + 86 86 86 18 18 18 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 18 18 18 + 119 122 130 230 230 231 219 155 20 254 190 11 + 254 202 13 254 206 18 254 202 13 254 202 13 + 254 198 13 254 198 13 254 194 14 250 194 13 + 250 194 13 254 194 9 254 194 9 254 198 6 + 254 198 6 253 207 3 190 145 2 2 2 2 + 2 2 2 2 2 2 2 2 2 50 50 51 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 250 + 254 254 250 254 254 250 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 204 208 219 190 198 214 204 154 50 + 234 170 6 248 183 3 234 170 6 211 145 3 + 206 137 3 194 131 6 194 131 6 194 134 10 + 211 145 3 234 170 6 254 198 13 254 206 18 + 254 206 18 254 206 18 222 182 66 222 222 223 + 166 166 167 70 70 71 14 14 15 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 15 + 105 107 112 222 222 223 196 157 72 248 183 3 + 254 198 13 254 206 18 254 202 13 254 198 13 + 254 194 14 250 194 13 250 194 13 250 194 13 + 250 194 13 250 194 13 254 194 9 254 194 9 + 254 198 6 254 198 6 253 207 3 82 58 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 86 86 86 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 214 214 215 190 198 214 187 145 53 + 226 160 6 241 183 7 241 183 7 231 166 7 + 218 159 3 221 154 6 221 154 6 218 159 3 + 236 174 8 250 190 11 254 202 13 254 202 13 + 254 206 18 254 202 13 254 202 13 190 167 108 + 230 230 231 163 162 161 74 74 74 22 22 23 + 6 6 7 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 11 + 90 90 90 214 214 215 188 154 82 240 174 22 + 254 194 14 254 202 13 254 198 13 254 198 13 + 250 194 13 250 194 13 246 190 13 246 190 13 + 246 190 13 250 190 11 250 194 13 254 194 9 + 254 198 13 254 198 6 253 202 2 218 173 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 249 250 251 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 230 234 235 190 198 214 174 134 38 + 221 154 6 248 183 3 250 190 11 241 183 7 + 236 174 8 236 174 8 234 170 6 236 174 8 + 241 183 7 254 194 14 254 198 13 254 198 13 + 254 202 13 254 202 13 254 202 13 254 198 13 + 190 167 108 234 234 235 182 182 182 112 112 112 + 50 50 51 10 10 11 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 7 + 74 74 74 202 202 202 179 164 133 231 166 7 + 254 190 11 254 202 13 254 198 13 254 194 14 + 250 194 13 246 190 13 246 190 13 246 190 13 + 246 190 13 246 190 13 250 194 13 250 194 13 + 254 194 9 254 198 13 254 198 6 253 207 3 + 156 110 2 2 2 2 2 2 2 2 2 2 + 2 2 2 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 241 242 244 105 107 112 142 90 5 + 221 154 6 241 183 7 254 194 9 254 190 11 + 254 186 7 241 183 7 241 183 7 248 184 12 + 250 190 11 254 194 14 254 198 13 254 198 13 + 254 198 13 254 202 13 254 202 13 254 206 18 + 254 206 18 218 182 78 214 214 215 214 214 215 + 140 140 141 38 38 39 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 7 + 66 66 67 194 194 195 174 162 150 226 162 16 + 250 190 11 254 198 13 254 198 13 250 194 13 + 250 194 13 246 190 13 246 190 13 246 190 13 + 246 190 13 246 190 13 250 190 11 250 194 13 + 254 194 9 254 194 9 254 198 6 253 202 2 + 253 202 2 62 39 2 2 2 2 6 10 24 + 178 182 190 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 122 126 140 2 2 2 142 90 5 + 218 159 3 248 183 3 254 194 9 254 198 13 + 254 198 13 254 194 9 250 194 13 250 194 13 + 250 194 13 250 194 13 254 194 14 254 198 13 + 254 198 13 254 202 13 254 202 13 254 206 18 + 254 212 22 254 216 14 254 206 18 194 178 146 + 198 198 200 74 74 74 6 6 7 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 11 + 78 78 79 202 202 202 179 164 133 226 162 16 + 250 190 11 254 198 13 254 198 13 250 194 13 + 250 194 13 246 190 13 246 190 13 246 190 13 + 246 190 13 246 190 13 246 190 13 250 194 13 + 250 194 13 254 194 9 254 198 6 254 194 9 + 253 207 3 214 162 3 171 170 167 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 100 100 102 2 2 2 2 2 2 156 101 3 + 226 160 6 248 184 12 254 194 9 254 198 13 + 254 194 9 250 194 13 250 194 13 250 194 13 + 250 194 13 250 194 13 250 194 13 254 194 14 + 254 198 13 254 202 13 254 202 13 254 206 18 + 254 212 22 254 216 14 254 216 14 226 190 78 + 214 214 215 90 90 90 10 10 11 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 18 18 18 + 112 112 112 222 222 223 186 150 74 226 162 16 + 254 194 14 254 198 13 254 198 13 254 194 14 + 250 194 13 250 190 11 246 190 13 246 190 13 + 246 190 13 246 190 13 246 190 13 250 194 13 + 250 194 13 254 194 9 254 194 9 254 194 9 + 254 198 2 242 198 2 182 138 22 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 241 242 244 46 46 47 + 2 2 2 2 2 2 2 2 2 156 101 3 + 226 160 6 254 186 7 254 194 9 254 198 13 + 254 194 9 250 194 13 250 194 13 250 194 13 + 250 194 13 250 194 13 254 194 14 254 198 13 + 254 198 13 254 202 13 254 206 18 254 206 18 + 254 212 22 254 206 18 254 198 13 194 178 146 + 206 206 206 82 82 82 10 10 11 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 42 42 43 + 158 158 158 226 226 226 211 145 3 236 174 8 + 254 198 13 254 202 13 254 198 13 254 198 13 + 254 194 14 250 194 13 250 194 13 250 194 13 + 250 194 13 250 190 11 250 194 13 250 194 13 + 250 194 13 254 194 9 254 194 9 254 194 9 + 254 194 9 242 198 2 214 162 3 146 122 78 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 130 130 132 2 2 2 2 2 2 + 2 2 2 2 2 2 18 6 2 156 101 3 + 231 166 7 250 190 11 254 198 13 254 198 13 + 254 194 9 250 194 13 250 194 13 250 194 13 + 250 194 13 254 194 14 254 198 13 254 198 13 + 254 202 13 254 202 13 254 206 18 254 206 18 + 254 202 13 248 184 12 226 174 56 222 222 223 + 158 158 158 50 50 51 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 7 70 70 71 + 198 198 200 182 170 146 226 160 6 254 194 9 + 254 206 18 254 202 13 254 202 13 254 198 13 + 254 198 13 254 198 13 254 194 14 250 194 13 + 250 194 13 250 194 13 250 194 13 250 194 13 + 250 194 13 254 194 9 254 198 13 254 198 6 + 254 198 6 241 183 7 231 166 7 142 90 5 + 63 62 63 214 214 215 254 254 254 254 254 254 + 254 254 254 254 254 254 254 254 254 254 254 254 + 254 254 254 254 254 254 230 230 231 134 134 134 + 6 6 7 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 38 22 2 166 110 10 + 231 166 7 250 190 11 254 198 13 254 198 13 + 254 198 13 254 194 14 254 194 14 254 194 14 + 254 198 13 254 198 13 254 198 13 254 202 13 + 254 202 13 254 202 13 254 194 14 248 184 12 + 240 174 22 179 164 133 234 234 235 178 177 177 + 82 82 82 14 14 15 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 10 10 11 90 90 90 + 214 214 215 196 157 72 231 166 7 254 190 11 + 254 202 13 254 202 13 254 202 13 254 198 13 + 254 198 13 254 198 13 254 198 13 254 198 13 + 254 198 13 254 198 13 254 198 13 254 198 13 + 254 198 13 254 194 9 254 198 13 254 198 13 + 254 198 6 254 186 7 231 166 7 170 112 4 + 45 26 2 2 2 2 12 14 26 78 78 79 + 119 119 118 126 126 127 112 112 112 94 94 95 + 54 54 55 6 6 7 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 55 34 3 170 112 4 + 231 166 7 254 190 11 254 202 13 254 202 13 + 254 198 13 254 198 13 254 198 13 254 198 13 + 254 198 13 254 198 13 254 194 14 254 198 13 + 254 194 14 240 174 22 219 155 20 179 164 133 + 214 214 215 210 210 210 150 150 151 74 74 74 + 18 18 18 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 10 10 11 90 90 90 + 210 210 210 196 157 72 221 154 6 234 170 6 + 248 183 3 248 184 12 250 190 11 250 190 11 + 254 190 11 254 194 14 254 198 13 254 198 13 + 254 198 13 254 198 13 254 198 13 254 198 13 + 254 198 13 254 198 13 254 202 13 254 202 13 + 254 202 13 250 190 11 226 160 6 170 112 4 + 90 52 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 82 51 7 182 118 3 + 226 162 16 250 190 11 254 202 13 254 202 13 + 254 202 13 254 202 13 254 198 13 254 198 13 + 254 198 13 250 190 11 248 184 12 236 174 8 + 213 150 7 167 155 134 226 226 226 210 210 210 + 163 162 161 100 100 102 46 46 47 10 10 11 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 7 66 66 67 + 187 187 186 202 202 202 198 146 54 194 131 6 + 206 137 3 207 143 12 213 150 7 221 154 6 + 226 162 16 231 166 7 236 174 8 241 183 7 + 248 184 12 250 190 11 254 198 13 254 198 13 + 254 202 13 254 202 13 254 202 13 254 202 13 + 254 198 13 242 177 7 207 143 12 156 101 3 + 100 63 4 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 82 51 7 170 112 4 + 213 150 7 242 177 7 254 198 13 254 198 13 + 254 202 13 254 198 13 254 198 13 254 194 14 + 241 183 7 231 166 7 221 154 6 187 145 53 + 206 206 206 218 218 219 163 162 161 100 100 102 + 46 46 47 18 18 18 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 26 26 28 + 105 107 112 187 187 186 226 226 226 226 226 226 + 182 182 182 163 143 109 174 126 38 180 114 4 + 186 124 4 186 124 4 194 131 6 194 134 10 + 207 143 12 221 154 6 234 170 6 241 183 7 + 254 190 11 254 194 14 254 198 13 254 194 14 + 248 183 3 221 154 6 182 118 3 142 90 5 + 90 52 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 70 46 2 156 101 3 + 194 134 10 226 162 16 248 183 3 254 194 14 + 254 194 14 254 194 14 248 183 3 234 170 6 + 221 154 6 186 124 4 163 143 109 234 234 235 + 187 187 186 119 119 118 54 54 55 14 14 15 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 7 + 26 26 28 74 74 74 112 112 112 150 150 151 + 182 182 182 210 210 210 230 230 231 202 202 202 + 171 170 167 146 122 78 146 98 22 142 90 5 + 156 101 3 166 110 10 186 124 4 206 137 3 + 211 145 3 218 159 3 231 166 7 226 162 16 + 211 145 3 182 118 3 148 89 3 111 67 3 + 55 34 3 50 50 51 182 182 182 182 182 182 + 202 202 202 237 238 239 234 234 235 234 234 235 + 234 234 235 234 234 235 234 234 235 234 234 235 + 234 234 235 234 234 235 218 218 219 182 182 182 + 178 177 177 126 126 127 78 58 26 130 88 2 + 182 118 3 206 137 3 221 154 6 231 166 7 + 231 166 7 226 162 16 211 145 3 194 134 10 + 166 110 10 174 162 150 226 226 226 163 162 161 + 78 78 79 26 26 28 6 6 7 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 6 6 7 18 18 18 33 34 35 + 58 58 59 90 90 90 130 130 132 163 162 161 + 194 194 195 218 218 219 234 234 235 202 202 202 + 167 155 134 130 114 86 118 76 2 142 90 5 + 156 101 3 166 110 10 170 112 4 170 112 4 + 156 101 3 134 82 2 111 67 3 89 59 3 + 146 146 146 218 218 219 206 206 206 171 170 167 + 155 153 152 140 140 141 130 130 132 126 126 127 + 126 126 127 126 126 127 126 126 127 126 126 127 + 126 126 127 134 134 134 150 150 151 166 166 167 + 191 191 190 234 234 235 130 130 132 100 63 4 + 156 101 3 182 118 3 186 124 4 194 131 6 + 194 131 6 186 124 4 170 112 4 142 90 5 + 171 170 167 218 218 219 146 146 146 63 62 63 + 14 14 15 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 7 10 10 11 26 26 28 42 42 43 + 66 66 67 100 100 102 134 134 134 166 166 167 + 194 194 195 222 222 223 230 230 231 155 153 152 + 110 86 42 111 67 3 111 67 3 118 76 2 + 111 67 3 100 63 4 82 51 7 182 182 182 + 218 218 219 158 158 158 94 94 95 50 50 51 + 33 34 35 26 26 28 22 22 23 22 22 23 + 22 22 23 22 22 23 22 22 23 22 22 23 + 22 22 23 26 26 28 33 34 35 42 42 43 + 78 78 79 166 166 167 226 226 226 120 112 108 + 89 59 3 134 82 2 148 89 3 156 101 3 + 156 101 3 142 90 5 120 78 12 171 170 167 + 218 218 219 134 134 134 50 50 51 10 10 11 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 7 14 14 15 26 26 28 46 46 47 + 70 70 71 112 112 112 155 153 152 198 198 200 + 230 230 231 202 202 202 140 140 141 110 94 70 + 110 94 70 155 153 152 218 218 219 202 202 202 + 126 126 127 50 50 51 14 14 15 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 14 14 15 74 74 74 163 162 161 222 222 223 + 191 191 190 119 119 118 106 92 68 110 94 70 + 118 106 86 150 150 151 226 226 226 202 202 202 + 130 130 132 46 46 47 6 6 7 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 7 18 18 18 42 42 43 78 78 79 + 126 126 127 171 170 167 198 198 200 214 214 215 + 214 214 215 194 194 195 155 153 152 100 100 102 + 33 34 35 6 6 7 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 14 14 15 58 58 59 126 126 127 + 178 177 177 206 206 206 214 214 215 214 214 215 + 210 210 210 194 194 195 150 150 151 90 90 90 + 38 38 39 6 6 7 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 11 + 26 26 28 46 46 47 74 74 74 90 90 90 + 90 90 90 70 70 71 38 38 39 14 14 15 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 7 26 26 28 + 54 54 55 82 82 82 90 90 90 94 94 95 + 86 86 86 66 66 67 38 38 39 14 14 15 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 diff --git a/drivers/video/logo/logo_sgi_clut224.ppm b/drivers/video/logo/logo_sgi_clut224.ppm new file mode 100644 index 000000000000..6fe4697c6001 --- /dev/null +++ b/drivers/video/logo/logo_sgi_clut224.ppm @@ -0,0 +1,1604 @@ +P3 +# 224-color SGI Linux logo +80 80 +255 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 6 6 6 10 10 10 10 10 10 + 10 10 10 6 6 6 6 6 6 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 10 10 10 14 14 14 + 22 22 22 26 26 26 30 30 30 34 34 34 + 30 30 30 30 30 30 26 26 26 18 18 18 + 14 14 14 10 10 10 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 26 26 26 42 42 42 + 54 54 54 66 66 66 78 78 78 78 78 78 + 78 78 78 74 74 74 66 66 66 54 54 54 + 42 42 42 26 26 26 18 18 18 10 10 10 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 22 22 22 42 42 42 66 66 66 86 86 86 + 66 66 66 38 38 38 38 38 38 22 22 22 + 26 26 26 34 34 34 54 54 54 66 66 66 + 86 86 86 70 70 70 46 46 46 26 26 26 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 26 26 26 + 50 50 50 82 82 82 58 58 58 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 54 54 54 86 86 86 66 66 66 + 38 38 38 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 22 22 22 50 50 50 + 78 78 78 34 34 34 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 6 6 6 70 70 70 + 78 78 78 46 46 46 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 42 42 42 82 82 82 + 26 26 26 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 14 14 14 + 46 46 46 34 34 34 6 6 6 2 2 6 + 42 42 42 78 78 78 42 42 42 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 30 30 30 66 66 66 58 58 58 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 26 26 26 + 86 86 86 101 101 101 46 46 46 10 10 10 + 2 2 6 58 58 58 70 70 70 34 34 34 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 42 42 42 86 86 86 10 10 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 30 30 30 + 94 94 94 94 94 94 58 58 58 26 26 26 + 2 2 6 6 6 6 78 78 78 54 54 54 + 22 22 22 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 62 62 62 62 62 62 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 26 26 26 + 54 54 54 38 38 38 18 18 18 10 10 10 + 2 2 6 2 2 6 34 34 34 82 82 82 + 38 38 38 14 14 14 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 30 30 30 78 78 78 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 10 10 10 + 10 10 10 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 78 78 78 + 50 50 50 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 14 14 14 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 54 54 54 + 66 66 66 26 26 26 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 82 82 82 2 2 6 2 2 6 + 2 2 6 6 6 6 10 10 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 6 6 6 + 14 14 14 10 10 10 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 18 18 18 + 82 82 82 34 34 34 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 2 2 6 + 6 6 6 6 6 6 22 22 22 34 34 34 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 34 34 34 + 10 10 10 50 50 50 22 22 22 2 2 6 + 2 2 6 2 2 6 2 2 6 10 10 10 + 86 86 86 42 42 42 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 2 2 6 + 38 38 38 116 116 116 94 94 94 22 22 22 + 22 22 22 2 2 6 2 2 6 2 2 6 + 14 14 14 86 86 86 138 138 138 162 162 162 +154 154 154 38 38 38 26 26 26 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 86 86 86 46 46 46 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 14 14 14 +134 134 134 198 198 198 195 195 195 116 116 116 + 10 10 10 2 2 6 2 2 6 6 6 6 +101 98 89 187 187 187 210 210 210 218 218 218 +214 214 214 134 134 134 14 14 14 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 86 86 86 50 50 50 18 18 18 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 54 54 54 +218 218 218 195 195 195 226 226 226 246 246 246 + 58 58 58 2 2 6 2 2 6 30 30 30 +210 210 210 253 253 253 174 174 174 123 123 123 +221 221 221 234 234 234 74 74 74 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 82 82 82 2 2 6 106 106 106 +170 170 170 26 26 26 86 86 86 226 226 226 +123 123 123 10 10 10 14 14 14 46 46 46 +231 231 231 190 190 190 6 6 6 70 70 70 + 90 90 90 238 238 238 158 158 158 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 86 86 86 6 6 6 116 116 116 +106 106 106 6 6 6 70 70 70 149 149 149 +128 128 128 18 18 18 38 38 38 54 54 54 +221 221 221 106 106 106 2 2 6 14 14 14 + 46 46 46 190 190 190 198 198 198 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 62 62 62 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 94 94 94 14 14 14 101 101 101 +128 128 128 2 2 6 18 18 18 116 116 116 +118 98 46 121 92 8 121 92 8 98 78 10 +162 162 162 106 106 106 2 2 6 2 2 6 + 2 2 6 195 195 195 195 195 195 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 62 62 62 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 1 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 90 90 90 14 14 14 58 58 58 +210 210 210 26 26 26 54 38 6 154 114 10 +226 170 11 236 186 11 225 175 15 184 144 12 +215 174 15 175 146 61 37 26 9 2 2 6 + 70 70 70 246 246 246 138 138 138 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 66 66 66 26 26 26 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 14 14 14 10 10 10 +195 195 195 188 164 115 192 133 9 225 175 15 +239 182 13 234 190 10 232 195 16 232 200 30 +245 207 45 241 208 19 232 195 16 184 144 12 +218 194 134 211 206 186 42 42 42 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 50 50 50 74 74 74 30 30 30 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 86 86 86 14 14 14 2 2 6 +121 87 25 192 133 9 219 162 10 239 182 13 +236 186 11 232 195 16 241 208 19 244 214 54 +246 218 60 246 218 38 246 215 20 241 208 19 +241 208 19 226 184 13 121 87 25 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 50 50 50 82 82 82 34 34 34 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 82 82 82 30 30 30 61 42 6 +180 123 7 206 145 10 230 174 11 239 182 13 +234 190 10 238 202 15 241 208 19 246 218 74 +246 218 38 246 215 20 246 215 20 246 215 20 +226 184 13 215 174 15 184 144 12 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 26 26 26 94 94 94 42 42 42 14 14 14 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 50 50 50 104 69 6 +192 133 9 216 158 10 236 178 12 236 186 11 +232 195 16 241 208 19 244 214 54 245 215 43 +246 215 20 246 215 20 241 208 19 198 155 10 +200 144 11 216 158 10 156 118 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 90 90 90 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 46 46 46 22 22 22 +137 92 6 210 162 10 239 182 13 238 190 10 +238 202 15 241 208 19 246 215 20 246 215 20 +241 208 19 203 166 17 185 133 11 210 150 10 +216 158 10 210 150 10 102 78 10 2 2 6 + 6 6 6 54 54 54 14 14 14 2 2 6 + 2 2 6 62 62 62 74 74 74 30 30 30 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 78 78 78 50 50 50 6 6 6 + 94 70 30 139 102 15 190 146 13 226 184 13 +232 200 30 232 195 16 215 174 15 190 146 13 +168 122 10 192 133 9 210 150 10 213 154 11 +202 150 34 182 157 106 101 98 89 2 2 6 + 2 2 6 78 78 78 116 116 116 58 58 58 + 2 2 6 22 22 22 90 90 90 46 46 46 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 50 50 50 6 6 6 +128 128 128 174 154 114 156 107 11 168 122 10 +198 155 10 184 144 12 197 138 11 200 144 11 +206 145 10 206 145 10 197 138 11 188 164 115 +195 195 195 198 198 198 174 174 174 14 14 14 + 2 2 6 22 22 22 116 116 116 116 116 116 + 22 22 22 2 2 6 74 74 74 70 70 70 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 101 101 101 26 26 26 10 10 10 +138 138 138 190 190 190 174 154 114 156 107 11 +197 138 11 200 144 11 197 138 11 192 133 9 +180 123 7 190 142 34 190 178 144 187 187 187 +202 202 202 221 221 221 214 214 214 66 66 66 + 2 2 6 2 2 6 50 50 50 62 62 62 + 6 6 6 2 2 6 10 10 10 90 90 90 + 50 50 50 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 34 34 34 + 74 74 74 74 74 74 2 2 6 6 6 6 +144 144 144 198 198 198 190 190 190 178 166 146 +154 121 60 156 107 11 156 107 11 168 124 44 +174 154 114 187 187 187 190 190 190 210 210 210 +246 246 246 253 253 253 253 253 253 182 182 182 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 62 62 62 + 74 74 74 34 34 34 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 10 10 10 22 22 22 54 54 54 + 94 94 94 18 18 18 2 2 6 46 46 46 +234 234 234 221 221 221 190 190 190 190 190 190 +190 190 190 187 187 187 187 187 187 190 190 190 +190 190 190 195 195 195 214 214 214 242 242 242 +253 253 253 253 253 253 253 253 253 253 253 253 + 82 82 82 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 14 14 14 + 86 86 86 54 54 54 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 46 46 46 90 90 90 + 46 46 46 18 18 18 6 6 6 182 182 182 +253 253 253 246 246 246 206 206 206 190 190 190 +190 190 190 190 190 190 190 190 190 190 190 190 +206 206 206 231 231 231 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +202 202 202 14 14 14 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 42 42 42 86 86 86 42 42 42 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 14 14 14 38 38 38 74 74 74 66 66 66 + 2 2 6 6 6 6 90 90 90 250 250 250 +253 253 253 253 253 253 238 238 238 198 198 198 +190 190 190 190 190 190 195 195 195 221 221 221 +246 246 246 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 82 82 82 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 78 78 78 70 70 70 34 34 34 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 34 34 34 66 66 66 78 78 78 6 6 6 + 2 2 6 18 18 18 218 218 218 253 253 253 +253 253 253 253 253 253 253 253 253 246 246 246 +226 226 226 231 231 231 246 246 246 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 178 178 178 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 18 18 18 90 90 90 62 62 62 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 26 26 26 + 58 58 58 90 90 90 18 18 18 2 2 6 + 2 2 6 110 110 110 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 231 231 231 18 18 18 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 94 94 94 + 54 54 54 26 26 26 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 22 22 22 50 50 50 + 90 90 90 26 26 26 2 2 6 2 2 6 + 14 14 14 195 195 195 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +250 250 250 242 242 242 54 54 54 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 38 38 38 + 86 86 86 50 50 50 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 38 38 38 82 82 82 + 34 34 34 2 2 6 2 2 6 2 2 6 + 42 42 42 195 195 195 246 246 246 253 253 253 +253 253 253 253 253 253 253 253 253 250 250 250 +242 242 242 242 242 242 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 250 250 250 246 246 246 238 238 238 +226 226 226 231 231 231 101 101 101 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 38 38 38 82 82 82 42 42 42 14 14 14 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 26 26 26 62 62 62 66 66 66 + 2 2 6 2 2 6 2 2 6 6 6 6 + 70 70 70 170 170 170 206 206 206 234 234 234 +246 246 246 250 250 250 250 250 250 238 238 238 +226 226 226 231 231 231 238 238 238 250 250 250 +250 250 250 250 250 250 246 246 246 231 231 231 +214 214 214 206 206 206 202 202 202 202 202 202 +198 198 198 202 202 202 182 182 182 18 18 18 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 62 62 62 66 66 66 30 30 30 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 42 42 42 82 82 82 18 18 18 + 2 2 6 2 2 6 2 2 6 10 10 10 + 94 94 94 182 182 182 218 218 218 242 242 242 +250 250 250 253 253 253 253 253 253 250 250 250 +234 234 234 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 246 246 246 +238 238 238 226 226 226 210 210 210 202 202 202 +195 195 195 195 195 195 210 210 210 158 158 158 + 6 6 6 14 14 14 50 50 50 14 14 14 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 86 86 86 46 46 46 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 54 54 54 70 70 70 2 2 6 + 2 2 6 10 10 10 2 2 6 22 22 22 +166 166 166 231 231 231 250 250 250 253 253 253 +253 253 253 253 253 253 253 253 253 250 250 250 +242 242 242 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 246 246 246 +231 231 231 206 206 206 198 198 198 226 226 226 + 94 94 94 2 2 6 6 6 6 38 38 38 + 30 30 30 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 62 62 62 66 66 66 + 26 26 26 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 74 74 74 50 50 50 2 2 6 + 26 26 26 26 26 26 2 2 6 106 106 106 +238 238 238 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 231 231 231 +134 134 134 106 106 106 174 174 174 253 253 253 +182 182 182 54 54 54 128 128 128 231 231 231 +250 250 250 253 253 253 253 253 253 253 253 253 +253 253 253 246 246 246 218 218 218 202 202 202 +210 210 210 14 14 14 2 2 6 2 2 6 + 30 30 30 22 22 22 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 86 86 86 + 42 42 42 14 14 14 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 90 90 90 22 22 22 2 2 6 + 42 42 42 2 2 6 18 18 18 218 218 218 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 231 231 231 149 149 149 94 94 94 +154 154 154 182 182 182 101 101 101 250 250 250 +116 116 116 10 10 10 14 14 14 42 42 42 +128 128 128 231 231 231 253 253 253 253 253 253 +253 253 253 253 253 253 250 250 250 221 221 221 +218 218 218 101 101 101 2 2 6 14 14 14 + 18 18 18 38 38 38 10 10 10 2 2 6 + 2 2 6 2 2 6 2 2 6 78 78 78 + 58 58 58 22 22 22 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 54 54 54 82 82 82 2 2 6 26 26 26 + 22 22 22 2 2 6 123 123 123 253 253 253 +253 253 253 253 253 253 253 253 253 238 238 238 +158 158 158 101 101 101 149 149 149 182 182 182 +128 128 128 94 94 94 94 94 94 246 246 246 +123 123 123 78 78 78 38 38 38 14 14 14 + 18 18 18 62 62 62 158 158 158 238 238 238 +253 253 253 253 253 253 253 253 253 250 250 250 +238 238 238 198 198 198 6 6 6 38 38 38 + 58 58 58 26 26 26 38 38 38 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 78 78 78 30 30 30 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 30 30 30 + 74 74 74 58 58 58 2 2 6 42 42 42 + 2 2 6 22 22 22 231 231 231 253 253 253 +253 253 253 250 250 250 128 128 128 62 62 62 +128 128 128 158 158 158 116 116 116 128 128 128 +116 116 116 90 90 90 90 90 90 246 246 246 +128 128 128 116 116 116 106 106 106 101 101 101 + 38 38 38 10 10 10 22 22 22 54 54 54 +149 149 149 250 250 250 253 253 253 253 253 253 +253 253 253 246 246 246 46 46 46 38 38 38 + 42 42 42 14 14 14 38 38 38 14 14 14 + 2 2 6 2 2 6 2 2 6 6 6 6 + 86 86 86 46 46 46 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 42 42 42 + 90 90 90 18 18 18 18 18 18 26 26 26 + 2 2 6 116 116 116 253 253 253 253 253 253 +253 253 253 231 231 231 30 30 30 14 14 14 + 30 30 30 62 62 62 134 134 134 210 210 210 +174 174 174 101 101 101 86 86 86 250 250 250 +128 128 128 116 116 116 149 149 149 210 210 210 +134 134 134 38 38 38 46 46 46 154 154 154 +174 174 174 198 198 198 253 253 253 253 253 253 +253 253 253 253 253 253 94 94 94 6 6 6 + 2 2 6 2 2 6 10 10 10 34 34 34 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 10 10 10 26 26 26 66 66 66 + 82 82 82 2 2 6 38 38 38 6 6 6 + 14 14 14 210 210 210 253 253 253 253 253 253 +253 253 253 246 246 246 138 138 138 46 46 46 + 6 6 6 18 18 18 54 54 54 166 166 166 +174 174 174 101 101 101 74 74 74 238 238 238 +123 123 123 101 101 101 166 166 166 182 182 182 + 90 90 90 116 116 116 202 202 202 149 149 149 +128 128 128 231 231 231 253 253 253 253 253 253 +253 253 253 253 253 253 144 144 144 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 2 2 6 2 2 6 2 2 6 2 2 6 + 42 42 42 74 74 74 30 30 30 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 42 42 42 90 90 90 + 26 26 26 6 6 6 42 42 42 2 2 6 + 74 74 74 250 250 250 253 253 253 253 253 253 +238 238 238 221 221 221 238 238 238 166 166 166 + 90 90 90 38 38 38 10 10 10 18 18 18 + 46 46 46 46 46 46 62 62 62 246 246 246 +101 101 101 42 42 42 62 62 62 116 116 116 +190 190 190 141 141 141 116 116 116 141 141 141 +221 221 221 250 250 250 253 253 253 253 253 253 +253 253 253 253 253 253 182 182 182 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 2 2 6 2 2 6 2 2 6 2 2 6 + 10 10 10 86 86 86 38 38 38 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 26 26 26 66 66 66 82 82 82 + 2 2 6 22 22 22 18 18 18 2 2 6 +149 149 149 253 253 253 253 253 253 214 214 214 + 38 38 38 38 38 38 166 166 166 238 238 238 +214 214 214 116 116 116 70 70 70 26 26 26 + 10 10 10 26 26 26 42 42 42 182 182 182 + 62 62 62 86 86 86 187 187 187 174 174 174 +123 123 123 138 138 138 190 190 190 246 246 246 +210 210 210 110 110 110 138 138 138 221 221 221 +253 253 253 253 253 253 206 206 206 2 2 6 + 2 2 6 2 2 6 2 2 6 38 38 38 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 86 86 86 46 46 46 14 14 14 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 18 18 18 46 46 46 86 86 86 18 18 18 + 2 2 6 34 34 34 10 10 10 6 6 6 +210 210 210 253 253 253 253 253 253 190 190 190 + 38 38 38 14 14 14 26 26 26 86 86 86 +198 198 198 238 238 238 174 174 174 90 90 90 + 62 62 62 26 26 26 22 22 22 54 54 54 +166 166 166 187 187 187 134 134 134 128 128 128 +166 166 166 231 231 231 231 231 231 149 149 149 +123 123 123 166 166 166 174 174 174 190 190 190 +253 253 253 253 253 253 221 221 221 6 6 6 + 2 2 6 2 2 6 6 6 6 30 30 30 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 82 82 82 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 26 26 26 66 66 66 62 62 62 2 2 6 + 2 2 6 38 38 38 10 10 10 26 26 26 +238 238 238 253 253 253 253 253 253 214 214 214 +116 116 116 90 90 90 30 30 30 14 14 14 + 38 38 38 110 110 110 214 214 214 195 195 195 +116 116 116 62 62 62 54 54 54 54 54 54 +138 138 138 116 116 116 128 128 128 221 221 221 +246 246 246 166 166 166 116 116 116 174 174 174 +166 166 166 141 141 141 138 138 138 206 206 206 +253 253 253 253 253 253 231 231 231 6 6 6 + 2 2 6 2 2 6 10 10 10 30 30 30 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 58 58 58 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 78 78 78 6 6 6 2 2 6 + 2 2 6 46 46 46 14 14 14 42 42 42 +246 246 246 253 253 253 253 253 253 210 210 210 +134 134 134 116 116 116 110 110 110 54 54 54 + 14 14 14 26 26 26 62 62 62 106 106 106 + 54 54 54 70 70 70 78 78 78 110 110 110 + 82 82 82 74 74 74 86 86 86 166 166 166 +116 116 116 128 128 128 198 198 198 141 141 141 +141 141 141 134 134 134 128 128 128 210 210 210 +253 253 253 253 253 253 234 234 234 10 10 10 + 2 2 6 2 2 6 22 22 22 14 14 14 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 62 62 62 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 74 74 74 2 2 6 2 2 6 + 14 14 14 70 70 70 34 34 34 62 62 62 +250 250 250 253 253 253 253 253 253 231 231 231 +134 134 134 106 106 106 128 128 128 166 166 166 + 90 90 90 22 22 22 14 14 14 30 30 30 + 46 46 46 66 66 66 138 138 138 221 221 221 +128 128 128 46 46 46 54 54 54 101 101 101 +182 182 182 166 166 166 134 134 134 166 166 166 +128 128 128 101 101 101 134 134 134 221 221 221 +253 253 253 253 253 253 234 234 234 14 14 14 + 2 2 6 2 2 6 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 62 62 62 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 54 54 54 62 62 62 2 2 6 2 2 6 + 2 2 6 30 30 30 46 46 46 70 70 70 +250 250 250 253 253 253 253 253 253 231 231 231 +128 128 128 116 116 116 158 158 158 158 158 158 + 74 74 74 110 110 110 82 82 82 18 18 18 + 18 18 18 101 101 101 182 182 182 214 214 214 +134 134 134 54 54 54 174 174 174 166 166 166 +138 138 138 134 134 134 78 78 78 211 206 186 +123 123 123 116 116 116 138 138 138 231 231 231 +253 253 253 253 253 253 226 226 226 10 10 10 + 2 2 6 6 6 6 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 58 58 58 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 58 58 58 62 62 62 2 2 6 2 2 6 + 2 2 6 2 2 6 30 30 30 78 78 78 +250 250 250 253 253 253 253 253 253 246 246 246 +138 138 138 116 116 116 86 86 86 101 101 101 +174 174 174 94 94 94 94 94 94 116 116 116 + 54 54 54 70 70 70 90 90 90 46 46 46 + 54 54 54 30 30 30 101 101 101 141 141 141 +128 128 128 46 46 46 30 30 30 54 54 54 + 78 78 78 110 110 110 138 138 138 238 238 238 +253 253 253 253 253 253 206 206 206 2 2 6 + 22 22 22 34 34 34 18 14 6 22 22 22 + 26 26 26 18 18 18 6 6 6 2 2 6 + 2 2 6 82 82 82 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 26 26 26 + 62 62 62 106 106 106 74 54 14 185 133 11 +210 162 10 121 92 8 6 6 6 62 62 62 +238 238 238 253 253 253 253 253 253 246 246 246 +141 141 141 123 123 123 106 106 106 128 128 128 +101 101 101 141 141 141 214 214 214 166 166 166 +134 134 134 149 149 149 106 106 106 78 78 78 + 90 90 90 138 138 138 154 154 154 195 195 195 +190 190 190 86 86 86 46 46 46 14 14 14 + 42 42 42 116 116 116 149 149 149 246 246 246 +253 253 253 253 253 253 158 158 158 18 18 18 + 14 14 14 2 2 6 2 2 6 2 2 6 + 6 6 6 18 18 18 66 66 66 38 38 38 + 6 6 6 94 94 94 50 50 50 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 10 10 10 10 10 10 18 18 18 38 38 38 + 78 78 78 142 134 106 216 158 10 242 186 14 +246 190 14 246 190 14 156 118 10 10 10 10 + 90 90 90 238 238 238 253 253 253 250 250 250 +138 138 138 116 116 116 86 86 86 149 149 149 +198 198 198 221 221 221 138 138 138 82 82 82 +134 134 134 128 128 128 82 82 82 106 106 106 + 82 82 82 138 138 138 138 138 138 128 128 128 +187 187 187 221 221 221 166 166 166 70 70 70 + 54 54 54 116 116 116 166 166 166 246 246 246 +238 204 91 238 204 91 181 142 44 37 26 9 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 38 38 38 46 46 46 + 26 26 26 106 106 106 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 22 22 22 + 30 30 30 38 38 38 50 50 50 70 70 70 +106 106 106 190 142 34 226 170 11 242 186 14 +246 190 14 246 190 14 246 190 14 154 114 10 + 6 6 6 74 74 74 226 226 226 253 253 253 +206 206 206 138 138 138 187 187 187 246 246 246 +187 187 187 110 110 110 101 101 101 62 62 62 +123 123 123 134 134 134 116 116 116 238 238 238 + 94 94 94 134 134 134 134 134 134 54 54 54 + 26 26 26 101 101 101 231 231 231 231 231 231 +128 128 128 128 128 128 214 214 214 228 184 62 +241 196 14 241 208 19 232 195 16 38 30 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 30 30 30 26 26 26 +203 166 17 154 142 90 66 66 66 26 26 26 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 38 38 38 58 58 58 + 78 78 78 86 86 86 101 101 101 123 123 123 +175 146 61 210 150 10 234 174 13 246 186 14 +246 190 14 246 190 14 246 190 14 238 190 10 +102 78 10 2 2 6 46 46 46 198 198 198 +253 253 253 246 246 246 221 221 221 123 123 123 +110 110 110 128 128 128 86 86 86 90 90 90 +116 116 116 138 138 138 128 128 128 250 250 250 +106 106 106 138 138 138 128 128 128 62 62 62 + 22 22 22 18 18 18 46 46 46 166 166 166 +246 246 246 246 246 246 253 253 253 224 178 62 +242 186 14 241 196 14 210 166 10 22 18 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 6 6 6 121 92 8 +238 202 15 232 195 16 82 82 82 34 34 34 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 38 38 38 70 70 70 154 122 46 +190 142 34 200 144 11 197 138 11 197 138 11 +213 154 11 226 170 11 242 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +225 175 15 46 32 6 2 2 6 22 22 22 +158 158 158 246 246 246 101 101 101 38 38 38 + 46 46 46 74 74 74 182 182 182 198 198 198 +116 116 116 134 134 134 123 123 123 246 246 246 +110 110 110 134 134 134 149 149 149 195 195 195 +128 128 128 38 38 38 38 38 38 123 123 123 +211 206 186 250 250 250 242 242 242 224 178 62 +239 182 13 236 186 11 213 154 11 46 32 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 61 42 6 225 175 15 +238 190 10 236 186 11 112 100 78 42 42 42 + 14 14 14 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 54 54 54 154 122 46 213 154 11 +226 170 11 230 174 11 226 170 11 226 170 11 +236 178 12 242 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +241 196 14 184 144 12 10 10 10 2 2 6 + 6 6 6 116 116 116 154 154 154 38 38 38 + 10 10 10 18 18 18 116 116 116 218 218 218 +123 123 123 134 134 134 134 134 134 250 250 250 +110 110 110 134 134 134 166 166 166 221 221 221 +128 128 128 74 74 74 187 187 187 141 141 141 +202 202 202 231 231 231 198 198 198 214 170 54 +236 178 12 236 178 12 210 150 10 137 92 6 + 18 14 6 2 2 6 2 2 6 2 2 6 + 6 6 6 70 47 6 200 144 11 236 178 12 +239 182 13 239 182 13 124 112 88 58 58 58 + 22 22 22 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 70 70 70 180 133 36 226 170 11 +239 182 13 242 186 14 242 186 14 246 186 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 232 195 16 98 70 6 2 2 6 + 2 2 6 2 2 6 66 66 66 149 149 149 + 70 70 70 14 14 14 30 30 30 66 66 66 +116 116 116 138 138 138 128 128 128 246 246 246 +101 101 101 138 138 138 138 138 138 94 94 94 +123 123 123 182 182 182 128 128 128 182 182 182 +246 246 246 206 206 206 198 198 198 214 166 58 +230 174 11 230 174 11 216 158 10 192 133 9 +163 110 8 116 81 8 102 78 10 116 81 8 +167 114 7 197 138 11 226 170 11 239 182 13 +242 186 14 242 186 14 162 146 94 78 78 78 + 34 34 34 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 30 30 30 78 78 78 190 142 34 226 170 11 +239 182 13 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 241 196 14 203 166 17 22 18 6 + 2 2 6 2 2 6 2 2 6 38 38 38 +182 182 182 101 101 101 38 38 38 30 30 30 +110 110 110 134 134 134 141 141 141 250 250 250 +101 101 101 138 138 138 138 138 138 158 158 158 +158 158 158 154 154 154 221 221 221 253 253 253 +250 250 250 206 206 206 198 198 198 202 162 69 +226 170 11 236 178 12 224 166 10 210 150 10 +200 144 11 197 138 11 192 133 9 197 138 11 +210 150 10 226 170 11 242 186 14 246 190 14 +246 190 14 246 186 14 225 175 15 124 112 88 + 62 62 62 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 174 135 50 224 166 10 +239 182 13 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 241 196 14 139 102 15 + 2 2 6 2 2 6 2 2 6 2 2 6 + 78 78 78 198 198 198 138 138 138 70 70 70 +106 106 106 134 134 134 141 141 141 246 246 246 + 94 94 94 138 138 138 134 134 134 134 134 134 +182 182 182 238 238 238 253 253 253 253 253 253 +250 250 250 214 214 214 198 198 198 190 150 46 +219 162 10 236 178 12 234 174 13 224 166 10 +216 158 10 213 154 11 213 154 11 216 158 10 +226 170 11 239 182 13 246 190 14 246 190 14 +246 190 14 246 190 14 242 186 14 206 162 42 +101 101 101 58 58 58 30 30 30 14 14 14 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 74 74 74 174 135 50 216 158 10 +236 178 12 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 241 196 14 226 184 13 + 61 42 6 2 2 6 2 2 6 2 2 6 + 22 22 22 238 238 238 246 246 246 174 174 174 +116 116 116 128 128 128 182 182 182 246 246 246 +110 110 110 134 134 134 149 149 149 214 214 214 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 226 226 226 187 187 187 180 133 36 +216 158 10 236 178 12 239 182 13 236 178 12 +230 174 11 226 170 11 226 170 11 230 174 11 +236 178 12 242 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 186 14 239 182 13 +206 162 42 106 106 106 66 66 66 34 34 34 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 26 26 26 70 70 70 163 133 67 213 154 11 +236 178 12 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 241 196 14 +190 146 13 18 14 6 2 2 6 2 2 6 + 46 46 46 246 246 246 253 253 253 250 250 250 +206 206 206 198 198 198 246 246 246 253 253 253 +221 221 221 195 195 195 231 231 231 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 221 221 221 86 86 86 156 107 11 +216 158 10 236 178 12 242 186 14 246 186 14 +242 186 14 239 182 13 239 182 13 242 186 14 +242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +242 186 14 225 175 15 142 122 72 66 66 66 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 26 26 26 70 70 70 163 133 67 210 150 10 +236 178 12 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +232 195 16 121 92 8 34 34 34 106 106 106 +221 221 221 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +242 242 242 82 82 82 18 14 6 163 110 8 +216 158 10 236 178 12 242 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 242 186 14 163 133 67 + 46 46 46 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 163 133 67 210 150 10 +236 178 12 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +241 196 14 215 174 15 190 178 144 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 218 218 218 + 58 58 58 2 2 6 22 18 6 167 114 7 +216 158 10 236 178 12 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 186 14 242 186 14 190 150 46 + 54 54 54 22 22 22 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 38 38 38 86 86 86 180 133 36 213 154 11 +236 178 12 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 232 195 16 190 146 13 214 214 214 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 250 250 250 170 170 170 26 26 26 + 2 2 6 2 2 6 37 26 9 163 110 8 +219 162 10 239 182 13 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 236 178 12 224 166 10 142 122 72 + 46 46 46 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 109 106 95 192 133 9 224 166 10 +242 186 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +242 186 14 226 184 13 210 162 10 142 110 46 +226 226 226 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +253 253 253 253 253 253 253 253 253 253 253 253 +198 198 198 66 66 66 2 2 6 2 2 6 + 2 2 6 2 2 6 50 34 6 156 107 11 +219 162 10 239 182 13 246 186 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 242 186 14 +234 174 13 213 154 11 154 122 46 66 66 66 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 58 58 58 154 121 60 206 145 10 234 174 13 +242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 236 178 12 210 162 10 163 110 8 + 61 42 6 138 138 138 218 218 218 250 250 250 +253 253 253 253 253 253 253 253 253 250 250 250 +242 242 242 210 210 210 144 144 144 66 66 66 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 61 42 6 163 110 8 +216 158 10 236 178 12 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 239 182 13 230 174 11 216 158 10 +190 142 34 124 112 88 70 70 70 38 38 38 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 62 62 62 168 124 44 206 145 10 224 166 10 +236 178 12 239 182 13 242 186 14 242 186 14 +246 186 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 236 178 12 216 158 10 175 118 6 + 80 54 7 2 2 6 6 6 6 30 30 30 + 54 54 54 62 62 62 50 50 50 38 38 38 + 14 14 14 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 80 54 7 167 114 7 +213 154 11 236 178 12 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 242 186 14 239 182 13 239 182 13 +230 174 11 210 150 10 174 135 50 124 112 88 + 82 82 82 54 54 54 34 34 34 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 158 118 36 192 133 9 200 144 11 +216 158 10 219 162 10 224 166 10 226 170 11 +230 174 11 236 178 12 239 182 13 239 182 13 +242 186 14 246 186 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 186 14 230 174 11 210 150 10 163 110 8 +104 69 6 10 10 10 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 91 60 6 167 114 7 +206 145 10 230 174 11 242 186 14 246 190 14 +246 190 14 246 190 14 246 186 14 242 186 14 +239 182 13 230 174 11 224 166 10 213 154 11 +180 133 36 124 112 88 86 86 86 58 58 58 + 38 38 38 22 22 22 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 34 34 34 70 70 70 138 110 50 158 118 36 +167 114 7 180 123 7 192 133 9 197 138 11 +200 144 11 206 145 10 213 154 11 219 162 10 +224 166 10 230 174 11 239 182 13 242 186 14 +246 186 14 246 186 14 246 186 14 246 186 14 +239 182 13 216 158 10 185 133 11 152 99 6 +104 69 6 18 14 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 80 54 7 152 99 6 +192 133 9 219 162 10 236 178 12 239 182 13 +246 186 14 242 186 14 239 182 13 236 178 12 +224 166 10 206 145 10 192 133 9 154 121 60 + 94 94 94 62 62 62 42 42 42 22 22 22 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 18 18 18 34 34 34 58 58 58 78 78 78 +101 98 89 124 112 88 142 110 46 156 107 11 +163 110 8 167 114 7 175 118 6 180 123 7 +185 133 11 197 138 11 210 150 10 219 162 10 +226 170 11 236 178 12 236 178 12 234 174 13 +219 162 10 197 138 11 163 110 8 130 83 6 + 91 60 6 10 10 10 2 2 6 2 2 6 + 18 18 18 38 38 38 38 38 38 38 38 38 + 38 38 38 38 38 38 38 38 38 38 38 38 + 38 38 38 38 38 38 26 26 26 2 2 6 + 2 2 6 6 6 6 70 47 6 137 92 6 +175 118 6 200 144 11 219 162 10 230 174 11 +234 174 13 230 174 11 219 162 10 210 150 10 +192 133 9 163 110 8 124 112 88 82 82 82 + 50 50 50 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 22 22 22 34 34 34 + 42 42 42 58 58 58 74 74 74 86 86 86 +101 98 89 122 102 70 130 98 46 121 87 25 +137 92 6 152 99 6 163 110 8 180 123 7 +185 133 11 197 138 11 206 145 10 200 144 11 +180 123 7 156 107 11 130 83 6 104 69 6 + 50 34 6 54 54 54 110 110 110 101 98 89 + 86 86 86 82 82 82 78 78 78 78 78 78 + 78 78 78 78 78 78 78 78 78 78 78 78 + 78 78 78 82 82 82 86 86 86 94 94 94 +106 106 106 101 101 101 86 66 34 124 80 6 +156 107 11 180 123 7 192 133 9 200 144 11 +206 145 10 200 144 11 192 133 9 175 118 6 +139 102 15 109 106 95 70 70 70 42 42 42 + 22 22 22 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 10 10 10 + 14 14 14 22 22 22 30 30 30 38 38 38 + 50 50 50 62 62 62 74 74 74 90 90 90 +101 98 89 112 100 78 121 87 25 124 80 6 +137 92 6 152 99 6 152 99 6 152 99 6 +138 86 6 124 80 6 98 70 6 86 66 30 +101 98 89 82 82 82 58 58 58 46 46 46 + 38 38 38 34 34 34 34 34 34 34 34 34 + 34 34 34 34 34 34 34 34 34 34 34 34 + 34 34 34 34 34 34 38 38 38 42 42 42 + 54 54 54 82 82 82 94 86 76 91 60 6 +134 86 6 156 107 11 167 114 7 175 118 6 +175 118 6 167 114 7 152 99 6 121 87 25 +101 98 89 62 62 62 34 34 34 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 6 6 6 10 10 10 + 18 18 18 22 22 22 30 30 30 42 42 42 + 50 50 50 66 66 66 86 86 86 101 98 89 +106 86 58 98 70 6 104 69 6 104 69 6 +104 69 6 91 60 6 82 62 34 90 90 90 + 62 62 62 38 38 38 22 22 22 14 14 14 + 10 10 10 10 10 10 10 10 10 10 10 10 + 10 10 10 10 10 10 6 6 6 10 10 10 + 10 10 10 10 10 10 10 10 10 14 14 14 + 22 22 22 42 42 42 70 70 70 89 81 66 + 80 54 7 104 69 6 124 80 6 137 92 6 +134 86 6 116 81 8 100 82 52 86 86 86 + 58 58 58 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 10 10 10 14 14 14 + 18 18 18 26 26 26 38 38 38 54 54 54 + 70 70 70 86 86 86 94 86 76 89 81 66 + 89 81 66 86 86 86 74 74 74 50 50 50 + 30 30 30 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 34 34 34 58 58 58 + 82 82 82 89 81 66 89 81 66 89 81 66 + 94 86 66 94 86 76 74 74 74 50 50 50 + 26 26 26 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 6 6 6 14 14 14 18 18 18 + 30 30 30 38 38 38 46 46 46 54 54 54 + 50 50 50 42 42 42 30 30 30 18 18 18 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 26 26 26 + 38 38 38 50 50 50 58 58 58 58 58 58 + 54 54 54 42 42 42 30 30 30 18 18 18 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 6 6 6 10 10 10 14 14 14 18 18 18 + 18 18 18 14 14 14 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 14 14 14 18 18 18 22 22 22 22 22 22 + 18 18 18 14 14 14 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/drivers/video/logo/logo_sun_clut224.ppm b/drivers/video/logo/logo_sun_clut224.ppm new file mode 100644 index 000000000000..40e6339216f4 --- /dev/null +++ b/drivers/video/logo/logo_sun_clut224.ppm @@ -0,0 +1,1604 @@ +P3 +# 224-color Sun Linux logo +80 80 +255 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 6 6 6 10 10 10 10 10 10 + 10 10 10 6 6 6 6 6 6 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 10 10 10 14 14 14 + 22 22 22 26 26 26 30 30 30 34 34 34 + 30 30 30 30 30 30 26 26 26 18 18 18 + 14 14 14 10 10 10 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 26 26 26 42 42 42 + 54 54 54 66 66 66 78 78 78 78 78 78 + 78 78 78 74 74 74 66 66 66 54 54 54 + 42 42 42 26 26 26 18 18 18 10 10 10 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 22 22 22 42 42 42 66 66 66 86 86 86 + 66 66 66 38 38 38 38 38 38 22 22 22 + 26 26 26 34 34 34 54 54 54 66 66 66 + 86 86 86 70 70 70 46 46 46 26 26 26 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 26 26 26 + 50 50 50 82 82 82 58 58 58 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 54 54 54 86 86 86 66 66 66 + 38 38 38 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 22 22 22 50 50 50 + 78 78 78 34 34 34 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 6 6 6 70 70 70 + 78 78 78 46 46 46 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 42 42 42 82 82 82 + 26 26 26 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 14 14 14 + 46 46 46 34 34 34 6 6 6 2 2 6 + 42 42 42 78 78 78 42 42 42 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 30 30 30 66 66 66 58 58 58 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 26 26 26 + 86 86 86 101 101 101 46 46 46 10 10 10 + 2 2 6 58 58 58 70 70 70 34 34 34 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 42 42 42 86 86 86 10 10 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 30 30 30 + 94 94 94 94 94 94 58 58 58 26 26 26 + 2 2 6 6 6 6 78 78 78 54 54 54 + 22 22 22 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 62 62 62 62 62 62 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 26 26 26 + 54 54 54 38 38 38 18 18 18 10 10 10 + 2 2 6 2 2 6 34 34 34 82 82 82 + 38 38 38 14 14 14 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 30 30 30 78 78 78 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 10 10 10 + 10 10 10 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 78 78 78 + 50 50 50 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 14 14 14 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 54 54 54 + 66 66 66 26 26 26 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 82 82 82 2 2 6 2 2 6 + 2 2 6 6 6 6 10 10 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 6 6 6 + 14 14 14 10 10 10 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 18 18 18 + 82 82 82 34 34 34 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 2 2 6 + 6 6 6 6 6 6 22 22 22 34 34 34 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 34 34 34 + 10 10 10 50 50 50 22 22 22 2 2 6 + 2 2 6 2 2 6 2 2 6 10 10 10 + 86 86 86 42 42 42 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 2 2 6 + 38 38 38 116 116 116 94 94 94 22 22 22 + 22 22 22 2 2 6 2 2 6 2 2 6 + 14 14 14 86 86 86 138 138 138 162 162 162 + 154 154 154 38 38 38 26 26 26 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 86 86 86 46 46 46 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 14 14 14 + 134 134 134 198 198 198 195 195 195 116 116 116 + 10 10 10 2 2 6 2 2 6 6 6 6 + 101 98 89 187 187 187 210 210 210 218 218 218 + 214 214 214 134 134 134 14 14 14 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 86 86 86 50 50 50 18 18 18 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 86 86 86 2 2 6 54 54 54 + 218 218 218 195 195 195 226 226 226 246 246 246 + 58 58 58 2 2 6 2 2 6 30 30 30 + 210 210 210 253 253 253 174 174 174 123 123 123 + 221 221 221 234 234 234 74 74 74 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 46 46 46 82 82 82 2 2 6 106 106 106 + 170 170 170 26 26 26 86 86 86 226 226 226 + 123 123 123 10 10 10 14 14 14 46 46 46 + 231 231 231 190 190 190 6 6 6 70 70 70 + 90 90 90 238 238 238 158 158 158 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 1 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 86 86 86 6 6 6 116 116 116 + 106 106 106 6 6 6 70 70 70 149 149 149 + 128 128 128 18 18 18 38 38 38 54 54 54 + 221 221 221 106 106 106 2 2 6 14 14 14 + 46 46 46 190 190 190 198 198 198 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 62 62 62 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 94 94 94 14 14 14 101 101 101 + 128 128 128 2 2 6 18 18 18 116 116 116 + 118 98 46 121 92 8 121 92 8 98 78 10 + 162 162 162 106 106 106 2 2 6 2 2 6 + 2 2 6 195 195 195 195 195 195 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 62 62 62 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 1 + 0 0 1 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 90 90 90 14 14 14 58 58 58 + 210 210 210 26 26 26 54 38 6 154 114 10 + 226 170 11 236 186 11 225 175 15 184 144 12 + 215 174 15 175 146 61 37 26 9 2 2 6 + 70 70 70 246 246 246 138 138 138 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 66 66 66 26 26 26 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 14 14 14 10 10 10 + 195 195 195 188 164 115 192 133 9 225 175 15 + 239 182 13 234 190 10 232 195 16 232 200 30 + 245 207 45 241 208 19 232 195 16 184 144 12 + 218 194 134 211 206 186 42 42 42 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 50 50 50 74 74 74 30 30 30 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 86 86 86 14 14 14 2 2 6 + 121 87 25 192 133 9 219 162 10 239 182 13 + 236 186 11 232 195 16 241 208 19 244 214 54 + 246 218 60 246 218 38 246 215 20 241 208 19 + 241 208 19 226 184 13 121 87 25 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 50 50 50 82 82 82 34 34 34 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 82 82 82 30 30 30 61 42 6 + 180 123 7 206 145 10 230 174 11 239 182 13 + 234 190 10 238 202 15 241 208 19 246 218 74 + 246 218 38 246 215 20 246 215 20 246 215 20 + 226 184 13 215 174 15 184 144 12 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 26 26 26 94 94 94 42 42 42 14 14 14 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 50 50 50 104 69 6 + 192 133 9 216 158 10 236 178 12 236 186 11 + 232 195 16 241 208 19 244 214 54 245 215 43 + 246 215 20 246 215 20 241 208 19 198 155 10 + 200 144 11 216 158 10 156 118 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 90 90 90 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 46 46 46 22 22 22 + 137 92 6 210 162 10 239 182 13 238 190 10 + 238 202 15 241 208 19 246 215 20 246 215 20 + 241 208 19 203 166 17 185 133 11 210 150 10 + 216 158 10 210 150 10 102 78 10 2 2 6 + 6 6 6 54 54 54 14 14 14 2 2 6 + 2 2 6 62 62 62 74 74 74 30 30 30 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 34 34 34 78 78 78 50 50 50 6 6 6 + 94 70 30 139 102 15 190 146 13 226 184 13 + 232 200 30 232 195 16 215 174 15 190 146 13 + 168 122 10 192 133 9 210 150 10 213 154 11 + 202 150 34 182 157 106 101 98 89 2 2 6 + 2 2 6 78 78 78 116 116 116 58 58 58 + 2 2 6 22 22 22 90 90 90 46 46 46 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 86 86 86 50 50 50 6 6 6 + 128 128 128 174 154 114 156 107 11 168 122 10 + 198 155 10 184 144 12 197 138 11 200 144 11 + 206 145 10 206 145 10 197 138 11 188 164 115 + 195 195 195 198 198 198 174 174 174 14 14 14 + 2 2 6 22 22 22 116 116 116 116 116 116 + 22 22 22 2 2 6 74 74 74 70 70 70 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 101 101 101 26 26 26 10 10 10 + 138 138 138 190 190 190 174 154 114 156 107 11 + 197 138 11 200 144 11 197 138 11 192 133 9 + 180 123 7 190 142 34 190 178 144 187 187 187 + 202 202 202 221 221 221 214 214 214 66 66 66 + 2 2 6 2 2 6 50 50 50 62 62 62 + 6 6 6 2 2 6 10 10 10 90 90 90 + 50 50 50 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 34 34 34 + 74 74 74 74 74 74 2 2 6 6 6 6 + 144 144 144 198 198 198 190 190 190 178 166 146 + 154 121 60 156 107 11 156 107 11 168 124 44 + 174 154 114 187 187 187 190 190 190 210 210 210 + 246 246 246 253 253 253 253 253 253 182 182 182 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 62 62 62 + 74 74 74 34 34 34 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 10 10 10 22 22 22 54 54 54 + 94 94 94 18 18 18 2 2 6 46 46 46 + 234 234 234 221 221 221 190 190 190 190 190 190 + 190 190 190 187 187 187 187 187 187 190 190 190 + 190 190 190 195 195 195 214 214 214 242 242 242 + 253 253 253 253 253 253 253 253 253 253 253 253 + 82 82 82 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 14 14 14 + 86 86 86 54 54 54 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 46 46 46 90 90 90 + 46 46 46 18 18 18 6 6 6 182 182 182 + 253 253 253 246 246 246 206 206 206 190 190 190 + 190 190 190 190 190 190 190 190 190 190 190 190 + 206 206 206 231 231 231 250 250 250 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 202 202 202 14 14 14 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 42 42 42 86 86 86 42 42 42 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 14 14 14 38 38 38 74 74 74 66 66 66 + 2 2 6 6 6 6 90 90 90 250 250 250 + 253 253 253 253 253 253 238 238 238 198 198 198 + 190 190 190 190 190 190 195 195 195 221 221 221 + 246 246 246 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 82 82 82 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 78 78 78 70 70 70 34 34 34 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 34 34 34 66 66 66 78 78 78 6 6 6 + 2 2 6 18 18 18 218 218 218 253 253 253 + 253 253 253 253 253 253 253 253 253 246 246 246 + 226 226 226 231 231 231 246 246 246 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 178 178 178 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 18 18 18 90 90 90 62 62 62 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 26 26 26 + 58 58 58 90 90 90 18 18 18 2 2 6 + 2 2 6 110 110 110 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 250 250 250 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 231 231 231 18 18 18 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 94 94 94 + 54 54 54 26 26 26 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 22 22 22 50 50 50 + 90 90 90 26 26 26 2 2 6 2 2 6 + 14 14 14 195 195 195 250 250 250 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 250 250 250 242 242 242 54 54 54 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 38 38 38 + 86 86 86 50 50 50 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 38 38 38 82 82 82 + 34 34 34 2 2 6 2 2 6 2 2 6 + 42 42 42 195 195 195 246 246 246 253 253 253 + 253 253 253 253 253 253 253 253 253 250 250 250 + 242 242 242 242 242 242 250 250 250 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 250 250 250 246 246 246 238 238 238 + 226 226 226 231 231 231 101 101 101 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 38 38 38 82 82 82 42 42 42 14 14 14 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 26 26 26 62 62 62 66 66 66 + 2 2 6 2 2 6 2 2 6 6 6 6 + 70 70 70 170 170 170 206 206 206 234 234 234 + 246 246 246 250 250 250 250 250 250 238 238 238 + 226 226 226 231 231 231 238 238 238 250 250 250 + 250 250 250 250 250 250 246 246 246 231 231 231 + 214 214 214 206 206 206 202 202 202 202 202 202 + 198 198 198 202 202 202 182 182 182 18 18 18 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 62 62 62 66 66 66 30 30 30 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 42 42 42 82 82 82 18 18 18 + 2 2 6 2 2 6 2 2 6 10 10 10 + 94 94 94 182 182 182 218 218 218 242 242 242 + 250 250 250 253 253 253 253 253 253 250 250 250 + 234 234 234 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 246 246 246 + 238 238 238 226 226 226 210 210 210 202 202 202 + 195 195 195 195 195 195 210 210 210 158 158 158 + 6 6 6 14 14 14 50 50 50 14 14 14 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 86 86 86 46 46 46 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 54 54 54 70 70 70 2 2 6 + 2 2 6 10 10 10 2 2 6 22 22 22 + 166 166 166 231 231 231 250 250 250 253 253 253 + 253 253 253 253 253 253 253 253 253 250 250 250 + 242 242 242 254 250 234 238 238 238 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 246 246 246 + 231 231 231 206 206 206 198 198 198 226 226 226 + 94 94 94 2 2 6 6 6 6 38 38 38 + 30 30 30 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 62 62 62 66 66 66 + 26 26 26 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 74 74 74 50 50 50 2 2 6 + 26 26 26 26 26 26 2 2 6 106 106 106 + 238 238 238 253 253 253 253 253 253 253 253 253 + 246 246 246 254 250 234 253 253 253 253 253 253 + 253 253 253 246 234 182 236 215 124 254 246 218 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 246 246 246 218 218 218 202 202 202 + 210 210 210 14 14 14 2 2 6 2 2 6 + 30 30 30 22 22 22 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 86 86 86 + 42 42 42 14 14 14 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 42 42 42 90 90 90 22 22 22 2 2 6 + 42 42 42 2 2 6 18 18 18 218 218 218 + 253 253 253 253 253 253 253 253 253 253 253 253 + 210 188 142 234 218 166 253 253 253 253 253 253 + 254 250 234 245 222 135 242 218 102 254 250 234 + 253 253 253 253 253 253 253 253 253 254 246 218 + 242 230 182 246 246 246 253 253 253 253 253 253 + 253 253 253 253 253 253 250 250 250 221 221 221 + 218 218 218 101 101 101 2 2 6 14 14 14 + 18 18 18 38 38 38 10 10 10 2 2 6 + 2 2 6 2 2 6 2 2 6 78 78 78 + 58 58 58 22 22 22 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 54 54 54 82 82 82 2 2 6 26 26 26 + 22 22 22 2 2 6 123 123 123 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 233 202 129 236 215 124 253 253 253 253 253 253 + 254 250 234 238 216 106 242 218 102 254 250 234 + 253 253 253 253 253 253 246 234 198 236 215 124 + 245 222 135 254 250 234 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 250 250 250 + 238 238 238 198 198 198 6 6 6 38 38 38 + 58 58 58 26 26 26 38 38 38 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 78 78 78 30 30 30 10 10 10 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 10 10 10 30 30 30 + 74 74 74 58 58 58 2 2 6 42 42 42 + 2 2 6 22 22 22 231 231 231 253 253 253 + 238 238 238 238 238 238 253 253 253 253 253 253 + 242 224 154 238 204 91 246 234 182 253 253 253 + 246 242 210 242 218 102 242 218 102 254 250 234 + 253 253 253 254 246 218 238 216 106 242 218 102 + 254 246 218 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 246 246 246 46 46 46 38 38 38 + 42 42 42 14 14 14 38 38 38 14 14 14 + 2 2 6 2 2 6 2 2 6 6 6 6 + 86 86 86 46 46 46 14 14 14 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 42 42 42 + 90 90 90 18 18 18 18 18 18 26 26 26 + 2 2 6 116 116 116 253 253 253 253 253 253 + 218 206 182 212 178 106 253 253 253 253 253 253 + 246 242 210 238 204 91 236 215 124 254 250 234 + 254 246 218 238 216 106 238 216 106 254 246 218 + 253 253 253 242 224 154 246 218 74 242 230 182 + 253 253 253 253 253 253 253 253 253 253 253 253 + 254 250 234 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 94 94 94 6 6 6 + 2 2 6 2 2 6 10 10 10 34 34 34 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 58 58 58 22 22 22 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 10 10 10 26 26 26 66 66 66 + 82 82 82 2 2 6 38 38 38 6 6 6 + 14 14 14 210 210 210 253 253 253 253 253 253 + 250 238 202 202 162 69 242 214 146 254 250 234 + 253 253 253 246 230 178 245 222 135 246 230 178 + 242 224 154 238 216 106 238 216 106 246 230 178 + 254 246 202 238 216 106 242 215 82 250 238 202 + 253 253 253 253 253 253 246 234 182 245 222 135 + 236 215 124 246 242 210 253 253 253 253 253 253 + 253 253 253 253 253 253 144 144 144 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 2 2 6 2 2 6 2 2 6 2 2 6 + 42 42 42 74 74 74 30 30 30 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 42 42 42 90 90 90 + 26 26 26 6 6 6 42 42 42 2 2 6 + 74 74 74 250 250 250 253 253 253 253 253 253 + 253 253 253 218 197 138 228 184 62 234 218 166 + 254 246 218 242 230 182 242 215 82 246 218 74 + 246 218 60 246 218 60 244 214 54 246 218 60 + 238 216 106 242 215 82 242 224 154 253 253 253 + 254 250 234 242 224 154 238 216 106 236 215 124 + 246 234 198 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 182 182 182 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 2 2 6 2 2 6 2 2 6 2 2 6 + 10 10 10 86 86 86 38 38 38 10 10 10 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 10 10 10 26 26 26 66 66 66 82 82 82 + 2 2 6 22 22 22 18 18 18 2 2 6 + 149 149 149 253 253 253 253 253 253 253 253 253 + 253 253 253 254 246 218 233 202 129 236 215 124 + 245 222 135 242 218 102 244 214 54 244 214 54 + 246 218 60 246 218 60 246 218 60 246 218 60 + 246 218 60 246 218 74 245 222 135 246 234 182 + 246 234 182 246 218 74 242 218 102 254 246 218 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 206 206 206 2 2 6 + 2 2 6 2 2 6 2 2 6 38 38 38 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 86 86 86 46 46 46 14 14 14 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 18 18 18 46 46 46 86 86 86 18 18 18 + 2 2 6 34 34 34 10 10 10 6 6 6 + 210 210 210 253 253 253 221 221 221 254 246 218 + 254 250 234 253 253 253 254 246 218 236 215 124 + 246 198 46 244 214 54 244 214 54 242 215 82 + 246 218 74 246 218 60 246 218 74 246 218 74 + 244 214 54 246 218 60 246 218 74 242 215 82 + 242 218 102 236 215 124 246 234 182 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 221 221 221 6 6 6 + 2 2 6 2 2 6 6 6 6 30 30 30 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 82 82 82 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 26 26 26 66 66 66 62 62 62 2 2 6 + 2 2 6 38 38 38 10 10 10 26 26 26 + 238 238 238 253 253 253 210 188 142 202 162 69 + 218 197 138 246 230 178 246 234 198 238 204 91 + 245 207 45 245 207 45 244 214 54 246 218 60 + 246 218 60 246 218 60 246 218 60 246 218 60 + 246 218 74 246 218 60 246 218 60 242 215 82 + 242 218 102 254 246 202 253 253 253 254 250 234 + 254 246 202 254 246 202 254 246 218 254 250 234 + 253 253 253 253 253 253 231 231 231 6 6 6 + 2 2 6 2 2 6 10 10 10 30 30 30 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 58 58 58 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 38 38 38 78 78 78 6 6 6 2 2 6 + 2 2 6 46 46 46 14 14 14 42 42 42 + 246 246 246 253 253 253 254 246 218 218 197 138 + 212 178 106 221 185 102 242 206 102 245 207 45 + 244 214 54 244 214 54 246 218 60 246 218 60 + 246 218 60 246 218 60 246 218 60 246 218 74 + 246 218 60 246 218 60 242 218 102 246 218 60 + 242 215 82 246 234 182 246 234 198 242 218 102 + 242 218 102 238 216 106 242 214 146 246 230 178 + 253 253 253 253 253 253 234 234 234 10 10 10 + 2 2 6 2 2 6 22 22 22 14 14 14 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 62 62 62 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 74 74 74 2 2 6 2 2 6 + 14 14 14 70 70 70 34 34 34 62 62 62 + 250 250 250 253 253 253 253 253 253 253 253 253 + 250 238 202 250 238 202 242 206 102 246 198 46 + 245 207 45 245 207 45 241 208 19 246 218 74 + 246 218 60 242 215 82 246 218 60 242 215 82 + 246 218 74 246 218 74 246 218 74 246 218 74 + 246 218 74 245 222 135 238 222 174 238 216 106 + 245 222 135 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 234 234 234 14 14 14 + 2 2 6 2 2 6 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 62 62 62 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 54 54 54 62 62 62 2 2 6 2 2 6 + 2 2 6 30 30 30 46 46 46 70 70 70 + 250 250 250 253 253 253 253 253 253 253 253 253 + 253 253 253 254 250 234 238 204 91 245 207 45 + 250 206 62 244 214 54 244 214 54 244 214 54 + 242 215 82 246 218 60 244 214 54 246 218 60 + 246 218 60 246 218 74 246 218 74 242 215 82 + 242 215 82 245 222 135 254 250 234 254 250 234 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 226 226 226 10 10 10 + 2 2 6 6 6 6 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 58 58 58 22 22 22 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 58 58 58 62 62 62 2 2 6 2 2 6 + 2 2 6 2 2 6 30 30 30 78 78 78 + 250 250 250 253 253 253 253 253 253 250 238 202 + 246 234 198 246 230 178 240 198 71 246 198 46 + 246 198 46 245 207 45 244 214 54 244 214 54 + 242 215 82 246 218 60 246 218 74 244 214 54 + 246 218 74 246 218 60 246 218 74 246 218 74 + 242 215 82 238 216 106 254 246 218 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 206 206 206 2 2 6 + 22 22 22 34 34 34 18 14 6 22 22 22 + 26 26 26 18 18 18 6 6 6 2 2 6 + 2 2 6 82 82 82 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 26 26 26 + 62 62 62 106 106 106 74 54 14 185 133 11 + 210 162 10 121 92 8 6 6 6 62 62 62 + 238 238 238 253 253 253 253 253 253 188 164 115 + 202 162 69 214 174 82 242 190 54 242 190 54 + 246 198 46 246 198 46 245 207 45 250 206 62 + 244 214 54 244 214 54 244 214 54 246 218 74 + 246 218 74 246 218 74 246 218 74 244 214 54 + 246 218 74 238 216 106 246 234 182 242 224 154 + 246 230 178 254 246 218 253 253 253 253 253 253 + 253 253 253 253 253 253 158 158 158 18 18 18 + 14 14 14 2 2 6 2 2 6 2 2 6 + 6 6 6 18 18 18 66 66 66 38 38 38 + 6 6 6 94 94 94 50 50 50 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 10 10 10 10 10 10 18 18 18 38 38 38 + 78 78 78 142 134 106 216 158 10 242 186 14 + 246 190 14 246 190 14 156 118 10 10 10 10 + 90 90 90 238 238 238 253 253 253 253 253 253 + 250 238 202 246 234 198 233 202 129 240 198 71 + 245 207 45 246 198 46 246 198 46 245 207 45 + 245 207 45 244 214 54 244 214 54 246 218 60 + 244 214 54 244 214 54 242 215 82 244 214 54 + 246 218 74 242 224 154 242 224 154 242 215 82 + 246 218 74 242 218 102 246 230 178 246 230 190 + 238 204 91 238 204 91 181 142 44 37 26 9 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 38 38 38 46 46 46 + 26 26 26 106 106 106 54 54 54 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 22 22 22 + 30 30 30 38 38 38 50 50 50 70 70 70 + 106 106 106 190 142 34 226 170 11 242 186 14 + 246 190 14 246 190 14 246 190 14 154 114 10 + 6 6 6 74 74 74 226 226 226 253 253 253 + 253 253 253 253 253 253 250 238 202 239 182 13 + 242 190 54 246 198 46 246 198 46 246 198 46 + 245 207 45 246 215 20 244 214 54 244 214 54 + 246 218 60 246 215 20 246 218 60 246 218 60 + 242 218 102 246 234 182 254 250 234 254 246 202 + 254 246 202 246 234 182 236 215 124 228 184 62 + 241 196 14 241 208 19 232 195 16 38 30 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 30 30 30 26 26 26 + 203 166 17 154 142 90 66 66 66 26 26 26 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 38 38 38 58 58 58 + 78 78 78 86 86 86 101 101 101 123 123 123 + 175 146 61 210 150 10 234 174 13 246 186 14 + 246 190 14 246 190 14 246 190 14 238 190 10 + 102 78 10 2 2 6 46 46 46 198 198 198 + 254 246 218 234 218 166 233 202 129 238 216 106 + 246 198 46 246 198 46 246 198 46 246 198 46 + 245 207 45 244 214 54 244 214 54 244 214 54 + 244 214 54 246 215 20 246 218 60 246 215 20 + 242 218 102 254 246 202 254 250 234 254 250 234 + 253 253 253 253 253 253 253 253 253 224 178 62 + 242 186 14 241 196 14 210 166 10 22 18 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 6 6 6 121 92 8 + 238 202 15 232 195 16 82 82 82 34 34 34 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 14 14 14 38 38 38 70 70 70 154 122 46 + 190 142 34 200 144 11 197 138 11 197 138 11 + 213 154 11 226 170 11 242 186 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 225 175 15 46 32 6 2 2 6 22 22 22 + 210 198 158 202 162 69 212 178 106 246 234 198 + 242 206 102 246 198 46 245 207 45 245 207 45 + 245 207 45 246 215 20 244 214 54 244 214 54 + 244 214 54 246 218 60 244 214 54 246 218 74 + 236 215 124 238 216 106 236 215 124 250 238 202 + 254 250 234 250 250 250 242 242 242 224 178 62 + 239 182 13 236 186 11 213 154 11 46 32 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 61 42 6 225 175 15 + 238 190 10 236 186 11 112 100 78 42 42 42 + 14 14 14 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 22 22 22 54 54 54 154 122 46 213 154 11 + 226 170 11 230 174 11 226 170 11 226 170 11 + 236 178 12 242 186 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 241 196 14 184 144 12 10 10 10 2 2 6 + 6 6 6 116 116 116 242 242 242 253 253 253 + 254 246 218 233 202 129 228 184 62 242 190 54 + 246 198 46 245 207 45 245 207 45 250 206 62 + 245 207 45 244 214 54 242 215 82 254 246 202 + 254 246 202 242 224 154 242 215 82 236 215 124 + 250 238 202 231 231 231 198 198 198 214 170 54 + 236 178 12 236 178 12 210 150 10 137 92 6 + 18 14 6 2 2 6 2 2 6 2 2 6 + 6 6 6 70 47 6 200 144 11 236 178 12 + 239 182 13 239 182 13 124 112 88 58 58 58 + 22 22 22 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 70 70 70 180 133 36 226 170 11 + 239 182 13 242 186 14 242 186 14 246 186 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 232 195 16 98 70 6 2 2 6 + 2 2 6 2 2 6 66 66 66 221 221 221 + 218 206 158 238 214 174 246 230 178 233 202 129 + 240 198 71 240 198 71 240 198 71 240 198 71 + 238 216 106 242 224 154 246 230 178 245 222 135 + 254 246 218 254 250 234 254 246 218 236 215 124 + 218 194 134 206 206 206 198 198 198 214 166 58 + 230 174 11 230 174 11 216 158 10 192 133 9 + 163 110 8 116 81 8 102 78 10 116 81 8 + 167 114 7 197 138 11 226 170 11 239 182 13 + 242 186 14 242 186 14 162 146 94 78 78 78 + 34 34 34 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 30 30 30 78 78 78 190 142 34 226 170 11 + 239 182 13 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 241 196 14 203 166 17 22 18 6 + 2 2 6 2 2 6 2 2 6 38 38 38 + 202 162 69 238 214 174 253 253 253 236 215 124 + 242 214 146 250 238 202 250 238 202 246 230 178 + 254 246 218 253 253 253 242 230 182 240 198 71 + 238 216 106 254 246 218 253 253 253 254 250 234 + 246 234 198 206 206 206 198 198 198 202 162 69 + 226 170 11 236 178 12 224 166 10 210 150 10 + 200 144 11 197 138 11 192 133 9 197 138 11 + 210 150 10 226 170 11 242 186 14 246 190 14 + 246 190 14 246 186 14 225 175 15 124 112 88 + 62 62 62 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 174 135 50 224 166 10 + 239 182 13 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 241 196 14 139 102 15 + 2 2 6 2 2 6 2 2 6 2 2 6 + 78 78 78 250 250 250 253 253 253 221 185 102 + 212 178 106 254 246 218 254 246 218 221 185 102 + 233 202 129 254 250 234 253 253 253 242 230 182 + 228 184 62 238 214 174 253 253 253 253 253 253 + 250 250 250 214 214 214 198 198 198 190 150 46 + 219 162 10 236 178 12 234 174 13 224 166 10 + 216 158 10 213 154 11 213 154 11 216 158 10 + 226 170 11 239 182 13 246 190 14 246 190 14 + 246 190 14 246 190 14 242 186 14 206 162 42 + 101 101 101 58 58 58 30 30 30 14 14 14 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 74 74 74 174 135 50 216 158 10 + 236 178 12 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 241 196 14 226 184 13 + 61 42 6 2 2 6 2 2 6 2 2 6 + 22 22 22 238 238 238 253 253 253 210 188 142 + 212 178 106 254 250 234 253 253 253 218 197 138 + 212 178 106 254 246 218 253 253 253 254 250 234 + 226 214 178 218 206 158 253 253 253 253 253 253 + 253 253 253 226 226 226 187 187 187 180 133 36 + 216 158 10 236 178 12 239 182 13 236 178 12 + 230 174 11 226 170 11 226 170 11 230 174 11 + 236 178 12 242 186 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 186 14 239 182 13 + 206 162 42 106 106 106 66 66 66 34 34 34 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 26 26 26 70 70 70 163 133 67 213 154 11 + 236 178 12 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 241 196 14 + 190 146 13 18 14 6 2 2 6 2 2 6 + 46 46 46 246 246 246 253 253 253 231 231 231 + 246 234 182 253 253 253 253 253 253 226 214 178 + 190 178 144 254 250 234 253 253 253 254 250 234 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 221 221 221 86 86 86 156 107 11 + 216 158 10 236 178 12 242 186 14 246 186 14 + 242 186 14 239 182 13 239 182 13 242 186 14 + 242 186 14 246 186 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 242 186 14 225 175 15 142 122 72 66 66 66 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 26 26 26 70 70 70 163 133 67 210 150 10 + 236 178 12 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 232 195 16 121 92 8 34 34 34 106 106 106 + 221 221 221 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 242 242 242 82 82 82 18 14 6 163 110 8 + 216 158 10 236 178 12 242 186 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 242 186 14 163 133 67 + 46 46 46 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 10 10 10 + 30 30 30 78 78 78 163 133 67 210 150 10 + 236 178 12 246 186 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 241 196 14 215 174 15 190 178 144 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 218 218 218 + 58 58 58 2 2 6 22 18 6 167 114 7 + 216 158 10 236 178 12 246 186 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 186 14 242 186 14 190 150 46 + 54 54 54 22 22 22 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 38 38 38 86 86 86 180 133 36 213 154 11 + 236 178 12 246 186 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 232 195 16 190 146 13 214 214 214 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 250 250 250 170 170 170 26 26 26 + 2 2 6 2 2 6 37 26 9 163 110 8 + 219 162 10 239 182 13 246 186 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 186 14 236 178 12 224 166 10 142 122 72 + 46 46 46 18 18 18 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 109 106 95 192 133 9 224 166 10 + 242 186 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 242 186 14 226 184 13 210 162 10 142 110 46 + 226 226 226 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 253 253 253 253 253 253 253 253 253 253 253 253 + 198 198 198 66 66 66 2 2 6 2 2 6 + 2 2 6 2 2 6 50 34 6 156 107 11 + 219 162 10 239 182 13 246 186 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 242 186 14 + 234 174 13 213 154 11 154 122 46 66 66 66 + 30 30 30 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 58 58 58 154 121 60 206 145 10 234 174 13 + 242 186 14 246 186 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 186 14 236 178 12 210 162 10 163 110 8 + 61 42 6 138 138 138 218 218 218 250 250 250 + 253 253 253 253 253 253 253 253 253 250 250 250 + 242 242 242 210 210 210 144 144 144 66 66 66 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 61 42 6 163 110 8 + 216 158 10 236 178 12 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 239 182 13 230 174 11 216 158 10 + 190 142 34 124 112 88 70 70 70 38 38 38 + 18 18 18 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 22 22 22 + 62 62 62 168 124 44 206 145 10 224 166 10 + 236 178 12 239 182 13 242 186 14 242 186 14 + 246 186 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 236 178 12 216 158 10 175 118 6 + 80 54 7 2 2 6 6 6 6 30 30 30 + 54 54 54 62 62 62 50 50 50 38 38 38 + 14 14 14 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 80 54 7 167 114 7 + 213 154 11 236 178 12 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 190 14 242 186 14 239 182 13 239 182 13 + 230 174 11 210 150 10 174 135 50 124 112 88 + 82 82 82 54 54 54 34 34 34 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 18 18 18 + 50 50 50 158 118 36 192 133 9 200 144 11 + 216 158 10 219 162 10 224 166 10 226 170 11 + 230 174 11 236 178 12 239 182 13 239 182 13 + 242 186 14 246 186 14 246 190 14 246 190 14 + 246 190 14 246 190 14 246 190 14 246 190 14 + 246 186 14 230 174 11 210 150 10 163 110 8 + 104 69 6 10 10 10 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 91 60 6 167 114 7 + 206 145 10 230 174 11 242 186 14 246 190 14 + 246 190 14 246 190 14 246 186 14 242 186 14 + 239 182 13 230 174 11 224 166 10 213 154 11 + 180 133 36 124 112 88 86 86 86 58 58 58 + 38 38 38 22 22 22 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 14 14 14 + 34 34 34 70 70 70 138 110 50 158 118 36 + 167 114 7 180 123 7 192 133 9 197 138 11 + 200 144 11 206 145 10 213 154 11 219 162 10 + 224 166 10 230 174 11 239 182 13 242 186 14 + 246 186 14 246 186 14 246 186 14 246 186 14 + 239 182 13 216 158 10 185 133 11 152 99 6 + 104 69 6 18 14 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 80 54 7 152 99 6 + 192 133 9 219 162 10 236 178 12 239 182 13 + 246 186 14 242 186 14 239 182 13 236 178 12 + 224 166 10 206 145 10 192 133 9 154 121 60 + 94 94 94 62 62 62 42 42 42 22 22 22 + 14 14 14 6 6 6 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 18 18 18 34 34 34 58 58 58 78 78 78 + 101 98 89 124 112 88 142 110 46 156 107 11 + 163 110 8 167 114 7 175 118 6 180 123 7 + 185 133 11 197 138 11 210 150 10 219 162 10 + 226 170 11 236 178 12 236 178 12 234 174 13 + 219 162 10 197 138 11 163 110 8 130 83 6 + 91 60 6 10 10 10 2 2 6 2 2 6 + 18 18 18 38 38 38 38 38 38 38 38 38 + 38 38 38 38 38 38 38 38 38 38 38 38 + 38 38 38 38 38 38 26 26 26 2 2 6 + 2 2 6 6 6 6 70 47 6 137 92 6 + 175 118 6 200 144 11 219 162 10 230 174 11 + 234 174 13 230 174 11 219 162 10 210 150 10 + 192 133 9 163 110 8 124 112 88 82 82 82 + 50 50 50 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 14 14 14 22 22 22 34 34 34 + 42 42 42 58 58 58 74 74 74 86 86 86 + 101 98 89 122 102 70 130 98 46 121 87 25 + 137 92 6 152 99 6 163 110 8 180 123 7 + 185 133 11 197 138 11 206 145 10 200 144 11 + 180 123 7 156 107 11 130 83 6 104 69 6 + 50 34 6 54 54 54 110 110 110 101 98 89 + 86 86 86 82 82 82 78 78 78 78 78 78 + 78 78 78 78 78 78 78 78 78 78 78 78 + 78 78 78 82 82 82 86 86 86 94 94 94 + 106 106 106 101 101 101 86 66 34 124 80 6 + 156 107 11 180 123 7 192 133 9 200 144 11 + 206 145 10 200 144 11 192 133 9 175 118 6 + 139 102 15 109 106 95 70 70 70 42 42 42 + 22 22 22 10 10 10 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 6 6 6 10 10 10 + 14 14 14 22 22 22 30 30 30 38 38 38 + 50 50 50 62 62 62 74 74 74 90 90 90 + 101 98 89 112 100 78 121 87 25 124 80 6 + 137 92 6 152 99 6 152 99 6 152 99 6 + 138 86 6 124 80 6 98 70 6 86 66 30 + 101 98 89 82 82 82 58 58 58 46 46 46 + 38 38 38 34 34 34 34 34 34 34 34 34 + 34 34 34 34 34 34 34 34 34 34 34 34 + 34 34 34 34 34 34 38 38 38 42 42 42 + 54 54 54 82 82 82 94 86 76 91 60 6 + 134 86 6 156 107 11 167 114 7 175 118 6 + 175 118 6 167 114 7 152 99 6 121 87 25 + 101 98 89 62 62 62 34 34 34 18 18 18 + 6 6 6 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 6 6 6 10 10 10 + 18 18 18 22 22 22 30 30 30 42 42 42 + 50 50 50 66 66 66 86 86 86 101 98 89 + 106 86 58 98 70 6 104 69 6 104 69 6 + 104 69 6 91 60 6 82 62 34 90 90 90 + 62 62 62 38 38 38 22 22 22 14 14 14 + 10 10 10 10 10 10 10 10 10 10 10 10 + 10 10 10 10 10 10 6 6 6 10 10 10 + 10 10 10 10 10 10 10 10 10 14 14 14 + 22 22 22 42 42 42 70 70 70 89 81 66 + 80 54 7 104 69 6 124 80 6 137 92 6 + 134 86 6 116 81 8 100 82 52 86 86 86 + 58 58 58 30 30 30 14 14 14 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 10 10 10 14 14 14 + 18 18 18 26 26 26 38 38 38 54 54 54 + 70 70 70 86 86 86 94 86 76 89 81 66 + 89 81 66 86 86 86 74 74 74 50 50 50 + 30 30 30 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 18 18 18 34 34 34 58 58 58 + 82 82 82 89 81 66 89 81 66 89 81 66 + 94 86 66 94 86 76 74 74 74 50 50 50 + 26 26 26 14 14 14 6 6 6 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 6 6 6 6 6 6 14 14 14 18 18 18 + 30 30 30 38 38 38 46 46 46 54 54 54 + 50 50 50 42 42 42 30 30 30 18 18 18 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 6 6 6 14 14 14 26 26 26 + 38 38 38 50 50 50 58 58 58 58 58 58 + 54 54 54 42 42 42 30 30 30 18 18 18 + 10 10 10 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 6 6 6 10 10 10 14 14 14 18 18 18 + 18 18 18 14 14 14 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 6 6 6 + 14 14 14 18 18 18 22 22 22 22 22 22 + 18 18 18 14 14 14 10 10 10 6 6 6 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/drivers/video/logo/logo_superh_clut224.ppm b/drivers/video/logo/logo_superh_clut224.ppm new file mode 100644 index 000000000000..0241aacee180 --- /dev/null +++ b/drivers/video/logo/logo_superh_clut224.ppm @@ -0,0 +1,1604 @@ +P3 +# 224-color SuperH Linux logo +80 80 +255 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 6 6 6 6 10 10 10 10 10 10 + 10 10 10 6 6 6 6 6 6 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 6 6 6 10 10 10 14 14 13 + 22 22 22 26 26 26 30 30 30 34 34 34 + 30 30 30 30 30 30 26 26 26 18 18 18 + 14 14 13 10 10 10 6 6 6 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 6 14 14 13 26 26 26 42 42 43 + 54 54 54 66 66 66 78 78 78 78 78 78 + 78 78 78 74 74 74 66 66 66 54 54 54 + 42 42 43 26 26 26 18 18 18 10 10 10 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 22 22 22 42 42 43 66 66 66 86 86 86 + 66 66 66 38 38 38 38 38 38 22 22 22 + 26 26 26 34 34 34 54 54 54 66 66 66 + 86 86 86 70 70 70 46 46 46 26 26 26 + 14 14 13 6 6 6 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 10 10 10 26 26 26 + 50 50 50 82 82 82 58 58 58 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 54 54 54 86 86 86 66 66 66 + 38 38 38 18 18 18 6 6 6 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 6 6 6 22 22 22 50 50 50 + 78 78 78 34 34 34 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 6 6 6 70 70 70 + 78 78 78 46 46 46 22 22 22 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 6 18 18 18 42 42 43 82 82 82 + 26 26 26 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 14 14 13 + 46 46 46 34 34 34 6 6 6 2 2 6 + 42 42 43 78 78 78 42 42 43 18 18 18 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 10 10 10 30 30 30 66 66 66 58 58 58 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 26 26 26 + 86 86 86 102 102 102 46 46 46 10 10 10 + 2 2 6 58 58 58 70 70 70 34 34 34 + 10 10 10 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 14 14 13 42 42 43 86 86 86 10 10 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 30 30 30 + 94 94 93 94 94 93 58 58 58 26 26 26 + 2 2 6 6 6 6 78 78 78 54 54 54 + 22 22 22 6 6 6 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 6 + 22 22 22 62 62 62 62 62 62 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 26 26 26 + 54 54 54 38 38 38 18 18 18 10 10 10 + 2 2 6 2 2 6 34 34 34 82 82 82 + 38 38 38 14 14 13 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 6 + 30 30 30 78 78 78 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 10 10 10 + 10 10 10 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 78 78 78 + 50 50 50 18 18 18 6 6 6 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 38 38 38 86 86 86 14 14 13 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 54 54 54 + 66 66 66 26 26 26 6 6 6 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 13 + 42 42 43 82 82 82 2 2 6 2 2 6 + 2 2 6 6 6 6 10 10 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 6 6 6 + 14 14 13 10 10 10 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 18 18 18 + 82 82 82 34 34 34 10 10 10 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 13 + 46 46 46 86 86 86 2 2 6 2 2 6 + 6 6 6 6 6 6 22 22 22 34 34 34 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 34 34 34 + 10 10 10 50 50 50 22 22 22 2 2 6 + 2 2 6 2 2 6 2 2 6 10 10 10 + 86 86 86 42 42 43 14 14 13 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 13 + 46 46 46 86 86 86 2 2 6 2 2 6 + 38 38 38 118 118 118 94 94 93 22 22 22 + 22 22 22 2 2 6 2 2 6 2 2 6 + 14 14 13 86 86 86 138 138 142 163 163 163 +154 154 154 38 38 38 26 26 26 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 86 86 86 46 46 46 14 14 13 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 13 + 46 46 46 86 86 86 2 2 6 14 14 13 +134 134 134 198 198 196 194 194 194 118 118 118 + 10 10 10 2 2 6 2 2 6 6 6 6 +102 98 90 186 186 186 210 210 210 218 218 218 +214 214 214 134 134 134 14 14 13 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 86 86 86 50 50 50 18 18 18 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 13 + 46 46 46 86 86 86 2 2 6 54 54 54 +218 218 218 194 194 194 226 226 226 246 246 246 + 58 58 58 2 2 6 2 2 6 30 30 30 +210 210 210 254 254 254 174 174 174 122 122 122 +223 222 222 234 234 234 74 74 74 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 58 58 58 22 22 22 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 13 + 46 46 46 82 82 82 2 2 6 106 106 105 +170 170 170 26 26 26 86 86 86 226 226 226 +122 122 122 10 10 10 14 14 13 46 46 46 +230 230 228 190 190 187 6 6 6 70 70 70 + 89 90 90 238 238 238 158 158 158 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 58 58 58 22 22 22 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 13 + 42 42 43 86 86 86 6 6 6 118 118 118 +106 106 105 6 6 6 70 70 70 150 150 150 +130 130 130 18 18 18 38 38 38 54 54 54 +223 222 222 106 106 105 2 2 6 14 14 13 + 46 46 46 190 190 187 198 198 196 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 62 62 62 22 22 22 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 13 + 42 42 43 94 94 93 14 14 13 102 102 102 +130 130 130 2 2 6 18 18 18 118 118 118 +122 100 66 122 94 10 122 94 10 104 78 10 +163 163 163 106 106 105 2 2 6 2 2 6 + 2 2 6 194 194 194 194 194 194 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 62 62 62 22 22 22 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 38 38 38 89 90 90 14 14 13 58 58 58 +210 210 210 26 26 26 60 40 9 154 114 10 +226 170 10 241 186 13 229 174 11 186 146 17 +214 174 14 178 147 70 38 26 10 2 2 6 + 70 70 70 246 246 246 138 138 142 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 70 70 70 66 66 66 26 26 26 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 38 38 38 86 86 86 14 14 13 10 10 10 +194 194 194 190 166 114 195 134 10 229 174 11 +238 182 14 234 190 10 234 196 18 238 202 21 +246 206 46 244 212 20 234 196 18 186 146 17 +218 194 134 206 206 194 42 42 43 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 50 50 50 74 74 74 30 30 30 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 34 34 34 86 86 86 14 14 13 2 2 6 +122 86 26 195 134 10 220 162 10 238 182 14 +241 186 13 234 196 18 244 212 20 246 217 53 +246 217 53 246 217 39 244 212 20 244 212 20 +244 212 20 224 188 14 122 86 26 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 50 50 50 82 82 82 34 34 34 10 10 10 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 34 34 34 82 82 82 30 30 30 60 40 9 +181 122 9 204 146 11 229 174 11 238 182 14 +234 190 10 238 202 21 244 212 20 246 218 74 +246 217 39 244 212 20 244 212 20 244 212 20 +224 188 14 214 174 14 186 146 17 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 26 26 26 94 94 93 42 42 43 14 14 13 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 30 30 30 78 78 78 50 50 50 105 70 7 +195 134 10 219 158 11 238 178 14 241 186 13 +234 196 18 244 212 20 246 217 53 241 214 34 +244 212 20 244 212 20 244 212 20 197 151 13 +204 146 11 219 158 11 158 118 10 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 89 90 90 54 54 54 18 18 18 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 30 30 30 78 78 78 46 46 46 22 22 22 +138 94 6 210 162 12 238 182 14 238 190 10 +238 202 21 244 212 20 244 212 20 244 212 20 +244 212 20 202 164 20 186 134 10 211 150 11 +219 158 11 211 150 11 104 78 10 2 2 6 + 6 6 6 54 54 54 14 14 13 2 2 6 + 2 2 6 62 62 62 74 74 74 30 30 30 + 10 10 10 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 34 34 34 78 78 78 50 50 50 6 6 6 + 92 69 26 138 102 14 190 146 14 224 188 14 +238 202 21 234 196 18 214 174 14 190 146 14 +170 122 12 195 134 10 211 150 11 214 154 10 +202 147 31 182 158 106 102 98 90 2 2 6 + 2 2 6 78 78 78 118 118 118 58 58 58 + 2 2 6 22 22 22 89 90 90 46 46 46 + 18 18 18 6 6 6 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 38 38 38 86 86 86 50 50 50 6 6 6 +130 130 130 173 154 115 158 106 9 170 122 12 +197 151 13 186 146 17 197 139 12 204 146 11 +204 146 11 204 146 11 197 139 12 190 166 114 +194 194 194 198 198 196 174 174 174 14 14 13 + 2 2 6 22 22 22 118 118 118 118 118 118 + 22 22 22 2 2 6 74 74 74 70 70 70 + 30 30 30 10 10 10 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 6 18 18 18 + 50 50 50 102 102 102 26 26 26 10 10 10 +138 138 142 190 190 187 173 154 115 158 106 9 +197 139 12 204 146 11 197 139 12 195 134 10 +181 122 9 188 140 34 191 178 145 186 186 186 +201 202 203 223 222 222 214 214 214 66 66 66 + 2 2 6 2 2 6 50 50 50 62 62 62 + 6 6 6 2 2 6 10 10 10 89 90 90 + 50 50 50 18 18 18 6 6 6 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 10 10 10 34 34 34 + 74 74 74 74 74 74 2 2 6 6 6 6 +146 146 146 198 198 196 190 190 187 178 166 146 +154 122 54 158 106 9 158 106 9 170 126 38 +173 154 115 186 186 186 190 190 187 210 210 210 +246 246 246 254 254 254 254 254 254 182 182 182 + 6 6 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 62 62 62 + 74 74 74 34 34 34 14 14 13 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 10 10 10 22 22 22 54 54 54 + 94 94 93 18 18 18 2 2 6 46 46 46 +234 234 234 223 222 222 190 190 187 190 190 187 +190 190 187 186 186 186 186 186 186 190 190 187 +190 190 187 194 194 194 214 214 214 242 242 242 +254 254 254 254 254 254 254 254 254 254 254 254 + 82 82 82 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 14 14 13 + 86 86 86 54 54 54 22 22 22 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 6 18 18 18 46 46 46 89 90 90 + 46 46 46 18 18 18 6 6 6 182 182 182 +254 254 254 246 246 246 206 206 206 190 190 187 +190 190 187 190 190 187 190 190 187 190 190 187 +206 206 206 230 230 228 250 250 250 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +201 202 203 14 14 13 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 42 42 43 86 86 86 42 42 43 18 18 18 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 6 + 14 14 13 38 38 38 74 74 74 66 66 66 + 2 2 6 6 6 6 89 90 90 250 250 250 +254 254 254 254 254 254 238 238 238 198 198 196 +190 190 187 190 190 187 194 194 194 223 222 222 +246 246 246 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 82 82 82 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 78 78 78 70 70 70 34 34 34 + 14 14 13 6 6 6 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 13 + 34 34 34 66 66 66 78 78 78 6 6 6 + 2 2 6 18 18 18 218 218 218 254 254 254 +254 254 254 254 254 254 254 254 254 246 246 246 +226 226 226 230 230 228 246 246 246 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 174 174 174 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 18 18 18 89 90 90 62 62 62 + 30 30 30 10 10 10 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 10 10 10 26 26 26 + 58 58 58 89 90 90 18 18 18 2 2 6 + 2 2 6 110 110 110 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +250 250 250 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 230 230 228 18 18 18 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 94 94 93 + 54 54 54 26 26 26 10 10 10 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 6 6 6 22 22 22 50 50 50 + 89 90 90 26 26 26 2 2 6 2 2 6 + 14 14 13 194 194 194 250 250 250 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +250 250 250 242 242 242 54 54 54 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 38 38 38 + 86 86 86 50 50 50 22 22 22 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 6 14 14 13 38 38 38 82 82 82 + 34 34 34 2 2 6 2 2 6 2 2 6 + 42 42 43 194 194 194 246 246 246 254 254 254 +254 254 254 254 254 254 254 254 254 250 250 250 +242 242 242 242 242 242 250 250 250 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 250 250 250 246 246 246 238 238 238 +226 226 226 230 230 228 102 102 102 6 6 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 38 38 38 82 82 82 42 42 43 14 14 13 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 10 10 10 26 26 26 62 62 62 66 66 66 + 2 2 6 2 2 6 2 2 6 6 6 6 + 70 70 70 170 170 170 206 206 206 234 234 234 +246 246 246 250 250 250 250 250 250 238 238 238 +226 226 226 230 230 228 238 238 238 250 250 250 +250 250 250 250 250 250 246 246 246 230 230 228 +214 214 214 206 206 206 201 202 203 201 202 203 +198 198 196 201 202 203 182 182 182 18 18 18 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 62 62 62 66 66 66 30 30 30 + 10 10 10 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 14 14 13 42 42 43 82 82 82 18 18 18 + 2 2 6 2 2 6 2 2 6 10 10 10 + 94 94 93 182 182 182 218 218 218 242 242 242 +250 250 250 254 254 254 254 254 254 250 250 250 +234 234 234 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 246 246 246 +238 238 238 226 226 226 210 210 210 201 202 203 +194 194 194 194 194 194 210 210 210 158 158 158 + 6 6 6 14 14 13 50 50 50 14 14 13 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 86 86 86 46 46 46 + 18 18 18 6 6 6 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 6 + 22 22 22 54 54 54 70 70 70 2 2 6 + 2 2 6 10 10 10 2 2 6 22 22 22 +166 166 166 230 230 228 250 250 250 254 254 254 +254 254 254 254 254 254 254 254 254 250 250 250 +242 242 242 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 246 246 246 +230 230 228 206 206 206 198 198 196 226 226 226 + 94 94 93 2 2 6 6 6 6 38 38 38 + 30 30 30 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 62 62 62 66 66 66 + 26 26 26 10 10 10 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 30 30 30 74 74 74 50 50 50 2 2 6 + 26 26 26 26 26 26 2 2 6 106 106 105 +238 238 238 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 246 246 246 218 218 218 201 202 203 +210 210 210 14 14 13 2 2 6 2 2 6 + 30 30 30 22 22 22 2 2 6 2 2 6 + 2 2 6 2 2 6 18 18 18 86 86 86 + 42 42 43 14 14 13 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 14 14 13 + 42 42 43 89 90 90 22 22 22 2 2 6 + 42 42 43 2 2 6 18 18 18 218 218 218 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 250 250 250 223 222 222 +218 218 218 102 102 102 2 2 6 14 14 13 + 18 18 18 38 38 38 10 10 10 2 2 6 + 2 2 6 2 2 6 2 2 6 78 78 78 + 58 58 58 22 22 22 6 6 6 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 6 18 18 18 + 54 54 54 82 82 82 2 2 6 26 26 26 + 22 22 22 2 2 6 122 122 122 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 250 250 250 +238 238 238 198 198 196 6 6 6 38 38 38 + 58 58 58 26 26 26 38 38 38 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 78 78 78 30 30 30 10 10 10 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 10 10 10 30 30 30 + 74 74 74 58 58 58 2 2 6 42 42 43 + 2 2 6 22 22 22 230 230 228 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 250 250 250 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 246 246 246 46 46 46 38 38 38 + 42 42 43 14 14 13 38 38 38 14 14 13 + 2 2 6 2 2 6 2 2 6 6 6 6 + 86 86 86 46 46 46 14 14 13 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 6 6 6 14 14 13 42 42 43 + 89 90 90 18 18 18 18 18 18 26 26 26 + 2 2 6 118 118 118 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 250 250 250 238 238 238 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 94 94 93 6 6 6 + 2 2 6 2 2 6 10 10 10 34 34 34 + 2 2 6 2 2 6 2 2 6 2 2 6 + 74 74 74 58 58 58 22 22 22 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 10 10 10 26 26 26 66 66 66 + 82 82 82 2 2 6 38 38 38 6 6 6 + 14 14 13 210 210 210 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 246 246 246 242 242 242 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 146 146 146 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 2 2 6 2 2 6 2 2 6 2 2 6 + 42 42 43 74 74 74 30 30 30 10 10 10 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 6 14 14 13 42 42 43 89 90 90 + 26 26 26 6 6 6 42 42 43 2 2 6 + 74 74 74 250 250 250 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 242 242 242 242 242 242 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 182 182 182 2 2 6 + 2 2 6 2 2 6 2 2 6 46 46 46 + 2 2 6 2 2 6 2 2 6 2 2 6 + 10 10 10 86 86 86 38 38 38 10 10 10 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 10 10 10 26 26 26 66 66 66 82 82 82 + 2 2 6 22 22 22 18 18 18 2 2 6 +150 150 150 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 234 234 234 242 242 242 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 206 206 206 2 2 6 + 2 2 6 2 2 6 2 2 6 38 38 38 + 2 2 6 2 2 6 2 2 6 2 2 6 + 6 6 6 86 86 86 46 46 46 14 14 13 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 6 + 18 18 18 46 46 46 86 86 86 18 18 18 + 2 2 6 34 34 34 10 10 10 6 6 6 +210 210 210 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 234 234 234 242 242 242 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 223 222 222 6 6 6 + 2 2 6 2 2 6 6 6 6 30 30 30 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 82 82 82 54 54 54 18 18 18 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 26 26 26 66 66 66 62 62 62 2 2 6 + 2 2 6 38 38 38 10 10 10 26 26 26 +238 238 238 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 230 230 228 238 238 238 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 230 230 228 6 6 6 + 2 2 6 2 2 6 10 10 10 30 30 30 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 58 58 58 22 22 22 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 38 38 38 78 78 78 6 6 6 2 2 6 + 2 2 6 46 46 46 14 14 13 42 42 43 +246 246 246 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 230 230 228 242 242 242 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 234 234 234 10 10 10 + 2 2 6 2 2 6 22 22 22 14 14 13 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 62 62 62 22 22 22 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 6 18 18 18 + 50 50 50 74 74 74 2 2 6 2 2 6 + 14 14 13 70 70 70 34 34 34 62 62 62 +250 250 250 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 230 230 228 246 246 246 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 234 234 234 14 14 13 + 2 2 6 2 2 6 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 62 62 62 22 22 22 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 6 18 18 18 + 54 54 54 62 62 62 2 2 6 2 2 6 + 2 2 6 30 30 30 46 46 46 70 70 70 +250 250 250 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 230 230 228 246 246 246 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 226 226 226 10 10 10 + 2 2 6 6 6 6 30 30 30 2 2 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 66 66 66 58 58 58 22 22 22 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 6 22 22 22 + 58 58 58 62 62 62 2 2 6 2 2 6 + 2 2 6 2 2 6 30 30 30 78 78 78 +250 250 250 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 230 230 228 246 246 246 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 206 206 206 2 2 6 + 22 22 22 34 34 34 18 14 6 22 22 22 + 26 26 26 18 18 18 6 6 6 2 2 6 + 2 2 6 82 82 82 54 54 54 18 18 18 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 6 26 26 26 + 62 62 62 106 106 105 74 51 11 186 134 10 +210 162 12 122 94 10 6 6 6 62 62 62 +238 238 238 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 230 230 228 246 246 246 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 158 158 158 18 18 18 + 14 14 13 2 2 6 2 2 6 2 2 6 + 6 6 6 18 18 18 66 66 66 38 38 38 + 6 6 6 94 94 93 50 50 50 18 18 18 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 6 + 10 10 10 10 10 10 18 18 18 38 38 38 + 78 78 78 142 134 106 219 158 11 241 186 13 +246 190 14 246 190 14 158 118 10 10 10 10 + 89 90 90 238 238 238 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 230 230 228 250 250 250 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 246 230 190 +238 206 90 238 206 90 188 140 34 38 26 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 38 38 38 46 46 46 + 26 26 26 106 106 105 54 54 54 18 18 18 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 6 6 6 14 14 13 22 22 22 + 30 30 30 38 38 38 50 50 50 70 70 70 +106 106 105 188 140 34 226 170 10 241 186 13 +246 190 14 246 190 14 246 190 14 154 114 10 + 6 6 6 74 74 74 226 226 226 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 230 230 228 250 250 250 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 233 188 64 +240 198 14 244 212 20 234 196 18 38 30 10 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 6 6 6 30 30 30 26 26 26 +202 164 20 154 142 90 66 66 66 26 26 26 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 6 18 18 18 38 38 38 58 58 58 + 78 78 78 86 86 86 102 102 102 122 122 122 +178 147 70 211 150 11 234 174 12 246 186 14 +246 190 14 246 190 14 246 190 14 238 190 10 +104 78 10 2 2 6 46 46 46 198 198 196 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 234 234 234 242 242 242 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 222 175 59 +241 186 13 240 198 14 210 162 12 18 18 18 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 6 6 6 122 94 10 +238 202 21 234 196 18 82 82 82 34 34 34 + 10 10 10 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 14 14 13 38 38 38 70 70 70 154 122 54 +188 140 34 204 146 11 197 139 12 197 139 12 +214 154 10 226 170 10 241 186 13 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +229 174 11 49 35 6 2 2 6 22 22 22 +158 158 158 250 250 250 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 250 250 250 242 242 242 222 175 59 +238 182 14 241 186 13 214 154 10 49 35 6 + 2 2 6 2 2 6 2 2 6 2 2 6 + 2 2 6 2 2 6 60 40 9 229 174 11 +238 190 10 241 186 13 114 102 78 42 42 43 + 14 14 13 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 6 + 22 22 22 54 54 54 154 122 54 214 154 10 +226 170 10 229 174 11 226 170 10 226 170 10 +238 178 14 241 186 13 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +240 198 14 186 146 17 10 10 10 2 2 6 + 6 6 6 118 118 118 242 242 242 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 230 230 228 198 198 196 206 170 74 +238 178 14 238 178 14 211 150 11 138 94 6 + 18 14 6 2 2 6 2 2 6 2 2 6 + 6 6 6 70 46 6 204 146 11 238 178 14 +238 182 14 238 182 14 126 114 90 58 58 58 + 22 22 22 6 6 6 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 30 30 30 70 70 70 182 134 38 226 170 10 +238 182 14 241 186 13 241 186 13 246 186 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 234 196 18 98 70 6 2 2 6 + 2 2 6 2 2 6 66 66 66 223 222 222 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 206 206 206 198 198 196 207 165 68 +229 174 11 229 174 11 219 158 11 195 134 10 +163 110 10 118 82 10 104 78 10 118 82 10 +164 114 8 197 139 12 226 170 10 238 182 14 +241 186 13 241 186 13 162 146 94 78 78 78 + 34 34 34 14 14 13 6 6 6 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 6 + 30 30 30 78 78 78 188 140 34 226 170 10 +238 182 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 240 198 14 202 164 20 18 18 18 + 2 2 6 2 2 6 2 2 6 38 38 38 +218 218 218 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +250 250 250 206 206 206 198 198 196 207 165 68 +226 170 10 238 178 14 226 166 13 211 150 11 +204 146 11 197 139 12 195 134 10 197 139 12 +211 150 11 226 170 10 241 186 13 246 190 14 +246 190 14 246 186 14 229 174 11 126 114 90 + 62 62 62 30 30 30 14 14 13 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 30 30 30 78 78 78 174 134 50 226 166 13 +238 182 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 240 198 14 138 102 14 + 2 2 6 2 2 6 2 2 6 2 2 6 + 78 78 78 250 250 250 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +250 250 250 214 214 214 198 198 196 192 148 44 +220 162 10 238 178 14 234 174 12 226 166 13 +219 158 11 214 154 10 214 154 10 219 158 11 +226 170 10 238 182 14 246 190 14 246 190 14 +246 190 14 246 190 14 241 186 13 206 160 36 +102 102 102 58 58 58 30 30 30 14 14 13 + 6 6 6 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 10 10 10 86 86 86 150 150 150 +170 170 170 186 186 186 226 210 207 231 220 218 +246 230 190 246 230 190 246 230 190 246 230 190 +238 206 90 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 246 190 14 246 190 14 +246 190 14 246 190 14 240 198 14 224 188 14 + 60 40 9 2 2 6 6 6 6 2 2 6 + 22 22 22 238 238 238 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 226 226 226 186 186 186 182 134 38 +219 158 11 238 178 14 238 182 14 238 178 14 +229 174 11 226 170 10 226 170 10 229 174 11 +238 178 14 241 186 13 246 190 14 246 190 14 +246 190 14 240 198 14 246 230 190 246 230 190 +226 210 207 186 186 186 110 110 110 38 38 38 + 26 26 26 122 122 122 138 138 142 138 138 142 +138 138 142 102 98 90 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 14 14 13 154 154 154 246 246 246 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +246 230 190 238 206 90 240 198 14 240 198 14 +240 198 14 240 198 14 246 190 14 246 190 14 +246 190 14 240 198 14 240 198 14 238 202 21 +206 160 36 18 18 18 22 22 22 30 30 30 + 70 70 70 246 246 246 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 254 254 254 254 254 254 254 254 254 +254 254 254 230 230 228 118 118 118 170 126 38 +220 162 10 238 178 14 241 186 13 246 190 14 +234 196 18 246 190 14 246 190 14 234 196 18 +246 190 14 246 206 46 238 206 90 246 206 46 +240 198 14 246 230 190 254 254 254 254 254 254 +254 254 254 252 251 251 205 195 190 110 110 110 +134 134 134 242 242 242 250 250 250 254 254 254 +250 250 250 138 138 142 102 98 90 2 2 2 + 2 2 2 2 2 2 3 3 3 18 14 6 +150 150 150 242 242 242 239 159 153 249 100 93 +249 100 93 249 100 93 249 100 93 249 100 93 +249 100 93 249 100 93 249 100 93 249 100 93 +239 159 153 246 218 74 246 246 246 246 246 246 +246 246 246 246 246 246 238 206 90 246 190 14 +246 230 190 246 246 246 246 246 246 246 246 246 +246 230 190 138 102 14 182 182 182 242 242 242 +252 251 251 252 251 251 252 251 251 252 251 251 +252 251 251 252 251 251 254 254 254 252 251 251 +252 251 251 252 251 251 246 246 246 252 251 251 +254 254 254 252 251 251 252 251 251 254 254 254 +254 254 254 252 251 251 242 242 242 238 238 238 +238 206 90 238 178 14 241 186 13 246 230 190 +246 246 246 246 246 246 246 246 246 246 230 190 +246 230 190 246 246 246 252 251 251 246 230 190 +246 230 190 246 230 190 249 100 93 249 100 93 +249 100 93 249 100 93 218 194 134 218 194 134 +234 234 234 212 132 53 249 100 93 249 100 93 +249 100 93 239 159 153 138 138 142 102 98 90 + 2 2 2 2 2 2 10 10 10 150 150 150 +242 242 242 249 100 93 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +239 159 153 246 246 246 246 230 190 246 230 190 +246 230 190 246 230 190 246 230 190 246 230 190 +246 230 190 246 230 190 246 230 190 246 230 190 +246 230 190 246 230 190 238 238 238 246 230 190 +246 230 190 246 230 190 246 230 190 246 246 246 +231 220 218 218 194 134 218 194 134 226 210 207 +246 246 246 246 246 246 246 246 246 252 251 251 +246 246 246 226 210 207 218 194 134 218 194 134 +239 159 153 218 194 134 226 210 207 246 230 190 +246 246 246 238 206 90 246 230 190 246 230 190 +246 230 190 246 230 190 246 230 190 246 230 190 +246 246 246 226 210 207 239 159 153 226 210 207 +246 246 246 239 159 153 254 3 3 254 3 3 +254 3 3 254 3 3 218 194 134 246 246 246 +231 220 218 254 21 21 254 3 3 254 3 3 +254 3 3 212 132 53 250 250 250 122 122 122 + 2 2 2 2 2 2 89 90 90 246 246 246 +239 159 153 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 254 21 21 +226 210 207 226 210 207 254 21 21 254 21 21 +254 21 21 254 21 21 239 159 153 252 251 251 +249 100 93 254 21 21 254 21 21 254 21 21 +249 100 93 246 246 246 249 100 93 254 21 21 +254 21 21 254 21 21 249 100 93 249 100 93 +254 21 21 254 3 3 254 3 3 254 21 21 +212 132 53 246 246 246 252 251 251 226 210 207 +254 56 56 254 21 21 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 254 21 21 +249 100 93 242 242 242 246 246 246 249 100 93 +254 21 21 254 21 21 254 21 21 249 100 93 +249 100 93 254 3 3 254 3 3 254 56 56 +246 246 246 249 100 93 254 3 3 254 3 3 +254 3 3 254 21 21 246 230 190 252 251 251 +239 159 153 254 3 3 254 3 3 254 3 3 +254 3 3 218 194 134 246 246 246 58 58 58 + 2 2 2 6 6 6 182 182 182 252 251 251 +254 56 56 254 3 3 254 3 3 254 3 3 +254 3 3 249 100 93 239 159 153 239 159 153 +239 159 153 212 132 53 249 100 93 249 100 93 +246 246 246 212 132 53 254 3 3 254 3 3 +254 3 3 254 21 21 238 238 238 246 230 190 +254 21 21 254 3 3 254 3 3 254 3 3 +239 159 153 246 230 190 254 21 21 254 3 3 +254 3 3 254 3 3 254 21 21 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 21 21 246 246 246 231 220 218 254 21 21 +254 3 3 254 3 3 254 3 3 254 3 3 +254 21 21 254 21 21 254 3 3 254 3 3 +254 3 3 239 159 153 246 230 190 254 21 21 +254 3 3 254 3 3 254 3 3 254 56 56 +254 3 3 254 3 3 254 3 3 212 132 53 +246 246 246 254 21 21 254 3 3 254 3 3 +254 3 3 249 100 93 246 246 246 246 246 246 +249 100 93 254 3 3 254 3 3 254 3 3 +254 21 21 242 242 242 214 214 214 14 14 13 + 2 2 2 6 6 6 210 210 210 252 251 251 +254 56 56 254 3 3 254 3 3 254 3 3 +254 3 3 249 100 93 239 159 153 239 159 153 +239 159 153 239 159 153 238 238 238 246 246 246 +246 246 246 254 56 56 254 3 3 254 3 3 +254 3 3 249 100 93 246 246 246 239 159 153 +254 3 3 254 3 3 254 3 3 254 3 3 +246 230 190 239 159 153 254 3 3 254 3 3 +254 3 3 254 3 3 254 21 21 254 21 21 +254 3 3 254 3 3 254 3 3 254 3 3 +254 3 3 246 246 246 249 100 93 254 3 3 +254 3 3 254 3 3 254 21 21 218 194 134 +242 242 242 239 159 153 254 3 3 254 3 3 +254 3 3 249 100 93 239 159 153 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 218 194 134 +226 210 207 254 3 3 254 3 3 254 3 3 +254 3 3 254 21 21 254 21 21 254 21 21 +254 3 3 254 3 3 254 3 3 254 3 3 +249 100 93 254 254 254 158 158 158 2 2 2 + 2 2 2 10 10 10 186 186 186 246 246 246 +254 56 56 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 56 56 252 251 251 +246 230 190 254 21 21 254 3 3 254 3 3 +254 3 3 239 159 153 252 251 251 249 100 93 +254 3 3 254 3 3 254 3 3 254 56 56 +252 251 251 249 100 93 254 3 3 254 3 3 +254 3 3 254 21 21 218 194 134 226 210 207 +254 56 56 254 3 3 254 3 3 254 3 3 +254 56 56 231 220 218 254 21 21 254 3 3 +254 3 3 254 3 3 254 21 21 254 56 56 +254 56 56 254 56 56 254 3 3 254 3 3 +254 3 3 239 159 153 249 100 93 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 21 21 246 246 246 +212 132 53 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +239 159 153 252 251 251 89 90 90 2 2 2 + 2 2 2 6 6 6 50 50 50 206 206 206 +226 210 207 249 100 93 254 56 56 254 21 21 +254 21 21 254 21 21 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 238 238 238 +239 159 153 254 3 3 254 3 3 254 3 3 +254 21 21 226 210 207 238 238 238 254 21 21 +254 3 3 254 3 3 254 3 3 212 132 53 +238 238 238 254 56 56 254 3 3 254 3 3 +254 3 3 239 159 153 246 246 246 246 246 246 +254 56 56 254 3 3 254 3 3 254 3 3 +249 100 93 239 159 153 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 21 21 226 210 207 254 56 56 254 3 3 +254 3 3 254 3 3 254 21 21 249 100 93 +239 159 153 239 159 153 239 159 153 246 246 246 +254 56 56 254 3 3 254 3 3 254 3 3 +254 3 3 254 21 21 254 21 21 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +246 230 190 242 242 242 26 26 26 2 2 2 + 6 6 6 50 50 50 206 206 206 226 210 207 +231 220 218 231 220 218 231 220 218 246 230 190 +246 230 190 239 159 153 254 3 3 254 3 3 +254 3 3 254 3 3 254 21 21 246 246 246 +249 100 93 254 3 3 254 3 3 254 3 3 +254 21 21 231 220 218 239 159 153 254 3 3 +254 3 3 254 3 3 254 3 3 218 194 134 +218 194 134 254 3 3 254 3 3 254 3 3 +254 3 3 239 159 153 246 230 190 239 159 153 +254 3 3 254 3 3 254 3 3 254 3 3 +239 159 153 212 132 53 254 3 3 254 3 3 +254 3 3 254 21 21 218 194 134 231 220 218 +231 220 218 231 220 218 226 210 207 218 194 134 +226 210 207 231 220 218 254 3 3 254 3 3 +254 3 3 254 3 3 212 132 53 246 246 246 +252 251 251 252 251 251 242 242 242 231 220 218 +254 21 21 254 3 3 254 3 3 254 3 3 +249 100 93 242 242 242 238 238 238 254 56 56 +254 3 3 254 3 3 254 3 3 254 56 56 +246 246 246 194 194 194 6 6 6 2 2 2 + 22 22 22 210 210 210 246 230 190 254 56 56 +254 21 21 254 21 21 254 21 21 254 21 21 +254 21 21 254 21 21 254 3 3 254 3 3 +254 3 3 254 3 3 249 100 93 246 246 246 +254 56 56 254 3 3 254 3 3 254 3 3 +254 3 3 254 21 21 254 21 21 254 3 3 +254 3 3 254 3 3 254 56 56 242 242 242 +212 132 53 254 3 3 254 3 3 254 3 3 +254 3 3 254 21 21 254 21 21 254 3 3 +254 3 3 254 3 3 254 3 3 254 56 56 +238 238 238 212 132 53 254 3 3 254 3 3 +254 3 3 254 3 3 254 56 56 249 100 93 +249 100 93 249 100 93 254 56 56 254 56 56 +246 246 246 239 159 153 254 3 3 254 3 3 +254 3 3 254 21 21 231 220 218 246 246 246 +206 170 74 182 158 106 246 246 246 239 159 153 +254 3 3 254 3 3 254 3 3 254 3 3 +218 194 134 242 242 242 246 230 190 254 21 21 +254 3 3 254 3 3 254 3 3 212 132 53 +252 251 251 131 126 116 6 6 6 2 2 2 + 89 90 90 246 246 246 239 159 153 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 3 3 254 21 21 226 210 207 246 246 246 +249 100 93 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 3 3 254 56 56 226 210 207 252 251 251 +254 56 56 254 3 3 254 3 3 254 3 3 +254 56 56 254 21 21 254 3 3 254 3 3 +254 3 3 254 3 3 254 21 21 218 194 134 +238 238 238 226 210 207 254 21 21 254 3 3 +254 3 3 254 3 3 254 3 3 254 3 3 +254 3 3 254 3 3 254 3 3 239 159 153 +252 251 251 249 100 93 254 3 3 254 3 3 +254 3 3 254 56 56 246 246 246 231 220 218 +138 102 14 198 198 196 252 251 251 249 100 93 +254 3 3 254 3 3 254 3 3 254 21 21 +246 230 190 252 251 251 239 159 153 254 3 3 +254 3 3 254 3 3 254 3 3 218 194 134 +242 242 242 62 62 62 6 6 6 2 2 2 + 58 58 58 122 122 122 218 194 134 212 132 53 +249 100 93 249 100 93 254 56 56 254 56 56 +254 56 56 254 56 56 254 56 56 249 100 93 +212 132 53 246 230 190 214 214 214 146 146 146 +242 242 242 239 159 153 249 100 93 254 56 56 +254 56 56 254 56 56 254 56 56 249 100 93 +239 159 153 246 230 190 246 246 246 246 230 190 +254 21 21 254 3 3 254 3 3 254 3 3 +239 159 153 218 194 134 249 100 93 254 56 56 +254 56 56 249 100 93 226 210 207 230 230 228 + 89 90 90 231 220 218 226 210 207 249 100 93 +249 100 93 254 56 56 254 56 56 254 56 56 +249 100 93 249 100 93 239 159 153 238 238 238 +218 194 134 239 159 153 212 132 53 249 100 93 +249 100 93 239 159 153 231 220 218 154 142 90 +102 102 102 146 146 146 170 170 170 239 159 153 +249 100 93 249 100 93 249 100 93 239 159 153 +218 218 218 130 130 130 239 159 153 249 100 93 +249 100 93 249 100 93 212 132 53 246 230 190 +118 118 118 18 14 6 6 6 6 2 2 2 + 2 2 2 58 58 58 118 118 118 242 242 242 +254 254 254 250 250 250 246 246 246 246 246 246 +246 246 246 246 246 246 246 246 246 252 251 251 +252 251 251 214 214 214 50 50 50 18 18 18 +138 138 142 246 246 246 252 251 251 246 246 246 +246 246 246 246 246 246 246 246 246 252 251 251 +252 251 251 231 220 218 252 251 251 239 159 153 +254 3 3 254 3 3 254 3 3 254 21 21 +231 220 218 238 238 238 252 251 251 242 242 242 +252 251 251 252 251 251 230 230 228 74 74 74 + 18 18 18 62 62 62 226 226 226 254 254 254 +252 251 251 246 246 246 246 246 246 252 251 251 +252 251 251 252 251 251 250 250 250 150 150 150 +162 146 94 205 195 190 252 251 251 252 251 251 +252 251 251 226 210 207 142 134 106 86 86 86 + 58 58 58 34 34 34 122 122 122 163 163 163 +252 251 251 254 254 254 250 250 250 223 222 222 +102 98 90 78 78 78 130 130 130 254 254 254 +254 254 254 254 254 254 246 246 246 118 118 118 + 18 14 6 3 3 3 2 2 2 2 2 2 + 2 2 2 2 2 2 58 58 58 122 122 122 +150 150 150 170 170 170 182 182 182 190 190 187 +201 202 203 201 202 203 190 190 187 170 170 170 +118 118 118 30 30 30 6 6 6 6 6 6 + 10 10 10 86 86 86 150 150 150 182 182 182 +201 202 203 201 202 203 190 190 187 174 174 174 +134 134 134 146 146 146 190 190 187 239 159 153 +249 100 93 249 100 93 249 100 93 249 100 93 +234 234 234 138 138 142 166 166 166 198 198 196 +190 190 187 138 138 142 42 42 43 6 6 6 + 3 3 3 6 6 6 50 50 50 138 138 142 +174 174 174 198 198 196 198 198 196 182 182 182 +163 163 163 138 138 142 102 98 90 70 70 70 + 94 86 75 158 158 158 178 166 146 170 170 170 +174 174 174 138 138 142 74 74 74 50 50 50 + 26 26 26 14 14 13 10 10 10 118 118 118 +130 130 130 130 130 130 130 130 130 102 98 90 + 6 6 6 3 3 3 78 78 78 130 130 130 +130 130 130 130 130 130 118 118 118 18 14 6 + 3 3 3 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 6 6 6 6 6 6 + 10 10 10 10 10 10 6 6 6 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 6 + 6 6 6 6 6 6 6 6 6 6 6 6 + 14 14 13 14 14 13 22 22 22 22 22 22 + 34 34 34 42 42 43 122 122 122 174 174 174 +254 254 254 254 254 254 254 254 254 238 238 238 +138 138 142 6 6 6 6 6 6 10 10 10 + 6 6 6 2 2 2 2 2 2 6 6 6 + 6 6 6 6 6 6 6 6 6 2 2 2 + 6 6 6 10 10 10 10 10 10 6 6 6 + 2 2 2 6 6 6 14 14 13 30 30 30 + 42 42 43 54 54 54 62 62 62 62 62 62 + 54 54 54 42 42 43 30 30 30 18 18 18 + 10 10 10 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 6 2 2 2 6 6 6 2 2 2 + 2 2 2 2 2 2 2 2 2 10 10 10 + 10 10 10 10 10 10 14 14 13 106 106 105 +163 163 163 170 170 170 166 166 166 138 138 142 + 6 6 6 6 6 6 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 6 6 6 6 6 6 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 6 6 6 + 18 18 18 22 22 22 22 22 22 22 22 22 + 18 18 18 14 14 13 10 10 10 6 6 6 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 2 2 2 diff --git a/drivers/video/logo/logo_superh_mono.pbm b/drivers/video/logo/logo_superh_mono.pbm new file mode 100644 index 000000000000..6cd378e37aa1 --- /dev/null +++ b/drivers/video/logo/logo_superh_mono.pbm @@ -0,0 +1,203 @@ +P1 +# Black and white SuperH Linux logo +80 80 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 +1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 +1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 1 1 +1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +0 1 1 0 0 1 1 1 0 0 1 1 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 1 1 1 0 1 1 1 1 0 0 1 +1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 1 1 1 0 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 +1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +0 1 1 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 1 0 0 1 0 0 0 0 0 1 1 1 +1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 +1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 0 1 1 0 0 0 0 1 1 +1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 1 1 1 1 1 1 1 0 0 0 0 1 1 0 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 +1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 +0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 +1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 +0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 +1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1 +0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 +1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 +1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 +1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 +1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 +1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 1 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1 1 1 1 0 +0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 1 0 0 0 +0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 +1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 1 1 1 1 0 1 +1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 1 1 1 1 0 0 0 1 1 1 1 1 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 +0 0 1 1 1 1 1 0 0 1 1 1 1 0 1 1 1 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 +1 1 1 0 0 0 0 1 1 1 0 0 1 1 1 1 0 1 1 1 1 1 0 0 0 1 1 1 1 0 0 1 +1 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 1 1 1 1 0 1 1 +1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 +0 1 1 1 1 0 0 0 1 1 1 1 1 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 +0 1 1 1 1 1 0 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 +0 1 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 +1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 1 1 1 1 0 1 1 1 +1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 +1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 +0 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 +1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 +1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 0 1 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 +1 0 0 0 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 +1 1 1 1 1 0 0 0 1 1 1 1 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 +1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 +1 1 1 1 0 0 1 1 1 1 0 0 0 1 0 0 1 1 1 1 0 0 0 1 1 1 1 1 0 0 1 1 +1 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 +1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 1 0 0 1 +1 1 1 1 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 +0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 0 1 1 1 1 1 +1 1 0 0 0 1 1 1 1 0 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1 1 1 0 0 1 1 1 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 +0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 +0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 +1 1 0 0 0 0 0 0 1 1 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 +0 0 1 1 1 0 0 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 +0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 diff --git a/drivers/video/logo/logo_superh_vga16.ppm b/drivers/video/logo/logo_superh_vga16.ppm new file mode 100644 index 000000000000..a8ffcd72951b --- /dev/null +++ b/drivers/video/logo/logo_superh_vga16.ppm @@ -0,0 +1,1604 @@ +P3 +# 16-color SuperH Linux logo +80 80 +255 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 85 85 85 85 85 85 85 85 85 + 85 85 85 85 85 85 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 85 85 85 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 85 85 85 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 170 170 170 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 170 170 170 170 170 85 85 85 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 170 170 170 170 170 +170 170 170 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 85 85 85 170 170 170 170 170 170 170 170 170 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 170 170 170 255 255 255 255 255 255 +255 255 255 170 170 170 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 +170 170 170 170 170 170 255 255 255 255 255 255 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 170 170 255 255 255 170 170 170 170 170 170 +255 255 255 170 170 170 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 +170 170 170 0 0 0 0 0 0 255 255 255 + 85 85 85 0 0 0 0 0 0 0 0 0 +255 255 255 170 170 170 0 0 0 85 85 85 +170 170 170 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 + 85 85 85 0 0 0 0 0 0 170 170 170 + 85 85 85 0 0 0 0 0 0 0 0 0 +255 255 255 85 85 85 0 0 0 0 0 0 + 85 85 85 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 +170 170 170 0 0 0 0 0 0 170 170 170 + 85 85 85 85 85 85 85 85 85 85 85 85 +255 255 255 85 85 85 0 0 0 0 0 0 + 85 85 85 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 +255 255 255 0 0 0 0 0 0 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 0 0 0 0 0 0 + 85 85 85 255 255 255 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 +170 170 170 170 170 170 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 170 170 170 170 170 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 85 85 85 0 0 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 85 85 85 0 0 0 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 170 85 0 +170 85 0 170 85 0 85 85 85 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 85 85 85 0 0 0 + 85 85 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 85 85 85 0 0 0 + 0 0 0 85 85 85 170 170 170 85 85 85 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 85 85 85 0 0 0 + 85 85 85 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 170 170 170 170 170 170 170 170 0 0 0 + 0 0 0 0 0 0 170 170 170 170 170 170 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 85 85 85 170 170 170 170 85 0 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 85 0 170 85 0 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 85 85 85 + 0 0 0 0 0 0 85 85 85 85 85 85 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 85 85 85 170 170 170 170 170 170 170 85 0 +170 85 0 170 85 0 170 85 0 170 85 0 +170 170 170 170 170 170 170 170 170 170 170 170 +255 255 255 255 255 255 255 255 255 170 170 170 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 85 85 85 +255 255 255 255 255 255 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 170 170 170 +255 255 255 255 255 255 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 85 85 85 255 255 255 +255 255 255 255 255 255 255 255 255 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 85 85 85 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 85 85 85 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 170 170 170 170 170 170 170 170 170 +255 255 255 255 255 255 255 255 255 170 170 170 +170 170 170 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 170 170 170 170 170 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 85 85 85 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 170 170 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 170 170 170 + 0 0 0 0 0 0 0 0 0 85 85 85 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 85 85 85 0 0 0 0 0 0 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 170 170 170 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 170 170 170 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +170 170 170 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 + 0 0 0 0 0 0 85 85 85 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 0 0 0 85 85 85 + 85 85 85 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 + 0 0 0 85 85 85 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 0 0 0 85 85 85 + 85 85 85 0 0 0 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 85 85 85 + 0 0 0 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 85 85 85 0 0 0 + 0 0 0 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 85 85 85 0 0 0 + 85 85 85 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 85 85 85 0 0 0 0 0 0 +170 170 170 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 0 0 + 85 85 85 85 85 85 85 85 85 85 85 85 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 0 0 0 170 85 0 +255 255 85 170 85 0 0 0 0 0 0 0 + 85 85 85 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 85 85 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 85 85 85 0 0 0 + 0 0 0 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 0 0 0 + 0 0 0 85 85 85 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 85 170 85 0 255 255 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 85 85 85 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 + 0 0 0 0 0 0 85 85 85 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 85 +170 85 0 255 255 85 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 85 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 0 0 0 0 0 0 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 170 85 0 +255 255 85 170 85 0 255 255 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 170 85 0 +255 255 85 170 85 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 0 0 0 0 0 0 0 0 0 + 85 85 85 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 85 +170 85 0 255 255 85 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 255 255 85 +170 85 0 255 255 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 0 0 0 0 0 0 + 0 0 0 85 85 85 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 255 255 85 170 85 0 +255 255 85 170 85 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 0 0 0 + 0 0 0 0 0 0 85 85 85 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 170 170 170 +170 170 170 170 170 170 170 170 170 255 255 255 +170 170 170 255 255 255 170 170 170 255 255 85 +170 170 170 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 0 0 0 0 0 0 0 0 0 + 0 0 0 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 255 170 170 170 +255 255 85 170 170 170 85 85 85 0 0 0 + 0 0 0 85 85 85 170 170 170 85 85 85 +170 170 170 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 85 170 170 170 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 170 85 0 255 255 85 170 85 0 +255 255 85 0 0 0 0 0 0 0 0 0 + 85 85 85 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 85 0 255 255 85 +170 85 0 255 255 85 170 170 170 255 255 85 +170 85 0 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 85 85 85 85 85 85 + 85 85 85 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 +170 170 170 255 255 255 170 170 170 255 85 85 +255 85 85 255 85 85 255 85 85 255 85 85 +255 85 85 255 85 85 255 85 85 255 85 85 +170 170 170 255 255 85 255 255 255 255 255 255 +255 255 255 255 255 255 170 170 170 255 255 85 +170 170 170 255 255 255 255 255 255 255 255 255 +170 170 170 255 255 85 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 85 0 255 255 85 170 170 170 +255 255 255 255 255 255 255 255 255 170 170 170 +255 255 85 255 255 255 255 255 255 255 255 255 +255 255 85 255 255 255 255 85 85 255 85 85 +255 85 85 255 85 85 170 170 170 170 170 170 +255 255 255 170 170 170 255 85 85 255 85 85 +255 85 85 170 170 170 170 170 170 85 85 85 + 0 0 0 0 0 0 0 0 0 170 170 170 +255 255 255 255 85 85 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 170 170 255 255 255 170 170 170 255 255 255 +255 255 255 170 170 170 255 255 255 170 170 170 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 255 255 255 255 255 255 +255 255 255 170 170 170 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 255 255 255 +255 255 255 255 255 85 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 170 170 170 170 170 170 170 170 170 +255 255 255 170 170 170 170 0 0 255 85 85 +170 0 0 255 85 85 170 170 170 255 255 255 +170 170 170 170 0 0 170 0 0 170 0 0 +170 0 0 255 85 85 255 255 255 85 85 85 + 0 0 0 0 0 0 85 85 85 255 255 255 +170 170 170 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 170 170 255 255 255 170 0 0 170 0 0 +170 0 0 170 0 0 170 170 170 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +255 85 85 255 255 255 255 85 85 170 0 0 +170 0 0 170 0 0 255 85 85 255 85 85 +170 0 0 170 0 0 170 0 0 170 0 0 +255 85 85 255 255 255 255 255 255 170 170 170 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +255 85 85 255 255 255 255 255 255 255 85 85 +170 0 0 170 0 0 170 0 0 255 85 85 +255 85 85 170 0 0 170 0 0 255 85 85 +255 255 255 255 85 85 170 0 0 170 0 0 +170 0 0 255 85 85 255 255 255 255 255 255 +170 170 170 170 0 0 170 0 0 170 0 0 +255 85 85 170 170 170 255 255 255 85 85 85 + 0 0 0 0 0 0 170 170 170 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 255 85 85 170 170 170 170 170 170 +170 170 170 255 85 85 255 85 85 170 170 170 +255 255 255 255 85 85 170 0 0 170 0 0 +170 0 0 255 85 85 255 255 255 170 170 170 +170 0 0 170 0 0 170 0 0 170 0 0 +170 170 170 255 255 255 170 0 0 170 0 0 +170 0 0 170 0 0 255 85 85 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 255 255 255 255 255 255 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 170 170 170 255 255 255 170 0 0 +170 0 0 170 0 0 170 0 0 255 85 85 +170 0 0 170 0 0 170 0 0 255 85 85 +255 255 255 170 0 0 170 0 0 170 0 0 +170 0 0 255 85 85 255 255 255 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 255 255 255 255 255 255 0 0 0 + 0 0 0 0 0 0 170 170 170 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 255 85 85 255 85 85 170 170 170 +170 170 170 170 170 170 255 255 255 255 255 255 +255 255 255 255 85 85 170 0 0 170 0 0 +170 0 0 255 85 85 255 255 255 170 170 170 +170 0 0 170 0 0 170 0 0 170 0 0 +255 255 255 170 170 170 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 255 255 255 255 85 85 170 0 0 +170 0 0 170 0 0 170 0 0 170 170 170 +255 255 255 170 170 170 170 0 0 170 0 0 +170 0 0 255 85 85 170 170 170 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 170 170 +255 255 255 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +255 85 85 255 255 255 170 170 170 0 0 0 + 0 0 0 0 0 0 170 170 170 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 255 85 85 255 255 255 +255 255 255 170 0 0 170 0 0 170 0 0 +170 0 0 255 85 85 255 255 255 255 85 85 +170 0 0 170 0 0 170 0 0 255 85 85 +255 255 255 255 85 85 170 0 0 170 0 0 +170 0 0 255 85 85 170 170 170 255 255 255 +170 0 0 170 0 0 170 0 0 170 0 0 +255 85 85 170 170 170 255 85 85 170 0 0 +170 0 0 170 0 0 255 85 85 255 85 85 +255 85 85 255 85 85 170 0 0 170 0 0 +170 0 0 170 170 170 255 85 85 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 255 85 85 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 170 170 255 255 255 85 85 85 0 0 0 + 0 0 0 0 0 0 0 0 0 255 255 255 +170 170 170 255 85 85 255 85 85 170 0 0 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 255 255 255 +170 170 170 170 0 0 170 0 0 170 0 0 +255 85 85 170 170 170 255 255 255 255 85 85 +170 0 0 170 0 0 170 0 0 255 85 85 +255 255 255 255 85 85 170 0 0 170 0 0 +170 0 0 255 85 85 255 255 255 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +255 85 85 170 170 170 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 255 255 255 255 85 85 170 0 0 +170 0 0 170 0 0 170 0 0 255 85 85 +170 170 170 255 85 85 170 170 170 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 255 85 85 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +255 255 255 255 255 255 0 0 0 0 0 0 + 0 0 0 85 85 85 170 170 170 170 170 170 +255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 170 170 170 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 255 255 255 170 170 170 170 0 0 +170 0 0 170 0 0 170 0 0 170 170 170 +170 170 170 170 0 0 170 0 0 170 0 0 +170 0 0 170 170 170 255 255 255 255 85 85 +170 0 0 170 0 0 170 0 0 170 0 0 +170 170 170 255 85 85 170 0 0 170 0 0 +170 0 0 170 0 0 255 255 255 170 170 170 +255 255 255 255 255 255 170 170 170 255 255 255 +170 170 170 255 255 255 170 0 0 170 0 0 +170 0 0 170 0 0 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 170 170 170 +170 0 0 170 0 0 170 0 0 170 0 0 +170 170 170 255 255 255 255 255 255 255 85 85 +170 0 0 170 0 0 170 0 0 255 85 85 +255 255 255 170 170 170 0 0 0 0 0 0 + 0 0 0 255 255 255 255 255 255 255 85 85 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 255 85 85 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 255 85 85 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 255 85 85 170 0 0 +170 0 0 170 0 0 170 0 0 255 85 85 +255 255 255 170 170 170 170 0 0 170 0 0 +170 0 0 170 0 0 255 85 85 255 85 85 +255 85 85 255 85 85 170 0 0 255 85 85 +255 255 255 170 170 170 170 0 0 170 0 0 +170 0 0 170 0 0 255 255 255 255 255 255 +255 85 85 170 170 170 255 255 255 170 170 170 +170 0 0 170 0 0 170 0 0 170 0 0 +170 170 170 170 170 170 255 255 255 170 0 0 +170 0 0 170 0 0 170 0 0 255 85 85 +255 255 255 170 170 170 0 0 0 0 0 0 + 85 85 85 255 255 255 255 85 85 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 255 85 85 170 170 170 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 255 85 85 170 170 170 255 255 255 +255 85 85 170 0 0 170 0 0 170 0 0 +255 85 85 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 170 170 +255 255 255 170 170 170 255 85 85 170 0 0 +170 0 0 170 0 0 170 0 0 170 0 0 +170 0 0 170 0 0 170 0 0 170 170 170 +255 255 255 255 85 85 170 0 0 170 0 0 +170 0 0 255 85 85 255 255 255 170 170 170 +170 85 0 170 170 170 255 255 255 255 85 85 +170 0 0 170 0 0 170 0 0 255 85 85 +255 255 255 255 255 255 170 170 170 170 0 0 +170 0 0 170 0 0 170 0 0 170 170 170 +255 255 255 85 85 85 0 0 0 0 0 0 + 85 85 85 170 170 170 170 170 170 170 170 170 +255 85 85 255 85 85 255 85 85 255 85 85 +255 85 85 255 85 85 255 85 85 255 85 85 +255 85 85 255 255 255 170 170 170 170 170 170 +255 255 255 170 170 170 255 85 85 255 85 85 +255 85 85 255 85 85 255 85 85 255 85 85 +255 85 85 255 255 255 255 255 255 255 255 255 +170 0 0 170 0 0 170 0 0 170 0 0 +170 170 170 170 170 170 255 85 85 255 85 85 +255 85 85 255 85 85 170 170 170 255 255 255 + 85 85 85 170 170 170 255 255 255 255 85 85 +255 85 85 255 85 85 255 85 85 255 85 85 +255 85 85 255 85 85 170 170 170 255 255 255 +170 170 170 255 85 85 170 170 170 255 85 85 +255 85 85 170 170 170 255 255 85 170 170 170 + 0 0 0 85 85 85 170 170 170 255 85 85 +170 170 170 255 85 85 255 85 85 255 85 85 +255 255 255 255 85 85 170 170 170 255 85 85 +170 170 170 255 85 85 170 170 170 255 255 255 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 170 85 0 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 0 0 0 0 0 0 +170 170 170 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 85 85 +170 0 0 170 0 0 170 0 0 170 0 0 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 85 85 85 + 0 0 0 85 85 85 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 85 85 85 +170 170 170 255 255 85 255 255 255 255 255 255 +255 255 255 255 255 255 255 85 85 0 0 0 + 0 0 0 0 0 0 170 170 170 170 170 170 +255 255 255 255 255 255 255 255 255 255 255 255 + 85 85 85 85 85 85 170 170 170 255 255 255 +255 255 255 255 255 255 255 255 255 170 85 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 85 85 85 +170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 85 85 85 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 + 85 85 85 85 85 85 170 170 170 170 170 170 +255 85 85 255 85 85 255 85 85 255 85 85 +255 255 255 170 85 0 170 170 170 170 170 170 +170 170 170 170 170 170 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 85 85 85 170 85 0 0 0 0 + 0 0 0 85 85 85 85 85 85 170 170 170 + 85 85 85 85 85 85 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 +170 170 170 85 85 85 170 170 170 85 85 85 + 0 0 0 0 0 0 85 85 85 85 85 85 +170 170 170 85 85 85 170 170 170 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 85 85 85 170 170 170 +255 255 255 255 255 255 255 255 255 255 255 255 + 85 85 85 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 85 85 85 +170 170 170 170 170 170 170 170 170 170 170 170 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c new file mode 100644 index 000000000000..4945a4c02209 --- /dev/null +++ b/drivers/video/macfb.c @@ -0,0 +1,970 @@ +/* macfb.c: Generic framebuffer for Macs whose colourmaps/modes we + don't know how to set */ + +/* (c) 1999 David Huggins-Daines <dhd@debian.org> + + Primarily based on vesafb.c, by Gerd Knorr + (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + + Also uses information and code from: + + The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen + Mellinger, Mikael Forselius, Michael Schmitz, and others. + + valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan + Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven. + + This code is free software. You may copy, modify, and distribute + it subject to the terms and conditions of the GNU General Public + License, version 2, or any later version, at your convenience. */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#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/nubus.h> +#include <linux/init.h> +#include <linux/fb.h> + +#include <asm/setup.h> +#include <asm/bootinfo.h> +#include <asm/uaccess.h> +#include <asm/pgtable.h> +#include <asm/irq.h> +#include <asm/macintosh.h> +#include <asm/io.h> +#include <asm/machw.h> + +/* Common DAC base address for the LC, RBV, Valkyrie, and IIvx */ +#define DAC_BASE 0x50f24000 + +/* Some addresses for the DAFB */ +#define DAFB_BASE 0xf9800200 + +/* Address for the built-in Civic framebuffer in Quadra AVs */ +#define CIVIC_BASE 0x50f30800 /* Only tested on 660AV! */ + +/* GSC (Gray Scale Controller) base address */ +#define GSC_BASE 0x50F20000 + +/* CSC (Color Screen Controller) base address */ +#define CSC_BASE 0x50F20000 + +static int (*macfb_setpalette) (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *info) = NULL; +static int valkyrie_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *info); +static int dafb_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *fb_info); +static int rbv_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *fb_info); +static int mdc_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *fb_info); +static int toby_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *fb_info); +static int civic_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *fb_info); +static int csc_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *fb_info); + +static volatile struct { + unsigned char addr; + /* Note: word-aligned */ + char pad[3]; + unsigned char lut; +} *valkyrie_cmap_regs; + +static volatile struct { + unsigned char addr; + unsigned char lut; +} *v8_brazil_cmap_regs; + +static volatile struct { + unsigned char addr; + char pad1[3]; /* word aligned */ + unsigned char lut; + char pad2[3]; /* word aligned */ + unsigned char cntl; /* a guess as to purpose */ +} *rbv_cmap_regs; + +static volatile struct { + unsigned long reset; + unsigned long pad1[3]; + unsigned char pad2[3]; + unsigned char lut; +} *dafb_cmap_regs; + +static volatile struct { + unsigned char addr; /* OFFSET: 0x00 */ + unsigned char pad1[15]; + unsigned char lut; /* OFFSET: 0x10 */ + unsigned char pad2[15]; + unsigned char status; /* OFFSET: 0x20 */ + unsigned char pad3[7]; + unsigned long vbl_addr; /* OFFSET: 0x28 */ + unsigned int status2; /* OFFSET: 0x2C */ +} *civic_cmap_regs; + +static volatile struct { + char pad1[0x40]; + unsigned char clut_waddr; /* 0x40 */ + char pad2; + unsigned char clut_data; /* 0x42 */ + char pad3[0x3]; + unsigned char clut_raddr; /* 0x46 */ +} *csc_cmap_regs; + +/* We will leave these the way they are for the time being */ +struct mdc_cmap_regs { + char pad1[0x200200]; + unsigned char addr; + char pad2[6]; + unsigned char lut; +}; + +struct toby_cmap_regs { + char pad1[0x90018]; + unsigned char lut; /* TFBClutWDataReg, offset 0x90018 */ + char pad2[3]; + unsigned char addr; /* TFBClutAddrReg, offset 0x9001C */ +}; + +struct jet_cmap_regs { + char pad1[0xe0e000]; + unsigned char addr; + unsigned char lut; +}; + +#define PIXEL_TO_MM(a) (((a)*10)/28) /* width in mm at 72 dpi */ + +/* mode */ +static int video_slot = 0; + +static struct fb_var_screeninfo macfb_defined = { + .bits_per_pixel = 8, + .activate = FB_ACTIVATE_NOW, + .width = -1, + .height = -1, + .right_margin = 32, + .upper_margin = 16, + .lower_margin = 4, + .vsync_len = 4, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo macfb_fix = { + .id = "Macintosh ", + .type = FB_TYPE_PACKED_PIXELS, + .accel = FB_ACCEL_NONE, +}; + +static struct fb_info fb_info; +static u32 pseudo_palette[17]; +static int inverse = 0; +static int vidtest = 0; + +static int valkyrie_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *info) +{ + unsigned long flags; + + red >>= 8; + green >>= 8; + blue >>= 8; + + local_irq_save(flags); + + /* tell clut which address to fill */ + nubus_writeb(regno, &valkyrie_cmap_regs->addr); + nop(); + + /* send one color channel at a time */ + nubus_writeb(red, &valkyrie_cmap_regs->lut); + nop(); + nubus_writeb(green, &valkyrie_cmap_regs->lut); + nop(); + nubus_writeb(blue, &valkyrie_cmap_regs->lut); + + local_irq_restore(flags); + return 0; +} + +/* Unlike the Valkyrie, the DAFB cannot set individual colormap + registers. Therefore, we do what the MacOS driver does (no + kidding!) and simply set them one by one until we hit the one we + want. */ +static int dafb_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *info) +{ + /* FIXME: really, really need to use ioremap() here, + phys_to_virt() doesn't work anymore */ + static int lastreg = -1; + unsigned long flags; + + red >>= 8; + green >>= 8; + blue >>= 8; + + local_irq_save(flags); + + /* fbdev will set an entire colourmap, but X won't. Hopefully + this should accommodate both of them */ + if (regno != lastreg+1) { + int i; + + /* Stab in the dark trying to reset the CLUT pointer */ + nubus_writel(0, &dafb_cmap_regs->reset); + nop(); + + /* Loop until we get to the register we want */ + for (i = 0; i < regno; i++) { + nubus_writeb(info->cmap.red[i] >> 8, &dafb_cmap_regs->lut); + nop(); + nubus_writeb(info->cmap.green[i] >> 8, &dafb_cmap_regs->lut); + nop(); + nubus_writeb(info->cmap.blue[i] >> 8, &dafb_cmap_regs->lut); + nop(); + } + } + + nubus_writeb(red, &dafb_cmap_regs->lut); + nop(); + nubus_writeb(green, &dafb_cmap_regs->lut); + nop(); + nubus_writeb(blue, &dafb_cmap_regs->lut); + + local_irq_restore(flags); + lastreg = regno; + return 0; +} + +/* V8 and Brazil seem to use the same DAC. Sonora does as well. */ +static int v8_brazil_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *info) +{ + unsigned int bpp = info->var.bits_per_pixel; + unsigned char _red =red>>8; + unsigned char _green=green>>8; + unsigned char _blue =blue>>8; + unsigned char _regno; + unsigned long flags; + + if (bpp > 8) return 1; /* failsafe */ + + local_irq_save(flags); + + /* On these chips, the CLUT register numbers are spread out + across the register space. Thus: + + In 8bpp, all regnos are valid. + + In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc + + In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff */ + _regno = (regno << (8 - bpp)) | (0xFF >> bpp); + nubus_writeb(_regno, &v8_brazil_cmap_regs->addr); nop(); + + /* send one color channel at a time */ + nubus_writeb(_red, &v8_brazil_cmap_regs->lut); nop(); + nubus_writeb(_green, &v8_brazil_cmap_regs->lut); nop(); + nubus_writeb(_blue, &v8_brazil_cmap_regs->lut); + + local_irq_restore(flags); + return 0; +} + +static int rbv_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *info) +{ + /* use MSBs */ + unsigned char _red =red>>8; + unsigned char _green=green>>8; + unsigned char _blue =blue>>8; + unsigned char _regno; + unsigned long flags; + + if (info->var.bits_per_pixel > 8) return 1; /* failsafe */ + + local_irq_save(flags); + + /* From the VideoToolbox driver. Seems to be saying that + * regno #254 and #255 are the important ones for 1-bit color, + * regno #252-255 are the important ones for 2-bit color, etc. + */ + _regno = regno + (256-(1 << info->var.bits_per_pixel)); + + /* reset clut? (VideoToolbox sez "not necessary") */ + nubus_writeb(0xFF, &rbv_cmap_regs->cntl); nop(); + + /* tell clut which address to use. */ + nubus_writeb(_regno, &rbv_cmap_regs->addr); nop(); + + /* send one color channel at a time. */ + nubus_writeb(_red, &rbv_cmap_regs->lut); nop(); + nubus_writeb(_green, &rbv_cmap_regs->lut); nop(); + nubus_writeb(_blue, &rbv_cmap_regs->lut); + + local_irq_restore(flags); /* done. */ + return 0; +} + +/* Macintosh Display Card (8x24) */ +static int mdc_setpalette(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *info) +{ + volatile struct mdc_cmap_regs *cmap_regs = + nubus_slot_addr(video_slot); + /* use MSBs */ + unsigned char _red =red>>8; + unsigned char _green=green>>8; + unsigned char _blue =blue>>8; + unsigned char _regno=regno; + unsigned long flags; + + local_irq_save(flags); + + /* the nop's are there to order writes. */ + nubus_writeb(_regno, &cmap_regs->addr); nop(); + nubus_writeb(_red, &cmap_regs->lut); nop(); + nubus_writeb(_green, &cmap_regs->lut); nop(); + nubus_writeb(_blue, &cmap_regs->lut); + + local_irq_restore(flags); + return 0; +} + +/* Toby frame buffer */ +static int toby_setpalette(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *info) +{ + volatile struct toby_cmap_regs *cmap_regs = + nubus_slot_addr(video_slot); + unsigned int bpp = info->var.bits_per_pixel; + /* use MSBs */ + unsigned char _red =~(red>>8); + unsigned char _green=~(green>>8); + unsigned char _blue =~(blue>>8); + unsigned char _regno = (regno << (8 - bpp)) | (0xFF >> bpp); + unsigned long flags; + + local_irq_save(flags); + + nubus_writeb(_regno, &cmap_regs->addr); nop(); + nubus_writeb(_red, &cmap_regs->lut); nop(); + nubus_writeb(_green, &cmap_regs->lut); nop(); + nubus_writeb(_blue, &cmap_regs->lut); + + local_irq_restore(flags); + return 0; +} + +/* Jet frame buffer */ +static int jet_setpalette(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *info) +{ + volatile struct jet_cmap_regs *cmap_regs = + nubus_slot_addr(video_slot); + /* use MSBs */ + unsigned char _red = (red>>8); + unsigned char _green = (green>>8); + unsigned char _blue = (blue>>8); + unsigned long flags; + + local_irq_save(flags); + + nubus_writeb(regno, &cmap_regs->addr); nop(); + nubus_writeb(_red, &cmap_regs->lut); nop(); + nubus_writeb(_green, &cmap_regs->lut); nop(); + nubus_writeb(_blue, &cmap_regs->lut); + + local_irq_restore(flags); + return 0; +} + +/* + * Civic framebuffer -- Quadra AV built-in video. A chip + * called Sebastian holds the actual color palettes, and + * apparently, there are two different banks of 512K RAM + * which can act as separate framebuffers for doing video + * input and viewing the screen at the same time! The 840AV + * Can add another 1MB RAM to give the two framebuffers + * 1MB RAM apiece. + * + * FIXME: this doesn't seem to work anymore. + */ +static int civic_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *info) +{ + static int lastreg = -1; + unsigned long flags; + int clut_status; + + if (info->var.bits_per_pixel > 8) return 1; /* failsafe */ + + red >>= 8; + green >>= 8; + blue >>= 8; + + local_irq_save(flags); + + /* + * Set the register address + */ + nubus_writeb(regno, &civic_cmap_regs->addr); nop(); + + /* + * Wait for VBL interrupt here; + * They're usually not enabled from Penguin, so we won't check + */ +#if 0 + { +#define CIVIC_VBL_OFFSET 0x120 + volatile unsigned long *vbl = nubus_readl(civic_cmap_regs->vbl_addr + CIVIC_VBL_OFFSET); + /* do interrupt setup stuff here? */ + *vbl = 0L; nop(); /* clear */ + *vbl = 1L; nop(); /* set */ + while (*vbl != 0L) /* wait for next vbl */ + { + usleep(10); /* needed? */ + } + /* do interrupt shutdown stuff here? */ + } +#endif + + /* + * Grab a status word and do some checking; + * Then finally write the clut! + */ + clut_status = nubus_readb(&civic_cmap_regs->status2); + + if ((clut_status & 0x0008) == 0) + { +#if 0 + if ((clut_status & 0x000D) != 0) + { + nubus_writeb(0x00, &civic_cmap_regs->lut); nop(); + nubus_writeb(0x00, &civic_cmap_regs->lut); nop(); + } +#endif + + nubus_writeb( red, &civic_cmap_regs->lut); nop(); + nubus_writeb(green, &civic_cmap_regs->lut); nop(); + nubus_writeb( blue, &civic_cmap_regs->lut); nop(); + nubus_writeb( 0x00, &civic_cmap_regs->lut); nop(); + } + else + { + unsigned char junk; + + junk = nubus_readb(&civic_cmap_regs->lut); nop(); + junk = nubus_readb(&civic_cmap_regs->lut); nop(); + junk = nubus_readb(&civic_cmap_regs->lut); nop(); + junk = nubus_readb(&civic_cmap_regs->lut); nop(); + + if ((clut_status & 0x000D) != 0) + { + nubus_writeb(0x00, &civic_cmap_regs->lut); nop(); + nubus_writeb(0x00, &civic_cmap_regs->lut); nop(); + } + + nubus_writeb( red, &civic_cmap_regs->lut); nop(); + nubus_writeb(green, &civic_cmap_regs->lut); nop(); + nubus_writeb( blue, &civic_cmap_regs->lut); nop(); + nubus_writeb( junk, &civic_cmap_regs->lut); nop(); + } + + local_irq_restore(flags); + lastreg = regno; + return 0; +} + +/* + * The CSC is the framebuffer on the PowerBook 190 series + * (and the 5300 too, but that's a PowerMac). This function + * brought to you in part by the ECSC driver for MkLinux. + */ + +static int csc_setpalette (unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + struct fb_info *info) +{ + mdelay(1); + csc_cmap_regs->clut_waddr = regno; + csc_cmap_regs->clut_data = red; + csc_cmap_regs->clut_data = green; + csc_cmap_regs->clut_data = blue; + return 0; +} + +static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info) +{ + /* + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return + * != 0 for invalid regno. + */ + + if (regno >= fb_info->cmap.len) + return 1; + + switch (fb_info->var.bits_per_pixel) { + case 1: + /* We shouldn't get here */ + break; + case 2: + case 4: + case 8: + if (macfb_setpalette) + macfb_setpalette(regno, red, green, blue, fb_info); + else + return 1; + break; + case 16: + if (fb_info->var.red.offset == 10) { + /* 1:5:5:5 */ + ((u32*) (fb_info->pseudo_palette))[regno] = + ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11) | + ((transp != 0) << 15); + } else { + /* 0:5:6:5 */ + ((u32*) (fb_info->pseudo_palette))[regno] = + ((red & 0xf800) ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + } + break; + /* I'm pretty sure that one or the other of these + doesn't exist on 68k Macs */ + case 24: + red >>= 8; + green >>= 8; + blue >>= 8; + ((u32 *)(fb_info->pseudo_palette))[regno] = + (red << fb_info->var.red.offset) | + (green << fb_info->var.green.offset) | + (blue << fb_info->var.blue.offset); + break; + case 32: + red >>= 8; + green >>= 8; + blue >>= 8; + ((u32 *)(fb_info->pseudo_palette))[regno] = + (red << fb_info->var.red.offset) | + (green << fb_info->var.green.offset) | + (blue << fb_info->var.blue.offset); + break; + } + return 0; +} + +static struct fb_ops macfb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = macfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +void __init macfb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) continue; + + if (! strcmp(this_opt, "inverse")) + inverse=1; + /* This means "turn on experimental CLUT code" */ + else if (!strcmp(this_opt, "vidtest")) + vidtest=1; + } +} + +void __init macfb_init(void) +{ + int video_cmap_len, video_is_nubus = 0; + struct nubus_dev* ndev = NULL; + char *option = NULL; + + if (fb_get_options("macfb", &option)) + return -ENODEV; + macfb_setup(option); + + if (!MACH_IS_MAC) + return; + + /* There can only be one internal video controller anyway so + we're not too worried about this */ + macfb_defined.xres = mac_bi_data.dimensions & 0xFFFF; + macfb_defined.yres = mac_bi_data.dimensions >> 16; + macfb_defined.bits_per_pixel = mac_bi_data.videodepth; + macfb_fix.line_length = mac_bi_data.videorow; + macfb_fix.smem_len = macfb_fix.line_length * macfb_defined.yres; + /* Note: physical address (since 2.1.127) */ + macfb_fix.smem_start = mac_bi_data.videoaddr; + /* This is actually redundant with the initial mappings. + However, there are some non-obvious aspects to the way + those mappings are set up, so this is in fact the safest + way to ensure that this driver will work on every possible + Mac */ + fb_info.screen_base = ioremap(mac_bi_data.videoaddr, macfb_fix.smem_len); + + printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n", + macfb_fix.smem_start, fb_info.screen_base, macfb_fix.smem_len/1024); + printk("macfb: mode is %dx%dx%d, linelength=%d\n", + macfb_defined.xres, macfb_defined.yres, macfb_defined.bits_per_pixel, macfb_fix.line_length); + + /* + * Fill in the available video resolution + */ + + macfb_defined.xres_virtual = macfb_defined.xres; + macfb_defined.yres_virtual = macfb_defined.yres; + macfb_defined.height = PIXEL_TO_MM(macfb_defined.yres); + macfb_defined.width = PIXEL_TO_MM(macfb_defined.xres); + + printk("macfb: scrolling: redraw\n"); + macfb_defined.yres_virtual = macfb_defined.yres; + + /* some dummy values for timing to make fbset happy */ + macfb_defined.pixclock = 10000000 / macfb_defined.xres * 1000 / macfb_defined.yres; + macfb_defined.left_margin = (macfb_defined.xres / 8) & 0xf8; + macfb_defined.hsync_len = (macfb_defined.xres / 8) & 0xf8; + + switch (macfb_defined.bits_per_pixel) { + case 1: + /* XXX: I think this will catch any program that tries + to do FBIO_PUTCMAP when the visual is monochrome */ + macfb_defined.red.length = macfb_defined.bits_per_pixel; + macfb_defined.green.length = macfb_defined.bits_per_pixel; + macfb_defined.blue.length = macfb_defined.bits_per_pixel; + video_cmap_len = 0; + macfb_fix.visual = FB_VISUAL_MONO01; + break; + case 2: + case 4: + case 8: + macfb_defined.red.length = macfb_defined.bits_per_pixel; + macfb_defined.green.length = macfb_defined.bits_per_pixel; + macfb_defined.blue.length = macfb_defined.bits_per_pixel; + video_cmap_len = 1 << macfb_defined.bits_per_pixel; + macfb_fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + case 16: + macfb_defined.transp.offset = 15; + macfb_defined.transp.length = 1; + macfb_defined.red.offset = 10; + macfb_defined.red.length = 5; + macfb_defined.green.offset = 5; + macfb_defined.green.length = 5; + macfb_defined.blue.offset = 0; + macfb_defined.blue.length = 5; + printk("macfb: directcolor: " + "size=1:5:5:5, shift=15:10:5:0\n"); + video_cmap_len = 16; + /* Should actually be FB_VISUAL_DIRECTCOLOR, but this + works too */ + macfb_fix.visual = FB_VISUAL_TRUECOLOR; + break; + case 24: + case 32: + /* XXX: have to test these... can any 68k Macs + actually do this on internal video? */ + macfb_defined.red.offset = 16; + macfb_defined.red.length = 8; + macfb_defined.green.offset = 8; + macfb_defined.green.length = 8; + macfb_defined.blue.offset = 0; + macfb_defined.blue.length = 8; + printk("macfb: truecolor: " + "size=0:8:8:8, shift=0:16:8:0\n"); + video_cmap_len = 16; + macfb_fix.visual = FB_VISUAL_TRUECOLOR; + default: + video_cmap_len = 0; + macfb_fix.visual = FB_VISUAL_MONO01; + printk("macfb: unknown or unsupported bit depth: %d\n", macfb_defined.bits_per_pixel); + break; + } + + /* Hardware dependent stuff */ + /* We take a wild guess that if the video physical address is + * in nubus slot space, that the nubus card is driving video. + * Penguin really ought to tell us whether we are using internal + * video or not. + */ + /* Hopefully we only find one of them. Otherwise our NuBus + code is really broken :-) */ + + while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY, NUBUS_TYPE_VIDEO, ndev)) + != NULL) + { + if (!(mac_bi_data.videoaddr >= ndev->board->slot_addr + && (mac_bi_data.videoaddr < + (unsigned long)nubus_slot_addr(ndev->board->slot+1)))) + continue; + video_is_nubus = 1; + /* We should probably just use the slot address... */ + video_slot = ndev->board->slot; + + switch(ndev->dr_hw) { + case NUBUS_DRHW_APPLE_MDC: + strcat( macfb_fix.id, "Display Card" ); + macfb_setpalette = mdc_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + break; + case NUBUS_DRHW_APPLE_TFB: + strcat( macfb_fix.id, "Toby" ); + macfb_setpalette = toby_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + break; + case NUBUS_DRHW_APPLE_JET: + strcat( macfb_fix.id, "Jet"); + macfb_setpalette = jet_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + break; + default: + strcat( macfb_fix.id, "Generic NuBus" ); + break; + } + } + + /* If it's not a NuBus card, it must be internal video */ + /* FIXME: this function is getting way too big. (this driver + is too...) */ + if (!video_is_nubus) + switch( mac_bi_data.id ) + { + /* These don't have onboard video. Eventually, we may + be able to write separate framebuffer drivers for + them (tobyfb.c, hiresfb.c, etc, etc) */ + case MAC_MODEL_II: + case MAC_MODEL_IIX: + case MAC_MODEL_IICX: + case MAC_MODEL_IIFX: + strcat( macfb_fix.id, "Generic NuBus" ); + break; + + /* Valkyrie Quadras */ + case MAC_MODEL_Q630: + /* I'm not sure about this one */ + case MAC_MODEL_P588: + strcat( macfb_fix.id, "Valkyrie built-in" ); + macfb_setpalette = valkyrie_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + valkyrie_cmap_regs = ioremap(DAC_BASE, 0x1000); + break; + + /* DAFB Quadras */ + /* Note: these first four have the v7 DAFB, which is + known to be rather unlike the ones used in the + other models */ + case MAC_MODEL_P475: + case MAC_MODEL_P475F: + case MAC_MODEL_P575: + case MAC_MODEL_Q605: + + case MAC_MODEL_Q800: + case MAC_MODEL_Q650: + case MAC_MODEL_Q610: + case MAC_MODEL_C650: + case MAC_MODEL_C610: + case MAC_MODEL_Q700: + case MAC_MODEL_Q900: + case MAC_MODEL_Q950: + strcat( macfb_fix.id, "DAFB built-in" ); + macfb_setpalette = dafb_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000); + break; + + /* LC II uses the V8 framebuffer */ + case MAC_MODEL_LCII: + strcat( macfb_fix.id, "V8 built-in" ); + macfb_setpalette = v8_brazil_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000); + break; + + /* IIvi, IIvx use the "Brazil" framebuffer (which is + very much like the V8, it seems, and probably uses + the same DAC) */ + case MAC_MODEL_IIVI: + case MAC_MODEL_IIVX: + case MAC_MODEL_P600: + strcat( macfb_fix.id, "Brazil built-in" ); + macfb_setpalette = v8_brazil_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000); + break; + + /* LC III (and friends) use the Sonora framebuffer */ + /* Incidentally this is also used in the non-AV models + of the x100 PowerMacs */ + /* These do in fact seem to use the same DAC interface + as the LC II. */ + case MAC_MODEL_LCIII: + case MAC_MODEL_P520: + case MAC_MODEL_P550: + case MAC_MODEL_P460: + macfb_setpalette = v8_brazil_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + strcat( macfb_fix.id, "Sonora built-in" ); + v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000); + break; + + /* IIci and IIsi use the infamous RBV chip + (the IIsi is just a rebadged and crippled + IIci in a different case, BTW) */ + case MAC_MODEL_IICI: + case MAC_MODEL_IISI: + macfb_setpalette = rbv_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + strcat( macfb_fix.id, "RBV built-in" ); + rbv_cmap_regs = ioremap(DAC_BASE, 0x1000); + break; + + /* AVs use the Civic framebuffer */ + case MAC_MODEL_Q840: + case MAC_MODEL_C660: + macfb_setpalette = civic_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + strcat( macfb_fix.id, "Civic built-in" ); + civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000); + break; + + + /* Write a setpalette function for your machine, then + you can add something similar here. These are + grouped by classes of video chipsets. Some of this + information is from the VideoToolbox "Bugs" web + page at + http://rajsky.psych.nyu.edu/Tips/VideoBugs.html */ + + /* Assorted weirdos */ + /* We think this may be like the LC II */ + case MAC_MODEL_LC: + if (vidtest) { + macfb_setpalette = v8_brazil_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + v8_brazil_cmap_regs = + ioremap(DAC_BASE, 0x1000); + } + strcat( macfb_fix.id, "LC built-in" ); + break; + /* We think this may be like the LC II */ + case MAC_MODEL_CCL: + if (vidtest) { + macfb_setpalette = v8_brazil_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + v8_brazil_cmap_regs = + ioremap(DAC_BASE, 0x1000); + } + strcat( macfb_fix.id, "Color Classic built-in" ); + break; + + /* And we *do* mean "weirdos" */ + case MAC_MODEL_TV: + strcat( macfb_fix.id, "Mac TV built-in" ); + break; + + /* These don't have colour, so no need to worry */ + case MAC_MODEL_SE30: + case MAC_MODEL_CLII: + strcat( macfb_fix.id, "Monochrome built-in" ); + break; + + /* Powerbooks are particularly difficult. Many of + them have separate framebuffers for external and + internal video, which is admittedly pretty cool, + but will be a bit of a headache to support here. + Also, many of them are grayscale, and we don't + really support that. */ + + case MAC_MODEL_PB140: + case MAC_MODEL_PB145: + case MAC_MODEL_PB170: + strcat( macfb_fix.id, "DDC built-in" ); + break; + + /* Internal is GSC, External (if present) is ViSC */ + case MAC_MODEL_PB150: /* no external video */ + case MAC_MODEL_PB160: + case MAC_MODEL_PB165: + case MAC_MODEL_PB180: + case MAC_MODEL_PB210: + case MAC_MODEL_PB230: + strcat( macfb_fix.id, "GSC built-in" ); + break; + + /* Internal is TIM, External is ViSC */ + case MAC_MODEL_PB165C: + case MAC_MODEL_PB180C: + strcat( macfb_fix.id, "TIM built-in" ); + break; + + /* Internal is CSC, External is Keystone+Ariel. */ + case MAC_MODEL_PB190: /* external video is optional */ + case MAC_MODEL_PB520: + case MAC_MODEL_PB250: + case MAC_MODEL_PB270C: + case MAC_MODEL_PB280: + case MAC_MODEL_PB280C: + macfb_setpalette = csc_setpalette; + macfb_defined.activate = FB_ACTIVATE_NOW; + strcat( macfb_fix.id, "CSC built-in" ); + csc_cmap_regs = ioremap(CSC_BASE, 0x1000); + break; + + default: + strcat( macfb_fix.id, "Unknown/Unsupported built-in" ); + break; + } + + fb_info.fbops = &macfb_ops; + fb_info.var = macfb_defined; + fb_info.fix = macfb_fix; + fb_info.pseudo_palette = pseudo_palette; + fb_info.flags = FBINFO_DEFAULT; + + fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0); + + if (register_framebuffer(&fb_info) < 0) + return; + + printk("fb%d: %s frame buffer device\n", + fb_info.node, fb_info.fix.id); +} + +module_init(macfb_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c new file mode 100644 index 000000000000..de5a0f383600 --- /dev/null +++ b/drivers/video/macmodes.c @@ -0,0 +1,389 @@ +/* + * linux/drivers/video/macmodes.c -- Standard MacOS video modes + * + * Copyright (C) 1998 Geert Uytterhoeven + * + * 2000 - Removal of OpenFirmware dependencies by: + * - Ani Joshi + * - Brad Douglas <brad@neruo.com> + * + * 2001 - Documented with DocBook + * - Brad Douglas <brad@neruo.com> + * + * 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/config.h> +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/string.h> +#include <linux/module.h> + +#include "macmodes.h" + + /* + * MacOS video mode definitions + * + * Order IS important! If you change these, don't forget to update + * mac_modes[] below! + */ + +#define DEFAULT_MODEDB_INDEX 0 + +static const struct fb_videomode mac_modedb[] = { + { + /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ + "mac5", 60, 640, 480, 39722, 32, 32, 33, 10, 96, 2, + 0, FB_VMODE_NONINTERLACED + }, { + /* 640x480, 67Hz, Non-Interlaced (30.0 MHz dotclock) */ + "mac6", 67, 640, 480, 33334, 80, 80, 39, 3, 64, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 800x600, 56 Hz, Non-Interlaced (36.00 MHz dotclock) */ + "mac9", 56, 800, 600, 27778, 112, 40, 22, 1, 72, 2, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 800x600, 60 Hz, Non-Interlaced (40.00 MHz dotclock) */ + "mac10", 60, 800, 600, 25000, 72, 56, 23, 1, 128, 4, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 800x600, 72 Hz, Non-Interlaced (50.00 MHz dotclock) */ + "mac11", 72, 800, 600, 20000, 48, 72, 23, 37, 120, 6, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 800x600, 75 Hz, Non-Interlaced (49.50 MHz dotclock) */ + "mac12", 75, 800, 600, 20203, 144, 32, 21, 1, 80, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 832x624, 75Hz, Non-Interlaced (57.6 MHz dotclock) */ + "mac13", 75, 832, 624, 17362, 208, 48, 39, 1, 64, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768, 60 Hz, Non-Interlaced (65.00 MHz dotclock) */ + "mac14", 60, 1024, 768, 15385, 144, 40, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768, 72 Hz, Non-Interlaced (75.00 MHz dotclock) */ + "mac15", 72, 1024, 768, 13334, 128, 40, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ + "mac16", 75, 1024, 768, 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) */ + "mac17", 75, 1024, 768, 12699, 160, 32, 28, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1152x870, 75 Hz, Non-Interlaced (100.0 MHz dotclock) */ + "mac18", 75, 1152, 870, 10000, 128, 48, 39, 3, 128, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1280x960, 75 Hz, Non-Interlaced (126.00 MHz dotclock) */ + "mac19", 75, 1280, 960, 7937, 224, 32, 36, 1, 144, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */ + "mac20", 75, 1280, 1024, 7408, 232, 64, 38, 1, 112, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1152x768, 60 Hz, Titanium PowerBook */ + "mac21", 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1600x1024, 60 Hz, Non-Interlaced (112.27 MHz dotclock) */ + "mac22", 60, 1600, 1024, 8908, 88, 104, 1, 10, 16, 1, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + +#if 0 + /* Anyone who has timings for these? */ + { + /* VMODE_512_384_60I: 512x384, 60Hz, Interlaced (NTSC) */ + "mac1", 60, 512, 384, pixclock, left, right, upper, lower, hslen, vslen, + sync, FB_VMODE_INTERLACED + }, { + /* VMODE_512_384_60: 512x384, 60Hz, Non-Interlaced */ + "mac2", 60, 512, 384, pixclock, left, right, upper, lower, hslen, vslen, + sync, FB_VMODE_NONINTERLACED + }, { + /* VMODE_640_480_50I: 640x480, 50Hz, Interlaced (PAL) */ + "mac3", 50, 640, 480, pixclock, left, right, upper, lower, hslen, vslen, + sync, FB_VMODE_INTERLACED + }, { + /* VMODE_640_480_60I: 640x480, 60Hz, Interlaced (NTSC) */ + "mac4", 60, 640, 480, pixclock, left, right, upper, lower, hslen, vslen, + sync, FB_VMODE_INTERLACED + }, { + /* VMODE_640_870_75P: 640x870, 75Hz (portrait), Non-Interlaced */ + "mac7", 75, 640, 870, pixclock, left, right, upper, lower, hslen, vslen, + sync, FB_VMODE_NONINTERLACED + }, { + /* VMODE_768_576_50I: 768x576, 50Hz (PAL full frame), Interlaced */ + "mac8", 50, 768, 576, pixclock, left, right, upper, lower, hslen, vslen, + sync, FB_VMODE_INTERLACED + }, +#endif +}; + + + /* + * Mapping between MacOS video mode numbers and video mode definitions + * + * These MUST be ordered in + * - increasing resolution + * - decreasing refresh rate + */ + +static const struct mode_map { + int vmode; + const struct fb_videomode *mode; +} mac_modes[] = { + /* 640x480 */ + { VMODE_640_480_67, &mac_modedb[1] }, + { VMODE_640_480_60, &mac_modedb[0] }, + /* 800x600 */ + { VMODE_800_600_75, &mac_modedb[5] }, + { VMODE_800_600_72, &mac_modedb[4] }, + { VMODE_800_600_60, &mac_modedb[3] }, + { VMODE_800_600_56, &mac_modedb[2] }, + /* 832x624 */ + { VMODE_832_624_75, &mac_modedb[6] }, + /* 1024x768 */ + { VMODE_1024_768_75, &mac_modedb[10] }, + { VMODE_1024_768_75V, &mac_modedb[9] }, + { VMODE_1024_768_70, &mac_modedb[8] }, + { VMODE_1024_768_60, &mac_modedb[7] }, + /* 1152x768 */ + { VMODE_1152_768_60, &mac_modedb[14] }, + /* 1152x870 */ + { VMODE_1152_870_75, &mac_modedb[11] }, + /* 1280x960 */ + { VMODE_1280_960_75, &mac_modedb[12] }, + /* 1280x1024 */ + { VMODE_1280_1024_75, &mac_modedb[13] }, + /* 1600x1024 */ + { VMODE_1600_1024_60, &mac_modedb[15] }, + { -1, NULL } +}; + + + /* + * Mapping between monitor sense values and MacOS video mode numbers + */ + +static const struct monitor_map { + int sense; + int vmode; +} mac_monitors[] = { + { 0x000, VMODE_1280_1024_75 }, /* 21" RGB */ + { 0x114, VMODE_640_870_75P }, /* Portrait Monochrome */ + { 0x221, VMODE_512_384_60 }, /* 12" RGB*/ + { 0x331, VMODE_1280_1024_75 }, /* 21" RGB (Radius) */ + { 0x334, VMODE_1280_1024_75 }, /* 21" mono (Radius) */ + { 0x335, VMODE_1280_1024_75 }, /* 21" mono */ + { 0x40A, VMODE_640_480_60I }, /* NTSC */ + { 0x51E, VMODE_640_870_75P }, /* Portrait RGB */ + { 0x603, VMODE_832_624_75 }, /* 12"-16" multiscan */ + { 0x60b, VMODE_1024_768_70 }, /* 13"-19" multiscan */ + { 0x623, VMODE_1152_870_75 }, /* 13"-21" multiscan */ + { 0x62b, VMODE_640_480_67 }, /* 13"/14" RGB */ + { 0x700, VMODE_640_480_50I }, /* PAL */ + { 0x714, VMODE_640_480_60I }, /* NTSC */ + { 0x717, VMODE_800_600_75 }, /* VGA */ + { 0x72d, VMODE_832_624_75 }, /* 16" RGB (Goldfish) */ + { 0x730, VMODE_768_576_50I }, /* PAL (Alternate) */ + { 0x73a, VMODE_1152_870_75 }, /* 3rd party 19" */ + { 0x73f, VMODE_640_480_67 }, /* no sense lines connected at all */ + { 0xBEEF, VMODE_1600_1024_60 }, /* 22" Apple Cinema Display */ + { -1, VMODE_640_480_60 }, /* catch-all, must be last */ +}; + +/** + * mac_vmode_to_var - converts vmode/cmode pair to var structure + * @vmode: MacOS video mode + * @cmode: MacOS color mode + * @var: frame buffer video mode structure + * + * Converts a MacOS vmode/cmode pair to a frame buffer video + * mode structure. + * + * Returns negative errno on error, or zero for success. + * + */ + +int mac_vmode_to_var(int vmode, int cmode, struct fb_var_screeninfo *var) +{ + const struct fb_videomode *mode = NULL; + const struct mode_map *map; + + for (map = mac_modes; map->vmode != -1; map++) + if (map->vmode == vmode) { + mode = map->mode; + break; + } + if (!mode) + return -EINVAL; + + memset(var, 0, sizeof(struct fb_var_screeninfo)); + switch (cmode) { + case CMODE_8: + var->bits_per_pixel = 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; + break; + + case CMODE_16: + var->bits_per_pixel = 16; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + break; + + case CMODE_32: + var->bits_per_pixel = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + + default: + return -EINVAL; + } + var->xres = mode->xres; + var->yres = mode->yres; + var->xres_virtual = mode->xres; + var->yres_virtual = mode->yres; + var->height = -1; + var->width = -1; + var->pixclock = mode->pixclock; + var->left_margin = mode->left_margin; + var->right_margin = mode->right_margin; + var->upper_margin = mode->upper_margin; + var->lower_margin = mode->lower_margin; + var->hsync_len = mode->hsync_len; + var->vsync_len = mode->vsync_len; + var->sync = mode->sync; + var->vmode = mode->vmode; + return 0; +} +EXPORT_SYMBOL(mac_vmode_to_var); + +/** + * mac_var_to_vmode - convert var structure to MacOS vmode/cmode pair + * @var: frame buffer video mode structure + * @vmode: MacOS video mode + * @cmode: MacOS color mode + * + * Converts a frame buffer video mode structure to a MacOS + * vmode/cmode pair. + * + * Returns negative errno on error, or zero for success. + * + */ + +int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, + int *cmode) +{ + const struct fb_videomode *mode = NULL; + const struct mode_map *map; + + if (var->bits_per_pixel <= 8) + *cmode = CMODE_8; + else if (var->bits_per_pixel <= 16) + *cmode = CMODE_16; + else if (var->bits_per_pixel <= 32) + *cmode = CMODE_32; + else + return -EINVAL; + + for (map = mac_modes; map->vmode != -1; map++) { + mode = map->mode; + if (var->xres > mode->xres || var->yres > mode->yres) + continue; + if (var->xres_virtual > mode->xres || var->yres_virtual > mode->yres) + continue; + if (var->pixclock > mode->pixclock) + continue; + if ((var->vmode & FB_VMODE_MASK) != mode->vmode) + continue; + *vmode = map->vmode; + return 0; + } + return -EINVAL; +} +EXPORT_SYMBOL(mac_var_to_vmode); + +/** + * mac_map_monitor_sense - Convert monitor sense to vmode + * @sense: Macintosh monitor sense number + * + * Converts a Macintosh monitor sense number to a MacOS + * vmode number. + * + * Returns MacOS vmode video mode number. + * + */ + +int mac_map_monitor_sense(int sense) +{ + const struct monitor_map *map; + + for (map = mac_monitors; map->sense != -1; map++) + if (map->sense == sense) + break; + return map->vmode; +} +EXPORT_SYMBOL(mac_map_monitor_sense); + +/** + * mac_find_mode - find a video mode + * @var: frame buffer user defined part of display + * @info: frame buffer info structure + * @mode_option: video mode name (see mac_modedb[]) + * @default_bpp: default color depth in bits per pixel + * + * Finds a suitable video mode. Tries to set mode specified + * by @mode_option. If the name of the wanted mode begins with + * 'mac', the Mac video mode database will be used, otherwise it + * will fall back to the standard video mode database. + * + * Note: Function marked as __init and can only be used during + * system boot. + * + * Returns error code from fb_find_mode (see fb_find_mode + * function). + * + */ + +int __init mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, + const char *mode_option, unsigned int default_bpp) +{ + const struct fb_videomode *db = NULL; + unsigned int dbsize = 0; + + if (mode_option && !strncmp(mode_option, "mac", 3)) { + mode_option += 3; + db = mac_modedb; + dbsize = sizeof(mac_modedb)/sizeof(*mac_modedb); + } + return fb_find_mode(var, info, mode_option, db, dbsize, + &mac_modedb[DEFAULT_MODEDB_INDEX], default_bpp); +} +EXPORT_SYMBOL(mac_find_mode); + diff --git a/drivers/video/macmodes.h b/drivers/video/macmodes.h new file mode 100644 index 000000000000..232f5a09a499 --- /dev/null +++ b/drivers/video/macmodes.h @@ -0,0 +1,70 @@ +/* + * linux/drivers/video/macmodes.h -- Standard MacOS video modes + * + * Copyright (C) 1998 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_MACMODES_H +#define _VIDEO_MACMODES_H + + /* + * Video mode values. + * These are supposed to be the same as the values that Apple uses in + * MacOS. + */ + +#define VMODE_NVRAM 0 +#define VMODE_512_384_60I 1 /* 512x384, 60Hz interlaced (NTSC) */ +#define VMODE_512_384_60 2 /* 512x384, 60Hz */ +#define VMODE_640_480_50I 3 /* 640x480, 50Hz interlaced (PAL) */ +#define VMODE_640_480_60I 4 /* 640x480, 60Hz interlaced (NTSC) */ +#define VMODE_640_480_60 5 /* 640x480, 60Hz (VGA) */ +#define VMODE_640_480_67 6 /* 640x480, 67Hz */ +#define VMODE_640_870_75P 7 /* 640x870, 75Hz (portrait) */ +#define VMODE_768_576_50I 8 /* 768x576, 50Hz (PAL full frame) */ +#define VMODE_800_600_56 9 /* 800x600, 56Hz */ +#define VMODE_800_600_60 10 /* 800x600, 60Hz */ +#define VMODE_800_600_72 11 /* 800x600, 72Hz */ +#define VMODE_800_600_75 12 /* 800x600, 75Hz */ +#define VMODE_832_624_75 13 /* 832x624, 75Hz */ +#define VMODE_1024_768_60 14 /* 1024x768, 60Hz */ +#define VMODE_1024_768_70 15 /* 1024x768, 70Hz (or 72Hz?) */ +#define VMODE_1024_768_75V 16 /* 1024x768, 75Hz (VESA) */ +#define VMODE_1024_768_75 17 /* 1024x768, 75Hz */ +#define VMODE_1152_870_75 18 /* 1152x870, 75Hz */ +#define VMODE_1280_960_75 19 /* 1280x960, 75Hz */ +#define VMODE_1280_1024_75 20 /* 1280x1024, 75Hz */ +#define VMODE_1152_768_60 21 /* 1152x768, 60Hz Titanium PowerBook */ +#define VMODE_1600_1024_60 22 /* 1600x1024, 60Hz 22" Cinema Display */ +#define VMODE_MAX 22 +#define VMODE_CHOOSE 99 + +#define CMODE_NVRAM -1 +#define CMODE_CHOOSE -2 +#define CMODE_8 0 /* 8 bits/pixel */ +#define CMODE_16 1 /* 16 (actually 15) bits/pixel */ +#define CMODE_32 2 /* 32 (actually 24) bits/pixel */ + + +extern int mac_vmode_to_var(int vmode, int cmode, + struct fb_var_screeninfo *var); +extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, + int *cmode); +extern int mac_map_monitor_sense(int sense); +extern int __init mac_find_mode(struct fb_var_screeninfo *var, + struct fb_info *info, const char *mode_option, + unsigned int default_bpp); + + + /* + * Addresses in NVRAM where video mode and pixel size are stored. + */ + +#define NV_VMODE 0x140f +#define NV_CMODE 0x1410 + +#endif /* _VIDEO_MACMODES_H */ diff --git a/drivers/video/matrox/Makefile b/drivers/video/matrox/Makefile new file mode 100644 index 000000000000..f9c00ebe2530 --- /dev/null +++ b/drivers/video/matrox/Makefile @@ -0,0 +1,11 @@ +# Makefile for the Linux video drivers. +# 5 Aug 1999, James Simmons, <mailto:jsimmons@edgeglobal.com> +# Rewritten to use lists instead of if-statements. + +# Each configuration option enables a list of files. + +my-obj-$(CONFIG_FB_MATROX_G) += g450_pll.o matroxfb_g450.o matroxfb_crtc2.o + +obj-$(CONFIG_FB_MATROX) += matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o $(my-obj-y) +obj-$(CONFIG_FB_MATROX_I2C) += i2c-matroxfb.o +obj-$(CONFIG_FB_MATROX_MAVEN) += matroxfb_maven.o matroxfb_crtc2.o diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c new file mode 100644 index 000000000000..8073a73f6f35 --- /dev/null +++ b/drivers/video/matrox/g450_pll.c @@ -0,0 +1,479 @@ +/* + * + * Hardware accelerated Matrox PCI cards - G450/G550 PLL control. + * + * (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Portions Copyright (c) 2001 Matrox Graphics Inc. + * + * Version: 1.64 2002/06/10 + * + * 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 "g450_pll.h" +#include "matroxfb_DAC1064.h" + +static inline unsigned int g450_vco2f(unsigned char p, unsigned int fvco) { + return (p & 0x40) ? fvco : fvco >> ((p & 3) + 1); +} + +static inline unsigned int g450_f2vco(unsigned char p, unsigned int fin) { + return (p & 0x40) ? fin : fin << ((p & 3) + 1); +} + +static unsigned int g450_mnp2vco(CPMINFO unsigned int mnp) { + unsigned int m, n; + + m = ((mnp >> 16) & 0x0FF) + 1; + n = ((mnp >> 7) & 0x1FE) + 4; + return (ACCESS_FBINFO(features).pll.ref_freq * n + (m >> 1)) / m; +} + +unsigned int g450_mnp2f(CPMINFO unsigned int mnp) { + return g450_vco2f(mnp, g450_mnp2vco(PMINFO mnp)); +} + +static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) { + if (f2 < f1) { + f2 = f1 - f2; + } else { + f2 = f2 - f1; + } + return f2; +} + +#define NO_MORE_MNP 0x01FFFFFF +#define G450_MNP_FREQBITS (0xFFFFFF43) /* do not mask high byte so we'll catch NO_MORE_MNP */ + +static unsigned int g450_nextpll(CPMINFO const struct matrox_pll_limits* pi, unsigned int* fvco, unsigned int mnp) { + unsigned int m, n, p; + unsigned int tvco = *fvco; + + m = (mnp >> 16) & 0xFF; + p = mnp & 0xFF; + + do { + if (m == 0 || m == 0xFF) { + if (m == 0) { + if (p & 0x40) { + return NO_MORE_MNP; + } + if (p & 3) { + p--; + } else { + p = 0x40; + } + tvco >>= 1; + if (tvco < pi->vcomin) { + return NO_MORE_MNP; + } + *fvco = tvco; + } + + p &= 0x43; + if (tvco < 550000) { +/* p |= 0x00; */ + } else if (tvco < 700000) { + p |= 0x08; + } else if (tvco < 1000000) { + p |= 0x10; + } else if (tvco < 1150000) { + p |= 0x18; + } else { + p |= 0x20; + } + m = 9; + } else { + m--; + } + n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2; + } while (n < 0x03 || n > 0x7A); + return (m << 16) | (n << 8) | p; +} + +static unsigned int g450_firstpll(CPMINFO const struct matrox_pll_limits* pi, unsigned int* vco, unsigned int fout) { + unsigned int p; + unsigned int vcomax; + + vcomax = pi->vcomax; + if (fout > (vcomax / 2)) { + if (fout > vcomax) { + *vco = vcomax; + } else { + *vco = fout; + } + p = 0x40; + } else { + unsigned int tvco; + + p = 3; + tvco = g450_f2vco(p, fout); + while (p && (tvco > vcomax)) { + p--; + tvco >>= 1; + } + if (tvco < pi->vcomin) { + tvco = pi->vcomin; + } + *vco = tvco; + } + return g450_nextpll(PMINFO pi, vco, 0xFF0000 | p); +} + +static inline unsigned int g450_setpll(CPMINFO unsigned int mnp, unsigned int pll) { + switch (pll) { + case M_PIXEL_PLL_A: + matroxfb_DAC_out(PMINFO M1064_XPIXPLLAM, mnp >> 16); + matroxfb_DAC_out(PMINFO M1064_XPIXPLLAN, mnp >> 8); + matroxfb_DAC_out(PMINFO M1064_XPIXPLLAP, mnp); + return M1064_XPIXPLLSTAT; + + case M_PIXEL_PLL_B: + matroxfb_DAC_out(PMINFO M1064_XPIXPLLBM, mnp >> 16); + matroxfb_DAC_out(PMINFO M1064_XPIXPLLBN, mnp >> 8); + matroxfb_DAC_out(PMINFO M1064_XPIXPLLBP, mnp); + return M1064_XPIXPLLSTAT; + + case M_PIXEL_PLL_C: + matroxfb_DAC_out(PMINFO M1064_XPIXPLLCM, mnp >> 16); + matroxfb_DAC_out(PMINFO M1064_XPIXPLLCN, mnp >> 8); + matroxfb_DAC_out(PMINFO M1064_XPIXPLLCP, mnp); + return M1064_XPIXPLLSTAT; + + case M_SYSTEM_PLL: + matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLM, mnp >> 16); + matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLN, mnp >> 8); + matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLP, mnp); + return DAC1064_XSYSPLLSTAT; + + case M_VIDEO_PLL: + matroxfb_DAC_out(PMINFO M1064_XVIDPLLM, mnp >> 16); + matroxfb_DAC_out(PMINFO M1064_XVIDPLLN, mnp >> 8); + matroxfb_DAC_out(PMINFO M1064_XVIDPLLP, mnp); + return M1064_XVIDPLLSTAT; + } + return 0; +} + +static inline unsigned int g450_cmppll(CPMINFO unsigned int mnp, unsigned int pll) { + unsigned char m = mnp >> 16; + unsigned char n = mnp >> 8; + unsigned char p = mnp; + + switch (pll) { + case M_PIXEL_PLL_A: + return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLAM) != m || + matroxfb_DAC_in(PMINFO M1064_XPIXPLLAN) != n || + matroxfb_DAC_in(PMINFO M1064_XPIXPLLAP) != p); + + case M_PIXEL_PLL_B: + return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLBM) != m || + matroxfb_DAC_in(PMINFO M1064_XPIXPLLBN) != n || + matroxfb_DAC_in(PMINFO M1064_XPIXPLLBP) != p); + + case M_PIXEL_PLL_C: + return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLCM) != m || + matroxfb_DAC_in(PMINFO M1064_XPIXPLLCN) != n || + matroxfb_DAC_in(PMINFO M1064_XPIXPLLCP) != p); + + case M_SYSTEM_PLL: + return (matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLM) != m || + matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLN) != n || + matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLP) != p); + + case M_VIDEO_PLL: + return (matroxfb_DAC_in(PMINFO M1064_XVIDPLLM) != m || + matroxfb_DAC_in(PMINFO M1064_XVIDPLLN) != n || + matroxfb_DAC_in(PMINFO M1064_XVIDPLLP) != p); + } + return 1; +} + +static inline int g450_isplllocked(CPMINFO unsigned int regidx) { + unsigned int j; + + for (j = 0; j < 1000; j++) { + if (matroxfb_DAC_in(PMINFO regidx) & 0x40) { + unsigned int r = 0; + int i; + + for (i = 0; i < 100; i++) { + r += matroxfb_DAC_in(PMINFO regidx) & 0x40; + } + return r >= (90 * 0x40); + } + /* udelay(1)... but DAC_in is much slower... */ + } + return 0; +} + +static int g450_testpll(CPMINFO unsigned int mnp, unsigned int pll) { + return g450_isplllocked(PMINFO g450_setpll(PMINFO mnp, pll)); +} + +static void updatehwstate_clk(struct matrox_hw_state* hw, unsigned int mnp, unsigned int pll) { + switch (pll) { + case M_SYSTEM_PLL: + hw->DACclk[3] = mnp >> 16; + hw->DACclk[4] = mnp >> 8; + hw->DACclk[5] = mnp; + break; + } +} + +void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) { + if (g450_cmppll(PMINFO mnp, pll)) { + g450_setpll(PMINFO mnp, pll); + } +} + +static inline unsigned int g450_findworkingpll(WPMINFO unsigned int pll, unsigned int* mnparray, unsigned int mnpcount) { + unsigned int found = 0; + unsigned int idx; + unsigned int mnpfound = mnparray[0]; + + for (idx = 0; idx < mnpcount; idx++) { + unsigned int sarray[3]; + unsigned int *sptr; + { + unsigned int mnp; + + sptr = sarray; + mnp = mnparray[idx]; + if (mnp & 0x38) { + *sptr++ = mnp - 8; + } + if ((mnp & 0x38) != 0x38) { + *sptr++ = mnp + 8; + } + *sptr = mnp; + } + while (sptr >= sarray) { + unsigned int mnp = *sptr--; + + if (g450_testpll(PMINFO mnp - 0x0300, pll) && + g450_testpll(PMINFO mnp + 0x0300, pll) && + g450_testpll(PMINFO mnp - 0x0200, pll) && + g450_testpll(PMINFO mnp + 0x0200, pll) && + g450_testpll(PMINFO mnp - 0x0100, pll) && + g450_testpll(PMINFO mnp + 0x0100, pll)) { + if (g450_testpll(PMINFO mnp, pll)) { + return mnp; + } + } else if (!found && g450_testpll(PMINFO mnp, pll)) { + mnpfound = mnp; + found = 1; + } + } + } + g450_setpll(PMINFO mnpfound, pll); + return mnpfound; +} + +static void g450_addcache(struct matrox_pll_cache* ci, unsigned int mnp_key, unsigned int mnp_value) { + if (++ci->valid > ARRAY_SIZE(ci->data)) { + ci->valid = ARRAY_SIZE(ci->data); + } + memmove(ci->data + 1, ci->data, (ci->valid - 1) * sizeof(*ci->data)); + ci->data[0].mnp_key = mnp_key & G450_MNP_FREQBITS; + ci->data[0].mnp_value = mnp_value; +} + +static int g450_checkcache(WPMINFO struct matrox_pll_cache* ci, unsigned int mnp_key) { + unsigned int i; + + mnp_key &= G450_MNP_FREQBITS; + for (i = 0; i < ci->valid; i++) { + if (ci->data[i].mnp_key == mnp_key) { + unsigned int mnp; + + mnp = ci->data[i].mnp_value; + if (i) { + memmove(ci->data + 1, ci->data, i * sizeof(*ci->data)); + ci->data[0].mnp_key = mnp_key; + ci->data[0].mnp_value = mnp; + } + return mnp; + } + } + return NO_MORE_MNP; +} + +static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll, + unsigned int* mnparray, unsigned int* deltaarray) { + unsigned int mnpcount; + unsigned int pixel_vco; + const struct matrox_pll_limits* pi; + struct matrox_pll_cache* ci; + + pixel_vco = 0; + switch (pll) { + case M_PIXEL_PLL_A: + case M_PIXEL_PLL_B: + case M_PIXEL_PLL_C: + { + u_int8_t tmp; + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); + tmp = matroxfb_DAC_in(PMINFO M1064_XPIXCLKCTRL); + if (!(tmp & M1064_XPIXCLKCTRL_PLL_UP)) { + matroxfb_DAC_out(PMINFO M1064_XPIXCLKCTRL, tmp | M1064_XPIXCLKCTRL_PLL_UP); + } + matroxfb_DAC_unlock_irqrestore(flags); + } + { + u_int8_t misc; + + misc = mga_inb(M_MISC_REG_READ) & ~0x0C; + switch (pll) { + case M_PIXEL_PLL_A: + break; + case M_PIXEL_PLL_B: + misc |= 0x04; + break; + default: + misc |= 0x0C; + break; + } + mga_outb(M_MISC_REG, misc); + } + pi = &ACCESS_FBINFO(limits.pixel); + ci = &ACCESS_FBINFO(cache.pixel); + break; + case M_SYSTEM_PLL: + { + u_int32_t opt; + + pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &opt); + if (!(opt & 0x20)) { + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, opt | 0x20); + } + } + pi = &ACCESS_FBINFO(limits.system); + ci = &ACCESS_FBINFO(cache.system); + break; + case M_VIDEO_PLL: + { + u_int8_t tmp; + unsigned int mnp; + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); + tmp = matroxfb_DAC_in(PMINFO M1064_XPWRCTRL); + if (!(tmp & 2)) { + matroxfb_DAC_out(PMINFO M1064_XPWRCTRL, tmp | 2); + } + + mnp = matroxfb_DAC_in(PMINFO M1064_XPIXPLLCM) << 16; + mnp |= matroxfb_DAC_in(PMINFO M1064_XPIXPLLCN) << 8; + pixel_vco = g450_mnp2vco(PMINFO mnp); + matroxfb_DAC_unlock_irqrestore(flags); + } + pi = &ACCESS_FBINFO(limits.video); + ci = &ACCESS_FBINFO(cache.video); + break; + default: + return -EINVAL; + } + + mnpcount = 0; + { + unsigned int mnp; + unsigned int xvco; + + for(mnp = g450_firstpll(PMINFO pi, &xvco, fout); mnp != NO_MORE_MNP; mnp = g450_nextpll(PMINFO pi, &xvco, mnp)) { + unsigned int idx; + unsigned int vco; + unsigned int delta; + + vco = g450_mnp2vco(PMINFO mnp); +#if 0 + if (pll == M_VIDEO_PLL) { + unsigned int big, small; + + if (vco < pixel_vco) { + small = vco; + big = pixel_vco; + } else { + small = pixel_vco; + big = vco; + } + while (big > small) { + big >>= 1; + } + if (big == small) { + continue; + } + } +#endif + delta = pll_freq_delta(fout, g450_vco2f(mnp, vco)); + for (idx = mnpcount; idx > 0; idx--) { + /* == is important; due to nextpll algorithm we get + sorted equally good frequencies from lower VCO + frequency to higher - with <= lowest wins, while + with < highest one wins */ + if (delta <= deltaarray[idx-1]) { + mnparray[idx] = mnparray[idx-1]; + deltaarray[idx] = deltaarray[idx-1]; + } else { + break; + } + } + mnparray[idx] = mnp; + deltaarray[idx] = delta; + mnpcount++; + } + } + /* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */ + if (!mnpcount) { + return -EBUSY; + } + { + unsigned long flags; + unsigned int mnp; + + matroxfb_DAC_lock_irqsave(flags); + mnp = g450_checkcache(PMINFO ci, mnparray[0]); + if (mnp != NO_MORE_MNP) { + matroxfb_g450_setpll_cond(PMINFO mnp, pll); + } else { + mnp = g450_findworkingpll(PMINFO pll, mnparray, mnpcount); + g450_addcache(ci, mnparray[0], mnp); + } + updatehwstate_clk(&ACCESS_FBINFO(hw), mnp, pll); + matroxfb_DAC_unlock_irqrestore(flags); + return mnp; + } +} + +/* It must be greater than number of possible PLL values. + * Currently there is 5(p) * 10(m) = 50 possible values. */ +#define MNP_TABLE_SIZE 64 + +int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll) { + unsigned int* arr; + + arr = kmalloc(sizeof(*arr) * MNP_TABLE_SIZE * 2, GFP_KERNEL); + if (arr) { + int r; + + r = __g450_setclk(PMINFO fout, pll, arr, arr + MNP_TABLE_SIZE); + kfree(arr); + return r; + } + return -ENOMEM; +} + +EXPORT_SYMBOL(matroxfb_g450_setclk); +EXPORT_SYMBOL(g450_mnp2f); +EXPORT_SYMBOL(matroxfb_g450_setpll_cond); + +MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Matrox G450/G550 PLL driver"); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/matrox/g450_pll.h b/drivers/video/matrox/g450_pll.h new file mode 100644 index 000000000000..c17ed74501e9 --- /dev/null +++ b/drivers/video/matrox/g450_pll.h @@ -0,0 +1,10 @@ +#ifndef __G450_PLL_H__ +#define __G450_PLL_H__ + +#include "matroxfb_base.h" + +int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll); +unsigned int g450_mnp2f(CPMINFO unsigned int mnp); +void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll); + +#endif /* __G450_PLL_H__ */ diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c new file mode 100644 index 000000000000..57abbae5520f --- /dev/null +++ b/drivers/video/matrox/i2c-matroxfb.c @@ -0,0 +1,223 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. + * + * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Version: 1.64 2002/06/10 + * + * See matroxfb_base.c for contributors. + * + */ + +#include "matroxfb_base.h" +#include "matroxfb_maven.h" +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +/* MGA-TVO I2C for G200, G400 */ +#define MAT_CLK 0x20 +#define MAT_DATA 0x10 +/* primary head DDC for Mystique(?), G100, G200, G400 */ +#define DDC1_CLK 0x08 +#define DDC1_DATA 0x02 +/* primary head DDC for Millennium, Millennium II */ +#define DDC1B_CLK 0x10 +#define DDC1B_DATA 0x04 +/* secondary head DDC for G400 */ +#define DDC2_CLK 0x04 +#define DDC2_DATA 0x01 + +/******************************************************/ + +struct matroxfb_dh_maven_info { + struct i2c_bit_adapter maven; + struct i2c_bit_adapter ddc1; + struct i2c_bit_adapter ddc2; +}; + +static int matroxfb_read_gpio(struct matrox_fb_info* minfo) { + unsigned long flags; + int v; + + matroxfb_DAC_lock_irqsave(flags); + v = matroxfb_DAC_in(PMINFO DAC_XGENIODATA); + matroxfb_DAC_unlock_irqrestore(flags); + return v; +} + +static void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) { + unsigned long flags; + int v; + + matroxfb_DAC_lock_irqsave(flags); + v = (matroxfb_DAC_in(PMINFO DAC_XGENIOCTRL) & mask) | val; + matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, v); + /* We must reset GENIODATA very often... XFree plays with this register */ + matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0x00); + matroxfb_DAC_unlock_irqrestore(flags); +} + +/* software I2C functions */ +static inline void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) { + if (state) + state = 0; + else + state = mask; + matroxfb_set_gpio(minfo, ~mask, state); +} + +static void matroxfb_gpio_setsda(void* data, int state) { + struct i2c_bit_adapter* b = data; + matroxfb_i2c_set(b->minfo, b->mask.data, state); +} + +static void matroxfb_gpio_setscl(void* data, int state) { + struct i2c_bit_adapter* b = data; + matroxfb_i2c_set(b->minfo, b->mask.clock, state); +} + +static int matroxfb_gpio_getsda(void* data) { + struct i2c_bit_adapter* b = data; + return (matroxfb_read_gpio(b->minfo) & b->mask.data) ? 1 : 0; +} + +static int matroxfb_gpio_getscl(void* data) { + struct i2c_bit_adapter* b = data; + return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0; +} + +static struct i2c_adapter matrox_i2c_adapter_template = +{ + .owner = THIS_MODULE, + .id = I2C_HW_B_G400, +}; + +static struct i2c_algo_bit_data matrox_i2c_algo_template = +{ + NULL, + matroxfb_gpio_setsda, + matroxfb_gpio_setscl, + matroxfb_gpio_getsda, + matroxfb_gpio_getscl, + 10, 10, 100, +}; + +static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, + unsigned int data, unsigned int clock, const char* name) { + int err; + + b->minfo = minfo; + b->mask.data = data; + b->mask.clock = clock; + b->adapter = matrox_i2c_adapter_template; + snprintf(b->adapter.name, I2C_NAME_SIZE, name, + minfo->fbcon.node); + i2c_set_adapdata(&b->adapter, b); + b->adapter.algo_data = &b->bac; + b->bac = matrox_i2c_algo_template; + b->bac.data = b; + err = i2c_bit_add_bus(&b->adapter); + b->initialized = !err; + return err; +} + +static void i2c_bit_bus_del(struct i2c_bit_adapter* b) { + if (b->initialized) { + i2c_bit_del_bus(&b->adapter); + b->initialized = 0; + } +} + +static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) { + i2c_bit_bus_del(&minfo2->maven); +} + +static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) { + i2c_bit_bus_del(&minfo2->ddc1); +} + +static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) { + i2c_bit_bus_del(&minfo2->ddc2); +} + +static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) { + int err; + unsigned long flags; + struct matroxfb_dh_maven_info* m2info; + + m2info = (struct matroxfb_dh_maven_info*)kmalloc(sizeof(*m2info), GFP_KERNEL); + if (!m2info) + return NULL; + + matroxfb_DAC_lock_irqsave(flags); + matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0xFF); + matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, 0x00); + matroxfb_DAC_unlock_irqrestore(flags); + + memset(m2info, 0, sizeof(*m2info)); + + switch (ACCESS_FBINFO(chip)) { + case MGA_2064: + case MGA_2164: + err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1B_DATA, DDC1B_CLK, "DDC:fb%u #0"); + break; + default: + err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1_DATA, DDC1_CLK, "DDC:fb%u #0"); + break; + } + if (err) + goto fail_ddc1; + if (ACCESS_FBINFO(devflags.dualhead)) { + err = i2c_bus_reg(&m2info->ddc2, minfo, DDC2_DATA, DDC2_CLK, "DDC:fb%u #1"); + if (err == -ENODEV) { + printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n"); + } else if (err) + printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n"); + /* Register maven bus even on G450/G550 */ + err = i2c_bus_reg(&m2info->maven, minfo, MAT_DATA, MAT_CLK, "MAVEN:fb%u"); + if (err) + printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n"); + } + return m2info; +fail_ddc1:; + kfree(m2info); + printk(KERN_ERR "i2c-matroxfb: Could not register primary adapter DDC bus.\n"); + return NULL; +} + +static void i2c_matroxfb_remove(struct matrox_fb_info* minfo, void* data) { + struct matroxfb_dh_maven_info* m2info = data; + + i2c_maven_done(m2info); + i2c_ddc2_done(m2info); + i2c_ddc1_done(m2info); + kfree(m2info); +} + +static struct matroxfb_driver i2c_matroxfb = { + .node = LIST_HEAD_INIT(i2c_matroxfb.node), + .name = "i2c-matroxfb", + .probe = i2c_matroxfb_probe, + .remove = i2c_matroxfb_remove, +}; + +static int __init i2c_matroxfb_init(void) { + if (matroxfb_register_driver(&i2c_matroxfb)) { + printk(KERN_ERR "i2c-matroxfb: failed to register driver\n"); + return -ENXIO; + } + return 0; +} + +static void __exit i2c_matroxfb_exit(void) { + matroxfb_unregister_driver(&i2c_matroxfb); +} + +MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards"); + +module_init(i2c_matroxfb_init); +module_exit(i2c_matroxfb_exit); +/* no __setup required */ +MODULE_LICENSE("GPL"); diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c new file mode 100644 index 000000000000..149680f8bcf0 --- /dev/null +++ b/drivers/video/matrox/matroxfb_DAC1064.c @@ -0,0 +1,1086 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. + * + * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Portions Copyright (c) 2001 Matrox Graphics Inc. + * + * Version: 1.65 2002/08/14 + * + * See matroxfb_base.c for contributors. + * + */ + +/* make checkconfig does not walk through include tree :-( */ +#include <linux/config.h> + +#include "matroxfb_DAC1064.h" +#include "matroxfb_misc.h" +#include "matroxfb_accel.h" +#include "g450_pll.h" +#include <linux/matroxfb.h> + +#ifdef NEED_DAC1064 +#define outDAC1064 matroxfb_DAC_out +#define inDAC1064 matroxfb_DAC_in + +#define DAC1064_OPT_SCLK_PCI 0x00 +#define DAC1064_OPT_SCLK_PLL 0x01 +#define DAC1064_OPT_SCLK_EXT 0x02 +#define DAC1064_OPT_SCLK_MASK 0x03 +#define DAC1064_OPT_GDIV1 0x04 /* maybe it is GDIV2 on G100 ?! */ +#define DAC1064_OPT_GDIV3 0x00 +#define DAC1064_OPT_MDIV1 0x08 +#define DAC1064_OPT_MDIV2 0x00 +#define DAC1064_OPT_RESERVED 0x10 + +static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) { + unsigned int fvco; + unsigned int p; + + DBG(__FUNCTION__) + + /* only for devices older than G450 */ + + fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p); + + p = (1 << p) - 1; + if (fvco <= 100000) + ; + else if (fvco <= 140000) + p |= 0x08; + else if (fvco <= 180000) + p |= 0x10; + else + p |= 0x18; + *post = p; +} + +/* they must be in POS order */ +static const unsigned char MGA1064_DAC_regs[] = { + M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL, + M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE, + M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE, + M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE, + DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL, + M1064_XMISCCTRL, + M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST, + M1064_XCRCBITSEL, + M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH }; + +static const unsigned char MGA1064_DAC[] = { + 0x00, 0x00, M1064_XCURCTRL_DIS, + 0x00, 0x00, 0x00, /* black */ + 0xFF, 0xFF, 0xFF, /* white */ + 0xFF, 0x00, 0x00, /* red */ + 0x00, 0, + M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL, + M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN, + M1064_XMISCCTRL_DAC_8BIT, + 0x00, 0x00, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN, + 0x00, + 0x00, 0x00, 0xFF, 0xFF}; + +static void DAC1064_setpclk(WPMINFO unsigned long fout) { + unsigned int m, n, p; + + DBG(__FUNCTION__) + + DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); + ACCESS_FBINFO(hw).DACclk[0] = m; + ACCESS_FBINFO(hw).DACclk[1] = n; + ACCESS_FBINFO(hw).DACclk[2] = p; +} + +static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) { + u_int32_t mx; + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + DBG(__FUNCTION__) + + if (ACCESS_FBINFO(devflags.noinit)) { + /* read MCLK and give up... */ + hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM); + hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN); + hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP); + return; + } + mx = hw->MXoptionReg | 0x00000004; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + mx &= ~0x000000BB; + if (oscinfo & DAC1064_OPT_GDIV1) + mx |= 0x00000008; + if (oscinfo & DAC1064_OPT_MDIV1) + mx |= 0x00000010; + if (oscinfo & DAC1064_OPT_RESERVED) + mx |= 0x00000080; + if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) { + /* select PCI clock until we have setup oscilator... */ + int clk; + unsigned int m, n, p; + + /* powerup system PLL, select PCI clock */ + mx |= 0x00000020; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + mx &= ~0x00000004; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + + /* !!! you must not access device if MCLK is not running !!! + Doing so cause immediate PCI lockup :-( Maybe they should + generate ABORT or I/O (parity...) error and Linux should + recover from this... (kill driver/process). But world is not + perfect... */ + /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not + select PLL... because of PLL can be stopped at this time) */ + DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); + outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m); + outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n); + outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p); + for (clk = 65536; clk; --clk) { + if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40) + break; + } + if (!clk) + printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n"); + /* select PLL */ + mx |= 0x00000005; + } else { + /* select specified system clock source */ + mx |= oscinfo & DAC1064_OPT_SCLK_MASK; + } + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + mx &= ~0x00000004; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + hw->MXoptionReg = mx; +} + +#ifdef CONFIG_FB_MATROX_G +static void g450_set_plls(WPMINFO2) { + u_int32_t c2_ctl; + unsigned int pxc; + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + int pixelmnp; + int videomnp; + + c2_ctl = hw->crtc2.ctl & ~0x4007; /* Clear PLL + enable for CRTC2 */ + c2_ctl |= 0x0001; /* Enable CRTC2 */ + hw->DACreg[POS1064_XPWRCTRL] &= ~0x02; /* Stop VIDEO PLL */ + pixelmnp = ACCESS_FBINFO(crtc1).mnp; + videomnp = ACCESS_FBINFO(crtc2).mnp; + if (videomnp < 0) { + c2_ctl &= ~0x0001; /* Disable CRTC2 */ + hw->DACreg[POS1064_XPWRCTRL] &= ~0x10; /* Powerdown CRTC2 */ + } else if (ACCESS_FBINFO(crtc2).pixclock == ACCESS_FBINFO(features).pll.ref_freq) { + c2_ctl |= 0x4002; /* Use reference directly */ + } else if (videomnp == pixelmnp) { + c2_ctl |= 0x0004; /* Use pixel PLL */ + } else { + if (0 == ((videomnp ^ pixelmnp) & 0xFFFFFF00)) { + /* PIXEL and VIDEO PLL must not use same frequency. We modify N + of PIXEL PLL in such case because of VIDEO PLL may be source + of TVO clocks, and chroma subcarrier is derived from its + pixel clocks */ + pixelmnp += 0x000100; + } + c2_ctl |= 0x0006; /* Use video PLL */ + hw->DACreg[POS1064_XPWRCTRL] |= 0x02; + + outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]); + matroxfb_g450_setpll_cond(PMINFO videomnp, M_VIDEO_PLL); + } + + hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP; + if (pixelmnp >= 0) { + hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP; + + outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]); + matroxfb_g450_setpll_cond(PMINFO pixelmnp, M_PIXEL_PLL_C); + } + if (c2_ctl != hw->crtc2.ctl) { + hw->crtc2.ctl = c2_ctl; + mga_outl(0x3C10, c2_ctl); + } + + pxc = ACCESS_FBINFO(crtc1).pixclock; + if (pxc == 0 || ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC2) { + pxc = ACCESS_FBINFO(crtc2).pixclock; + } + if (ACCESS_FBINFO(chip) == MGA_G550) { + if (pxc < 45000) { + hw->DACreg[POS1064_XPANMODE] = 0x00; /* 0-50 */ + } else if (pxc < 55000) { + hw->DACreg[POS1064_XPANMODE] = 0x08; /* 34-62 */ + } else if (pxc < 70000) { + hw->DACreg[POS1064_XPANMODE] = 0x10; /* 42-78 */ + } else if (pxc < 85000) { + hw->DACreg[POS1064_XPANMODE] = 0x18; /* 62-92 */ + } else if (pxc < 100000) { + hw->DACreg[POS1064_XPANMODE] = 0x20; /* 74-108 */ + } else if (pxc < 115000) { + hw->DACreg[POS1064_XPANMODE] = 0x28; /* 94-122 */ + } else if (pxc < 125000) { + hw->DACreg[POS1064_XPANMODE] = 0x30; /* 108-132 */ + } else { + hw->DACreg[POS1064_XPANMODE] = 0x38; /* 120-168 */ + } + } else { + /* G450 */ + if (pxc < 45000) { + hw->DACreg[POS1064_XPANMODE] = 0x00; /* 0-54 */ + } else if (pxc < 65000) { + hw->DACreg[POS1064_XPANMODE] = 0x08; /* 38-70 */ + } else if (pxc < 85000) { + hw->DACreg[POS1064_XPANMODE] = 0x10; /* 56-96 */ + } else if (pxc < 105000) { + hw->DACreg[POS1064_XPANMODE] = 0x18; /* 80-114 */ + } else if (pxc < 135000) { + hw->DACreg[POS1064_XPANMODE] = 0x20; /* 102-144 */ + } else if (pxc < 160000) { + hw->DACreg[POS1064_XPANMODE] = 0x28; /* 132-166 */ + } else if (pxc < 175000) { + hw->DACreg[POS1064_XPANMODE] = 0x30; /* 154-182 */ + } else { + hw->DACreg[POS1064_XPANMODE] = 0x38; /* 170-204 */ + } + } +} +#endif + +void DAC1064_global_init(WPMINFO2) { + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK; + hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN; + hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL; +#ifdef CONFIG_FB_MATROX_G + if (ACCESS_FBINFO(devflags.g450dac)) { + hw->DACreg[POS1064_XPWRCTRL] = 0x1F; /* powerup everything */ + hw->DACreg[POS1064_XOUTPUTCONN] = 0x00; /* disable outputs */ + hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN; + switch (ACCESS_FBINFO(outputs[0]).src) { + case MATROXFB_SRC_CRTC1: + case MATROXFB_SRC_CRTC2: + hw->DACreg[POS1064_XOUTPUTCONN] |= 0x01; /* enable output; CRTC1/2 selection is in CRTC2 ctl */ + break; + case MATROXFB_SRC_NONE: + hw->DACreg[POS1064_XMISCCTRL] &= ~M1064_XMISCCTRL_DAC_EN; + break; + } + switch (ACCESS_FBINFO(outputs[1]).src) { + case MATROXFB_SRC_CRTC1: + hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04; + break; + case MATROXFB_SRC_CRTC2: + if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_MONITOR) { + hw->DACreg[POS1064_XOUTPUTCONN] |= 0x08; + } else { + hw->DACreg[POS1064_XOUTPUTCONN] |= 0x0C; + } + break; + case MATROXFB_SRC_NONE: + hw->DACreg[POS1064_XPWRCTRL] &= ~0x01; /* Poweroff DAC2 */ + break; + } + switch (ACCESS_FBINFO(outputs[2]).src) { + case MATROXFB_SRC_CRTC1: + hw->DACreg[POS1064_XOUTPUTCONN] |= 0x20; + break; + case MATROXFB_SRC_CRTC2: + hw->DACreg[POS1064_XOUTPUTCONN] |= 0x40; + break; + case MATROXFB_SRC_NONE: +#if 0 + /* HELP! If we boot without DFP connected to DVI, we can + poweroff TMDS. But if we boot with DFP connected, + TMDS generated clocks are used instead of ALL pixclocks + available... If someone knows which register + handles it, please reveal this secret to me... */ + hw->DACreg[POS1064_XPWRCTRL] &= ~0x04; /* Poweroff TMDS */ +#endif + break; + } + /* Now set timming related variables... */ + g450_set_plls(PMINFO2); + } else +#endif + { + if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) { + hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT; + hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12; + } else if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) { + hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12; + } else if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) + hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12; + else + hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS; + + if (ACCESS_FBINFO(outputs[0]).src != MATROXFB_SRC_NONE) + hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN; + } +} + +void DAC1064_global_restore(WPMINFO2) { + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]); + outDAC1064(PMINFO M1064_XMISCCTRL, hw->DACreg[POS1064_XMISCCTRL]); + if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) { + outDAC1064(PMINFO 0x20, 0x04); + outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type)); + if (ACCESS_FBINFO(devflags.g450dac)) { + outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC); + outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]); + outDAC1064(PMINFO M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]); + outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]); + } + } +} + +static int DAC1064_init_1(WPMINFO struct my_timming* m) { + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + DBG(__FUNCTION__) + + memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs)); + switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { + /* case 4: not supported by MGA1064 DAC */ + case 8: + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + break; + case 16: + if (ACCESS_FBINFO(fbcon).var.green.length == 5) + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + else + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + break; + case 24: + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + break; + case 32: + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + break; + default: + return 1; /* unsupported depth */ + } + hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl); + hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK; + hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN; + hw->DACreg[POS1064_XCURADDL] = 0; + hw->DACreg[POS1064_XCURADDH] = 0; + + DAC1064_global_init(PMINFO2); + return 0; +} + +static int DAC1064_init_2(WPMINFO struct my_timming* m) { + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + DBG(__FUNCTION__) + + if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 16) { /* 256 entries */ + int i; + + for (i = 0; i < 256; i++) { + hw->DACpal[i * 3 + 0] = i; + hw->DACpal[i * 3 + 1] = i; + hw->DACpal[i * 3 + 2] = i; + } + } else if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 8) { + if (ACCESS_FBINFO(fbcon).var.green.length == 5) { /* 0..31, 128..159 */ + int i; + + for (i = 0; i < 32; i++) { + /* with p15 == 0 */ + hw->DACpal[i * 3 + 0] = i << 3; + hw->DACpal[i * 3 + 1] = i << 3; + hw->DACpal[i * 3 + 2] = i << 3; + /* with p15 == 1 */ + hw->DACpal[(i + 128) * 3 + 0] = i << 3; + hw->DACpal[(i + 128) * 3 + 1] = i << 3; + hw->DACpal[(i + 128) * 3 + 2] = i << 3; + } + } else { + int i; + + for (i = 0; i < 64; i++) { /* 0..63 */ + hw->DACpal[i * 3 + 0] = i << 3; + hw->DACpal[i * 3 + 1] = i << 2; + hw->DACpal[i * 3 + 2] = i << 3; + } + } + } else { + memset(hw->DACpal, 0, 768); + } + return 0; +} + +static void DAC1064_restore_1(WPMINFO2) { + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + CRITFLAGS + + DBG(__FUNCTION__) + + CRITBEGIN + + if ((inDAC1064(PMINFO DAC1064_XSYSPLLM) != hw->DACclk[3]) || + (inDAC1064(PMINFO DAC1064_XSYSPLLN) != hw->DACclk[4]) || + (inDAC1064(PMINFO DAC1064_XSYSPLLP) != hw->DACclk[5])) { + outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]); + outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]); + outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]); + } + { + unsigned int i; + + for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { + if ((i != POS1064_XPIXCLKCTRL) && (i != POS1064_XMISCCTRL)) + outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]); + } + } + + DAC1064_global_restore(PMINFO2); + + CRITEND +}; + +static void DAC1064_restore_2(WPMINFO2) { +#ifdef DEBUG + unsigned int i; +#endif + + DBG(__FUNCTION__) + +#ifdef DEBUG + dprintk(KERN_DEBUG "DAC1064regs "); + for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { + dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], ACCESS_FBINFO(hw).DACreg[i]); + if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... "); + } + dprintk("\n" KERN_DEBUG "DAC1064clk "); + for (i = 0; i < 6; i++) + dprintk("C%02X=%02X ", i, ACCESS_FBINFO(hw).DACclk[i]); + dprintk("\n"); +#endif +} + +static int m1064_compute(void* out, struct my_timming* m) { +#define minfo ((struct matrox_fb_info*)out) + { + int i; + int tmout; + CRITFLAGS + + DAC1064_setpclk(PMINFO m->pixclock); + + CRITBEGIN + + for (i = 0; i < 3; i++) + outDAC1064(PMINFO M1064_XPIXPLLCM + i, ACCESS_FBINFO(hw).DACclk[i]); + for (tmout = 500000; tmout; tmout--) { + if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40) + break; + udelay(10); + }; + + CRITEND + + if (!tmout) + printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); + } +#undef minfo + return 0; +} + +static struct matrox_altout m1064 = { + .name = "Primary output", + .compute = m1064_compute, +}; + +#ifdef CONFIG_FB_MATROX_G +static int g450_compute(void* out, struct my_timming* m) { +#define minfo ((struct matrox_fb_info*)out) + if (m->mnp < 0) { + m->mnp = matroxfb_g450_setclk(PMINFO m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL); + if (m->mnp >= 0) { + m->pixclock = g450_mnp2f(PMINFO m->mnp); + } + } +#undef minfo + return 0; +} + +static struct matrox_altout g450out = { + .name = "Primary output", + .compute = g450_compute, +}; +#endif + +#endif /* NEED_DAC1064 */ + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static int MGA1064_init(WPMINFO struct my_timming* m) { + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + DBG(__FUNCTION__) + + if (DAC1064_init_1(PMINFO m)) return 1; + if (matroxfb_vgaHWinit(PMINFO m)) return 1; + + hw->MiscOutReg = 0xCB; + if (m->sync & FB_SYNC_HOR_HIGH_ACT) + hw->MiscOutReg &= ~0x40; + if (m->sync & FB_SYNC_VERT_HIGH_ACT) + hw->MiscOutReg &= ~0x80; + if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */ + hw->CRTCEXT[3] |= 0x40; + + if (DAC1064_init_2(PMINFO m)) return 1; + return 0; +} +#endif + +#ifdef CONFIG_FB_MATROX_G +static int MGAG100_init(WPMINFO struct my_timming* m) { + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + DBG(__FUNCTION__) + + if (DAC1064_init_1(PMINFO m)) return 1; + hw->MXoptionReg &= ~0x2000; + if (matroxfb_vgaHWinit(PMINFO m)) return 1; + + hw->MiscOutReg = 0xEF; + if (m->sync & FB_SYNC_HOR_HIGH_ACT) + hw->MiscOutReg &= ~0x40; + if (m->sync & FB_SYNC_VERT_HIGH_ACT) + hw->MiscOutReg &= ~0x80; + if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */ + hw->CRTCEXT[3] |= 0x40; + + if (DAC1064_init_2(PMINFO m)) return 1; + return 0; +} +#endif /* G */ + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static void MGA1064_ramdac_init(WPMINFO2) { + + DBG(__FUNCTION__) + + /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */ + ACCESS_FBINFO(features.pll.vco_freq_min) = 62000; + ACCESS_FBINFO(features.pll.ref_freq) = 14318; + ACCESS_FBINFO(features.pll.feed_div_min) = 100; + ACCESS_FBINFO(features.pll.feed_div_max) = 127; + ACCESS_FBINFO(features.pll.in_div_min) = 1; + ACCESS_FBINFO(features.pll.in_div_max) = 31; + ACCESS_FBINFO(features.pll.post_shift_max) = 3; + ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL; + /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */ + DAC1064_setmclk(PMINFO DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333); +} +#endif + +#ifdef CONFIG_FB_MATROX_G +/* BIOS environ */ +static int x7AF4 = 0x10; /* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */ + /* G100 wants 0x10, G200 SGRAM does not care... */ +#if 0 +static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */ +#endif + +static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) { + int reg; + int selClk; + int clk; + + DBG(__FUNCTION__) + + outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS | + M1064_XPIXCLKCTRL_PLL_UP); + switch (flags & 3) { + case 0: reg = M1064_XPIXPLLAM; break; + case 1: reg = M1064_XPIXPLLBM; break; + default: reg = M1064_XPIXPLLCM; break; + } + outDAC1064(PMINFO reg++, m); + outDAC1064(PMINFO reg++, n); + outDAC1064(PMINFO reg, p); + selClk = mga_inb(M_MISC_REG_READ) & ~0xC; + /* there should be flags & 0x03 & case 0/1/else */ + /* and we should first select source and after that we should wait for PLL */ + /* and we are waiting for PLL with oscilator disabled... Is it right? */ + switch (flags & 0x03) { + case 0x00: break; + case 0x01: selClk |= 4; break; + default: selClk |= 0x0C; break; + } + mga_outb(M_MISC_REG, selClk); + for (clk = 500000; clk; clk--) { + if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40) + break; + udelay(10); + }; + if (!clk) + printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A'); + selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK; + switch (flags & 0x0C) { + case 0x00: selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break; + case 0x04: selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break; + default: selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break; + } + outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk); + outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS); +} + +static void MGAG100_setPixClock(CPMINFO int flags, int freq) { + unsigned int m, n, p; + + DBG(__FUNCTION__) + + DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); + MGAG100_progPixClock(PMINFO flags, m, n, p); +} +#endif + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static int MGA1064_preinit(WPMINFO2) { + static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960, + 1024, 1152, 1280, 1600, 1664, 1920, + 2048, 0}; + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + DBG(__FUNCTION__) + + /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ + ACCESS_FBINFO(capable.text) = 1; + ACCESS_FBINFO(capable.vxres) = vxres_mystique; + ACCESS_FBINFO(features.accel.has_cacheflush) = 1; + + ACCESS_FBINFO(outputs[0]).output = &m1064; + ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src; + ACCESS_FBINFO(outputs[0]).data = MINFO; + ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR; + + if (ACCESS_FBINFO(devflags.noinit)) + return 0; /* do not modify settings */ + hw->MXoptionReg &= 0xC0000100; + hw->MXoptionReg |= 0x00094E20; + if (ACCESS_FBINFO(devflags.novga)) + hw->MXoptionReg &= ~0x00000100; + if (ACCESS_FBINFO(devflags.nobios)) + hw->MXoptionReg &= ~0x40000000; + if (ACCESS_FBINFO(devflags.nopciretry)) + hw->MXoptionReg |= 0x20000000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + mga_setr(M_SEQ_INDEX, 0x01, 0x20); + mga_outl(M_CTLWTST, 0x00000000); + udelay(200); + mga_outl(M_MACCESS, 0x00008000); + udelay(100); + mga_outl(M_MACCESS, 0x0000C000); + return 0; +} + +static void MGA1064_reset(WPMINFO2) { + + DBG(__FUNCTION__); + + MGA1064_ramdac_init(PMINFO2); +} +#endif + +#ifdef CONFIG_FB_MATROX_G +static void g450_mclk_init(WPMINFO2) { + /* switch all clocks to PCI source */ + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg | 4); + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION3_REG, ACCESS_FBINFO(values).reg.opt3 & ~0x00300C03); + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); + + if (((ACCESS_FBINFO(values).reg.opt3 & 0x000003) == 0x000003) || + ((ACCESS_FBINFO(values).reg.opt3 & 0x000C00) == 0x000C00) || + ((ACCESS_FBINFO(values).reg.opt3 & 0x300000) == 0x300000)) { + matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.video), M_VIDEO_PLL); + } else { + unsigned long flags; + unsigned int pwr; + + matroxfb_DAC_lock_irqsave(flags); + pwr = inDAC1064(PMINFO M1064_XPWRCTRL) & ~0x02; + outDAC1064(PMINFO M1064_XPWRCTRL, pwr); + matroxfb_DAC_unlock_irqrestore(flags); + } + matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.system), M_SYSTEM_PLL); + + /* switch clocks to their real PLL source(s) */ + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg | 4); + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION3_REG, ACCESS_FBINFO(values).reg.opt3); + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); + +} + +static void g450_memory_init(WPMINFO2) { + /* disable memory refresh */ + ACCESS_FBINFO(hw).MXoptionReg &= ~0x001F8000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); + + /* set memory interface parameters */ + ACCESS_FBINFO(hw).MXoptionReg &= ~0x00207E00; + ACCESS_FBINFO(hw).MXoptionReg |= 0x00207E00 & ACCESS_FBINFO(values).reg.opt; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, ACCESS_FBINFO(values).reg.opt2); + + mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst); + + /* first set up memory interface with disabled memory interface clocks */ + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MEMMISC_REG, ACCESS_FBINFO(values).reg.memmisc & ~0x80000000U); + mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk); + mga_outl(M_MACCESS, ACCESS_FBINFO(values).reg.maccess); + /* start memory clocks */ + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MEMMISC_REG, ACCESS_FBINFO(values).reg.memmisc | 0x80000000U); + + udelay(200); + + if (ACCESS_FBINFO(values).memory.ddr && (!ACCESS_FBINFO(values).memory.emrswen || !ACCESS_FBINFO(values).memory.dll)) { + mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk & ~0x1000); + } + mga_outl(M_MACCESS, ACCESS_FBINFO(values).reg.maccess | 0x8000); + + udelay(200); + + ACCESS_FBINFO(hw).MXoptionReg |= 0x001F8000 & ACCESS_FBINFO(values).reg.opt; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); + + /* value is written to memory chips only if old != new */ + mga_outl(M_PLNWT, 0); + mga_outl(M_PLNWT, ~0); + + if (ACCESS_FBINFO(values).reg.mctlwtst != ACCESS_FBINFO(values).reg.mctlwtst_core) { + mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst_core); + } + +} + +static void g450_preinit(WPMINFO2) { + u_int32_t c2ctl; + u_int8_t curctl; + u_int8_t c1ctl; + + /* ACCESS_FBINFO(hw).MXoptionReg = minfo->values.reg.opt; */ + ACCESS_FBINFO(hw).MXoptionReg &= 0xC0000100; + ACCESS_FBINFO(hw).MXoptionReg |= 0x00000020; + if (ACCESS_FBINFO(devflags.novga)) + ACCESS_FBINFO(hw).MXoptionReg &= ~0x00000100; + if (ACCESS_FBINFO(devflags.nobios)) + ACCESS_FBINFO(hw).MXoptionReg &= ~0x40000000; + if (ACCESS_FBINFO(devflags.nopciretry)) + ACCESS_FBINFO(hw).MXoptionReg |= 0x20000000; + ACCESS_FBINFO(hw).MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x03400040; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); + + /* Init system clocks */ + + /* stop crtc2 */ + c2ctl = mga_inl(M_C2CTL); + mga_outl(M_C2CTL, c2ctl & ~1); + /* stop cursor */ + curctl = inDAC1064(PMINFO M1064_XCURCTRL); + outDAC1064(PMINFO M1064_XCURCTRL, 0); + /* stop crtc1 */ + c1ctl = mga_readr(M_SEQ_INDEX, 1); + mga_setr(M_SEQ_INDEX, 1, c1ctl | 0x20); + + g450_mclk_init(PMINFO2); + g450_memory_init(PMINFO2); + + /* set legacy VGA clock sources for DOSEmu or VMware... */ + matroxfb_g450_setclk(PMINFO 25175, M_PIXEL_PLL_A); + matroxfb_g450_setclk(PMINFO 28322, M_PIXEL_PLL_B); + + /* restore crtc1 */ + mga_setr(M_SEQ_INDEX, 1, c1ctl); + + /* restore cursor */ + outDAC1064(PMINFO M1064_XCURCTRL, curctl); + + /* restore crtc2 */ + mga_outl(M_C2CTL, c2ctl); + + return; +} + +static int MGAG100_preinit(WPMINFO2) { + static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960, + 1024, 1152, 1280, 1600, 1664, 1920, + 2048, 0}; + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + u_int32_t reg50; +#if 0 + u_int32_t q; +#endif + + DBG(__FUNCTION__) + + /* there are some instabilities if in_div > 19 && vco < 61000 */ + if (ACCESS_FBINFO(devflags.g450dac)) { + ACCESS_FBINFO(features.pll.vco_freq_min) = 130000; /* my sample: >118 */ + } else { + ACCESS_FBINFO(features.pll.vco_freq_min) = 62000; + } + if (!ACCESS_FBINFO(features.pll.ref_freq)) { + ACCESS_FBINFO(features.pll.ref_freq) = 27000; + } + ACCESS_FBINFO(features.pll.feed_div_min) = 7; + ACCESS_FBINFO(features.pll.feed_div_max) = 127; + ACCESS_FBINFO(features.pll.in_div_min) = 1; + ACCESS_FBINFO(features.pll.in_div_max) = 31; + ACCESS_FBINFO(features.pll.post_shift_max) = 3; + ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT; + /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ + ACCESS_FBINFO(capable.text) = 1; + ACCESS_FBINFO(capable.vxres) = vxres_g100; + ACCESS_FBINFO(features.accel.has_cacheflush) = 1; + ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100 + ? ACCESS_FBINFO(devflags.sgram) : 1; + +#ifdef CONFIG_FB_MATROX_G + if (ACCESS_FBINFO(devflags.g450dac)) { + ACCESS_FBINFO(outputs[0]).output = &g450out; + } else +#endif + { + ACCESS_FBINFO(outputs[0]).output = &m1064; + } + ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src; + ACCESS_FBINFO(outputs[0]).data = MINFO; + ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR; + + if (ACCESS_FBINFO(devflags.g450dac)) { + /* we must do this always, BIOS does not do it for us + and accelerator dies without it */ + mga_outl(0x1C0C, 0); + } + if (ACCESS_FBINFO(devflags.noinit)) + return 0; + if (ACCESS_FBINFO(devflags.g450dac)) { + g450_preinit(PMINFO2); + return 0; + } + hw->MXoptionReg &= 0xC0000100; + hw->MXoptionReg |= 0x00000020; + if (ACCESS_FBINFO(devflags.novga)) + hw->MXoptionReg &= ~0x00000100; + if (ACCESS_FBINFO(devflags.nobios)) + hw->MXoptionReg &= ~0x40000000; + if (ACCESS_FBINFO(devflags.nopciretry)) + hw->MXoptionReg |= 0x20000000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + DAC1064_setmclk(PMINFO DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333); + + if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100) { + pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, ®50); + reg50 &= ~0x3000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50); + + hw->MXoptionReg |= 0x1080; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst); + udelay(100); + mga_outb(0x1C05, 0x00); + mga_outb(0x1C05, 0x80); + udelay(100); + mga_outb(0x1C05, 0x40); + mga_outb(0x1C05, 0xC0); + udelay(100); + reg50 &= ~0xFF; + reg50 |= 0x07; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50); + /* it should help with G100 */ + mga_outb(M_GRAPHICS_INDEX, 6); + mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4); + mga_setr(M_EXTVGA_INDEX, 0x03, 0x81); + mga_setr(M_EXTVGA_INDEX, 0x04, 0x00); + mga_writeb(ACCESS_FBINFO(video.vbase), 0x0000, 0xAA); + mga_writeb(ACCESS_FBINFO(video.vbase), 0x0800, 0x55); + mga_writeb(ACCESS_FBINFO(video.vbase), 0x4000, 0x55); +#if 0 + if (mga_readb(ACCESS_FBINFO(video.vbase), 0x0000) != 0xAA) { + hw->MXoptionReg &= ~0x1000; + } +#endif + hw->MXoptionReg |= 0x00078020; + } else if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG200) { + pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, ®50); + reg50 &= ~0x3000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50); + + if (ACCESS_FBINFO(devflags.memtype) == -1) + hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00; + else + hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10; + if (ACCESS_FBINFO(devflags.sgram)) + hw->MXoptionReg |= 0x4000; + mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst); + mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk); + udelay(200); + mga_outl(M_MACCESS, 0x00000000); + mga_outl(M_MACCESS, 0x00008000); + udelay(100); + mga_outw(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk); + hw->MXoptionReg |= 0x00078020; + } else { + pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, ®50); + reg50 &= ~0x00000100; + reg50 |= 0x00000000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50); + + if (ACCESS_FBINFO(devflags.memtype) == -1) + hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00; + else + hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10; + if (ACCESS_FBINFO(devflags.sgram)) + hw->MXoptionReg |= 0x4000; + mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst); + mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk); + udelay(200); + mga_outl(M_MACCESS, 0x00000000); + mga_outl(M_MACCESS, 0x00008000); + udelay(100); + mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk); + hw->MXoptionReg |= 0x00040020; + } + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + return 0; +} + +static void MGAG100_reset(WPMINFO2) { + u_int8_t b; + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + DBG(__FUNCTION__) + + { +#ifdef G100_BROKEN_IBM_82351 + u_int32_t d; + + find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */ + pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b); + if (b == ACCESS_FBINFO(pcidev)->bus->number) { + pci_write_config_byte(ibm, PCI_COMMAND+1, 0); /* disable back-to-back & SERR */ + pci_write_config_byte(ibm, 0x41, 0xF4); /* ??? */ + pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0); /* ??? */ + pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00); /* ??? */ + } +#endif + if (!ACCESS_FBINFO(devflags.noinit)) { + if (x7AF4 & 8) { + hw->MXoptionReg |= 0x40; /* FIXME... */ + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + } + mga_setr(M_EXTVGA_INDEX, 0x06, 0x50); + } + } + if (ACCESS_FBINFO(devflags.g450dac)) { + /* either leave MCLK as is... or they were set in preinit */ + hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM); + hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN); + hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP); + } else { + DAC1064_setmclk(PMINFO DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333); + } + if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) { + if (ACCESS_FBINFO(devflags.dfp_type) == -1) { + ACCESS_FBINFO(devflags.dfp_type) = inDAC1064(PMINFO 0x1F); + } + } + if (ACCESS_FBINFO(devflags.noinit)) + return; + if (ACCESS_FBINFO(devflags.g450dac)) { + } else { + MGAG100_setPixClock(PMINFO 4, 25175); + MGAG100_setPixClock(PMINFO 5, 28322); + if (x7AF4 & 0x10) { + b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1; + outDAC1064(PMINFO M1064_XGENIODATA, b); + b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1; + outDAC1064(PMINFO M1064_XGENIOCTRL, b); + } + } +} +#endif + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static void MGA1064_restore(WPMINFO2) { + int i; + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + CRITFLAGS + + DBG(__FUNCTION__) + + CRITBEGIN + + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + mga_outb(M_IEN, 0x00); + mga_outb(M_CACHEFLUSH, 0x00); + + CRITEND + + DAC1064_restore_1(PMINFO2); + matroxfb_vgaHWrestore(PMINFO2); + ACCESS_FBINFO(crtc1.panpos) = -1; + for (i = 0; i < 6; i++) + mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); + DAC1064_restore_2(PMINFO2); +} +#endif + +#ifdef CONFIG_FB_MATROX_G +static void MGAG100_restore(WPMINFO2) { + int i; + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + CRITFLAGS + + DBG(__FUNCTION__) + + CRITBEGIN + + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + CRITEND + + DAC1064_restore_1(PMINFO2); + matroxfb_vgaHWrestore(PMINFO2); +#ifdef CONFIG_FB_MATROX_32MB + if (ACCESS_FBINFO(devflags.support32MB)) + mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]); +#endif + ACCESS_FBINFO(crtc1.panpos) = -1; + for (i = 0; i < 6; i++) + mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); + DAC1064_restore_2(PMINFO2); +} +#endif + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +struct matrox_switch matrox_mystique = { + MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore, +}; +EXPORT_SYMBOL(matrox_mystique); +#endif + +#ifdef CONFIG_FB_MATROX_G +struct matrox_switch matrox_G100 = { + MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore, +}; +EXPORT_SYMBOL(matrox_G100); +#endif + +#ifdef NEED_DAC1064 +EXPORT_SYMBOL(DAC1064_global_init); +EXPORT_SYMBOL(DAC1064_global_restore); +#endif +MODULE_LICENSE("GPL"); diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h new file mode 100644 index 000000000000..a6a470127289 --- /dev/null +++ b/drivers/video/matrox/matroxfb_DAC1064.h @@ -0,0 +1,164 @@ +#ifndef __MATROXFB_DAC1064_H__ +#define __MATROXFB_DAC1064_H__ + +/* make checkconfig does not walk through include tree */ +#include <linux/config.h> + +#include "matroxfb_base.h" + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +extern struct matrox_switch matrox_mystique; +#endif +#ifdef CONFIG_FB_MATROX_G +extern struct matrox_switch matrox_G100; +#endif +#ifdef NEED_DAC1064 +void DAC1064_global_init(WPMINFO2); +void DAC1064_global_restore(WPMINFO2); +#endif + +#define M1064_INDEX 0x00 +#define M1064_PALWRADD 0x00 +#define M1064_PALDATA 0x01 +#define M1064_PIXRDMSK 0x02 +#define M1064_PALRDADD 0x03 +#define M1064_X_DATAREG 0x0A +#define M1064_CURPOSXL 0x0C /* can be accessed as DWORD */ +#define M1064_CURPOSXH 0x0D +#define M1064_CURPOSYL 0x0E +#define M1064_CURPOSYH 0x0F + +#define M1064_XCURADDL 0x04 +#define M1064_XCURADDH 0x05 +#define M1064_XCURCTRL 0x06 +#define M1064_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */ +#define M1064_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */ +#define M1064_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */ +#define M1064_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */ +#define M1064_XCURCOL0RED 0x08 +#define M1064_XCURCOL0GREEN 0x09 +#define M1064_XCURCOL0BLUE 0x0A +#define M1064_XCURCOL1RED 0x0C +#define M1064_XCURCOL1GREEN 0x0D +#define M1064_XCURCOL1BLUE 0x0E +#define M1064_XCURCOL2RED 0x10 +#define M1064_XCURCOL2GREEN 0x11 +#define M1064_XCURCOL2BLUE 0x12 +#define DAC1064_XVREFCTRL 0x18 +#define DAC1064_XVREFCTRL_INTERNAL 0x3F +#define DAC1064_XVREFCTRL_EXTERNAL 0x00 +#define DAC1064_XVREFCTRL_G100_DEFAULT 0x03 +#define M1064_XMULCTRL 0x19 +#define M1064_XMULCTRL_DEPTH_8BPP 0x00 /* 8 bpp paletized */ +#define M1064_XMULCTRL_DEPTH_15BPP_1BPP 0x01 /* 15 bpp paletized + 1 bpp overlay */ +#define M1064_XMULCTRL_DEPTH_16BPP 0x02 /* 16 bpp paletized */ +#define M1064_XMULCTRL_DEPTH_24BPP 0x03 /* 24 bpp paletized */ +#define M1064_XMULCTRL_DEPTH_24BPP_8BPP 0x04 /* 24 bpp direct + 8 bpp overlay paletized */ +#define M1064_XMULCTRL_2G8V16 0x05 /* 15 bpp video direct, half xres, 8bpp paletized */ +#define M1064_XMULCTRL_G16V16 0x06 /* 15 bpp video, 15bpp graphics, one of them paletized */ +#define M1064_XMULCTRL_DEPTH_32BPP 0x07 /* 24 bpp paletized + 8 bpp unused */ +#define M1064_XMULCTRL_GRAPHICS_PALETIZED 0x00 +#define M1064_XMULCTRL_VIDEO_PALETIZED 0x08 +#define M1064_XPIXCLKCTRL 0x1A +#define M1064_XPIXCLKCTRL_SRC_PCI 0x00 +#define M1064_XPIXCLKCTRL_SRC_PLL 0x01 +#define M1064_XPIXCLKCTRL_SRC_EXT 0x02 +#define M1064_XPIXCLKCTRL_SRC_SYS 0x03 /* G200/G400 */ +#define M1064_XPIXCLKCTRL_SRC_PLL2 0x03 /* G450 */ +#define M1064_XPIXCLKCTRL_SRC_MASK 0x03 +#define M1064_XPIXCLKCTRL_EN 0x00 +#define M1064_XPIXCLKCTRL_DIS 0x04 +#define M1064_XPIXCLKCTRL_PLL_DOWN 0x00 +#define M1064_XPIXCLKCTRL_PLL_UP 0x08 +#define M1064_XGENCTRL 0x1D +#define M1064_XGENCTRL_VS_0 0x00 +#define M1064_XGENCTRL_VS_1 0x01 +#define M1064_XGENCTRL_ALPHA_DIS 0x00 +#define M1064_XGENCTRL_ALPHA_EN 0x02 +#define M1064_XGENCTRL_BLACK_0IRE 0x00 +#define M1064_XGENCTRL_BLACK_75IRE 0x10 +#define M1064_XGENCTRL_SYNC_ON_GREEN 0x00 +#define M1064_XGENCTRL_NO_SYNC_ON_GREEN 0x20 +#define M1064_XGENCTRL_SYNC_ON_GREEN_MASK 0x20 +#define M1064_XMISCCTRL 0x1E +#define M1064_XMISCCTRL_DAC_DIS 0x00 +#define M1064_XMISCCTRL_DAC_EN 0x01 +#define M1064_XMISCCTRL_MFC_VGA 0x00 +#define M1064_XMISCCTRL_MFC_MAFC 0x02 +#define M1064_XMISCCTRL_MFC_DIS 0x06 +#define GX00_XMISCCTRL_MFC_MAFC 0x02 +#define GX00_XMISCCTRL_MFC_PANELLINK 0x04 +#define GX00_XMISCCTRL_MFC_DIS 0x06 +#define GX00_XMISCCTRL_MFC_MASK 0x06 +#define M1064_XMISCCTRL_DAC_6BIT 0x00 +#define M1064_XMISCCTRL_DAC_8BIT 0x08 +#define M1064_XMISCCTRL_DAC_WIDTHMASK 0x08 +#define M1064_XMISCCTRL_LUT_DIS 0x00 +#define M1064_XMISCCTRL_LUT_EN 0x10 +#define G400_XMISCCTRL_VDO_MAFC12 0x00 +#define G400_XMISCCTRL_VDO_BYPASS656 0x40 +#define G400_XMISCCTRL_VDO_C2_MAFC12 0x80 +#define G400_XMISCCTRL_VDO_C2_BYPASS656 0xC0 +#define G400_XMISCCTRL_VDO_MASK 0xE0 +#define M1064_XGENIOCTRL 0x2A +#define M1064_XGENIODATA 0x2B +#define DAC1064_XSYSPLLM 0x2C +#define DAC1064_XSYSPLLN 0x2D +#define DAC1064_XSYSPLLP 0x2E +#define DAC1064_XSYSPLLSTAT 0x2F +#define M1064_XZOOMCTRL 0x38 +#define M1064_XZOOMCTRL_1 0x00 +#define M1064_XZOOMCTRL_2 0x01 +#define M1064_XZOOMCTRL_4 0x03 +#define M1064_XSENSETEST 0x3A +#define M1064_XSENSETEST_BCOMP 0x01 +#define M1064_XSENSETEST_GCOMP 0x02 +#define M1064_XSENSETEST_RCOMP 0x04 +#define M1064_XSENSETEST_PDOWN 0x00 +#define M1064_XSENSETEST_PUP 0x80 +#define M1064_XCRCREML 0x3C +#define M1064_XCRCREMH 0x3D +#define M1064_XCRCBITSEL 0x3E +#define M1064_XCOLKEYMASKL 0x40 +#define M1064_XCOLKEYMASKH 0x41 +#define M1064_XCOLKEYL 0x42 +#define M1064_XCOLKEYH 0x43 +#define M1064_XPIXPLLAM 0x44 +#define M1064_XPIXPLLAN 0x45 +#define M1064_XPIXPLLAP 0x46 +#define M1064_XPIXPLLBM 0x48 +#define M1064_XPIXPLLBN 0x49 +#define M1064_XPIXPLLBP 0x4A +#define M1064_XPIXPLLCM 0x4C +#define M1064_XPIXPLLCN 0x4D +#define M1064_XPIXPLLCP 0x4E +#define M1064_XPIXPLLSTAT 0x4F + +#define M1064_XTVO_IDX 0x87 +#define M1064_XTVO_DATA 0x88 + +#define M1064_XOUTPUTCONN 0x8A +#define M1064_XSYNCCTRL 0x8B +#define M1064_XVIDPLLSTAT 0x8C +#define M1064_XVIDPLLP 0x8D +#define M1064_XVIDPLLM 0x8E +#define M1064_XVIDPLLN 0x8F + +#define M1064_XPWRCTRL 0xA0 + +#define M1064_XPANMODE 0xA2 + +enum POS1064 { + POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL, + POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE, + POS1064_XCURCOL1RED, POS1064_XCURCOL1GREEN, POS1064_XCURCOL1BLUE, + POS1064_XCURCOL2RED, POS1064_XCURCOL2GREEN, POS1064_XCURCOL2BLUE, + POS1064_XVREFCTRL, POS1064_XMULCTRL, POS1064_XPIXCLKCTRL, POS1064_XGENCTRL, + POS1064_XMISCCTRL, + POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST, + POS1064_XCRCBITSEL, + POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH, + POS1064_XOUTPUTCONN, POS1064_XPANMODE, POS1064_XPWRCTRL }; + + +#endif /* __MATROXFB_DAC1064_H__ */ diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c new file mode 100644 index 000000000000..537ade5d8b21 --- /dev/null +++ b/drivers/video/matrox/matroxfb_Ti3026.c @@ -0,0 +1,739 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 + * + * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Portions Copyright (c) 2001 Matrox Graphics Inc. + * + * Version: 1.65 2002/08/14 + * + * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> + * + * Contributors: "menion?" <menion@mindless.com> + * Betatesting, fixes, ideas + * + * "Kurt Garloff" <garloff@suse.de> + * Betatesting, fixes, ideas, videomodes, videomodes timmings + * + * "Tom Rini" <trini@kernel.crashing.org> + * MTRR stuff, PPC cleanups, betatesting, fixes, ideas + * + * "Bibek Sahu" <scorpio@dodds.net> + * Access device through readb|w|l and write b|w|l + * Extensive debugging stuff + * + * "Daniel Haun" <haund@usa.net> + * Testing, hardware cursor fixes + * + * "Scott Wood" <sawst46+@pitt.edu> + * Fixes + * + * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> + * Betatesting + * + * "Kelly French" <targon@hazmat.com> + * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> + * Betatesting, bug reporting + * + * "Pablo Bianucci" <pbian@pccp.com.ar> + * Fixes, ideas, betatesting + * + * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> + * Fixes, enhandcements, ideas, betatesting + * + * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> + * PPC betatesting, PPC support, backward compatibility + * + * "Paul Womar" <Paul@pwomar.demon.co.uk> + * "Owen Waller" <O.Waller@ee.qub.ac.uk> + * PPC betatesting + * + * "Thomas Pornin" <pornin@bolet.ens.fr> + * Alpha betatesting + * + * "Pieter van Leuven" <pvl@iae.nl> + * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> + * G100 testing + * + * "H. Peter Arvin" <hpa@transmeta.com> + * Ideas + * + * "Cort Dougan" <cort@cs.nmt.edu> + * CHRP fixes and PReP cleanup + * + * "Mark Vojkovich" <mvojkovi@ucsd.edu> + * G400 support + * + * (following author is not in any relation with this code, but his code + * is included in this driver) + * + * Based on framebuffer driver for VBE 2.0 compliant graphic boards + * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + * + * (following author is not in any relation with this code, but his ideas + * were used when writting this driver) + * + * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> + * + */ + +/* make checkconfig does not verify included files... */ +#include <linux/config.h> + +#include "matroxfb_Ti3026.h" +#include "matroxfb_misc.h" +#include "matroxfb_accel.h" +#include <linux/matroxfb.h> + +#ifdef CONFIG_FB_MATROX_MILLENIUM +#define outTi3026 matroxfb_DAC_out +#define inTi3026 matroxfb_DAC_in + +#define TVP3026_INDEX 0x00 +#define TVP3026_PALWRADD 0x00 +#define TVP3026_PALDATA 0x01 +#define TVP3026_PIXRDMSK 0x02 +#define TVP3026_PALRDADD 0x03 +#define TVP3026_CURCOLWRADD 0x04 +#define TVP3026_CLOVERSCAN 0x00 +#define TVP3026_CLCOLOR0 0x01 +#define TVP3026_CLCOLOR1 0x02 +#define TVP3026_CLCOLOR2 0x03 +#define TVP3026_CURCOLDATA 0x05 +#define TVP3026_CURCOLRDADD 0x07 +#define TVP3026_CURCTRL 0x09 +#define TVP3026_X_DATAREG 0x0A +#define TVP3026_CURRAMDATA 0x0B +#define TVP3026_CURPOSXL 0x0C +#define TVP3026_CURPOSXH 0x0D +#define TVP3026_CURPOSYL 0x0E +#define TVP3026_CURPOSYH 0x0F + +#define TVP3026_XSILICONREV 0x01 +#define TVP3026_XCURCTRL 0x06 +#define TVP3026_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */ +#define TVP3026_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */ +#define TVP3026_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */ +#define TVP3026_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */ +#define TVP3026_XCURCTRL_BLANK2048 0x00 +#define TVP3026_XCURCTRL_BLANK4096 0x10 +#define TVP3026_XCURCTRL_INTERLACED 0x20 +#define TVP3026_XCURCTRL_ODD 0x00 /* ext.signal ODD/\EVEN */ +#define TVP3026_XCURCTRL_EVEN 0x40 /* ext.signal EVEN/\ODD */ +#define TVP3026_XCURCTRL_INDIRECT 0x00 +#define TVP3026_XCURCTRL_DIRECT 0x80 +#define TVP3026_XLATCHCTRL 0x0F +#define TVP3026_XLATCHCTRL_1_1 0x06 +#define TVP3026_XLATCHCTRL_2_1 0x07 +#define TVP3026_XLATCHCTRL_4_1 0x06 +#define TVP3026_XLATCHCTRL_8_1 0x06 +#define TVP3026_XLATCHCTRL_16_1 0x06 +#define TVP3026A_XLATCHCTRL_4_3 0x06 /* ??? do not understand... but it works... !!! */ +#define TVP3026A_XLATCHCTRL_8_3 0x07 +#define TVP3026B_XLATCHCTRL_4_3 0x08 +#define TVP3026B_XLATCHCTRL_8_3 0x06 /* ??? do not understand... but it works... !!! */ +#define TVP3026_XTRUECOLORCTRL 0x18 +#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL 0x00 +#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP 0x20 +#define TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR 0x80 +#define TVP3026_XTRUECOLORCTRL_TRUECOLOR 0x40 /* paletized */ +#define TVP3026_XTRUECOLORCTRL_DIRECTCOLOR 0x00 +#define TVP3026_XTRUECOLORCTRL_24_ALTERNATE 0x08 /* 5:4/5:2 instead of 4:3/8:3 */ +#define TVP3026_XTRUECOLORCTRL_RGB_888 0x16 /* 4:3/8:3 (or 5:4/5:2) */ +#define TVP3026_XTRUECOLORCTRL_BGR_888 0x17 +#define TVP3026_XTRUECOLORCTRL_ORGB_8888 0x06 +#define TVP3026_XTRUECOLORCTRL_BGRO_8888 0x07 +#define TVP3026_XTRUECOLORCTRL_RGB_565 0x05 +#define TVP3026_XTRUECOLORCTRL_ORGB_1555 0x04 +#define TVP3026_XTRUECOLORCTRL_RGB_664 0x03 +#define TVP3026_XTRUECOLORCTRL_RGBO_4444 0x01 +#define TVP3026_XMUXCTRL 0x19 +#define TVP3026_XMUXCTRL_MEMORY_8BIT 0x01 /* - */ +#define TVP3026_XMUXCTRL_MEMORY_16BIT 0x02 /* - */ +#define TVP3026_XMUXCTRL_MEMORY_32BIT 0x03 /* 2MB RAM, 512K * 4 */ +#define TVP3026_XMUXCTRL_MEMORY_64BIT 0x04 /* >2MB RAM, 512K * 8 & more */ +#define TVP3026_XMUXCTRL_PIXEL_4BIT 0x40 /* L0,H0,L1,H1... */ +#define TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED 0x60 /* H0,L0,H1,L1... */ +#define TVP3026_XMUXCTRL_PIXEL_8BIT 0x48 +#define TVP3026_XMUXCTRL_PIXEL_16BIT 0x50 +#define TVP3026_XMUXCTRL_PIXEL_32BIT 0x58 +#define TVP3026_XMUXCTRL_VGA 0x98 /* VGA MEMORY, 8BIT PIXEL */ +#define TVP3026_XCLKCTRL 0x1A +#define TVP3026_XCLKCTRL_DIV1 0x00 +#define TVP3026_XCLKCTRL_DIV2 0x10 +#define TVP3026_XCLKCTRL_DIV4 0x20 +#define TVP3026_XCLKCTRL_DIV8 0x30 +#define TVP3026_XCLKCTRL_DIV16 0x40 +#define TVP3026_XCLKCTRL_DIV32 0x50 +#define TVP3026_XCLKCTRL_DIV64 0x60 +#define TVP3026_XCLKCTRL_CLKSTOPPED 0x70 +#define TVP3026_XCLKCTRL_SRC_CLK0 0x00 +#define TVP3026_XCLKCTRL_SRC_CLK1 0x01 +#define TVP3026_XCLKCTRL_SRC_CLK2 0x02 /* CLK2 is TTL source*/ +#define TVP3026_XCLKCTRL_SRC_NCLK2 0x03 /* not CLK2 is TTL source */ +#define TVP3026_XCLKCTRL_SRC_ECLK2 0x04 /* CLK2 and not CLK2 is ECL source */ +#define TVP3026_XCLKCTRL_SRC_PLL 0x05 +#define TVP3026_XCLKCTRL_SRC_DIS 0x06 /* disable & poweroff internal clock */ +#define TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07 +#define TVP3026_XPALETTEPAGE 0x1C +#define TVP3026_XGENCTRL 0x1D +#define TVP3026_XGENCTRL_HSYNC_POS 0x00 +#define TVP3026_XGENCTRL_HSYNC_NEG 0x01 +#define TVP3026_XGENCTRL_VSYNC_POS 0x00 +#define TVP3026_XGENCTRL_VSYNC_NEG 0x02 +#define TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00 +#define TVP3026_XGENCTRL_BIG_ENDIAN 0x08 +#define TVP3026_XGENCTRL_BLACK_0IRE 0x00 +#define TVP3026_XGENCTRL_BLACK_75IRE 0x10 +#define TVP3026_XGENCTRL_NO_SYNC_ON_GREEN 0x00 +#define TVP3026_XGENCTRL_SYNC_ON_GREEN 0x20 +#define TVP3026_XGENCTRL_OVERSCAN_DIS 0x00 +#define TVP3026_XGENCTRL_OVERSCAN_EN 0x40 +#define TVP3026_XMISCCTRL 0x1E +#define TVP3026_XMISCCTRL_DAC_PUP 0x00 +#define TVP3026_XMISCCTRL_DAC_PDOWN 0x01 +#define TVP3026_XMISCCTRL_DAC_EXT 0x00 /* or 8, bit 3 is ignored */ +#define TVP3026_XMISCCTRL_DAC_6BIT 0x04 +#define TVP3026_XMISCCTRL_DAC_8BIT 0x0C +#define TVP3026_XMISCCTRL_PSEL_DIS 0x00 +#define TVP3026_XMISCCTRL_PSEL_EN 0x10 +#define TVP3026_XMISCCTRL_PSEL_LOW 0x00 /* PSEL high selects directcolor */ +#define TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */ +#define TVP3026_XGENIOCTRL 0x2A +#define TVP3026_XGENIODATA 0x2B +#define TVP3026_XPLLADDR 0x2C +#define TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX)) +#define TVP3026_XPLLDATA_N 0x00 +#define TVP3026_XPLLDATA_M 0x01 +#define TVP3026_XPLLDATA_P 0x02 +#define TVP3026_XPLLDATA_STAT 0x03 +#define TVP3026_XPIXPLLDATA 0x2D +#define TVP3026_XMEMPLLDATA 0x2E +#define TVP3026_XLOOPPLLDATA 0x2F +#define TVP3026_XCOLKEYOVRMIN 0x30 +#define TVP3026_XCOLKEYOVRMAX 0x31 +#define TVP3026_XCOLKEYREDMIN 0x32 +#define TVP3026_XCOLKEYREDMAX 0x33 +#define TVP3026_XCOLKEYGREENMIN 0x34 +#define TVP3026_XCOLKEYGREENMAX 0x35 +#define TVP3026_XCOLKEYBLUEMIN 0x36 +#define TVP3026_XCOLKEYBLUEMAX 0x37 +#define TVP3026_XCOLKEYCTRL 0x38 +#define TVP3026_XCOLKEYCTRL_OVR_EN 0x01 +#define TVP3026_XCOLKEYCTRL_RED_EN 0x02 +#define TVP3026_XCOLKEYCTRL_GREEN_EN 0x04 +#define TVP3026_XCOLKEYCTRL_BLUE_EN 0x08 +#define TVP3026_XCOLKEYCTRL_NEGATE 0x10 +#define TVP3026_XCOLKEYCTRL_ZOOM1 0x00 +#define TVP3026_XCOLKEYCTRL_ZOOM2 0x20 +#define TVP3026_XCOLKEYCTRL_ZOOM4 0x40 +#define TVP3026_XCOLKEYCTRL_ZOOM8 0x60 +#define TVP3026_XCOLKEYCTRL_ZOOM16 0x80 +#define TVP3026_XCOLKEYCTRL_ZOOM32 0xA0 +#define TVP3026_XMEMPLLCTRL 0x39 +#define TVP3026_XMEMPLLCTRL_DIV(X) (((X)-1)>>1) /* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */ +#define TVP3026_XMEMPLLCTRL_STROBEMKC4 0x08 +#define TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK 0x00 /* MKC4 */ +#define TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL 0x10 /* MKC4 */ +#define TVP3026_XMEMPLLCTRL_RCLK_PIXPLL 0x00 +#define TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL 0x20 +#define TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN 0x40 /* dot clock divided by loop pclk N prescaler */ +#define TVP3026_XSENSETEST 0x3A +#define TVP3026_XTESTMODEDATA 0x3B +#define TVP3026_XCRCREML 0x3C +#define TVP3026_XCRCREMH 0x3D +#define TVP3026_XCRCBITSEL 0x3E +#define TVP3026_XID 0x3F + +static const unsigned char DACseq[] = +{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL, + TVP3026_XMUXCTRL, TVP3026_XCLKCTRL, + TVP3026_XPALETTEPAGE, + TVP3026_XGENCTRL, + TVP3026_XMISCCTRL, + TVP3026_XGENIOCTRL, + TVP3026_XGENIODATA, + TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX, + TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX, + TVP3026_XCOLKEYCTRL, + TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL }; + +#define POS3026_XLATCHCTRL 0 +#define POS3026_XTRUECOLORCTRL 1 +#define POS3026_XMUXCTRL 2 +#define POS3026_XCLKCTRL 3 +#define POS3026_XGENCTRL 5 +#define POS3026_XMISCCTRL 6 +#define POS3026_XMEMPLLCTRL 18 +#define POS3026_XCURCTRL 20 + +static const unsigned char MGADACbpp32[] = +{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888, + 0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL, + 0x00, + TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS, + TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH, + 0x00, + 0x1E, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + TVP3026_XCOLKEYCTRL_ZOOM1, + 0x00, 0x00, TVP3026_XCURCTRL_DIS }; + +static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) { + unsigned int fvco; + unsigned int lin, lfeed, lpost; + + DBG(__FUNCTION__) + + fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost); + fvco >>= (*post = lpost); + *in = 64 - lin; + *feed = 64 - lfeed; + return fvco; +} + +static int Ti3026_setpclk(WPMINFO int clk) { + unsigned int f_pll; + unsigned int pixfeed, pixin, pixpost; + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + DBG(__FUNCTION__) + + f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost); + + hw->DACclk[0] = pixin | 0xC0; + hw->DACclk[1] = pixfeed; + hw->DACclk[2] = pixpost | 0xB0; + + { + unsigned int loopfeed, loopin, looppost, loopdiv, z; + unsigned int Bpp; + + Bpp = ACCESS_FBINFO(curr.final_bppShift); + + if (ACCESS_FBINFO(fbcon).var.bits_per_pixel == 24) { + loopfeed = 3; /* set lm to any possible value */ + loopin = 3 * 32 / Bpp; + } else { + loopfeed = 4; + loopin = 4 * 32 / Bpp; + } + z = (110000 * loopin) / (f_pll * loopfeed); + loopdiv = 0; /* div 2 */ + if (z < 2) + looppost = 0; + else if (z < 4) + looppost = 1; + else if (z < 8) + looppost = 2; + else { + looppost = 3; + loopdiv = z/16; + } + if (ACCESS_FBINFO(fbcon).var.bits_per_pixel == 24) { + hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0; + hw->DACclk[4] = (65 - loopfeed) | 0x80; + if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) { + if (isInterleave(MINFO)) + hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3; + else { + hw->DACclk[4] &= ~0xC0; + hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3; + } + } else { + if (isInterleave(MINFO)) + ; /* default... */ + else { + hw->DACclk[4] ^= 0xC0; /* change from 0x80 to 0x40 */ + hw->DACreg[POS3026_XLATCHCTRL] = TVP3026A_XLATCHCTRL_4_3; + } + } + hw->DACclk[5] = looppost | 0xF8; + if (ACCESS_FBINFO(devflags.mga_24bpp_fix)) + hw->DACclk[5] ^= 0x40; + } else { + hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0; + hw->DACclk[4] = 65 - loopfeed; + hw->DACclk[5] = looppost | 0xF0; + } + hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL; + } + return 0; +} + +static int Ti3026_init(WPMINFO struct my_timming* m) { + u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT; + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + DBG(__FUNCTION__) + + memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg)); + switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { + case 4: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1; /* or _8_1, they are same */ + hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8; + hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW; + break; + case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; /* or _4_1, they are same */ + hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4; + hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW; + break; + case 16: + /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */ + hw->DACreg[POS3026_XTRUECOLORCTRL] = (ACCESS_FBINFO(fbcon).var.green.length == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565); + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2; + break; + case 24: + /* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */ + hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888; + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4; + break; + case 32: + /* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */ + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT; + break; + default: + return 1; /* TODO: failed */ + } + if (matroxfb_vgaHWinit(PMINFO m)) return 1; + + /* set SYNC */ + hw->MiscOutReg = 0xCB; + if (m->sync & FB_SYNC_HOR_HIGH_ACT) + hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG; + if (m->sync & FB_SYNC_VERT_HIGH_ACT) + hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG; + if (m->sync & FB_SYNC_ON_GREEN) + hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN; + + /* set DELAY */ + if (ACCESS_FBINFO(video.len) < 0x400000) + hw->CRTCEXT[3] |= 0x08; + else if (ACCESS_FBINFO(video.len) > 0x400000) + hw->CRTCEXT[3] |= 0x10; + + /* set HWCURSOR */ + if (m->interlaced) { + hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED; + } + if (m->HTotal >= 1536) + hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_BLANK4096; + + /* set interleaving */ + hw->MXoptionReg &= ~0x00001000; + if (isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000; + + /* set DAC */ + Ti3026_setpclk(PMINFO m->pixclock); + return 0; +} + +static void ti3026_setMCLK(WPMINFO int fout){ + unsigned int f_pll; + unsigned int pclk_m, pclk_n, pclk_p; + unsigned int mclk_m, mclk_n, mclk_p; + unsigned int rfhcnt, mclk_ctl; + int tmout; + + DBG(__FUNCTION__) + + f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p); + + /* save pclk */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC); + pclk_n = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFD); + pclk_m = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE); + pclk_p = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + + /* stop pclk */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00); + + /* set pclk to new mclk */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_n | 0xC0); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_m); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_p | 0xB0); + + /* wait for PLL to lock */ + for (tmout = 500000; tmout; tmout--) { + if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) + break; + udelay(10); + }; + if (!tmout) + printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n"); + + /* output pclk on mclk pin */ + mclk_ctl = inTi3026(PMINFO TVP3026_XMEMPLLCTRL); + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7); + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4); + + /* stop MCLK */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFB); + outTi3026(PMINFO TVP3026_XMEMPLLDATA, 0x00); + + /* set mclk to new freq */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xF3); + outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_n | 0xC0); + outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_m); + outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_p | 0xB0); + + /* wait for PLL to lock */ + for (tmout = 500000; tmout; tmout--) { + if (inTi3026(PMINFO TVP3026_XMEMPLLDATA) & 0x40) + break; + udelay(10); + } + if (!tmout) + printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n"); + + f_pll = f_pll * 333 / (10000 << mclk_p); + if (isMilleniumII(MINFO)) { + rfhcnt = (f_pll - 128) / 256; + if (rfhcnt > 15) + rfhcnt = 15; + } else { + rfhcnt = (f_pll - 64) / 128; + if (rfhcnt > 15) + rfhcnt = 0; + } + ACCESS_FBINFO(hw).MXoptionReg = (ACCESS_FBINFO(hw).MXoptionReg & ~0x000F0000) | (rfhcnt << 16); + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); + + /* output MCLK to MCLK pin */ + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL); + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4); + + /* stop PCLK */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00); + + /* restore pclk */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_n); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_m); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_p); + + /* wait for PLL to lock */ + for (tmout = 500000; tmout; tmout--) { + if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) + break; + udelay(10); + } + if (!tmout) + printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); +} + +static void ti3026_ramdac_init(WPMINFO2) { + + DBG(__FUNCTION__) + + ACCESS_FBINFO(features.pll.vco_freq_min) = 110000; + ACCESS_FBINFO(features.pll.ref_freq) = 114545; + ACCESS_FBINFO(features.pll.feed_div_min) = 2; + ACCESS_FBINFO(features.pll.feed_div_max) = 24; + ACCESS_FBINFO(features.pll.in_div_min) = 2; + ACCESS_FBINFO(features.pll.in_div_max) = 63; + ACCESS_FBINFO(features.pll.post_shift_max) = 3; + if (ACCESS_FBINFO(devflags.noinit)) + return; + ti3026_setMCLK(PMINFO 60000); +} + +static void Ti3026_restore(WPMINFO2) { + int i; + unsigned char progdac[6]; + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + CRITFLAGS + + DBG(__FUNCTION__) + +#ifdef DEBUG + dprintk(KERN_INFO "EXTVGA regs: "); + for (i = 0; i < 6; i++) + dprintk("%02X:", hw->CRTCEXT[i]); + dprintk("\n"); +#endif + + CRITBEGIN + + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + + CRITEND + + matroxfb_vgaHWrestore(PMINFO2); + + CRITBEGIN + + ACCESS_FBINFO(crtc1.panpos) = -1; + for (i = 0; i < 6; i++) + mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); + + for (i = 0; i < 21; i++) { + outTi3026(PMINFO DACseq[i], hw->DACreg[i]); + } + + outTi3026(PMINFO TVP3026_XPLLADDR, 0x00); + progdac[0] = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + progdac[3] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA); + outTi3026(PMINFO TVP3026_XPLLADDR, 0x15); + progdac[1] = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + progdac[4] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA); + outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A); + progdac[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + progdac[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA); + + CRITEND + if (memcmp(hw->DACclk, progdac, 6)) { + /* agrhh... setting up PLL is very slow on Millennium... */ + /* Mystique PLL is locked in few ms, but Millennium PLL lock takes about 0.15 s... */ + /* Maybe even we should call schedule() ? */ + + CRITBEGIN + outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]); + outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A); + outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0); + + outTi3026(PMINFO TVP3026_XPLLADDR, 0x00); + for (i = 0; i < 3; i++) + outTi3026(PMINFO TVP3026_XPIXPLLDATA, hw->DACclk[i]); + /* wait for PLL only if PLL clock requested (always for PowerMode, never for VGA) */ + if (hw->MiscOutReg & 0x08) { + int tmout; + outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F); + for (tmout = 500000; tmout; --tmout) { + if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) + break; + udelay(10); + } + + CRITEND + + if (!tmout) + printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); + else + dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout); + CRITBEGIN + } + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]); + outTi3026(PMINFO TVP3026_XPLLADDR, 0x00); + for (i = 3; i < 6; i++) + outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]); + CRITEND + if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) { + int tmout; + + CRITBEGIN + outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F); + for (tmout = 500000; tmout; --tmout) { + if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40) + break; + udelay(10); + } + CRITEND + if (!tmout) + printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n"); + else + dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout); + } + } + +#ifdef DEBUG + dprintk(KERN_DEBUG "3026DACregs "); + for (i = 0; i < 21; i++) { + dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]); + if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... "); + } + dprintk("\n" KERN_DEBUG "DACclk "); + for (i = 0; i < 6; i++) + dprintk("C%02X=%02X ", i, hw->DACclk[i]); + dprintk("\n"); +#endif +} + +static void Ti3026_reset(WPMINFO2) { + + DBG(__FUNCTION__) + + ti3026_ramdac_init(PMINFO2); +} + +static struct matrox_altout ti3026_output = { + .name = "Primary output", +}; + +static int Ti3026_preinit(WPMINFO2) { + static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960, + 1024, 1152, 1280, 1600, 1664, 1920, + 2048, 0}; + static const int vxres_mill1[] = { 640, 768, 800, 960, + 1024, 1152, 1280, 1600, 1920, + 2048, 0}; + struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); + + DBG(__FUNCTION__) + + ACCESS_FBINFO(millenium) = 1; + ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL); + ACCESS_FBINFO(capable.cfb4) = 1; + ACCESS_FBINFO(capable.text) = 1; /* isMilleniumII(MINFO); */ + ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1; + + ACCESS_FBINFO(outputs[0]).data = MINFO; + ACCESS_FBINFO(outputs[0]).output = &ti3026_output; + ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src; + ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR; + + if (ACCESS_FBINFO(devflags.noinit)) + return 0; + /* preserve VGA I/O, BIOS and PPC */ + hw->MXoptionReg &= 0xC0000100; + hw->MXoptionReg |= 0x002C0000; + if (ACCESS_FBINFO(devflags.novga)) + hw->MXoptionReg &= ~0x00000100; + if (ACCESS_FBINFO(devflags.nobios)) + hw->MXoptionReg &= ~0x40000000; + if (ACCESS_FBINFO(devflags.nopciretry)) + hw->MXoptionReg |= 0x20000000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + + ACCESS_FBINFO(accel.ramdac_rev) = inTi3026(PMINFO TVP3026_XSILICONREV); + + outTi3026(PMINFO TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED); + outTi3026(PMINFO TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR); + outTi3026(PMINFO TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA); + + outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A); + outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0x00); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00); + + mga_outb(M_MISC_REG, 0x67); + + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL); + + mga_outl(M_RESET, 1); + udelay(250); + mga_outl(M_RESET, 0); + udelay(250); + mga_outl(M_MACCESS, 0x00008000); + udelay(10); + return 0; +} + +struct matrox_switch matrox_millennium = { + Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore +}; +EXPORT_SYMBOL(matrox_millennium); +#endif +MODULE_LICENSE("GPL"); diff --git a/drivers/video/matrox/matroxfb_Ti3026.h b/drivers/video/matrox/matroxfb_Ti3026.h new file mode 100644 index 000000000000..541933d7e4ea --- /dev/null +++ b/drivers/video/matrox/matroxfb_Ti3026.h @@ -0,0 +1,13 @@ +#ifndef __MATROXFB_TI3026_H__ +#define __MATROXFB_TI3026_H__ + +/* make checkconfig does not walk through whole include tree */ +#include <linux/config.h> + +#include "matroxfb_base.h" + +#ifdef CONFIG_FB_MATROX_MILLENIUM +extern struct matrox_switch matrox_millennium; +#endif + +#endif /* __MATROXFB_TI3026_H__ */ diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c new file mode 100644 index 000000000000..c7f3e1321224 --- /dev/null +++ b/drivers/video/matrox/matroxfb_accel.c @@ -0,0 +1,497 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 + * + * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Version: 1.65 2002/08/14 + * + * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> + * + * Contributors: "menion?" <menion@mindless.com> + * Betatesting, fixes, ideas + * + * "Kurt Garloff" <garloff@suse.de> + * Betatesting, fixes, ideas, videomodes, videomodes timmings + * + * "Tom Rini" <trini@kernel.crashing.org> + * MTRR stuff, PPC cleanups, betatesting, fixes, ideas + * + * "Bibek Sahu" <scorpio@dodds.net> + * Access device through readb|w|l and write b|w|l + * Extensive debugging stuff + * + * "Daniel Haun" <haund@usa.net> + * Testing, hardware cursor fixes + * + * "Scott Wood" <sawst46+@pitt.edu> + * Fixes + * + * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> + * Betatesting + * + * "Kelly French" <targon@hazmat.com> + * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> + * Betatesting, bug reporting + * + * "Pablo Bianucci" <pbian@pccp.com.ar> + * Fixes, ideas, betatesting + * + * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> + * Fixes, enhandcements, ideas, betatesting + * + * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> + * PPC betatesting, PPC support, backward compatibility + * + * "Paul Womar" <Paul@pwomar.demon.co.uk> + * "Owen Waller" <O.Waller@ee.qub.ac.uk> + * PPC betatesting + * + * "Thomas Pornin" <pornin@bolet.ens.fr> + * Alpha betatesting + * + * "Pieter van Leuven" <pvl@iae.nl> + * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> + * G100 testing + * + * "H. Peter Arvin" <hpa@transmeta.com> + * Ideas + * + * "Cort Dougan" <cort@cs.nmt.edu> + * CHRP fixes and PReP cleanup + * + * "Mark Vojkovich" <mvojkovi@ucsd.edu> + * G400 support + * + * (following author is not in any relation with this code, but his code + * is included in this driver) + * + * Based on framebuffer driver for VBE 2.0 compliant graphic boards + * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + * + * (following author is not in any relation with this code, but his ideas + * were used when writting this driver) + * + * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> + * + */ + +#include "matroxfb_accel.h" +#include "matroxfb_DAC1064.h" +#include "matroxfb_Ti3026.h" +#include "matroxfb_misc.h" + +#define curr_ydstorg(x) ACCESS_FBINFO2(x, curr.ydstorg.pixels) + +#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l)) + +static inline void matrox_cfb4_pal(u_int32_t* pal) { + unsigned int i; + + for (i = 0; i < 16; i++) { + pal[i] = i * 0x11111111U; + } + pal[i] = 0xFFFFFFFF; +} + +static inline void matrox_cfb8_pal(u_int32_t* pal) { + unsigned int i; + + for (i = 0; i < 16; i++) { + pal[i] = i * 0x01010101U; + } + pal[i] = 0x0F0F0F0F; +} + +static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area); +static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect); +static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image); +static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect); +static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area); + +void matrox_cfbX_init(WPMINFO2) { + u_int32_t maccess; + u_int32_t mpitch; + u_int32_t mopmode; + int accel; + + DBG(__FUNCTION__) + + mpitch = ACCESS_FBINFO(fbcon).var.xres_virtual; + + ACCESS_FBINFO(fbops).fb_copyarea = cfb_copyarea; + ACCESS_FBINFO(fbops).fb_fillrect = cfb_fillrect; + ACCESS_FBINFO(fbops).fb_imageblit = cfb_imageblit; + ACCESS_FBINFO(fbops).fb_cursor = soft_cursor; + + accel = (ACCESS_FBINFO(fbcon).var.accel_flags & FB_ACCELF_TEXT) == FB_ACCELF_TEXT; + + switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { + case 4: maccess = 0x00000000; /* accelerate as 8bpp video */ + mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */ + mopmode = M_OPMODE_4BPP; + matrox_cfb4_pal(ACCESS_FBINFO(cmap)); + if (accel && !(mpitch & 1)) { + ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_cfb4_copyarea; + ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_cfb4_fillrect; + } + break; + case 8: maccess = 0x00000000; + mopmode = M_OPMODE_8BPP; + matrox_cfb8_pal(ACCESS_FBINFO(cmap)); + if (accel) { + ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; + ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; + ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit; + } + break; + case 16: if (ACCESS_FBINFO(fbcon).var.green.length == 5) { + maccess = 0xC0000001; + ACCESS_FBINFO(cmap[16]) = 0x7FFF7FFF; + } else { + maccess = 0x40000001; + ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF; + } + mopmode = M_OPMODE_16BPP; + if (accel) { + ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; + ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; + ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit; + } + break; + case 24: maccess = 0x00000003; + mopmode = M_OPMODE_24BPP; + ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF; + if (accel) { + ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; + ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; + ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit; + } + break; + case 32: maccess = 0x00000002; + mopmode = M_OPMODE_32BPP; + ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF; + if (accel) { + ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; + ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; + ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit; + } + break; + default: maccess = 0x00000000; + mopmode = 0x00000000; + break; /* turn off acceleration!!! */ + } + mga_fifo(8); + mga_outl(M_PITCH, mpitch); + mga_outl(M_YDSTORG, curr_ydstorg(MINFO)); + if (ACCESS_FBINFO(capable.plnwt)) + mga_outl(M_PLNWT, -1); + if (ACCESS_FBINFO(capable.srcorg)) { + mga_outl(M_SRCORG, 0); + mga_outl(M_DSTORG, 0); + } + mga_outl(M_OPMODE, mopmode); + mga_outl(M_CXBNDRY, 0xFFFF0000); + mga_outl(M_YTOP, 0); + mga_outl(M_YBOT, 0x01FFFFFF); + mga_outl(M_MACCESS, maccess); + ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO; + if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC; + ACCESS_FBINFO(accel.m_opmode) = mopmode; +} + +EXPORT_SYMBOL(matrox_cfbX_init); + +static void matrox_accel_bmove(WPMINFO int vxres, int sy, int sx, int dy, int dx, int height, int width) { + int start, end; + CRITFLAGS + + DBG(__FUNCTION__) + + CRITBEGIN + + if ((dy < sy) || ((dy == sy) && (dx <= sx))) { + mga_fifo(2); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | + M_DWG_BFCOL | M_DWG_REPLACE); + mga_outl(M_AR5, vxres); + width--; + start = sy*vxres+sx+curr_ydstorg(MINFO); + end = start+width; + } else { + mga_fifo(3); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); + mga_outl(M_SGN, 5); + mga_outl(M_AR5, -vxres); + width--; + end = (sy+height-1)*vxres+sx+curr_ydstorg(MINFO); + start = end+width; + dy += height-1; + } + mga_fifo(4); + mga_outl(M_AR0, end); + mga_outl(M_AR3, start); + mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); + mga_ydstlen(dy, height); + WaitTillIdle(); + + CRITEND +} + +static void matrox_accel_bmove_lin(WPMINFO int vxres, int sy, int sx, int dy, int dx, int height, int width) { + int start, end; + CRITFLAGS + + DBG(__FUNCTION__) + + CRITBEGIN + + if ((dy < sy) || ((dy == sy) && (dx <= sx))) { + mga_fifo(2); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | + M_DWG_BFCOL | M_DWG_REPLACE); + mga_outl(M_AR5, vxres); + width--; + start = sy*vxres+sx+curr_ydstorg(MINFO); + end = start+width; + } else { + mga_fifo(3); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); + mga_outl(M_SGN, 5); + mga_outl(M_AR5, -vxres); + width--; + end = (sy+height-1)*vxres+sx+curr_ydstorg(MINFO); + start = end+width; + dy += height-1; + } + mga_fifo(5); + mga_outl(M_AR0, end); + mga_outl(M_AR3, start); + mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); + mga_outl(M_YDST, dy*vxres >> 5); + mga_outl(M_LEN | M_EXEC, height); + WaitTillIdle(); + + CRITEND +} + +static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area) { + MINFO_FROM_INFO(info); + + if ((area->sx | area->dx | area->width) & 1) + cfb_copyarea(info, area); + else + matrox_accel_bmove_lin(PMINFO ACCESS_FBINFO(fbcon.var.xres_virtual) >> 1, area->sy, area->sx >> 1, area->dy, area->dx >> 1, area->height, area->width >> 1); +} + +static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area) { + MINFO_FROM_INFO(info); + + matrox_accel_bmove(PMINFO ACCESS_FBINFO(fbcon.var.xres_virtual), area->sy, area->sx, area->dy, area->dx, area->height, area->width); +} + +static void matroxfb_accel_clear(WPMINFO u_int32_t color, int sy, int sx, int height, + int width) { + CRITFLAGS + + DBG(__FUNCTION__) + + CRITBEGIN + + mga_fifo(5); + mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE); + mga_outl(M_FCOL, color); + mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); + mga_ydstlen(sy, height); + WaitTillIdle(); + + CRITEND +} + +static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect) { + MINFO_FROM_INFO(info); + + switch (rect->rop) { + case ROP_COPY: + matroxfb_accel_clear(PMINFO ((u_int32_t*)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width); + break; + } +} + +static void matroxfb_cfb4_clear(WPMINFO u_int32_t bgx, int sy, int sx, int height, int width) { + int whattodo; + CRITFLAGS + + DBG(__FUNCTION__) + + CRITBEGIN + + whattodo = 0; + if (sx & 1) { + sx ++; + if (!width) return; + width --; + whattodo = 1; + } + if (width & 1) { + whattodo |= 2; + } + width >>= 1; + sx >>= 1; + if (width) { + mga_fifo(5); + mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2); + mga_outl(M_FCOL, bgx); + mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); + mga_outl(M_YDST, sy * ACCESS_FBINFO(fbcon).var.xres_virtual >> 6); + mga_outl(M_LEN | M_EXEC, height); + WaitTillIdle(); + } + if (whattodo) { + u_int32_t step = ACCESS_FBINFO(fbcon).var.xres_virtual >> 1; + vaddr_t vbase = ACCESS_FBINFO(video.vbase); + if (whattodo & 1) { + unsigned int uaddr = sy * step + sx - 1; + u_int32_t loop; + u_int8_t bgx2 = bgx & 0xF0; + for (loop = height; loop > 0; loop --) { + mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2); + uaddr += step; + } + } + if (whattodo & 2) { + unsigned int uaddr = sy * step + sx + width; + u_int32_t loop; + u_int8_t bgx2 = bgx & 0x0F; + for (loop = height; loop > 0; loop --) { + mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2); + uaddr += step; + } + } + } + + CRITEND +} + +static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect) { + MINFO_FROM_INFO(info); + + switch (rect->rop) { + case ROP_COPY: + matroxfb_cfb4_clear(PMINFO ((u_int32_t*)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width); + break; + } +} + +static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx, + const u_int8_t* chardata, int width, int height, int yy, int xx) { + u_int32_t step; + u_int32_t ydstlen; + u_int32_t xlen; + u_int32_t ar0; + u_int32_t charcell; + u_int32_t fxbndry; + vaddr_t mmio; + int easy; + CRITFLAGS + + DBG_HEAVY(__FUNCTION__); + + step = (width + 7) >> 3; + charcell = height * step; + xlen = (charcell + 3) & ~3; + ydstlen = (yy << 16) | height; + if (width == step << 3) { + ar0 = height * width - 1; + easy = 1; + } else { + ar0 = width - 1; + easy = 0; + } + + CRITBEGIN + + mga_fifo(3); + if (easy) + mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); + else + mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE); + mga_outl(M_FCOL, fgx); + mga_outl(M_BCOL, bgx); + fxbndry = ((xx + width - 1) << 16) | xx; + mmio = ACCESS_FBINFO(mmio.vbase); + + mga_fifo(6); + mga_writel(mmio, M_FXBNDRY, fxbndry); + mga_writel(mmio, M_AR0, ar0); + mga_writel(mmio, M_AR3, 0); + if (easy) { + mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); + mga_memcpy_toio(mmio, chardata, xlen); + } else { + mga_writel(mmio, M_AR5, 0); + mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); + if ((step & 3) == 0) { + /* Great. Source has 32bit aligned lines, so we can feed them + directly to the accelerator. */ + mga_memcpy_toio(mmio, chardata, charcell); + } else if (step == 1) { + /* Special case for 1..8bit widths */ + while (height--) { +#if defined(__BIG_ENDIAN) + fb_writel((*chardata) << 24, mmio.vaddr); +#else + fb_writel(*chardata, mmio.vaddr); +#endif + chardata++; + } + } else if (step == 2) { + /* Special case for 9..15bit widths */ + while (height--) { +#if defined(__BIG_ENDIAN) + fb_writel((*(u_int16_t*)chardata) << 16, mmio.vaddr); +#else + fb_writel(*(u_int16_t*)chardata, mmio.vaddr); +#endif + chardata += 2; + } + } else { + /* Tell... well, why bother... */ + while (height--) { + size_t i; + + for (i = 0; i < step; i += 4) { + /* Hope that there are at least three readable bytes beyond the end of bitmap */ + fb_writel(get_unaligned((u_int32_t*)(chardata + i)),mmio.vaddr); + } + chardata += step; + } + } + } + WaitTillIdle(); + CRITEND +} + + +static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) { + MINFO_FROM_INFO(info); + + DBG_HEAVY(__FUNCTION__); + + if (image->depth == 1) { + u_int32_t fgx, bgx; + + fgx = ((u_int32_t*)info->pseudo_palette)[image->fg_color]; + bgx = ((u_int32_t*)info->pseudo_palette)[image->bg_color]; + matroxfb_1bpp_imageblit(PMINFO fgx, bgx, image->data, image->width, image->height, image->dy, image->dx); + } else { + /* Danger! image->depth is useless: logo painting code always + passes framebuffer color depth here, although logo data are + always 8bpp and info->pseudo_palette is changed to contain + logo palette to be used (but only for true/direct-color... sic...). + So do it completely in software... */ + cfb_imageblit(info, image); + } +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/matrox/matroxfb_accel.h b/drivers/video/matrox/matroxfb_accel.h new file mode 100644 index 000000000000..f40c314b4c30 --- /dev/null +++ b/drivers/video/matrox/matroxfb_accel.h @@ -0,0 +1,8 @@ +#ifndef __MATROXFB_ACCEL_H__ +#define __MATROXFB_ACCEL_H__ + +#include "matroxfb_base.h" + +void matrox_cfbX_init(WPMINFO2); + +#endif diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c new file mode 100644 index 000000000000..98e00d8601e5 --- /dev/null +++ b/drivers/video/matrox/matroxfb_base.c @@ -0,0 +1,2589 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 + * + * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Portions Copyright (c) 2001 Matrox Graphics Inc. + * + * Version: 1.65 2002/08/14 + * + * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> + * + * Contributors: "menion?" <menion@mindless.com> + * Betatesting, fixes, ideas + * + * "Kurt Garloff" <garloff@suse.de> + * Betatesting, fixes, ideas, videomodes, videomodes timmings + * + * "Tom Rini" <trini@kernel.crashing.org> + * MTRR stuff, PPC cleanups, betatesting, fixes, ideas + * + * "Bibek Sahu" <scorpio@dodds.net> + * Access device through readb|w|l and write b|w|l + * Extensive debugging stuff + * + * "Daniel Haun" <haund@usa.net> + * Testing, hardware cursor fixes + * + * "Scott Wood" <sawst46+@pitt.edu> + * Fixes + * + * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> + * Betatesting + * + * "Kelly French" <targon@hazmat.com> + * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> + * Betatesting, bug reporting + * + * "Pablo Bianucci" <pbian@pccp.com.ar> + * Fixes, ideas, betatesting + * + * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> + * Fixes, enhandcements, ideas, betatesting + * + * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> + * PPC betatesting, PPC support, backward compatibility + * + * "Paul Womar" <Paul@pwomar.demon.co.uk> + * "Owen Waller" <O.Waller@ee.qub.ac.uk> + * PPC betatesting + * + * "Thomas Pornin" <pornin@bolet.ens.fr> + * Alpha betatesting + * + * "Pieter van Leuven" <pvl@iae.nl> + * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> + * G100 testing + * + * "H. Peter Arvin" <hpa@transmeta.com> + * Ideas + * + * "Cort Dougan" <cort@cs.nmt.edu> + * CHRP fixes and PReP cleanup + * + * "Mark Vojkovich" <mvojkovi@ucsd.edu> + * G400 support + * + * "Samuel Hocevar" <sam@via.ecp.fr> + * Fixes + * + * "Anton Altaparmakov" <AntonA@bigfoot.com> + * G400 MAX/non-MAX distinction + * + * "Ken Aaker" <kdaaker@rchland.vnet.ibm.com> + * memtype extension (needed for GXT130P RS/6000 adapter) + * + * "Uns Lider" <unslider@miranda.org> + * G100 PLNWT fixes + * + * "Denis Zaitsev" <zzz@cd-club.ru> + * Fixes + * + * "Mike Pieper" <mike@pieper-family.de> + * TVOut enhandcements, V4L2 control interface. + * + * "Diego Biurrun" <diego@biurrun.de> + * DFP testing + * + * (following author is not in any relation with this code, but his code + * is included in this driver) + * + * Based on framebuffer driver for VBE 2.0 compliant graphic boards + * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + * + * (following author is not in any relation with this code, but his ideas + * were used when writting this driver) + * + * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> + * + */ + +/* make checkconfig does not check included files... */ +#include <linux/config.h> +#include <linux/version.h> + +#include "matroxfb_base.h" +#include "matroxfb_misc.h" +#include "matroxfb_accel.h" +#include "matroxfb_DAC1064.h" +#include "matroxfb_Ti3026.h" +#include "matroxfb_maven.h" +#include "matroxfb_crtc2.h" +#include "matroxfb_g450.h" +#include <linux/matroxfb.h> +#include <linux/interrupt.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_PPC_PMAC +unsigned char nvram_read_byte(int); +static int default_vmode = VMODE_NVRAM; +static int default_cmode = CMODE_NVRAM; +#endif + +static void matroxfb_unregister_device(struct matrox_fb_info* minfo); + +/* --------------------------------------------------------------------- */ + +/* + * card parameters + */ + +/* --------------------------------------------------------------------- */ + +static struct fb_var_screeninfo vesafb_defined = { + 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/ + 0,0, /* virtual -> visible no offset */ + 8, /* depth -> load bits_per_pixel */ + 0, /* greyscale ? */ + {0,0,0}, /* R */ + {0,0,0}, /* G */ + {0,0,0}, /* B */ + {0,0,0}, /* transparency */ + 0, /* standard pixel format */ + FB_ACTIVATE_NOW, + -1,-1, + FB_ACCELF_TEXT, /* accel flags */ + 39721L,48L,16L,33L,10L, + 96L,2L,~0, /* No sync info */ + FB_VMODE_NONINTERLACED, + 0, {0,0,0,0,0} +}; + + + +/* --------------------------------------------------------------------- */ +static void update_crtc2(WPMINFO unsigned int pos) { + struct matroxfb_dh_fb_info* info = ACCESS_FBINFO(crtc2.info); + + /* Make sure that displays are compatible */ + if (info && (info->fbcon.var.bits_per_pixel == ACCESS_FBINFO(fbcon).var.bits_per_pixel) + && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual) + && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length) + ) { + switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { + case 16: + case 32: + pos = pos * 8; + if (info->interlaced) { + mga_outl(0x3C2C, pos); + mga_outl(0x3C28, pos + ACCESS_FBINFO(fbcon).var.xres_virtual * ACCESS_FBINFO(fbcon).var.bits_per_pixel / 8); + } else { + mga_outl(0x3C28, pos); + } + break; + } + } +} + +static void matroxfb_crtc1_panpos(WPMINFO2) { + if (ACCESS_FBINFO(crtc1.panpos) >= 0) { + unsigned long flags; + int panpos; + + matroxfb_DAC_lock_irqsave(flags); + panpos = ACCESS_FBINFO(crtc1.panpos); + if (panpos >= 0) { + unsigned int extvga_reg; + + ACCESS_FBINFO(crtc1.panpos) = -1; /* No update pending anymore */ + extvga_reg = mga_inb(M_EXTVGA_INDEX); + mga_setr(M_EXTVGA_INDEX, 0x00, panpos); + if (extvga_reg != 0x00) { + mga_outb(M_EXTVGA_INDEX, extvga_reg); + } + } + matroxfb_DAC_unlock_irqrestore(flags); + } +} + +static irqreturn_t matrox_irq(int irq, void *dev_id, struct pt_regs *fp) +{ + u_int32_t status; + int handled = 0; + + MINFO_FROM(dev_id); + + status = mga_inl(M_STATUS); + + if (status & 0x20) { + mga_outl(M_ICLEAR, 0x20); + ACCESS_FBINFO(crtc1.vsync.cnt)++; + matroxfb_crtc1_panpos(PMINFO2); + wake_up_interruptible(&ACCESS_FBINFO(crtc1.vsync.wait)); + handled = 1; + } + if (status & 0x200) { + mga_outl(M_ICLEAR, 0x200); + ACCESS_FBINFO(crtc2.vsync.cnt)++; + wake_up_interruptible(&ACCESS_FBINFO(crtc2.vsync.wait)); + handled = 1; + } + return IRQ_RETVAL(handled); +} + +int matroxfb_enable_irq(WPMINFO int reenable) { + u_int32_t bm; + + if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) + bm = 0x220; + else + bm = 0x020; + + if (!test_and_set_bit(0, &ACCESS_FBINFO(irq_flags))) { + if (request_irq(ACCESS_FBINFO(pcidev)->irq, matrox_irq, + SA_SHIRQ, "matroxfb", MINFO)) { + clear_bit(0, &ACCESS_FBINFO(irq_flags)); + return -EINVAL; + } + /* Clear any pending field interrupts */ + mga_outl(M_ICLEAR, bm); + mga_outl(M_IEN, mga_inl(M_IEN) | bm); + } else if (reenable) { + u_int32_t ien; + + ien = mga_inl(M_IEN); + if ((ien & bm) != bm) { + printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien); + mga_outl(M_IEN, ien | bm); + } + } + return 0; +} + +static void matroxfb_disable_irq(WPMINFO2) { + if (test_and_clear_bit(0, &ACCESS_FBINFO(irq_flags))) { + /* Flush pending pan-at-vbl request... */ + matroxfb_crtc1_panpos(PMINFO2); + if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) + mga_outl(M_IEN, mga_inl(M_IEN) & ~0x220); + else + mga_outl(M_IEN, mga_inl(M_IEN) & ~0x20); + free_irq(ACCESS_FBINFO(pcidev)->irq, MINFO); + } +} + +int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc) { + wait_queue_t __wait; + struct matrox_vsync *vs; + unsigned int cnt; + int ret; + + switch (crtc) { + case 0: + vs = &ACCESS_FBINFO(crtc1.vsync); + break; + case 1: + if (ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG400) { + return -ENODEV; + } + vs = &ACCESS_FBINFO(crtc2.vsync); + break; + default: + return -ENODEV; + } + ret = matroxfb_enable_irq(PMINFO 0); + if (ret) { + return ret; + } + init_waitqueue_entry(&__wait, current); + + cnt = vs->cnt; + ret = wait_event_interruptible_timeout(vs->wait, cnt != vs->cnt, HZ/10); + if (ret < 0) { + return ret; + } + if (ret == 0) { + matroxfb_enable_irq(PMINFO 1); + return -ETIMEDOUT; + } + return 0; +} + +/* --------------------------------------------------------------------- */ + +static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) { + unsigned int pos; + unsigned short p0, p1, p2; +#ifdef CONFIG_FB_MATROX_32MB + unsigned int p3; +#endif + int vbl; + unsigned long flags; + + CRITFLAGS + + DBG(__FUNCTION__) + + if (ACCESS_FBINFO(dead)) + return; + + ACCESS_FBINFO(fbcon).var.xoffset = var->xoffset; + ACCESS_FBINFO(fbcon).var.yoffset = var->yoffset; + pos = (ACCESS_FBINFO(fbcon).var.yoffset * ACCESS_FBINFO(fbcon).var.xres_virtual + ACCESS_FBINFO(fbcon).var.xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; + pos += ACCESS_FBINFO(curr.ydstorg.chunks); + p0 = ACCESS_FBINFO(hw).CRTC[0x0D] = pos & 0xFF; + p1 = ACCESS_FBINFO(hw).CRTC[0x0C] = (pos & 0xFF00) >> 8; + p2 = ACCESS_FBINFO(hw).CRTCEXT[0] = (ACCESS_FBINFO(hw).CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); +#ifdef CONFIG_FB_MATROX_32MB + p3 = ACCESS_FBINFO(hw).CRTCEXT[8] = pos >> 21; +#endif + + /* FB_ACTIVATE_VBL and we can acquire interrupts? Honor FB_ACTIVATE_VBL then... */ + vbl = (var->activate & FB_ACTIVATE_VBL) && (matroxfb_enable_irq(PMINFO 0) == 0); + + CRITBEGIN + + matroxfb_DAC_lock_irqsave(flags); + mga_setr(M_CRTC_INDEX, 0x0D, p0); + mga_setr(M_CRTC_INDEX, 0x0C, p1); +#ifdef CONFIG_FB_MATROX_32MB + if (ACCESS_FBINFO(devflags.support32MB)) + mga_setr(M_EXTVGA_INDEX, 0x08, p3); +#endif + if (vbl) { + ACCESS_FBINFO(crtc1.panpos) = p2; + } else { + /* Abort any pending change */ + ACCESS_FBINFO(crtc1.panpos) = -1; + mga_setr(M_EXTVGA_INDEX, 0x00, p2); + } + matroxfb_DAC_unlock_irqrestore(flags); + + update_crtc2(PMINFO pos); + + CRITEND +} + +static void matroxfb_remove(WPMINFO int dummy) { + /* Currently we are holding big kernel lock on all dead & usecount updates. + * Destroy everything after all users release it. Especially do not unregister + * framebuffer and iounmap memory, neither fbmem nor fbcon-cfb* does not check + * for device unplugged when in use. + * In future we should point mmio.vbase & video.vbase somewhere where we can + * write data without causing too much damage... + */ + + ACCESS_FBINFO(dead) = 1; + if (ACCESS_FBINFO(usecount)) { + /* destroy it later */ + return; + } + matroxfb_unregister_device(MINFO); + unregister_framebuffer(&ACCESS_FBINFO(fbcon)); + matroxfb_g450_shutdown(PMINFO2); +#ifdef CONFIG_MTRR + if (ACCESS_FBINFO(mtrr.vram_valid)) + mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len)); +#endif + mga_iounmap(ACCESS_FBINFO(mmio.vbase)); + mga_iounmap(ACCESS_FBINFO(video.vbase)); + release_mem_region(ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len_maximum)); + release_mem_region(ACCESS_FBINFO(mmio.base), 16384); +#ifdef CONFIG_FB_MATROX_MULTIHEAD + kfree(minfo); +#endif +} + + /* + * Open/Release the frame buffer device + */ + +static int matroxfb_open(struct fb_info *info, int user) +{ + MINFO_FROM_INFO(info); + + DBG_LOOP(__FUNCTION__) + + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + ACCESS_FBINFO(usecount)++; + if (user) { + ACCESS_FBINFO(userusecount)++; + } + return(0); +} + +static int matroxfb_release(struct fb_info *info, int user) +{ + MINFO_FROM_INFO(info); + + DBG_LOOP(__FUNCTION__) + + if (user) { + if (0 == --ACCESS_FBINFO(userusecount)) { + matroxfb_disable_irq(PMINFO2); + } + } + if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) { + matroxfb_remove(PMINFO 0); + } + return(0); +} + +static int matroxfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info* info) { + MINFO_FROM_INFO(info); + + DBG(__FUNCTION__) + + matrox_pan_var(PMINFO var); + return 0; +} + +static int matroxfb_get_final_bppShift(CPMINFO int bpp) { + int bppshft2; + + DBG(__FUNCTION__) + + bppshft2 = bpp; + if (!bppshft2) { + return 8; + } + if (isInterleave(MINFO)) + bppshft2 >>= 1; + if (ACCESS_FBINFO(devflags.video64bits)) + bppshft2 >>= 1; + return bppshft2; +} + +static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) { + int over; + int rounding; + + DBG(__FUNCTION__) + + switch (bpp) { + case 0: return xres; + case 4: rounding = 128; + break; + case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */ + break; + case 16: rounding = 32; + break; + case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */ + break; + default: rounding = 16; + /* on G400, 16 really does not work */ + if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) + rounding = 32; + break; + } + if (isInterleave(MINFO)) { + rounding *= 2; + } + over = xres % rounding; + if (over) + xres += rounding-over; + return xres; +} + +static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) { + const int* width; + int xres_new; + + DBG(__FUNCTION__) + + if (!bpp) return xres; + + width = ACCESS_FBINFO(capable.vxres); + + if (ACCESS_FBINFO(devflags.precise_width)) { + while (*width) { + if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) { + break; + } + width++; + } + xres_new = *width; + } else { + xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp); + } + if (!xres_new) return 0; + if (xres != xres_new) { + printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new); + } + return xres_new; +} + +static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) { + + DBG(__FUNCTION__) + + switch (var->bits_per_pixel) { + case 4: + return 16; /* pseudocolor... 16 entries HW palette */ + case 8: + return 256; /* pseudocolor... 256 entries HW palette */ + case 16: + return 16; /* directcolor... 16 entries SW palette */ + /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ + case 24: + return 16; /* directcolor... 16 entries SW palette */ + /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ + case 32: + return 16; /* directcolor... 16 entries SW palette */ + /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ + } + return 16; /* return something reasonable... or panic()? */ +} + +static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) { + struct RGBT { + unsigned char bpp; + struct { + unsigned char offset, + length; + } red, + green, + blue, + transp; + signed char visual; + }; + static const struct RGBT table[]= { + { 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR}, + {15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR}, + {16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR}, + {24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR}, + {32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR} + }; + struct RGBT const *rgbt; + unsigned int bpp = var->bits_per_pixel; + unsigned int vramlen; + unsigned int memlen; + + DBG(__FUNCTION__) + + switch (bpp) { + case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL; + break; + case 8: break; + case 16: break; + case 24: break; + case 32: break; + default: return -EINVAL; + } + *ydstorg = 0; + vramlen = ACCESS_FBINFO(video.len_usable); + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + + var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, bpp); + memlen = var->xres_virtual * bpp * var->yres_virtual / 8; + if (memlen > vramlen) { + var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp); + memlen = var->xres_virtual * bpp * var->yres_virtual / 8; + } + /* There is hardware bug that no line can cross 4MB boundary */ + /* give up for CFB24, it is impossible to easy workaround it */ + /* for other try to do something */ + if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) { + if (bpp == 24) { + /* sorry */ + } else { + unsigned int linelen; + unsigned int m1 = linelen = var->xres_virtual * bpp / 8; + unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */ + unsigned int max_yres; + + while (m1) { + int t; + + while (m2 >= m1) m2 -= m1; + t = m1; + m1 = m2; + m2 = t; + } + m2 = linelen * PAGE_SIZE / m2; + *ydstorg = m2 = 0x400000 % m2; + max_yres = (vramlen - m2) / linelen; + if (var->yres_virtual > max_yres) + var->yres_virtual = max_yres; + } + } + /* YDSTLEN contains only signed 16bit value */ + if (var->yres_virtual > 32767) + var->yres_virtual = 32767; + /* we must round yres/xres down, we already rounded y/xres_virtual up + if it was possible. We should return -EINVAL, but I disagree */ + if (var->yres_virtual < var->yres) + var->yres = var->yres_virtual; + if (var->xres_virtual < var->xres) + var->xres = var->xres_virtual; + if (var->xoffset + var->xres > var->xres_virtual) + var->xoffset = var->xres_virtual - var->xres; + if (var->yoffset + var->yres > var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres; + + if (bpp == 16 && var->green.length == 5) { + bpp--; /* an artifical value - 15 */ + } + + for (rgbt = table; rgbt->bpp < bpp; rgbt++); +#define SETCLR(clr)\ + var->clr.offset = rgbt->clr.offset;\ + var->clr.length = rgbt->clr.length + SETCLR(red); + SETCLR(green); + SETCLR(blue); + SETCLR(transp); +#undef SETCLR + *visual = rgbt->visual; + + if (bpp > 8) + dprintk("matroxfb: truecolor: " + "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", + var->transp.length, var->red.length, var->green.length, var->blue.length, + var->transp.offset, var->red.offset, var->green.offset, var->blue.offset); + + *video_cmap_len = matroxfb_get_cmap_len(var); + dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel, + var->xres_virtual, var->yres_virtual); + return 0; +} + +static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info) +{ +#ifdef CONFIG_FB_MATROX_MULTIHEAD + struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon); +#endif + + DBG(__FUNCTION__) + + /* + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return + * != 0 for invalid regno. + */ + + if (regno >= ACCESS_FBINFO(curr.cmap_len)) + return 1; + + if (ACCESS_FBINFO(fbcon).var.grayscale) { + /* gray = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + red = CNVT_TOHW(red, ACCESS_FBINFO(fbcon).var.red.length); + green = CNVT_TOHW(green, ACCESS_FBINFO(fbcon).var.green.length); + blue = CNVT_TOHW(blue, ACCESS_FBINFO(fbcon).var.blue.length); + transp = CNVT_TOHW(transp, ACCESS_FBINFO(fbcon).var.transp.length); + + switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { + case 4: + case 8: + mga_outb(M_DAC_REG, regno); + mga_outb(M_DAC_VAL, red); + mga_outb(M_DAC_VAL, green); + mga_outb(M_DAC_VAL, blue); + break; + case 16: + { + u_int16_t col = + (red << ACCESS_FBINFO(fbcon).var.red.offset) | + (green << ACCESS_FBINFO(fbcon).var.green.offset) | + (blue << ACCESS_FBINFO(fbcon).var.blue.offset) | + (transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* for 1:5:5:5 */ + ACCESS_FBINFO(cmap[regno]) = col | (col << 16); + } + break; + case 24: + case 32: + ACCESS_FBINFO(cmap[regno]) = + (red << ACCESS_FBINFO(fbcon).var.red.offset) | + (green << ACCESS_FBINFO(fbcon).var.green.offset) | + (blue << ACCESS_FBINFO(fbcon).var.blue.offset) | + (transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* 8:8:8:8 */ + break; + } + return 0; +} + +static void matroxfb_init_fix(WPMINFO2) +{ + struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; + DBG(__FUNCTION__) + + strcpy(fix->id,"MATROX"); + + fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */ + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->mmio_start = ACCESS_FBINFO(mmio.base); + fix->mmio_len = ACCESS_FBINFO(mmio.len); + fix->accel = ACCESS_FBINFO(devflags.accelerator); +} + +static void matroxfb_update_fix(WPMINFO2) +{ + struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; + DBG(__FUNCTION__) + + fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); + fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); +} + +static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + int err; + int visual; + int cmap_len; + unsigned int ydstorg; + MINFO_FROM_INFO(info); + + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len, &ydstorg)) != 0) + return err; + return 0; +} + +static int matroxfb_set_par(struct fb_info *info) +{ + int err; + int visual; + int cmap_len; + unsigned int ydstorg; + struct fb_var_screeninfo *var; + MINFO_FROM_INFO(info); + + DBG(__FUNCTION__) + + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + + var = &info->var; + if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len, &ydstorg)) != 0) + return err; + ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg; + matroxfb_update_fix(PMINFO2); + ACCESS_FBINFO(fbcon).fix.visual = visual; + ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_PACKED_PIXELS; + ACCESS_FBINFO(fbcon).fix.type_aux = 0; + ACCESS_FBINFO(fbcon).fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; + { + unsigned int pos; + + ACCESS_FBINFO(curr.cmap_len) = cmap_len; + ydstorg += ACCESS_FBINFO(devflags.ydstorg); + ACCESS_FBINFO(curr.ydstorg.bytes) = ydstorg; + ACCESS_FBINFO(curr.ydstorg.chunks) = ydstorg >> (isInterleave(MINFO)?3:2); + if (var->bits_per_pixel == 4) + ACCESS_FBINFO(curr.ydstorg.pixels) = ydstorg; + else + ACCESS_FBINFO(curr.ydstorg.pixels) = (ydstorg * 8) / var->bits_per_pixel; + ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel); + { struct my_timming mt; + struct matrox_hw_state* hw; + int out; + + matroxfb_var2my(var, &mt); + mt.crtc = MATROXFB_SRC_CRTC1; + /* CRTC1 delays */ + switch (var->bits_per_pixel) { + case 0: mt.delay = 31 + 0; break; + case 16: mt.delay = 21 + 8; break; + case 24: mt.delay = 17 + 8; break; + case 32: mt.delay = 16 + 8; break; + default: mt.delay = 31 + 8; break; + } + + hw = &ACCESS_FBINFO(hw); + + down_read(&ACCESS_FBINFO(altout).lock); + for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { + if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 && + ACCESS_FBINFO(outputs[out]).output->compute) { + ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt); + } + } + up_read(&ACCESS_FBINFO(altout).lock); + ACCESS_FBINFO(crtc1).pixclock = mt.pixclock; + ACCESS_FBINFO(crtc1).mnp = mt.mnp; + ACCESS_FBINFO(hw_switch->init(PMINFO &mt)); + pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; + pos += ACCESS_FBINFO(curr.ydstorg.chunks); + + hw->CRTC[0x0D] = pos & 0xFF; + hw->CRTC[0x0C] = (pos & 0xFF00) >> 8; + hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); + hw->CRTCEXT[8] = pos >> 21; + ACCESS_FBINFO(hw_switch->restore(PMINFO2)); + update_crtc2(PMINFO pos); + down_read(&ACCESS_FBINFO(altout).lock); + for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { + if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 && + ACCESS_FBINFO(outputs[out]).output->program) { + ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data); + } + } + for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { + if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 && + ACCESS_FBINFO(outputs[out]).output->start) { + ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data); + } + } + up_read(&ACCESS_FBINFO(altout).lock); + matrox_cfbX_init(PMINFO2); + } + } + ACCESS_FBINFO(initialized) = 1; + return 0; +} + +static int matroxfb_get_vblank(WPMINFO struct fb_vblank *vblank) +{ + unsigned int sts1; + + matroxfb_enable_irq(PMINFO 0); + memset(vblank, 0, sizeof(*vblank)); + vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC | + FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_HBLANK; + sts1 = mga_inb(M_INSTS1); + vblank->vcount = mga_inl(M_VCOUNT); + /* BTW, on my PIII/450 with G400, reading M_INSTS1 + byte makes this call about 12% slower (1.70 vs. 2.05 us + per ioctl()) */ + if (sts1 & 1) + vblank->flags |= FB_VBLANK_HBLANKING; + if (sts1 & 8) + vblank->flags |= FB_VBLANK_VSYNCING; + if (vblank->vcount >= ACCESS_FBINFO(fbcon).var.yres) + vblank->flags |= FB_VBLANK_VBLANKING; + if (test_bit(0, &ACCESS_FBINFO(irq_flags))) { + vblank->flags |= FB_VBLANK_HAVE_COUNT; + /* Only one writer, aligned int value... + it should work without lock and without atomic_t */ + vblank->count = ACCESS_FBINFO(crtc1).vsync.cnt; + } + return 0; +} + +static struct matrox_altout panellink_output = { + .name = "Panellink output", +}; + +static int matroxfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + struct fb_info *info) +{ + void __user *argp = (void __user *)arg; + MINFO_FROM_INFO(info); + + DBG(__FUNCTION__) + + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + + switch (cmd) { + case FBIOGET_VBLANK: + { + struct fb_vblank vblank; + int err; + + err = matroxfb_get_vblank(PMINFO &vblank); + if (err) + return err; + if (copy_to_user(argp, &vblank, sizeof(vblank))) + return -EFAULT; + return 0; + } + case FBIO_WAITFORVSYNC: + { + u_int32_t crt; + + if (get_user(crt, (u_int32_t __user *)arg)) + return -EFAULT; + + return matroxfb_wait_for_sync(PMINFO crt); + } + case MATROXFB_SET_OUTPUT_MODE: + { + struct matroxioc_output_mode mom; + struct matrox_altout *oproc; + int val; + + if (copy_from_user(&mom, argp, sizeof(mom))) + return -EFAULT; + if (mom.output >= MATROXFB_MAX_OUTPUTS) + return -ENXIO; + down_read(&ACCESS_FBINFO(altout.lock)); + oproc = ACCESS_FBINFO(outputs[mom.output]).output; + if (!oproc) { + val = -ENXIO; + } else if (!oproc->verifymode) { + if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) { + val = 0; + } else { + val = -EINVAL; + } + } else { + val = oproc->verifymode(ACCESS_FBINFO(outputs[mom.output]).data, mom.mode); + } + if (!val) { + if (ACCESS_FBINFO(outputs[mom.output]).mode != mom.mode) { + ACCESS_FBINFO(outputs[mom.output]).mode = mom.mode; + val = 1; + } + } + up_read(&ACCESS_FBINFO(altout.lock)); + if (val != 1) + return val; + switch (ACCESS_FBINFO(outputs[mom.output]).src) { + case MATROXFB_SRC_CRTC1: + matroxfb_set_par(info); + break; + case MATROXFB_SRC_CRTC2: + { + struct matroxfb_dh_fb_info* crtc2; + + down_read(&ACCESS_FBINFO(crtc2.lock)); + crtc2 = ACCESS_FBINFO(crtc2.info); + if (crtc2) + crtc2->fbcon.fbops->fb_set_par(&crtc2->fbcon); + up_read(&ACCESS_FBINFO(crtc2.lock)); + } + break; + } + return 0; + } + case MATROXFB_GET_OUTPUT_MODE: + { + struct matroxioc_output_mode mom; + struct matrox_altout *oproc; + int val; + + if (copy_from_user(&mom, argp, sizeof(mom))) + return -EFAULT; + if (mom.output >= MATROXFB_MAX_OUTPUTS) + return -ENXIO; + down_read(&ACCESS_FBINFO(altout.lock)); + oproc = ACCESS_FBINFO(outputs[mom.output]).output; + if (!oproc) { + val = -ENXIO; + } else { + mom.mode = ACCESS_FBINFO(outputs[mom.output]).mode; + val = 0; + } + up_read(&ACCESS_FBINFO(altout.lock)); + if (val) + return val; + if (copy_to_user(argp, &mom, sizeof(mom))) + return -EFAULT; + return 0; + } + case MATROXFB_SET_OUTPUT_CONNECTION: + { + u_int32_t tmp; + int i; + int changes; + + if (copy_from_user(&tmp, argp, sizeof(tmp))) + return -EFAULT; + for (i = 0; i < 32; i++) { + if (tmp & (1 << i)) { + if (i >= MATROXFB_MAX_OUTPUTS) + return -ENXIO; + if (!ACCESS_FBINFO(outputs[i]).output) + return -ENXIO; + switch (ACCESS_FBINFO(outputs[i]).src) { + case MATROXFB_SRC_NONE: + case MATROXFB_SRC_CRTC1: + break; + default: + return -EBUSY; + } + } + } + if (ACCESS_FBINFO(devflags.panellink)) { + if (tmp & MATROXFB_OUTPUT_CONN_DFP) { + if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY) + return -EINVAL; + for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { + if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC2) { + return -EBUSY; + } + } + } + } + changes = 0; + for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { + if (tmp & (1 << i)) { + if (ACCESS_FBINFO(outputs[i]).src != MATROXFB_SRC_CRTC1) { + changes = 1; + ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_CRTC1; + } + } else if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) { + changes = 1; + ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_NONE; + } + } + if (!changes) + return 0; + matroxfb_set_par(info); + return 0; + } + case MATROXFB_GET_OUTPUT_CONNECTION: + { + u_int32_t conn = 0; + int i; + + for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { + if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) { + conn |= 1 << i; + } + } + if (put_user(conn, (u_int32_t __user *)arg)) + return -EFAULT; + return 0; + } + case MATROXFB_GET_AVAILABLE_OUTPUTS: + { + u_int32_t conn = 0; + int i; + + for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { + if (ACCESS_FBINFO(outputs[i]).output) { + switch (ACCESS_FBINFO(outputs[i]).src) { + case MATROXFB_SRC_NONE: + case MATROXFB_SRC_CRTC1: + conn |= 1 << i; + break; + } + } + } + if (ACCESS_FBINFO(devflags.panellink)) { + if (conn & MATROXFB_OUTPUT_CONN_DFP) + conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY; + if (conn & MATROXFB_OUTPUT_CONN_SECONDARY) + conn &= ~MATROXFB_OUTPUT_CONN_DFP; + } + if (put_user(conn, (u_int32_t __user *)arg)) + return -EFAULT; + return 0; + } + case MATROXFB_GET_ALL_OUTPUTS: + { + u_int32_t conn = 0; + int i; + + for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { + if (ACCESS_FBINFO(outputs[i]).output) { + conn |= 1 << i; + } + } + if (put_user(conn, (u_int32_t __user *)arg)) + return -EFAULT; + return 0; + } + case VIDIOC_QUERYCAP: + { + struct v4l2_capability r; + + memset(&r, 0, sizeof(r)); + strcpy(r.driver, "matroxfb"); + strcpy(r.card, "Matrox"); + sprintf(r.bus_info, "PCI:%s", pci_name(ACCESS_FBINFO(pcidev))); + r.version = KERNEL_VERSION(1,0,0); + r.capabilities = V4L2_CAP_VIDEO_OUTPUT; + if (copy_to_user(argp, &r, sizeof(r))) + return -EFAULT; + return 0; + + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl qctrl; + int err; + + if (copy_from_user(&qctrl, argp, sizeof(qctrl))) + return -EFAULT; + + down_read(&ACCESS_FBINFO(altout).lock); + if (!ACCESS_FBINFO(outputs[1]).output) { + err = -ENXIO; + } else if (ACCESS_FBINFO(outputs[1]).output->getqueryctrl) { + err = ACCESS_FBINFO(outputs[1]).output->getqueryctrl(ACCESS_FBINFO(outputs[1]).data, &qctrl); + } else { + err = -EINVAL; + } + up_read(&ACCESS_FBINFO(altout).lock); + if (err >= 0 && + copy_to_user(argp, &qctrl, sizeof(qctrl))) + return -EFAULT; + return err; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control ctrl; + int err; + + if (copy_from_user(&ctrl, argp, sizeof(ctrl))) + return -EFAULT; + + down_read(&ACCESS_FBINFO(altout).lock); + if (!ACCESS_FBINFO(outputs[1]).output) { + err = -ENXIO; + } else if (ACCESS_FBINFO(outputs[1]).output->getctrl) { + err = ACCESS_FBINFO(outputs[1]).output->getctrl(ACCESS_FBINFO(outputs[1]).data, &ctrl); + } else { + err = -EINVAL; + } + up_read(&ACCESS_FBINFO(altout).lock); + if (err >= 0 && + copy_to_user(argp, &ctrl, sizeof(ctrl))) + return -EFAULT; + return err; + } + case VIDIOC_S_CTRL_OLD: + case VIDIOC_S_CTRL: + { + struct v4l2_control ctrl; + int err; + + if (copy_from_user(&ctrl, argp, sizeof(ctrl))) + return -EFAULT; + + down_read(&ACCESS_FBINFO(altout).lock); + if (!ACCESS_FBINFO(outputs[1]).output) { + err = -ENXIO; + } else if (ACCESS_FBINFO(outputs[1]).output->setctrl) { + err = ACCESS_FBINFO(outputs[1]).output->setctrl(ACCESS_FBINFO(outputs[1]).data, &ctrl); + } else { + err = -EINVAL; + } + up_read(&ACCESS_FBINFO(altout).lock); + return err; + } + } + return -ENOTTY; +} + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ + +static int matroxfb_blank(int blank, struct fb_info *info) +{ + int seq; + int crtc; + CRITFLAGS + MINFO_FROM_INFO(info); + + DBG(__FUNCTION__) + + if (ACCESS_FBINFO(dead)) + return 1; + + switch (blank) { + case FB_BLANK_NORMAL: seq = 0x20; crtc = 0x00; break; /* works ??? */ + case FB_BLANK_VSYNC_SUSPEND: seq = 0x20; crtc = 0x10; break; + case FB_BLANK_HSYNC_SUSPEND: seq = 0x20; crtc = 0x20; break; + case FB_BLANK_POWERDOWN: seq = 0x20; crtc = 0x30; break; + default: seq = 0x00; crtc = 0x00; break; + } + + CRITBEGIN + + mga_outb(M_SEQ_INDEX, 1); + mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq); + mga_outb(M_EXTVGA_INDEX, 1); + mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc); + + CRITEND + return 0; +} + +static struct fb_ops matroxfb_ops = { + .owner = THIS_MODULE, + .fb_open = matroxfb_open, + .fb_release = matroxfb_release, + .fb_check_var = matroxfb_check_var, + .fb_set_par = matroxfb_set_par, + .fb_setcolreg = matroxfb_setcolreg, + .fb_pan_display =matroxfb_pan_display, + .fb_blank = matroxfb_blank, + .fb_ioctl = matroxfb_ioctl, +/* .fb_fillrect = <set by matrox_cfbX_init>, */ +/* .fb_copyarea = <set by matrox_cfbX_init>, */ +/* .fb_imageblit = <set by matrox_cfbX_init>, */ +/* .fb_cursor = <set by matrox_cfbX_init>, */ +}; + +#define RSDepth(X) (((X) >> 8) & 0x0F) +#define RS8bpp 0x1 +#define RS15bpp 0x2 +#define RS16bpp 0x3 +#define RS32bpp 0x4 +#define RS4bpp 0x5 +#define RS24bpp 0x6 +#define RSText 0x7 +#define RSText8 0x8 +/* 9-F */ +static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] = { + { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 8 }, + { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 }, + { { 11, 5, 0}, { 5, 6, 0}, { 0, 5, 0}, { 0, 0, 0}, 16 }, + { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 }, + { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 }, + { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 }, + { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode with (default) VGA8x16 */ + { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode hardwired to VGA8x8 */ +}; + +/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */ +static unsigned int mem; /* "matrox:mem:xxxxxM" */ +static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */ +static int inv24; /* "matrox:inv24" */ +static int cross4MB = -1; /* "matrox:cross4MB" */ +static int disabled; /* "matrox:disabled" */ +static int noaccel; /* "matrox:noaccel" */ +static int nopan; /* "matrox:nopan" */ +static int no_pci_retry; /* "matrox:nopciretry" */ +static int novga; /* "matrox:novga" */ +static int nobios; /* "matrox:nobios" */ +static int noinit = 1; /* "matrox:init" */ +static int inverse; /* "matrox:inverse" */ +static int sgram; /* "matrox:sgram" */ +#ifdef CONFIG_MTRR +static int mtrr = 1; /* "matrox:nomtrr" */ +#endif +static int grayscale; /* "matrox:grayscale" */ +static int dev = -1; /* "matrox:dev:xxxxx" */ +static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */ +static int depth = -1; /* "matrox:depth:xxxxx" */ +static unsigned int xres; /* "matrox:xres:xxxxx" */ +static unsigned int yres; /* "matrox:yres:xxxxx" */ +static unsigned int upper = ~0; /* "matrox:upper:xxxxx" */ +static unsigned int lower = ~0; /* "matrox:lower:xxxxx" */ +static unsigned int vslen; /* "matrox:vslen:xxxxx" */ +static unsigned int left = ~0; /* "matrox:left:xxxxx" */ +static unsigned int right = ~0; /* "matrox:right:xxxxx" */ +static unsigned int hslen; /* "matrox:hslen:xxxxx" */ +static unsigned int pixclock; /* "matrox:pixclock:xxxxx" */ +static int sync = -1; /* "matrox:sync:xxxxx" */ +static unsigned int fv; /* "matrox:fv:xxxxx" */ +static unsigned int fh; /* "matrox:fh:xxxxxk" */ +static unsigned int maxclk; /* "matrox:maxclk:xxxxM" */ +static int dfp; /* "matrox:dfp */ +static int dfp_type = -1; /* "matrox:dfp:xxx */ +static int memtype = -1; /* "matrox:memtype:xxx" */ +static char outputs[8]; /* "matrox:outputs:xxx" */ + +#ifndef MODULE +static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */ +#endif + +static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSize){ + vaddr_t vm; + unsigned int offs; + unsigned int offs2; + unsigned char store; + unsigned char bytes[32]; + unsigned char* tmp; + + DBG(__FUNCTION__) + + vm = ACCESS_FBINFO(video.vbase); + maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */ + /* at least 2MB */ + if (maxSize < 0x0200000) return 0; + if (maxSize > 0x2000000) maxSize = 0x2000000; + + mga_outb(M_EXTVGA_INDEX, 0x03); + mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80); + + store = mga_readb(vm, 0x1234); + tmp = bytes; + for (offs = 0x100000; offs < maxSize; offs += 0x200000) + *tmp++ = mga_readb(vm, offs); + for (offs = 0x100000; offs < maxSize; offs += 0x200000) + mga_writeb(vm, offs, 0x02); + if (ACCESS_FBINFO(features.accel.has_cacheflush)) + mga_outb(M_CACHEFLUSH, 0x00); + else + mga_writeb(vm, 0x1234, 0x99); + for (offs = 0x100000; offs < maxSize; offs += 0x200000) { + if (mga_readb(vm, offs) != 0x02) + break; + mga_writeb(vm, offs, mga_readb(vm, offs) - 0x02); + if (mga_readb(vm, offs)) + break; + } + tmp = bytes; + for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000) + mga_writeb(vm, offs2, *tmp++); + mga_writeb(vm, 0x1234, store); + + mga_outb(M_EXTVGA_INDEX, 0x03); + mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80); + + *realSize = offs - 0x100000; +#ifdef CONFIG_FB_MATROX_MILLENIUM + ACCESS_FBINFO(interleave) = !(!isMillenium(MINFO) || ((offs - 0x100000) & 0x3FFFFF)); +#endif + return 1; +} + +struct video_board { + int maxvram; + int maxdisplayable; + int accelID; + struct matrox_switch* lowlevel; + }; +#ifdef CONFIG_FB_MATROX_MILLENIUM +static struct video_board vbMillennium = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W, &matrox_millennium}; +static struct video_board vbMillennium2 = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W, &matrox_millennium}; +static struct video_board vbMillennium2A = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millennium}; +#endif /* CONFIG_FB_MATROX_MILLENIUM */ +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static struct video_board vbMystique = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG, &matrox_mystique}; +#endif /* CONFIG_FB_MATROX_MYSTIQUE */ +#ifdef CONFIG_FB_MATROX_G +static struct video_board vbG100 = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100, &matrox_G100}; +static struct video_board vbG200 = {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200, &matrox_G100}; +#ifdef CONFIG_FB_MATROX_32MB +/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for + whole 32MB */ +static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100}; +#else +static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100}; +#endif +#endif + +#define DEVF_VIDEO64BIT 0x0001 +#define DEVF_SWAPS 0x0002 +#define DEVF_SRCORG 0x0004 +#define DEVF_DUALHEAD 0x0008 +#define DEVF_CROSS4MB 0x0010 +#define DEVF_TEXT4B 0x0020 +/* #define DEVF_recycled 0x0040 */ +/* #define DEVF_recycled 0x0080 */ +#define DEVF_SUPPORT32MB 0x0100 +#define DEVF_ANY_VXRES 0x0200 +#define DEVF_TEXT16B 0x0400 +#define DEVF_CRTC2 0x0800 +#define DEVF_MAVEN_CAPABLE 0x1000 +#define DEVF_PANELLINK_CAPABLE 0x2000 +#define DEVF_G450DAC 0x4000 + +#define DEVF_GCORE (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB) +#define DEVF_G2CORE (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG | DEVF_DUALHEAD) +#define DEVF_G100 (DEVF_GCORE) /* no doc, no vxres... */ +#define DEVF_G200 (DEVF_G2CORE) +#define DEVF_G400 (DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2) +/* if you'll find how to drive DFP... */ +#define DEVF_G450 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG | DEVF_DUALHEAD) +#define DEVF_G550 (DEVF_G450) + +static struct board { + unsigned short vendor, device, rev, svid, sid; + unsigned int flags; + unsigned int maxclk; + enum mga_chip chip; + struct video_board* base; + const char* name; + } dev_list[] = { +#ifdef CONFIG_FB_MATROX_MILLENIUM + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 0xFF, + 0, 0, + DEVF_TEXT4B, + 230000, + MGA_2064, + &vbMillennium, + "Millennium (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 0xFF, + 0, 0, + DEVF_SWAPS, + 220000, + MGA_2164, + &vbMillennium2, + "Millennium II (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 0xFF, + 0, 0, + DEVF_SWAPS, + 250000, + MGA_2164, + &vbMillennium2A, + "Millennium II (AGP)"}, +#endif +#ifdef CONFIG_FB_MATROX_MYSTIQUE + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0x02, + 0, 0, + DEVF_VIDEO64BIT | DEVF_CROSS4MB, + 180000, + MGA_1064, + &vbMystique, + "Mystique (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0xFF, + 0, 0, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + MGA_1164, + &vbMystique, + "Mystique 220 (PCI)"}, +#endif +#ifdef CONFIG_FB_MATROX_G + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, 0xFF, + 0, 0, + DEVF_G100, + 230000, + MGA_G100, + &vbG100, + "MGA-G100 (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, + 0, 0, + DEVF_G100, + 230000, + MGA_G100, + &vbG100, + "MGA-G100 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF, + 0, 0, + DEVF_G200, + 250000, + MGA_G200, + &vbG200, + "MGA-G200 (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC, + DEVF_G200, + 220000, + MGA_G200, + &vbG200, + "MGA-G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP, + DEVF_G200, + 230000, + MGA_G200, + &vbG200, + "Mystique G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENIUM_G200_AGP, + DEVF_G200, + 250000, + MGA_G200, + &vbG200, + "Millennium G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MARVEL_G200_AGP, + DEVF_G200, + 230000, + MGA_G200, + &vbG200, + "Marvel G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G200_AGP, + DEVF_G200, + 230000, + MGA_G200, + &vbG200, + "MGA-G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + 0, 0, + DEVF_G200, + 230000, + MGA_G200, + &vbG200, + "G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0x80, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP, + DEVF_G400, + 360000, + MGA_G400, + &vbG400, + "Millennium G400 MAX (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0x80, + 0, 0, + DEVF_G400, + 300000, + MGA_G400, + &vbG400, + "G400 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0xFF, + 0, 0, + DEVF_G450, + 360000, + MGA_G450, + &vbG400, + "G450"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, 0xFF, + 0, 0, + DEVF_G550, + 360000, + MGA_G550, + &vbG400, + "G550"}, +#endif + {0, 0, 0xFF, + 0, 0, + 0, + 0, + 0, + NULL, + NULL}}; + +#ifndef MODULE +static struct fb_videomode defaultmode = { + /* 640x480 @ 60Hz, 31.5 kHz */ + NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, + 0, FB_VMODE_NONINTERLACED +}; +#endif /* !MODULE */ + +static int hotplug = 0; + +static void setDefaultOutputs(WPMINFO2) { + unsigned int i; + const char* ptr; + + ACCESS_FBINFO(outputs[0]).default_src = MATROXFB_SRC_CRTC1; + if (ACCESS_FBINFO(devflags.g450dac)) { + ACCESS_FBINFO(outputs[1]).default_src = MATROXFB_SRC_CRTC1; + ACCESS_FBINFO(outputs[2]).default_src = MATROXFB_SRC_CRTC1; + } else if (dfp) { + ACCESS_FBINFO(outputs[2]).default_src = MATROXFB_SRC_CRTC1; + } + ptr = outputs; + for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { + char c = *ptr++; + + if (c == 0) { + break; + } + if (c == '0') { + ACCESS_FBINFO(outputs[i]).default_src = MATROXFB_SRC_NONE; + } else if (c == '1') { + ACCESS_FBINFO(outputs[i]).default_src = MATROXFB_SRC_CRTC1; + } else if (c == '2' && ACCESS_FBINFO(devflags.crtc2)) { + ACCESS_FBINFO(outputs[i]).default_src = MATROXFB_SRC_CRTC2; + } else { + printk(KERN_ERR "matroxfb: Unknown outputs setting\n"); + break; + } + } + /* Nullify this option for subsequent adapters */ + outputs[0] = 0; +} + +static int initMatrox2(WPMINFO struct board* b){ + unsigned long ctrlptr_phys = 0; + unsigned long video_base_phys = 0; + unsigned int memsize; + int err; + + static struct pci_device_id intel_82437[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437) }, + { }, + }; + + DBG(__FUNCTION__) + + /* set default values... */ + vesafb_defined.accel_flags = FB_ACCELF_TEXT; + + ACCESS_FBINFO(hw_switch) = b->base->lowlevel; + ACCESS_FBINFO(devflags.accelerator) = b->base->accelID; + ACCESS_FBINFO(max_pixel_clock) = b->maxclk; + + printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name); + ACCESS_FBINFO(capable.plnwt) = 1; + ACCESS_FBINFO(chip) = b->chip; + ACCESS_FBINFO(capable.srcorg) = b->flags & DEVF_SRCORG; + ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT; + if (b->flags & DEVF_TEXT4B) { + ACCESS_FBINFO(devflags.vgastep) = 4; + ACCESS_FBINFO(devflags.textmode) = 4; + ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16; + } else if (b->flags & DEVF_TEXT16B) { + ACCESS_FBINFO(devflags.vgastep) = 16; + ACCESS_FBINFO(devflags.textmode) = 1; + ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16; + } else { + ACCESS_FBINFO(devflags.vgastep) = 8; + ACCESS_FBINFO(devflags.textmode) = 1; + ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8; + } +#ifdef CONFIG_FB_MATROX_32MB + ACCESS_FBINFO(devflags.support32MB) = (b->flags & DEVF_SUPPORT32MB) != 0; +#endif + ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES); + ACCESS_FBINFO(devflags.crtc2) = (b->flags & DEVF_CRTC2) != 0; + ACCESS_FBINFO(devflags.maven_capable) = (b->flags & DEVF_MAVEN_CAPABLE) != 0; + ACCESS_FBINFO(devflags.dualhead) = (b->flags & DEVF_DUALHEAD) != 0; + ACCESS_FBINFO(devflags.dfp_type) = dfp_type; + ACCESS_FBINFO(devflags.g450dac) = (b->flags & DEVF_G450DAC) != 0; + ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode); + ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode); + setDefaultOutputs(PMINFO2); + if (b->flags & DEVF_PANELLINK_CAPABLE) { + ACCESS_FBINFO(outputs[2]).data = MINFO; + ACCESS_FBINFO(outputs[2]).output = &panellink_output; + ACCESS_FBINFO(outputs[2]).src = ACCESS_FBINFO(outputs[2]).default_src; + ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR; + ACCESS_FBINFO(devflags.panellink) = 1; + } + + if (ACCESS_FBINFO(capable.cross4MB) < 0) + ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB; + if (b->flags & DEVF_SWAPS) { + ctrlptr_phys = pci_resource_start(ACCESS_FBINFO(pcidev), 1); + video_base_phys = pci_resource_start(ACCESS_FBINFO(pcidev), 0); + ACCESS_FBINFO(devflags.fbResource) = PCI_BASE_ADDRESS_0; + } else { + ctrlptr_phys = pci_resource_start(ACCESS_FBINFO(pcidev), 0); + video_base_phys = pci_resource_start(ACCESS_FBINFO(pcidev), 1); + ACCESS_FBINFO(devflags.fbResource) = PCI_BASE_ADDRESS_1; + } + err = -EINVAL; + if (!ctrlptr_phys) { + printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n"); + goto fail; + } + if (!video_base_phys) { + printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n"); + goto fail; + } + memsize = b->base->maxvram; + if (!request_mem_region(ctrlptr_phys, 16384, "matroxfb MMIO")) { + goto fail; + } + if (!request_mem_region(video_base_phys, memsize, "matroxfb FB")) { + goto failCtrlMR; + } + ACCESS_FBINFO(video.len_maximum) = memsize; + /* convert mem (autodetect k, M) */ + if (mem < 1024) mem *= 1024; + if (mem < 0x00100000) mem *= 1024; + + if (mem && (mem < memsize)) + memsize = mem; + err = -ENOMEM; + if (mga_ioremap(ctrlptr_phys, 16384, MGA_IOREMAP_MMIO, &ACCESS_FBINFO(mmio.vbase))) { + printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys); + goto failVideoMR; + } + ACCESS_FBINFO(mmio.base) = ctrlptr_phys; + ACCESS_FBINFO(mmio.len) = 16384; + ACCESS_FBINFO(video.base) = video_base_phys; + if (mga_ioremap(video_base_phys, memsize, MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) { + printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", + video_base_phys, memsize); + goto failCtrlIO; + } + { + u_int32_t cmd; + u_int32_t mga_option; + + pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &mga_option); + pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd); + mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */ + mga_option |= MX_OPTION_BSWAP; + /* disable palette snooping */ + cmd &= ~PCI_COMMAND_VGA_PALETTE; + if (pci_dev_present(intel_82437)) { + if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) { + printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n"); + } + mga_option |= 0x20000000; + ACCESS_FBINFO(devflags.nopciretry) = 1; + } + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, cmd); + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mga_option); + ACCESS_FBINFO(hw).MXoptionReg = mga_option; + + /* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */ + /* maybe preinit() candidate, but it is same... for all devices... at this time... */ + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MGA_INDEX, 0x00003C00); + } + + err = -ENXIO; + matroxfb_read_pins(PMINFO2); + if (ACCESS_FBINFO(hw_switch)->preinit(PMINFO2)) { + goto failVideoIO; + } + + err = -ENOMEM; + if (!matroxfb_getmemory(PMINFO memsize, &ACCESS_FBINFO(video.len)) || !ACCESS_FBINFO(video.len)) { + printk(KERN_ERR "matroxfb: cannot determine memory size\n"); + goto failVideoIO; + } + ACCESS_FBINFO(devflags.ydstorg) = 0; + + ACCESS_FBINFO(video.base) = video_base_phys; + ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len); + if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable) + ACCESS_FBINFO(video.len_usable) = b->base->maxdisplayable; +#ifdef CONFIG_MTRR + if (mtrr) { + ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1); + ACCESS_FBINFO(mtrr.vram_valid) = 1; + printk(KERN_INFO "matroxfb: MTRR's turned on\n"); + } +#endif /* CONFIG_MTRR */ + + if (!ACCESS_FBINFO(devflags.novga)) + request_region(0x3C0, 32, "matrox"); + matroxfb_g450_connect(PMINFO2); + ACCESS_FBINFO(hw_switch->reset(PMINFO2)); + + ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0; + ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh; + ACCESS_FBINFO(fbcon.monspecs.vfmin) = 0; + ACCESS_FBINFO(fbcon.monspecs.vfmax) = fv; + ACCESS_FBINFO(fbcon.monspecs.dpms) = 0; /* TBD */ + + /* static settings */ + vesafb_defined.red = colors[depth-1].red; + vesafb_defined.green = colors[depth-1].green; + vesafb_defined.blue = colors[depth-1].blue; + vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel; + vesafb_defined.grayscale = grayscale; + vesafb_defined.vmode = 0; + if (noaccel) + vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT; + + ACCESS_FBINFO(fbops) = matroxfb_ops; + ACCESS_FBINFO(fbcon.fbops) = &ACCESS_FBINFO(fbops); + ACCESS_FBINFO(fbcon.pseudo_palette) = ACCESS_FBINFO(cmap); + /* after __init time we are like module... no logo */ + ACCESS_FBINFO(fbcon.flags) = hotplug ? FBINFO_FLAG_MODULE : FBINFO_FLAG_DEFAULT; + ACCESS_FBINFO(fbcon.flags) |= FBINFO_PARTIAL_PAN_OK | /* Prefer panning for scroll under MC viewer/edit */ + FBINFO_HWACCEL_COPYAREA | /* We have hw-assisted bmove */ + FBINFO_HWACCEL_FILLRECT | /* And fillrect */ + FBINFO_HWACCEL_IMAGEBLIT | /* And imageblit */ + FBINFO_HWACCEL_XPAN | /* And we support both horizontal */ + FBINFO_HWACCEL_YPAN; /* And vertical panning */ + ACCESS_FBINFO(video.len_usable) &= PAGE_MASK; + fb_alloc_cmap(&ACCESS_FBINFO(fbcon.cmap), 256, 1); + +#ifndef MODULE + /* mode database is marked __init!!! */ + if (!hotplug) { + fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL, + NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel); + } +#endif /* !MODULE */ + + /* mode modifiers */ + if (hslen) + vesafb_defined.hsync_len = hslen; + if (vslen) + vesafb_defined.vsync_len = vslen; + if (left != ~0) + vesafb_defined.left_margin = left; + if (right != ~0) + vesafb_defined.right_margin = right; + if (upper != ~0) + vesafb_defined.upper_margin = upper; + if (lower != ~0) + vesafb_defined.lower_margin = lower; + if (xres) + vesafb_defined.xres = xres; + if (yres) + vesafb_defined.yres = yres; + if (sync != -1) + vesafb_defined.sync = sync; + else if (vesafb_defined.sync == ~0) { + vesafb_defined.sync = 0; + if (yres < 400) + vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT; + else if (yres < 480) + vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT; + } + + /* fv, fh, maxclk limits was specified */ + { + unsigned int tmp; + + if (fv) { + tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres + + vesafb_defined.lower_margin + vesafb_defined.vsync_len); + if ((tmp < fh) || (fh == 0)) fh = tmp; + } + if (fh) { + tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres + + vesafb_defined.right_margin + vesafb_defined.hsync_len); + if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp; + } + tmp = (maxclk + 499) / 500; + if (tmp) { + tmp = (2000000000 + tmp) / tmp; + if (tmp > pixclock) pixclock = tmp; + } + } + if (pixclock) { + if (pixclock < 2000) /* > 500MHz */ + pixclock = 4000; /* 250MHz */ + if (pixclock > 1000000) + pixclock = 1000000; /* 1MHz */ + vesafb_defined.pixclock = pixclock; + } + + /* FIXME: Where to move this?! */ +#if defined(CONFIG_PPC_PMAC) +#ifndef MODULE + if (_machine == _MACH_Pmac) { + struct fb_var_screeninfo var; + 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; + if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) { + var.accel_flags = vesafb_defined.accel_flags; + var.xoffset = var.yoffset = 0; + /* Note: mac_vmode_to_var() does not set all parameters */ + vesafb_defined = var; + } + } +#endif /* !MODULE */ +#endif /* CONFIG_PPC_PMAC */ + vesafb_defined.xres_virtual = vesafb_defined.xres; + if (nopan) { + vesafb_defined.yres_virtual = vesafb_defined.yres; + } else { + vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough + to yres_virtual * xres_virtual < 2^32 */ + } + matroxfb_init_fix(PMINFO2); + /* Normalize values (namely yres_virtual) */ + matroxfb_check_var(&vesafb_defined, &ACCESS_FBINFO(fbcon)); + /* And put it into "current" var. Do NOT program hardware yet, or we'll not take over + * vgacon correctly. fbcon_startup will call fb_set_par for us, WITHOUT check_var, + * and unfortunately it will do it BEFORE vgacon contents is saved, so it won't work + * anyway. But we at least tried... */ + ACCESS_FBINFO(fbcon.var) = vesafb_defined; + err = -EINVAL; + + printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n", + vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, + vesafb_defined.xres_virtual, vesafb_defined.yres_virtual); + printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n", + ACCESS_FBINFO(video.base), vaddr_va(ACCESS_FBINFO(video.vbase)), ACCESS_FBINFO(video.len)); + +/* We do not have to set currcon to 0... register_framebuffer do it for us on first console + * and we do not want currcon == 0 for subsequent framebuffers */ + + ACCESS_FBINFO(fbcon).device = &ACCESS_FBINFO(pcidev)->dev; + if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) { + goto failVideoIO; + } + printk("fb%d: %s frame buffer device\n", + ACCESS_FBINFO(fbcon.node), ACCESS_FBINFO(fbcon.fix.id)); + + /* there is no console on this fb... but we have to initialize hardware + * until someone tells me what is proper thing to do */ + if (!ACCESS_FBINFO(initialized)) { + printk(KERN_INFO "fb%d: initializing hardware\n", + ACCESS_FBINFO(fbcon.node)); + /* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var + * already before, so register_framebuffer works correctly. */ + vesafb_defined.activate |= FB_ACTIVATE_FORCE; + fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined); + } + + return 0; +failVideoIO:; + matroxfb_g450_shutdown(PMINFO2); + mga_iounmap(ACCESS_FBINFO(video.vbase)); +failCtrlIO:; + mga_iounmap(ACCESS_FBINFO(mmio.vbase)); +failVideoMR:; + release_mem_region(video_base_phys, ACCESS_FBINFO(video.len_maximum)); +failCtrlMR:; + release_mem_region(ctrlptr_phys, 16384); +fail:; + return err; +} + +static LIST_HEAD(matroxfb_list); +static LIST_HEAD(matroxfb_driver_list); + +#define matroxfb_l(x) list_entry(x, struct matrox_fb_info, next_fb) +#define matroxfb_driver_l(x) list_entry(x, struct matroxfb_driver, node) +int matroxfb_register_driver(struct matroxfb_driver* drv) { + struct matrox_fb_info* minfo; + + list_add(&drv->node, &matroxfb_driver_list); + for (minfo = matroxfb_l(matroxfb_list.next); + minfo != matroxfb_l(&matroxfb_list); + minfo = matroxfb_l(minfo->next_fb.next)) { + void* p; + + if (minfo->drivers_count == MATROXFB_MAX_FB_DRIVERS) + continue; + p = drv->probe(minfo); + if (p) { + minfo->drivers_data[minfo->drivers_count] = p; + minfo->drivers[minfo->drivers_count++] = drv; + } + } + return 0; +} + +void matroxfb_unregister_driver(struct matroxfb_driver* drv) { + struct matrox_fb_info* minfo; + + list_del(&drv->node); + for (minfo = matroxfb_l(matroxfb_list.next); + minfo != matroxfb_l(&matroxfb_list); + minfo = matroxfb_l(minfo->next_fb.next)) { + int i; + + for (i = 0; i < minfo->drivers_count; ) { + if (minfo->drivers[i] == drv) { + if (drv && drv->remove) + drv->remove(minfo, minfo->drivers_data[i]); + minfo->drivers[i] = minfo->drivers[--minfo->drivers_count]; + minfo->drivers_data[i] = minfo->drivers_data[minfo->drivers_count]; + } else + i++; + } + } +} + +static void matroxfb_register_device(struct matrox_fb_info* minfo) { + struct matroxfb_driver* drv; + int i = 0; + list_add(&ACCESS_FBINFO(next_fb), &matroxfb_list); + for (drv = matroxfb_driver_l(matroxfb_driver_list.next); + drv != matroxfb_driver_l(&matroxfb_driver_list); + drv = matroxfb_driver_l(drv->node.next)) { + if (drv && drv->probe) { + void *p = drv->probe(minfo); + if (p) { + minfo->drivers_data[i] = p; + minfo->drivers[i++] = drv; + if (i == MATROXFB_MAX_FB_DRIVERS) + break; + } + } + } + minfo->drivers_count = i; +} + +static void matroxfb_unregister_device(struct matrox_fb_info* minfo) { + int i; + + list_del(&ACCESS_FBINFO(next_fb)); + for (i = 0; i < minfo->drivers_count; i++) { + struct matroxfb_driver* drv = minfo->drivers[i]; + + if (drv && drv->remove) + drv->remove(minfo, minfo->drivers_data[i]); + } +} + +static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) { + struct board* b; + u_int8_t rev; + u_int16_t svid; + u_int16_t sid; + struct matrox_fb_info* minfo; + int err; + u_int32_t cmd; +#ifndef CONFIG_FB_MATROX_MULTIHEAD + static int registered = 0; +#endif + DBG(__FUNCTION__) + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); + svid = pdev->subsystem_vendor; + sid = pdev->subsystem_device; + for (b = dev_list; b->vendor; b++) { + if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue; + if (b->svid) + if ((b->svid != svid) || (b->sid != sid)) continue; + break; + } + /* not match... */ + if (!b->vendor) + return -1; + if (dev > 0) { + /* not requested one... */ + dev--; + return -1; + } + pci_read_config_dword(pdev, PCI_COMMAND, &cmd); + if (pci_enable_device(pdev)) { + return -1; + } + +#ifdef CONFIG_FB_MATROX_MULTIHEAD + minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL); + if (!minfo) + return -1; +#else + if (registered) /* singlehead driver... */ + return -1; + minfo = &matroxfb_global_mxinfo; +#endif + memset(MINFO, 0, sizeof(*MINFO)); + + ACCESS_FBINFO(pcidev) = pdev; + ACCESS_FBINFO(dead) = 0; + ACCESS_FBINFO(usecount) = 0; + ACCESS_FBINFO(userusecount) = 0; + + pci_set_drvdata(pdev, MINFO); + /* DEVFLAGS */ + ACCESS_FBINFO(devflags.memtype) = memtype; + if (memtype != -1) + noinit = 0; + if (cmd & PCI_COMMAND_MEMORY) { + ACCESS_FBINFO(devflags.novga) = novga; + ACCESS_FBINFO(devflags.nobios) = nobios; + ACCESS_FBINFO(devflags.noinit) = noinit; + /* subsequent heads always needs initialization and must not enable BIOS */ + novga = 1; + nobios = 1; + noinit = 0; + } else { + ACCESS_FBINFO(devflags.novga) = 1; + ACCESS_FBINFO(devflags.nobios) = 1; + ACCESS_FBINFO(devflags.noinit) = 0; + } + + ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry; + ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24; + ACCESS_FBINFO(devflags.precise_width) = option_precise_width; + ACCESS_FBINFO(devflags.sgram) = sgram; + ACCESS_FBINFO(capable.cross4MB) = cross4MB; + + spin_lock_init(&ACCESS_FBINFO(lock.DAC)); + spin_lock_init(&ACCESS_FBINFO(lock.accel)); + init_rwsem(&ACCESS_FBINFO(crtc2.lock)); + init_rwsem(&ACCESS_FBINFO(altout.lock)); + ACCESS_FBINFO(irq_flags) = 0; + init_waitqueue_head(&ACCESS_FBINFO(crtc1.vsync.wait)); + init_waitqueue_head(&ACCESS_FBINFO(crtc2.vsync.wait)); + ACCESS_FBINFO(crtc1.panpos) = -1; + + err = initMatrox2(PMINFO b); + if (!err) { +#ifndef CONFIG_FB_MATROX_MULTIHEAD + registered = 1; +#endif + matroxfb_register_device(MINFO); + return 0; + } +#ifdef CONFIG_FB_MATROX_MULTIHEAD + kfree(minfo); +#endif + return -1; +} + +static void pci_remove_matrox(struct pci_dev* pdev) { + struct matrox_fb_info* minfo; + + minfo = pci_get_drvdata(pdev); + matroxfb_remove(PMINFO 1); +} + +static struct pci_device_id matroxfb_devices[] = { +#ifdef CONFIG_FB_MATROX_MILLENIUM + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +#endif +#ifdef CONFIG_FB_MATROX_MYSTIQUE + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +#endif +#ifdef CONFIG_FB_MATROX_G + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +#endif + {0, 0, + 0, 0, 0, 0, 0} +}; + +MODULE_DEVICE_TABLE(pci, matroxfb_devices); + + +static struct pci_driver matroxfb_driver = { + .name = "matroxfb", + .id_table = matroxfb_devices, + .probe = matroxfb_probe, + .remove = pci_remove_matrox, +}; + +/* **************************** init-time only **************************** */ + +#define RSResolution(X) ((X) & 0x0F) +#define RS640x400 1 +#define RS640x480 2 +#define RS800x600 3 +#define RS1024x768 4 +#define RS1280x1024 5 +#define RS1600x1200 6 +#define RS768x576 7 +#define RS960x720 8 +#define RS1152x864 9 +#define RS1408x1056 10 +#define RS640x350 11 +#define RS1056x344 12 /* 132 x 43 text */ +#define RS1056x400 13 /* 132 x 50 text */ +#define RS1056x480 14 /* 132 x 60 text */ +#define RSNoxNo 15 +/* 10-FF */ +static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = { + { 640, 400, 48, 16, 39, 8, 96, 2, 70 }, + { 640, 480, 48, 16, 33, 10, 96, 2, 60 }, + { 800, 600, 144, 24, 28, 8, 112, 6, 60 }, + { 1024, 768, 160, 32, 30, 4, 128, 4, 60 }, + { 1280, 1024, 224, 32, 32, 4, 136, 4, 60 }, + { 1600, 1200, 272, 48, 32, 5, 152, 5, 60 }, + { 768, 576, 144, 16, 28, 6, 112, 4, 60 }, + { 960, 720, 144, 24, 28, 8, 112, 4, 60 }, + { 1152, 864, 192, 32, 30, 4, 128, 4, 60 }, + { 1408, 1056, 256, 40, 32, 5, 144, 5, 60 }, + { 640, 350, 48, 16, 39, 8, 96, 2, 70 }, + { 1056, 344, 96, 24, 59, 44, 160, 2, 70 }, + { 1056, 400, 96, 24, 39, 8, 160, 2, 70 }, + { 1056, 480, 96, 24, 36, 12, 160, 3, 60 }, + { 0, 0, ~0, ~0, ~0, ~0, 0, 0, 0 } +}; + +#define RSCreate(X,Y) ((X) | ((Y) << 8)) +static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = { +/* default must be first */ + { ~0, RSCreate(RSNoxNo, RS8bpp ) }, + { 0x101, RSCreate(RS640x480, RS8bpp ) }, + { 0x100, RSCreate(RS640x400, RS8bpp ) }, + { 0x180, RSCreate(RS768x576, RS8bpp ) }, + { 0x103, RSCreate(RS800x600, RS8bpp ) }, + { 0x188, RSCreate(RS960x720, RS8bpp ) }, + { 0x105, RSCreate(RS1024x768, RS8bpp ) }, + { 0x190, RSCreate(RS1152x864, RS8bpp ) }, + { 0x107, RSCreate(RS1280x1024, RS8bpp ) }, + { 0x198, RSCreate(RS1408x1056, RS8bpp ) }, + { 0x11C, RSCreate(RS1600x1200, RS8bpp ) }, + { 0x110, RSCreate(RS640x480, RS15bpp) }, + { 0x181, RSCreate(RS768x576, RS15bpp) }, + { 0x113, RSCreate(RS800x600, RS15bpp) }, + { 0x189, RSCreate(RS960x720, RS15bpp) }, + { 0x116, RSCreate(RS1024x768, RS15bpp) }, + { 0x191, RSCreate(RS1152x864, RS15bpp) }, + { 0x119, RSCreate(RS1280x1024, RS15bpp) }, + { 0x199, RSCreate(RS1408x1056, RS15bpp) }, + { 0x11D, RSCreate(RS1600x1200, RS15bpp) }, + { 0x111, RSCreate(RS640x480, RS16bpp) }, + { 0x182, RSCreate(RS768x576, RS16bpp) }, + { 0x114, RSCreate(RS800x600, RS16bpp) }, + { 0x18A, RSCreate(RS960x720, RS16bpp) }, + { 0x117, RSCreate(RS1024x768, RS16bpp) }, + { 0x192, RSCreate(RS1152x864, RS16bpp) }, + { 0x11A, RSCreate(RS1280x1024, RS16bpp) }, + { 0x19A, RSCreate(RS1408x1056, RS16bpp) }, + { 0x11E, RSCreate(RS1600x1200, RS16bpp) }, + { 0x1B2, RSCreate(RS640x480, RS24bpp) }, + { 0x184, RSCreate(RS768x576, RS24bpp) }, + { 0x1B5, RSCreate(RS800x600, RS24bpp) }, + { 0x18C, RSCreate(RS960x720, RS24bpp) }, + { 0x1B8, RSCreate(RS1024x768, RS24bpp) }, + { 0x194, RSCreate(RS1152x864, RS24bpp) }, + { 0x1BB, RSCreate(RS1280x1024, RS24bpp) }, + { 0x19C, RSCreate(RS1408x1056, RS24bpp) }, + { 0x1BF, RSCreate(RS1600x1200, RS24bpp) }, + { 0x112, RSCreate(RS640x480, RS32bpp) }, + { 0x183, RSCreate(RS768x576, RS32bpp) }, + { 0x115, RSCreate(RS800x600, RS32bpp) }, + { 0x18B, RSCreate(RS960x720, RS32bpp) }, + { 0x118, RSCreate(RS1024x768, RS32bpp) }, + { 0x193, RSCreate(RS1152x864, RS32bpp) }, + { 0x11B, RSCreate(RS1280x1024, RS32bpp) }, + { 0x19B, RSCreate(RS1408x1056, RS32bpp) }, + { 0x11F, RSCreate(RS1600x1200, RS32bpp) }, + { 0x010, RSCreate(RS640x350, RS4bpp ) }, + { 0x012, RSCreate(RS640x480, RS4bpp ) }, + { 0x102, RSCreate(RS800x600, RS4bpp ) }, + { 0x104, RSCreate(RS1024x768, RS4bpp ) }, + { 0x106, RSCreate(RS1280x1024, RS4bpp ) }, + { 0, 0 }}; + +static void __init matroxfb_init_params(void) { + /* fh from kHz to Hz */ + if (fh < 1000) + fh *= 1000; /* 1kHz minimum */ + /* maxclk */ + if (maxclk < 1000) maxclk *= 1000; /* kHz -> Hz, MHz -> kHz */ + if (maxclk < 1000000) maxclk *= 1000; /* kHz -> Hz, 1MHz minimum */ + /* fix VESA number */ + if (vesa != ~0) + vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */ + + /* static settings */ + for (RSptr = vesamap; RSptr->vesa; RSptr++) { + if (RSptr->vesa == vesa) break; + } + if (!RSptr->vesa) { + printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa); + RSptr = vesamap; + } + { + int res = RSResolution(RSptr->info)-1; + if (left == ~0) + left = timmings[res].left; + if (!xres) + xres = timmings[res].xres; + if (right == ~0) + right = timmings[res].right; + if (!hslen) + hslen = timmings[res].hslen; + if (upper == ~0) + upper = timmings[res].upper; + if (!yres) + yres = timmings[res].yres; + if (lower == ~0) + lower = timmings[res].lower; + if (!vslen) + vslen = timmings[res].vslen; + if (!(fv||fh||maxclk||pixclock)) + fv = timmings[res].vfreq; + if (depth == -1) + depth = RSDepth(RSptr->info); + } +} + +static void __init matrox_init(void) { + matroxfb_init_params(); + pci_register_driver(&matroxfb_driver); + dev = -1; /* accept all new devices... */ +} + +/* **************************** exit-time only **************************** */ + +static void __exit matrox_done(void) { + pci_unregister_driver(&matroxfb_driver); +} + +#ifndef MODULE + +/* ************************* init in-kernel code ************************** */ + +static int __init matroxfb_setup(char *options) { + char *this_opt; + + DBG(__FUNCTION__) + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) continue; + + dprintk("matroxfb_setup: option %s\n", this_opt); + + if (!strncmp(this_opt, "dev:", 4)) + dev = simple_strtoul(this_opt+4, NULL, 0); + else if (!strncmp(this_opt, "depth:", 6)) { + switch (simple_strtoul(this_opt+6, NULL, 0)) { + case 0: depth = RSText; break; + case 4: depth = RS4bpp; break; + case 8: depth = RS8bpp; break; + case 15:depth = RS15bpp; break; + case 16:depth = RS16bpp; break; + case 24:depth = RS24bpp; break; + case 32:depth = RS32bpp; break; + default: + printk(KERN_ERR "matroxfb: unsupported color depth\n"); + } + } 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, "vslen:", 6)) + vslen = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "hslen:", 6)) + hslen = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "left:", 5)) + left = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "right:", 6)) + right = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "upper:", 6)) + upper = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "lower:", 6)) + lower = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "pixclock:", 9)) + pixclock = simple_strtoul(this_opt+9, NULL, 0); + else if (!strncmp(this_opt, "sync:", 5)) + sync = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "vesa:", 5)) + vesa = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "maxclk:", 7)) + maxclk = simple_strtoul(this_opt+7, NULL, 0); + else if (!strncmp(this_opt, "fh:", 3)) + fh = simple_strtoul(this_opt+3, NULL, 0); + else if (!strncmp(this_opt, "fv:", 3)) + fv = simple_strtoul(this_opt+3, NULL, 0); + else if (!strncmp(this_opt, "mem:", 4)) + mem = simple_strtoul(this_opt+4, NULL, 0); + else if (!strncmp(this_opt, "mode:", 5)) + strlcpy(videomode, this_opt+5, sizeof(videomode)); + else if (!strncmp(this_opt, "outputs:", 8)) + strlcpy(outputs, this_opt+8, sizeof(outputs)); + else if (!strncmp(this_opt, "dfp:", 4)) { + dfp_type = simple_strtoul(this_opt+4, NULL, 0); + dfp = 1; + } +#ifdef CONFIG_PPC_PMAC + else if (!strncmp(this_opt, "vmode:", 6)) { + unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + default_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); + switch (cmode) { + case 0: + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + case 24: + case 32: + default_cmode = CMODE_32; + break; + } + } +#endif + else if (!strcmp(this_opt, "disabled")) /* nodisabled does not exist */ + disabled = 1; + else if (!strcmp(this_opt, "enabled")) /* noenabled does not exist */ + disabled = 0; + else if (!strcmp(this_opt, "sgram")) /* nosgram == sdram */ + sgram = 1; + else if (!strcmp(this_opt, "sdram")) + sgram = 0; + else if (!strncmp(this_opt, "memtype:", 8)) + memtype = simple_strtoul(this_opt+8, NULL, 0); + else { + int value = 1; + + if (!strncmp(this_opt, "no", 2)) { + value = 0; + this_opt += 2; + } + if (! strcmp(this_opt, "inverse")) + inverse = value; + else if (!strcmp(this_opt, "accel")) + noaccel = !value; + else if (!strcmp(this_opt, "pan")) + nopan = !value; + else if (!strcmp(this_opt, "pciretry")) + no_pci_retry = !value; + else if (!strcmp(this_opt, "vga")) + novga = !value; + else if (!strcmp(this_opt, "bios")) + nobios = !value; + else if (!strcmp(this_opt, "init")) + noinit = !value; +#ifdef CONFIG_MTRR + else if (!strcmp(this_opt, "mtrr")) + mtrr = value; +#endif + else if (!strcmp(this_opt, "inv24")) + inv24 = value; + else if (!strcmp(this_opt, "cross4MB")) + cross4MB = value; + else if (!strcmp(this_opt, "grayscale")) + grayscale = value; + else if (!strcmp(this_opt, "dfp")) + dfp = value; + else { + strlcpy(videomode, this_opt, sizeof(videomode)); + } + } + } + return 0; +} + +static int __initdata initialized = 0; + +static int __init matroxfb_init(void) +{ + char *option = NULL; + + DBG(__FUNCTION__) + + if (fb_get_options("matroxfb", &option)) + return -ENODEV; + matroxfb_setup(option); + + if (disabled) + return -ENXIO; + if (!initialized) { + initialized = 1; + matrox_init(); + } + hotplug = 1; + /* never return failure, user can hotplug matrox later... */ + return 0; +} + +module_init(matroxfb_init); + +#else + +/* *************************** init module code **************************** */ + +MODULE_AUTHOR("(c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450/G550"); +MODULE_LICENSE("GPL"); + +module_param(mem, int, 0); +MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)"); +module_param(disabled, int, 0); +MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled) (default=0)"); +module_param(noaccel, int, 0); +MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)"); +module_param(nopan, int, 0); +MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)"); +module_param(no_pci_retry, int, 0); +MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)"); +module_param(novga, int, 0); +MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)"); +module_param(nobios, int, 0); +MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)"); +module_param(noinit, int, 0); +MODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)"); +module_param(memtype, int, 0); +MODULE_PARM_DESC(memtype, "Memory type for G200/G400 (see Documentation/fb/matroxfb.txt for explanation) (default=3 for G200, 0 for G400)"); +#ifdef CONFIG_MTRR +module_param(mtrr, int, 0); +MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)"); +#endif +module_param(sgram, int, 0); +MODULE_PARM_DESC(sgram, "Indicates that G100/G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)"); +module_param(inv24, int, 0); +MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)"); +module_param(inverse, int, 0); +MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)"); +#ifdef CONFIG_FB_MATROX_MULTIHEAD +module_param(dev, int, 0); +MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)"); +#else +module_param(dev, int, 0); +MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=first working)"); +#endif +module_param(vesa, int, 0); +MODULE_PARM_DESC(vesa, "Startup videomode (0x000-0x1FF) (default=0x101)"); +module_param(xres, int, 0); +MODULE_PARM_DESC(xres, "Horizontal resolution (px), overrides xres from vesa (default=vesa)"); +module_param(yres, int, 0); +MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)"); +module_param(upper, int, 0); +MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)"); +module_param(lower, int, 0); +MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)"); +module_param(vslen, int, 0); +MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)"); +module_param(left, int, 0); +MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)"); +module_param(right, int, 0); +MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)"); +module_param(hslen, int, 0); +MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)"); +module_param(pixclock, int, 0); +MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)"); +module_param(sync, int, 0); +MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)"); +module_param(depth, int, 0); +MODULE_PARM_DESC(depth, "Color depth (0=text,8,15,16,24,32) (default=vesa)"); +module_param(maxclk, int, 0); +MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz"); +module_param(fh, int, 0); +MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz"); +module_param(fv, int, 0); +MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n" +"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n"); +module_param(grayscale, int, 0); +MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)"); +module_param(cross4MB, int, 0); +MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)"); +module_param(dfp, int, 0); +MODULE_PARM_DESC(dfp, "Specifies whether to use digital flat panel interface of G200/G400 (0 or 1) (default=0)"); +module_param(dfp_type, int, 0); +MODULE_PARM_DESC(dfp_type, "Specifies DFP interface type (0 to 255) (default=read from hardware)"); +module_param_string(outputs, outputs, sizeof(outputs), 0); +MODULE_PARM_DESC(outputs, "Specifies which CRTC is mapped to which output (string of up to three letters, consisting of 0 (disabled), 1 (CRTC1), 2 (CRTC2)) (default=111 for Gx50, 101 for G200/G400 with DFP, and 100 for all other devices)"); +#ifdef CONFIG_PPC_PMAC +module_param_named(vmode, default_vmode, int, 0); +MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)"); +module_param_named(cmode, default_cmode, int, 0); +MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)"); +#endif + +int __init init_module(void){ + + DBG(__FUNCTION__) + + if (disabled) + return -ENXIO; + + if (depth == 0) + depth = RSText; + else if (depth == 4) + depth = RS4bpp; + else if (depth == 8) + depth = RS8bpp; + else if (depth == 15) + depth = RS15bpp; + else if (depth == 16) + depth = RS16bpp; + else if (depth == 24) + depth = RS24bpp; + else if (depth == 32) + depth = RS32bpp; + else if (depth != -1) { + printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth); + depth = -1; + } + matrox_init(); + /* never return failure; user can hotplug matrox later... */ + return 0; +} +#endif /* MODULE */ + +module_exit(matrox_done); +EXPORT_SYMBOL(matroxfb_register_driver); +EXPORT_SYMBOL(matroxfb_unregister_driver); +EXPORT_SYMBOL(matroxfb_wait_for_sync); +EXPORT_SYMBOL(matroxfb_enable_irq); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h new file mode 100644 index 000000000000..85a0b2558452 --- /dev/null +++ b/drivers/video/matrox/matroxfb_base.h @@ -0,0 +1,781 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450 + * + * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> + * + */ +#ifndef __MATROXFB_H__ +#define __MATROXFB_H__ + +/* general, but fairly heavy, debugging */ +#undef MATROXFB_DEBUG + +/* heavy debugging: */ +/* -- logs putc[s], so everytime a char is displayed, it's logged */ +#undef MATROXFB_DEBUG_HEAVY + +/* This one _could_ cause infinite loops */ +/* It _does_ cause lots and lots of messages during idle loops */ +#undef MATROXFB_DEBUG_LOOP + +/* Debug register calls, too? */ +#undef MATROXFB_DEBUG_REG + +/* Guard accelerator accesses with spin_lock_irqsave... */ +#undef MATROXFB_USE_SPINLOCKS + +#include <linux/config.h> +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/console.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/kd.h> + +#include <asm/io.h> +#include <asm/unaligned.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include "../console/fbcon.h" + +#if defined(CONFIG_PPC_PMAC) +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#include "../macmodes.h" +#endif + +/* always compile support for 32MB... It cost almost nothing */ +#define CONFIG_FB_MATROX_32MB + +#ifdef MATROXFB_DEBUG + +#define DEBUG +#define DBG(x) printk(KERN_DEBUG "matroxfb: %s\n", (x)); + +#ifdef MATROXFB_DEBUG_HEAVY +#define DBG_HEAVY(x) DBG(x) +#else /* MATROXFB_DEBUG_HEAVY */ +#define DBG_HEAVY(x) /* DBG_HEAVY */ +#endif /* MATROXFB_DEBUG_HEAVY */ + +#ifdef MATROXFB_DEBUG_LOOP +#define DBG_LOOP(x) DBG(x) +#else /* MATROXFB_DEBUG_LOOP */ +#define DBG_LOOP(x) /* DBG_LOOP */ +#endif /* MATROXFB_DEBUG_LOOP */ + +#ifdef MATROXFB_DEBUG_REG +#define DBG_REG(x) DBG(x) +#else /* MATROXFB_DEBUG_REG */ +#define DBG_REG(x) /* DBG_REG */ +#endif /* MATROXFB_DEBUG_REG */ + +#else /* MATROXFB_DEBUG */ + +#define DBG(x) /* DBG */ +#define DBG_HEAVY(x) /* DBG_HEAVY */ +#define DBG_REG(x) /* DBG_REG */ +#define DBG_LOOP(x) /* DBG_LOOP */ + +#endif /* MATROXFB_DEBUG */ + +#ifdef DEBUG +#define dprintk(X...) printk(X) +#else +#define dprintk(X...) +#endif + +#ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF +#define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF 0x110A +#endif +#ifndef PCI_SS_VENDOR_ID_MATROX +#define PCI_SS_VENDOR_ID_MATROX PCI_VENDOR_ID_MATROX +#endif + +#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP +#define PCI_SS_ID_MATROX_GENERIC 0xFF00 +#define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP 0xFF01 +#define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP 0xFF02 +#define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP 0xFF03 +#define PCI_SS_ID_MATROX_MARVEL_G200_AGP 0xFF04 +#define PCI_SS_ID_MATROX_MGA_G100_PCI 0xFF05 +#define PCI_SS_ID_MATROX_MGA_G100_AGP 0x1001 +#define PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP 0x2179 +#define PCI_SS_ID_SIEMENS_MGA_G100_AGP 0x001E /* 30 */ +#define PCI_SS_ID_SIEMENS_MGA_G200_AGP 0x0032 /* 50 */ +#endif + +#define MX_VISUAL_TRUECOLOR FB_VISUAL_DIRECTCOLOR +#define MX_VISUAL_DIRECTCOLOR FB_VISUAL_TRUECOLOR +#define MX_VISUAL_PSEUDOCOLOR FB_VISUAL_PSEUDOCOLOR + +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) + +/* G-series and Mystique have (almost) same DAC */ +#undef NEED_DAC1064 +#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G) +#define NEED_DAC1064 1 +#endif + +typedef struct { + void __iomem* vaddr; +} vaddr_t; + +static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) { + return readb(va.vaddr + offs); +} + +static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) { + writeb(value, va.vaddr + offs); +} + +static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) { + writew(value, va.vaddr + offs); +} + +static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) { + return readl(va.vaddr + offs); +} + +static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) { + writel(value, va.vaddr + offs); +} + +static inline void mga_memcpy_toio(vaddr_t va, const void* src, int len) { +#if defined(__alpha__) || defined(__i386__) || defined(__x86_64__) + /* + * memcpy_toio works for us if: + * (1) Copies data as 32bit quantities, not byte after byte, + * (2) Performs LE ordered stores, and + * (3) It copes with unaligned source (destination is guaranteed to be page + * aligned and length is guaranteed to be multiple of 4). + */ + memcpy_toio(va.vaddr, src, len); +#else + u_int32_t __iomem* addr = va.vaddr; + + if ((unsigned long)src & 3) { + while (len >= 4) { + fb_writel(get_unaligned((u32 *)src), addr); + addr++; + len -= 4; + src += 4; + } + } else { + while (len >= 4) { + fb_writel(*(u32 *)src, addr); + addr++; + len -= 4; + src += 4; + } + } +#endif +} + +static inline void vaddr_add(vaddr_t* va, unsigned long offs) { + va->vaddr += offs; +} + +static inline void __iomem* vaddr_va(vaddr_t va) { + return va.vaddr; +} + +#define MGA_IOREMAP_NORMAL 0 +#define MGA_IOREMAP_NOCACHE 1 + +#define MGA_IOREMAP_FB MGA_IOREMAP_NOCACHE +#define MGA_IOREMAP_MMIO MGA_IOREMAP_NOCACHE +static inline int mga_ioremap(unsigned long phys, unsigned long size, int flags, vaddr_t* virt) { + if (flags & MGA_IOREMAP_NOCACHE) + virt->vaddr = ioremap_nocache(phys, size); + else + virt->vaddr = ioremap(phys, size); + return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */ +} + +static inline void mga_iounmap(vaddr_t va) { + iounmap(va.vaddr); +} + +struct my_timming { + unsigned int pixclock; + int mnp; + unsigned int crtc; + unsigned int HDisplay; + unsigned int HSyncStart; + unsigned int HSyncEnd; + unsigned int HTotal; + unsigned int VDisplay; + unsigned int VSyncStart; + unsigned int VSyncEnd; + unsigned int VTotal; + unsigned int sync; + int dblscan; + int interlaced; + unsigned int delay; /* CRTC delay */ +}; + +enum { M_SYSTEM_PLL, M_PIXEL_PLL_A, M_PIXEL_PLL_B, M_PIXEL_PLL_C, M_VIDEO_PLL }; + +struct matrox_pll_cache { + unsigned int valid; + struct { + unsigned int mnp_key; + unsigned int mnp_value; + } data[4]; +}; + +struct matrox_pll_limits { + unsigned int vcomin; + unsigned int vcomax; +}; + +struct matrox_pll_features { + unsigned int vco_freq_min; + unsigned int ref_freq; + unsigned int feed_div_min; + unsigned int feed_div_max; + unsigned int in_div_min; + unsigned int in_div_max; + unsigned int post_shift_max; +}; + +struct matroxfb_par +{ + unsigned int final_bppShift; + unsigned int cmap_len; + struct { + unsigned int bytes; + unsigned int pixels; + unsigned int chunks; + } ydstorg; +}; + +struct matrox_fb_info; + +struct matrox_DAC1064_features { + u_int8_t xvrefctrl; + u_int8_t xmiscctrl; +}; + +struct matrox_accel_features { + int has_cacheflush; +}; + +/* current hardware status */ +struct mavenregs { + u_int8_t regs[256]; + int mode; + int vlines; + int xtal; + int fv; + + u_int16_t htotal; + u_int16_t hcorr; +}; + +struct matrox_crtc2 { + u_int32_t ctl; +}; + +struct matrox_hw_state { + u_int32_t MXoptionReg; + unsigned char DACclk[6]; + unsigned char DACreg[80]; + unsigned char MiscOutReg; + unsigned char DACpal[768]; + unsigned char CRTC[25]; + unsigned char CRTCEXT[9]; + unsigned char SEQ[5]; + /* unused for MGA mode, but who knows... */ + unsigned char GCTL[9]; + /* unused for MGA mode, but who knows... */ + unsigned char ATTR[21]; + + /* TVOut only */ + struct mavenregs maven; + + struct matrox_crtc2 crtc2; +}; + +struct matrox_accel_data { +#ifdef CONFIG_FB_MATROX_MILLENIUM + unsigned char ramdac_rev; +#endif + u_int32_t m_dwg_rect; + u_int32_t m_opmode; +}; + +struct v4l2_queryctrl; +struct v4l2_control; + +struct matrox_altout { + const char *name; + int (*compute)(void* altout_dev, struct my_timming* input); + int (*program)(void* altout_dev); + int (*start)(void* altout_dev); + int (*verifymode)(void* altout_dev, u_int32_t mode); + int (*getqueryctrl)(void* altout_dev, + struct v4l2_queryctrl* ctrl); + int (*getctrl)(void* altout_dev, + struct v4l2_control* ctrl); + int (*setctrl)(void* altout_dev, + struct v4l2_control* ctrl); +}; + +#define MATROXFB_SRC_NONE 0 +#define MATROXFB_SRC_CRTC1 1 +#define MATROXFB_SRC_CRTC2 2 + +enum mga_chip { MGA_2064, MGA_2164, MGA_1064, MGA_1164, MGA_G100, MGA_G200, MGA_G400, MGA_G450, MGA_G550 }; + +struct matrox_bios { + unsigned int bios_valid : 1; + unsigned int pins_len; + unsigned char pins[128]; + struct { + unsigned char vMaj, vMin, vRev; + } version; + struct { + unsigned char state, tvout; + } output; +}; + +extern struct display fb_display[]; + +struct matrox_switch; +struct matroxfb_driver; +struct matroxfb_dh_fb_info; + +struct matrox_vsync { + wait_queue_head_t wait; + unsigned int cnt; +}; + +struct matrox_fb_info { + struct fb_info fbcon; + + struct list_head next_fb; + + int dead; + int initialized; + unsigned int usecount; + + unsigned int userusecount; + unsigned long irq_flags; + + struct matroxfb_par curr; + struct matrox_hw_state hw; + + struct matrox_accel_data accel; + + struct pci_dev* pcidev; + + struct { + struct matrox_vsync vsync; + unsigned int pixclock; + int mnp; + int panpos; + } crtc1; + struct { + struct matrox_vsync vsync; + unsigned int pixclock; + int mnp; + struct matroxfb_dh_fb_info* info; + struct rw_semaphore lock; + } crtc2; + struct { + struct rw_semaphore lock; + struct { + int brightness, contrast, saturation, hue, gamma; + int testout, deflicker; + } tvo_params; + } altout; +#define MATROXFB_MAX_OUTPUTS 3 + struct { + unsigned int src; + struct matrox_altout* output; + void* data; + unsigned int mode; + unsigned int default_src; + } outputs[MATROXFB_MAX_OUTPUTS]; + +#define MATROXFB_MAX_FB_DRIVERS 5 + struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]); + void* (drivers_data[MATROXFB_MAX_FB_DRIVERS]); + unsigned int drivers_count; + + struct { + unsigned long base; /* physical */ + vaddr_t vbase; /* CPU view */ + unsigned int len; + unsigned int len_usable; + unsigned int len_maximum; + } video; + + struct { + unsigned long base; /* physical */ + vaddr_t vbase; /* CPU view */ + unsigned int len; + } mmio; + + unsigned int max_pixel_clock; + + struct matrox_switch* hw_switch; + + struct { + struct matrox_pll_features pll; + struct matrox_DAC1064_features DAC1064; + struct matrox_accel_features accel; + } features; + struct { + spinlock_t DAC; + spinlock_t accel; + } lock; + + enum mga_chip chip; + + int interleave; + int millenium; + int milleniumII; + struct { + int cfb4; + const int* vxres; + int cross4MB; + int text; + int plnwt; + int srcorg; + } capable; +#ifdef CONFIG_MTRR + struct { + int vram; + int vram_valid; + } mtrr; +#endif + struct { + int precise_width; + int mga_24bpp_fix; + int novga; + int nobios; + int nopciretry; + int noinit; + int sgram; +#ifdef CONFIG_FB_MATROX_32MB + int support32MB; +#endif + + int accelerator; + int text_type_aux; + int video64bits; + int crtc2; + int maven_capable; + unsigned int vgastep; + unsigned int textmode; + unsigned int textstep; + unsigned int textvram; /* character cells */ + unsigned int ydstorg; /* offset in bytes from video start to usable memory */ + /* 0 except for 6MB Millenium */ + int memtype; + int g450dac; + int dfp_type; + int panellink; /* G400 DFP possible (not G450/G550) */ + int dualhead; + unsigned int fbResource; + } devflags; + struct fb_ops fbops; + struct matrox_bios bios; + struct { + struct matrox_pll_limits pixel; + struct matrox_pll_limits system; + struct matrox_pll_limits video; + } limits; + struct { + struct matrox_pll_cache pixel; + struct matrox_pll_cache system; + struct matrox_pll_cache video; + } cache; + struct { + struct { + unsigned int video; + unsigned int system; + } pll; + struct { + u_int32_t opt; + u_int32_t opt2; + u_int32_t opt3; + u_int32_t mctlwtst; + u_int32_t mctlwtst_core; + u_int32_t memmisc; + u_int32_t memrdbk; + u_int32_t maccess; + } reg; + struct { + unsigned int ddr:1, + emrswen:1, + dll:1; + } memory; + } values; + u_int32_t cmap[17]; +}; + +#define info2minfo(info) container_of(info, struct matrox_fb_info, fbcon) + +#ifdef CONFIG_FB_MATROX_MULTIHEAD +#define ACCESS_FBINFO2(info, x) (info->x) +#define ACCESS_FBINFO(x) ACCESS_FBINFO2(minfo,x) + +#define MINFO minfo + +#define WPMINFO2 struct matrox_fb_info* minfo +#define WPMINFO WPMINFO2 , +#define CPMINFO2 const struct matrox_fb_info* minfo +#define CPMINFO CPMINFO2 , +#define PMINFO2 minfo +#define PMINFO PMINFO2 , + +#define MINFO_FROM(x) struct matrox_fb_info* minfo = x +#else + +extern struct matrox_fb_info matroxfb_global_mxinfo; + +#define ACCESS_FBINFO(x) (matroxfb_global_mxinfo.x) +#define ACCESS_FBINFO2(info, x) (matroxfb_global_mxinfo.x) + +#define MINFO (&matroxfb_global_mxinfo) + +#define WPMINFO2 void +#define WPMINFO +#define CPMINFO2 void +#define CPMINFO +#define PMINFO2 +#define PMINFO + +#define MINFO_FROM(x) + +#endif + +#define MINFO_FROM_INFO(x) MINFO_FROM(info2minfo(x)) + +struct matrox_switch { + int (*preinit)(WPMINFO2); + void (*reset)(WPMINFO2); + int (*init)(WPMINFO struct my_timming*); + void (*restore)(WPMINFO2); +}; + +struct matroxfb_driver { + struct list_head node; + char* name; + void* (*probe)(struct matrox_fb_info* info); + void (*remove)(struct matrox_fb_info* info, void* data); +}; + +int matroxfb_register_driver(struct matroxfb_driver* drv); +void matroxfb_unregister_driver(struct matroxfb_driver* drv); + +#define PCI_OPTION_REG 0x40 +#define PCI_OPTION_ENABLE_ROM 0x40000000 + +#define PCI_MGA_INDEX 0x44 +#define PCI_MGA_DATA 0x48 +#define PCI_OPTION2_REG 0x50 +#define PCI_OPTION3_REG 0x54 +#define PCI_MEMMISC_REG 0x58 + +#define M_DWGCTL 0x1C00 +#define M_MACCESS 0x1C04 +#define M_CTLWTST 0x1C08 + +#define M_PLNWT 0x1C1C + +#define M_BCOL 0x1C20 +#define M_FCOL 0x1C24 + +#define M_SGN 0x1C58 +#define M_LEN 0x1C5C +#define M_AR0 0x1C60 +#define M_AR1 0x1C64 +#define M_AR2 0x1C68 +#define M_AR3 0x1C6C +#define M_AR4 0x1C70 +#define M_AR5 0x1C74 +#define M_AR6 0x1C78 + +#define M_CXBNDRY 0x1C80 +#define M_FXBNDRY 0x1C84 +#define M_YDSTLEN 0x1C88 +#define M_PITCH 0x1C8C +#define M_YDST 0x1C90 +#define M_YDSTORG 0x1C94 +#define M_YTOP 0x1C98 +#define M_YBOT 0x1C9C + +/* mystique only */ +#define M_CACHEFLUSH 0x1FFF + +#define M_EXEC 0x0100 + +#define M_DWG_TRAP 0x04 +#define M_DWG_BITBLT 0x08 +#define M_DWG_ILOAD 0x09 + +#define M_DWG_LINEAR 0x0080 +#define M_DWG_SOLID 0x0800 +#define M_DWG_ARZERO 0x1000 +#define M_DWG_SGNZERO 0x2000 +#define M_DWG_SHIFTZERO 0x4000 + +#define M_DWG_REPLACE 0x000C0000 +#define M_DWG_REPLACE2 (M_DWG_REPLACE | 0x40) +#define M_DWG_XOR 0x00060010 + +#define M_DWG_BFCOL 0x04000000 +#define M_DWG_BMONOWF 0x08000000 + +#define M_DWG_TRANSC 0x40000000 + +#define M_FIFOSTATUS 0x1E10 +#define M_STATUS 0x1E14 +#define M_ICLEAR 0x1E18 +#define M_IEN 0x1E1C + +#define M_VCOUNT 0x1E20 + +#define M_RESET 0x1E40 +#define M_MEMRDBK 0x1E44 + +#define M_AGP2PLL 0x1E4C + +#define M_OPMODE 0x1E54 +#define M_OPMODE_DMA_GEN_WRITE 0x00 +#define M_OPMODE_DMA_BLIT 0x04 +#define M_OPMODE_DMA_VECTOR_WRITE 0x08 +#define M_OPMODE_DMA_LE 0x0000 /* little endian - no transformation */ +#define M_OPMODE_DMA_BE_8BPP 0x0000 +#define M_OPMODE_DMA_BE_16BPP 0x0100 +#define M_OPMODE_DMA_BE_32BPP 0x0200 +#define M_OPMODE_DIR_LE 0x000000 /* little endian - no transformation */ +#define M_OPMODE_DIR_BE_8BPP 0x000000 +#define M_OPMODE_DIR_BE_16BPP 0x010000 +#define M_OPMODE_DIR_BE_32BPP 0x020000 + +#define M_ATTR_INDEX 0x1FC0 +#define M_ATTR_DATA 0x1FC1 + +#define M_MISC_REG 0x1FC2 +#define M_3C2_RD 0x1FC2 + +#define M_SEQ_INDEX 0x1FC4 +#define M_SEQ_DATA 0x1FC5 + +#define M_MISC_REG_READ 0x1FCC + +#define M_GRAPHICS_INDEX 0x1FCE +#define M_GRAPHICS_DATA 0x1FCF + +#define M_CRTC_INDEX 0x1FD4 + +#define M_ATTR_RESET 0x1FDA +#define M_3DA_WR 0x1FDA +#define M_INSTS1 0x1FDA + +#define M_EXTVGA_INDEX 0x1FDE +#define M_EXTVGA_DATA 0x1FDF + +/* G200 only */ +#define M_SRCORG 0x2CB4 +#define M_DSTORG 0x2CB8 + +#define M_RAMDAC_BASE 0x3C00 + +/* fortunately, same on TVP3026 and MGA1064 */ +#define M_DAC_REG (M_RAMDAC_BASE+0) +#define M_DAC_VAL (M_RAMDAC_BASE+1) +#define M_PALETTE_MASK (M_RAMDAC_BASE+2) + +#define M_X_INDEX 0x00 +#define M_X_DATAREG 0x0A + +#define DAC_XGENIOCTRL 0x2A +#define DAC_XGENIODATA 0x2B + +#define M_C2CTL 0x3C10 + +#define MX_OPTION_BSWAP 0x00000000 + +#ifdef __LITTLE_ENDIAN +#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#define M_OPMODE_8BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#define M_OPMODE_16BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#define M_OPMODE_24BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#define M_OPMODE_32BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#else +#ifdef __BIG_ENDIAN +#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) /* TODO */ +#define M_OPMODE_8BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) +#define M_OPMODE_16BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT) +#define M_OPMODE_24BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) /* TODO, ?32 */ +#define M_OPMODE_32BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT) +#else +#error "Byte ordering have to be defined. Cannot continue." +#endif +#endif + +#define mga_inb(addr) mga_readb(ACCESS_FBINFO(mmio.vbase), (addr)) +#define mga_inl(addr) mga_readl(ACCESS_FBINFO(mmio.vbase), (addr)) +#define mga_outb(addr,val) mga_writeb(ACCESS_FBINFO(mmio.vbase), (addr), (val)) +#define mga_outw(addr,val) mga_writew(ACCESS_FBINFO(mmio.vbase), (addr), (val)) +#define mga_outl(addr,val) mga_writel(ACCESS_FBINFO(mmio.vbase), (addr), (val)) +#define mga_readr(port,idx) (mga_outb((port),(idx)), mga_inb((port)+1)) +#define mga_setr(addr,port,val) mga_outw(addr, ((val)<<8) | (port)) + +#define mga_fifo(n) do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n)) + +#define WaitTillIdle() do {} while (mga_inl(M_STATUS) & 0x10000) + +/* code speedup */ +#ifdef CONFIG_FB_MATROX_MILLENIUM +#define isInterleave(x) (x->interleave) +#define isMillenium(x) (x->millenium) +#define isMilleniumII(x) (x->milleniumII) +#else +#define isInterleave(x) (0) +#define isMillenium(x) (0) +#define isMilleniumII(x) (0) +#endif + +#define matroxfb_DAC_lock() spin_lock(&ACCESS_FBINFO(lock.DAC)) +#define matroxfb_DAC_unlock() spin_unlock(&ACCESS_FBINFO(lock.DAC)) +#define matroxfb_DAC_lock_irqsave(flags) spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC),flags) +#define matroxfb_DAC_unlock_irqrestore(flags) spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC),flags) +extern void matroxfb_DAC_out(CPMINFO int reg, int val); +extern int matroxfb_DAC_in(CPMINFO int reg); +extern void matroxfb_var2my(struct fb_var_screeninfo* fvsi, struct my_timming* mt); +extern int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc); +extern int matroxfb_enable_irq(WPMINFO int reenable); + +#ifdef MATROXFB_USE_SPINLOCKS +#define CRITBEGIN spin_lock_irqsave(&ACCESS_FBINFO(lock.accel), critflags); +#define CRITEND spin_unlock_irqrestore(&ACCESS_FBINFO(lock.accel), critflags); +#define CRITFLAGS unsigned long critflags; +#else +#define CRITBEGIN +#define CRITEND +#define CRITFLAGS +#endif + +#endif /* __MATROXFB_H__ */ diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c new file mode 100644 index 000000000000..429047ac615a --- /dev/null +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -0,0 +1,741 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. + * + * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Portions Copyright (c) 2001 Matrox Graphics Inc. + * + * Version: 1.65 2002/08/14 + * + */ + +#include "matroxfb_maven.h" +#include "matroxfb_crtc2.h" +#include "matroxfb_misc.h" +#include "matroxfb_DAC1064.h" +#include <linux/matroxfb.h> +#include <asm/uaccess.h> + +/* **************************************************** */ + +static int mem = 8192; + +module_param(mem, int, 0); +MODULE_PARM_DESC(mem, "Memory size reserved for dualhead (default=8MB)"); + +/* **************************************************** */ + +static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info* info) { + u_int32_t col; +#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) + + if (regno >= 16) + return 1; + if (m2info->fbcon.var.grayscale) { + /* gray = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + red = CNVT_TOHW(red, m2info->fbcon.var.red.length); + green = CNVT_TOHW(green, m2info->fbcon.var.green.length); + blue = CNVT_TOHW(blue, m2info->fbcon.var.blue.length); + transp = CNVT_TOHW(transp, m2info->fbcon.var.transp.length); + + col = (red << m2info->fbcon.var.red.offset) | + (green << m2info->fbcon.var.green.offset) | + (blue << m2info->fbcon.var.blue.offset) | + (transp << m2info->fbcon.var.transp.offset); + + switch (m2info->fbcon.var.bits_per_pixel) { + case 16: + m2info->cmap[regno] = col | (col << 16); + break; + case 32: + m2info->cmap[regno] = col; + break; + } + return 0; +#undef m2info +} + +static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, + struct my_timming* mt, + int mode, + unsigned int pos) { + u_int32_t tmp; + u_int32_t datactl; + MINFO_FROM(m2info->primary_dev); + + switch (mode) { + case 15: + tmp = 0x00200000; + break; + case 16: + tmp = 0x00400000; + break; +/* case 32: */ + default: + tmp = 0x00800000; + break; + } + tmp |= 0x00000001; /* enable CRTC2 */ + datactl = 0; + if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) { + if (ACCESS_FBINFO(devflags.g450dac)) { + tmp |= 0x00000006; /* source from secondary pixel PLL */ + /* no vidrst when in monitor mode */ + if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) { + tmp |= 0xC0001000; /* Enable H/V vidrst */ + } + } else { + tmp |= 0x00000002; /* source from VDOCLK */ + tmp |= 0xC0000000; /* enable vvidrst & hvidrst */ + /* MGA TVO is our clock source */ + } + } else if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) { + tmp |= 0x00000004; /* source from pixclock */ + /* PIXPLL is our clock source */ + } + if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) { + tmp |= 0x00100000; /* connect CRTC2 to DAC */ + } + if (mt->interlaced) { + tmp |= 0x02000000; /* interlaced, second field is bigger, as G450 apparently ignores it */ + mt->VDisplay >>= 1; + mt->VSyncStart >>= 1; + mt->VSyncEnd >>= 1; + mt->VTotal >>= 1; + } + if ((mt->HTotal & 7) == 2) { + datactl |= 0x00000010; + mt->HTotal &= ~7; + } + tmp |= 0x10000000; /* 0x10000000 is VIDRST polarity */ + mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8)); + mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8)); + mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1)); + mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1)); + mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */ + { + u_int32_t linelen = m2info->fbcon.var.xres_virtual * (m2info->fbcon.var.bits_per_pixel >> 3); + if (tmp & 0x02000000) { + /* field #0 is smaller, so... */ + mga_outl(0x3C2C, pos); /* field #1 vmemory start */ + mga_outl(0x3C28, pos + linelen); /* field #0 vmemory start */ + linelen <<= 1; + m2info->interlaced = 1; + } else { + mga_outl(0x3C28, pos); /* vmemory start */ + m2info->interlaced = 0; + } + mga_outl(0x3C40, linelen); + } + mga_outl(0x3C4C, datactl); /* data control */ + if (tmp & 0x02000000) { + int i; + + mga_outl(0x3C10, tmp & ~0x02000000); + for (i = 0; i < 2; i++) { + unsigned int nl; + unsigned int lastl = 0; + + while ((nl = mga_inl(0x3C48) & 0xFFF) >= lastl) { + lastl = nl; + } + } + } + mga_outl(0x3C10, tmp); + ACCESS_FBINFO(hw).crtc2.ctl = tmp; + + tmp = mt->VDisplay << 16; /* line compare */ + if (mt->sync & FB_SYNC_HOR_HIGH_ACT) + tmp |= 0x00000100; + if (mt->sync & FB_SYNC_VERT_HIGH_ACT) + tmp |= 0x00000200; + mga_outl(0x3C44, tmp); +} + +static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) { + MINFO_FROM(m2info->primary_dev); + + mga_outl(0x3C10, 0x00000004); /* disable CRTC2, CRTC1->DAC1, PLL as clock source */ + ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004; +} + +static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info) { + /* no acceleration for secondary head... */ + m2info->cmap[16] = 0xFFFFFFFF; +} + +static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, + struct fb_var_screeninfo* var) { + unsigned int pos; + unsigned int linelen; + unsigned int pixelsize; + MINFO_FROM(m2info->primary_dev); + + m2info->fbcon.var.xoffset = var->xoffset; + m2info->fbcon.var.yoffset = var->yoffset; + pixelsize = m2info->fbcon.var.bits_per_pixel >> 3; + linelen = m2info->fbcon.var.xres_virtual * pixelsize; + pos = m2info->fbcon.var.yoffset * linelen + m2info->fbcon.var.xoffset * pixelsize; + pos += m2info->video.offbase; + if (m2info->interlaced) { + mga_outl(0x3C2C, pos); + mga_outl(0x3C28, pos + linelen); + } else { + mga_outl(0x3C28, pos); + } +} + +static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info, + struct fb_var_screeninfo* var, + int *visual, + int *video_cmap_len, + int *mode) { + unsigned int mask; + unsigned int memlen; + unsigned int vramlen; + + switch (var->bits_per_pixel) { + case 16: mask = 0x1F; + break; + case 32: mask = 0x0F; + break; + default: return -EINVAL; + } + vramlen = m2info->video.len_usable; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + var->xres_virtual = (var->xres_virtual + mask) & ~mask; + if (var->yres_virtual > 32767) + return -EINVAL; + memlen = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel >> 3); + if (memlen > vramlen) + return -EINVAL; + if (var->xoffset + var->xres > var->xres_virtual) + var->xoffset = var->xres_virtual - var->xres; + if (var->yoffset + var->yres > var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres; + + var->xres &= ~7; + var->left_margin &= ~7; + var->right_margin &= ~7; + var->hsync_len &= ~7; + + *mode = var->bits_per_pixel; + if (var->bits_per_pixel == 16) { + if (var->green.length == 5) { + 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; + *mode = 15; + } else { + 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; + } + } else { + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + } + *visual = FB_VISUAL_TRUECOLOR; + *video_cmap_len = 16; + return 0; +} + +static int matroxfb_dh_open(struct fb_info* info, int user) { +#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) + MINFO_FROM(m2info->primary_dev); + + if (MINFO) { + int err; + + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + err = ACCESS_FBINFO(fbops).fb_open(&ACCESS_FBINFO(fbcon), user); + if (err) { + return err; + } + } + return 0; +#undef m2info +} + +static int matroxfb_dh_release(struct fb_info* info, int user) { +#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) + int err = 0; + MINFO_FROM(m2info->primary_dev); + + if (MINFO) { + err = ACCESS_FBINFO(fbops).fb_release(&ACCESS_FBINFO(fbcon), user); + } + return err; +#undef m2info +} + +static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) { + struct fb_fix_screeninfo *fix = &m2info->fbcon.fix; + + strcpy(fix->id, "MATROX DH"); + + fix->smem_start = m2info->video.base; + fix->smem_len = m2info->video.len_usable; + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->xpanstep = 8; /* TBD */ + fix->mmio_start = m2info->mmio.base; + fix->mmio_len = m2info->mmio.len; + fix->accel = 0; /* no accel... */ +} + +static int matroxfb_dh_check_var(struct fb_var_screeninfo* var, struct fb_info* info) { +#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) + int visual; + int cmap_len; + int mode; + + return matroxfb_dh_decode_var(m2info, var, &visual, &cmap_len, &mode); +#undef m2info +} + +static int matroxfb_dh_set_par(struct fb_info* info) { +#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) + int visual; + int cmap_len; + int mode; + int err; + struct fb_var_screeninfo* var = &info->var; + MINFO_FROM(m2info->primary_dev); + + if ((err = matroxfb_dh_decode_var(m2info, var, &visual, &cmap_len, &mode)) != 0) + return err; + /* cmap */ + { + m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase); + m2info->fbcon.fix.visual = visual; + m2info->fbcon.fix.type = FB_TYPE_PACKED_PIXELS; + m2info->fbcon.fix.type_aux = 0; + m2info->fbcon.fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; + } + { + struct my_timming mt; + unsigned int pos; + int out; + int cnt; + + matroxfb_var2my(&m2info->fbcon.var, &mt); + mt.crtc = MATROXFB_SRC_CRTC2; + /* CRTC2 delay */ + mt.delay = 34; + + pos = (m2info->fbcon.var.yoffset * m2info->fbcon.var.xres_virtual + m2info->fbcon.var.xoffset) * m2info->fbcon.var.bits_per_pixel >> 3; + pos += m2info->video.offbase; + cnt = 0; + down_read(&ACCESS_FBINFO(altout).lock); + for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { + if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) { + cnt++; + if (ACCESS_FBINFO(outputs[out]).output->compute) { + ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt); + } + } + } + ACCESS_FBINFO(crtc2).pixclock = mt.pixclock; + ACCESS_FBINFO(crtc2).mnp = mt.mnp; + up_read(&ACCESS_FBINFO(altout).lock); + if (cnt) { + matroxfb_dh_restore(m2info, &mt, mode, pos); + } else { + matroxfb_dh_disable(m2info); + } + DAC1064_global_init(PMINFO2); + DAC1064_global_restore(PMINFO2); + down_read(&ACCESS_FBINFO(altout).lock); + for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { + if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 && + ACCESS_FBINFO(outputs[out]).output->program) { + ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data); + } + } + for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { + if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 && + ACCESS_FBINFO(outputs[out]).output->start) { + ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data); + } + } + up_read(&ACCESS_FBINFO(altout).lock); + matroxfb_dh_cfbX_init(m2info); + } + m2info->initialized = 1; + return 0; +#undef m2info +} + +static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, struct fb_info* info) { +#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) + matroxfb_dh_pan_var(m2info, var); + return 0; +#undef m2info +} + +static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, struct fb_vblank* vblank) { + MINFO_FROM(m2info->primary_dev); + + matroxfb_enable_irq(PMINFO 0); + memset(vblank, 0, sizeof(*vblank)); + vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VBLANK; + /* mask out reserved bits + field number (odd/even) */ + vblank->vcount = mga_inl(0x3C48) & 0x000007FF; + /* compatibility stuff */ + if (vblank->vcount >= m2info->fbcon.var.yres) + vblank->flags |= FB_VBLANK_VBLANKING; + if (test_bit(0, &ACCESS_FBINFO(irq_flags))) { + vblank->flags |= FB_VBLANK_HAVE_COUNT; + /* Only one writer, aligned int value... + it should work without lock and without atomic_t */ + vblank->count = ACCESS_FBINFO(crtc2).vsync.cnt; + } + return 0; +} + +static int matroxfb_dh_ioctl(struct inode* inode, + struct file* file, + unsigned int cmd, + unsigned long arg, + struct fb_info* info) { +#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) + MINFO_FROM(m2info->primary_dev); + + DBG(__FUNCTION__) + + switch (cmd) { + case FBIOGET_VBLANK: + { + struct fb_vblank vblank; + int err; + + err = matroxfb_dh_get_vblank(m2info, &vblank); + if (err) + return err; + if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) + return -EFAULT; + return 0; + } + case FBIO_WAITFORVSYNC: + { + u_int32_t crt; + + if (get_user(crt, (u_int32_t __user *)arg)) + return -EFAULT; + + if (crt != 0) + return -ENODEV; + return matroxfb_wait_for_sync(PMINFO 1); + } + case MATROXFB_SET_OUTPUT_MODE: + case MATROXFB_GET_OUTPUT_MODE: + case MATROXFB_GET_ALL_OUTPUTS: + { + return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(inode, file, cmd, arg, &ACCESS_FBINFO(fbcon)); + } + case MATROXFB_SET_OUTPUT_CONNECTION: + { + u_int32_t tmp; + int out; + int changes; + + if (get_user(tmp, (u_int32_t __user *)arg)) + return -EFAULT; + for (out = 0; out < 32; out++) { + if (tmp & (1 << out)) { + if (out >= MATROXFB_MAX_OUTPUTS) + return -ENXIO; + if (!ACCESS_FBINFO(outputs[out]).output) + return -ENXIO; + switch (ACCESS_FBINFO(outputs[out]).src) { + case MATROXFB_SRC_NONE: + case MATROXFB_SRC_CRTC2: + break; + default: + return -EBUSY; + } + } + } + if (ACCESS_FBINFO(devflags.panellink)) { + if (tmp & MATROXFB_OUTPUT_CONN_DFP) + return -EINVAL; + if ((ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) && tmp) + return -EBUSY; + } + changes = 0; + for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { + if (tmp & (1 << out)) { + if (ACCESS_FBINFO(outputs[out]).src != MATROXFB_SRC_CRTC2) { + changes = 1; + ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_CRTC2; + } + } else if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) { + changes = 1; + ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_NONE; + } + } + if (!changes) + return 0; + matroxfb_dh_set_par(info); + return 0; + } + case MATROXFB_GET_OUTPUT_CONNECTION: + { + u_int32_t conn = 0; + int out; + + for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { + if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) { + conn |= 1 << out; + } + } + if (put_user(conn, (u_int32_t __user *)arg)) + return -EFAULT; + return 0; + } + case MATROXFB_GET_AVAILABLE_OUTPUTS: + { + u_int32_t tmp = 0; + int out; + + for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { + if (ACCESS_FBINFO(outputs[out]).output) { + switch (ACCESS_FBINFO(outputs[out]).src) { + case MATROXFB_SRC_NONE: + case MATROXFB_SRC_CRTC2: + tmp |= 1 << out; + break; + } + } + } + if (ACCESS_FBINFO(devflags.panellink)) { + tmp &= ~MATROXFB_OUTPUT_CONN_DFP; + if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) { + tmp = 0; + } + } + if (put_user(tmp, (u_int32_t __user *)arg)) + return -EFAULT; + return 0; + } + } + return -ENOTTY; +#undef m2info +} + +static int matroxfb_dh_blank(int blank, struct fb_info* info) { +#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) + switch (blank) { + case 1: + case 2: + case 3: + case 4: + default:; + } + /* do something... */ + return 0; +#undef m2info +} + +static struct fb_ops matroxfb_dh_ops = { + .owner = THIS_MODULE, + .fb_open = matroxfb_dh_open, + .fb_release = matroxfb_dh_release, + .fb_check_var = matroxfb_dh_check_var, + .fb_set_par = matroxfb_dh_set_par, + .fb_setcolreg = matroxfb_dh_setcolreg, + .fb_pan_display =matroxfb_dh_pan_display, + .fb_blank = matroxfb_dh_blank, + .fb_ioctl = matroxfb_dh_ioctl, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +static struct fb_var_screeninfo matroxfb_dh_defined = { + 640,480,640,480,/* W,H, virtual W,H */ + 0,0, /* offset */ + 32, /* depth */ + 0, /* gray */ + {0,0,0}, /* R */ + {0,0,0}, /* G */ + {0,0,0}, /* B */ + {0,0,0}, /* alpha */ + 0, /* nonstd */ + FB_ACTIVATE_NOW, + -1,-1, /* display size */ + 0, /* accel flags */ + 39721L,48L,16L,33L,10L, + 96L,2,0, /* no sync info */ + FB_VMODE_NONINTERLACED, + 0, {0,0,0,0,0} +}; + +static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) { +#define minfo (m2info->primary_dev) + void* oldcrtc2; + + m2info->fbcon.fbops = &matroxfb_dh_ops; + m2info->fbcon.flags = FBINFO_FLAG_DEFAULT; + m2info->fbcon.flags |= FBINFO_HWACCEL_XPAN | + FBINFO_HWACCEL_YPAN; + m2info->fbcon.pseudo_palette = m2info->cmap; + fb_alloc_cmap(&m2info->fbcon.cmap, 256, 1); + + if (mem < 64) + mem *= 1024; + if (mem < 64*1024) + mem *= 1024; + mem &= ~0x00000FFF; /* PAGE_MASK? */ + if (ACCESS_FBINFO(video.len_usable) + mem <= ACCESS_FBINFO(video.len)) + m2info->video.offbase = ACCESS_FBINFO(video.len) - mem; + else if (ACCESS_FBINFO(video.len) < mem) { + return -ENOMEM; + } else { /* check yres on first head... */ + m2info->video.borrowed = mem; + ACCESS_FBINFO(video.len_usable) -= mem; + m2info->video.offbase = ACCESS_FBINFO(video.len_usable); + } + m2info->video.base = ACCESS_FBINFO(video.base) + m2info->video.offbase; + m2info->video.len = m2info->video.len_usable = m2info->video.len_maximum = mem; + m2info->video.vbase.vaddr = vaddr_va(ACCESS_FBINFO(video.vbase)) + m2info->video.offbase; + m2info->mmio.base = ACCESS_FBINFO(mmio.base); + m2info->mmio.vbase = ACCESS_FBINFO(mmio.vbase); + m2info->mmio.len = ACCESS_FBINFO(mmio.len); + + matroxfb_dh_init_fix(m2info); + if (register_framebuffer(&m2info->fbcon)) { + return -ENXIO; + } + if (!m2info->initialized) + fb_set_var(&m2info->fbcon, &matroxfb_dh_defined); + down_write(&ACCESS_FBINFO(crtc2.lock)); + oldcrtc2 = ACCESS_FBINFO(crtc2.info); + ACCESS_FBINFO(crtc2.info) = m2info; + up_write(&ACCESS_FBINFO(crtc2.lock)); + if (oldcrtc2) { + printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n", + oldcrtc2); + } + return 0; +#undef minfo +} + +/* ************************** */ + +static int matroxfb_dh_registerfb(struct matroxfb_dh_fb_info* m2info) { +#define minfo (m2info->primary_dev) + if (matroxfb_dh_regit(PMINFO m2info)) { + printk(KERN_ERR "matroxfb_crtc2: secondary head failed to register\n"); + return -1; + } + printk(KERN_INFO "matroxfb_crtc2: secondary head of fb%u was registered as fb%u\n", + ACCESS_FBINFO(fbcon.node), m2info->fbcon.node); + m2info->fbcon_registered = 1; + return 0; +#undef minfo +} + +static void matroxfb_dh_deregisterfb(struct matroxfb_dh_fb_info* m2info) { +#define minfo (m2info->primary_dev) + if (m2info->fbcon_registered) { + int id; + struct matroxfb_dh_fb_info* crtc2; + + down_write(&ACCESS_FBINFO(crtc2.lock)); + crtc2 = ACCESS_FBINFO(crtc2.info); + if (crtc2 == m2info) + ACCESS_FBINFO(crtc2.info) = NULL; + up_write(&ACCESS_FBINFO(crtc2.lock)); + if (crtc2 != m2info) { + printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n", + crtc2, m2info); + printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n"); + return; + } + id = m2info->fbcon.node; + unregister_framebuffer(&m2info->fbcon); + /* return memory back to primary head */ + ACCESS_FBINFO(video.len_usable) += m2info->video.borrowed; + printk(KERN_INFO "matroxfb_crtc2: fb%u unregistered\n", id); + m2info->fbcon_registered = 0; + } +#undef minfo +} + +static void* matroxfb_crtc2_probe(struct matrox_fb_info* minfo) { + struct matroxfb_dh_fb_info* m2info; + + /* hardware is CRTC2 incapable... */ + if (!ACCESS_FBINFO(devflags.crtc2)) + return NULL; + m2info = (struct matroxfb_dh_fb_info*)kmalloc(sizeof(*m2info), GFP_KERNEL); + if (!m2info) { + printk(KERN_ERR "matroxfb_crtc2: Not enough memory for CRTC2 control structs\n"); + return NULL; + } + memset(m2info, 0, sizeof(*m2info)); + m2info->primary_dev = MINFO; + if (matroxfb_dh_registerfb(m2info)) { + kfree(m2info); + printk(KERN_ERR "matroxfb_crtc2: CRTC2 framebuffer failed to register\n"); + return NULL; + } + return m2info; +} + +static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) { + matroxfb_dh_deregisterfb(crtc2); + kfree(crtc2); +} + +static struct matroxfb_driver crtc2 = { + .name = "Matrox G400 CRTC2", + .probe = matroxfb_crtc2_probe, + .remove = matroxfb_crtc2_remove }; + +static int matroxfb_crtc2_init(void) { + if (fb_get_options("matrox_crtc2fb", NULL)) + return -ENODEV; + + matroxfb_register_driver(&crtc2); + return 0; +} + +static void matroxfb_crtc2_exit(void) { + matroxfb_unregister_driver(&crtc2); +} + +MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Matrox G400 CRTC2 driver"); +MODULE_LICENSE("GPL"); +module_init(matroxfb_crtc2_init); +module_exit(matroxfb_crtc2_exit); +/* we do not have __setup() yet */ diff --git a/drivers/video/matrox/matroxfb_crtc2.h b/drivers/video/matrox/matroxfb_crtc2.h new file mode 100644 index 000000000000..608e40bb20e9 --- /dev/null +++ b/drivers/video/matrox/matroxfb_crtc2.h @@ -0,0 +1,36 @@ +#ifndef __MATROXFB_CRTC2_H__ +#define __MATROXFB_CRTC2_H__ + +#include <linux/ioctl.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include "matroxfb_base.h" + +struct matroxfb_dh_fb_info { + struct fb_info fbcon; + int fbcon_registered; + int initialized; + + struct matrox_fb_info* primary_dev; + + struct { + unsigned long base; /* physical */ + vaddr_t vbase; /* virtual */ + unsigned int len; + unsigned int len_usable; + unsigned int len_maximum; + unsigned int offbase; + unsigned int borrowed; + } video; + struct { + unsigned long base; + vaddr_t vbase; + unsigned int len; + } mmio; + + unsigned int interlaced:1; + + u_int32_t cmap[17]; +}; + +#endif /* __MATROXFB_CRTC2_H__ */ diff --git a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c new file mode 100644 index 000000000000..35008af7db75 --- /dev/null +++ b/drivers/video/matrox/matroxfb_g450.c @@ -0,0 +1,626 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. + * + * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Portions Copyright (c) 2001 Matrox Graphics Inc. + * + * Version: 1.65 2002/08/14 + * + * See matroxfb_base.c for contributors. + * + */ + +#include "matroxfb_base.h" +#include "matroxfb_misc.h" +#include "matroxfb_DAC1064.h" +#include "g450_pll.h" +#include <linux/matroxfb.h> +#include <asm/uaccess.h> +#include <asm/div64.h> + +/* Definition of the various controls */ +struct mctl { + struct v4l2_queryctrl desc; + size_t control; +}; + +#define BLMIN 0xF3 +#define WLMAX 0x3FF + +static const struct mctl g450_controls[] = +{ { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, + "brightness", + 0, WLMAX-BLMIN, 1, 370-BLMIN, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) }, + { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, + "contrast", + 0, 1023, 1, 127, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) }, + { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER, + "saturation", + 0, 255, 1, 165, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) }, + { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER, + "hue", + 0, 255, 1, 0, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) }, + { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN, + "test output", + 0, 1, 1, 0, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) }, +}; + +#define G450CTRLS (sizeof(g450_controls)/sizeof(g450_controls[0])) + +/* Return: positive number: id found + -EINVAL: id not found, return failure + -ENOENT: id not found, create fake disabled control */ +static int get_ctrl_id(__u32 v4l2_id) { + int i; + + for (i = 0; i < G450CTRLS; i++) { + if (v4l2_id < g450_controls[i].desc.id) { + if (g450_controls[i].desc.id == 0x08000000) { + return -EINVAL; + } + return -ENOENT; + } + if (v4l2_id == g450_controls[i].desc.id) { + return i; + } + } + return -EINVAL; +} + +static inline int* get_ctrl_ptr(WPMINFO unsigned int idx) { + return (int*)((char*)MINFO + g450_controls[idx].control); +} + +static void tvo_fill_defaults(WPMINFO2) { + unsigned int i; + + for (i = 0; i < G450CTRLS; i++) { + *get_ctrl_ptr(PMINFO i) = g450_controls[i].desc.default_value; + } +} + +static int cve2_get_reg(WPMINFO int reg) { + unsigned long flags; + int val; + + matroxfb_DAC_lock_irqsave(flags); + matroxfb_DAC_out(PMINFO 0x87, reg); + val = matroxfb_DAC_in(PMINFO 0x88); + matroxfb_DAC_unlock_irqrestore(flags); + return val; +} + +static void cve2_set_reg(WPMINFO int reg, int val) { + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); + matroxfb_DAC_out(PMINFO 0x87, reg); + matroxfb_DAC_out(PMINFO 0x88, val); + matroxfb_DAC_unlock_irqrestore(flags); +} + +static void cve2_set_reg10(WPMINFO int reg, int val) { + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); + matroxfb_DAC_out(PMINFO 0x87, reg); + matroxfb_DAC_out(PMINFO 0x88, val >> 2); + matroxfb_DAC_out(PMINFO 0x87, reg + 1); + matroxfb_DAC_out(PMINFO 0x88, val & 3); + matroxfb_DAC_unlock_irqrestore(flags); +} + +static void g450_compute_bwlevel(CPMINFO int *bl, int *wl) { + const int b = ACCESS_FBINFO(altout.tvo_params.brightness) + BLMIN; + const int c = ACCESS_FBINFO(altout.tvo_params.contrast); + + *bl = max(b - c, BLMIN); + *wl = min(b + c, WLMAX); +} + +static int g450_query_ctrl(void* md, struct v4l2_queryctrl *p) { + int i; + + i = get_ctrl_id(p->id); + if (i >= 0) { + *p = g450_controls[i].desc; + return 0; + } + if (i == -ENOENT) { + static const struct v4l2_queryctrl disctrl = + { .flags = V4L2_CTRL_FLAG_DISABLED }; + + i = p->id; + *p = disctrl; + p->id = i; + sprintf(p->name, "Ctrl #%08X", i); + return 0; + } + return -EINVAL; +} + +static int g450_set_ctrl(void* md, struct v4l2_control *p) { + int i; + MINFO_FROM(md); + + i = get_ctrl_id(p->id); + if (i < 0) return -EINVAL; + + /* + * Check if changed. + */ + if (p->value == *get_ctrl_ptr(PMINFO i)) return 0; + + /* + * Check limits. + */ + if (p->value > g450_controls[i].desc.maximum) return -EINVAL; + if (p->value < g450_controls[i].desc.minimum) return -EINVAL; + + /* + * Store new value. + */ + *get_ctrl_ptr(PMINFO i) = p->value; + + switch (p->id) { + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_CONTRAST: + { + int blacklevel, whitelevel; + g450_compute_bwlevel(PMINFO &blacklevel, &whitelevel); + cve2_set_reg10(PMINFO 0x0e, blacklevel); + cve2_set_reg10(PMINFO 0x1e, whitelevel); + } + break; + case V4L2_CID_SATURATION: + cve2_set_reg(PMINFO 0x20, p->value); + cve2_set_reg(PMINFO 0x22, p->value); + break; + case V4L2_CID_HUE: + cve2_set_reg(PMINFO 0x25, p->value); + break; + case MATROXFB_CID_TESTOUT: + { + unsigned char val = cve2_get_reg (PMINFO 0x05); + if (p->value) val |= 0x02; + else val &= ~0x02; + cve2_set_reg(PMINFO 0x05, val); + } + break; + } + + + return 0; +} + +static int g450_get_ctrl(void* md, struct v4l2_control *p) { + int i; + MINFO_FROM(md); + + i = get_ctrl_id(p->id); + if (i < 0) return -EINVAL; + p->value = *get_ctrl_ptr(PMINFO i); + return 0; +} + +struct output_desc { + unsigned int h_vis; + unsigned int h_f_porch; + unsigned int h_sync; + unsigned int h_b_porch; + unsigned long long int chromasc; + unsigned int burst; + unsigned int v_total; +}; + +static void computeRegs(WPMINFO struct mavenregs* r, struct my_timming* mt, const struct output_desc* outd) { + u_int32_t chromasc; + u_int32_t hlen; + u_int32_t hsl; + u_int32_t hbp; + u_int32_t hfp; + u_int32_t hvis; + unsigned int pixclock; + unsigned long long piic; + int mnp; + int over; + + r->regs[0x80] = 0x03; /* | 0x40 for SCART */ + + hvis = ((mt->HDisplay << 1) + 3) & ~3; + + if (hvis >= 2048) { + hvis = 2044; + } + + piic = 1000000000ULL * hvis; + do_div(piic, outd->h_vis); + + dprintk(KERN_DEBUG "Want %u kHz pixclock\n", (unsigned int)piic); + + mnp = matroxfb_g450_setclk(PMINFO piic, M_VIDEO_PLL); + + mt->mnp = mnp; + mt->pixclock = g450_mnp2f(PMINFO mnp); + + dprintk(KERN_DEBUG "MNP=%08X\n", mnp); + + pixclock = 1000000000U / mt->pixclock; + + dprintk(KERN_DEBUG "Got %u ps pixclock\n", pixclock); + + piic = outd->chromasc; + do_div(piic, mt->pixclock); + chromasc = piic; + + dprintk(KERN_DEBUG "Chroma is %08X\n", chromasc); + + r->regs[0] = piic >> 24; + r->regs[1] = piic >> 16; + r->regs[2] = piic >> 8; + r->regs[3] = piic >> 0; + hbp = (((outd->h_b_porch + pixclock) / pixclock)) & ~1; + hfp = (((outd->h_f_porch + pixclock) / pixclock)) & ~1; + hsl = (((outd->h_sync + pixclock) / pixclock)) & ~1; + hlen = hvis + hfp + hsl + hbp; + over = hlen & 0x0F; + + dprintk(KERN_DEBUG "WL: vis=%u, hf=%u, hs=%u, hb=%u, total=%u\n", hvis, hfp, hsl, hbp, hlen); + + if (over) { + hfp -= over; + hlen -= over; + if (over <= 2) { + } else if (over < 10) { + hfp += 4; + hlen += 4; + } else { + hfp += 16; + hlen += 16; + } + } + + /* maybe cve2 has requirement 800 < hlen < 1184 */ + r->regs[0x08] = hsl; + r->regs[0x09] = (outd->burst + pixclock - 1) / pixclock; /* burst length */ + r->regs[0x0A] = hbp; + r->regs[0x2C] = hfp; + r->regs[0x31] = hvis / 8; + r->regs[0x32] = hvis & 7; + + dprintk(KERN_DEBUG "PG: vis=%04X, hf=%02X, hs=%02X, hb=%02X, total=%04X\n", hvis, hfp, hsl, hbp, hlen); + + r->regs[0x84] = 1; /* x sync point */ + r->regs[0x85] = 0; + hvis = hvis >> 1; + hlen = hlen >> 1; + + dprintk(KERN_DEBUG "hlen=%u hvis=%u\n", hlen, hvis); + + mt->interlaced = 1; + + mt->HDisplay = hvis & ~7; + mt->HSyncStart = mt->HDisplay + 8; + mt->HSyncEnd = (hlen & ~7) - 8; + mt->HTotal = hlen; + + { + int upper; + unsigned int vtotal; + unsigned int vsyncend; + unsigned int vdisplay; + + vtotal = mt->VTotal; + vsyncend = mt->VSyncEnd; + vdisplay = mt->VDisplay; + if (vtotal < outd->v_total) { + unsigned int yovr = outd->v_total - vtotal; + + vsyncend += yovr >> 1; + } else if (vtotal > outd->v_total) { + vdisplay = outd->v_total - 4; + vsyncend = outd->v_total; + } + upper = (outd->v_total - vsyncend) >> 1; /* in field lines */ + r->regs[0x17] = outd->v_total / 4; + r->regs[0x18] = outd->v_total & 3; + r->regs[0x33] = upper - 1; /* upper blanking */ + r->regs[0x82] = upper; /* y sync point */ + r->regs[0x83] = upper >> 8; + + mt->VDisplay = vdisplay; + mt->VSyncStart = outd->v_total - 2; + mt->VSyncEnd = outd->v_total; + mt->VTotal = outd->v_total; + } +} + +static void cve2_init_TVdata(int norm, struct mavenregs* data, const struct output_desc** outd) { + static const struct output_desc paloutd = { + .h_vis = 52148148, // ps + .h_f_porch = 1407407, // ps + .h_sync = 4666667, // ps + .h_b_porch = 5777778, // ps + .chromasc = 19042247534182ULL, // 4433618.750 Hz + .burst = 2518518, // ps + .v_total = 625, + }; + static const struct output_desc ntscoutd = { + .h_vis = 52888889, // ps + .h_f_porch = 1333333, // ps + .h_sync = 4666667, // ps + .h_b_porch = 4666667, // ps + .chromasc = 15374030659475ULL, // 3579545.454 Hz + .burst = 2418418, // ps + .v_total = 525, // lines + }; + + static const struct mavenregs palregs = { { + 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */ + 0x00, + 0x00, /* test */ + 0xF9, /* modified by code (F9 written...) */ + 0x00, /* ? not written */ + 0x7E, /* 08 */ + 0x44, /* 09 */ + 0x9C, /* 0A */ + 0x2E, /* 0B */ + 0x21, /* 0C */ + 0x00, /* ? not written */ +// 0x3F, 0x03, /* 0E-0F */ + 0x3C, 0x03, + 0x3C, 0x03, /* 10-11 */ + 0x1A, /* 12 */ + 0x2A, /* 13 */ + 0x1C, 0x3D, 0x14, /* 14-16 */ + 0x9C, 0x01, /* 17-18 */ + 0x00, /* 19 */ + 0xFE, /* 1A */ + 0x7E, /* 1B */ + 0x60, /* 1C */ + 0x05, /* 1D */ +// 0x89, 0x03, /* 1E-1F */ + 0xAD, 0x03, +// 0x72, /* 20 */ + 0xA5, + 0x07, /* 21 */ +// 0x72, /* 22 */ + 0xA5, + 0x00, /* 23 */ + 0x00, /* 24 */ + 0x00, /* 25 */ + 0x08, /* 26 */ + 0x04, /* 27 */ + 0x00, /* 28 */ + 0x1A, /* 29 */ + 0x55, 0x01, /* 2A-2B */ + 0x26, /* 2C */ + 0x07, 0x7E, /* 2D-2E */ + 0x02, 0x54, /* 2F-30 */ + 0xB0, 0x00, /* 31-32 */ + 0x14, /* 33 */ + 0x49, /* 34 */ + 0x00, /* 35 written multiple times */ + 0x00, /* 36 not written */ + 0xA3, /* 37 */ + 0xC8, /* 38 */ + 0x22, /* 39 */ + 0x02, /* 3A */ + 0x22, /* 3B */ + 0x3F, 0x03, /* 3C-3D */ + 0x00, /* 3E written multiple times */ + 0x00, /* 3F not written */ + } }; + static struct mavenregs ntscregs = { { + 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */ + 0x00, + 0x00, /* test */ + 0xF9, /* modified by code (F9 written...) */ + 0x00, /* ? not written */ + 0x7E, /* 08 */ + 0x43, /* 09 */ + 0x7E, /* 0A */ + 0x3D, /* 0B */ + 0x00, /* 0C */ + 0x00, /* ? not written */ + 0x41, 0x00, /* 0E-0F */ + 0x3C, 0x00, /* 10-11 */ + 0x17, /* 12 */ + 0x21, /* 13 */ + 0x1B, 0x1B, 0x24, /* 14-16 */ + 0x83, 0x01, /* 17-18 */ + 0x00, /* 19 */ + 0x0F, /* 1A */ + 0x0F, /* 1B */ + 0x60, /* 1C */ + 0x05, /* 1D */ + //0x89, 0x02, /* 1E-1F */ + 0xC0, 0x02, /* 1E-1F */ + //0x5F, /* 20 */ + 0x9C, /* 20 */ + 0x04, /* 21 */ + //0x5F, /* 22 */ + 0x9C, /* 22 */ + 0x01, /* 23 */ + 0x02, /* 24 */ + 0x00, /* 25 */ + 0x0A, /* 26 */ + 0x05, /* 27 */ + 0x00, /* 28 */ + 0x10, /* 29 */ + 0xFF, 0x03, /* 2A-2B */ + 0x24, /* 2C */ + 0x0F, 0x78, /* 2D-2E */ + 0x00, 0x00, /* 2F-30 */ + 0xB2, 0x04, /* 31-32 */ + 0x14, /* 33 */ + 0x02, /* 34 */ + 0x00, /* 35 written multiple times */ + 0x00, /* 36 not written */ + 0xA3, /* 37 */ + 0xC8, /* 38 */ + 0x15, /* 39 */ + 0x05, /* 3A */ + 0x3B, /* 3B */ + 0x3C, 0x00, /* 3C-3D */ + 0x00, /* 3E written multiple times */ + 0x00, /* never written */ + } }; + + if (norm == MATROXFB_OUTPUT_MODE_PAL) { + *data = palregs; + *outd = &paloutd; + } else { + *data = ntscregs; + *outd = &ntscoutd; + } + return; +} + +#define LR(x) cve2_set_reg(PMINFO (x), m->regs[(x)]) +static void cve2_init_TV(WPMINFO const struct mavenregs* m) { + int i; + + LR(0x80); + LR(0x82); LR(0x83); + LR(0x84); LR(0x85); + + cve2_set_reg(PMINFO 0x3E, 0x01); + + for (i = 0; i < 0x3E; i++) { + LR(i); + } + cve2_set_reg(PMINFO 0x3E, 0x00); +} + +static int matroxfb_g450_compute(void* md, struct my_timming* mt) { + MINFO_FROM(md); + + dprintk(KERN_DEBUG "Computing, mode=%u\n", ACCESS_FBINFO(outputs[1]).mode); + + if (mt->crtc == MATROXFB_SRC_CRTC2 && + ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) { + const struct output_desc* outd; + + cve2_init_TVdata(ACCESS_FBINFO(outputs[1]).mode, &ACCESS_FBINFO(hw).maven, &outd); + { + int blacklevel, whitelevel; + g450_compute_bwlevel(PMINFO &blacklevel, &whitelevel); + ACCESS_FBINFO(hw).maven.regs[0x0E] = blacklevel >> 2; + ACCESS_FBINFO(hw).maven.regs[0x0F] = blacklevel & 3; + ACCESS_FBINFO(hw).maven.regs[0x1E] = whitelevel >> 2; + ACCESS_FBINFO(hw).maven.regs[0x1F] = whitelevel & 3; + + ACCESS_FBINFO(hw).maven.regs[0x20] = + ACCESS_FBINFO(hw).maven.regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation); + + ACCESS_FBINFO(hw).maven.regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue); + + if (ACCESS_FBINFO(altout.tvo_params.testout)) { + ACCESS_FBINFO(hw).maven.regs[0x05] |= 0x02; + } + } + computeRegs(PMINFO &ACCESS_FBINFO(hw).maven, mt, outd); + } else if (mt->mnp < 0) { + /* We must program clocks before CRTC2, otherwise interlaced mode + startup may fail */ + mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL); + mt->pixclock = g450_mnp2f(PMINFO mt->mnp); + } + dprintk(KERN_DEBUG "Pixclock = %u\n", mt->pixclock); + return 0; +} + +static int matroxfb_g450_program(void* md) { + MINFO_FROM(md); + + if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) { + cve2_init_TV(PMINFO &ACCESS_FBINFO(hw).maven); + } + return 0; +} + +static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) { + switch (arg) { + case MATROXFB_OUTPUT_MODE_PAL: + case MATROXFB_OUTPUT_MODE_NTSC: + case MATROXFB_OUTPUT_MODE_MONITOR: + return 0; + } + return -EINVAL; +} + +static int g450_dvi_compute(void* md, struct my_timming* mt) { + MINFO_FROM(md); + + if (mt->mnp < 0) { + mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL); + mt->pixclock = g450_mnp2f(PMINFO mt->mnp); + } + return 0; +} + +static struct matrox_altout matroxfb_g450_altout = { + .name = "Secondary output", + .compute = matroxfb_g450_compute, + .program = matroxfb_g450_program, + .verifymode = matroxfb_g450_verify_mode, + .getqueryctrl = g450_query_ctrl, + .getctrl = g450_get_ctrl, + .setctrl = g450_set_ctrl, +}; + +static struct matrox_altout matroxfb_g450_dvi = { + .name = "DVI output", + .compute = g450_dvi_compute, +}; + +void matroxfb_g450_connect(WPMINFO2) { + if (ACCESS_FBINFO(devflags.g450dac)) { + down_write(&ACCESS_FBINFO(altout.lock)); + tvo_fill_defaults(PMINFO2); + ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src; + ACCESS_FBINFO(outputs[1]).data = MINFO; + ACCESS_FBINFO(outputs[1]).output = &matroxfb_g450_altout; + ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR; + ACCESS_FBINFO(outputs[2]).src = ACCESS_FBINFO(outputs[2]).default_src; + ACCESS_FBINFO(outputs[2]).data = MINFO; + ACCESS_FBINFO(outputs[2]).output = &matroxfb_g450_dvi; + ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR; + up_write(&ACCESS_FBINFO(altout.lock)); + } +} + +void matroxfb_g450_shutdown(WPMINFO2) { + if (ACCESS_FBINFO(devflags.g450dac)) { + down_write(&ACCESS_FBINFO(altout.lock)); + ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE; + ACCESS_FBINFO(outputs[1]).output = NULL; + ACCESS_FBINFO(outputs[1]).data = NULL; + ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR; + ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE; + ACCESS_FBINFO(outputs[2]).output = NULL; + ACCESS_FBINFO(outputs[2]).data = NULL; + ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR; + up_write(&ACCESS_FBINFO(altout.lock)); + } +} + +EXPORT_SYMBOL(matroxfb_g450_connect); +EXPORT_SYMBOL(matroxfb_g450_shutdown); + +MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Matrox G450/G550 output driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/matrox/matroxfb_g450.h b/drivers/video/matrox/matroxfb_g450.h new file mode 100644 index 000000000000..a0822a6033e5 --- /dev/null +++ b/drivers/video/matrox/matroxfb_g450.h @@ -0,0 +1,14 @@ +#ifndef __MATROXFB_G450_H__ +#define __MATROXFB_G450_H__ + +#include "matroxfb_base.h" + +#ifdef CONFIG_FB_MATROX_G +void matroxfb_g450_connect(WPMINFO2); +void matroxfb_g450_shutdown(WPMINFO2); +#else +static inline void matroxfb_g450_connect(WPMINFO2) { }; +static inline void matroxfb_g450_shutdown(WPMINFO2) { }; +#endif + +#endif /* __MATROXFB_G450_H__ */ diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c new file mode 100644 index 000000000000..e529841cd83d --- /dev/null +++ b/drivers/video/matrox/matroxfb_maven.c @@ -0,0 +1,1328 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. + * + * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Portions Copyright (c) 2001 Matrox Graphics Inc. + * + * Version: 1.65 2002/08/14 + * + * See matroxfb_base.c for contributors. + * + */ + +#include "matroxfb_maven.h" +#include "matroxfb_misc.h" +#include "matroxfb_DAC1064.h" +#include <linux/i2c.h> +#include <linux/matroxfb.h> +#include <asm/div64.h> +#include <asm/uaccess.h> + +#define MAVEN_I2CID (0x1B) + +#define MGATVO_B 1 +#define MGATVO_C 2 + +static const struct maven_gamma { + unsigned char reg83; + unsigned char reg84; + unsigned char reg85; + unsigned char reg86; + unsigned char reg87; + unsigned char reg88; + unsigned char reg89; + unsigned char reg8a; + unsigned char reg8b; +} maven_gamma[] = { + { 131, 57, 223, 15, 117, 212, 251, 91, 156}, + { 133, 61, 128, 63, 180, 147, 195, 100, 180}, + { 131, 19, 63, 31, 50, 66, 171, 64, 176}, + { 0, 0, 0, 31, 16, 16, 16, 100, 200}, + { 8, 23, 47, 73, 147, 244, 220, 80, 195}, + { 22, 43, 64, 80, 147, 115, 58, 85, 168}, + { 34, 60, 80, 214, 147, 212, 188, 85, 167}, + { 45, 77, 96, 216, 147, 99, 91, 85, 159}, + { 56, 76, 112, 107, 147, 212, 148, 64, 144}, + { 65, 91, 128, 137, 147, 196, 17, 69, 148}, + { 72, 104, 136, 138, 147, 180, 245, 73, 147}, + { 87, 116, 143, 126, 16, 83, 229, 77, 144}, + { 95, 119, 152, 254, 244, 83, 221, 77, 151}, + { 100, 129, 159, 156, 244, 148, 197, 77, 160}, + { 105, 141, 167, 247, 244, 132, 181, 84, 166}, + { 105, 147, 168, 247, 244, 245, 181, 90, 170}, + { 120, 153, 175, 248, 212, 229, 165, 90, 180}, + { 119, 156, 176, 248, 244, 229, 84, 74, 160}, + { 119, 158, 183, 248, 244, 229, 149, 78, 165} +}; + +/* Definition of the various controls */ +struct mctl { + struct v4l2_queryctrl desc; + size_t control; +}; + +#define BLMIN 0x0FF +#define WLMAX 0x3FF + +static const struct mctl maven_controls[] = +{ { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, + "brightness", + 0, WLMAX - BLMIN, 1, 379 - BLMIN, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) }, + { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, + "contrast", + 0, 1023, 1, 127, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) }, + { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER, + "saturation", + 0, 255, 1, 155, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) }, + { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER, + "hue", + 0, 255, 1, 0, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) }, + { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER, + "gamma", + 0, sizeof(maven_gamma)/sizeof(maven_gamma[0])-1, 1, 3, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) }, + { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN, + "test output", + 0, 1, 1, 0, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) }, + { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER, + "deflicker mode", + 0, 2, 1, 0, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) }, + +}; + +#define MAVCTRLS (sizeof(maven_controls)/sizeof(maven_controls[0])) + +/* Return: positive number: id found + -EINVAL: id not found, return failure + -ENOENT: id not found, create fake disabled control */ +static int get_ctrl_id(__u32 v4l2_id) { + int i; + + for (i = 0; i < MAVCTRLS; i++) { + if (v4l2_id < maven_controls[i].desc.id) { + if (maven_controls[i].desc.id == 0x08000000) { + return -EINVAL; + } + return -ENOENT; + } + if (v4l2_id == maven_controls[i].desc.id) { + return i; + } + } + return -EINVAL; +} + +struct maven_data { + struct matrox_fb_info* primary_head; + struct i2c_client* client; + int version; +}; + +static int* get_ctrl_ptr(struct maven_data* md, int idx) { + return (int*)((char*)(md->primary_head) + maven_controls[idx].control); +} + +static int maven_get_reg(struct i2c_client* c, char reg) { + char dst; + struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), ® }, + { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }}; + s32 err; + + err = i2c_transfer(c->adapter, msgs, 2); + if (err < 0) + printk(KERN_INFO "ReadReg(%d) failed\n", reg); + return dst & 0xFF; +} + +static int maven_set_reg(struct i2c_client* c, int reg, int val) { + s32 err; + + err = i2c_smbus_write_byte_data(c, reg, val); + if (err) + printk(KERN_INFO "WriteReg(%d) failed\n", reg); + return err; +} + +static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) { + s32 err; + + err = i2c_smbus_write_word_data(c, reg, val); + if (err) + printk(KERN_INFO "WriteRegPair(%d) failed\n", reg); + return err; +} + +static const struct matrox_pll_features maven_pll = { + 50000, + 27000, + 4, 127, + 2, 31, + 3 +}; + +struct matrox_pll_features2 { + unsigned int vco_freq_min; + unsigned int vco_freq_max; + unsigned int feed_div_min; + unsigned int feed_div_max; + unsigned int in_div_min; + unsigned int in_div_max; + unsigned int post_shift_max; +}; + +struct matrox_pll_ctl { + unsigned int ref_freq; + unsigned int den; +}; + +static const struct matrox_pll_features2 maven1000_pll = { + 50000000, + 300000000, + 5, 128, + 3, 32, + 3 +}; + +static const struct matrox_pll_ctl maven_PAL = { + 540000, + 50 +}; + +static const struct matrox_pll_ctl maven_NTSC = { + 450450, /* 27027000/60 == 27000000/59.94005994 */ + 60 +}; + +static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, + const struct matrox_pll_ctl* ctl, + unsigned int htotal, unsigned int vtotal, + unsigned int* in, unsigned int* feed, unsigned int* post, + unsigned int* h2) { + unsigned int besth2 = 0; + unsigned int fxtal = ctl->ref_freq; + unsigned int fmin = pll->vco_freq_min / ctl->den; + unsigned int fwant; + unsigned int p; + unsigned int scrlen; + unsigned int fmax; + + DBG(__FUNCTION__) + + scrlen = htotal * (vtotal - 1); + fwant = htotal * vtotal; + fmax = pll->vco_freq_max / ctl->den; + + dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n", + fwant, fxtal, htotal, vtotal, fmax); + for (p = 1; p <= pll->post_shift_max; p++) { + if (fwant * 2 > fmax) + break; + fwant *= 2; + } + if (fwant > fmax) + return 0; + for (; p-- > 0; fwant >>= 1) { + unsigned int m; + + if (fwant < fmin) break; + for (m = pll->in_div_min; m <= pll->in_div_max; m++) { + unsigned int n; + unsigned int dvd; + unsigned int ln; + + n = (fwant * m) / fxtal; + if (n < pll->feed_div_min) + continue; + if (n > pll->feed_div_max) + break; + + ln = fxtal * n; + dvd = m << p; + + if (ln % dvd) + continue; + ln = ln / dvd; + + if (ln < scrlen + 2) + continue; + ln = ln - scrlen; + if (ln > htotal) + continue; + dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln); + if (ln > besth2) { + dprintk(KERN_DEBUG "Better...\n"); + *h2 = besth2 = ln; + *post = p; + *in = m; + *feed = n; + } + } + } + if (besth2 < 2) + return 0; + dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant); + return fxtal * (*feed) / (*in) * ctl->den; +} + +static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl, + unsigned int htotal, unsigned int vtotal, + unsigned int* in, unsigned int* feed, unsigned int* post, + unsigned int* htotal2) { + unsigned int fvco; + unsigned int p; + + fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2); + if (!fvco) + return -EINVAL; + p = (1 << p) - 1; + if (fvco <= 100000000) + ; + else if (fvco <= 140000000) + p |= 0x08; + else if (fvco <= 180000000) + p |= 0x10; + else + p |= 0x18; + *post = p; + return 0; +} + +static void DAC1064_calcclock(unsigned int freq, unsigned int fmax, + unsigned int* in, unsigned int* feed, unsigned int* post) { + unsigned int fvco; + unsigned int p; + + fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p); + p = (1 << p) - 1; + if (fvco <= 100000) + ; + else if (fvco <= 140000) + p |= 0x08; + else if (fvco <= 180000) + p |= 0x10; + else + p |= 0x18; + *post = p; + return; +} + +static unsigned char maven_compute_deflicker (const struct maven_data* md) { + unsigned char df; + + df = (md->version == MGATVO_B?0x40:0x00); + switch (md->primary_head->altout.tvo_params.deflicker) { + case 0: +/* df |= 0x00; */ + break; + case 1: + df |= 0xB1; + break; + case 2: + df |= 0xA2; + break; + } + return df; +} + +static void maven_compute_bwlevel (const struct maven_data* md, + int *bl, int *wl) { + const int b = md->primary_head->altout.tvo_params.brightness + BLMIN; + const int c = md->primary_head->altout.tvo_params.contrast; + + *bl = max(b - c, BLMIN); + *wl = min(b + c, WLMAX); +} + +static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) { + return maven_gamma + md->primary_head->altout.tvo_params.gamma; +} + + +static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) { + static struct mavenregs palregs = { { + 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */ + 0x00, + 0x00, /* ? not written */ + 0x00, /* modified by code (F9 written...) */ + 0x00, /* ? not written */ + 0x7E, /* 08 */ + 0x44, /* 09 */ + 0x9C, /* 0A */ + 0x2E, /* 0B */ + 0x21, /* 0C */ + 0x00, /* ? not written */ + 0x3F, 0x03, /* 0E-0F */ + 0x3F, 0x03, /* 10-11 */ + 0x1A, /* 12 */ + 0x2A, /* 13 */ + 0x1C, 0x3D, 0x14, /* 14-16 */ + 0x9C, 0x01, /* 17-18 */ + 0x00, /* 19 */ + 0xFE, /* 1A */ + 0x7E, /* 1B */ + 0x60, /* 1C */ + 0x05, /* 1D */ + 0x89, 0x03, /* 1E-1F */ + 0x72, /* 20 */ + 0x07, /* 21 */ + 0x72, /* 22 */ + 0x00, /* 23 */ + 0x00, /* 24 */ + 0x00, /* 25 */ + 0x08, /* 26 */ + 0x04, /* 27 */ + 0x00, /* 28 */ + 0x1A, /* 29 */ + 0x55, 0x01, /* 2A-2B */ + 0x26, /* 2C */ + 0x07, 0x7E, /* 2D-2E */ + 0x02, 0x54, /* 2F-30 */ + 0xB0, 0x00, /* 31-32 */ + 0x14, /* 33 */ + 0x49, /* 34 */ + 0x00, /* 35 written multiple times */ + 0x00, /* 36 not written */ + 0xA3, /* 37 */ + 0xC8, /* 38 */ + 0x22, /* 39 */ + 0x02, /* 3A */ + 0x22, /* 3B */ + 0x3F, 0x03, /* 3C-3D */ + 0x00, /* 3E written multiple times */ + 0x00, /* 3F not written */ + }, MATROXFB_OUTPUT_MODE_PAL, 625, 50 }; + static struct mavenregs ntscregs = { { + 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */ + 0x00, + 0x00, /* ? not written */ + 0x00, /* modified by code (F9 written...) */ + 0x00, /* ? not written */ + 0x7E, /* 08 */ + 0x43, /* 09 */ + 0x7E, /* 0A */ + 0x3D, /* 0B */ + 0x00, /* 0C */ + 0x00, /* ? not written */ + 0x41, 0x00, /* 0E-0F */ + 0x3C, 0x00, /* 10-11 */ + 0x17, /* 12 */ + 0x21, /* 13 */ + 0x1B, 0x1B, 0x24, /* 14-16 */ + 0x83, 0x01, /* 17-18 */ + 0x00, /* 19 */ + 0x0F, /* 1A */ + 0x0F, /* 1B */ + 0x60, /* 1C */ + 0x05, /* 1D */ + 0x89, 0x02, /* 1E-1F */ + 0x5F, /* 20 */ + 0x04, /* 21 */ + 0x5F, /* 22 */ + 0x01, /* 23 */ + 0x02, /* 24 */ + 0x00, /* 25 */ + 0x0A, /* 26 */ + 0x05, /* 27 */ + 0x00, /* 28 */ + 0x10, /* 29 */ + 0xFF, 0x03, /* 2A-2B */ + 0x24, /* 2C */ + 0x0F, 0x78, /* 2D-2E */ + 0x00, 0x00, /* 2F-30 */ + 0xB2, 0x04, /* 31-32 */ + 0x14, /* 33 */ + 0x02, /* 34 */ + 0x00, /* 35 written multiple times */ + 0x00, /* 36 not written */ + 0xA3, /* 37 */ + 0xC8, /* 38 */ + 0x15, /* 39 */ + 0x05, /* 3A */ + 0x3B, /* 3B */ + 0x3C, 0x00, /* 3C-3D */ + 0x00, /* 3E written multiple times */ + 0x00, /* never written */ + }, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 }; + MINFO_FROM(md->primary_head); + + if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_PAL) + *data = palregs; + else + *data = ntscregs; + + /* Set deflicker */ + data->regs[0x93] = maven_compute_deflicker(md); + + /* set gamma */ + { + const struct maven_gamma* g; + g = maven_compute_gamma(md); + data->regs[0x83] = g->reg83; + data->regs[0x84] = g->reg84; + data->regs[0x85] = g->reg85; + data->regs[0x86] = g->reg86; + data->regs[0x87] = g->reg87; + data->regs[0x88] = g->reg88; + data->regs[0x89] = g->reg89; + data->regs[0x8A] = g->reg8a; + data->regs[0x8B] = g->reg8b; + } + + /* Set contrast / brightness */ + { + int bl, wl; + maven_compute_bwlevel (md, &bl, &wl); + data->regs[0x0e] = bl >> 2; + data->regs[0x0f] = bl & 3; + data->regs[0x1e] = wl >> 2; + data->regs[0x1f] = wl & 3; + } + + /* Set saturation */ + { + data->regs[0x20] = + data->regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation); + } + + /* Set HUE */ + data->regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue); + return; +} + +#define LR(x) maven_set_reg(c, (x), m->regs[(x)]) +#define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8)) +static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) { + int val; + + + maven_set_reg(c, 0x3E, 0x01); + maven_get_reg(c, 0x82); /* fetch oscillator state? */ + maven_set_reg(c, 0x8C, 0x00); + maven_get_reg(c, 0x94); /* get 0x82 */ + maven_set_reg(c, 0x94, 0xA2); + /* xmiscctrl */ + + maven_set_reg_pair(c, 0x8E, 0x1EFF); + maven_set_reg(c, 0xC6, 0x01); + + /* removed code... */ + + maven_get_reg(c, 0x06); + maven_set_reg(c, 0x06, 0xF9); /* or read |= 0xF0 ? */ + + /* removed code here... */ + + /* real code begins here? */ + /* chroma subcarrier */ + LR(0x00); LR(0x01); LR(0x02); LR(0x03); + + LR(0x04); + + LR(0x2C); + LR(0x08); + LR(0x0A); + LR(0x09); + LR(0x29); + LRP(0x31); + LRP(0x17); + LR(0x0B); + LR(0x0C); + if (m->mode == MATROXFB_OUTPUT_MODE_PAL) { + maven_set_reg(c, 0x35, 0x10); /* ... */ + } else { + maven_set_reg(c, 0x35, 0x0F); /* ... */ + } + + LRP(0x10); + + LRP(0x0E); + LRP(0x1E); + + LR(0x20); /* saturation #1 */ + LR(0x22); /* saturation #2 */ + LR(0x25); /* hue */ + LR(0x34); + LR(0x33); + LR(0x19); + LR(0x12); + LR(0x3B); + LR(0x13); + LR(0x39); + LR(0x1D); + LR(0x3A); + LR(0x24); + LR(0x14); + LR(0x15); + LR(0x16); + LRP(0x2D); + LRP(0x2F); + LR(0x1A); + LR(0x1B); + LR(0x1C); + LR(0x23); + LR(0x26); + LR(0x28); + LR(0x27); + LR(0x21); + LRP(0x2A); + if (m->mode == MATROXFB_OUTPUT_MODE_PAL) + maven_set_reg(c, 0x35, 0x1D); /* ... */ + else + maven_set_reg(c, 0x35, 0x1C); + + LRP(0x3C); + LR(0x37); + LR(0x38); + maven_set_reg(c, 0xB3, 0x01); + + maven_get_reg(c, 0xB0); /* read 0x80 */ + maven_set_reg(c, 0xB0, 0x08); /* ugh... */ + maven_get_reg(c, 0xB9); /* read 0x7C */ + maven_set_reg(c, 0xB9, 0x78); + maven_get_reg(c, 0xBF); /* read 0x00 */ + maven_set_reg(c, 0xBF, 0x02); + maven_get_reg(c, 0x94); /* read 0x82 */ + maven_set_reg(c, 0x94, 0xB3); + + LR(0x80); /* 04 1A 91 or 05 21 91 */ + LR(0x81); + LR(0x82); + + maven_set_reg(c, 0x8C, 0x20); + maven_get_reg(c, 0x8D); + maven_set_reg(c, 0x8D, 0x10); + + LR(0x90); /* 4D 50 52 or 4E 05 45 */ + LR(0x91); + LR(0x92); + + LRP(0x9A); /* 0049 or 004F */ + LRP(0x9C); /* 0004 or 0004 */ + LRP(0x9E); /* 0458 or 045E */ + LRP(0xA0); /* 05DA or 051B */ + LRP(0xA2); /* 00CC or 00CF */ + LRP(0xA4); /* 007D or 007F */ + LRP(0xA6); /* 007C or 007E */ + LRP(0xA8); /* 03CB or 03CE */ + LRP(0x98); /* 0000 or 0000 */ + LRP(0xAE); /* 0044 or 003A */ + LRP(0x96); /* 05DA or 051B */ + LRP(0xAA); /* 04BC or 046A */ + LRP(0xAC); /* 004D or 004E */ + + LR(0xBE); + LR(0xC2); + + maven_get_reg(c, 0x8D); + maven_set_reg(c, 0x8D, 0x04); + + LR(0x20); /* saturation #1 */ + LR(0x22); /* saturation #2 */ + LR(0x93); /* whoops */ + LR(0x20); /* oh, saturation #1 again */ + LR(0x22); /* oh, saturation #2 again */ + LR(0x25); /* hue */ + LRP(0x0E); + LRP(0x1E); + LRP(0x0E); /* problems with memory? */ + LRP(0x1E); /* yes, matrox must have problems in memory area... */ + + /* load gamma correction stuff */ + LR(0x83); + LR(0x84); + LR(0x85); + LR(0x86); + LR(0x87); + LR(0x88); + LR(0x89); + LR(0x8A); + LR(0x8B); + + val = maven_get_reg(c, 0x8D); + val &= 0x14; /* 0x10 or anything ored with it */ + maven_set_reg(c, 0x8D, val); + + LR(0x33); + LR(0x19); + LR(0x12); + LR(0x3B); + LR(0x13); + LR(0x39); + LR(0x1D); + LR(0x3A); + LR(0x24); + LR(0x14); + LR(0x15); + LR(0x16); + LRP(0x2D); + LRP(0x2F); + LR(0x1A); + LR(0x1B); + LR(0x1C); + LR(0x23); + LR(0x26); + LR(0x28); + LR(0x27); + LR(0x21); + LRP(0x2A); + if (m->mode == MATROXFB_OUTPUT_MODE_PAL) + maven_set_reg(c, 0x35, 0x1D); + else + maven_set_reg(c, 0x35, 0x1C); + LRP(0x3C); + LR(0x37); + LR(0x38); + + maven_get_reg(c, 0xB0); + LR(0xB0); /* output mode */ + LR(0x90); + LR(0xBE); + LR(0xC2); + + LRP(0x9A); + LRP(0xA2); + LRP(0x9E); + LRP(0xA6); + LRP(0xAA); + LRP(0xAC); + maven_set_reg(c, 0x3E, 0x00); + maven_set_reg(c, 0x95, 0x20); +} + +static int maven_find_exact_clocks(unsigned int ht, unsigned int vt, + struct mavenregs* m) { + unsigned int x; + unsigned int err = ~0; + + /* 1:1 */ + m->regs[0x80] = 0x0F; + m->regs[0x81] = 0x07; + m->regs[0x82] = 0x81; + + for (x = 0; x < 8; x++) { + unsigned int a, b, c, h2; + unsigned int h = ht + 2 + x; + + if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) { + unsigned int diff = h - h2; + + if (diff < err) { + err = diff; + m->regs[0x80] = a - 1; + m->regs[0x81] = b - 1; + m->regs[0x82] = c | 0x80; + m->hcorr = h2 - 2; + m->htotal = h - 2; + } + } + } + return err != ~0U; +} + +static inline int maven_compute_timming(struct maven_data* md, + struct my_timming* mt, + struct mavenregs* m) { + unsigned int tmpi; + unsigned int a, bv, c; + MINFO_FROM(md->primary_head); + + m->mode = ACCESS_FBINFO(outputs[1]).mode; + if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) { + unsigned int lmargin; + unsigned int umargin; + unsigned int vslen; + unsigned int hcrt; + unsigned int slen; + + maven_init_TVdata(md, m); + + if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0) + return -EINVAL; + + lmargin = mt->HTotal - mt->HSyncEnd; + slen = mt->HSyncEnd - mt->HSyncStart; + hcrt = mt->HTotal - slen - mt->delay; + umargin = mt->VTotal - mt->VSyncEnd; + vslen = mt->VSyncEnd - mt->VSyncStart; + + if (m->hcorr < mt->HTotal) + hcrt += m->hcorr; + if (hcrt > mt->HTotal) + hcrt -= mt->HTotal; + if (hcrt + 2 > mt->HTotal) + hcrt = 0; /* or issue warning? */ + + /* last (first? middle?) line in picture can have different length */ + /* hlen - 2 */ + m->regs[0x96] = m->hcorr; + m->regs[0x97] = m->hcorr >> 8; + /* ... */ + m->regs[0x98] = 0x00; m->regs[0x99] = 0x00; + /* hblanking end */ + m->regs[0x9A] = lmargin; /* 100% */ + m->regs[0x9B] = lmargin >> 8; /* 100% */ + /* who knows */ + m->regs[0x9C] = 0x04; + m->regs[0x9D] = 0x00; + /* htotal - 2 */ + m->regs[0xA0] = m->htotal; + m->regs[0xA1] = m->htotal >> 8; + /* vblanking end */ + m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */ + m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8; + /* something end... [A6]+1..[A8] */ + if (md->version == MGATVO_B) { + m->regs[0xA4] = 0x04; + m->regs[0xA5] = 0x00; + } else { + m->regs[0xA4] = 0x01; + m->regs[0xA5] = 0x00; + } + /* something start... 0..[A4]-1 */ + m->regs[0xA6] = 0x00; + m->regs[0xA7] = 0x00; + /* vertical line count - 1 */ + m->regs[0xA8] = mt->VTotal - 1; + m->regs[0xA9] = (mt->VTotal - 1) >> 8; + /* horizontal vidrst pos */ + m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */ + m->regs[0xAB] = hcrt >> 8; + /* vertical vidrst pos */ + m->regs[0xAC] = mt->VTotal - 2; + m->regs[0xAD] = (mt->VTotal - 2) >> 8; + /* moves picture up/down and so on... */ + m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */ + m->regs[0xAF] = 0x00; + { + int hdec; + int hlen; + unsigned int ibmin = 4 + lmargin + mt->HDisplay; + unsigned int ib; + int i; + + /* Verify! */ + /* Where 94208 came from? */ + if (mt->HTotal) + hdec = 94208 / (mt->HTotal); + else + hdec = 0x81; + if (hdec > 0x81) + hdec = 0x81; + if (hdec < 0x41) + hdec = 0x41; + hdec--; + hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec); + if (hlen < 0) + hlen = 0; + hlen = hlen >> 8; + if (hlen > 0xFF) + hlen = 0xFF; + /* Now we have to compute input buffer length. + If you want any picture, it must be between + 4 + lmargin + xres + and + 94208 / hdec + If you want perfect picture even on the top + of screen, it must be also + 0x3C0000 * i / hdec + Q - R / hdec + where + R Qmin Qmax + 0x07000 0x5AE 0x5BF + 0x08000 0x5CF 0x5FF + 0x0C000 0x653 0x67F + 0x10000 0x6F8 0x6FF + */ + i = 1; + do { + ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8; + i++; + } while (ib < ibmin); + if (ib >= m->htotal + 2) { + ib = ibmin; + } + + m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */ + m->regs[0xC2] = hlen; + /* 'valid' input line length */ + m->regs[0x9E] = ib; + m->regs[0x9F] = ib >> 8; + } + { + int vdec; + int vlen; + +#define MATROX_USE64BIT_DIVIDE + if (mt->VTotal) { +#ifdef MATROX_USE64BIT_DIVIDE + u64 f1; + u32 a; + u32 b; + + a = m->vlines * (m->htotal + 2); + b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2; + + f1 = ((u64)a) << 15; /* *32768 */ + do_div(f1, b); + vdec = f1; +#else + vdec = m->vlines * 32768 / mt->VTotal; +#endif + } else + vdec = 0x8000; + if (vdec > 0x8000) + vdec = 0x8000; + vlen = (vslen + umargin + mt->VDisplay) * vdec; + vlen = (vlen >> 16) - 146; /* FIXME: 146?! */ + if (vlen < 0) + vlen = 0; + if (vlen > 0xFF) + vlen = 0xFF; + vdec--; + m->regs[0x91] = vdec; + m->regs[0x92] = vdec >> 8; + m->regs[0xBE] = vlen; + } + m->regs[0xB0] = 0x08; /* output: SVideo/Composite */ + return 0; + } + + DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c); + m->regs[0x80] = a; + m->regs[0x81] = bv; + m->regs[0x82] = c | 0x80; + + m->regs[0xB3] = 0x01; + m->regs[0x94] = 0xB2; + + /* htotal... */ + m->regs[0x96] = mt->HTotal; + m->regs[0x97] = mt->HTotal >> 8; + /* ?? */ + m->regs[0x98] = 0x00; + m->regs[0x99] = 0x00; + /* hsync len */ + tmpi = mt->HSyncEnd - mt->HSyncStart; + m->regs[0x9A] = tmpi; + m->regs[0x9B] = tmpi >> 8; + /* hblank end */ + tmpi = mt->HTotal - mt->HSyncStart; + m->regs[0x9C] = tmpi; + m->regs[0x9D] = tmpi >> 8; + /* hblank start */ + tmpi += mt->HDisplay; + m->regs[0x9E] = tmpi; + m->regs[0x9F] = tmpi >> 8; + /* htotal + 1 */ + tmpi = mt->HTotal + 1; + m->regs[0xA0] = tmpi; + m->regs[0xA1] = tmpi >> 8; + /* vsync?! */ + tmpi = mt->VSyncEnd - mt->VSyncStart - 1; + m->regs[0xA2] = tmpi; + m->regs[0xA3] = tmpi >> 8; + /* ignored? */ + tmpi = mt->VTotal - mt->VSyncStart; + m->regs[0xA4] = tmpi; + m->regs[0xA5] = tmpi >> 8; + /* ignored? */ + tmpi = mt->VTotal - 1; + m->regs[0xA6] = tmpi; + m->regs[0xA7] = tmpi >> 8; + /* vtotal - 1 */ + m->regs[0xA8] = tmpi; + m->regs[0xA9] = tmpi >> 8; + /* hor vidrst */ + tmpi = mt->HTotal - mt->delay; + m->regs[0xAA] = tmpi; + m->regs[0xAB] = tmpi >> 8; + /* vert vidrst */ + tmpi = mt->VTotal - 2; + m->regs[0xAC] = tmpi; + m->regs[0xAD] = tmpi >> 8; + /* ignored? */ + m->regs[0xAE] = 0x00; + m->regs[0xAF] = 0x00; + + m->regs[0xB0] = 0x03; /* output: monitor */ + m->regs[0xB1] = 0xA0; /* ??? */ + m->regs[0x8C] = 0x20; /* must be set... */ + m->regs[0x8D] = 0x04; /* defaults to 0x10: test signal */ + m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */ + m->regs[0xBF] = 0x22; /* makes picture stable */ + + return 0; +} + +static inline int maven_program_timming(struct maven_data* md, + const struct mavenregs* m) { + struct i2c_client* c = md->client; + + if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) { + LR(0x80); + LR(0x81); + LR(0x82); + + LR(0xB3); + LR(0x94); + + LRP(0x96); + LRP(0x98); + LRP(0x9A); + LRP(0x9C); + LRP(0x9E); + LRP(0xA0); + LRP(0xA2); + LRP(0xA4); + LRP(0xA6); + LRP(0xA8); + LRP(0xAA); + LRP(0xAC); + LRP(0xAE); + + LR(0xB0); /* output: monitor */ + LR(0xB1); /* ??? */ + LR(0x8C); /* must be set... */ + LR(0x8D); /* defaults to 0x10: test signal */ + LR(0xB9); /* defaults to 0x2C: too bright */ + LR(0xBF); /* makes picture stable */ + } else { + maven_init_TV(c, m); + } + return 0; +} + +static inline int maven_resync(struct maven_data* md) { + struct i2c_client* c = md->client; + maven_set_reg(c, 0x95, 0x20); /* start whole thing */ + return 0; +} + +static int maven_get_queryctrl (struct maven_data* md, + struct v4l2_queryctrl *p) { + int i; + + i = get_ctrl_id(p->id); + if (i >= 0) { + *p = maven_controls[i].desc; + return 0; + } + if (i == -ENOENT) { + static const struct v4l2_queryctrl disctrl = + { .flags = V4L2_CTRL_FLAG_DISABLED }; + + i = p->id; + *p = disctrl; + p->id = i; + sprintf(p->name, "Ctrl #%08X", i); + return 0; + } + return -EINVAL; +} + +static int maven_set_control (struct maven_data* md, + struct v4l2_control *p) { + int i; + + i = get_ctrl_id(p->id); + if (i < 0) return -EINVAL; + + /* + * Check if changed. + */ + if (p->value == *get_ctrl_ptr(md, i)) return 0; + + /* + * Check limits. + */ + if (p->value > maven_controls[i].desc.maximum) return -EINVAL; + if (p->value < maven_controls[i].desc.minimum) return -EINVAL; + + /* + * Store new value. + */ + *get_ctrl_ptr(md, i) = p->value; + + switch (p->id) { + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_CONTRAST: + { + int blacklevel, whitelevel; + maven_compute_bwlevel(md, &blacklevel, &whitelevel); + blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8); + whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8); + maven_set_reg_pair(md->client, 0x0e, blacklevel); + maven_set_reg_pair(md->client, 0x1e, whitelevel); + } + break; + case V4L2_CID_SATURATION: + { + maven_set_reg(md->client, 0x20, p->value); + maven_set_reg(md->client, 0x22, p->value); + } + break; + case V4L2_CID_HUE: + { + maven_set_reg(md->client, 0x25, p->value); + } + break; + case V4L2_CID_GAMMA: + { + const struct maven_gamma* g; + g = maven_compute_gamma(md); + maven_set_reg(md->client, 0x83, g->reg83); + maven_set_reg(md->client, 0x84, g->reg84); + maven_set_reg(md->client, 0x85, g->reg85); + maven_set_reg(md->client, 0x86, g->reg86); + maven_set_reg(md->client, 0x87, g->reg87); + maven_set_reg(md->client, 0x88, g->reg88); + maven_set_reg(md->client, 0x89, g->reg89); + maven_set_reg(md->client, 0x8a, g->reg8a); + maven_set_reg(md->client, 0x8b, g->reg8b); + } + break; + case MATROXFB_CID_TESTOUT: + { + unsigned char val + = maven_get_reg (md->client,0x8d); + if (p->value) val |= 0x10; + else val &= ~0x10; + maven_set_reg (md->client, 0x8d, val); + } + break; + case MATROXFB_CID_DEFLICKER: + { + maven_set_reg(md->client, 0x93, maven_compute_deflicker(md)); + } + break; + } + + + return 0; +} + +static int maven_get_control (struct maven_data* md, + struct v4l2_control *p) { + int i; + + i = get_ctrl_id(p->id); + if (i < 0) return -EINVAL; + p->value = *get_ctrl_ptr(md, i); + return 0; +} + +/******************************************************/ + +static int maven_out_compute(void* md, struct my_timming* mt) { +#define mdinfo ((struct maven_data*)md) +#define minfo (mdinfo->primary_head) + return maven_compute_timming(md, mt, &ACCESS_FBINFO(hw).maven); +#undef minfo +#undef mdinfo +} + +static int maven_out_program(void* md) { +#define mdinfo ((struct maven_data*)md) +#define minfo (mdinfo->primary_head) + return maven_program_timming(md, &ACCESS_FBINFO(hw).maven); +#undef minfo +#undef mdinfo +} + +static int maven_out_start(void* md) { + return maven_resync(md); +} + +static int maven_out_verify_mode(void* md, u_int32_t arg) { + switch (arg) { + case MATROXFB_OUTPUT_MODE_PAL: + case MATROXFB_OUTPUT_MODE_NTSC: + case MATROXFB_OUTPUT_MODE_MONITOR: + return 0; + } + return -EINVAL; +} + +static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) { + return maven_get_queryctrl(md, p); +} + +static int maven_out_get_ctrl(void* md, struct v4l2_control* p) { + return maven_get_control(md, p); +} + +static int maven_out_set_ctrl(void* md, struct v4l2_control* p) { + return maven_set_control(md, p); +} + +static struct matrox_altout maven_altout = { + .name = "Secondary output", + .compute = maven_out_compute, + .program = maven_out_program, + .start = maven_out_start, + .verifymode = maven_out_verify_mode, + .getqueryctrl = maven_out_get_queryctrl, + .getctrl = maven_out_get_ctrl, + .setctrl = maven_out_set_ctrl, +}; + +static int maven_init_client(struct i2c_client* clnt) { + struct maven_data* md = i2c_get_clientdata(clnt); + MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo); + + md->primary_head = MINFO; + md->client = clnt; + down_write(&ACCESS_FBINFO(altout.lock)); + ACCESS_FBINFO(outputs[1]).output = &maven_altout; + ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src; + ACCESS_FBINFO(outputs[1]).data = md; + ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR; + up_write(&ACCESS_FBINFO(altout.lock)); + if (maven_get_reg(clnt, 0xB2) < 0x14) { + md->version = MGATVO_B; + /* Tweak some things for this old chip */ + } else { + md->version = MGATVO_C; + } + /* + * Set all parameters to its initial values. + */ + { + unsigned int i; + + for (i = 0; i < MAVCTRLS; ++i) { + *get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value; + } + } + + return 0; +} + +static int maven_shutdown_client(struct i2c_client* clnt) { + struct maven_data* md = i2c_get_clientdata(clnt); + + if (md->primary_head) { + MINFO_FROM(md->primary_head); + + down_write(&ACCESS_FBINFO(altout.lock)); + ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE; + ACCESS_FBINFO(outputs[1]).output = NULL; + ACCESS_FBINFO(outputs[1]).data = NULL; + ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR; + up_write(&ACCESS_FBINFO(altout.lock)); + md->primary_head = NULL; + } + return 0; +} + +static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { MAVEN_I2CID, MAVEN_I2CID, I2C_CLIENT_END }; +I2C_CLIENT_INSMOD; + +static struct i2c_driver maven_driver; + +static int maven_detect_client(struct i2c_adapter* adapter, int address, int kind) { + int err = 0; + struct i2c_client* new_client; + struct maven_data* data; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_PROTOCOL_MANGLING)) + goto ERROR0; + if (!(new_client = (struct i2c_client*)kmalloc(sizeof(*new_client) + sizeof(*data), + GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + memset(new_client, 0, sizeof(*new_client) + sizeof(*data)); + data = (struct maven_data*)(new_client + 1); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &maven_driver; + new_client->flags = 0; + strcpy(new_client->name, "maven client"); + if ((err = i2c_attach_client(new_client))) + goto ERROR3; + err = maven_init_client(new_client); + if (err) + goto ERROR4; + return 0; +ERROR4:; + i2c_detach_client(new_client); +ERROR3:; + kfree(new_client); +ERROR0:; + return err; +} + +static int maven_attach_adapter(struct i2c_adapter* adapter) { + if (adapter->id == (I2C_ALGO_BIT | I2C_HW_B_G400)) + return i2c_probe(adapter, &addr_data, &maven_detect_client); + return 0; +} + +static int maven_detach_client(struct i2c_client* client) { + int err; + + if ((err = i2c_detach_client(client))) { + printk(KERN_ERR "maven: Cannot deregister client\n"); + return err; + } + maven_shutdown_client(client); + kfree(client); + return 0; +} + +static int maven_command(struct i2c_client* client, unsigned int cmd, void* arg) { + return -ENOIOCTLCMD; /* or -EINVAL, depends on who will call this */ +} + +static struct i2c_driver maven_driver={ + .owner = THIS_MODULE, + .name = "maven", + .id = I2C_DRIVERID_MGATVO, + .flags = I2C_DF_NOTIFY, + .attach_adapter = maven_attach_adapter, + .detach_client = maven_detach_client, + .command = maven_command, +}; + +/* ************************** */ + +static int matroxfb_maven_init(void) { + int err; + + err = i2c_add_driver(&maven_driver); + if (err) { + printk(KERN_ERR "maven: Maven driver failed to register (%d).\n", err); + return err; + } + return 0; +} + +static void matroxfb_maven_exit(void) { + i2c_del_driver(&maven_driver); +} + +MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver"); +MODULE_LICENSE("GPL"); +module_init(matroxfb_maven_init); +module_exit(matroxfb_maven_exit); +/* we do not have __setup() yet */ diff --git a/drivers/video/matrox/matroxfb_maven.h b/drivers/video/matrox/matroxfb_maven.h new file mode 100644 index 000000000000..99eddec9f30c --- /dev/null +++ b/drivers/video/matrox/matroxfb_maven.h @@ -0,0 +1,20 @@ +#ifndef __MATROXFB_MAVEN_H__ +#define __MATROXFB_MAVEN_H__ + +#include <linux/ioctl.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include "matroxfb_base.h" + +struct i2c_bit_adapter { + struct i2c_adapter adapter; + int initialized; + struct i2c_algo_bit_data bac; + struct matrox_fb_info* minfo; + struct { + unsigned int data; + unsigned int clock; + } mask; +}; + +#endif /* __MATROXFB_MAVEN_H__ */ diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c new file mode 100644 index 000000000000..76fd3a519b8a --- /dev/null +++ b/drivers/video/matrox/matroxfb_misc.c @@ -0,0 +1,777 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 + * + * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Portions Copyright (c) 2001 Matrox Graphics Inc. + * + * Version: 1.65 2002/08/14 + * + * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> + * + * Contributors: "menion?" <menion@mindless.com> + * Betatesting, fixes, ideas + * + * "Kurt Garloff" <garloff@suse.de> + * Betatesting, fixes, ideas, videomodes, videomodes timmings + * + * "Tom Rini" <trini@kernel.crashing.org> + * MTRR stuff, PPC cleanups, betatesting, fixes, ideas + * + * "Bibek Sahu" <scorpio@dodds.net> + * Access device through readb|w|l and write b|w|l + * Extensive debugging stuff + * + * "Daniel Haun" <haund@usa.net> + * Testing, hardware cursor fixes + * + * "Scott Wood" <sawst46+@pitt.edu> + * Fixes + * + * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> + * Betatesting + * + * "Kelly French" <targon@hazmat.com> + * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> + * Betatesting, bug reporting + * + * "Pablo Bianucci" <pbian@pccp.com.ar> + * Fixes, ideas, betatesting + * + * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> + * Fixes, enhandcements, ideas, betatesting + * + * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> + * PPC betatesting, PPC support, backward compatibility + * + * "Paul Womar" <Paul@pwomar.demon.co.uk> + * "Owen Waller" <O.Waller@ee.qub.ac.uk> + * PPC betatesting + * + * "Thomas Pornin" <pornin@bolet.ens.fr> + * Alpha betatesting + * + * "Pieter van Leuven" <pvl@iae.nl> + * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> + * G100 testing + * + * "H. Peter Arvin" <hpa@transmeta.com> + * Ideas + * + * "Cort Dougan" <cort@cs.nmt.edu> + * CHRP fixes and PReP cleanup + * + * "Mark Vojkovich" <mvojkovi@ucsd.edu> + * G400 support + * + * "David C. Hansen" <haveblue@us.ibm.com> + * Fixes + * + * (following author is not in any relation with this code, but his code + * is included in this driver) + * + * Based on framebuffer driver for VBE 2.0 compliant graphic boards + * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + * + * (following author is not in any relation with this code, but his ideas + * were used when writting this driver) + * + * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> + * + */ + +/* make checkconfig does not check includes for this... */ +#include <linux/config.h> + +#include "matroxfb_misc.h" +#include <linux/interrupt.h> +#include <linux/matroxfb.h> + +void matroxfb_DAC_out(CPMINFO int reg, int val) { + DBG_REG(__FUNCTION__) + mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); + mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val); +} + +int matroxfb_DAC_in(CPMINFO int reg) { + DBG_REG(__FUNCTION__) + mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); + return mga_inb(M_RAMDAC_BASE+M_X_DATAREG); +} + +void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) { + unsigned int pixclock = var->pixclock; + + DBG(__FUNCTION__) + + if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ + mt->pixclock = 1000000000 / pixclock; + if (mt->pixclock < 1) mt->pixclock = 1; + mt->mnp = -1; + mt->dblscan = var->vmode & FB_VMODE_DOUBLE; + mt->interlaced = var->vmode & FB_VMODE_INTERLACED; + mt->HDisplay = var->xres; + mt->HSyncStart = mt->HDisplay + var->right_margin; + mt->HSyncEnd = mt->HSyncStart + var->hsync_len; + mt->HTotal = mt->HSyncEnd + var->left_margin; + mt->VDisplay = var->yres; + mt->VSyncStart = mt->VDisplay + var->lower_margin; + mt->VSyncEnd = mt->VSyncStart + var->vsync_len; + mt->VTotal = mt->VSyncEnd + var->upper_margin; + mt->sync = var->sync; +} + +int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax, + unsigned int* in, unsigned int* feed, unsigned int* post) { + unsigned int bestdiff = ~0; + unsigned int bestvco = 0; + unsigned int fxtal = pll->ref_freq; + unsigned int fwant; + unsigned int p; + + DBG(__FUNCTION__) + + fwant = freq; + +#ifdef DEBUG + printk(KERN_ERR "post_shift_max: %d\n", pll->post_shift_max); + printk(KERN_ERR "ref_freq: %d\n", pll->ref_freq); + printk(KERN_ERR "freq: %d\n", freq); + printk(KERN_ERR "vco_freq_min: %d\n", pll->vco_freq_min); + printk(KERN_ERR "in_div_min: %d\n", pll->in_div_min); + printk(KERN_ERR "in_div_max: %d\n", pll->in_div_max); + printk(KERN_ERR "feed_div_min: %d\n", pll->feed_div_min); + printk(KERN_ERR "feed_div_max: %d\n", pll->feed_div_max); + printk(KERN_ERR "fmax: %d\n", fmax); +#endif + for (p = 1; p <= pll->post_shift_max; p++) { + if (fwant * 2 > fmax) + break; + fwant *= 2; + } + if (fwant < pll->vco_freq_min) fwant = pll->vco_freq_min; + if (fwant > fmax) fwant = fmax; + for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) { + unsigned int m; + + if (fwant < pll->vco_freq_min) break; + for (m = pll->in_div_min; m <= pll->in_div_max; m++) { + unsigned int diff, fvco; + unsigned int n; + + n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1; + if (n > pll->feed_div_max) + break; + if (n < pll->feed_div_min) + n = pll->feed_div_min; + fvco = (fxtal * (n + 1)) / (m + 1); + if (fvco < fwant) + diff = fwant - fvco; + else + diff = fvco - fwant; + if (diff < bestdiff) { + bestdiff = diff; + *post = p; + *in = m; + *feed = n; + bestvco = fvco; + } + } + } + dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant); + return bestvco; +} + +int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) { + unsigned int hd, hs, he, hbe, ht; + unsigned int vd, vs, ve, vt, lc; + unsigned int wd; + unsigned int divider; + int i; + int fwidth; + struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); + + fwidth = 8; + + DBG(__FUNCTION__) + + hw->SEQ[0] = 0x00; + if (fwidth == 9) + hw->SEQ[1] = 0x00; + else + hw->SEQ[1] = 0x01; /* or 0x09 */ + hw->SEQ[2] = 0x0F; /* bitplanes */ + hw->SEQ[3] = 0x00; + hw->SEQ[4] = 0x0E; + /* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millennium code... Hope that by MGA1064 too */ + if (m->dblscan) { + m->VTotal <<= 1; + m->VDisplay <<= 1; + m->VSyncStart <<= 1; + m->VSyncEnd <<= 1; + } + if (m->interlaced) { + m->VTotal >>= 1; + m->VDisplay >>= 1; + m->VSyncStart >>= 1; + m->VSyncEnd >>= 1; + } + + /* GCTL is ignored when not using 0xA0000 aperture */ + hw->GCTL[0] = 0x00; + hw->GCTL[1] = 0x00; + hw->GCTL[2] = 0x00; + hw->GCTL[3] = 0x00; + hw->GCTL[4] = 0x00; + hw->GCTL[5] = 0x40; + hw->GCTL[6] = 0x05; + hw->GCTL[7] = 0x0F; + hw->GCTL[8] = 0xFF; + + /* Whole ATTR is ignored in PowerGraphics mode */ + for (i = 0; i < 16; i++) + hw->ATTR[i] = i; + hw->ATTR[16] = 0x41; + hw->ATTR[17] = 0xFF; + hw->ATTR[18] = 0x0F; + if (fwidth == 9) + hw->ATTR[19] = 0x08; + else + hw->ATTR[19] = 0x00; + hw->ATTR[20] = 0x00; + + hd = m->HDisplay >> 3; + hs = m->HSyncStart >> 3; + he = m->HSyncEnd >> 3; + ht = m->HTotal >> 3; + /* standard timmings are in 8pixels, but for interleaved we cannot */ + /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */ + /* using 16 or more pixels per unit can save us */ + divider = ACCESS_FBINFO(curr.final_bppShift); + while (divider & 3) { + hd >>= 1; + hs >>= 1; + he >>= 1; + ht >>= 1; + divider <<= 1; + } + divider = divider / 4; + /* divider can be from 1 to 8 */ + while (divider > 8) { + hd <<= 1; + hs <<= 1; + he <<= 1; + ht <<= 1; + divider >>= 1; + } + hd = hd - 1; + hs = hs - 1; + he = he - 1; + ht = ht - 1; + vd = m->VDisplay - 1; + vs = m->VSyncStart - 1; + ve = m->VSyncEnd - 1; + vt = m->VTotal - 2; + lc = vd; + /* G200 cannot work with (ht & 7) == 6 */ + if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04)) + ht++; + hbe = ht; + wd = ACCESS_FBINFO(fbcon).var.xres_virtual * ACCESS_FBINFO(curr.final_bppShift) / 64; + + hw->CRTCEXT[0] = 0; + hw->CRTCEXT[5] = 0; + if (m->interlaced) { + hw->CRTCEXT[0] = 0x80; + hw->CRTCEXT[5] = (hs + he - ht) >> 1; + if (!m->dblscan) + wd <<= 1; + vt &= ~1; + } + hw->CRTCEXT[0] |= (wd & 0x300) >> 4; + hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) | + ((hd & 0x100) >> 7) | /* blanking */ + ((hs & 0x100) >> 6) | /* sync start */ + (hbe & 0x040); /* end hor. blanking */ + /* FIXME: Enable vidrst only on G400, and only if TV-out is used */ + if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) + hw->CRTCEXT[1] |= 0x88; /* enable horizontal and vertical vidrst */ + hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) | + ((vd & 0x400) >> 8) | /* disp end */ + ((vd & 0xC00) >> 7) | /* vblanking start */ + ((vs & 0xC00) >> 5) | + ((lc & 0x400) >> 3); + hw->CRTCEXT[3] = (divider - 1) | 0x80; + hw->CRTCEXT[4] = 0; + + hw->CRTC[0] = ht-4; + hw->CRTC[1] = hd; + hw->CRTC[2] = hd; + hw->CRTC[3] = (hbe & 0x1F) | 0x80; + hw->CRTC[4] = hs; + hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F); + hw->CRTC[6] = vt & 0xFF; + hw->CRTC[7] = ((vt & 0x100) >> 8) | + ((vd & 0x100) >> 7) | + ((vs & 0x100) >> 6) | + ((vd & 0x100) >> 5) | + ((lc & 0x100) >> 4) | + ((vt & 0x200) >> 4) | + ((vd & 0x200) >> 3) | + ((vs & 0x200) >> 2); + hw->CRTC[8] = 0x00; + hw->CRTC[9] = ((vd & 0x200) >> 4) | + ((lc & 0x200) >> 3); + if (m->dblscan && !m->interlaced) + hw->CRTC[9] |= 0x80; + for (i = 10; i < 16; i++) + hw->CRTC[i] = 0x00; + hw->CRTC[16] = vs /* & 0xFF */; + hw->CRTC[17] = (ve & 0x0F) | 0x20; + hw->CRTC[18] = vd /* & 0xFF */; + hw->CRTC[19] = wd /* & 0xFF */; + hw->CRTC[20] = 0x00; + hw->CRTC[21] = vd /* & 0xFF */; + hw->CRTC[22] = (vt + 1) /* & 0xFF */; + hw->CRTC[23] = 0xC3; + hw->CRTC[24] = lc; + return 0; +}; + +void matroxfb_vgaHWrestore(WPMINFO2) { + int i; + struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); + CRITFLAGS + + DBG(__FUNCTION__) + + dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg); + dprintk(KERN_INFO "SEQ regs: "); + for (i = 0; i < 5; i++) + dprintk("%02X:", hw->SEQ[i]); + dprintk("\n"); + dprintk(KERN_INFO "GDC regs: "); + for (i = 0; i < 9; i++) + dprintk("%02X:", hw->GCTL[i]); + dprintk("\n"); + dprintk(KERN_INFO "CRTC regs: "); + for (i = 0; i < 25; i++) + dprintk("%02X:", hw->CRTC[i]); + dprintk("\n"); + dprintk(KERN_INFO "ATTR regs: "); + for (i = 0; i < 21; i++) + dprintk("%02X:", hw->ATTR[i]); + dprintk("\n"); + + CRITBEGIN + + mga_inb(M_ATTR_RESET); + mga_outb(M_ATTR_INDEX, 0); + mga_outb(M_MISC_REG, hw->MiscOutReg); + for (i = 1; i < 5; i++) + mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]); + mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F); + for (i = 0; i < 25; i++) + mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]); + for (i = 0; i < 9; i++) + mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]); + for (i = 0; i < 21; i++) { + mga_inb(M_ATTR_RESET); + mga_outb(M_ATTR_INDEX, i); + mga_outb(M_ATTR_INDEX, hw->ATTR[i]); + } + mga_outb(M_PALETTE_MASK, 0xFF); + mga_outb(M_DAC_REG, 0x00); + for (i = 0; i < 768; i++) + mga_outb(M_DAC_VAL, hw->DACpal[i]); + mga_inb(M_ATTR_RESET); + mga_outb(M_ATTR_INDEX, 0x20); + + CRITEND +} + +static void get_pins(unsigned char __iomem* pins, struct matrox_bios* bd) { + unsigned int b0 = readb(pins); + + if (b0 == 0x2E && readb(pins+1) == 0x41) { + unsigned int pins_len = readb(pins+2); + unsigned int i; + unsigned char cksum; + unsigned char* dst = bd->pins; + + if (pins_len < 3 || pins_len > 128) { + return; + } + *dst++ = 0x2E; + *dst++ = 0x41; + *dst++ = pins_len; + cksum = 0x2E + 0x41 + pins_len; + for (i = 3; i < pins_len; i++) { + cksum += *dst++ = readb(pins+i); + } + if (cksum) { + return; + } + bd->pins_len = pins_len; + } else if (b0 == 0x40 && readb(pins+1) == 0x00) { + unsigned int i; + unsigned char* dst = bd->pins; + + *dst++ = 0x40; + *dst++ = 0; + for (i = 2; i < 0x40; i++) { + *dst++ = readb(pins+i); + } + bd->pins_len = 0x40; + } +} + +static void get_bios_version(unsigned char __iomem * vbios, struct matrox_bios* bd) { + unsigned int pcir_offset; + + pcir_offset = readb(vbios + 24) | (readb(vbios + 25) << 8); + if (pcir_offset >= 26 && pcir_offset < 0xFFE0 && + readb(vbios + pcir_offset ) == 'P' && + readb(vbios + pcir_offset + 1) == 'C' && + readb(vbios + pcir_offset + 2) == 'I' && + readb(vbios + pcir_offset + 3) == 'R') { + unsigned char h; + + h = readb(vbios + pcir_offset + 0x12); + bd->version.vMaj = (h >> 4) & 0xF; + bd->version.vMin = h & 0xF; + bd->version.vRev = readb(vbios + pcir_offset + 0x13); + } else { + unsigned char h; + + h = readb(vbios + 5); + bd->version.vMaj = (h >> 4) & 0xF; + bd->version.vMin = h & 0xF; + bd->version.vRev = 0; + } +} + +static void get_bios_output(unsigned char __iomem* vbios, struct matrox_bios* bd) { + unsigned char b; + + b = readb(vbios + 0x7FF1); + if (b == 0xFF) { + b = 0; + } + bd->output.state = b; +} + +static void get_bios_tvout(unsigned char __iomem* vbios, struct matrox_bios* bd) { + unsigned int i; + + /* Check for 'IBM .*(V....TVO' string - it means TVO BIOS */ + bd->output.tvout = 0; + if (readb(vbios + 0x1D) != 'I' || + readb(vbios + 0x1E) != 'B' || + readb(vbios + 0x1F) != 'M' || + readb(vbios + 0x20) != ' ') { + return; + } + for (i = 0x2D; i < 0x2D + 128; i++) { + unsigned char b = readb(vbios + i); + + if (b == '(' && readb(vbios + i + 1) == 'V') { + if (readb(vbios + i + 6) == 'T' && + readb(vbios + i + 7) == 'V' && + readb(vbios + i + 8) == 'O') { + bd->output.tvout = 1; + } + return; + } + if (b == 0) + break; + } +} + +static void parse_bios(unsigned char __iomem* vbios, struct matrox_bios* bd) { + unsigned int pins_offset; + + if (readb(vbios) != 0x55 || readb(vbios + 1) != 0xAA) { + return; + } + bd->bios_valid = 1; + get_bios_version(vbios, bd); + get_bios_output(vbios, bd); + get_bios_tvout(vbios, bd); + pins_offset = readb(vbios + 0x7FFC) | (readb(vbios + 0x7FFD) << 8); + if (pins_offset <= 0xFF80) { + get_pins(vbios + pins_offset, bd); + } +} + +#define get_u16(x) (le16_to_cpu(get_unaligned((__u16*)(x)))) +#define get_u32(x) (le32_to_cpu(get_unaligned((__u32*)(x)))) +static int parse_pins1(WPMINFO const struct matrox_bios* bd) { + unsigned int maxdac; + + switch (bd->pins[22]) { + case 0: maxdac = 175000; break; + case 1: maxdac = 220000; break; + default: maxdac = 240000; break; + } + if (get_u16(bd->pins + 24)) { + maxdac = get_u16(bd->pins + 24) * 10; + } + MINFO->limits.pixel.vcomax = maxdac; + MINFO->values.pll.system = get_u16(bd->pins + 28) ? get_u16(bd->pins + 28) * 10 : 50000; + /* ignore 4MB, 8MB, module clocks */ + MINFO->features.pll.ref_freq = 14318; + MINFO->values.reg.mctlwtst = 0x00030101; + return 0; +} + +static void default_pins1(WPMINFO2) { + /* Millennium */ + MINFO->limits.pixel.vcomax = 220000; + MINFO->values.pll.system = 50000; + MINFO->features.pll.ref_freq = 14318; + MINFO->values.reg.mctlwtst = 0x00030101; +} + +static int parse_pins2(WPMINFO const struct matrox_bios* bd) { + MINFO->limits.pixel.vcomax = + MINFO->limits.system.vcomax = (bd->pins[41] == 0xFF) ? 230000 : ((bd->pins[41] + 100) * 1000); + MINFO->values.reg.mctlwtst = ((bd->pins[51] & 0x01) ? 0x00000001 : 0) | + ((bd->pins[51] & 0x02) ? 0x00000100 : 0) | + ((bd->pins[51] & 0x04) ? 0x00010000 : 0) | + ((bd->pins[51] & 0x08) ? 0x00020000 : 0); + MINFO->values.pll.system = (bd->pins[43] == 0xFF) ? 50000 : ((bd->pins[43] + 100) * 1000); + MINFO->features.pll.ref_freq = 14318; + return 0; +} + +static void default_pins2(WPMINFO2) { + /* Millennium II, Mystique */ + MINFO->limits.pixel.vcomax = + MINFO->limits.system.vcomax = 230000; + MINFO->values.reg.mctlwtst = 0x00030101; + MINFO->values.pll.system = 50000; + MINFO->features.pll.ref_freq = 14318; +} + +static int parse_pins3(WPMINFO const struct matrox_bios* bd) { + MINFO->limits.pixel.vcomax = + MINFO->limits.system.vcomax = (bd->pins[36] == 0xFF) ? 230000 : ((bd->pins[36] + 100) * 1000); + MINFO->values.reg.mctlwtst = get_u32(bd->pins + 48) == 0xFFFFFFFF ? 0x01250A21 : get_u32(bd->pins + 48); + /* memory config */ + MINFO->values.reg.memrdbk = ((bd->pins[57] << 21) & 0x1E000000) | + ((bd->pins[57] << 22) & 0x00C00000) | + ((bd->pins[56] << 1) & 0x000001E0) | + ( bd->pins[56] & 0x0000000F); + MINFO->values.reg.opt = (bd->pins[54] & 7) << 10; + MINFO->values.reg.opt2 = bd->pins[58] << 12; + MINFO->features.pll.ref_freq = (bd->pins[52] & 0x20) ? 14318 : 27000; + return 0; +} + +static void default_pins3(WPMINFO2) { + /* G100, G200 */ + MINFO->limits.pixel.vcomax = + MINFO->limits.system.vcomax = 230000; + MINFO->values.reg.mctlwtst = 0x01250A21; + MINFO->values.reg.memrdbk = 0x00000000; + MINFO->values.reg.opt = 0x00000C00; + MINFO->values.reg.opt2 = 0x00000000; + MINFO->features.pll.ref_freq = 27000; +} + +static int parse_pins4(WPMINFO const struct matrox_bios* bd) { + MINFO->limits.pixel.vcomax = (bd->pins[ 39] == 0xFF) ? 230000 : bd->pins[ 39] * 4000; + MINFO->limits.system.vcomax = (bd->pins[ 38] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 38] * 4000; + MINFO->values.reg.mctlwtst = get_u32(bd->pins + 71); + MINFO->values.reg.memrdbk = ((bd->pins[87] << 21) & 0x1E000000) | + ((bd->pins[87] << 22) & 0x00C00000) | + ((bd->pins[86] << 1) & 0x000001E0) | + ( bd->pins[86] & 0x0000000F); + MINFO->values.reg.opt = ((bd->pins[53] << 15) & 0x00400000) | + ((bd->pins[53] << 22) & 0x10000000) | + ((bd->pins[53] << 7) & 0x00001C00); + MINFO->values.reg.opt3 = get_u32(bd->pins + 67); + MINFO->values.pll.system = (bd->pins[ 65] == 0xFF) ? 200000 : bd->pins[ 65] * 4000; + MINFO->features.pll.ref_freq = (bd->pins[ 92] & 0x01) ? 14318 : 27000; + return 0; +} + +static void default_pins4(WPMINFO2) { + /* G400 */ + MINFO->limits.pixel.vcomax = + MINFO->limits.system.vcomax = 252000; + MINFO->values.reg.mctlwtst = 0x04A450A1; + MINFO->values.reg.memrdbk = 0x000000E7; + MINFO->values.reg.opt = 0x10000400; + MINFO->values.reg.opt3 = 0x0190A419; + MINFO->values.pll.system = 200000; + MINFO->features.pll.ref_freq = 27000; +} + +static int parse_pins5(WPMINFO const struct matrox_bios* bd) { + unsigned int mult; + + mult = bd->pins[4]?8000:6000; + + MINFO->limits.pixel.vcomax = (bd->pins[ 38] == 0xFF) ? 600000 : bd->pins[ 38] * mult; + MINFO->limits.system.vcomax = (bd->pins[ 36] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 36] * mult; + MINFO->limits.video.vcomax = (bd->pins[ 37] == 0xFF) ? MINFO->limits.system.vcomax : bd->pins[ 37] * mult; + MINFO->limits.pixel.vcomin = (bd->pins[123] == 0xFF) ? 256000 : bd->pins[123] * mult; + MINFO->limits.system.vcomin = (bd->pins[121] == 0xFF) ? MINFO->limits.pixel.vcomin : bd->pins[121] * mult; + MINFO->limits.video.vcomin = (bd->pins[122] == 0xFF) ? MINFO->limits.system.vcomin : bd->pins[122] * mult; + MINFO->values.pll.system = + MINFO->values.pll.video = (bd->pins[ 92] == 0xFF) ? 284000 : bd->pins[ 92] * 4000; + MINFO->values.reg.opt = get_u32(bd->pins+ 48); + MINFO->values.reg.opt2 = get_u32(bd->pins+ 52); + MINFO->values.reg.opt3 = get_u32(bd->pins+ 94); + MINFO->values.reg.mctlwtst = get_u32(bd->pins+ 98); + MINFO->values.reg.memmisc = get_u32(bd->pins+102); + MINFO->values.reg.memrdbk = get_u32(bd->pins+106); + MINFO->features.pll.ref_freq = (bd->pins[110] & 0x01) ? 14318 : 27000; + MINFO->values.memory.ddr = (bd->pins[114] & 0x60) == 0x20; + MINFO->values.memory.dll = (bd->pins[115] & 0x02) != 0; + MINFO->values.memory.emrswen = (bd->pins[115] & 0x01) != 0; + MINFO->values.reg.maccess = MINFO->values.memory.emrswen ? 0x00004000 : 0x00000000; + if (bd->pins[115] & 4) { + MINFO->values.reg.mctlwtst_core = MINFO->values.reg.mctlwtst; + } else { + u_int32_t wtst_xlat[] = { 0, 1, 5, 6, 7, 5, 2, 3 }; + MINFO->values.reg.mctlwtst_core = (MINFO->values.reg.mctlwtst & ~7) | + wtst_xlat[MINFO->values.reg.mctlwtst & 7]; + } + return 0; +} + +static void default_pins5(WPMINFO2) { + /* Mine 16MB G450 with SDRAM DDR */ + MINFO->limits.pixel.vcomax = + MINFO->limits.system.vcomax = + MINFO->limits.video.vcomax = 600000; + MINFO->limits.pixel.vcomin = + MINFO->limits.system.vcomin = + MINFO->limits.video.vcomin = 256000; + MINFO->values.pll.system = + MINFO->values.pll.video = 284000; + MINFO->values.reg.opt = 0x404A1160; + MINFO->values.reg.opt2 = 0x0000AC00; + MINFO->values.reg.opt3 = 0x0090A409; + MINFO->values.reg.mctlwtst_core = + MINFO->values.reg.mctlwtst = 0x0C81462B; + MINFO->values.reg.memmisc = 0x80000004; + MINFO->values.reg.memrdbk = 0x01001103; + MINFO->features.pll.ref_freq = 27000; + MINFO->values.memory.ddr = 1; + MINFO->values.memory.dll = 1; + MINFO->values.memory.emrswen = 1; + MINFO->values.reg.maccess = 0x00004000; +} + +static int matroxfb_set_limits(WPMINFO const struct matrox_bios* bd) { + unsigned int pins_version; + static const unsigned int pinslen[] = { 64, 64, 64, 128, 128 }; + + switch (ACCESS_FBINFO(chip)) { + case MGA_2064: default_pins1(PMINFO2); break; + case MGA_2164: + case MGA_1064: + case MGA_1164: default_pins2(PMINFO2); break; + case MGA_G100: + case MGA_G200: default_pins3(PMINFO2); break; + case MGA_G400: default_pins4(PMINFO2); break; + case MGA_G450: + case MGA_G550: default_pins5(PMINFO2); break; + } + if (!bd->bios_valid) { + printk(KERN_INFO "matroxfb: Your Matrox device does not have BIOS\n"); + return -1; + } + if (bd->pins_len < 64) { + printk(KERN_INFO "matroxfb: BIOS on your Matrox device does not contain powerup info\n"); + return -1; + } + if (bd->pins[0] == 0x2E && bd->pins[1] == 0x41) { + pins_version = bd->pins[5]; + if (pins_version < 2 || pins_version > 5) { + printk(KERN_INFO "matroxfb: Unknown version (%u) of powerup info\n", pins_version); + return -1; + } + } else { + pins_version = 1; + } + if (bd->pins_len != pinslen[pins_version - 1]) { + printk(KERN_INFO "matroxfb: Invalid powerup info\n"); + return -1; + } + switch (pins_version) { + case 1: + return parse_pins1(PMINFO bd); + case 2: + return parse_pins2(PMINFO bd); + case 3: + return parse_pins3(PMINFO bd); + case 4: + return parse_pins4(PMINFO bd); + case 5: + return parse_pins5(PMINFO bd); + default: + printk(KERN_DEBUG "matroxfb: Powerup info version %u is not yet supported\n", pins_version); + return -1; + } +} + +void matroxfb_read_pins(WPMINFO2) { + u32 opt; + u32 biosbase; + u32 fbbase; + struct pci_dev* pdev = ACCESS_FBINFO(pcidev); + + memset(&ACCESS_FBINFO(bios), 0, sizeof(ACCESS_FBINFO(bios))); + pci_read_config_dword(pdev, PCI_OPTION_REG, &opt); + pci_write_config_dword(pdev, PCI_OPTION_REG, opt | PCI_OPTION_ENABLE_ROM); + pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &biosbase); + pci_read_config_dword(pdev, ACCESS_FBINFO(devflags.fbResource), &fbbase); + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, (fbbase & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE); + parse_bios(vaddr_va(ACCESS_FBINFO(video).vbase), &ACCESS_FBINFO(bios)); + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, biosbase); + pci_write_config_dword(pdev, PCI_OPTION_REG, opt); +#ifdef CONFIG_X86 + if (!ACCESS_FBINFO(bios).bios_valid) { + unsigned char __iomem* b; + + b = ioremap(0x000C0000, 65536); + if (!b) { + printk(KERN_INFO "matroxfb: Unable to map legacy BIOS\n"); + } else { + unsigned int ven = readb(b+0x64+0) | (readb(b+0x64+1) << 8); + unsigned int dev = readb(b+0x64+2) | (readb(b+0x64+3) << 8); + + if (ven != pdev->vendor || dev != pdev->device) { + printk(KERN_INFO "matroxfb: Legacy BIOS is for %04X:%04X, while this device is %04X:%04X\n", + ven, dev, pdev->vendor, pdev->device); + } else { + parse_bios(b, &ACCESS_FBINFO(bios)); + } + iounmap(b); + } + } +#endif + matroxfb_set_limits(PMINFO &ACCESS_FBINFO(bios)); +} + +EXPORT_SYMBOL(matroxfb_DAC_in); +EXPORT_SYMBOL(matroxfb_DAC_out); +EXPORT_SYMBOL(matroxfb_var2my); +EXPORT_SYMBOL(matroxfb_PLL_calcclock); +#ifndef CONFIG_FB_MATROX_MULTIHEAD +struct matrox_fb_info matroxfb_global_mxinfo; +EXPORT_SYMBOL(matroxfb_global_mxinfo); +#endif +EXPORT_SYMBOL(matroxfb_vgaHWinit); /* DAC1064, Ti3026 */ +EXPORT_SYMBOL(matroxfb_vgaHWrestore); /* DAC1064, Ti3026 */ +EXPORT_SYMBOL(matroxfb_read_pins); + +MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Miscellaneous support for Matrox video cards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/matrox/matroxfb_misc.h b/drivers/video/matrox/matroxfb_misc.h new file mode 100644 index 000000000000..cb62cc0ead96 --- /dev/null +++ b/drivers/video/matrox/matroxfb_misc.h @@ -0,0 +1,18 @@ +#ifndef __MATROXFB_MISC_H__ +#define __MATROXFB_MISC_H__ + +#include "matroxfb_base.h" + +/* also for modules */ +int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax, + unsigned int* in, unsigned int* feed, unsigned int* post); +static inline int PLL_calcclock(CPMINFO unsigned int freq, unsigned int fmax, + unsigned int* in, unsigned int* feed, unsigned int* post) { + return matroxfb_PLL_calcclock(&ACCESS_FBINFO(features.pll), freq, fmax, in, feed, post); +} + +int matroxfb_vgaHWinit(WPMINFO struct my_timming* m); +void matroxfb_vgaHWrestore(WPMINFO2); +void matroxfb_read_pins(WPMINFO2); + +#endif /* __MATROXFB_MISC_H__ */ diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c new file mode 100644 index 000000000000..f192d995d030 --- /dev/null +++ b/drivers/video/maxinefb.c @@ -0,0 +1,180 @@ +/* + * linux/drivers/video/maxinefb.c + * + * DECstation 5000/xx onboard framebuffer support ... derived from: + * "HP300 Topcat framebuffer support (derived from macfb of all things) + * Phil Blundell <philb@gnu.org> 1998", the original code can be + * found in the file hpfb.c in the same directory. + * + * DECstation related code Copyright (C) 1999,2000,2001 by + * Michael Engel <engel@unix-ag.org> and + * 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. + * + */ + +/* + * Changes: + * 2001/01/27 removed debugging and testing code, fixed fb_ops + * initialization which had caused a crash before, + * general cleanup, first official release (KM) + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#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/init.h> +#include <linux/fb.h> +#include <video/maxinefb.h> + +/* bootinfo.h defines the machine type values, needed when checking */ +/* whether are really running on a maxine, KM */ +#include <asm/bootinfo.h> + +static struct fb_info fb_info; + +static struct fb_var_screeninfo maxinefb_defined = { + .xres = 1024, + .yres = 768, + .xres_virtual = 1024, + .yres_virtual = 768, + .bits_per_pixel =8, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo maxinefb_fix = { + .id = "Maxine onboard graphics 1024x768x8", + .smem_len = (1024*768), + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .line_length = 1024, +}; + +/* Handle the funny Inmos RamDAC/video controller ... */ + +void maxinefb_ims332_write_register(int regno, register unsigned int val) +{ + register unsigned char *regs = (char *) MAXINEFB_IMS332_ADDRESS; + unsigned char *wptr; + + wptr = regs + 0xa0000 + (regno << 4); + *((volatile unsigned int *) (regs)) = (val >> 8) & 0xff00; + *((volatile unsigned short *) (wptr)) = val; +} + +unsigned int maxinefb_ims332_read_register(int regno) +{ + register unsigned char *regs = (char *) MAXINEFB_IMS332_ADDRESS; + unsigned char *rptr; + register unsigned int j, k; + + rptr = regs + 0x80000 + (regno << 4); + j = *((volatile unsigned short *) rptr); + k = *((volatile unsigned short *) regs); + + return (j & 0xffff) | ((k & 0xff00) << 8); +} + +/* Set the palette */ +static int maxinefb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + /* value to be written into the palette reg. */ + unsigned long hw_colorvalue = 0; + + red >>= 8; /* The cmap fields are 16 bits */ + green >>= 8; /* wide, but the harware colormap */ + blue >>= 8; /* registers are only 8 bits wide */ + + hw_colorvalue = (blue << 16) + (green << 8) + (red); + + maxinefb_ims332_write_register(IMS332_REG_COLOR_PALETTE + regno, + hw_colorvalue); + return 0; +} + +static struct fb_ops maxinefb_ops = { + .owner = THIS_MODULE, + .fb_get_fix = gen_get_fix, + .fb_get_var = gen_get_var, + .fb_setcolreg = maxinefb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +int __init maxinefb_init(void) +{ + unsigned long fboff; + unsigned long fb_start; + int i; + + if (fb_get_options("maxinefb", NULL)) + return -ENODEV; + + /* Validate we're on the proper machine type */ + if (mips_machtype != MACH_DS5000_XX) { + return -EINVAL; + } + + printk(KERN_INFO "Maxinefb: Personal DECstation detected\n"); + printk(KERN_INFO "Maxinefb: initializing onboard framebuffer\n"); + + /* Framebuffer display memory base address */ + fb_start = DS5000_xx_ONBOARD_FBMEM_START; + + /* Clear screen */ + for (fboff = fb_start; fboff < fb_start + 0x1ffff; fboff++) + *(volatile unsigned char *)fboff = 0x0; + + maxinefb_fix.smem_start = fb_start; + + /* erase hardware cursor */ + for (i = 0; i < 512; i++) { + maxinefb_ims332_write_register(IMS332_REG_CURSOR_RAM + i, + 0); + /* + if (i&0x8 == 0) + maxinefb_ims332_write_register (IMS332_REG_CURSOR_RAM + i, 0x0f); + else + maxinefb_ims332_write_register (IMS332_REG_CURSOR_RAM + i, 0xf0); + */ + } + + fb_info.fbops = &maxinefb_ops; + fb_info.screen_base = (char *)maxinefb_fix.smem_start; + fb_info.var = maxinefb_defined; + fb_info.fix = maxinefb_fix; + fb_info.flags = FBINFO_DEFAULT; + + fb_alloc_cmap(&fb_info.cmap, 256, 0); + + if (register_framebuffer(&fb_info) < 0) + return 1; + return 0; +} + +static void __exit maxinefb_exit(void) +{ + unregister_framebuffer(&fb_info); +} + +#ifdef MODULE +MODULE_LICENSE("GPL"); +#endif +module_init(maxinefb_init); +module_exit(maxinefb_exit); + diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c new file mode 100644 index 000000000000..fbf659b6dab0 --- /dev/null +++ b/drivers/video/modedb.c @@ -0,0 +1,892 @@ +/* + * linux/drivers/video/modedb.c -- Standard video mode database management + * + * Copyright (C) 1999 Geert Uytterhoeven + * + * 2001 - Documented with DocBook + * - Brad Douglas <brad@neruo.com> + * + * 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/fb.h> +#include <linux/sched.h> + +#undef DEBUG + +#define name_matches(v, s, l) \ + ((v).name && !strncmp((s), (v).name, (l)) && strlen((v).name) == (l)) +#define res_matches(v, x, y) \ + ((v).xres == (x) && (v).yres == (y)) + +#ifdef DEBUG +#define DPRINTK(fmt, args...) printk("modedb %s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +const char *global_mode_option; + + /* + * Standard video mode definitions (taken from XFree86) + */ + +#define DEFAULT_MODEDB_INDEX 0 + +static const struct fb_videomode modedb[] = { + { + /* 640x400 @ 70 Hz, 31.5 kHz hsync */ + NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, + 0, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 60 Hz, 31.5 kHz hsync */ + NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, + 0, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 56 Hz, 35.15 kHz hsync */ + NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */ + NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, + 0, FB_VMODE_INTERLACED + }, { + /* 640x400 @ 85 Hz, 37.86 kHz hsync */ + NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 72 Hz, 36.5 kHz hsync */ + NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 75 Hz, 37.50 kHz hsync */ + NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 60 Hz, 37.8 kHz hsync */ + NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 85 Hz, 43.27 kHz hsync */ + NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */ + NULL, 69, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, + 0, FB_VMODE_INTERLACED + }, { + /* 800x600 @ 72 Hz, 48.0 kHz hsync */ + NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 60 Hz, 48.4 kHz hsync */ + NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 640x480 @ 100 Hz, 53.01 kHz hsync */ + NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 60 Hz, 53.5 kHz hsync */ + NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, + 0, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 85 Hz, 55.84 kHz hsync */ + NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 70 Hz, 56.5 kHz hsync */ + NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */ + NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, + 0, FB_VMODE_INTERLACED + }, { + /* 800x600 @ 100 Hz, 64.02 kHz hsync */ + NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 76 Hz, 62.5 kHz hsync */ + NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 70 Hz, 62.4 kHz hsync */ + NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 61 Hz, 64.2 kHz hsync */ + NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1400x1050 @ 60Hz, 63.9 kHz hsync */ + NULL, 68, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/ + NULL, 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/ + NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 85 Hz, 70.24 kHz hsync */ + NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 78 Hz, 70.8 kHz hsync */ + NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 70 Hz, 74.59 kHz hsync */ + NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 60Hz, 75.00 kHz hsync */ + NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 84 Hz, 76.0 kHz hsync */ + NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 74 Hz, 78.85 kHz hsync */ + NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 100Hz, 80.21 kHz hsync */ + NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 76 Hz, 81.13 kHz hsync */ + NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 70 Hz, 87.50 kHz hsync */ + NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1152x864 @ 100 Hz, 89.62 kHz hsync */ + NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 85 Hz, 91.15 kHz hsync */ + NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 75 Hz, 93.75 kHz hsync */ + NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */ + NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1280x1024 @ 100 Hz, 107.16 kHz hsync */ + NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1800x1440 @ 64Hz, 96.15 kHz hsync */ + NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 1800x1440 @ 70Hz, 104.52 kHz hsync */ + NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* 512x384 @ 78 Hz, 31.50 kHz hsync */ + NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 512x384 @ 85 Hz, 34.38 kHz hsync */ + NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, + 0, FB_VMODE_NONINTERLACED + }, { + /* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */ + NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, + 0, FB_VMODE_DOUBLE + }, { + /* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */ + NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, + 0, FB_VMODE_DOUBLE + }, { + /* 320x240 @ 72 Hz, 36.5 kHz hsync */ + NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, + 0, FB_VMODE_DOUBLE + }, { + /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */ + NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, + 0, FB_VMODE_DOUBLE + }, { + /* 400x300 @ 60 Hz, 37.8 kHz hsync */ + NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, + 0, FB_VMODE_DOUBLE + }, { + /* 400x300 @ 72 Hz, 48.0 kHz hsync */ + NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3, + 0, FB_VMODE_DOUBLE + }, { + /* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */ + NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, + 0, FB_VMODE_DOUBLE + }, { + /* 480x300 @ 60 Hz, 37.8 kHz hsync */ + NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, + 0, FB_VMODE_DOUBLE + }, { + /* 480x300 @ 63 Hz, 39.6 kHz hsync */ + NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, + 0, FB_VMODE_DOUBLE + }, { + /* 480x300 @ 72 Hz, 48.0 kHz hsync */ + NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, + 0, FB_VMODE_DOUBLE + }, +}; + +#ifdef CONFIG_FB_MODE_HELPERS +const struct fb_videomode vesa_modes[] = { + /* 0 640x350-85 VESA */ + { NULL, 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3, + FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA}, + /* 1 640x400-85 VESA */ + { NULL, 85, 640, 400, 31746, 96, 32, 41, 01, 64, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 2 720x400-85 VESA */ + { NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 3 640x480-60 VESA */ + { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 4 640x480-72 VESA */ + { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 5 640x480-75 VESA */ + { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 6 640x480-85 VESA */ + { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 7 800x600-56 VESA */ + { NULL, 56, 800, 600, 27777, 128, 24, 22, 01, 72, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 8 800x600-60 VESA */ + { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 9 800x600-72 VESA */ + { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 10 800x600-75 VESA */ + { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 11 800x600-85 VESA */ + { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 12 1024x768i-43 VESA */ + { NULL, 53, 1024, 768, 22271, 56, 8, 41, 0, 176, 8, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_INTERLACED, FB_MODE_IS_VESA }, + /* 13 1024x768-60 VESA */ + { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 14 1024x768-70 VESA */ + { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 15 1024x768-75 VESA */ + { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 16 1024x768-85 VESA */ + { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 17 1152x864-75 VESA */ + { NULL, 75, 1153, 864, 9259, 256, 64, 32, 1, 128, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 18 1280x960-60 VESA */ + { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 19 1280x960-85 VESA */ + { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 20 1280x1024-60 VESA */ + { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 21 1280x1024-75 VESA */ + { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 22 1280x1024-85 VESA */ + { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 23 1600x1200-60 VESA */ + { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 24 1600x1200-65 VESA */ + { NULL, 65, 1600, 1200, 5698, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 25 1600x1200-70 VESA */ + { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 26 1600x1200-75 VESA */ + { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 27 1600x1200-85 VESA */ + { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 28 1792x1344-60 VESA */ + { NULL, 60, 1792, 1344, 4882, 328, 128, 46, 1, 200, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 29 1792x1344-75 VESA */ + { NULL, 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 30 1856x1392-60 VESA */ + { NULL, 60, 1856, 1392, 4580, 352, 96, 43, 1, 224, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 31 1856x1392-75 VESA */ + { NULL, 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 32 1920x1440-60 VESA */ + { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 33 1920x1440-75 VESA */ + { NULL, 60, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, +}; +EXPORT_SYMBOL(vesa_modes); +#endif /* CONFIG_FB_MODE_HELPERS */ + +static int my_atoi(const char *name) +{ + int val = 0; + + for (;; name++) { + switch (*name) { + case '0'...'9': + val = 10*val+(*name-'0'); + break; + default: + return val; + } + } +} + +/** + * fb_try_mode - test a video mode + * @var: frame buffer user defined part of display + * @info: frame buffer info structure + * @mode: frame buffer video mode structure + * @bpp: color depth in bits per pixel + * + * Tries a video mode to test it's validity for device @info. + * + * Returns 1 on success. + * + */ + +static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, + const struct fb_videomode *mode, unsigned int bpp) +{ + int err = 0; + + DPRINTK("Trying mode %s %dx%d-%d@%d\n", mode->name ? mode->name : "noname", + mode->xres, mode->yres, bpp, mode->refresh); + var->xres = mode->xres; + var->yres = mode->yres; + var->xres_virtual = mode->xres; + var->yres_virtual = mode->yres; + var->xoffset = 0; + var->yoffset = 0; + var->bits_per_pixel = bpp; + var->activate |= FB_ACTIVATE_TEST; + var->pixclock = mode->pixclock; + var->left_margin = mode->left_margin; + var->right_margin = mode->right_margin; + var->upper_margin = mode->upper_margin; + var->lower_margin = mode->lower_margin; + var->hsync_len = mode->hsync_len; + var->vsync_len = mode->vsync_len; + var->sync = mode->sync; + var->vmode = mode->vmode; + if (info->fbops->fb_check_var) + err = info->fbops->fb_check_var(var, info); + var->activate &= ~FB_ACTIVATE_TEST; + return err; +} + +/** + * fb_find_mode - finds a valid video mode + * @var: frame buffer user defined part of display + * @info: frame buffer info structure + * @mode_option: string video mode to find + * @db: video mode database + * @dbsize: size of @db + * @default_mode: default video mode to fall back to + * @default_bpp: default color depth in bits per pixel + * + * Finds a suitable video mode, starting with the specified mode + * in @mode_option with fallback to @default_mode. If + * @default_mode fails, all modes in the video mode database will + * be tried. + * + * Valid mode specifiers for @mode_option: + * + * <xres>x<yres>[-<bpp>][@<refresh>] or + * <name>[-<bpp>][@<refresh>] + * + * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and + * <name> a string. + * + * NOTE: The passed struct @var is _not_ cleared! This allows you + * to supply values for e.g. the grayscale and accel_flags fields. + * + * Returns zero for failure, 1 if using specified @mode_option, + * 2 if using specified @mode_option with an ignored refresh rate, + * 3 if default mode is used, 4 if fall back to any valid mode. + * + */ + +int fb_find_mode(struct fb_var_screeninfo *var, + struct fb_info *info, const char *mode_option, + const struct fb_videomode *db, unsigned int dbsize, + const struct fb_videomode *default_mode, + unsigned int default_bpp) +{ + int i; + + /* Set up defaults */ + if (!db) { + db = modedb; + dbsize = sizeof(modedb)/sizeof(*modedb); + } + if (!default_mode) + default_mode = &modedb[DEFAULT_MODEDB_INDEX]; + if (!default_bpp) + default_bpp = 8; + + /* Did the user specify a video mode? */ + if (mode_option || (mode_option = global_mode_option)) { + const char *name = mode_option; + unsigned int namelen = strlen(name); + int res_specified = 0, bpp_specified = 0, refresh_specified = 0; + unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; + int yres_specified = 0; + u32 best, diff; + + for (i = namelen-1; i >= 0; i--) { + switch (name[i]) { + case '@': + namelen = i; + if (!refresh_specified && !bpp_specified && + !yres_specified) { + refresh = my_atoi(&name[i+1]); + refresh_specified = 1; + } else + goto done; + break; + case '-': + namelen = i; + if (!bpp_specified && !yres_specified) { + bpp = my_atoi(&name[i+1]); + bpp_specified = 1; + } else + goto done; + break; + case 'x': + if (!yres_specified) { + yres = my_atoi(&name[i+1]); + yres_specified = 1; + } else + goto done; + break; + case '0'...'9': + break; + default: + goto done; + } + } + if (i < 0 && yres_specified) { + xres = my_atoi(name); + res_specified = 1; + } +done: + DPRINTK("Trying specified video mode%s %ix%i\n", + refresh_specified ? "" : " (ignoring refresh rate)", xres, yres); + + diff = refresh; + best = -1; + for (i = 0; i < dbsize; i++) { + if ((name_matches(db[i], name, namelen) && + !fb_try_mode(var, info, &db[i], bpp))) + return 1; + if (res_specified && res_matches(db[i], xres, yres)) { + if(!fb_try_mode(var, info, &db[i], bpp)) { + if(!refresh_specified || db[i].refresh == refresh) + return 1; + else { + if(diff > abs(db[i].refresh - refresh)) { + diff = abs(db[i].refresh - refresh); + best = i; + } + } + } + } + } + if (best != -1) { + fb_try_mode(var, info, &db[best], bpp); + return 2; + } + + diff = xres + yres; + best = -1; + DPRINTK("Trying best-fit modes\n"); + for (i = 0; i < dbsize; i++) { + if (xres <= db[i].xres && yres <= db[i].yres) { + DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres); + if (!fb_try_mode(var, info, &db[i], bpp)) { + if (diff > (db[i].xres - xres) + (db[i].yres - yres)) { + diff = (db[i].xres - xres) + (db[i].yres - yres); + best = i; + } + } + } + } + if (best != -1) { + fb_try_mode(var, info, &db[best], bpp); + return 5; + } + } + + DPRINTK("Trying default video mode\n"); + if (!fb_try_mode(var, info, default_mode, default_bpp)) + return 3; + + DPRINTK("Trying all modes\n"); + for (i = 0; i < dbsize; i++) + if (!fb_try_mode(var, info, &db[i], default_bpp)) + return 4; + + DPRINTK("No valid mode found\n"); + return 0; +} + +/** + * fb_var_to_videomode - convert fb_var_screeninfo to fb_videomode + * @mode: pointer to struct fb_videomode + * @var: pointer to struct fb_var_screeninfo + */ +void fb_var_to_videomode(struct fb_videomode *mode, + struct fb_var_screeninfo *var) +{ + u32 pixclock, hfreq, htotal, vtotal; + + mode->name = NULL; + mode->xres = var->xres; + mode->yres = var->yres; + mode->pixclock = var->pixclock; + mode->hsync_len = var->hsync_len; + mode->vsync_len = var->vsync_len; + mode->left_margin = var->left_margin; + mode->right_margin = var->right_margin; + mode->upper_margin = var->upper_margin; + mode->lower_margin = var->lower_margin; + mode->sync = var->sync; + mode->vmode = var->vmode & FB_VMODE_MASK; + mode->flag = FB_MODE_IS_FROM_VAR; + if (!var->pixclock) + return; + + pixclock = PICOS2KHZ(var->pixclock) * 1000; + + htotal = var->xres + var->right_margin + var->hsync_len + + var->left_margin; + vtotal = var->yres + var->lower_margin + var->vsync_len + + var->upper_margin; + + if (var->vmode & FB_VMODE_INTERLACED) + vtotal /= 2; + if (var->vmode & FB_VMODE_DOUBLE) + vtotal *= 2; + + hfreq = pixclock/htotal; + mode->refresh = hfreq/vtotal; +} + +/** + * fb_videomode_to_var - convert fb_videomode to fb_var_screeninfo + * @var: pointer to struct fb_var_screeninfo + * @mode: pointer to struct fb_videomode + */ +void fb_videomode_to_var(struct fb_var_screeninfo *var, + struct fb_videomode *mode) +{ + var->xres = mode->xres; + var->yres = mode->yres; + var->pixclock = mode->pixclock; + var->left_margin = mode->left_margin; + var->hsync_len = mode->hsync_len; + var->vsync_len = mode->vsync_len; + var->right_margin = mode->right_margin; + var->upper_margin = mode->upper_margin; + var->lower_margin = mode->lower_margin; + var->sync = mode->sync; + var->vmode = mode->vmode & FB_VMODE_MASK; +} + +/** + * fb_mode_is_equal - compare 2 videomodes + * @mode1: first videomode + * @mode2: second videomode + * + * RETURNS: + * 1 if equal, 0 if not + */ +int fb_mode_is_equal(struct fb_videomode *mode1, + struct fb_videomode *mode2) +{ + return (mode1->xres == mode2->xres && + mode1->yres == mode2->yres && + mode1->pixclock == mode2->pixclock && + mode1->hsync_len == mode2->hsync_len && + mode1->vsync_len == mode2->vsync_len && + mode1->left_margin == mode2->left_margin && + mode1->right_margin == mode2->right_margin && + mode1->upper_margin == mode2->upper_margin && + mode1->lower_margin == mode2->lower_margin && + mode1->sync == mode2->sync && + mode1->vmode == mode2->vmode); +} + +/** + * fb_find_best_mode - find best matching videomode + * @var: pointer to struct fb_var_screeninfo + * @head: pointer to struct list_head of modelist + * + * RETURNS: + * struct fb_videomode, NULL if none found + * + * IMPORTANT: + * This function assumes that all modelist entries in + * info->modelist are valid. + * + * NOTES: + * Finds best matching videomode which has an equal or greater dimension than + * var->xres and var->yres. If more than 1 videomode is found, will return + * the videomode with the highest refresh rate + */ +struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var, + struct list_head *head) +{ + struct list_head *pos; + struct fb_modelist *modelist; + struct fb_videomode *mode, *best = NULL; + u32 diff = -1; + + list_for_each(pos, head) { + u32 d; + + modelist = list_entry(pos, struct fb_modelist, list); + mode = &modelist->mode; + + if (mode->xres >= var->xres && mode->yres >= var->yres) { + d = (mode->xres - var->xres) + + (mode->yres - var->yres); + if (diff > d) { + diff = d; + best = mode; + } else if (diff == d && mode->refresh > best->refresh) + best = mode; + } + } + return best; +} + +/** + * fb_find_nearest_mode - find mode closest video mode + * + * @var: pointer to struct fb_var_screeninfo + * @head: pointer to modelist + * + * Finds best matching videomode, smaller or greater in dimension. + * If more than 1 videomode is found, will return the videomode with + * the closest refresh rate + */ +struct fb_videomode *fb_find_nearest_mode(struct fb_var_screeninfo *var, + struct list_head *head) +{ + struct list_head *pos; + struct fb_modelist *modelist; + struct fb_videomode *mode, *best = NULL; + u32 diff = -1, diff_refresh = -1; + + list_for_each(pos, head) { + u32 d; + + modelist = list_entry(pos, struct fb_modelist, list); + mode = &modelist->mode; + + d = abs(mode->xres - var->xres) + + abs(mode->yres - var->yres); + if (diff > d) { + diff = d; + best = mode; + } else if (diff == d) { + d = abs(mode->refresh - best->refresh); + if (diff_refresh > d) { + diff_refresh = d; + best = mode; + } + } + } + + return best; +} + +/** + * fb_match_mode - find a videomode which exactly matches the timings in var + * @var: pointer to struct fb_var_screeninfo + * @head: pointer to struct list_head of modelist + * + * RETURNS: + * struct fb_videomode, NULL if none found + */ +struct fb_videomode *fb_match_mode(struct fb_var_screeninfo *var, + struct list_head *head) +{ + struct list_head *pos; + struct fb_modelist *modelist; + struct fb_videomode *m, mode; + + fb_var_to_videomode(&mode, var); + list_for_each(pos, head) { + modelist = list_entry(pos, struct fb_modelist, list); + m = &modelist->mode; + if (fb_mode_is_equal(m, &mode)) + return m; + } + return NULL; +} + +/** + * fb_add_videomode: adds videomode entry to modelist + * @mode: videomode to add + * @head: struct list_head of modelist + * + * NOTES: + * Will only add unmatched mode entries + */ +int fb_add_videomode(struct fb_videomode *mode, struct list_head *head) +{ + struct list_head *pos; + struct fb_modelist *modelist; + struct fb_videomode *m; + int found = 0; + + list_for_each(pos, head) { + modelist = list_entry(pos, struct fb_modelist, list); + m = &modelist->mode; + if (fb_mode_is_equal(m, mode)) { + found = 1; + break; + } + } + if (!found) { + modelist = kmalloc(sizeof(struct fb_modelist), + GFP_KERNEL); + + if (!modelist) + return -ENOMEM; + modelist->mode = *mode; + list_add(&modelist->list, head); + } + return 0; +} + +/** + * fb_delete_videomode: removed videomode entry from modelist + * @mode: videomode to remove + * @head: struct list_head of modelist + * + * NOTES: + * Will remove all matching mode entries + */ +void fb_delete_videomode(struct fb_videomode *mode, struct list_head *head) +{ + struct list_head *pos, *n; + struct fb_modelist *modelist; + struct fb_videomode *m; + + list_for_each_safe(pos, n, head) { + modelist = list_entry(pos, struct fb_modelist, list); + m = &modelist->mode; + if (fb_mode_is_equal(m, mode)) { + list_del(pos); + kfree(pos); + } + } +} + +/** + * fb_destroy_modelist: destroy modelist + * @head: struct list_head of modelist + */ +void fb_destroy_modelist(struct list_head *head) +{ + struct list_head *pos, *n; + + list_for_each_safe(pos, n, head) { + list_del(pos); + kfree(pos); + } +} + +/** + * fb_videomode_to_modelist: convert mode array to mode list + * @modedb: array of struct fb_videomode + * @num: number of entries in array + * @head: struct list_head of modelist + */ +void fb_videomode_to_modelist(struct fb_videomode *modedb, int num, + struct list_head *head) +{ + int i; + + INIT_LIST_HEAD(head); + + for (i = 0; i < num; i++) { + if (fb_add_videomode(&modedb[i], head)) + return; + } +} + +EXPORT_SYMBOL(fb_videomode_to_var); +EXPORT_SYMBOL(fb_var_to_videomode); +EXPORT_SYMBOL(fb_mode_is_equal); +EXPORT_SYMBOL(fb_add_videomode); +EXPORT_SYMBOL(fb_delete_videomode); +EXPORT_SYMBOL(fb_destroy_modelist); +EXPORT_SYMBOL(fb_match_mode); +EXPORT_SYMBOL(fb_find_best_mode); +EXPORT_SYMBOL(fb_find_nearest_mode); +EXPORT_SYMBOL(fb_videomode_to_modelist); +EXPORT_SYMBOL(fb_find_mode); diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c new file mode 100644 index 000000000000..5d424a30270a --- /dev/null +++ b/drivers/video/neofb.c @@ -0,0 +1,2315 @@ +/* + * linux/drivers/video/neofb.c -- NeoMagic Framebuffer Driver + * + * Copyright (c) 2001-2002 Denis Oliver Kropp <dok@directfb.org> + * + * + * Card specific code is based on XFree86's neomagic driver. + * Framebuffer framework code is based on code of cyber2000fb. + * + * 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. + * + * + * 0.4.1 + * - Cosmetic changes (dok) + * + * 0.4 + * - Toshiba Libretto support, allow modes larger than LCD size if + * LCD is disabled, keep BIOS settings if internal/external display + * haven't been enabled explicitly + * (Thomas J. Moore <dark@mama.indstate.edu>) + * + * 0.3.3 + * - Porting over to new fbdev api. (jsimmons) + * + * 0.3.2 + * - got rid of all floating point (dok) + * + * 0.3.1 + * - added module license (dok) + * + * 0.3 + * - hardware accelerated clear and move for 2200 and above (dok) + * - maximum allowed dotclock is handled now (dok) + * + * 0.2.1 + * - correct panning after X usage (dok) + * - added module and kernel parameters (dok) + * - no stretching if external display is enabled (dok) + * + * 0.2 + * - initial version (dok) + * + * + * TODO + * - ioctl for internal/external switching + * - blanking + * - 32bit depth support, maybe impossible + * - disable pan-on-sync, need specs + * + * BUGS + * - white margin on bootup like with tdfxfb (colormap problem?) + * + */ + +#include <linux/config.h> +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/pci.h> +#include <linux/init.h> +#ifdef CONFIG_TOSHIBA +#include <linux/toshiba.h> +extern int tosh_smm(SMMRegisters *regs); +#endif + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include <video/vga.h> +#include <video/neomagic.h> + +#define NEOFB_VERSION "0.4.2" + +/* --------------------------------------------------------------------- */ + +static int internal; +static int external; +static int libretto; +static int nostretch; +static int nopciburst; +static char *mode_option __devinitdata = NULL; + +#ifdef MODULE + +MODULE_AUTHOR("(c) 2001-2002 Denis Oliver Kropp <dok@convergence.de>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips"); +module_param(internal, bool, 0); +MODULE_PARM_DESC(internal, "Enable output on internal LCD Display."); +module_param(external, bool, 0); +MODULE_PARM_DESC(external, "Enable output on external CRT."); +module_param(libretto, bool, 0); +MODULE_PARM_DESC(libretto, "Force Libretto 100/110 800x480 LCD."); +module_param(nostretch, bool, 0); +MODULE_PARM_DESC(nostretch, + "Disable stretching of modes smaller than LCD."); +module_param(nopciburst, bool, 0); +MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode."); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Preferred video mode ('640x480-8@60', etc)"); + +#endif + + +/* --------------------------------------------------------------------- */ + +static biosMode bios8[] = { + {320, 240, 0x40}, + {300, 400, 0x42}, + {640, 400, 0x20}, + {640, 480, 0x21}, + {800, 600, 0x23}, + {1024, 768, 0x25}, +}; + +static biosMode bios16[] = { + {320, 200, 0x2e}, + {320, 240, 0x41}, + {300, 400, 0x43}, + {640, 480, 0x31}, + {800, 600, 0x34}, + {1024, 768, 0x37}, +}; + +static biosMode bios24[] = { + {640, 480, 0x32}, + {800, 600, 0x35}, + {1024, 768, 0x38} +}; + +#ifdef NO_32BIT_SUPPORT_YET +/* FIXME: guessed values, wrong */ +static biosMode bios32[] = { + {640, 480, 0x33}, + {800, 600, 0x36}, + {1024, 768, 0x39} +}; +#endif + +static inline void write_le32(int regindex, u32 val, const struct neofb_par *par) +{ + writel(val, par->neo2200 + par->cursorOff + regindex); +} + +static int neoFindMode(int xres, int yres, int depth) +{ + int xres_s; + int i, size; + biosMode *mode; + + switch (depth) { + case 8: + size = sizeof(bios8) / sizeof(biosMode); + mode = bios8; + break; + case 16: + size = sizeof(bios16) / sizeof(biosMode); + mode = bios16; + break; + case 24: + size = sizeof(bios24) / sizeof(biosMode); + mode = bios24; + break; +#ifdef NO_32BIT_SUPPORT_YET + case 32: + size = sizeof(bios32) / sizeof(biosMode); + mode = bios32; + break; +#endif + default: + return 0; + } + + for (i = 0; i < size; i++) { + if (xres <= mode[i].x_res) { + xres_s = mode[i].x_res; + for (; i < size; i++) { + if (mode[i].x_res != xres_s) + return mode[i - 1].mode; + if (yres <= mode[i].y_res) + return mode[i].mode; + } + } + } + return mode[size - 1].mode; +} + +/* + * neoCalcVCLK -- + * + * Determine the closest clock frequency to the one requested. + */ +#define REF_FREQ 0xe517 /* 14.31818 in 20.12 fixed point */ +#define MAX_N 127 +#define MAX_D 31 +#define MAX_F 1 + +static void neoCalcVCLK(const struct fb_info *info, + struct neofb_par *par, long freq) +{ + int n, d, f; + int n_best = 0, d_best = 0, f_best = 0; + long f_best_diff = (0x7ffff << 12); /* 20.12 */ + long f_target = (freq << 12) / 1000; /* 20.12 */ + + for (f = 0; f <= MAX_F; f++) + for (n = 0; n <= MAX_N; n++) + for (d = 0; d <= MAX_D; d++) { + long f_out; /* 20.12 */ + long f_diff; /* 20.12 */ + + f_out = + ((((n + 1) << 12) / ((d + + 1) * + (1 << f))) >> 12) + * REF_FREQ; + f_diff = abs(f_out - f_target); + if (f_diff < f_best_diff) { + f_best_diff = f_diff; + n_best = n; + d_best = d; + f_best = f; + } + } + + if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 || + info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 || + info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 || + info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) { + /* NOT_DONE: We are trying the full range of the 2200 clock. + We should be able to try n up to 2047 */ + par->VCLK3NumeratorLow = n_best; + par->VCLK3NumeratorHigh = (f_best << 7); + } else + par->VCLK3NumeratorLow = n_best | (f_best << 7); + + par->VCLK3Denominator = d_best; + +#ifdef NEOFB_DEBUG + printk("neoVCLK: f:%d NumLow=%d NumHi=%d Den=%d Df=%d\n", + f_target >> 12, + par->VCLK3NumeratorLow, + par->VCLK3NumeratorHigh, + par->VCLK3Denominator, f_best_diff >> 12); +#endif +} + +/* + * vgaHWInit -- + * Handle the initialization, etc. of a screen. + * Return FALSE on failure. + */ + +static int vgaHWInit(const struct fb_var_screeninfo *var, + const struct fb_info *info, + struct neofb_par *par, struct xtimings *timings) +{ + par->MiscOutReg = 0x23; + + if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT)) + par->MiscOutReg |= 0x40; + + if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT)) + par->MiscOutReg |= 0x80; + + /* + * Time Sequencer + */ + par->Sequencer[0] = 0x00; + par->Sequencer[1] = 0x01; + par->Sequencer[2] = 0x0F; + par->Sequencer[3] = 0x00; /* Font select */ + par->Sequencer[4] = 0x0E; /* Misc */ + + /* + * CRTC Controller + */ + par->CRTC[0] = (timings->HTotal >> 3) - 5; + par->CRTC[1] = (timings->HDisplay >> 3) - 1; + par->CRTC[2] = (timings->HDisplay >> 3) - 1; + par->CRTC[3] = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80; + par->CRTC[4] = (timings->HSyncStart >> 3); + par->CRTC[5] = ((((timings->HTotal >> 3) - 1) & 0x20) << 2) + | (((timings->HSyncEnd >> 3)) & 0x1F); + par->CRTC[6] = (timings->VTotal - 2) & 0xFF; + par->CRTC[7] = (((timings->VTotal - 2) & 0x100) >> 8) + | (((timings->VDisplay - 1) & 0x100) >> 7) + | ((timings->VSyncStart & 0x100) >> 6) + | (((timings->VDisplay - 1) & 0x100) >> 5) + | 0x10 | (((timings->VTotal - 2) & 0x200) >> 4) + | (((timings->VDisplay - 1) & 0x200) >> 3) + | ((timings->VSyncStart & 0x200) >> 2); + par->CRTC[8] = 0x00; + par->CRTC[9] = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40; + + if (timings->dblscan) + par->CRTC[9] |= 0x80; + + par->CRTC[10] = 0x00; + par->CRTC[11] = 0x00; + par->CRTC[12] = 0x00; + par->CRTC[13] = 0x00; + par->CRTC[14] = 0x00; + par->CRTC[15] = 0x00; + par->CRTC[16] = timings->VSyncStart & 0xFF; + par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20; + par->CRTC[18] = (timings->VDisplay - 1) & 0xFF; + par->CRTC[19] = var->xres_virtual >> 4; + par->CRTC[20] = 0x00; + par->CRTC[21] = (timings->VDisplay - 1) & 0xFF; + par->CRTC[22] = (timings->VTotal - 1) & 0xFF; + par->CRTC[23] = 0xC3; + par->CRTC[24] = 0xFF; + + /* + * are these unnecessary? + * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO); + * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO); + */ + + /* + * Graphics Display Controller + */ + par->Graphics[0] = 0x00; + par->Graphics[1] = 0x00; + par->Graphics[2] = 0x00; + par->Graphics[3] = 0x00; + par->Graphics[4] = 0x00; + par->Graphics[5] = 0x40; + par->Graphics[6] = 0x05; /* only map 64k VGA memory !!!! */ + par->Graphics[7] = 0x0F; + par->Graphics[8] = 0xFF; + + + par->Attribute[0] = 0x00; /* standard colormap translation */ + par->Attribute[1] = 0x01; + par->Attribute[2] = 0x02; + par->Attribute[3] = 0x03; + par->Attribute[4] = 0x04; + par->Attribute[5] = 0x05; + par->Attribute[6] = 0x06; + par->Attribute[7] = 0x07; + par->Attribute[8] = 0x08; + par->Attribute[9] = 0x09; + par->Attribute[10] = 0x0A; + par->Attribute[11] = 0x0B; + par->Attribute[12] = 0x0C; + par->Attribute[13] = 0x0D; + par->Attribute[14] = 0x0E; + par->Attribute[15] = 0x0F; + par->Attribute[16] = 0x41; + par->Attribute[17] = 0xFF; + par->Attribute[18] = 0x0F; + par->Attribute[19] = 0x00; + par->Attribute[20] = 0x00; + return 0; +} + +static void vgaHWLock(struct vgastate *state) +{ + /* Protect CRTC[0-7] */ + vga_wcrt(state->vgabase, 0x11, vga_rcrt(state->vgabase, 0x11) | 0x80); +} + +static void vgaHWUnlock(void) +{ + /* Unprotect CRTC[0-7] */ + vga_wcrt(NULL, 0x11, vga_rcrt(NULL, 0x11) & ~0x80); +} + +static void neoLock(struct vgastate *state) +{ + vga_wgfx(state->vgabase, 0x09, 0x00); + vgaHWLock(state); +} + +static void neoUnlock(void) +{ + vgaHWUnlock(); + vga_wgfx(NULL, 0x09, 0x26); +} + +/* + * VGA Palette management + */ +static int paletteEnabled = 0; + +static inline void VGAenablePalette(void) +{ + vga_r(NULL, VGA_IS1_RC); + vga_w(NULL, VGA_ATT_W, 0x00); + paletteEnabled = 1; +} + +static inline void VGAdisablePalette(void) +{ + vga_r(NULL, VGA_IS1_RC); + vga_w(NULL, VGA_ATT_W, 0x20); + paletteEnabled = 0; +} + +static inline void VGAwATTR(u8 index, u8 value) +{ + if (paletteEnabled) + index &= ~0x20; + else + index |= 0x20; + + vga_r(NULL, VGA_IS1_RC); + vga_wattr(NULL, index, value); +} + +static void vgaHWProtect(int on) +{ + unsigned char tmp; + + if (on) { + /* + * Turn off screen and disable sequencer. + */ + tmp = vga_rseq(NULL, 0x01); + vga_wseq(NULL, 0x00, 0x01); /* Synchronous Reset */ + vga_wseq(NULL, 0x01, tmp | 0x20); /* disable the display */ + + VGAenablePalette(); + } else { + /* + * Reenable sequencer, then turn on screen. + */ + tmp = vga_rseq(NULL, 0x01); + vga_wseq(NULL, 0x01, tmp & ~0x20); /* reenable display */ + vga_wseq(NULL, 0x00, 0x03); /* clear synchronousreset */ + + VGAdisablePalette(); + } +} + +static void vgaHWRestore(const struct fb_info *info, + const struct neofb_par *par) +{ + int i; + + vga_w(NULL, VGA_MIS_W, par->MiscOutReg); + + for (i = 1; i < 5; i++) + vga_wseq(NULL, i, par->Sequencer[i]); + + /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */ + vga_wcrt(NULL, 17, par->CRTC[17] & ~0x80); + + for (i = 0; i < 25; i++) + vga_wcrt(NULL, i, par->CRTC[i]); + + for (i = 0; i < 9; i++) + vga_wgfx(NULL, i, par->Graphics[i]); + + VGAenablePalette(); + + for (i = 0; i < 21; i++) + VGAwATTR(i, par->Attribute[i]); + + VGAdisablePalette(); +} + + +/* -------------------- Hardware specific routines ------------------------- */ + +/* + * Hardware Acceleration for Neo2200+ + */ +static inline int neo2200_sync(struct fb_info *info) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + int waitcycles; + + while (readl(&par->neo2200->bltStat) & 1) + waitcycles++; + return 0; +} + +static inline void neo2200_wait_fifo(struct fb_info *info, + int requested_fifo_space) +{ + // ndev->neo.waitfifo_calls++; + // ndev->neo.waitfifo_sum += requested_fifo_space; + + /* FIXME: does not work + if (neo_fifo_space < requested_fifo_space) + { + neo_fifo_waitcycles++; + + while (1) + { + neo_fifo_space = (neo2200->bltStat >> 8); + if (neo_fifo_space >= requested_fifo_space) + break; + } + } + else + { + neo_fifo_cache_hits++; + } + + neo_fifo_space -= requested_fifo_space; + */ + + neo2200_sync(info); +} + +static inline void neo2200_accel_init(struct fb_info *info, + struct fb_var_screeninfo *var) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + Neo2200 __iomem *neo2200 = par->neo2200; + u32 bltMod, pitch; + + neo2200_sync(info); + + switch (var->bits_per_pixel) { + case 8: + bltMod = NEO_MODE1_DEPTH8; + pitch = var->xres_virtual; + break; + case 15: + case 16: + bltMod = NEO_MODE1_DEPTH16; + pitch = var->xres_virtual * 2; + break; + case 24: + bltMod = NEO_MODE1_DEPTH24; + pitch = var->xres_virtual * 3; + break; + default: + printk(KERN_ERR + "neofb: neo2200_accel_init: unexpected bits per pixel!\n"); + return; + } + + writel(bltMod << 16, &neo2200->bltStat); + writel((pitch << 16) | pitch, &neo2200->pitch); +} + +/* --------------------------------------------------------------------- */ + +static int +neofb_open(struct fb_info *info, int user) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + int cnt = atomic_read(&par->ref_count); + + if (!cnt) { + memset(&par->state, 0, sizeof(struct vgastate)); + par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS; + save_vga(&par->state); + } + atomic_inc(&par->ref_count); + return 0; +} + +static int +neofb_release(struct fb_info *info, int user) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + int cnt = atomic_read(&par->ref_count); + + if (!cnt) + return -EINVAL; + if (cnt == 1) { + restore_vga(&par->state); + } + atomic_dec(&par->ref_count); + return 0; +} + +static int +neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + unsigned int pixclock = var->pixclock; + struct xtimings timings; + int memlen, vramlen; + int mode_ok = 0; + + DBG("neofb_check_var"); + + if (!pixclock) + pixclock = 10000; /* 10ns = 100MHz */ + timings.pixclock = 1000000000 / pixclock; + if (timings.pixclock < 1) + timings.pixclock = 1; + + if (timings.pixclock > par->maxClock) + return -EINVAL; + + timings.dblscan = var->vmode & FB_VMODE_DOUBLE; + timings.interlaced = var->vmode & FB_VMODE_INTERLACED; + timings.HDisplay = var->xres; + timings.HSyncStart = timings.HDisplay + var->right_margin; + timings.HSyncEnd = timings.HSyncStart + var->hsync_len; + timings.HTotal = timings.HSyncEnd + var->left_margin; + timings.VDisplay = var->yres; + timings.VSyncStart = timings.VDisplay + var->lower_margin; + timings.VSyncEnd = timings.VSyncStart + var->vsync_len; + timings.VTotal = timings.VSyncEnd + var->upper_margin; + timings.sync = var->sync; + + /* Is the mode larger than the LCD panel? */ + if (par->internal_display && + ((var->xres > par->NeoPanelWidth) || + (var->yres > par->NeoPanelHeight))) { + printk(KERN_INFO + "Mode (%dx%d) larger than the LCD panel (%dx%d)\n", + var->xres, var->yres, par->NeoPanelWidth, + par->NeoPanelHeight); + return -EINVAL; + } + + /* Is the mode one of the acceptable sizes? */ + if (!par->internal_display) + mode_ok = 1; + else { + switch (var->xres) { + case 1280: + if (var->yres == 1024) + mode_ok = 1; + break; + case 1024: + if (var->yres == 768) + mode_ok = 1; + break; + case 800: + if (var->yres == (par->libretto ? 480 : 600)) + mode_ok = 1; + break; + case 640: + if (var->yres == 480) + mode_ok = 1; + break; + } + } + + if (!mode_ok) { + printk(KERN_INFO + "Mode (%dx%d) won't display properly on LCD\n", + var->xres, var->yres); + return -EINVAL; + } + + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + + switch (var->bits_per_pixel) { + case 8: /* PSEUDOCOLOUR, 256 */ + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + break; + + case 16: /* DIRECTCOLOUR, 64k */ + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + + case 24: /* TRUECOLOUR, 16m */ + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + break; + +#ifdef NO_32BIT_SUPPORT_YET + case 32: /* TRUECOLOUR, 16m */ + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + break; +#endif + default: + printk(KERN_WARNING "neofb: no support for %dbpp\n", + var->bits_per_pixel); + return -EINVAL; + } + + vramlen = info->fix.smem_len; + if (vramlen > 4 * 1024 * 1024) + vramlen = 4 * 1024 * 1024; + + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + + memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual >> 3; + + if (memlen > vramlen) { + var->yres_virtual = vramlen * 8 / (var->xres_virtual * + var->bits_per_pixel); + memlen = var->xres_virtual * var->bits_per_pixel * + var->yres_virtual / 8; + } + + /* we must round yres/xres down, we already rounded y/xres_virtual up + if it was possible. We should return -EINVAL, but I disagree */ + if (var->yres_virtual < var->yres) + var->yres = var->yres_virtual; + if (var->xres_virtual < var->xres) + var->xres = var->xres_virtual; + if (var->xoffset + var->xres > var->xres_virtual) + var->xoffset = var->xres_virtual - var->xres; + if (var->yoffset + var->yres > var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres; + + var->nonstd = 0; + var->height = -1; + var->width = -1; + + if (var->bits_per_pixel >= 24 || !par->neo2200) + var->accel_flags &= ~FB_ACCELF_TEXT; + return 0; +} + +static int neofb_set_par(struct fb_info *info) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + struct xtimings timings; + unsigned char temp; + int i, clock_hi = 0; + int lcd_stretch; + int hoffset, voffset; + + DBG("neofb_set_par"); + + neoUnlock(); + + vgaHWProtect(1); /* Blank the screen */ + + timings.dblscan = info->var.vmode & FB_VMODE_DOUBLE; + timings.interlaced = info->var.vmode & FB_VMODE_INTERLACED; + timings.HDisplay = info->var.xres; + timings.HSyncStart = timings.HDisplay + info->var.right_margin; + timings.HSyncEnd = timings.HSyncStart + info->var.hsync_len; + timings.HTotal = timings.HSyncEnd + info->var.left_margin; + timings.VDisplay = info->var.yres; + timings.VSyncStart = timings.VDisplay + info->var.lower_margin; + timings.VSyncEnd = timings.VSyncStart + info->var.vsync_len; + timings.VTotal = timings.VSyncEnd + info->var.upper_margin; + timings.sync = info->var.sync; + timings.pixclock = PICOS2KHZ(info->var.pixclock); + + if (timings.pixclock < 1) + timings.pixclock = 1; + + /* + * This will allocate the datastructure and initialize all of the + * generic VGA registers. + */ + + if (vgaHWInit(&info->var, info, par, &timings)) + return -EINVAL; + + /* + * The default value assigned by vgaHW.c is 0x41, but this does + * not work for NeoMagic. + */ + par->Attribute[16] = 0x01; + + switch (info->var.bits_per_pixel) { + case 8: + par->CRTC[0x13] = info->var.xres_virtual >> 3; + par->ExtCRTOffset = info->var.xres_virtual >> 11; + par->ExtColorModeSelect = 0x11; + break; + case 16: + par->CRTC[0x13] = info->var.xres_virtual >> 2; + par->ExtCRTOffset = info->var.xres_virtual >> 10; + par->ExtColorModeSelect = 0x13; + break; + case 24: + par->CRTC[0x13] = (info->var.xres_virtual * 3) >> 3; + par->ExtCRTOffset = (info->var.xres_virtual * 3) >> 11; + par->ExtColorModeSelect = 0x14; + break; +#ifdef NO_32BIT_SUPPORT_YET + case 32: /* FIXME: guessed values */ + par->CRTC[0x13] = info->var.xres_virtual >> 1; + par->ExtCRTOffset = info->var.xres_virtual >> 9; + par->ExtColorModeSelect = 0x15; + break; +#endif + default: + break; + } + + par->ExtCRTDispAddr = 0x10; + + /* Vertical Extension */ + par->VerticalExt = (((timings.VTotal - 2) & 0x400) >> 10) + | (((timings.VDisplay - 1) & 0x400) >> 9) + | (((timings.VSyncStart) & 0x400) >> 8) + | (((timings.VSyncStart) & 0x400) >> 7); + + /* Fast write bursts on unless disabled. */ + if (par->pci_burst) + par->SysIfaceCntl1 = 0x30; + else + par->SysIfaceCntl1 = 0x00; + + par->SysIfaceCntl2 = 0xc0; /* VESA Bios sets this to 0x80! */ + + /* Enable any user specified display devices. */ + par->PanelDispCntlReg1 = 0x00; + if (par->internal_display) + par->PanelDispCntlReg1 |= 0x02; + if (par->external_display) + par->PanelDispCntlReg1 |= 0x01; + + /* If the user did not specify any display devices, then... */ + if (par->PanelDispCntlReg1 == 0x00) { + /* Default to internal (i.e., LCD) only. */ + par->PanelDispCntlReg1 |= 0x02; + } + + /* If we are using a fixed mode, then tell the chip we are. */ + switch (info->var.xres) { + case 1280: + par->PanelDispCntlReg1 |= 0x60; + break; + case 1024: + par->PanelDispCntlReg1 |= 0x40; + break; + case 800: + par->PanelDispCntlReg1 |= 0x20; + break; + case 640: + default: + break; + } + + /* Setup shadow register locking. */ + switch (par->PanelDispCntlReg1 & 0x03) { + case 0x01: /* External CRT only mode: */ + par->GeneralLockReg = 0x00; + /* We need to program the VCLK for external display only mode. */ + par->ProgramVCLK = 1; + break; + case 0x02: /* Internal LCD only mode: */ + case 0x03: /* Simultaneous internal/external (LCD/CRT) mode: */ + par->GeneralLockReg = 0x01; + /* Don't program the VCLK when using the LCD. */ + par->ProgramVCLK = 0; + break; + } + + /* + * If the screen is to be stretched, turn on stretching for the + * various modes. + * + * OPTION_LCD_STRETCH means stretching should be turned off! + */ + par->PanelDispCntlReg2 = 0x00; + par->PanelDispCntlReg3 = 0x00; + + if (par->lcd_stretch && (par->PanelDispCntlReg1 == 0x02) && /* LCD only */ + (info->var.xres != par->NeoPanelWidth)) { + switch (info->var.xres) { + case 320: /* Needs testing. KEM -- 24 May 98 */ + case 400: /* Needs testing. KEM -- 24 May 98 */ + case 640: + case 800: + case 1024: + lcd_stretch = 1; + par->PanelDispCntlReg2 |= 0xC6; + break; + default: + lcd_stretch = 0; + /* No stretching in these modes. */ + } + } else + lcd_stretch = 0; + + /* + * If the screen is to be centerd, turn on the centering for the + * various modes. + */ + par->PanelVertCenterReg1 = 0x00; + par->PanelVertCenterReg2 = 0x00; + par->PanelVertCenterReg3 = 0x00; + par->PanelVertCenterReg4 = 0x00; + par->PanelVertCenterReg5 = 0x00; + par->PanelHorizCenterReg1 = 0x00; + par->PanelHorizCenterReg2 = 0x00; + par->PanelHorizCenterReg3 = 0x00; + par->PanelHorizCenterReg4 = 0x00; + par->PanelHorizCenterReg5 = 0x00; + + + if (par->PanelDispCntlReg1 & 0x02) { + if (info->var.xres == par->NeoPanelWidth) { + /* + * No centering required when the requested display width + * equals the panel width. + */ + } else { + par->PanelDispCntlReg2 |= 0x01; + par->PanelDispCntlReg3 |= 0x10; + + /* Calculate the horizontal and vertical offsets. */ + if (!lcd_stretch) { + hoffset = + ((par->NeoPanelWidth - + info->var.xres) >> 4) - 1; + voffset = + ((par->NeoPanelHeight - + info->var.yres) >> 1) - 2; + } else { + /* Stretched modes cannot be centered. */ + hoffset = 0; + voffset = 0; + } + + switch (info->var.xres) { + case 320: /* Needs testing. KEM -- 24 May 98 */ + par->PanelHorizCenterReg3 = hoffset; + par->PanelVertCenterReg2 = voffset; + break; + case 400: /* Needs testing. KEM -- 24 May 98 */ + par->PanelHorizCenterReg4 = hoffset; + par->PanelVertCenterReg1 = voffset; + break; + case 640: + par->PanelHorizCenterReg1 = hoffset; + par->PanelVertCenterReg3 = voffset; + break; + case 800: + par->PanelHorizCenterReg2 = hoffset; + par->PanelVertCenterReg4 = voffset; + break; + case 1024: + par->PanelHorizCenterReg5 = hoffset; + par->PanelVertCenterReg5 = voffset; + break; + case 1280: + default: + /* No centering in these modes. */ + break; + } + } + } + + par->biosMode = + neoFindMode(info->var.xres, info->var.yres, + info->var.bits_per_pixel); + + /* + * Calculate the VCLK that most closely matches the requested dot + * clock. + */ + neoCalcVCLK(info, par, timings.pixclock); + + /* Since we program the clocks ourselves, always use VCLK3. */ + par->MiscOutReg |= 0x0C; + + /* alread unlocked above */ + /* BOGUS vga_wgfx(NULL, 0x09, 0x26); */ + + /* don't know what this is, but it's 0 from bootup anyway */ + vga_wgfx(NULL, 0x15, 0x00); + + /* was set to 0x01 by my bios in text and vesa modes */ + vga_wgfx(NULL, 0x0A, par->GeneralLockReg); + + /* + * The color mode needs to be set before calling vgaHWRestore + * to ensure the DAC is initialized properly. + * + * NOTE: Make sure we don't change bits make sure we don't change + * any reserved bits. + */ + temp = vga_rgfx(NULL, 0x90); + switch (info->fix.accel) { + case FB_ACCEL_NEOMAGIC_NM2070: + temp &= 0xF0; /* Save bits 7:4 */ + temp |= (par->ExtColorModeSelect & ~0xF0); + break; + case FB_ACCEL_NEOMAGIC_NM2090: + case FB_ACCEL_NEOMAGIC_NM2093: + case FB_ACCEL_NEOMAGIC_NM2097: + case FB_ACCEL_NEOMAGIC_NM2160: + case FB_ACCEL_NEOMAGIC_NM2200: + case FB_ACCEL_NEOMAGIC_NM2230: + case FB_ACCEL_NEOMAGIC_NM2360: + case FB_ACCEL_NEOMAGIC_NM2380: + temp &= 0x70; /* Save bits 6:4 */ + temp |= (par->ExtColorModeSelect & ~0x70); + break; + } + + vga_wgfx(NULL, 0x90, temp); + + /* + * In some rare cases a lockup might occur if we don't delay + * here. (Reported by Miles Lane) + */ + //mdelay(200); + + /* + * Disable horizontal and vertical graphics and text expansions so + * that vgaHWRestore works properly. + */ + temp = vga_rgfx(NULL, 0x25); + temp &= 0x39; + vga_wgfx(NULL, 0x25, temp); + + /* + * Sleep for 200ms to make sure that the two operations above have + * had time to take effect. + */ + mdelay(200); + + /* + * This function handles restoring the generic VGA registers. */ + vgaHWRestore(info, par); + + /* linear colormap for non palettized modes */ + switch (info->var.bits_per_pixel) { + case 8: + /* PseudoColor, 256 */ + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + case 16: + /* TrueColor, 64k */ + info->fix.visual = FB_VISUAL_TRUECOLOR; + + for (i = 0; i < 64; i++) { + outb(i, 0x3c8); + + outb(i << 1, 0x3c9); + outb(i, 0x3c9); + outb(i << 1, 0x3c9); + } + break; + case 24: +#ifdef NO_32BIT_SUPPORT_YET + case 32: +#endif + /* TrueColor, 16m */ + info->fix.visual = FB_VISUAL_TRUECOLOR; + + for (i = 0; i < 256; i++) { + outb(i, 0x3c8); + + outb(i, 0x3c9); + outb(i, 0x3c9); + outb(i, 0x3c9); + } + break; + } + + vga_wgfx(NULL, 0x0E, par->ExtCRTDispAddr); + vga_wgfx(NULL, 0x0F, par->ExtCRTOffset); + temp = vga_rgfx(NULL, 0x10); + temp &= 0x0F; /* Save bits 3:0 */ + temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */ + vga_wgfx(NULL, 0x10, temp); + + vga_wgfx(NULL, 0x11, par->SysIfaceCntl2); + vga_wgfx(NULL, 0x15, 0 /*par->SingleAddrPage */ ); + vga_wgfx(NULL, 0x16, 0 /*par->DualAddrPage */ ); + + temp = vga_rgfx(NULL, 0x20); + switch (info->fix.accel) { + case FB_ACCEL_NEOMAGIC_NM2070: + temp &= 0xFC; /* Save bits 7:2 */ + temp |= (par->PanelDispCntlReg1 & ~0xFC); + break; + case FB_ACCEL_NEOMAGIC_NM2090: + case FB_ACCEL_NEOMAGIC_NM2093: + case FB_ACCEL_NEOMAGIC_NM2097: + case FB_ACCEL_NEOMAGIC_NM2160: + temp &= 0xDC; /* Save bits 7:6,4:2 */ + temp |= (par->PanelDispCntlReg1 & ~0xDC); + break; + case FB_ACCEL_NEOMAGIC_NM2200: + case FB_ACCEL_NEOMAGIC_NM2230: + case FB_ACCEL_NEOMAGIC_NM2360: + case FB_ACCEL_NEOMAGIC_NM2380: + temp &= 0x98; /* Save bits 7,4:3 */ + temp |= (par->PanelDispCntlReg1 & ~0x98); + break; + } + vga_wgfx(NULL, 0x20, temp); + + temp = vga_rgfx(NULL, 0x25); + temp &= 0x38; /* Save bits 5:3 */ + temp |= (par->PanelDispCntlReg2 & ~0x38); + vga_wgfx(NULL, 0x25, temp); + + if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) { + temp = vga_rgfx(NULL, 0x30); + temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */ + temp |= (par->PanelDispCntlReg3 & ~0xEF); + vga_wgfx(NULL, 0x30, temp); + } + + vga_wgfx(NULL, 0x28, par->PanelVertCenterReg1); + vga_wgfx(NULL, 0x29, par->PanelVertCenterReg2); + vga_wgfx(NULL, 0x2a, par->PanelVertCenterReg3); + + if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) { + vga_wgfx(NULL, 0x32, par->PanelVertCenterReg4); + vga_wgfx(NULL, 0x33, par->PanelHorizCenterReg1); + vga_wgfx(NULL, 0x34, par->PanelHorizCenterReg2); + vga_wgfx(NULL, 0x35, par->PanelHorizCenterReg3); + } + + if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2160) + vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4); + + if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 || + info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 || + info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 || + info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) { + vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4); + vga_wgfx(NULL, 0x37, par->PanelVertCenterReg5); + vga_wgfx(NULL, 0x38, par->PanelHorizCenterReg5); + + clock_hi = 1; + } + + /* Program VCLK3 if needed. */ + if (par->ProgramVCLK && ((vga_rgfx(NULL, 0x9B) != par->VCLK3NumeratorLow) + || (vga_rgfx(NULL, 0x9F) != par->VCLK3Denominator) + || (clock_hi && ((vga_rgfx(NULL, 0x8F) & ~0x0f) + != (par->VCLK3NumeratorHigh & + ~0x0F))))) { + vga_wgfx(NULL, 0x9B, par->VCLK3NumeratorLow); + if (clock_hi) { + temp = vga_rgfx(NULL, 0x8F); + temp &= 0x0F; /* Save bits 3:0 */ + temp |= (par->VCLK3NumeratorHigh & ~0x0F); + vga_wgfx(NULL, 0x8F, temp); + } + vga_wgfx(NULL, 0x9F, par->VCLK3Denominator); + } + + if (par->biosMode) + vga_wcrt(NULL, 0x23, par->biosMode); + + vga_wgfx(NULL, 0x93, 0xc0); /* Gives 5x faster framebuffer writes !!! */ + + /* Program vertical extension register */ + if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 || + info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 || + info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 || + info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) { + vga_wcrt(NULL, 0x70, par->VerticalExt); + } + + vgaHWProtect(0); /* Turn on screen */ + + /* Calling this also locks offset registers required in update_start */ + neoLock(&par->state); + + info->fix.line_length = + info->var.xres_virtual * (info->var.bits_per_pixel >> 3); + + switch (info->fix.accel) { + case FB_ACCEL_NEOMAGIC_NM2200: + case FB_ACCEL_NEOMAGIC_NM2230: + case FB_ACCEL_NEOMAGIC_NM2360: + case FB_ACCEL_NEOMAGIC_NM2380: + neo2200_accel_init(info, &info->var); + break; + default: + break; + } + return 0; +} + +static void neofb_update_start(struct fb_info *info, + struct fb_var_screeninfo *var) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + struct vgastate *state = &par->state; + int oldExtCRTDispAddr; + int Base; + + DBG("neofb_update_start"); + + Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2; + Base *= (var->bits_per_pixel + 7) / 8; + + neoUnlock(); + + /* + * These are the generic starting address registers. + */ + vga_wcrt(state->vgabase, 0x0C, (Base & 0x00FF00) >> 8); + vga_wcrt(state->vgabase, 0x0D, (Base & 0x00FF)); + + /* + * Make sure we don't clobber some other bits that might already + * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't + * be needed. + */ + oldExtCRTDispAddr = vga_rgfx(NULL, 0x0E); + vga_wgfx(state->vgabase, 0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0))); + + neoLock(state); +} + +/* + * Pan or Wrap the Display + */ +static int neofb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + u_int y_bottom; + + y_bottom = var->yoffset; + + if (!(var->vmode & FB_VMODE_YWRAP)) + y_bottom += var->yres; + + if (var->xoffset > (var->xres_virtual - var->xres)) + return -EINVAL; + if (y_bottom > info->var.yres_virtual) + return -EINVAL; + + neofb_update_start(info, var); + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; +} + +static int neofb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *fb) +{ + if (regno >= fb->cmap.len || regno > 255) + return -EINVAL; + + switch (fb->var.bits_per_pixel) { + case 8: + outb(regno, 0x3c8); + + outb(red >> 10, 0x3c9); + outb(green >> 10, 0x3c9); + outb(blue >> 10, 0x3c9); + break; + case 16: + ((u32 *) fb->pseudo_palette)[regno] = + ((red & 0xf800)) | ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + ((u32 *) fb->pseudo_palette)[regno] = + ((red & 0xff00) << 8) | ((green & 0xff00)) | + ((blue & 0xff00) >> 8); + break; +#ifdef NO_32BIT_SUPPORT_YET + case 32: + ((u32 *) fb->pseudo_palette)[regno] = + ((transp & 0xff00) << 16) | ((red & 0xff00) << 8) | + ((green & 0xff00)) | ((blue & 0xff00) >> 8); + break; +#endif + default: + return 1; + } + return 0; +} + +/* + * (Un)Blank the display. + */ +static int neofb_blank(int blank_mode, struct fb_info *info) +{ + /* + * Blank the screen if blank_mode != 0, else unblank. + * Return 0 if blanking succeeded, != 0 if un-/blanking failed due to + * e.g. a video mode which doesn't support it. Implements VESA suspend + * and powerdown modes for monitors, and backlight control on LCDs. + * blank_mode == 0: unblanked (backlight on) + * blank_mode == 1: blank (backlight on) + * blank_mode == 2: suspend vsync (backlight off) + * blank_mode == 3: suspend hsync (backlight off) + * blank_mode == 4: powerdown (backlight off) + * + * wms...Enable VESA DPMS compatible powerdown mode + * run "setterm -powersave powerdown" to take advantage + */ + struct neofb_par *par = (struct neofb_par *)info->par; + int seqflags, lcdflags, dpmsflags, reg; + + switch (blank_mode) { + case FB_BLANK_POWERDOWN: /* powerdown - both sync lines down */ + seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */ + lcdflags = 0; /* LCD off */ + dpmsflags = NEO_GR01_SUPPRESS_HSYNC | + NEO_GR01_SUPPRESS_VSYNC; +#ifdef CONFIG_TOSHIBA + /* Do we still need this ? */ + /* attempt to turn off backlight on toshiba; also turns off external */ + { + SMMRegisters regs; + + regs.eax = 0xff00; /* HCI_SET */ + regs.ebx = 0x0002; /* HCI_BACKLIGHT */ + regs.ecx = 0x0000; /* HCI_DISABLE */ + tosh_smm(®s); + } +#endif + break; + case FB_BLANK_HSYNC_SUSPEND: /* hsync off */ + seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */ + lcdflags = 0; /* LCD off */ + dpmsflags = NEO_GR01_SUPPRESS_HSYNC; + break; + case FB_BLANK_VSYNC_SUSPEND: /* vsync off */ + seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */ + lcdflags = 0; /* LCD off */ + dpmsflags = NEO_GR01_SUPPRESS_VSYNC; + break; + case FB_BLANK_NORMAL: /* just blank screen (backlight stays on) */ + seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */ + lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */ + dpmsflags = 0; /* no hsync/vsync suppression */ + break; + case FB_BLANK_UNBLANK: /* unblank */ + seqflags = 0; /* Enable sequencer */ + lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */ + dpmsflags = 0x00; /* no hsync/vsync suppression */ +#ifdef CONFIG_TOSHIBA + /* Do we still need this ? */ + /* attempt to re-enable backlight/external on toshiba */ + { + SMMRegisters regs; + + regs.eax = 0xff00; /* HCI_SET */ + regs.ebx = 0x0002; /* HCI_BACKLIGHT */ + regs.ecx = 0x0001; /* HCI_ENABLE */ + tosh_smm(®s); + } +#endif + break; + default: /* Anything else we don't understand; return 1 to tell + * fb_blank we didn't aactually do anything */ + return 1; + } + + neoUnlock(); + reg = (vga_rseq(NULL, 0x01) & ~0x20) | seqflags; + vga_wseq(NULL, 0x01, reg); + reg = (vga_rgfx(NULL, 0x20) & ~0x02) | lcdflags; + vga_wgfx(NULL, 0x20, reg); + reg = (vga_rgfx(NULL, 0x01) & ~0xF0) | 0x80 | dpmsflags; + vga_wgfx(NULL, 0x01, reg); + neoLock(&par->state); + return 0; +} + +static void +neo2200_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + u_long dst, rop; + + dst = rect->dx + rect->dy * info->var.xres_virtual; + rop = rect->rop ? 0x060000 : 0x0c0000; + + neo2200_wait_fifo(info, 4); + + /* set blt control */ + writel(NEO_BC3_FIFO_EN | + NEO_BC0_SRC_IS_FG | NEO_BC3_SKIP_MAPPING | + // NEO_BC3_DST_XY_ADDR | + // NEO_BC3_SRC_XY_ADDR | + rop, &par->neo2200->bltCntl); + + switch (info->var.bits_per_pixel) { + case 8: + writel(rect->color, &par->neo2200->fgColor); + break; + case 16: + case 24: + writel(((u32 *) (info->pseudo_palette))[rect->color], + &par->neo2200->fgColor); + break; + } + + writel(dst * ((info->var.bits_per_pixel + 7) >> 3), + &par->neo2200->dstStart); + writel((rect->height << 16) | (rect->width & 0xffff), + &par->neo2200->xyExt); +} + +static void +neo2200_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy; + struct neofb_par *par = (struct neofb_par *) info->par; + u_long src, dst, bltCntl; + + bltCntl = NEO_BC3_FIFO_EN | NEO_BC3_SKIP_MAPPING | 0x0C0000; + + if ((dy > sy) || ((dy == sy) && (dx > sx))) { + /* Start with the lower right corner */ + sy += (area->height - 1); + dy += (area->height - 1); + sx += (area->width - 1); + dx += (area->width - 1); + + bltCntl |= NEO_BC0_X_DEC | NEO_BC0_DST_Y_DEC | NEO_BC0_SRC_Y_DEC; + } + + src = sx * (info->var.bits_per_pixel >> 3) + sy*info->fix.line_length; + dst = dx * (info->var.bits_per_pixel >> 3) + dy*info->fix.line_length; + + neo2200_wait_fifo(info, 4); + + /* set blt control */ + writel(bltCntl, &par->neo2200->bltCntl); + + writel(src, &par->neo2200->srcStart); + writel(dst, &par->neo2200->dstStart); + writel((area->height << 16) | (area->width & 0xffff), + &par->neo2200->xyExt); +} + +static void +neo2200_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + int s_pitch = (image->width * image->depth + 7) >> 3; + int scan_align = info->pixmap.scan_align - 1; + int buf_align = info->pixmap.buf_align - 1; + int bltCntl_flags, d_pitch, data_len; + + // The data is padded for the hardware + d_pitch = (s_pitch + scan_align) & ~scan_align; + data_len = ((d_pitch * image->height) + buf_align) & ~buf_align; + + neo2200_sync(info); + + if (image->depth == 1) { + if (info->var.bits_per_pixel == 24 && image->width < 16) { + /* FIXME. There is a bug with accelerated color-expanded + * transfers in 24 bit mode if the image being transferred + * is less than 16 bits wide. This is due to insufficient + * padding when writing the image. We need to adjust + * struct fb_pixmap. Not yet done. */ + return cfb_imageblit(info, image); + } + bltCntl_flags = NEO_BC0_SRC_MONO; + } else if (image->depth == info->var.bits_per_pixel) { + bltCntl_flags = 0; + } else { + /* We don't currently support hardware acceleration if image + * depth is different from display */ + return cfb_imageblit(info, image); + } + + switch (info->var.bits_per_pixel) { + case 8: + writel(image->fg_color, &par->neo2200->fgColor); + writel(image->bg_color, &par->neo2200->bgColor); + break; + case 16: + case 24: + writel(((u32 *) (info->pseudo_palette))[image->fg_color], + &par->neo2200->fgColor); + writel(((u32 *) (info->pseudo_palette))[image->bg_color], + &par->neo2200->bgColor); + break; + } + + writel(NEO_BC0_SYS_TO_VID | + NEO_BC3_SKIP_MAPPING | bltCntl_flags | + // NEO_BC3_DST_XY_ADDR | + 0x0c0000, &par->neo2200->bltCntl); + + writel(0, &par->neo2200->srcStart); +// par->neo2200->dstStart = (image->dy << 16) | (image->dx & 0xffff); + writel(((image->dx & 0xffff) * (info->var.bits_per_pixel >> 3) + + image->dy * info->fix.line_length), &par->neo2200->dstStart); + writel((image->height << 16) | (image->width & 0xffff), + &par->neo2200->xyExt); + + memcpy_toio(par->mmio_vbase + 0x100000, image->data, data_len); +} + +static void +neofb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + switch (info->fix.accel) { + case FB_ACCEL_NEOMAGIC_NM2200: + case FB_ACCEL_NEOMAGIC_NM2230: + case FB_ACCEL_NEOMAGIC_NM2360: + case FB_ACCEL_NEOMAGIC_NM2380: + neo2200_fillrect(info, rect); + break; + default: + cfb_fillrect(info, rect); + break; + } +} + +static void +neofb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + switch (info->fix.accel) { + case FB_ACCEL_NEOMAGIC_NM2200: + case FB_ACCEL_NEOMAGIC_NM2230: + case FB_ACCEL_NEOMAGIC_NM2360: + case FB_ACCEL_NEOMAGIC_NM2380: + neo2200_copyarea(info, area); + break; + default: + cfb_copyarea(info, area); + break; + } +} + +static void +neofb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + switch (info->fix.accel) { + case FB_ACCEL_NEOMAGIC_NM2200: + case FB_ACCEL_NEOMAGIC_NM2230: + case FB_ACCEL_NEOMAGIC_NM2360: + case FB_ACCEL_NEOMAGIC_NM2380: + neo2200_imageblit(info, image); + break; + default: + cfb_imageblit(info, image); + break; + } +} + +static int +neofb_sync(struct fb_info *info) +{ + switch (info->fix.accel) { + case FB_ACCEL_NEOMAGIC_NM2200: + case FB_ACCEL_NEOMAGIC_NM2230: + case FB_ACCEL_NEOMAGIC_NM2360: + case FB_ACCEL_NEOMAGIC_NM2380: + neo2200_sync(info); + break; + default: + break; + } + return 0; +} + +/* +static void +neofb_draw_cursor(struct fb_info *info, u8 *dst, u8 *src, unsigned int width) +{ + //memset_io(info->sprite.addr, 0xff, 1); +} + +static int +neofb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + + * Disable cursor * + write_le32(NEOREG_CURSCNTL, ~NEO_CURS_ENABLE, par); + + if (cursor->set & FB_CUR_SETPOS) { + u32 x = cursor->image.dx; + u32 y = cursor->image.dy; + + info->cursor.image.dx = x; + info->cursor.image.dy = y; + write_le32(NEOREG_CURSX, x, par); + write_le32(NEOREG_CURSY, y, par); + } + + if (cursor->set & FB_CUR_SETSIZE) { + info->cursor.image.height = cursor->image.height; + info->cursor.image.width = cursor->image.width; + } + + if (cursor->set & FB_CUR_SETHOT) + info->cursor.hot = cursor->hot; + + if (cursor->set & FB_CUR_SETCMAP) { + if (cursor->image.depth == 1) { + u32 fg = cursor->image.fg_color; + u32 bg = cursor->image.bg_color; + + info->cursor.image.fg_color = fg; + info->cursor.image.bg_color = bg; + + fg = ((fg & 0xff0000) >> 16) | ((fg & 0xff) << 16) | (fg & 0xff00); + bg = ((bg & 0xff0000) >> 16) | ((bg & 0xff) << 16) | (bg & 0xff00); + write_le32(NEOREG_CURSFGCOLOR, fg, par); + write_le32(NEOREG_CURSBGCOLOR, bg, par); + } + } + + if (cursor->set & FB_CUR_SETSHAPE) + fb_load_cursor_image(info); + + if (info->cursor.enable) + write_le32(NEOREG_CURSCNTL, NEO_CURS_ENABLE, par); + return 0; +} +*/ + +static struct fb_ops neofb_ops = { + .owner = THIS_MODULE, + .fb_open = neofb_open, + .fb_release = neofb_release, + .fb_check_var = neofb_check_var, + .fb_set_par = neofb_set_par, + .fb_setcolreg = neofb_setcolreg, + .fb_pan_display = neofb_pan_display, + .fb_blank = neofb_blank, + .fb_sync = neofb_sync, + .fb_fillrect = neofb_fillrect, + .fb_copyarea = neofb_copyarea, + .fb_imageblit = neofb_imageblit, + .fb_cursor = soft_cursor, +}; + +/* --------------------------------------------------------------------- */ + +static struct fb_videomode __devinitdata mode800x480 = { + .xres = 800, + .yres = 480, + .pixclock = 25000, + .left_margin = 88, + .right_margin = 40, + .upper_margin = 23, + .lower_margin = 1, + .hsync_len = 128, + .vsync_len = 4, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED +}; + +static int __devinit neo_map_mmio(struct fb_info *info, + struct pci_dev *dev) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + + DBG("neo_map_mmio"); + + switch (info->fix.accel) { + case FB_ACCEL_NEOMAGIC_NM2070: + info->fix.mmio_start = pci_resource_start(dev, 0)+ + 0x100000; + break; + case FB_ACCEL_NEOMAGIC_NM2090: + case FB_ACCEL_NEOMAGIC_NM2093: + info->fix.mmio_start = pci_resource_start(dev, 0)+ + 0x200000; + break; + case FB_ACCEL_NEOMAGIC_NM2160: + case FB_ACCEL_NEOMAGIC_NM2097: + case FB_ACCEL_NEOMAGIC_NM2200: + case FB_ACCEL_NEOMAGIC_NM2230: + case FB_ACCEL_NEOMAGIC_NM2360: + case FB_ACCEL_NEOMAGIC_NM2380: + info->fix.mmio_start = pci_resource_start(dev, 1); + break; + default: + info->fix.mmio_start = pci_resource_start(dev, 0); + } + info->fix.mmio_len = MMIO_SIZE; + + if (!request_mem_region + (info->fix.mmio_start, MMIO_SIZE, "memory mapped I/O")) { + printk("neofb: memory mapped IO in use\n"); + return -EBUSY; + } + + par->mmio_vbase = ioremap(info->fix.mmio_start, MMIO_SIZE); + if (!par->mmio_vbase) { + printk("neofb: unable to map memory mapped IO\n"); + release_mem_region(info->fix.mmio_start, + info->fix.mmio_len); + return -ENOMEM; + } else + printk(KERN_INFO "neofb: mapped io at %p\n", + par->mmio_vbase); + return 0; +} + +static void neo_unmap_mmio(struct fb_info *info) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + + DBG("neo_unmap_mmio"); + + iounmap(par->mmio_vbase); + par->mmio_vbase = NULL; + + release_mem_region(info->fix.mmio_start, + info->fix.mmio_len); +} + +static int __devinit neo_map_video(struct fb_info *info, + struct pci_dev *dev, int video_len) +{ + //unsigned long addr; + + DBG("neo_map_video"); + + info->fix.smem_start = pci_resource_start(dev, 0); + info->fix.smem_len = video_len; + + if (!request_mem_region(info->fix.smem_start, info->fix.smem_len, + "frame buffer")) { + printk("neofb: frame buffer in use\n"); + return -EBUSY; + } + + info->screen_base = + ioremap(info->fix.smem_start, info->fix.smem_len); + if (!info->screen_base) { + printk("neofb: unable to map screen memory\n"); + release_mem_region(info->fix.smem_start, + info->fix.smem_len); + return -ENOMEM; + } else + printk(KERN_INFO "neofb: mapped framebuffer at %p\n", + info->screen_base); + +#ifdef CONFIG_MTRR + ((struct neofb_par *)(info->par))->mtrr = + mtrr_add(info->fix.smem_start, pci_resource_len(dev, 0), + MTRR_TYPE_WRCOMB, 1); +#endif + + /* Clear framebuffer, it's all white in memory after boot */ + memset_io(info->screen_base, 0, info->fix.smem_len); + + /* Allocate Cursor drawing pad. + info->fix.smem_len -= PAGE_SIZE; + addr = info->fix.smem_start + info->fix.smem_len; + write_le32(NEOREG_CURSMEMPOS, ((0x000f & (addr >> 10)) << 8) | + ((0x0ff0 & (addr >> 10)) >> 4), par); + addr = (unsigned long) info->screen_base + info->fix.smem_len; + info->sprite.addr = (u8 *) addr; */ + return 0; +} + +static void neo_unmap_video(struct fb_info *info) +{ + DBG("neo_unmap_video"); + +#ifdef CONFIG_MTRR + { + struct neofb_par *par = (struct neofb_par *) info->par; + + mtrr_del(par->mtrr, info->fix.smem_start, + info->fix.smem_len); + } +#endif + iounmap(info->screen_base); + info->screen_base = NULL; + + release_mem_region(info->fix.smem_start, + info->fix.smem_len); +} + +static int __devinit neo_scan_monitor(struct fb_info *info) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + unsigned char type, display; + int w; + + // Eventually we will have i2c support. + info->monspecs.modedb = kmalloc(sizeof(struct fb_videomode), GFP_KERNEL); + if (!info->monspecs.modedb) + return -ENOMEM; + info->monspecs.modedb_len = 1; + + /* Determine the panel type */ + vga_wgfx(NULL, 0x09, 0x26); + type = vga_rgfx(NULL, 0x21); + display = vga_rgfx(NULL, 0x20); + if (!par->internal_display && !par->external_display) { + par->internal_display = display & 2 || !(display & 3) ? 1 : 0; + par->external_display = display & 1; + printk (KERN_INFO "Autodetected %s display\n", + par->internal_display && par->external_display ? "simultaneous" : + par->internal_display ? "internal" : "external"); + } + + /* Determine panel width -- used in NeoValidMode. */ + w = vga_rgfx(NULL, 0x20); + vga_wgfx(NULL, 0x09, 0x00); + switch ((w & 0x18) >> 3) { + case 0x00: + // 640x480@60 + par->NeoPanelWidth = 640; + par->NeoPanelHeight = 480; + memcpy(info->monspecs.modedb, &vesa_modes[3], sizeof(struct fb_videomode)); + break; + case 0x01: + par->NeoPanelWidth = 800; + if (par->libretto) { + par->NeoPanelHeight = 480; + memcpy(info->monspecs.modedb, &mode800x480, sizeof(struct fb_videomode)); + } else { + // 800x600@60 + par->NeoPanelHeight = 600; + memcpy(info->monspecs.modedb, &vesa_modes[8], sizeof(struct fb_videomode)); + } + break; + case 0x02: + // 1024x768@60 + par->NeoPanelWidth = 1024; + par->NeoPanelHeight = 768; + memcpy(info->monspecs.modedb, &vesa_modes[13], sizeof(struct fb_videomode)); + break; + case 0x03: + /* 1280x1024@60 panel support needs to be added */ +#ifdef NOT_DONE + par->NeoPanelWidth = 1280; + par->NeoPanelHeight = 1024; + memcpy(info->monspecs.modedb, &vesa_modes[20], sizeof(struct fb_videomode)); + break; +#else + printk(KERN_ERR + "neofb: Only 640x480, 800x600/480 and 1024x768 panels are currently supported\n"); + return -1; +#endif + default: + // 640x480@60 + par->NeoPanelWidth = 640; + par->NeoPanelHeight = 480; + memcpy(info->monspecs.modedb, &vesa_modes[3], sizeof(struct fb_videomode)); + break; + } + + printk(KERN_INFO "Panel is a %dx%d %s %s display\n", + par->NeoPanelWidth, + par->NeoPanelHeight, + (type & 0x02) ? "color" : "monochrome", + (type & 0x10) ? "TFT" : "dual scan"); + return 0; +} + +static int __devinit neo_init_hw(struct fb_info *info) +{ + struct neofb_par *par = (struct neofb_par *) info->par; + int videoRam = 896; + int maxClock = 65000; + int CursorMem = 1024; + int CursorOff = 0x100; + int linearSize = 1024; + int maxWidth = 1024; + int maxHeight = 1024; + + DBG("neo_init_hw"); + + neoUnlock(); + +#if 0 + printk(KERN_DEBUG "--- Neo extended register dump ---\n"); + for (int w = 0; w < 0x85; w++) + printk(KERN_DEBUG "CR %p: %p\n", (void *) w, + (void *) vga_rcrt(NULL, w); + for (int w = 0; w < 0xC7; w++) + printk(KERN_DEBUG "GR %p: %p\n", (void *) w, + (void *) vga_rgfx(NULL, w)); +#endif + switch (info->fix.accel) { + case FB_ACCEL_NEOMAGIC_NM2070: + videoRam = 896; + maxClock = 65000; + CursorMem = 2048; + CursorOff = 0x100; + linearSize = 1024; + maxWidth = 1024; + maxHeight = 1024; + break; + case FB_ACCEL_NEOMAGIC_NM2090: + case FB_ACCEL_NEOMAGIC_NM2093: + videoRam = 1152; + maxClock = 80000; + CursorMem = 2048; + CursorOff = 0x100; + linearSize = 2048; + maxWidth = 1024; + maxHeight = 1024; + break; + case FB_ACCEL_NEOMAGIC_NM2097: + videoRam = 1152; + maxClock = 80000; + CursorMem = 1024; + CursorOff = 0x100; + linearSize = 2048; + maxWidth = 1024; + maxHeight = 1024; + break; + case FB_ACCEL_NEOMAGIC_NM2160: + videoRam = 2048; + maxClock = 90000; + CursorMem = 1024; + CursorOff = 0x100; + linearSize = 2048; + maxWidth = 1024; + maxHeight = 1024; + break; + case FB_ACCEL_NEOMAGIC_NM2200: + videoRam = 2560; + maxClock = 110000; + CursorMem = 1024; + CursorOff = 0x1000; + linearSize = 4096; + maxWidth = 1280; + maxHeight = 1024; /* ???? */ + + par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase; + break; + case FB_ACCEL_NEOMAGIC_NM2230: + videoRam = 3008; + maxClock = 110000; + CursorMem = 1024; + CursorOff = 0x1000; + linearSize = 4096; + maxWidth = 1280; + maxHeight = 1024; /* ???? */ + + par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase; + break; + case FB_ACCEL_NEOMAGIC_NM2360: + videoRam = 4096; + maxClock = 110000; + CursorMem = 1024; + CursorOff = 0x1000; + linearSize = 4096; + maxWidth = 1280; + maxHeight = 1024; /* ???? */ + + par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase; + break; + case FB_ACCEL_NEOMAGIC_NM2380: + videoRam = 6144; + maxClock = 110000; + CursorMem = 1024; + CursorOff = 0x1000; + linearSize = 8192; + maxWidth = 1280; + maxHeight = 1024; /* ???? */ + + par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase; + break; + } +/* + info->sprite.size = CursorMem; + info->sprite.scan_align = 1; + info->sprite.buf_align = 1; + info->sprite.flags = FB_PIXMAP_IO; + info->sprite.outbuf = neofb_draw_cursor; +*/ + par->maxClock = maxClock; + par->cursorOff = CursorOff; + return ((videoRam * 1024)); +} + + +static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const struct + pci_device_id *id) +{ + struct fb_info *info; + struct neofb_par *par; + + info = framebuffer_alloc(sizeof(struct neofb_par) + sizeof(u32) * 256, &dev->dev); + + if (!info) + return NULL; + + par = info->par; + + info->fix.accel = id->driver_data; + + par->pci_burst = !nopciburst; + par->lcd_stretch = !nostretch; + par->libretto = libretto; + + par->internal_display = internal; + par->external_display = external; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + + switch (info->fix.accel) { + case FB_ACCEL_NEOMAGIC_NM2070: + sprintf(info->fix.id, "MagicGraph 128"); + break; + case FB_ACCEL_NEOMAGIC_NM2090: + sprintf(info->fix.id, "MagicGraph 128V"); + break; + case FB_ACCEL_NEOMAGIC_NM2093: + sprintf(info->fix.id, "MagicGraph 128ZV"); + break; + case FB_ACCEL_NEOMAGIC_NM2097: + sprintf(info->fix.id, "MagicGraph 128ZV+"); + break; + case FB_ACCEL_NEOMAGIC_NM2160: + sprintf(info->fix.id, "MagicGraph 128XD"); + break; + case FB_ACCEL_NEOMAGIC_NM2200: + sprintf(info->fix.id, "MagicGraph 256AV"); + info->flags |= FBINFO_HWACCEL_IMAGEBLIT | + FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_FILLRECT; + break; + case FB_ACCEL_NEOMAGIC_NM2230: + sprintf(info->fix.id, "MagicGraph 256AV+"); + info->flags |= FBINFO_HWACCEL_IMAGEBLIT | + FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_FILLRECT; + break; + case FB_ACCEL_NEOMAGIC_NM2360: + sprintf(info->fix.id, "MagicGraph 256ZX"); + info->flags |= FBINFO_HWACCEL_IMAGEBLIT | + FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_FILLRECT; + break; + case FB_ACCEL_NEOMAGIC_NM2380: + sprintf(info->fix.id, "MagicGraph 256XL+"); + info->flags |= FBINFO_HWACCEL_IMAGEBLIT | + FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_FILLRECT; + break; + } + + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + info->fix.xpanstep = 0; + info->fix.ypanstep = 4; + info->fix.ywrapstep = 0; + info->fix.accel = id->driver_data; + + info->fbops = &neofb_ops; + info->pseudo_palette = (void *) (par + 1); + return info; +} + +static void neo_free_fb_info(struct fb_info *info) +{ + if (info) { + /* + * Free the colourmap + */ + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + } +} + +/* --------------------------------------------------------------------- */ + +static int __devinit neofb_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct fb_info *info; + u_int h_sync, v_sync; + int video_len, err; + + DBG("neofb_probe"); + + err = pci_enable_device(dev); + if (err) + return err; + + err = -ENOMEM; + info = neo_alloc_fb_info(dev, id); + if (!info) + return err; + + err = neo_map_mmio(info, dev); + if (err) + goto err_map_mmio; + + err = neo_scan_monitor(info); + if (err) + goto err_scan_monitor; + + video_len = neo_init_hw(info); + if (video_len < 0) { + err = video_len; + goto err_init_hw; + } + + err = neo_map_video(info, dev, video_len); + if (err) + goto err_init_hw; + + if (!fb_find_mode(&info->var, info, mode_option, NULL, 0, + info->monspecs.modedb, 16)) { + printk(KERN_ERR "neofb: Unable to find usable video mode.\n"); + goto err_map_video; + } + + /* + * Calculate the hsync and vsync frequencies. Note that + * we split the 1e12 constant up so that we can preserve + * the precision and fit the results into 32-bit registers. + * (1953125000 * 512 = 1e12) + */ + h_sync = 1953125000 / info->var.pixclock; + h_sync = + h_sync * 512 / (info->var.xres + info->var.left_margin + + info->var.right_margin + info->var.hsync_len); + v_sync = + h_sync / (info->var.yres + info->var.upper_margin + + info->var.lower_margin + info->var.vsync_len); + + printk(KERN_INFO "neofb v" NEOFB_VERSION + ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", + info->fix.smem_len >> 10, info->var.xres, + info->var.yres, h_sync / 1000, h_sync % 1000, v_sync); + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + goto err_map_video; + + err = register_framebuffer(info); + if (err < 0) + goto err_reg_fb; + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + info->node, info->fix.id); + + /* + * Our driver data + */ + pci_set_drvdata(dev, info); + return 0; + +err_reg_fb: + fb_dealloc_cmap(&info->cmap); +err_map_video: + neo_unmap_video(info); +err_init_hw: + fb_destroy_modedb(info->monspecs.modedb); +err_scan_monitor: + neo_unmap_mmio(info); +err_map_mmio: + neo_free_fb_info(info); + return err; +} + +static void __devexit neofb_remove(struct pci_dev *dev) +{ + struct fb_info *info = pci_get_drvdata(dev); + + DBG("neofb_remove"); + + if (info) { + /* + * If unregister_framebuffer fails, then + * we will be leaving hooks that could cause + * oopsen laying around. + */ + if (unregister_framebuffer(info)) + printk(KERN_WARNING + "neofb: danger danger! Oopsen imminent!\n"); + + neo_unmap_video(info); + fb_destroy_modedb(info->monspecs.modedb); + neo_unmap_mmio(info); + neo_free_fb_info(info); + + /* + * Ensure that the driver data is no longer + * valid. + */ + pci_set_drvdata(dev, NULL); + } +} + +static struct pci_device_id neofb_devices[] = { + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070}, + + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090}, + + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093}, + + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097}, + + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160}, + + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200}, + + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230}, + + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360}, + + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380}, + + {0, 0, 0, 0, 0, 0, 0} +}; + +MODULE_DEVICE_TABLE(pci, neofb_devices); + +static struct pci_driver neofb_driver = { + .name = "neofb", + .id_table = neofb_devices, + .probe = neofb_probe, + .remove = __devexit_p(neofb_remove) +}; + +/* ************************* init in-kernel code ************************** */ + +#ifndef MODULE +static int __init neofb_setup(char *options) +{ + char *this_opt; + + DBG("neofb_setup"); + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + + if (!strncmp(this_opt, "internal", 8)) + internal = 1; + else if (!strncmp(this_opt, "external", 8)) + external = 1; + else if (!strncmp(this_opt, "nostretch", 9)) + nostretch = 1; + else if (!strncmp(this_opt, "nopciburst", 10)) + nopciburst = 1; + else if (!strncmp(this_opt, "libretto", 8)) + libretto = 1; + else + mode_option = this_opt; + } + return 0; +} +#endif /* MODULE */ + +static int __init neofb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("neofb", &option)) + return -ENODEV; + neofb_setup(option); +#endif + return pci_register_driver(&neofb_driver); +} + +module_init(neofb_init); + +#ifdef MODULE +static void __exit neofb_exit(void) +{ + pci_unregister_driver(&neofb_driver); +} + +module_exit(neofb_exit); +#endif /* MODULE */ diff --git a/drivers/video/nvidia/Makefile b/drivers/video/nvidia/Makefile new file mode 100644 index 000000000000..690d37e8de5b --- /dev/null +++ b/drivers/video/nvidia/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the nVidia framebuffer driver +# + +obj-$(CONFIG_FB_NVIDIA) += nvidiafb.o + +nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \ + nv_accel.o +nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o +nvidiafb-$(CONFIG_PPC_OF) += nv_of.o + +nvidiafb-objs := $(nvidiafb-y)
\ No newline at end of file diff --git a/drivers/video/nvidia/nv_accel.c b/drivers/video/nvidia/nv_accel.c new file mode 100644 index 000000000000..f377a29ec97a --- /dev/null +++ b/drivers/video/nvidia/nv_accel.c @@ -0,0 +1,419 @@ + /***************************************************************************\ +|* *| +|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/ + * XFree86 'nv' driver, this source code is provided under MIT-style licensing + * where the source code is provided "as is" without warranty of any kind. + * The only usage restriction is for the copyright notices to be retained + * whenever code is used. + * + * Antonino Daplas <adaplas@pol.net> 2005-03-11 + */ + +#include <linux/fb.h> +#include "nv_type.h" +#include "nv_proto.h" +#include "nv_dma.h" +#include "nv_local.h" + +/* There is a HW race condition with videoram command buffers. + You can't jump to the location of your put offset. We write put + at the jump offset + SKIPS dwords with noop padding in between + to solve this problem */ +#define SKIPS 8 + +static const int NVCopyROP[16] = { + 0xCC, /* copy */ + 0x55 /* invert */ +}; + +static const int NVCopyROP_PM[16] = { + 0xCA, /* copy */ + 0x5A, /* invert */ +}; + +static inline void NVFlush(struct nvidia_par *par) +{ + int count = 1000000000; + + while (--count && READ_GET(par) != par->dmaPut) ; + + if (!count) { + printk("nvidiafb: DMA Flush lockup\n"); + par->lockup = 1; + } +} + +static inline void NVSync(struct nvidia_par *par) +{ + int count = 1000000000; + + while (--count && NV_RD32(par->PGRAPH, 0x0700)) ; + + if (!count) { + printk("nvidiafb: DMA Sync lockup\n"); + par->lockup = 1; + } +} + +static void NVDmaKickoff(struct nvidia_par *par) +{ + if (par->dmaCurrent != par->dmaPut) { + par->dmaPut = par->dmaCurrent; + WRITE_PUT(par, par->dmaPut); + } +} + +static void NVDmaWait(struct nvidia_par *par, int size) +{ + int dmaGet; + int count = 1000000000, cnt; + size++; + + while (par->dmaFree < size && --count && !par->lockup) { + dmaGet = READ_GET(par); + + if (par->dmaPut >= dmaGet) { + par->dmaFree = par->dmaMax - par->dmaCurrent; + if (par->dmaFree < size) { + NVDmaNext(par, 0x20000000); + if (dmaGet <= SKIPS) { + if (par->dmaPut <= SKIPS) + WRITE_PUT(par, SKIPS + 1); + cnt = 1000000000; + do { + dmaGet = READ_GET(par); + } while (--cnt && dmaGet <= SKIPS); + if (!cnt) { + printk("DMA Get lockup\n"); + par->lockup = 1; + } + } + WRITE_PUT(par, SKIPS); + par->dmaCurrent = par->dmaPut = SKIPS; + par->dmaFree = dmaGet - (SKIPS + 1); + } + } else + par->dmaFree = dmaGet - par->dmaCurrent - 1; + } + + if (!count) { + printk("DMA Wait Lockup\n"); + par->lockup = 1; + } +} + +static void NVSetPattern(struct nvidia_par *par, u32 clr0, u32 clr1, + u32 pat0, u32 pat1) +{ + NVDmaStart(par, PATTERN_COLOR_0, 4); + NVDmaNext(par, clr0); + NVDmaNext(par, clr1); + NVDmaNext(par, pat0); + NVDmaNext(par, pat1); +} + +static void NVSetRopSolid(struct nvidia_par *par, u32 rop, u32 planemask) +{ + if (planemask != ~0) { + NVSetPattern(par, 0, planemask, ~0, ~0); + if (par->currentRop != (rop + 32)) { + NVDmaStart(par, ROP_SET, 1); + NVDmaNext(par, NVCopyROP_PM[rop]); + par->currentRop = rop + 32; + } + } else if (par->currentRop != rop) { + if (par->currentRop >= 16) + NVSetPattern(par, ~0, ~0, ~0, ~0); + NVDmaStart(par, ROP_SET, 1); + NVDmaNext(par, NVCopyROP[rop]); + par->currentRop = rop; + } +} + +static void NVSetClippingRectangle(struct fb_info *info, int x1, int y1, + int x2, int y2) +{ + struct nvidia_par *par = info->par; + int h = y2 - y1 + 1; + int w = x2 - x1 + 1; + + NVDmaStart(par, CLIP_POINT, 2); + NVDmaNext(par, (y1 << 16) | x1); + NVDmaNext(par, (h << 16) | w); +} + +void NVResetGraphics(struct fb_info *info) +{ + struct nvidia_par *par = info->par; + u32 surfaceFormat, patternFormat, rectFormat, lineFormat; + int pitch, i; + + pitch = info->fix.line_length; + + par->dmaBase = (u32 __iomem *) (&par->FbStart[par->FbUsableSize]); + + for (i = 0; i < SKIPS; i++) + NV_WR32(&par->dmaBase[i], 0, 0x00000000); + + NV_WR32(&par->dmaBase[0x0 + SKIPS], 0, 0x00040000); + NV_WR32(&par->dmaBase[0x1 + SKIPS], 0, 0x80000010); + NV_WR32(&par->dmaBase[0x2 + SKIPS], 0, 0x00042000); + NV_WR32(&par->dmaBase[0x3 + SKIPS], 0, 0x80000011); + NV_WR32(&par->dmaBase[0x4 + SKIPS], 0, 0x00044000); + NV_WR32(&par->dmaBase[0x5 + SKIPS], 0, 0x80000012); + NV_WR32(&par->dmaBase[0x6 + SKIPS], 0, 0x00046000); + NV_WR32(&par->dmaBase[0x7 + SKIPS], 0, 0x80000013); + NV_WR32(&par->dmaBase[0x8 + SKIPS], 0, 0x00048000); + NV_WR32(&par->dmaBase[0x9 + SKIPS], 0, 0x80000014); + NV_WR32(&par->dmaBase[0xA + SKIPS], 0, 0x0004A000); + NV_WR32(&par->dmaBase[0xB + SKIPS], 0, 0x80000015); + NV_WR32(&par->dmaBase[0xC + SKIPS], 0, 0x0004C000); + NV_WR32(&par->dmaBase[0xD + SKIPS], 0, 0x80000016); + NV_WR32(&par->dmaBase[0xE + SKIPS], 0, 0x0004E000); + NV_WR32(&par->dmaBase[0xF + SKIPS], 0, 0x80000017); + + par->dmaPut = 0; + par->dmaCurrent = 16 + SKIPS; + par->dmaMax = 8191; + par->dmaFree = par->dmaMax - par->dmaCurrent; + + switch (info->var.bits_per_pixel) { + case 32: + case 24: + surfaceFormat = SURFACE_FORMAT_DEPTH24; + patternFormat = PATTERN_FORMAT_DEPTH24; + rectFormat = RECT_FORMAT_DEPTH24; + lineFormat = LINE_FORMAT_DEPTH24; + break; + case 16: + surfaceFormat = SURFACE_FORMAT_DEPTH16; + patternFormat = PATTERN_FORMAT_DEPTH16; + rectFormat = RECT_FORMAT_DEPTH16; + lineFormat = LINE_FORMAT_DEPTH16; + break; + default: + surfaceFormat = SURFACE_FORMAT_DEPTH8; + patternFormat = PATTERN_FORMAT_DEPTH8; + rectFormat = RECT_FORMAT_DEPTH8; + lineFormat = LINE_FORMAT_DEPTH8; + break; + } + + NVDmaStart(par, SURFACE_FORMAT, 4); + NVDmaNext(par, surfaceFormat); + NVDmaNext(par, pitch | (pitch << 16)); + NVDmaNext(par, 0); + NVDmaNext(par, 0); + + NVDmaStart(par, PATTERN_FORMAT, 1); + NVDmaNext(par, patternFormat); + + NVDmaStart(par, RECT_FORMAT, 1); + NVDmaNext(par, rectFormat); + + NVDmaStart(par, LINE_FORMAT, 1); + NVDmaNext(par, lineFormat); + + par->currentRop = ~0; /* set to something invalid */ + NVSetRopSolid(par, ROP_COPY, ~0); + + NVSetClippingRectangle(info, 0, 0, info->var.xres_virtual, + info->var.yres_virtual); + + NVDmaKickoff(par); +} + +u8 byte_rev[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + +int nvidiafb_sync(struct fb_info *info) +{ + struct nvidia_par *par = info->par; + + if (!par->lockup) + NVFlush(par); + + if (!par->lockup) + NVSync(par); + + return 0; +} + +void nvidiafb_copyarea(struct fb_info *info, const struct fb_copyarea *region) +{ + struct nvidia_par *par = info->par; + + if (par->lockup) + return cfb_copyarea(info, region); + + NVDmaStart(par, BLIT_POINT_SRC, 3); + NVDmaNext(par, (region->sy << 16) | region->sx); + NVDmaNext(par, (region->dy << 16) | region->dx); + NVDmaNext(par, (region->height << 16) | region->width); + + NVDmaKickoff(par); +} + +void nvidiafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct nvidia_par *par = info->par; + u32 color; + + if (par->lockup) + return cfb_fillrect(info, rect); + + if (info->var.bits_per_pixel == 8) + color = rect->color; + else + color = ((u32 *) info->pseudo_palette)[rect->color]; + + if (rect->rop != ROP_COPY) + NVSetRopSolid(par, rect->rop, ~0); + + NVDmaStart(par, RECT_SOLID_COLOR, 1); + NVDmaNext(par, color); + + NVDmaStart(par, RECT_SOLID_RECTS(0), 2); + NVDmaNext(par, (rect->dx << 16) | rect->dy); + NVDmaNext(par, (rect->width << 16) | rect->height); + + NVDmaKickoff(par); + + if (rect->rop != ROP_COPY) + NVSetRopSolid(par, ROP_COPY, ~0); +} + +static void nvidiafb_mono_color_expand(struct fb_info *info, + const struct fb_image *image) +{ + struct nvidia_par *par = info->par; + u32 fg, bg, mask = ~(~0 >> (32 - info->var.bits_per_pixel)); + u32 dsize, width, *data = (u32 *) image->data, tmp; + int j, k = 0; + + width = (image->width + 31) & ~31; + dsize = (width * image->height) >> 5; + + if (info->var.bits_per_pixel == 8) { + fg = image->fg_color | mask; + bg = image->bg_color | mask; + } else { + fg = ((u32 *) info->pseudo_palette)[image->fg_color] | mask; + bg = ((u32 *) info->pseudo_palette)[image->bg_color] | mask; + } + + NVDmaStart(par, RECT_EXPAND_TWO_COLOR_CLIP, 7); + NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff)); + NVDmaNext(par, ((image->dy + image->height) << 16) | + ((image->dx + image->width) & 0xffff)); + NVDmaNext(par, bg); + NVDmaNext(par, fg); + NVDmaNext(par, (image->height << 16) | width); + NVDmaNext(par, (image->height << 16) | width); + NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff)); + + while (dsize >= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS) { + NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0), + RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS); + + for (j = RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS; j--;) { + tmp = data[k++]; + reverse_order(&tmp); + NVDmaNext(par, tmp); + } + + dsize -= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS; + } + + if (dsize) { + NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0), dsize); + + for (j = dsize; j--;) { + tmp = data[k++]; + reverse_order(&tmp); + NVDmaNext(par, tmp); + } + } + + NVDmaKickoff(par); +} + +void nvidiafb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct nvidia_par *par = info->par; + + if (image->depth == 1 && !par->lockup) + nvidiafb_mono_color_expand(info, image); + else + cfb_imageblit(info, image); +} diff --git a/drivers/video/nvidia/nv_dma.h b/drivers/video/nvidia/nv_dma.h new file mode 100644 index 000000000000..a7ed1c0acbbb --- /dev/null +++ b/drivers/video/nvidia/nv_dma.h @@ -0,0 +1,188 @@ + + /***************************************************************************\ +|* *| +|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/ + * XFree86 'nv' driver, this source code is provided under MIT-style licensing + * where the source code is provided "as is" without warranty of any kind. + * The only usage restriction is for the copyright notices to be retained + * whenever code is used. + * + * Antonino Daplas <adaplas@pol.net> 2005-03-11 + */ + +#define SURFACE_FORMAT 0x00000300 +#define SURFACE_FORMAT_DEPTH8 0x00000001 +#define SURFACE_FORMAT_DEPTH15 0x00000002 +#define SURFACE_FORMAT_DEPTH16 0x00000004 +#define SURFACE_FORMAT_DEPTH24 0x00000006 +#define SURFACE_PITCH 0x00000304 +#define SURFACE_PITCH_SRC 15:0 +#define SURFACE_PITCH_DST 31:16 +#define SURFACE_OFFSET_SRC 0x00000308 +#define SURFACE_OFFSET_DST 0x0000030C + +#define ROP_SET 0x00002300 + +#define PATTERN_FORMAT 0x00004300 +#define PATTERN_FORMAT_DEPTH8 0x00000003 +#define PATTERN_FORMAT_DEPTH16 0x00000001 +#define PATTERN_FORMAT_DEPTH24 0x00000003 +#define PATTERN_COLOR_0 0x00004310 +#define PATTERN_COLOR_1 0x00004314 +#define PATTERN_PATTERN_0 0x00004318 +#define PATTERN_PATTERN_1 0x0000431C + +#define CLIP_POINT 0x00006300 +#define CLIP_POINT_X 15:0 +#define CLIP_POINT_Y 31:16 +#define CLIP_SIZE 0x00006304 +#define CLIP_SIZE_WIDTH 15:0 +#define CLIP_SIZE_HEIGHT 31:16 + +#define LINE_FORMAT 0x00008300 +#define LINE_FORMAT_DEPTH8 0x00000003 +#define LINE_FORMAT_DEPTH16 0x00000001 +#define LINE_FORMAT_DEPTH24 0x00000003 +#define LINE_COLOR 0x00008304 +#define LINE_MAX_LINES 16 +#define LINE_LINES(i) 0x00008400\ + +(i)*8 +#define LINE_LINES_POINT0_X 15:0 +#define LINE_LINES_POINT0_Y 31:16 +#define LINE_LINES_POINT1_X 47:32 +#define LINE_LINES_POINT1_Y 63:48 + +#define BLIT_POINT_SRC 0x0000A300 +#define BLIT_POINT_SRC_X 15:0 +#define BLIT_POINT_SRC_Y 31:16 +#define BLIT_POINT_DST 0x0000A304 +#define BLIT_POINT_DST_X 15:0 +#define BLIT_POINT_DST_Y 31:16 +#define BLIT_SIZE 0x0000A308 +#define BLIT_SIZE_WIDTH 15:0 +#define BLIT_SIZE_HEIGHT 31:16 + +#define RECT_FORMAT 0x0000C300 +#define RECT_FORMAT_DEPTH8 0x00000003 +#define RECT_FORMAT_DEPTH16 0x00000001 +#define RECT_FORMAT_DEPTH24 0x00000003 +#define RECT_SOLID_COLOR 0x0000C3FC +#define RECT_SOLID_RECTS_MAX_RECTS 32 +#define RECT_SOLID_RECTS(i) 0x0000C400\ + +(i)*8 +#define RECT_SOLID_RECTS_Y 15:0 +#define RECT_SOLID_RECTS_X 31:16 +#define RECT_SOLID_RECTS_HEIGHT 47:32 +#define RECT_SOLID_RECTS_WIDTH 63:48 + +#define RECT_EXPAND_ONE_COLOR_CLIP 0x0000C7EC +#define RECT_EXPAND_ONE_COLOR_CLIP_POINT0_X 15:0 +#define RECT_EXPAND_ONE_COLOR_CLIP_POINT0_Y 31:16 +#define RECT_EXPAND_ONE_COLOR_CLIP_POINT1_X 47:32 +#define RECT_EXPAND_ONE_COLOR_CLIP_POINT1_Y 63:48 +#define RECT_EXPAND_ONE_COLOR_COLOR 0x0000C7F4 +#define RECT_EXPAND_ONE_COLOR_SIZE 0x0000C7F8 +#define RECT_EXPAND_ONE_COLOR_SIZE_WIDTH 15:0 +#define RECT_EXPAND_ONE_COLOR_SIZE_HEIGHT 31:16 +#define RECT_EXPAND_ONE_COLOR_POINT 0x0000C7FC +#define RECT_EXPAND_ONE_COLOR_POINT_X 15:0 +#define RECT_EXPAND_ONE_COLOR_POINT_Y 31:16 +#define RECT_EXPAND_ONE_COLOR_DATA_MAX_DWORDS 128 +#define RECT_EXPAND_ONE_COLOR_DATA(i) 0x0000C800\ + +(i)*4 + +#define RECT_EXPAND_TWO_COLOR_CLIP 0x0000CBE4 +#define RECT_EXPAND_TWO_COLOR_CLIP_POINT0_X 15:0 +#define RECT_EXPAND_TWO_COLOR_CLIP_POINT0_Y 31:16 +#define RECT_EXPAND_TWO_COLOR_CLIP_POINT1_X 47:32 +#define RECT_EXPAND_TWO_COLOR_CLIP_POINT1_Y 63:48 +#define RECT_EXPAND_TWO_COLOR_COLOR_0 0x0000CBEC +#define RECT_EXPAND_TWO_COLOR_COLOR_1 0x0000CBF0 +#define RECT_EXPAND_TWO_COLOR_SIZE_IN 0x0000CBF4 +#define RECT_EXPAND_TWO_COLOR_SIZE_IN_WIDTH 15:0 +#define RECT_EXPAND_TWO_COLOR_SIZE_IN_HEIGHT 31:16 +#define RECT_EXPAND_TWO_COLOR_SIZE_OUT 0x0000CBF8 +#define RECT_EXPAND_TWO_COLOR_SIZE_OUT_WIDTH 15:0 +#define RECT_EXPAND_TWO_COLOR_SIZE_OUT_HEIGHT 31:16 +#define RECT_EXPAND_TWO_COLOR_POINT 0x0000CBFC +#define RECT_EXPAND_TWO_COLOR_POINT_X 15:0 +#define RECT_EXPAND_TWO_COLOR_POINT_Y 31:16 +#define RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS 128 +#define RECT_EXPAND_TWO_COLOR_DATA(i) 0x0000CC00\ + +(i)*4 + +#define STRETCH_BLIT_FORMAT 0x0000E300 +#define STRETCH_BLIT_FORMAT_DEPTH8 0x00000004 +#define STRETCH_BLIT_FORMAT_DEPTH16 0x00000007 +#define STRETCH_BLIT_FORMAT_DEPTH24 0x00000004 +#define STRETCH_BLIT_FORMAT_X8R8G8B8 0x00000004 +#define STRETCH_BLIT_FORMAT_YUYV 0x00000005 +#define STRETCH_BLIT_FORMAT_UYVY 0x00000006 +#define STRETCH_BLIT_CLIP_POINT 0x0000E308 +#define STRETCH_BLIT_CLIP_POINT_X 15:0 +#define STRETCH_BLIT_CLIP_POINT_Y 31:16 +#define STRETCH_BLIT_CLIP_POINT 0x0000E308 +#define STRETCH_BLIT_CLIP_SIZE 0x0000E30C +#define STRETCH_BLIT_CLIP_SIZE_WIDTH 15:0 +#define STRETCH_BLIT_CLIP_SIZE_HEIGHT 31:16 +#define STRETCH_BLIT_DST_POINT 0x0000E310 +#define STRETCH_BLIT_DST_POINT_X 15:0 +#define STRETCH_BLIT_DST_POINT_Y 31:16 +#define STRETCH_BLIT_DST_SIZE 0x0000E314 +#define STRETCH_BLIT_DST_SIZE_WIDTH 15:0 +#define STRETCH_BLIT_DST_SIZE_HEIGHT 31:16 +#define STRETCH_BLIT_DU_DX 0x0000E318 +#define STRETCH_BLIT_DV_DY 0x0000E31C +#define STRETCH_BLIT_SRC_SIZE 0x0000E400 +#define STRETCH_BLIT_SRC_SIZE_WIDTH 15:0 +#define STRETCH_BLIT_SRC_SIZE_HEIGHT 31:16 +#define STRETCH_BLIT_SRC_FORMAT 0x0000E404 +#define STRETCH_BLIT_SRC_FORMAT_PITCH 15:0 +#define STRETCH_BLIT_SRC_FORMAT_ORIGIN 23:16 +#define STRETCH_BLIT_SRC_FORMAT_ORIGIN_CENTER 0x00000001 +#define STRETCH_BLIT_SRC_FORMAT_ORIGIN_CORNER 0x00000002 +#define STRETCH_BLIT_SRC_FORMAT_FILTER 31:24 +#define STRETCH_BLIT_SRC_FORMAT_FILTER_POINT_SAMPLE 0x00000000 +#define STRETCH_BLIT_SRC_FORMAT_FILTER_BILINEAR 0x00000001 +#define STRETCH_BLIT_SRC_OFFSET 0x0000E408 +#define STRETCH_BLIT_SRC_POINT 0x0000E40C +#define STRETCH_BLIT_SRC_POINT_U 15:0 +#define STRETCH_BLIT_SRC_POINT_V 31:16 diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c new file mode 100644 index 000000000000..b989358437b3 --- /dev/null +++ b/drivers/video/nvidia/nv_hw.c @@ -0,0 +1,1593 @@ + /***************************************************************************\ +|* *| +|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/ + * XFree86 'nv' driver, this source code is provided under MIT-style licensing + * where the source code is provided "as is" without warranty of any kind. + * The only usage restriction is for the copyright notices to be retained + * whenever code is used. + * + * Antonino Daplas <adaplas@pol.net> 2005-03-11 + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_hw.c,v 1.4 2003/11/03 05:11:25 tsi Exp $ */ + +#include <linux/pci.h> +#include "nv_type.h" +#include "nv_local.h" + +void NVLockUnlock(struct nvidia_par *par, int Lock) +{ + u8 cr11; + + VGA_WR08(par->PCIO, 0x3D4, 0x1F); + VGA_WR08(par->PCIO, 0x3D5, Lock ? 0x99 : 0x57); + + VGA_WR08(par->PCIO, 0x3D4, 0x11); + cr11 = VGA_RD08(par->PCIO, 0x3D5); + if (Lock) + cr11 |= 0x80; + else + cr11 &= ~0x80; + VGA_WR08(par->PCIO, 0x3D5, cr11); +} + +int NVShowHideCursor(struct nvidia_par *par, int ShowHide) +{ + int cur = par->CurrentState->cursor1; + + par->CurrentState->cursor1 = (par->CurrentState->cursor1 & 0xFE) | + (ShowHide & 0x01); + VGA_WR08(par->PCIO, 0x3D4, 0x31); + VGA_WR08(par->PCIO, 0x3D5, par->CurrentState->cursor1); + + if (par->Architecture == NV_ARCH_40) + NV_WR32(par->PRAMDAC, 0x0300, NV_RD32(par->PRAMDAC, 0x0300)); + + return (cur & 0x01); +} + +/****************************************************************************\ +* * +* The video arbitration routines calculate some "magic" numbers. Fixes * +* the snow seen when accessing the framebuffer without it. * +* It just works (I hope). * +* * +\****************************************************************************/ + +typedef struct { + int graphics_lwm; + int video_lwm; + int graphics_burst_size; + int video_burst_size; + int valid; +} nv4_fifo_info; + +typedef struct { + int pclk_khz; + int mclk_khz; + int nvclk_khz; + char mem_page_miss; + char mem_latency; + int memory_width; + char enable_video; + char gr_during_vid; + char pix_bpp; + char mem_aligned; + char enable_mp; +} nv4_sim_state; + +typedef struct { + int graphics_lwm; + int video_lwm; + int graphics_burst_size; + int video_burst_size; + int valid; +} nv10_fifo_info; + +typedef struct { + int pclk_khz; + int mclk_khz; + int nvclk_khz; + char mem_page_miss; + char mem_latency; + int memory_type; + int memory_width; + char enable_video; + char gr_during_vid; + char pix_bpp; + char mem_aligned; + char enable_mp; +} nv10_sim_state; + +static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk, + unsigned int *NVClk) +{ + unsigned int pll, N, M, MB, NB, P; + + if (par->Architecture >= NV_ARCH_40) { + pll = NV_RD32(par->PMC, 0x4020); + P = (pll >> 16) & 0x03; + pll = NV_RD32(par->PMC, 0x4024); + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + MB = (pll >> 16) & 0xFF; + NB = (pll >> 24) & 0xFF; + *MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; + + pll = NV_RD32(par->PMC, 0x4000); + P = (pll >> 16) & 0x03; + pll = NV_RD32(par->PMC, 0x4004); + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + MB = (pll >> 16) & 0xFF; + NB = (pll >> 24) & 0xFF; + + *NVClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; + } else if (par->twoStagePLL) { + pll = NV_RD32(par->PRAMDAC0, 0x0504); + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + pll = NV_RD32(par->PRAMDAC0, 0x0574); + if (pll & 0x80000000) { + MB = pll & 0xFF; + NB = (pll >> 8) & 0xFF; + } else { + MB = 1; + NB = 1; + } + *MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; + + pll = NV_RD32(par->PRAMDAC0, 0x0500); + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + pll = NV_RD32(par->PRAMDAC0, 0x0570); + if (pll & 0x80000000) { + MB = pll & 0xFF; + NB = (pll >> 8) & 0xFF; + } else { + MB = 1; + NB = 1; + } + *NVClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; + } else + if (((par->Chipset & 0x0ff0) == 0x0300) || + ((par->Chipset & 0x0ff0) == 0x0330)) { + pll = NV_RD32(par->PRAMDAC0, 0x0504); + M = pll & 0x0F; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x07; + if (pll & 0x00000080) { + MB = (pll >> 4) & 0x07; + NB = (pll >> 19) & 0x1f; + } else { + MB = 1; + NB = 1; + } + *MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; + + pll = NV_RD32(par->PRAMDAC0, 0x0500); + M = pll & 0x0F; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x07; + if (pll & 0x00000080) { + MB = (pll >> 4) & 0x07; + NB = (pll >> 19) & 0x1f; + } else { + MB = 1; + NB = 1; + } + *NVClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; + } else { + pll = NV_RD32(par->PRAMDAC0, 0x0504); + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + *MClk = (N * par->CrystalFreqKHz / M) >> P; + + pll = NV_RD32(par->PRAMDAC0, 0x0500); + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + *NVClk = (N * par->CrystalFreqKHz / M) >> P; + } +} + +static void nv4CalcArbitration(nv4_fifo_info * fifo, nv4_sim_state * arb) +{ + int data, pagemiss, cas, width, video_enable, bpp; + int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs; + int found, mclk_extra, mclk_loop, cbs, m1, p1; + int mclk_freq, pclk_freq, nvclk_freq, mp_enable; + int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate; + int vpm_us, us_video, vlwm, video_fill_us, cpm_us, us_crt, clwm; + + fifo->valid = 1; + pclk_freq = arb->pclk_khz; + mclk_freq = arb->mclk_khz; + nvclk_freq = arb->nvclk_khz; + pagemiss = arb->mem_page_miss; + cas = arb->mem_latency; + width = arb->memory_width >> 6; + video_enable = arb->enable_video; + bpp = arb->pix_bpp; + mp_enable = arb->enable_mp; + clwm = 0; + vlwm = 0; + cbs = 128; + pclks = 2; + nvclks = 2; + nvclks += 2; + nvclks += 1; + mclks = 5; + mclks += 3; + mclks += 1; + mclks += cas; + mclks += 1; + mclks += 1; + mclks += 1; + mclks += 1; + mclk_extra = 3; + nvclks += 2; + nvclks += 1; + nvclks += 1; + nvclks += 1; + if (mp_enable) + mclks += 4; + nvclks += 0; + pclks += 0; + found = 0; + vbs = 0; + while (found != 1) { + fifo->valid = 1; + found = 1; + mclk_loop = mclks + mclk_extra; + us_m = mclk_loop * 1000 * 1000 / mclk_freq; + us_n = nvclks * 1000 * 1000 / nvclk_freq; + us_p = nvclks * 1000 * 1000 / pclk_freq; + if (video_enable) { + video_drain_rate = pclk_freq * 2; + crtc_drain_rate = pclk_freq * bpp / 8; + vpagemiss = 2; + vpagemiss += 1; + crtpagemiss = 2; + vpm_us = + (vpagemiss * pagemiss) * 1000 * 1000 / mclk_freq; + if (nvclk_freq * 2 > mclk_freq * width) + video_fill_us = + cbs * 1000 * 1000 / 16 / nvclk_freq; + else + video_fill_us = + cbs * 1000 * 1000 / (8 * width) / + mclk_freq; + us_video = vpm_us + us_m + us_n + us_p + video_fill_us; + vlwm = us_video * video_drain_rate / (1000 * 1000); + vlwm++; + vbs = 128; + if (vlwm > 128) + vbs = 64; + if (vlwm > (256 - 64)) + vbs = 32; + if (nvclk_freq * 2 > mclk_freq * width) + video_fill_us = + vbs * 1000 * 1000 / 16 / nvclk_freq; + else + video_fill_us = + vbs * 1000 * 1000 / (8 * width) / + mclk_freq; + cpm_us = + crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq; + us_crt = + us_video + video_fill_us + cpm_us + us_m + us_n + + us_p; + clwm = us_crt * crtc_drain_rate / (1000 * 1000); + clwm++; + } else { + crtc_drain_rate = pclk_freq * bpp / 8; + crtpagemiss = 2; + crtpagemiss += 1; + cpm_us = + crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq; + us_crt = cpm_us + us_m + us_n + us_p; + clwm = us_crt * crtc_drain_rate / (1000 * 1000); + clwm++; + } + m1 = clwm + cbs - 512; + p1 = m1 * pclk_freq / mclk_freq; + p1 = p1 * bpp / 8; + if ((p1 < m1) && (m1 > 0)) { + fifo->valid = 0; + found = 0; + if (mclk_extra == 0) + found = 1; + mclk_extra--; + } else if (video_enable) { + if ((clwm > 511) || (vlwm > 255)) { + fifo->valid = 0; + found = 0; + if (mclk_extra == 0) + found = 1; + mclk_extra--; + } + } else { + if (clwm > 519) { + fifo->valid = 0; + found = 0; + if (mclk_extra == 0) + found = 1; + mclk_extra--; + } + } + if (clwm < 384) + clwm = 384; + if (vlwm < 128) + vlwm = 128; + data = (int)(clwm); + fifo->graphics_lwm = data; + fifo->graphics_burst_size = 128; + data = (int)((vlwm + 15)); + fifo->video_lwm = data; + fifo->video_burst_size = vbs; + } +} + +static void nv4UpdateArbitrationSettings(unsigned VClk, + unsigned pixelDepth, + unsigned *burst, + unsigned *lwm, struct nvidia_par *par) +{ + nv4_fifo_info fifo_data; + nv4_sim_state sim_data; + unsigned int MClk, NVClk, cfg1; + + nvGetClocks(par, &MClk, &NVClk); + + cfg1 = NV_RD32(par->PFB, 0x00000204); + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 0; + sim_data.enable_mp = 0; + sim_data.memory_width = (NV_RD32(par->PEXTDEV, 0x0000) & 0x10) ? + 128 : 64; + sim_data.mem_latency = (char)cfg1 & 0x0F; + sim_data.mem_aligned = 1; + sim_data.mem_page_miss = + (char)(((cfg1 >> 4) & 0x0F) + ((cfg1 >> 31) & 0x01)); + sim_data.gr_during_vid = 0; + sim_data.pclk_khz = VClk; + sim_data.mclk_khz = MClk; + sim_data.nvclk_khz = NVClk; + nv4CalcArbitration(&fifo_data, &sim_data); + if (fifo_data.valid) { + int b = fifo_data.graphics_burst_size >> 4; + *burst = 0; + while (b >>= 1) + (*burst)++; + *lwm = fifo_data.graphics_lwm >> 3; + } +} + +static void nv10CalcArbitration(nv10_fifo_info * fifo, nv10_sim_state * arb) +{ + int data, pagemiss, width, video_enable, bpp; + int nvclks, mclks, pclks, vpagemiss, crtpagemiss; + int nvclk_fill; + int found, mclk_extra, mclk_loop, cbs, m1; + int mclk_freq, pclk_freq, nvclk_freq, mp_enable; + int us_m, us_m_min, us_n, us_p, crtc_drain_rate; + int vus_m; + int vpm_us, us_video, cpm_us, us_crt, clwm; + int clwm_rnd_down; + int m2us, us_pipe_min, p1clk, p2; + int min_mclk_extra; + int us_min_mclk_extra; + + fifo->valid = 1; + pclk_freq = arb->pclk_khz; /* freq in KHz */ + mclk_freq = arb->mclk_khz; + nvclk_freq = arb->nvclk_khz; + pagemiss = arb->mem_page_miss; + width = arb->memory_width / 64; + video_enable = arb->enable_video; + bpp = arb->pix_bpp; + mp_enable = arb->enable_mp; + clwm = 0; + + cbs = 512; + + pclks = 4; /* lwm detect. */ + + nvclks = 3; /* lwm -> sync. */ + nvclks += 2; /* fbi bus cycles (1 req + 1 busy) */ + /* 2 edge sync. may be very close to edge so just put one. */ + mclks = 1; + mclks += 1; /* arb_hp_req */ + mclks += 5; /* ap_hp_req tiling pipeline */ + + mclks += 2; /* tc_req latency fifo */ + mclks += 2; /* fb_cas_n_ memory request to fbio block */ + mclks += 7; /* sm_d_rdv data returned from fbio block */ + + /* fb.rd.d.Put_gc need to accumulate 256 bits for read */ + if (arb->memory_type == 0) + if (arb->memory_width == 64) /* 64 bit bus */ + mclks += 4; + else + mclks += 2; + else if (arb->memory_width == 64) /* 64 bit bus */ + mclks += 2; + else + mclks += 1; + + if ((!video_enable) && (arb->memory_width == 128)) { + mclk_extra = (bpp == 32) ? 31 : 42; /* Margin of error */ + min_mclk_extra = 17; + } else { + mclk_extra = (bpp == 32) ? 8 : 4; /* Margin of error */ + /* mclk_extra = 4; *//* Margin of error */ + min_mclk_extra = 18; + } + + /* 2 edge sync. may be very close to edge so just put one. */ + nvclks += 1; + nvclks += 1; /* fbi_d_rdv_n */ + nvclks += 1; /* Fbi_d_rdata */ + nvclks += 1; /* crtfifo load */ + + if (mp_enable) + mclks += 4; /* Mp can get in with a burst of 8. */ + /* Extra clocks determined by heuristics */ + + nvclks += 0; + pclks += 0; + found = 0; + while (found != 1) { + fifo->valid = 1; + found = 1; + mclk_loop = mclks + mclk_extra; + /* Mclk latency in us */ + us_m = mclk_loop * 1000 * 1000 / mclk_freq; + /* Minimum Mclk latency in us */ + us_m_min = mclks * 1000 * 1000 / mclk_freq; + us_min_mclk_extra = min_mclk_extra * 1000 * 1000 / mclk_freq; + /* nvclk latency in us */ + us_n = nvclks * 1000 * 1000 / nvclk_freq; + /* nvclk latency in us */ + us_p = pclks * 1000 * 1000 / pclk_freq; + us_pipe_min = us_m_min + us_n + us_p; + + /* Mclk latency in us */ + vus_m = mclk_loop * 1000 * 1000 / mclk_freq; + + if (video_enable) { + crtc_drain_rate = pclk_freq * bpp / 8; /* MB/s */ + + vpagemiss = 1; /* self generating page miss */ + vpagemiss += 1; /* One higher priority before */ + + crtpagemiss = 2; /* self generating page miss */ + if (mp_enable) + crtpagemiss += 1; /* if MA0 conflict */ + + vpm_us = + (vpagemiss * pagemiss) * 1000 * 1000 / mclk_freq; + + /* Video has separate read return path */ + us_video = vpm_us + vus_m; + + cpm_us = + crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq; + /* Wait for video */ + us_crt = us_video + + cpm_us /* CRT Page miss */ + + us_m + us_n + us_p /* other latency */ + ; + + clwm = us_crt * crtc_drain_rate / (1000 * 1000); + /* fixed point <= float_point - 1. Fixes that */ + clwm++; + } else { + /* bpp * pclk/8 */ + crtc_drain_rate = pclk_freq * bpp / 8; + + crtpagemiss = 1; /* self generating page miss */ + crtpagemiss += 1; /* MA0 page miss */ + if (mp_enable) + crtpagemiss += 1; /* if MA0 conflict */ + cpm_us = + crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq; + us_crt = cpm_us + us_m + us_n + us_p; + clwm = us_crt * crtc_drain_rate / (1000 * 1000); + /* fixed point <= float_point - 1. Fixes that */ + clwm++; + + /* Finally, a heuristic check when width == 64 bits */ + if (width == 1) { + nvclk_fill = nvclk_freq * 8; + if (crtc_drain_rate * 100 >= nvclk_fill * 102) + /*Large number to fail */ + clwm = 0xfff; + + else if (crtc_drain_rate * 100 >= + nvclk_fill * 98) { + clwm = 1024; + cbs = 512; + } + } + } + + /* + Overfill check: + */ + + clwm_rnd_down = ((int)clwm / 8) * 8; + if (clwm_rnd_down < clwm) + clwm += 8; + + m1 = clwm + cbs - 1024; /* Amount of overfill */ + m2us = us_pipe_min + us_min_mclk_extra; + + /* pclk cycles to drain */ + p1clk = m2us * pclk_freq / (1000 * 1000); + p2 = p1clk * bpp / 8; /* bytes drained. */ + + if ((p2 < m1) && (m1 > 0)) { + fifo->valid = 0; + found = 0; + if (min_mclk_extra == 0) { + if (cbs <= 32) { + /* Can't adjust anymore! */ + found = 1; + } else { + /* reduce the burst size */ + cbs = cbs / 2; + } + } else { + min_mclk_extra--; + } + } else { + if (clwm > 1023) { /* Have some margin */ + fifo->valid = 0; + found = 0; + if (min_mclk_extra == 0) + /* Can't adjust anymore! */ + found = 1; + else + min_mclk_extra--; + } + } + + if (clwm < (1024 - cbs + 8)) + clwm = 1024 - cbs + 8; + data = (int)(clwm); + /* printf("CRT LWM: %f bytes, prog: 0x%x, bs: 256\n", + clwm, data ); */ + fifo->graphics_lwm = data; + fifo->graphics_burst_size = cbs; + + fifo->video_lwm = 1024; + fifo->video_burst_size = 512; + } +} + +static void nv10UpdateArbitrationSettings(unsigned VClk, + unsigned pixelDepth, + unsigned *burst, + unsigned *lwm, + struct nvidia_par *par) +{ + nv10_fifo_info fifo_data; + nv10_sim_state sim_data; + unsigned int MClk, NVClk, cfg1; + + nvGetClocks(par, &MClk, &NVClk); + + cfg1 = NV_RD32(par->PFB, 0x0204); + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 1; + sim_data.enable_mp = 0; + sim_data.memory_type = (NV_RD32(par->PFB, 0x0200) & 0x01) ? 1 : 0; + sim_data.memory_width = (NV_RD32(par->PEXTDEV, 0x0000) & 0x10) ? + 128 : 64; + sim_data.mem_latency = (char)cfg1 & 0x0F; + sim_data.mem_aligned = 1; + sim_data.mem_page_miss = + (char)(((cfg1 >> 4) & 0x0F) + ((cfg1 >> 31) & 0x01)); + sim_data.gr_during_vid = 0; + sim_data.pclk_khz = VClk; + sim_data.mclk_khz = MClk; + sim_data.nvclk_khz = NVClk; + nv10CalcArbitration(&fifo_data, &sim_data); + if (fifo_data.valid) { + int b = fifo_data.graphics_burst_size >> 4; + *burst = 0; + while (b >>= 1) + (*burst)++; + *lwm = fifo_data.graphics_lwm >> 3; + } +} + +static void nv30UpdateArbitrationSettings ( + struct nvidia_par *par, + unsigned int *burst, + unsigned int *lwm +) +{ + unsigned int MClk, NVClk; + unsigned int fifo_size, burst_size, graphics_lwm; + + fifo_size = 2048; + burst_size = 512; + graphics_lwm = fifo_size - burst_size; + + nvGetClocks(par, &MClk, &NVClk); + + *burst = 0; + burst_size >>= 5; + while(burst_size >>= 1) (*burst)++; + *lwm = graphics_lwm >> 3; +} + +static void nForceUpdateArbitrationSettings(unsigned VClk, + unsigned pixelDepth, + unsigned *burst, + unsigned *lwm, + struct nvidia_par *par) +{ + nv10_fifo_info fifo_data; + nv10_sim_state sim_data; + unsigned int M, N, P, pll, MClk, NVClk, memctrl; + struct pci_dev *dev; + + if ((par->Chipset & 0x0FF0) == 0x01A0) { + unsigned int uMClkPostDiv; + dev = pci_find_slot(0, 3); + pci_read_config_dword(dev, 0x6C, &uMClkPostDiv); + uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf; + + if (!uMClkPostDiv) + uMClkPostDiv = 4; + MClk = 400000 / uMClkPostDiv; + } else { + dev = pci_find_slot(0, 5); + pci_read_config_dword(dev, 0x4c, &MClk); + MClk /= 1000; + } + + pll = NV_RD32(par->PRAMDAC0, 0x0500); + M = (pll >> 0) & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + NVClk = (N * par->CrystalFreqKHz / M) >> P; + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 0; + sim_data.enable_mp = 0; + pci_find_slot(0, 1); + pci_read_config_dword(dev, 0x7C, &sim_data.memory_type); + sim_data.memory_type = (sim_data.memory_type >> 12) & 1; + sim_data.memory_width = 64; + + dev = pci_find_slot(0, 3); + pci_read_config_dword(dev, 0, &memctrl); + memctrl >>= 16; + + if ((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) { + int dimm[3]; + + pci_find_slot(0, 2); + pci_read_config_dword(dev, 0x40, &dimm[0]); + dimm[0] = (dimm[0] >> 8) & 0x4f; + pci_read_config_dword(dev, 0x44, &dimm[1]); + dimm[1] = (dimm[1] >> 8) & 0x4f; + pci_read_config_dword(dev, 0x48, &dimm[2]); + dimm[2] = (dimm[2] >> 8) & 0x4f; + + if ((dimm[0] + dimm[1]) != dimm[2]) { + printk("nvidiafb: your nForce DIMMs are not arranged " + "in optimal banks!\n"); + } + } + + sim_data.mem_latency = 3; + sim_data.mem_aligned = 1; + sim_data.mem_page_miss = 10; + sim_data.gr_during_vid = 0; + sim_data.pclk_khz = VClk; + sim_data.mclk_khz = MClk; + sim_data.nvclk_khz = NVClk; + nv10CalcArbitration(&fifo_data, &sim_data); + if (fifo_data.valid) { + int b = fifo_data.graphics_burst_size >> 4; + *burst = 0; + while (b >>= 1) + (*burst)++; + *lwm = fifo_data.graphics_lwm >> 3; + } +} + +/****************************************************************************\ +* * +* RIVA Mode State Routines * +* * +\****************************************************************************/ + +/* + * Calculate the Video Clock parameters for the PLL. + */ +static void CalcVClock(int clockIn, + int *clockOut, u32 * pllOut, struct nvidia_par *par) +{ + unsigned lowM, highM; + unsigned DeltaNew, DeltaOld; + unsigned VClk, Freq; + unsigned M, N, P; + + DeltaOld = 0xFFFFFFFF; + + VClk = (unsigned)clockIn; + + if (par->CrystalFreqKHz == 13500) { + lowM = 7; + highM = 13; + } else { + lowM = 8; + highM = 14; + } + + for (P = 0; P <= 4; P++) { + Freq = VClk << P; + if ((Freq >= 128000) && (Freq <= 350000)) { + for (M = lowM; M <= highM; M++) { + N = ((VClk << P) * M) / par->CrystalFreqKHz; + if (N <= 255) { + Freq = + ((par->CrystalFreqKHz * N) / + M) >> P; + if (Freq > VClk) + DeltaNew = Freq - VClk; + else + DeltaNew = VClk - Freq; + if (DeltaNew < DeltaOld) { + *pllOut = + (P << 16) | (N << 8) | M; + *clockOut = Freq; + DeltaOld = DeltaNew; + } + } + } + } + } +} + +static void CalcVClock2Stage(int clockIn, + int *clockOut, + u32 * pllOut, + u32 * pllBOut, struct nvidia_par *par) +{ + unsigned DeltaNew, DeltaOld; + unsigned VClk, Freq; + unsigned M, N, P; + + DeltaOld = 0xFFFFFFFF; + + *pllBOut = 0x80000401; /* fixed at x4 for now */ + + VClk = (unsigned)clockIn; + + for (P = 0; P <= 6; P++) { + Freq = VClk << P; + if ((Freq >= 400000) && (Freq <= 1000000)) { + for (M = 1; M <= 13; M++) { + N = ((VClk << P) * M) / + (par->CrystalFreqKHz << 2); + if ((N >= 5) && (N <= 255)) { + Freq = + (((par->CrystalFreqKHz << 2) * N) / + M) >> P; + if (Freq > VClk) + DeltaNew = Freq - VClk; + else + DeltaNew = VClk - Freq; + if (DeltaNew < DeltaOld) { + *pllOut = + (P << 16) | (N << 8) | M; + *clockOut = Freq; + DeltaOld = DeltaNew; + } + } + } + } + } +} + +/* + * Calculate extended mode parameters (SVGA) and save in a + * mode state structure. + */ +void NVCalcStateExt(struct nvidia_par *par, + RIVA_HW_STATE * state, + int bpp, + int width, + int hDisplaySize, int height, int dotClock, int flags) +{ + int pixelDepth, VClk; + /* + * Save mode parameters. + */ + state->bpp = bpp; /* this is not bitsPerPixel, it's 8,15,16,32 */ + state->width = width; + state->height = height; + /* + * Extended RIVA registers. + */ + pixelDepth = (bpp + 1) / 8; + if (par->twoStagePLL) + CalcVClock2Stage(dotClock, &VClk, &state->pll, &state->pllB, + par); + else + CalcVClock(dotClock, &VClk, &state->pll, par); + + switch (par->Architecture) { + case NV_ARCH_04: + nv4UpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), par); + state->cursor0 = 0x00; + state->cursor1 = 0xbC; + if (flags & FB_VMODE_DOUBLE) + state->cursor1 |= 2; + state->cursor2 = 0x00000000; + state->pllsel = 0x10000700; + state->config = 0x00001114; + state->general = bpp == 16 ? 0x00101100 : 0x00100100; + state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; + break; + case NV_ARCH_10: + case NV_ARCH_20: + case NV_ARCH_30: + default: + if (((par->Chipset & 0xffff) == 0x01A0) || + ((par->Chipset & 0xffff) == 0x01f0)) { + nForceUpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), + par); + } else if (par->Architecture < NV_ARCH_30) { + nv10UpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), + par); + } else { + nv30UpdateArbitrationSettings(par, + &(state->arbitration0), + &(state->arbitration1)); + } + + state->cursor0 = 0x80 | (par->CursorStart >> 17); + state->cursor1 = (par->CursorStart >> 11) << 2; + state->cursor2 = par->CursorStart >> 24; + if (flags & FB_VMODE_DOUBLE) + state->cursor1 |= 2; + state->pllsel = 0x10000700; + state->config = NV_RD32(par->PFB, 0x00000200); + state->general = bpp == 16 ? 0x00101100 : 0x00100100; + state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; + break; + } + + if (bpp != 8) /* DirectColor */ + state->general |= 0x00000030; + + state->repaint0 = (((width / 8) * pixelDepth) & 0x700) >> 3; + state->pixel = (pixelDepth > 2) ? 3 : pixelDepth; +} + +void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) +{ + int i; + + NV_WR32(par->PMC, 0x0140, 0x00000000); + NV_WR32(par->PMC, 0x0200, 0xFFFF00FF); + NV_WR32(par->PMC, 0x0200, 0xFFFFFFFF); + + NV_WR32(par->PTIMER, 0x0200 * 4, 0x00000008); + NV_WR32(par->PTIMER, 0x0210 * 4, 0x00000003); + NV_WR32(par->PTIMER, 0x0140 * 4, 0x00000000); + NV_WR32(par->PTIMER, 0x0100 * 4, 0xFFFFFFFF); + + if (par->Architecture == NV_ARCH_04) { + NV_WR32(par->PFB, 0x0200, state->config); + } else if ((par->Chipset & 0xfff0) == 0x0090) { + for (i = 0; i < 15; i++) { + NV_WR32(par->PFB, 0x0600 + (i * 0x10), 0); + NV_WR32(par->PFB, 0x0604 + (i * 0x10), par->FbMapSize - 1); + } + } else { + for (i = 0; i < 8; i++) { + NV_WR32(par->PFB, 0x0240 + (i * 0x10), 0); + NV_WR32(par->PFB, 0x0244 + (i * 0x10), par->FbMapSize - 1); + } + } + + if (par->Architecture >= NV_ARCH_40) { + NV_WR32(par->PRAMIN, 0x0000 * 4, 0x80000010); + NV_WR32(par->PRAMIN, 0x0001 * 4, 0x00101202); + NV_WR32(par->PRAMIN, 0x0002 * 4, 0x80000011); + NV_WR32(par->PRAMIN, 0x0003 * 4, 0x00101204); + NV_WR32(par->PRAMIN, 0x0004 * 4, 0x80000012); + NV_WR32(par->PRAMIN, 0x0005 * 4, 0x00101206); + NV_WR32(par->PRAMIN, 0x0006 * 4, 0x80000013); + NV_WR32(par->PRAMIN, 0x0007 * 4, 0x00101208); + NV_WR32(par->PRAMIN, 0x0008 * 4, 0x80000014); + NV_WR32(par->PRAMIN, 0x0009 * 4, 0x0010120A); + NV_WR32(par->PRAMIN, 0x000A * 4, 0x80000015); + NV_WR32(par->PRAMIN, 0x000B * 4, 0x0010120C); + NV_WR32(par->PRAMIN, 0x000C * 4, 0x80000016); + NV_WR32(par->PRAMIN, 0x000D * 4, 0x0010120E); + NV_WR32(par->PRAMIN, 0x000E * 4, 0x80000017); + NV_WR32(par->PRAMIN, 0x000F * 4, 0x00101210); + NV_WR32(par->PRAMIN, 0x0800 * 4, 0x00003000); + NV_WR32(par->PRAMIN, 0x0801 * 4, par->FbMapSize - 1); + NV_WR32(par->PRAMIN, 0x0802 * 4, 0x00000002); + NV_WR32(par->PRAMIN, 0x0808 * 4, 0x02080062); + NV_WR32(par->PRAMIN, 0x0809 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x080A * 4, 0x00001200); + NV_WR32(par->PRAMIN, 0x080B * 4, 0x00001200); + NV_WR32(par->PRAMIN, 0x080C * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x080D * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0810 * 4, 0x02080043); + NV_WR32(par->PRAMIN, 0x0811 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0812 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0813 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0814 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0815 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0818 * 4, 0x02080044); + NV_WR32(par->PRAMIN, 0x0819 * 4, 0x02000000); + NV_WR32(par->PRAMIN, 0x081A * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x081B * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x081C * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x081D * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0820 * 4, 0x02080019); + NV_WR32(par->PRAMIN, 0x0821 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0822 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0823 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0824 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0825 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0828 * 4, 0x020A005C); + NV_WR32(par->PRAMIN, 0x0829 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x082A * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x082B * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x082C * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x082D * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0830 * 4, 0x0208009F); + NV_WR32(par->PRAMIN, 0x0831 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0832 * 4, 0x00001200); + NV_WR32(par->PRAMIN, 0x0833 * 4, 0x00001200); + NV_WR32(par->PRAMIN, 0x0834 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0835 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0838 * 4, 0x0208004A); + NV_WR32(par->PRAMIN, 0x0839 * 4, 0x02000000); + NV_WR32(par->PRAMIN, 0x083A * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x083B * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x083C * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x083D * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0840 * 4, 0x02080077); + NV_WR32(par->PRAMIN, 0x0841 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0842 * 4, 0x00001200); + NV_WR32(par->PRAMIN, 0x0843 * 4, 0x00001200); + NV_WR32(par->PRAMIN, 0x0844 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0845 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x084C * 4, 0x00003002); + NV_WR32(par->PRAMIN, 0x084D * 4, 0x00007FFF); + NV_WR32(par->PRAMIN, 0x084E * 4, + par->FbUsableSize | 0x00000002); + +#ifdef __BIG_ENDIAN + NV_WR32(par->PRAMIN, 0x080A * 4, + NV_RD32(par->PRAMIN, 0x080A * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x0812 * 4, + NV_RD32(par->PRAMIN, 0x0812 * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x081A * 4, + NV_RD32(par->PRAMIN, 0x081A * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x0822 * 4, + NV_RD32(par->PRAMIN, 0x0822 * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x082A * 4, + NV_RD32(par->PRAMIN, 0x082A * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x0832 * 4, + NV_RD32(par->PRAMIN, 0x0832 * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x083A * 4, + NV_RD32(par->PRAMIN, 0x083A * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x0842 * 4, + NV_RD32(par->PRAMIN, 0x0842 * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x0819 * 4, 0x01000000); + NV_WR32(par->PRAMIN, 0x0839 * 4, 0x01000000); +#endif + } else { + NV_WR32(par->PRAMIN, 0x0000 * 4, 0x80000010); + NV_WR32(par->PRAMIN, 0x0001 * 4, 0x80011201); + NV_WR32(par->PRAMIN, 0x0002 * 4, 0x80000011); + NV_WR32(par->PRAMIN, 0x0003 * 4, 0x80011202); + NV_WR32(par->PRAMIN, 0x0004 * 4, 0x80000012); + NV_WR32(par->PRAMIN, 0x0005 * 4, 0x80011203); + NV_WR32(par->PRAMIN, 0x0006 * 4, 0x80000013); + NV_WR32(par->PRAMIN, 0x0007 * 4, 0x80011204); + NV_WR32(par->PRAMIN, 0x0008 * 4, 0x80000014); + NV_WR32(par->PRAMIN, 0x0009 * 4, 0x80011205); + NV_WR32(par->PRAMIN, 0x000A * 4, 0x80000015); + NV_WR32(par->PRAMIN, 0x000B * 4, 0x80011206); + NV_WR32(par->PRAMIN, 0x000C * 4, 0x80000016); + NV_WR32(par->PRAMIN, 0x000D * 4, 0x80011207); + NV_WR32(par->PRAMIN, 0x000E * 4, 0x80000017); + NV_WR32(par->PRAMIN, 0x000F * 4, 0x80011208); + NV_WR32(par->PRAMIN, 0x0800 * 4, 0x00003000); + NV_WR32(par->PRAMIN, 0x0801 * 4, par->FbMapSize - 1); + NV_WR32(par->PRAMIN, 0x0802 * 4, 0x00000002); + NV_WR32(par->PRAMIN, 0x0803 * 4, 0x00000002); + if (par->Architecture >= NV_ARCH_10) + NV_WR32(par->PRAMIN, 0x0804 * 4, 0x01008062); + else + NV_WR32(par->PRAMIN, 0x0804 * 4, 0x01008042); + NV_WR32(par->PRAMIN, 0x0805 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0806 * 4, 0x12001200); + NV_WR32(par->PRAMIN, 0x0807 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0808 * 4, 0x01008043); + NV_WR32(par->PRAMIN, 0x0809 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x080A * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x080B * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x080C * 4, 0x01008044); + NV_WR32(par->PRAMIN, 0x080D * 4, 0x00000002); + NV_WR32(par->PRAMIN, 0x080E * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x080F * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0810 * 4, 0x01008019); + NV_WR32(par->PRAMIN, 0x0811 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0812 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0813 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0814 * 4, 0x0100A05C); + NV_WR32(par->PRAMIN, 0x0815 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0816 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0817 * 4, 0x00000000); + if (par->WaitVSyncPossible) + NV_WR32(par->PRAMIN, 0x0818 * 4, 0x0100809F); + else + NV_WR32(par->PRAMIN, 0x0818 * 4, 0x0100805F); + NV_WR32(par->PRAMIN, 0x0819 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x081A * 4, 0x12001200); + NV_WR32(par->PRAMIN, 0x081B * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x081C * 4, 0x0100804A); + NV_WR32(par->PRAMIN, 0x081D * 4, 0x00000002); + NV_WR32(par->PRAMIN, 0x081E * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x081F * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0820 * 4, 0x01018077); + NV_WR32(par->PRAMIN, 0x0821 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0822 * 4, 0x12001200); + NV_WR32(par->PRAMIN, 0x0823 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0824 * 4, 0x00003002); + NV_WR32(par->PRAMIN, 0x0825 * 4, 0x00007FFF); + NV_WR32(par->PRAMIN, 0x0826 * 4, + par->FbUsableSize | 0x00000002); + NV_WR32(par->PRAMIN, 0x0827 * 4, 0x00000002); +#ifdef __BIG_ENDIAN + NV_WR32(par->PRAMIN, 0x0804 * 4, + NV_RD32(par->PRAMIN, 0x0804 * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x0808 * 4, + NV_RD32(par->PRAMIN, 0x0808 * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x080C * 4, + NV_RD32(par->PRAMIN, 0x080C * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x0810 * 4, + NV_RD32(par->PRAMIN, 0x0810 * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x0814 * 4, + NV_RD32(par->PRAMIN, 0x0814 * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x0818 * 4, + NV_RD32(par->PRAMIN, 0x0818 * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x081C * 4, + NV_RD32(par->PRAMIN, 0x081C * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x0820 * 4, + NV_RD32(par->PRAMIN, 0x0820 * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x080D * 4, 0x00000001); + NV_WR32(par->PRAMIN, 0x081D * 4, 0x00000001); +#endif + } + if (par->Architecture < NV_ARCH_10) { + if ((par->Chipset & 0x0fff) == 0x0020) { + NV_WR32(par->PRAMIN, 0x0824 * 4, + NV_RD32(par->PRAMIN, 0x0824 * 4) | 0x00020000); + NV_WR32(par->PRAMIN, 0x0826 * 4, + NV_RD32(par->PRAMIN, + 0x0826 * 4) + par->FbAddress); + } + NV_WR32(par->PGRAPH, 0x0080, 0x000001FF); + NV_WR32(par->PGRAPH, 0x0080, 0x1230C000); + NV_WR32(par->PGRAPH, 0x0084, 0x72111101); + NV_WR32(par->PGRAPH, 0x0088, 0x11D5F071); + NV_WR32(par->PGRAPH, 0x008C, 0x0004FF31); + NV_WR32(par->PGRAPH, 0x008C, 0x4004FF31); + NV_WR32(par->PGRAPH, 0x0140, 0x00000000); + NV_WR32(par->PGRAPH, 0x0100, 0xFFFFFFFF); + NV_WR32(par->PGRAPH, 0x0170, 0x10010100); + NV_WR32(par->PGRAPH, 0x0710, 0xFFFFFFFF); + NV_WR32(par->PGRAPH, 0x0720, 0x00000001); + NV_WR32(par->PGRAPH, 0x0810, 0x00000000); + NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF); + } else { + NV_WR32(par->PGRAPH, 0x0080, 0xFFFFFFFF); + NV_WR32(par->PGRAPH, 0x0080, 0x00000000); + + NV_WR32(par->PGRAPH, 0x0140, 0x00000000); + NV_WR32(par->PGRAPH, 0x0100, 0xFFFFFFFF); + NV_WR32(par->PGRAPH, 0x0144, 0x10010100); + NV_WR32(par->PGRAPH, 0x0714, 0xFFFFFFFF); + NV_WR32(par->PGRAPH, 0x0720, 0x00000001); + NV_WR32(par->PGRAPH, 0x0710, + NV_RD32(par->PGRAPH, 0x0710) & 0x0007ff00); + NV_WR32(par->PGRAPH, 0x0710, + NV_RD32(par->PGRAPH, 0x0710) | 0x00020100); + + if (par->Architecture == NV_ARCH_10) { + NV_WR32(par->PGRAPH, 0x0084, 0x00118700); + NV_WR32(par->PGRAPH, 0x0088, 0x24E00810); + NV_WR32(par->PGRAPH, 0x008C, 0x55DE0030); + + for (i = 0; i < 32; i++) + NV_WR32(&par->PGRAPH[(0x0B00 / 4) + i], 0, + NV_RD32(&par->PFB[(0x0240 / 4) + i], + 0)); + + NV_WR32(par->PGRAPH, 0x640, 0); + NV_WR32(par->PGRAPH, 0x644, 0); + NV_WR32(par->PGRAPH, 0x684, par->FbMapSize - 1); + NV_WR32(par->PGRAPH, 0x688, par->FbMapSize - 1); + + NV_WR32(par->PGRAPH, 0x0810, 0x00000000); + NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF); + } else { + if (par->Architecture >= NV_ARCH_40) { + NV_WR32(par->PGRAPH, 0x0084, 0x401287c0); + NV_WR32(par->PGRAPH, 0x008C, 0x60de8051); + NV_WR32(par->PGRAPH, 0x0090, 0x00008000); + NV_WR32(par->PGRAPH, 0x0610, 0x00be3c5f); + + if ((par->Chipset & 0xfff0) == 0x0040) { + NV_WR32(par->PGRAPH, 0x09b0, + 0x83280fff); + NV_WR32(par->PGRAPH, 0x09b4, + 0x000000a0); + } else { + NV_WR32(par->PGRAPH, 0x0820, + 0x83280eff); + NV_WR32(par->PGRAPH, 0x0824, + 0x000000a0); + } + + switch (par->Chipset & 0xfff0) { + case 0x0040: + case 0x0210: + NV_WR32(par->PGRAPH, 0x09b8, + 0x0078e366); + NV_WR32(par->PGRAPH, 0x09bc, + 0x0000014c); + NV_WR32(par->PFB, 0x033C, + NV_RD32(par->PFB, 0x33C) & + 0xffff7fff); + break; + case 0x00C0: + NV_WR32(par->PGRAPH, 0x0828, + 0x007596ff); + NV_WR32(par->PGRAPH, 0x082C, + 0x00000108); + break; + case 0x0160: + case 0x01D0: + NV_WR32(par->PMC, 0x1700, + NV_RD32(par->PFB, 0x020C)); + NV_WR32(par->PMC, 0x1704, 0); + NV_WR32(par->PMC, 0x1708, 0); + NV_WR32(par->PMC, 0x170C, + NV_RD32(par->PFB, 0x020C)); + NV_WR32(par->PGRAPH, 0x0860, 0); + NV_WR32(par->PGRAPH, 0x0864, 0); + NV_WR32(par->PRAMDAC, 0x0608, + NV_RD32(par->PRAMDAC, + 0x0608) | 0x00100000); + break; + case 0x0140: + NV_WR32(par->PGRAPH, 0x0828, + 0x0072cb77); + NV_WR32(par->PGRAPH, 0x082C, + 0x00000108); + break; + case 0x0220: + case 0x0230: + NV_WR32(par->PGRAPH, 0x0860, 0); + NV_WR32(par->PGRAPH, 0x0864, 0); + NV_WR32(par->PRAMDAC, 0x0608, + NV_RD32(par->PRAMDAC, 0x0608) | + 0x00100000); + break; + case 0x0090: + NV_WR32(par->PRAMDAC, 0x0608, + NV_RD32(par->PRAMDAC, 0x0608) | + 0x00100000); + NV_WR32(par->PGRAPH, 0x0828, + 0x07830610); + NV_WR32(par->PGRAPH, 0x082C, + 0x0000016A); + break; + default: + break; + }; + + NV_WR32(par->PGRAPH, 0x0b38, 0x2ffff800); + NV_WR32(par->PGRAPH, 0x0b3c, 0x00006000); + NV_WR32(par->PGRAPH, 0x032C, 0x01000000); + NV_WR32(par->PGRAPH, 0x0220, 0x00001200); + } else if (par->Architecture == NV_ARCH_30) { + NV_WR32(par->PGRAPH, 0x0084, 0x40108700); + NV_WR32(par->PGRAPH, 0x0890, 0x00140000); + NV_WR32(par->PGRAPH, 0x008C, 0xf00e0431); + NV_WR32(par->PGRAPH, 0x0090, 0x00008000); + NV_WR32(par->PGRAPH, 0x0610, 0xf04b1f36); + NV_WR32(par->PGRAPH, 0x0B80, 0x1002d888); + NV_WR32(par->PGRAPH, 0x0B88, 0x62ff007f); + } else { + NV_WR32(par->PGRAPH, 0x0084, 0x00118700); + NV_WR32(par->PGRAPH, 0x008C, 0xF20E0431); + NV_WR32(par->PGRAPH, 0x0090, 0x00000000); + NV_WR32(par->PGRAPH, 0x009C, 0x00000040); + + if ((par->Chipset & 0x0ff0) >= 0x0250) { + NV_WR32(par->PGRAPH, 0x0890, + 0x00080000); + NV_WR32(par->PGRAPH, 0x0610, + 0x304B1FB6); + NV_WR32(par->PGRAPH, 0x0B80, + 0x18B82880); + NV_WR32(par->PGRAPH, 0x0B84, + 0x44000000); + NV_WR32(par->PGRAPH, 0x0098, + 0x40000080); + NV_WR32(par->PGRAPH, 0x0B88, + 0x000000ff); + } else { + NV_WR32(par->PGRAPH, 0x0880, + 0x00080000); + NV_WR32(par->PGRAPH, 0x0094, + 0x00000005); + NV_WR32(par->PGRAPH, 0x0B80, + 0x45CAA208); + NV_WR32(par->PGRAPH, 0x0B84, + 0x24000000); + NV_WR32(par->PGRAPH, 0x0098, + 0x00000040); + NV_WR32(par->PGRAPH, 0x0750, + 0x00E00038); + NV_WR32(par->PGRAPH, 0x0754, + 0x00000030); + NV_WR32(par->PGRAPH, 0x0750, + 0x00E10038); + NV_WR32(par->PGRAPH, 0x0754, + 0x00000030); + } + } + + if ((par->Chipset & 0xfff0) == 0x0090) { + for (i = 0; i < 60; i++) + NV_WR32(par->PGRAPH, 0x0D00 + i, + NV_RD32(par->PFB, 0x0600 + i)); + } else { + for (i = 0; i < 32; i++) + NV_WR32(par->PGRAPH, 0x0900 + i, + NV_RD32(par->PFB, 0x0240 + i)); + } + + if (par->Architecture >= NV_ARCH_40) { + if ((par->Chipset & 0xfff0) == 0x0040) { + NV_WR32(par->PGRAPH, 0x09A4, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x09A8, + NV_RD32(par->PFB, 0x0204)); + NV_WR32(par->PGRAPH, 0x69A4, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x69A8, + NV_RD32(par->PFB, 0x0204)); + + NV_WR32(par->PGRAPH, 0x0820, 0); + NV_WR32(par->PGRAPH, 0x0824, 0); + NV_WR32(par->PGRAPH, 0x0864, + par->FbMapSize - 1); + NV_WR32(par->PGRAPH, 0x0868, + par->FbMapSize - 1); + } else { + if((par->Chipset & 0xfff0) == 0x0090) { + NV_WR32(par->PGRAPH, 0x0DF0, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x0DF4, + NV_RD32(par->PFB, 0x0204)); + } else { + NV_WR32(par->PGRAPH, 0x09F0, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x09F4, + NV_RD32(par->PFB, 0x0204)); + } + NV_WR32(par->PGRAPH, 0x69F0, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x69F4, + NV_RD32(par->PFB, 0x0204)); + + NV_WR32(par->PGRAPH, 0x0840, 0); + NV_WR32(par->PGRAPH, 0x0844, 0); + NV_WR32(par->PGRAPH, 0x08a0, + par->FbMapSize - 1); + NV_WR32(par->PGRAPH, 0x08a4, + par->FbMapSize - 1); + } + } else { + NV_WR32(par->PGRAPH, 0x09A4, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x09A8, + NV_RD32(par->PFB, 0x0204)); + NV_WR32(par->PGRAPH, 0x0750, 0x00EA0000); + NV_WR32(par->PGRAPH, 0x0754, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x0750, 0x00EA0004); + NV_WR32(par->PGRAPH, 0x0754, + NV_RD32(par->PFB, 0x0204)); + + NV_WR32(par->PGRAPH, 0x0820, 0); + NV_WR32(par->PGRAPH, 0x0824, 0); + NV_WR32(par->PGRAPH, 0x0864, + par->FbMapSize - 1); + NV_WR32(par->PGRAPH, 0x0868, + par->FbMapSize - 1); + } + NV_WR32(par->PGRAPH, 0x0B20, 0x00000000); + NV_WR32(par->PGRAPH, 0x0B04, 0xFFFFFFFF); + } + } + NV_WR32(par->PGRAPH, 0x053C, 0); + NV_WR32(par->PGRAPH, 0x0540, 0); + NV_WR32(par->PGRAPH, 0x0544, 0x00007FFF); + NV_WR32(par->PGRAPH, 0x0548, 0x00007FFF); + + NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x0141 * 4, 0x00000001); + NV_WR32(par->PFIFO, 0x0480 * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000000); + if (par->Architecture >= NV_ARCH_40) + NV_WR32(par->PFIFO, 0x0481 * 4, 0x00010000); + else + NV_WR32(par->PFIFO, 0x0481 * 4, 0x00000100); + NV_WR32(par->PFIFO, 0x0490 * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x0491 * 4, 0x00000000); + if (par->Architecture >= NV_ARCH_40) + NV_WR32(par->PFIFO, 0x048B * 4, 0x00001213); + else + NV_WR32(par->PFIFO, 0x048B * 4, 0x00001209); + NV_WR32(par->PFIFO, 0x0400 * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x0414 * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x0084 * 4, 0x03000100); + NV_WR32(par->PFIFO, 0x0085 * 4, 0x00000110); + NV_WR32(par->PFIFO, 0x0086 * 4, 0x00000112); + NV_WR32(par->PFIFO, 0x0143 * 4, 0x0000FFFF); + NV_WR32(par->PFIFO, 0x0496 * 4, 0x0000FFFF); + NV_WR32(par->PFIFO, 0x0050 * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x0040 * 4, 0xFFFFFFFF); + NV_WR32(par->PFIFO, 0x0415 * 4, 0x00000001); + NV_WR32(par->PFIFO, 0x048C * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x04A0 * 4, 0x00000000); +#ifdef __BIG_ENDIAN + NV_WR32(par->PFIFO, 0x0489 * 4, 0x800F0078); +#else + NV_WR32(par->PFIFO, 0x0489 * 4, 0x000F0078); +#endif + NV_WR32(par->PFIFO, 0x0488 * 4, 0x00000001); + NV_WR32(par->PFIFO, 0x0480 * 4, 0x00000001); + NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000001); + NV_WR32(par->PFIFO, 0x0495 * 4, 0x00000001); + NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000001); + if (par->Architecture >= NV_ARCH_10) { + if (par->twoHeads) { + NV_WR32(par->PCRTC0, 0x0860, state->head); + NV_WR32(par->PCRTC0, 0x2860, state->head2); + } + NV_WR32(par->PRAMDAC, 0x0404, NV_RD32(par->PRAMDAC, 0x0404) | + (1 << 25)); + + NV_WR32(par->PMC, 0x8704, 1); + NV_WR32(par->PMC, 0x8140, 0); + NV_WR32(par->PMC, 0x8920, 0); + NV_WR32(par->PMC, 0x8924, 0); + NV_WR32(par->PMC, 0x8908, par->FbMapSize - 1); + NV_WR32(par->PMC, 0x890C, par->FbMapSize - 1); + NV_WR32(par->PMC, 0x1588, 0); + + NV_WR32(par->PCRTC, 0x0810, state->cursorConfig); + NV_WR32(par->PCRTC, 0x0830, state->displayV - 3); + NV_WR32(par->PCRTC, 0x0834, state->displayV - 1); + + if (par->FlatPanel) { + if ((par->Chipset & 0x0ff0) == 0x0110) { + NV_WR32(par->PRAMDAC, 0x0528, state->dither); + } else if (par->twoHeads) { + NV_WR32(par->PRAMDAC, 0x083C, state->dither); + } + + VGA_WR08(par->PCIO, 0x03D4, 0x53); + VGA_WR08(par->PCIO, 0x03D5, state->timingH); + VGA_WR08(par->PCIO, 0x03D4, 0x54); + VGA_WR08(par->PCIO, 0x03D5, state->timingV); + VGA_WR08(par->PCIO, 0x03D4, 0x21); + VGA_WR08(par->PCIO, 0x03D5, 0xfa); + } + + VGA_WR08(par->PCIO, 0x03D4, 0x41); + VGA_WR08(par->PCIO, 0x03D5, state->extra); + } + + VGA_WR08(par->PCIO, 0x03D4, 0x19); + VGA_WR08(par->PCIO, 0x03D5, state->repaint0); + VGA_WR08(par->PCIO, 0x03D4, 0x1A); + VGA_WR08(par->PCIO, 0x03D5, state->repaint1); + VGA_WR08(par->PCIO, 0x03D4, 0x25); + VGA_WR08(par->PCIO, 0x03D5, state->screen); + VGA_WR08(par->PCIO, 0x03D4, 0x28); + VGA_WR08(par->PCIO, 0x03D5, state->pixel); + VGA_WR08(par->PCIO, 0x03D4, 0x2D); + VGA_WR08(par->PCIO, 0x03D5, state->horiz); + VGA_WR08(par->PCIO, 0x03D4, 0x1C); + VGA_WR08(par->PCIO, 0x03D5, state->fifo); + VGA_WR08(par->PCIO, 0x03D4, 0x1B); + VGA_WR08(par->PCIO, 0x03D5, state->arbitration0); + VGA_WR08(par->PCIO, 0x03D4, 0x20); + VGA_WR08(par->PCIO, 0x03D5, state->arbitration1); + + if(par->Architecture >= NV_ARCH_30) { + VGA_WR08(par->PCIO, 0x03D4, 0x47); + VGA_WR08(par->PCIO, 0x03D5, state->arbitration1 >> 8); + } + + VGA_WR08(par->PCIO, 0x03D4, 0x30); + VGA_WR08(par->PCIO, 0x03D5, state->cursor0); + VGA_WR08(par->PCIO, 0x03D4, 0x31); + VGA_WR08(par->PCIO, 0x03D5, state->cursor1); + VGA_WR08(par->PCIO, 0x03D4, 0x2F); + VGA_WR08(par->PCIO, 0x03D5, state->cursor2); + VGA_WR08(par->PCIO, 0x03D4, 0x39); + VGA_WR08(par->PCIO, 0x03D5, state->interlace); + + if (!par->FlatPanel) { + NV_WR32(par->PRAMDAC0, 0x050C, state->pllsel); + NV_WR32(par->PRAMDAC0, 0x0508, state->vpll); + if (par->twoHeads) + NV_WR32(par->PRAMDAC0, 0x0520, state->vpll2); + if (par->twoStagePLL) { + NV_WR32(par->PRAMDAC0, 0x0578, state->vpllB); + NV_WR32(par->PRAMDAC0, 0x057C, state->vpll2B); + } + } else { + NV_WR32(par->PRAMDAC, 0x0848, state->scale); + NV_WR32(par->PRAMDAC, 0x0828, state->crtcSync + + par->PanelTweak); + } + + NV_WR32(par->PRAMDAC, 0x0600, state->general); + + NV_WR32(par->PCRTC, 0x0140, 0); + NV_WR32(par->PCRTC, 0x0100, 1); + + par->CurrentState = state; +} + +void NVUnloadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) { + VGA_WR08(par->PCIO, 0x03D4, 0x19); + state->repaint0 = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x1A); + state->repaint1 = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x25); + state->screen = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x28); + state->pixel = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x2D); + state->horiz = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x1C); + state->fifo = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x1B); + state->arbitration0 = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x20); + state->arbitration1 = VGA_RD08(par->PCIO, 0x03D5); + + if(par->Architecture >= NV_ARCH_30) { + VGA_WR08(par->PCIO, 0x03D4, 0x47); + state->arbitration1 |= (VGA_RD08(par->PCIO, 0x03D5) & 1) << 8; + } + + VGA_WR08(par->PCIO, 0x03D4, 0x30); + state->cursor0 = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x31); + state->cursor1 = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x2F); + state->cursor2 = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x39); + state->interlace = VGA_RD08(par->PCIO, 0x03D5); + state->vpll = NV_RD32(par->PRAMDAC0, 0x0508); + if (par->twoHeads) + state->vpll2 = NV_RD32(par->PRAMDAC0, 0x0520); + if (par->twoStagePLL) { + state->vpllB = NV_RD32(par->PRAMDAC0, 0x0578); + state->vpll2B = NV_RD32(par->PRAMDAC0, 0x057C); + } + state->pllsel = NV_RD32(par->PRAMDAC0, 0x050C); + state->general = NV_RD32(par->PRAMDAC, 0x0600); + state->scale = NV_RD32(par->PRAMDAC, 0x0848); + state->config = NV_RD32(par->PFB, 0x0200); + + if (par->Architecture >= NV_ARCH_10) { + if (par->twoHeads) { + state->head = NV_RD32(par->PCRTC0, 0x0860); + state->head2 = NV_RD32(par->PCRTC0, 0x2860); + VGA_WR08(par->PCIO, 0x03D4, 0x44); + state->crtcOwner = VGA_RD08(par->PCIO, 0x03D5); + } + VGA_WR08(par->PCIO, 0x03D4, 0x41); + state->extra = VGA_RD08(par->PCIO, 0x03D5); + state->cursorConfig = NV_RD32(par->PCRTC, 0x0810); + + if ((par->Chipset & 0x0ff0) == 0x0110) { + state->dither = NV_RD32(par->PRAMDAC, 0x0528); + } else if (par->twoHeads) { + state->dither = NV_RD32(par->PRAMDAC, 0x083C); + } + + if (par->FlatPanel) { + VGA_WR08(par->PCIO, 0x03D4, 0x53); + state->timingH = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x54); + state->timingV = VGA_RD08(par->PCIO, 0x03D5); + } + } +} + +void NVSetStartAddress(struct nvidia_par *par, u32 start) +{ + NV_WR32(par->PCRTC, 0x800, start); +} diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c new file mode 100644 index 000000000000..3757c1407c19 --- /dev/null +++ b/drivers/video/nvidia/nv_i2c.c @@ -0,0 +1,215 @@ +/* + * linux/drivers/video/nvidia/nvidia-i2c.c - nVidia i2c + * + * Copyright 2004 Antonino A. Daplas <adaplas @pol.net> + * + * Based on rivafb-i2c.c + * + * 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/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/fb.h> + +#include <asm/io.h> + +#include "nv_type.h" +#include "nv_local.h" +#include "nv_proto.h" + +#include "../edid.h" + +static void nvidia_gpio_setscl(void *data, int state) +{ + struct nvidia_i2c_chan *chan = data; + struct nvidia_par *par = chan->par; + u32 val; + + VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1); + val = VGA_RD08(par->PCIO, 0x3d5) & 0xf0; + + if (state) + val |= 0x20; + else + val &= ~0x20; + + VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1); + VGA_WR08(par->PCIO, 0x3d5, val | 0x1); +} + +static void nvidia_gpio_setsda(void *data, int state) +{ + struct nvidia_i2c_chan *chan = (struct nvidia_i2c_chan *)data; + struct nvidia_par *par = chan->par; + u32 val; + + VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1); + val = VGA_RD08(par->PCIO, 0x3d5) & 0xf0; + + if (state) + val |= 0x10; + else + val &= ~0x10; + + VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1); + VGA_WR08(par->PCIO, 0x3d5, val | 0x1); +} + +static int nvidia_gpio_getscl(void *data) +{ + struct nvidia_i2c_chan *chan = (struct nvidia_i2c_chan *)data; + struct nvidia_par *par = chan->par; + u32 val = 0; + + VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base); + if (VGA_RD08(par->PCIO, 0x3d5) & 0x04) + val = 1; + + val = VGA_RD08(par->PCIO, 0x3d5); + + return val; +} + +static int nvidia_gpio_getsda(void *data) +{ + struct nvidia_i2c_chan *chan = (struct nvidia_i2c_chan *)data; + struct nvidia_par *par = chan->par; + u32 val = 0; + + VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base); + if (VGA_RD08(par->PCIO, 0x3d5) & 0x08) + val = 1; + + return val; +} + +#define I2C_ALGO_NVIDIA 0x0e0000 +static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name) +{ + int rc; + + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_ALGO_NVIDIA; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->par->pci_dev->dev; + chan->algo.setsda = nvidia_gpio_setsda; + chan->algo.setscl = nvidia_gpio_setscl; + chan->algo.getsda = nvidia_gpio_getsda; + chan->algo.getscl = nvidia_gpio_getscl; + chan->algo.udelay = 40; + chan->algo.timeout = msecs_to_jiffies(2); + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + /* Raise SCL and SDA */ + nvidia_gpio_setsda(chan, 1); + nvidia_gpio_setscl(chan, 1); + udelay(20); + + rc = i2c_bit_add_bus(&chan->adapter); + if (rc == 0) + dev_dbg(&chan->par->pci_dev->dev, + "I2C bus %s registered.\n", name); + else { + dev_warn(&chan->par->pci_dev->dev, + "Failed to register I2C bus %s.\n", name); + chan->par = NULL; + } + + return rc; +} + +void nvidia_create_i2c_busses(struct nvidia_par *par) +{ + par->bus = 3; + + par->chan[0].par = par; + par->chan[1].par = par; + par->chan[2].par = par; + + par->chan[0].ddc_base = 0x3e; + nvidia_setup_i2c_bus(&par->chan[0], "BUS1"); + + par->chan[1].ddc_base = 0x36; + nvidia_setup_i2c_bus(&par->chan[1], "BUS2"); + + par->chan[2].ddc_base = 0x50; + nvidia_setup_i2c_bus(&par->chan[2], "BUS3"); +} + +void nvidia_delete_i2c_busses(struct nvidia_par *par) +{ + if (par->chan[0].par) + i2c_bit_del_bus(&par->chan[0].adapter); + par->chan[0].par = NULL; + + if (par->chan[1].par) + i2c_bit_del_bus(&par->chan[1].adapter); + par->chan[1].par = NULL; + + if (par->chan[2].par) + i2c_bit_del_bus(&par->chan[2].adapter); + par->chan[2].par = NULL; + +} + +static u8 *nvidia_do_probe_i2c_edid(struct nvidia_i2c_chan *chan) +{ + u8 start = 0x0; + struct i2c_msg msgs[] = { + { + .addr = 0x50, + .len = 1, + .buf = &start, + }, { + .addr = 0x50, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + }, + }; + u8 *buf; + + if (!chan->par) + return NULL; + + buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!buf) { + dev_warn(&chan->par->pci_dev->dev, "Out of memory!\n"); + return NULL; + } + msgs[1].buf = buf; + + if (i2c_transfer(&chan->adapter, msgs, 2) == 2) + return buf; + dev_dbg(&chan->par->pci_dev->dev, "Unable to read EDID block.\n"); + kfree(buf); + return NULL; +} + +int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, u8 **out_edid) +{ + u8 *edid = NULL; + int i; + + for (i = 0; i < 3; i++) { + /* Do the real work */ + edid = nvidia_do_probe_i2c_edid(&par->chan[conn - 1]); + if (edid) + break; + } + if (out_edid) + *out_edid = edid; + if (!edid) + return 1; + + return 0; +} diff --git a/drivers/video/nvidia/nv_local.h b/drivers/video/nvidia/nv_local.h new file mode 100644 index 000000000000..9da320986f4c --- /dev/null +++ b/drivers/video/nvidia/nv_local.h @@ -0,0 +1,107 @@ +/***************************************************************************\ +|* *| +|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 1993-1999 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/ + * XFree86 'nv' driver, this source code is provided under MIT-style licensing + * where the source code is provided "as is" without warranty of any kind. + * The only usage restriction is for the copyright notices to be retained + * whenever code is used. + * + * Antonino Daplas <adaplas@pol.net> 2005-03-11 + */ + +#ifndef __NV_LOCAL_H__ +#define __NV_LOCAL_H__ + +/* + * This file includes any environment or machine specific values to access the + * HW. Put all affected includes, typdefs, etc. here so the riva_hw.* files + * can stay generic in nature. + */ + +/* + * HW access macros. These assume memory-mapped I/O, and not normal I/O space. + */ +#define NV_WR08(p,i,d) (__raw_writeb((d), (void __iomem *)(p) + (i))) +#define NV_RD08(p,i) (__raw_readb((void __iomem *)(p) + (i))) +#define NV_WR16(p,i,d) (__raw_writew((d), (void __iomem *)(p) + (i))) +#define NV_RD16(p,i) (__raw_readw((void __iomem *)(p) + (i))) +#define NV_WR32(p,i,d) (__raw_writel((d), (void __iomem *)(p) + (i))) +#define NV_RD32(p,i) (__raw_readl((void __iomem *)(p) + (i))) + +/* VGA I/O is now always done through MMIO */ +#define VGA_WR08(p,i,d) (writeb((d), (void __iomem *)(p) + (i))) +#define VGA_RD08(p,i) (readb((void __iomem *)(p) + (i))) + +#define NVDmaNext(par, data) \ + NV_WR32(&(par)->dmaBase[(par)->dmaCurrent++], 0, (data)) + +#define NVDmaStart(par, tag, size) { \ + if((par)->dmaFree <= (size)) \ + NVDmaWait(par, size); \ + NVDmaNext(par, ((size) << 18) | (tag)); \ + (par)->dmaFree -= ((size) + 1); \ +} + +#if defined(__i386__) +#define _NV_FENCE() outb(0, 0x3D0); +#else +#define _NV_FENCE() mb(); +#endif + +#define WRITE_PUT(par, data) { \ + _NV_FENCE() \ + NV_RD08((par)->FbStart, 0); \ + NV_WR32(&(par)->FIFO[0x0010], 0, (data) << 2); \ + mb(); \ +} + +#define READ_GET(par) (NV_RD32(&(par)->FIFO[0x0011], 0) >> 2) + +#define reverse_order(l) \ +do { \ + u8 *a = (u8 *)(l); \ + *a = byte_rev[*a], a++; \ + *a = byte_rev[*a], a++; \ + *a = byte_rev[*a], a++; \ + *a = byte_rev[*a]; \ +} while(0) + +#endif /* __NV_LOCAL_H__ */ diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c new file mode 100644 index 000000000000..7d12eb85310d --- /dev/null +++ b/drivers/video/nvidia/nv_of.c @@ -0,0 +1,59 @@ +/* + * linux/drivers/video/nvidia/nv_of.c + * + * Copyright 2004 Antonino A. Daplas <adaplas @pol.net> + * + * Based on rivafb-i2c.c + * + * 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/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/fb.h> + +#include <asm/io.h> + +#include <asm/prom.h> +#include <asm/pci-bridge.h> + +#include "nv_type.h" +#include "nv_local.h" +#include "nv_proto.h" + +void nvidia_create_i2c_busses(struct nvidia_par *par) {} +void nvidia_delete_i2c_busses(struct nvidia_par *par) {} + +int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, u8 **out_edid) +{ + struct device_node *dp; + unsigned char *pedid = NULL; + unsigned char *disptype = NULL; + static char *propnames[] = { + "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL }; + int i; + + dp = pci_device_to_OF_node(par->pci_dev); + for (; dp != NULL; dp = dp->child) { + disptype = (unsigned char *)get_property(dp, "display-type", NULL); + if (disptype == NULL) + continue; + if (strncmp(disptype, "LCD", 3) != 0) + continue; + for (i = 0; propnames[i] != NULL; ++i) { + pedid = (unsigned char *) + get_property(dp, propnames[i], NULL); + if (pedid != NULL) { + *out_edid = pedid; + return 0; + } + } + } + return 1; +} diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h new file mode 100644 index 000000000000..42847ce1b8dd --- /dev/null +++ b/drivers/video/nvidia/nv_proto.h @@ -0,0 +1,58 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_proto.h,v 1.10 2003/07/31 20:24:29 mvojkovi Exp $ */ + +#ifndef __NV_PROTO_H__ +#define __NV_PROTO_H__ + +/* in nv_setup.c */ +void NVCommonSetup(struct fb_info *info); +void NVWriteCrtc(struct nvidia_par *par, u8 index, u8 value); +u8 NVReadCrtc(struct nvidia_par *par, u8 index); +void NVWriteGr(struct nvidia_par *par, u8 index, u8 value); +u8 NVReadGr(struct nvidia_par *par, u8 index); +void NVWriteSeq(struct nvidia_par *par, u8 index, u8 value); +u8 NVReadSeq(struct nvidia_par *par, u8 index); +void NVWriteAttr(struct nvidia_par *par, u8 index, u8 value); +u8 NVReadAttr(struct nvidia_par *par, u8 index); +void NVWriteMiscOut(struct nvidia_par *par, u8 value); +u8 NVReadMiscOut(struct nvidia_par *par); +void NVWriteDacMask(struct nvidia_par *par, u8 value); +void NVWriteDacReadAddr(struct nvidia_par *par, u8 value); +void NVWriteDacWriteAddr(struct nvidia_par *par, u8 value); +void NVWriteDacData(struct nvidia_par *par, u8 value); +u8 NVReadDacData(struct nvidia_par *par); + +/* in nv_hw.c */ +void NVCalcStateExt(struct nvidia_par *par, struct _riva_hw_state *, + int, int, int, int, int, int); +void NVLoadStateExt(struct nvidia_par *par, struct _riva_hw_state *); +void NVUnloadStateExt(struct nvidia_par *par, struct _riva_hw_state *); +void NVSetStartAddress(struct nvidia_par *par, u32); +int NVShowHideCursor(struct nvidia_par *par, int); +void NVLockUnlock(struct nvidia_par *par, int); + +/* in nvidia-i2c.c */ +#if defined(CONFIG_FB_NVIDIA_I2C) || defined (CONFIG_PPC_OF) +void nvidia_create_i2c_busses(struct nvidia_par *par); +void nvidia_delete_i2c_busses(struct nvidia_par *par); +int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, + u8 ** out_edid); +#else +#define nvidia_create_i2c_busses(...) +#define nvidia_delete_i2c_busses(...) +#define nvidia_probe_i2c_connector(p, c, edid) \ +do { \ + *(edid) = NULL; \ +} while(0) +#endif + +/* in nv_accel.c */ +extern void NVResetGraphics(struct fb_info *info); +extern void nvidiafb_copyarea(struct fb_info *info, + const struct fb_copyarea *region); +extern void nvidiafb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect); +extern void nvidiafb_imageblit(struct fb_info *info, + const struct fb_image *image); +extern int nvidiafb_sync(struct fb_info *info); +extern u8 byte_rev[256]; +#endif /* __NV_PROTO_H__ */ diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c new file mode 100644 index 000000000000..0bbdca2e0f91 --- /dev/null +++ b/drivers/video/nvidia/nv_setup.c @@ -0,0 +1,636 @@ + /***************************************************************************\ +|* *| +|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/ + * XFree86 'nv' driver, this source code is provided under MIT-style licensing + * where the source code is provided "as is" without warranty of any kind. + * The only usage restriction is for the copyright notices to be retained + * whenever code is used. + * + * Antonino Daplas <adaplas@pol.net> 2005-03-11 + */ + +#include <video/vga.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include "nv_type.h" +#include "nv_local.h" +#include "nv_proto.h" +/* + * Override VGA I/O routines. + */ +void NVWriteCrtc(struct nvidia_par *par, u8 index, u8 value) +{ + VGA_WR08(par->PCIO, par->IOBase + 0x04, index); + VGA_WR08(par->PCIO, par->IOBase + 0x05, value); +} +u8 NVReadCrtc(struct nvidia_par *par, u8 index) +{ + VGA_WR08(par->PCIO, par->IOBase + 0x04, index); + return (VGA_RD08(par->PCIO, par->IOBase + 0x05)); +} +void NVWriteGr(struct nvidia_par *par, u8 index, u8 value) +{ + VGA_WR08(par->PVIO, VGA_GFX_I, index); + VGA_WR08(par->PVIO, VGA_GFX_D, value); +} +u8 NVReadGr(struct nvidia_par *par, u8 index) +{ + VGA_WR08(par->PVIO, VGA_GFX_I, index); + return (VGA_RD08(par->PVIO, VGA_GFX_D)); +} +void NVWriteSeq(struct nvidia_par *par, u8 index, u8 value) +{ + VGA_WR08(par->PVIO, VGA_SEQ_I, index); + VGA_WR08(par->PVIO, VGA_SEQ_D, value); +} +u8 NVReadSeq(struct nvidia_par *par, u8 index) +{ + VGA_WR08(par->PVIO, VGA_SEQ_I, index); + return (VGA_RD08(par->PVIO, VGA_SEQ_D)); +} +void NVWriteAttr(struct nvidia_par *par, u8 index, u8 value) +{ + volatile u8 tmp; + + tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a); + if (par->paletteEnabled) + index &= ~0x20; + else + index |= 0x20; + VGA_WR08(par->PCIO, VGA_ATT_IW, index); + VGA_WR08(par->PCIO, VGA_ATT_W, value); +} +u8 NVReadAttr(struct nvidia_par *par, u8 index) +{ + volatile u8 tmp; + + tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a); + if (par->paletteEnabled) + index &= ~0x20; + else + index |= 0x20; + VGA_WR08(par->PCIO, VGA_ATT_IW, index); + return (VGA_RD08(par->PCIO, VGA_ATT_R)); +} +void NVWriteMiscOut(struct nvidia_par *par, u8 value) +{ + VGA_WR08(par->PVIO, VGA_MIS_W, value); +} +u8 NVReadMiscOut(struct nvidia_par *par) +{ + return (VGA_RD08(par->PVIO, VGA_MIS_R)); +} +#if 0 +void NVEnablePalette(struct nvidia_par *par) +{ + volatile u8 tmp; + + tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a); + VGA_WR08(par->PCIO, VGA_ATT_IW, 0x00); + par->paletteEnabled = 1; +} +void NVDisablePalette(struct nvidia_par *par) +{ + volatile u8 tmp; + + tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a); + VGA_WR08(par->PCIO, VGA_ATT_IW, 0x20); + par->paletteEnabled = 0; +} +#endif /* 0 */ +void NVWriteDacMask(struct nvidia_par *par, u8 value) +{ + VGA_WR08(par->PDIO, VGA_PEL_MSK, value); +} +#if 0 +u8 NVReadDacMask(struct nvidia_par *par) +{ + return (VGA_RD08(par->PDIO, VGA_PEL_MSK)); +} +#endif /* 0 */ +void NVWriteDacReadAddr(struct nvidia_par *par, u8 value) +{ + VGA_WR08(par->PDIO, VGA_PEL_IR, value); +} +void NVWriteDacWriteAddr(struct nvidia_par *par, u8 value) +{ + VGA_WR08(par->PDIO, VGA_PEL_IW, value); +} +void NVWriteDacData(struct nvidia_par *par, u8 value) +{ + VGA_WR08(par->PDIO, VGA_PEL_D, value); +} +u8 NVReadDacData(struct nvidia_par *par) +{ + return (VGA_RD08(par->PDIO, VGA_PEL_D)); +} + +static int NVIsConnected(struct nvidia_par *par, int output) +{ + volatile u32 __iomem *PRAMDAC = par->PRAMDAC0; + u32 reg52C, reg608; + int present; + + if (output) + PRAMDAC += 0x800; + + reg52C = NV_RD32(PRAMDAC, 0x052C); + reg608 = NV_RD32(PRAMDAC, 0x0608); + + NV_WR32(PRAMDAC, 0x0608, reg608 & ~0x00010000); + + NV_WR32(PRAMDAC, 0x052C, reg52C & 0x0000FEEE); + msleep(1); + NV_WR32(PRAMDAC, 0x052C, NV_RD32(PRAMDAC, 0x052C) | 1); + + NV_WR32(par->PRAMDAC0, 0x0610, 0x94050140); + NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) | + 0x00001000); + + msleep(1); + + present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? 1 : 0; + + if (present) + printk("nvidiafb: CRTC%i found\n", output); + else + printk("nvidiafb: CRTC%i not found\n", output); + + NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) & + 0x0000EFFF); + + NV_WR32(PRAMDAC, 0x052C, reg52C); + NV_WR32(PRAMDAC, 0x0608, reg608); + + return present; +} + +static void NVSelectHeadRegisters(struct nvidia_par *par, int head) +{ + if (head) { + par->PCIO = par->PCIO0 + 0x2000; + par->PCRTC = par->PCRTC0 + 0x800; + par->PRAMDAC = par->PRAMDAC0 + 0x800; + par->PDIO = par->PDIO0 + 0x2000; + } else { + par->PCIO = par->PCIO0; + par->PCRTC = par->PCRTC0; + par->PRAMDAC = par->PRAMDAC0; + par->PDIO = par->PDIO0; + } +} + +static void nv4GetConfig(struct nvidia_par *par) +{ + if (NV_RD32(par->PFB, 0x0000) & 0x00000100) { + par->RamAmountKBytes = + ((NV_RD32(par->PFB, 0x0000) >> 12) & 0x0F) * 1024 * 2 + + 1024 * 2; + } else { + switch (NV_RD32(par->PFB, 0x0000) & 0x00000003) { + case 0: + par->RamAmountKBytes = 1024 * 32; + break; + case 1: + par->RamAmountKBytes = 1024 * 4; + break; + case 2: + par->RamAmountKBytes = 1024 * 8; + break; + case 3: + default: + par->RamAmountKBytes = 1024 * 16; + break; + } + } + par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & 0x00000040) ? + 14318 : 13500; + par->CURSOR = &par->PRAMIN[0x1E00]; + par->MinVClockFreqKHz = 12000; + par->MaxVClockFreqKHz = 350000; +} + +static void nv10GetConfig(struct nvidia_par *par) +{ + struct pci_dev *dev; + u32 implementation = par->Chipset & 0x0ff0; + +#ifdef __BIG_ENDIAN + /* turn on big endian register access */ + if (!(NV_RD32(par->PMC, 0x0004) & 0x01000001)) { + NV_WR32(par->PMC, 0x0004, 0x01000001); + mb(); + } +#endif + + dev = pci_find_slot(0, 1); + if ((par->Chipset && 0xffff) == 0x01a0) { + int amt = 0; + + pci_read_config_dword(dev, 0x7c, &amt); + par->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024; + } else if ((par->Chipset & 0xffff) == 0x01f0) { + int amt = 0; + + pci_read_config_dword(dev, 0x84, &amt); + par->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024; + } else { + par->RamAmountKBytes = + (NV_RD32(par->PFB, 0x020C) & 0xFFF00000) >> 10; + } + + par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 6)) ? + 14318 : 13500; + + if (par->twoHeads && (implementation != 0x0110)) { + if (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 22)) + par->CrystalFreqKHz = 27000; + } + + par->CursorStart = (par->RamAmountKBytes - 96) * 1024; + par->CURSOR = NULL; /* can't set this here */ + par->MinVClockFreqKHz = 12000; + par->MaxVClockFreqKHz = par->twoStagePLL ? 400000 : 350000; +} + +void NVCommonSetup(struct fb_info *info) +{ + struct nvidia_par *par = info->par; + struct fb_var_screeninfo var; + u16 implementation = par->Chipset & 0x0ff0; + u8 *edidA = NULL, *edidB = NULL; + struct fb_monspecs monitorA, monitorB; + struct fb_monspecs *monA = NULL, *monB = NULL; + int mobile = 0; + int tvA = 0; + int tvB = 0; + int FlatPanel = -1; /* really means the CRTC is slaved */ + int Television = 0; + + par->PRAMIN = par->REGS + (0x00710000 / 4); + par->PCRTC0 = par->REGS + (0x00600000 / 4); + par->PRAMDAC0 = par->REGS + (0x00680000 / 4); + par->PFB = par->REGS + (0x00100000 / 4); + par->PFIFO = par->REGS + (0x00002000 / 4); + par->PGRAPH = par->REGS + (0x00400000 / 4); + par->PEXTDEV = par->REGS + (0x00101000 / 4); + par->PTIMER = par->REGS + (0x00009000 / 4); + par->PMC = par->REGS + (0x00000000 / 4); + par->FIFO = par->REGS + (0x00800000 / 4); + + /* 8 bit registers */ + par->PCIO0 = (u8 __iomem *) par->REGS + 0x00601000; + par->PDIO0 = (u8 __iomem *) par->REGS + 0x00681000; + par->PVIO = (u8 __iomem *) par->REGS + 0x000C0000; + + par->twoHeads = (par->Architecture >= NV_ARCH_10) && + (implementation != 0x0100) && + (implementation != 0x0150) && + (implementation != 0x01A0) && (implementation != 0x0200); + + par->fpScaler = (par->FpScale && par->twoHeads && + (implementation != 0x0110)); + + par->twoStagePLL = (implementation == 0x0310) || + (implementation == 0x0340) || (par->Architecture >= NV_ARCH_40); + + par->WaitVSyncPossible = (par->Architecture >= NV_ARCH_10) && + (implementation != 0x0100); + + par->BlendingPossible = ((par->Chipset & 0xffff) != 0x0020); + + /* look for known laptop chips */ + switch (par->Chipset & 0xffff) { + case 0x0112: + case 0x0174: + case 0x0175: + case 0x0176: + case 0x0177: + case 0x0179: + case 0x017C: + case 0x017D: + case 0x0186: + case 0x0187: + case 0x018D: + case 0x0286: + case 0x028C: + case 0x0316: + case 0x0317: + case 0x031A: + case 0x031B: + case 0x031C: + case 0x031D: + case 0x031E: + case 0x031F: + case 0x0324: + case 0x0325: + case 0x0328: + case 0x0329: + case 0x032C: + case 0x032D: + case 0x0347: + case 0x0348: + case 0x0349: + case 0x034B: + case 0x034C: + case 0x0160: + case 0x0166: + case 0x00C8: + case 0x00CC: + case 0x0144: + case 0x0146: + case 0x0147: + case 0x0148: + mobile = 1; + break; + default: + break; + } + + if (par->Architecture == NV_ARCH_04) + nv4GetConfig(par); + else + nv10GetConfig(par); + + NVSelectHeadRegisters(par, 0); + + NVLockUnlock(par, 0); + + par->IOBase = (NVReadMiscOut(par) & 0x01) ? 0x3d0 : 0x3b0; + + par->Television = 0; + + nvidia_create_i2c_busses(par); + if (!par->twoHeads) { + par->CRTCnumber = 0; + nvidia_probe_i2c_connector(par, 1, &edidA); + if (edidA && !fb_parse_edid(edidA, &var)) { + printk("nvidiafb: EDID found from BUS1\n"); + monA = &monitorA; + fb_edid_to_monspecs(edidA, monA); + FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0; + + /* NV4 doesn't support FlatPanels */ + if ((par->Chipset & 0x0fff) <= 0x0020) + FlatPanel = 0; + } else { + VGA_WR08(par->PCIO, 0x03D4, 0x28); + if (VGA_RD08(par->PCIO, 0x03D5) & 0x80) { + VGA_WR08(par->PCIO, 0x03D4, 0x33); + if (!(VGA_RD08(par->PCIO, 0x03D5) & 0x01)) + Television = 1; + FlatPanel = 1; + } else { + FlatPanel = 0; + } + printk("nvidiafb: HW is currently programmed for %s\n", + FlatPanel ? (Television ? "TV" : "DFP") : + "CRT"); + } + + if (par->FlatPanel == -1) { + par->FlatPanel = FlatPanel; + par->Television = Television; + } else { + printk("nvidiafb: Forcing display type to %s as " + "specified\n", par->FlatPanel ? "DFP" : "CRT"); + } + } else { + u8 outputAfromCRTC, outputBfromCRTC; + int CRTCnumber = -1; + u8 slaved_on_A, slaved_on_B; + int analog_on_A, analog_on_B; + u32 oldhead; + u8 cr44; + + if (implementation != 0x0110) { + if (NV_RD32(par->PRAMDAC0, 0x0000052C) & 0x100) + outputAfromCRTC = 1; + else + outputAfromCRTC = 0; + if (NV_RD32(par->PRAMDAC0, 0x0000252C) & 0x100) + outputBfromCRTC = 1; + else + outputBfromCRTC = 0; + analog_on_A = NVIsConnected(par, 0); + analog_on_B = NVIsConnected(par, 1); + } else { + outputAfromCRTC = 0; + outputBfromCRTC = 1; + analog_on_A = 0; + analog_on_B = 0; + } + + VGA_WR08(par->PCIO, 0x03D4, 0x44); + cr44 = VGA_RD08(par->PCIO, 0x03D5); + + VGA_WR08(par->PCIO, 0x03D5, 3); + NVSelectHeadRegisters(par, 1); + NVLockUnlock(par, 0); + + VGA_WR08(par->PCIO, 0x03D4, 0x28); + slaved_on_B = VGA_RD08(par->PCIO, 0x03D5) & 0x80; + if (slaved_on_B) { + VGA_WR08(par->PCIO, 0x03D4, 0x33); + tvB = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01); + } + + VGA_WR08(par->PCIO, 0x03D4, 0x44); + VGA_WR08(par->PCIO, 0x03D5, 0); + NVSelectHeadRegisters(par, 0); + NVLockUnlock(par, 0); + + VGA_WR08(par->PCIO, 0x03D4, 0x28); + slaved_on_A = VGA_RD08(par->PCIO, 0x03D5) & 0x80; + if (slaved_on_A) { + VGA_WR08(par->PCIO, 0x03D4, 0x33); + tvA = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01); + } + + oldhead = NV_RD32(par->PCRTC0, 0x00000860); + NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010); + + nvidia_probe_i2c_connector(par, 1, &edidA); + if (edidA && !fb_parse_edid(edidA, &var)) { + printk("nvidiafb: EDID found from BUS1\n"); + monA = &monitorA; + fb_edid_to_monspecs(edidA, monA); + } + + nvidia_probe_i2c_connector(par, 2, &edidB); + if (edidB && !fb_parse_edid(edidB, &var)) { + printk("nvidiafb: EDID found from BUS2\n"); + monB = &monitorB; + fb_edid_to_monspecs(edidB, monB); + } + + if (slaved_on_A && !tvA) { + CRTCnumber = 0; + FlatPanel = 1; + printk("nvidiafb: CRTC 0 is currently programmed for " + "DFP\n"); + } else if (slaved_on_B && !tvB) { + CRTCnumber = 1; + FlatPanel = 1; + printk("nvidiafb: CRTC 1 is currently programmed " + "for DFP\n"); + } else if (analog_on_A) { + CRTCnumber = outputAfromCRTC; + FlatPanel = 0; + printk("nvidiafb: CRTC %i appears to have a " + "CRT attached\n", CRTCnumber); + } else if (analog_on_B) { + CRTCnumber = outputBfromCRTC; + FlatPanel = 0; + printk("nvidiafb: CRTC %i" + "appears to have a " + "CRT attached\n", CRTCnumber); + } else if (slaved_on_A) { + CRTCnumber = 0; + FlatPanel = 1; + Television = 1; + printk("nvidiafb: CRTC 0 is currently programmed " + "for TV\n"); + } else if (slaved_on_B) { + CRTCnumber = 1; + FlatPanel = 1; + Television = 1; + printk("nvidiafb: CRTC 1 is currently programmed for " + "TV\n"); + } else if (monA) { + FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0; + } else if (monB) { + FlatPanel = (monB->input & FB_DISP_DDI) ? 1 : 0; + } + + if (par->FlatPanel == -1) { + if (FlatPanel != -1) { + par->FlatPanel = FlatPanel; + par->Television = Television; + } else { + printk("nvidiafb: Unable to detect display " + "type...\n"); + if (mobile) { + printk("...On a laptop, assuming " + "DFP\n"); + par->FlatPanel = 1; + } else { + printk("...Using default of CRT\n"); + par->FlatPanel = 0; + } + } + } else { + printk("nvidiafb: Forcing display type to %s as " + "specified\n", par->FlatPanel ? "DFP" : "CRT"); + } + + if (par->CRTCnumber == -1) { + if (CRTCnumber != -1) + par->CRTCnumber = CRTCnumber; + else { + printk("nvidiafb: Unable to detect which " + "CRTCNumber...\n"); + if (par->FlatPanel) + par->CRTCnumber = 1; + else + par->CRTCnumber = 0; + printk("...Defaulting to CRTCNumber %i\n", + par->CRTCnumber); + } + } else { + printk("nvidiafb: Forcing CRTCNumber %i as " + "specified\n", par->CRTCnumber); + } + + if (monA) { + if (((monA->input & FB_DISP_DDI) && + par->FlatPanel) || + ((!(monA->input & FB_DISP_DDI)) && + !par->FlatPanel)) { + if (monB) { + fb_destroy_modedb(monB->modedb); + monB = NULL; + } + } else { + fb_destroy_modedb(monA->modedb); + monA = NULL; + } + } + + if (monB) { + if (((monB->input & FB_DISP_DDI) && + !par->FlatPanel) || + ((!(monB->input & FB_DISP_DDI)) && + par->FlatPanel)) { + fb_destroy_modedb(monB->modedb); + monB = NULL; + } else + monA = monB; + } + + if (implementation == 0x0110) + cr44 = par->CRTCnumber * 0x3; + + NV_WR32(par->PCRTC0, 0x00000860, oldhead); + + VGA_WR08(par->PCIO, 0x03D4, 0x44); + VGA_WR08(par->PCIO, 0x03D5, cr44); + NVSelectHeadRegisters(par, par->CRTCnumber); + } + + printk("nvidiafb: Using %s on CRTC %i\n", + par->FlatPanel ? (par->Television ? "TV" : "DFP") : "CRT", + par->CRTCnumber); + + if (par->FlatPanel && !par->Television) { + par->fpWidth = NV_RD32(par->PRAMDAC, 0x0820) + 1; + par->fpHeight = NV_RD32(par->PRAMDAC, 0x0800) + 1; + par->fpSyncs = NV_RD32(par->PRAMDAC, 0x0848) & 0x30000033; + + printk("Panel size is %i x %i\n", par->fpWidth, par->fpHeight); + } + + if (monA) + info->monspecs = *monA; + + kfree(edidA); + kfree(edidB); +} diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h new file mode 100644 index 000000000000..e4a5b1da71c4 --- /dev/null +++ b/drivers/video/nvidia/nv_type.h @@ -0,0 +1,174 @@ +#ifndef __NV_TYPE_H__ +#define __NV_TYPE_H__ + +#include <linux/fb.h> +#include <linux/types.h> +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/i2c-algo-bit.h> + +#define NV_ARCH_04 0x04 +#define NV_ARCH_10 0x10 +#define NV_ARCH_20 0x20 +#define NV_ARCH_30 0x30 +#define NV_ARCH_40 0x40 + +#define BITMASK(t,b) (((unsigned)(1U << (((t)-(b)+1)))-1) << (b)) +#define MASKEXPAND(mask) BITMASK(1?mask,0?mask) +#define SetBF(mask,value) ((value) << (0?mask)) +#define GetBF(var,mask) (((unsigned)((var) & MASKEXPAND(mask))) >> (0?mask) ) +#define SetBitField(value,from,to) SetBF(to, GetBF(value,from)) +#define SetBit(n) (1<<(n)) +#define Set8Bits(value) ((value)&0xff) + +#define V_DBLSCAN 1 + +typedef struct { + int bitsPerPixel; + int depth; + int displayWidth; + int weight; +} NVFBLayout; + +#define NUM_SEQ_REGS 0x05 +#define NUM_CRT_REGS 0x41 +#define NUM_GRC_REGS 0x09 +#define NUM_ATC_REGS 0x15 + +struct nvidia_par; + +struct nvidia_i2c_chan { + struct nvidia_par *par; + unsigned long ddc_base; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; +}; + +typedef struct _riva_hw_state { + u8 attr[NUM_ATC_REGS]; + u8 crtc[NUM_CRT_REGS]; + u8 gra[NUM_GRC_REGS]; + u8 seq[NUM_SEQ_REGS]; + u8 misc_output; + u32 bpp; + u32 width; + u32 height; + u32 interlace; + u32 repaint0; + u32 repaint1; + u32 screen; + u32 scale; + u32 dither; + u32 extra; + u32 fifo; + u32 pixel; + u32 horiz; + u32 arbitration0; + u32 arbitration1; + u32 pll; + u32 pllB; + u32 vpll; + u32 vpll2; + u32 vpllB; + u32 vpll2B; + u32 pllsel; + u32 general; + u32 crtcOwner; + u32 head; + u32 head2; + u32 config; + u32 cursorConfig; + u32 cursor0; + u32 cursor1; + u32 cursor2; + u32 timingH; + u32 timingV; + u32 displayV; + u32 crtcSync; +} RIVA_HW_STATE; + +struct riva_regs { + RIVA_HW_STATE ext; +}; + +struct nvidia_par { + RIVA_HW_STATE SavedReg; + RIVA_HW_STATE ModeReg; + RIVA_HW_STATE *CurrentState; + u32 pseudo_palette[16]; + struct pci_dev *pci_dev; + u32 Architecture; + u32 CursorStart; + int Chipset; + int bus; + unsigned long FbAddress; + u8 __iomem *FbStart; + u32 FbMapSize; + u32 FbUsableSize; + u32 ScratchBufferSize; + u32 ScratchBufferStart; + int FpScale; + u32 MinVClockFreqKHz; + u32 MaxVClockFreqKHz; + u32 CrystalFreqKHz; + u32 RamAmountKBytes; + u32 IOBase; + NVFBLayout CurrentLayout; + int cursor_reset; + int lockup; + int videoKey; + int FlatPanel; + int FPDither; + int Television; + int CRTCnumber; + int alphaCursor; + int twoHeads; + int twoStagePLL; + int fpScaler; + int fpWidth; + int fpHeight; + int PanelTweak; + int paneltweak; + u32 crtcSync_read; + u32 fpSyncs; + u32 dmaPut; + u32 dmaCurrent; + u32 dmaFree; + u32 dmaMax; + u32 __iomem *dmaBase; + u32 currentRop; + int WaitVSyncPossible; + int BlendingPossible; + u32 paletteEnabled; + u32 forceCRTC; + u8 DDCBase; +#ifdef CONFIG_MTRR + struct { + int vram; + int vram_valid; + } mtrr; +#endif + struct nvidia_i2c_chan chan[3]; + + volatile u32 __iomem *REGS; + volatile u32 __iomem *PCRTC0; + volatile u32 __iomem *PCRTC; + volatile u32 __iomem *PRAMDAC0; + volatile u32 __iomem *PFB; + volatile u32 __iomem *PFIFO; + volatile u32 __iomem *PGRAPH; + volatile u32 __iomem *PEXTDEV; + volatile u32 __iomem *PTIMER; + volatile u32 __iomem *PMC; + volatile u32 __iomem *PRAMIN; + volatile u32 __iomem *FIFO; + volatile u32 __iomem *CURSOR; + volatile u8 __iomem *PCIO0; + volatile u8 __iomem *PCIO; + volatile u8 __iomem *PVIO; + volatile u8 __iomem *PDIO0; + volatile u8 __iomem *PDIO; + volatile u32 __iomem *PRAMDAC; +}; + +#endif /* __NV_TYPE_H__ */ diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c new file mode 100644 index 000000000000..3a6555a8aaa2 --- /dev/null +++ b/drivers/video/nvidia/nvidia.c @@ -0,0 +1,1729 @@ +/* + * linux/drivers/video/nvidia/nvidia.c - nVidia fb driver + * + * Copyright 2004 Antonino Daplas <adaplas@pol.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. + * + */ + +#include <linux/config.h> +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif +#ifdef CONFIG_PPC_OF +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#endif +#ifdef CONFIG_PMAC_BACKLIGHT +#include <asm/backlight.h> +#endif + +#include "nv_local.h" +#include "nv_type.h" +#include "nv_proto.h" +#include "nv_dma.h" + +#ifndef CONFIG_PCI /* sanity check */ +#error This driver requires PCI support. +#endif + +#undef CONFIG_FB_NVIDIA_DEBUG +#ifdef CONFIG_FB_NVIDIA_DEBUG +#define NVTRACE printk +#else +#define NVTRACE if (0) printk +#endif + +#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __FUNCTION__) +#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __FUNCTION__) + +#ifdef CONFIG_FB_NVIDIA_DEBUG +#define assert(expr) \ + if (!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n",\ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + BUG(); \ + } +#else +#define assert(expr) +#endif + +#define PFX "nvidiafb: " + +/* HW cursor parameters */ +#define MAX_CURS 32 + +static struct pci_device_id nvidiafb_pci_tbl[] = { + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0252, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0313, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0316, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0317, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x031D, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x031E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x031F, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0329, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x032F, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0345, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0349, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x034B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x034F, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x00c0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A_LE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_GO1400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x00cd, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_1400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0142, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0143, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0144, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0145, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0146, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0147, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0148, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0149, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x014b, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x14c, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x014d, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0160, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0162, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0163, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0165, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0169, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x016b, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x016c, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x016d, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x016e, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0210, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x021d, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x021e, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0220, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0221, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0222, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_NVIDIA, 0x0228, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} /* terminate list */ +}; + +MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl); + +/* command line data, set in nvidiafb_setup() */ +static int flatpanel __devinitdata = -1; /* Autodetect later */ +static int forceCRTC __devinitdata = -1; +static int hwcur __devinitdata = 0; +static int noaccel __devinitdata = 0; +static int noscale __devinitdata = 0; +static int paneltweak __devinitdata = 0; +#ifdef CONFIG_MTRR +static int nomtrr __devinitdata = 0; +#endif + +static char *mode_option __devinitdata = NULL; + +static struct fb_fix_screeninfo __devinitdata nvidiafb_fix = { + .type = FB_TYPE_PACKED_PIXELS, + .xpanstep = 8, + .ypanstep = 1, +}; + +static struct fb_var_screeninfo __devinitdata nvidiafb_default_var = { + .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}, + .transp = {0, 0, 0}, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .pixclock = 39721, + .left_margin = 40, + .right_margin = 24, + .upper_margin = 32, + .lower_margin = 11, + .hsync_len = 96, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED +}; + +/* + * Backlight control + */ +#ifdef CONFIG_PMAC_BACKLIGHT + +static int nvidia_backlight_levels[] = { + 0x158, + 0x192, + 0x1c6, + 0x200, + 0x234, + 0x268, + 0x2a2, + 0x2d6, + 0x310, + 0x344, + 0x378, + 0x3b2, + 0x3e6, + 0x41a, + 0x454, + 0x534, +}; + +/* ------------------------------------------------------------------------- * + * + * Backlight operations + * + * ------------------------------------------------------------------------- */ + +static int nvidia_set_backlight_enable(int on, int level, void *data) +{ + struct nvidia_par *par = (struct nvidia_par *)data; + u32 tmp_pcrt, tmp_pmc, fpcontrol; + + tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF; + tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC; + fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC; + + if (on && (level > BACKLIGHT_OFF)) { + tmp_pcrt |= 0x1; + tmp_pmc |= (1 << 31); // backlight bit + tmp_pmc |= nvidia_backlight_levels[level - 1] << 16; + } + + if (on) + fpcontrol |= par->fpSyncs; + else + fpcontrol |= 0x20000022; + + NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt); + NV_WR32(par->PMC, 0x10F0, tmp_pmc); + NV_WR32(par->PRAMDAC, 0x848, fpcontrol); + + return 0; +} + +static int nvidia_set_backlight_level(int level, void *data) +{ + return nvidia_set_backlight_enable(1, level, data); +} + +static struct backlight_controller nvidia_backlight_controller = { + nvidia_set_backlight_enable, + nvidia_set_backlight_level +}; + +#endif /* CONFIG_PMAC_BACKLIGHT */ + +static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8, + u16 bg, u16 fg, u32 w, u32 h) +{ + int i, j, k = 0; + u32 b, tmp; + u32 *data = (u32 *) data8; + + w = (w + 1) & ~1; + + for (i = 0; i < h; i++) { + b = *data++; + reverse_order(&b); + + for (j = 0; j < w / 2; j++) { + tmp = 0; +#if defined (__BIG_ENDIAN) + tmp = (b & (1 << 31)) ? fg << 16 : bg << 16; + b <<= 1; + tmp |= (b & (1 << 31)) ? fg : bg; + b <<= 1; +#else + tmp = (b & 1) ? fg : bg; + b >>= 1; + tmp |= (b & 1) ? fg << 16 : bg << 16; + b >>= 1; +#endif + NV_WR32(&par->CURSOR[k++], 0, tmp); + } + k += (MAX_CURS - w) / 2; + } +} + +static void nvidia_write_clut(struct nvidia_par *par, + u8 regnum, u8 red, u8 green, u8 blue) +{ + NVWriteDacMask(par, 0xff); + NVWriteDacWriteAddr(par, regnum); + NVWriteDacData(par, red); + NVWriteDacData(par, green); + NVWriteDacData(par, blue); +} + +static void nvidia_read_clut(struct nvidia_par *par, + u8 regnum, u8 * red, u8 * green, u8 * blue) +{ + NVWriteDacMask(par, 0xff); + NVWriteDacReadAddr(par, regnum); + *red = NVReadDacData(par); + *green = NVReadDacData(par); + *blue = NVReadDacData(par); +} + +static int nvidia_panel_tweak(struct nvidia_par *par, + struct _riva_hw_state *state) +{ + int tweak = 0; + + if (par->paneltweak) { + tweak = par->paneltweak; + } else { + /* begin flat panel hacks */ + /* This is unfortunate, but some chips need this register + tweaked or else you get artifacts where adjacent pixels are + swapped. There are no hard rules for what to set here so all + we can do is experiment and apply hacks. */ + + if(((par->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) { + /* At least one NV34 laptop needs this workaround. */ + tweak = -1; + } + + if((par->Chipset & 0xfff0) == 0x0310) { + tweak = 1; + } + /* end flat panel hacks */ + } + + return tweak; +} + +static void nvidia_save_vga(struct nvidia_par *par, + struct _riva_hw_state *state) +{ + int i; + + NVTRACE_ENTER(); + NVLockUnlock(par, 0); + + NVUnloadStateExt(par, state); + + state->misc_output = NVReadMiscOut(par); + + for (i = 0; i < NUM_CRT_REGS; i++) + state->crtc[i] = NVReadCrtc(par, i); + + for (i = 0; i < NUM_ATC_REGS; i++) + state->attr[i] = NVReadAttr(par, i); + + for (i = 0; i < NUM_GRC_REGS; i++) + state->gra[i] = NVReadGr(par, i); + + for (i = 0; i < NUM_SEQ_REGS; i++) + state->seq[i] = NVReadSeq(par, i); + NVTRACE_LEAVE(); +} + +static void nvidia_write_regs(struct nvidia_par *par) +{ + struct _riva_hw_state *state = &par->ModeReg; + int i; + + NVTRACE_ENTER(); + NVWriteCrtc(par, 0x11, 0x00); + + NVLockUnlock(par, 0); + + NVLoadStateExt(par, state); + + NVWriteMiscOut(par, state->misc_output); + + for (i = 0; i < NUM_CRT_REGS; i++) { + switch (i) { + case 0x19: + case 0x20 ... 0x40: + break; + default: + NVWriteCrtc(par, i, state->crtc[i]); + } + } + + for (i = 0; i < NUM_ATC_REGS; i++) + NVWriteAttr(par, i, state->attr[i]); + + for (i = 0; i < NUM_GRC_REGS; i++) + NVWriteGr(par, i, state->gra[i]); + + for (i = 0; i < NUM_SEQ_REGS; i++) + NVWriteSeq(par, i, state->seq[i]); + NVTRACE_LEAVE(); +} + +static int nvidia_calc_regs(struct fb_info *info) +{ + struct nvidia_par *par = info->par; + struct _riva_hw_state *state = &par->ModeReg; + int i, depth = fb_get_color_depth(&info->var); + int h_display = info->var.xres / 8 - 1; + int h_start = (info->var.xres + info->var.right_margin) / 8 - 1; + int h_end = (info->var.xres + info->var.right_margin + + info->var.hsync_len) / 8 - 1; + int h_total = (info->var.xres + info->var.right_margin + + info->var.hsync_len + info->var.left_margin) / 8 - 5; + int h_blank_s = h_display; + int h_blank_e = h_total + 4; + int v_display = info->var.yres - 1; + int v_start = info->var.yres + info->var.lower_margin - 1; + int v_end = (info->var.yres + info->var.lower_margin + + info->var.vsync_len) - 1; + int v_total = (info->var.yres + info->var.lower_margin + + info->var.vsync_len + info->var.upper_margin) - 2; + int v_blank_s = v_display; + int v_blank_e = v_total + 1; + + /* + * Set all CRTC values. + */ + + if (info->var.vmode & FB_VMODE_INTERLACED) + v_total |= 1; + + if (par->FlatPanel == 1) { + v_start = v_total - 3; + v_end = v_total - 2; + v_blank_s = v_start; + h_start = h_total - 5; + h_end = h_total - 2; + h_blank_e = h_total + 4; + } + + state->crtc[0x0] = Set8Bits(h_total); + state->crtc[0x1] = Set8Bits(h_display); + state->crtc[0x2] = Set8Bits(h_blank_s); + state->crtc[0x3] = SetBitField(h_blank_e, 4: 0, 4:0) + | SetBit(7); + state->crtc[0x4] = Set8Bits(h_start); + state->crtc[0x5] = SetBitField(h_blank_e, 5: 5, 7:7) + | SetBitField(h_end, 4: 0, 4:0); + state->crtc[0x6] = SetBitField(v_total, 7: 0, 7:0); + state->crtc[0x7] = SetBitField(v_total, 8: 8, 0:0) + | SetBitField(v_display, 8: 8, 1:1) + | SetBitField(v_start, 8: 8, 2:2) + | SetBitField(v_blank_s, 8: 8, 3:3) + | SetBit(4) + | SetBitField(v_total, 9: 9, 5:5) + | SetBitField(v_display, 9: 9, 6:6) + | SetBitField(v_start, 9: 9, 7:7); + state->crtc[0x9] = SetBitField(v_blank_s, 9: 9, 5:5) + | SetBit(6) + | ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0x00); + state->crtc[0x10] = Set8Bits(v_start); + state->crtc[0x11] = SetBitField(v_end, 3: 0, 3:0) | SetBit(5); + state->crtc[0x12] = Set8Bits(v_display); + state->crtc[0x13] = ((info->var.xres_virtual / 8) * + (info->var.bits_per_pixel / 8)); + state->crtc[0x15] = Set8Bits(v_blank_s); + state->crtc[0x16] = Set8Bits(v_blank_e); + + state->attr[0x10] = 0x01; + + if (par->Television) + state->attr[0x11] = 0x00; + + state->screen = SetBitField(h_blank_e, 6: 6, 4:4) + | SetBitField(v_blank_s, 10: 10, 3:3) + | SetBitField(v_start, 10: 10, 2:2) + | SetBitField(v_display, 10: 10, 1:1) + | SetBitField(v_total, 10: 10, 0:0); + + state->horiz = SetBitField(h_total, 8: 8, 0:0) + | SetBitField(h_display, 8: 8, 1:1) + | SetBitField(h_blank_s, 8: 8, 2:2) + | SetBitField(h_start, 8: 8, 3:3); + + state->extra = SetBitField(v_total, 11: 11, 0:0) + | SetBitField(v_display, 11: 11, 2:2) + | SetBitField(v_start, 11: 11, 4:4) + | SetBitField(v_blank_s, 11: 11, 6:6); + + if (info->var.vmode & FB_VMODE_INTERLACED) { + h_total = (h_total >> 1) & ~1; + state->interlace = Set8Bits(h_total); + state->horiz |= SetBitField(h_total, 8: 8, 4:4); + } else { + state->interlace = 0xff; /* interlace off */ + } + + /* + * Calculate the extended registers. + */ + + if (depth < 24) + i = depth; + else + i = 32; + + if (par->Architecture >= NV_ARCH_10) + par->CURSOR = (volatile u32 __iomem *)(info->screen_base + + par->CursorStart); + + if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) + state->misc_output &= ~0x40; + else + state->misc_output |= 0x40; + if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) + state->misc_output &= ~0x80; + else + state->misc_output |= 0x80; + + NVCalcStateExt(par, state, i, info->var.xres_virtual, + info->var.xres, info->var.yres_virtual, + 1000000000 / info->var.pixclock, info->var.vmode); + + state->scale = NV_RD32(par->PRAMDAC, 0x00000848) & 0xfff000ff; + if (par->FlatPanel == 1) { + state->pixel |= (1 << 7); + + if (!par->fpScaler || (par->fpWidth <= info->var.xres) + || (par->fpHeight <= info->var.yres)) { + state->scale |= (1 << 8); + } + + if (!par->crtcSync_read) { + state->crtcSync = NV_RD32(par->PRAMDAC, 0x0828); + par->crtcSync_read = 1; + } + + par->PanelTweak = nvidia_panel_tweak(par, state); + } + + state->vpll = state->pll; + state->vpll2 = state->pll; + state->vpllB = state->pllB; + state->vpll2B = state->pllB; + + VGA_WR08(par->PCIO, 0x03D4, 0x1C); + state->fifo = VGA_RD08(par->PCIO, 0x03D5) & ~(1<<5); + + if (par->CRTCnumber) { + state->head = NV_RD32(par->PCRTC0, 0x00000860) & ~0x00001000; + state->head2 = NV_RD32(par->PCRTC0, 0x00002860) | 0x00001000; + state->crtcOwner = 3; + state->pllsel |= 0x20000800; + state->vpll = NV_RD32(par->PRAMDAC0, 0x00000508); + if (par->twoStagePLL) + state->vpllB = NV_RD32(par->PRAMDAC0, 0x00000578); + } else if (par->twoHeads) { + state->head = NV_RD32(par->PCRTC0, 0x00000860) | 0x00001000; + state->head2 = NV_RD32(par->PCRTC0, 0x00002860) & ~0x00001000; + state->crtcOwner = 0; + state->vpll2 = NV_RD32(par->PRAMDAC0, 0x0520); + if (par->twoStagePLL) + state->vpll2B = NV_RD32(par->PRAMDAC0, 0x057C); + } + + state->cursorConfig = 0x00000100; + + if (info->var.vmode & FB_VMODE_DOUBLE) + state->cursorConfig |= (1 << 4); + + if (par->alphaCursor) { + if ((par->Chipset & 0x0ff0) != 0x0110) + state->cursorConfig |= 0x04011000; + else + state->cursorConfig |= 0x14011000; + state->general |= (1 << 29); + } else + state->cursorConfig |= 0x02000000; + + if (par->twoHeads) { + if ((par->Chipset & 0x0ff0) == 0x0110) { + state->dither = NV_RD32(par->PRAMDAC, 0x0528) & + ~0x00010000; + if (par->FPDither) + state->dither |= 0x00010000; + } else { + state->dither = NV_RD32(par->PRAMDAC, 0x083C) & ~1; + if (par->FPDither) + state->dither |= 1; + } + } + + state->timingH = 0; + state->timingV = 0; + state->displayV = info->var.xres; + + return 0; +} + +static void nvidia_init_vga(struct fb_info *info) +{ + struct nvidia_par *par = info->par; + struct _riva_hw_state *state = &par->ModeReg; + int i; + + for (i = 0; i < 0x10; i++) + state->attr[i] = i; + state->attr[0x10] = 0x41; + state->attr[0x11] = 0x01; + state->attr[0x12] = 0x0f; + state->attr[0x13] = 0x00; + state->attr[0x14] = 0x00; + + memset(state->crtc, 0x00, NUM_CRT_REGS); + state->crtc[0x0a] = 0x20; + state->crtc[0x17] = 0xe3; + state->crtc[0x18] = 0xff; + state->crtc[0x28] = 0x40; + + memset(state->gra, 0x00, NUM_GRC_REGS); + state->gra[0x05] = 0x40; + state->gra[0x06] = 0x05; + state->gra[0x07] = 0x0f; + state->gra[0x08] = 0xff; + + state->seq[0x00] = 0x03; + state->seq[0x01] = 0x01; + state->seq[0x02] = 0x0f; + state->seq[0x03] = 0x00; + state->seq[0x04] = 0x0e; + + state->misc_output = 0xeb; +} + +static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct nvidia_par *par = info->par; + u8 data[MAX_CURS * MAX_CURS / 8]; + u16 fg, bg; + int i, set = cursor->set; + + if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS) + return soft_cursor(info, cursor); + + NVShowHideCursor(par, 0); + + if (par->cursor_reset) { + set = FB_CUR_SETALL; + par->cursor_reset = 0; + } + + if (set & FB_CUR_SETSIZE) + memset_io(par->CURSOR, 0, MAX_CURS * MAX_CURS * 2); + + if (set & FB_CUR_SETPOS) { + u32 xx, yy, temp; + + yy = cursor->image.dy - info->var.yoffset; + xx = cursor->image.dx - info->var.xoffset; + temp = xx & 0xFFFF; + temp |= yy << 16; + + NV_WR32(par->PRAMDAC, 0x0000300, temp); + } + + if (set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) { + u32 bg_idx = cursor->image.bg_color; + u32 fg_idx = cursor->image.fg_color; + u32 s_pitch = (cursor->image.width + 7) >> 3; + u32 d_pitch = MAX_CURS / 8; + u8 *dat = (u8 *) cursor->image.data; + u8 *msk = (u8 *) cursor->mask; + u8 *src; + + src = kmalloc(s_pitch * cursor->image.height, GFP_ATOMIC); + + if (src) { + switch (cursor->rop) { + case ROP_XOR: + for (i = 0; i < s_pitch * cursor->image.height; + i++) + src[i] = dat[i] ^ msk[i]; + break; + case ROP_COPY: + default: + for (i = 0; i < s_pitch * cursor->image.height; + i++) + src[i] = dat[i] & msk[i]; + break; + } + + fb_sysmove_buf_aligned(info, &info->pixmap, data, + d_pitch, src, s_pitch, + cursor->image.height); + + bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) | + ((info->cmap.green[bg_idx] & 0xf8) << 2) | + ((info->cmap.blue[bg_idx] & 0xf8) >> 3) | 1 << 15; + + fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) | + ((info->cmap.green[fg_idx] & 0xf8) << 2) | + ((info->cmap.blue[fg_idx] & 0xf8) >> 3) | 1 << 15; + + NVLockUnlock(par, 0); + + nvidiafb_load_cursor_image(par, data, bg, fg, + cursor->image.width, + cursor->image.height); + kfree(src); + } + } + + if (cursor->enable) + NVShowHideCursor(par, 1); + + return 0; +} + +static int nvidiafb_set_par(struct fb_info *info) +{ + struct nvidia_par *par = info->par; + + NVTRACE_ENTER(); + + NVLockUnlock(par, 1); + if (!par->FlatPanel || (info->var.bits_per_pixel != 24) || + !par->twoHeads) + par->FPDither = 0; + + nvidia_init_vga(info); + nvidia_calc_regs(info); + nvidia_write_regs(par); + + NVLockUnlock(par, 0); + if (par->twoHeads) { + VGA_WR08(par->PCIO, 0x03D4, 0x44); + VGA_WR08(par->PCIO, 0x03D5, par->ModeReg.crtcOwner); + NVLockUnlock(par, 0); + } + + NVWriteCrtc(par, 0x11, 0x00); + info->fix.line_length = (info->var.xres_virtual * + info->var.bits_per_pixel) >> 3; + info->fix.visual = (info->var.bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + + if (info->var.accel_flags) { + info->fbops->fb_imageblit = nvidiafb_imageblit; + info->fbops->fb_fillrect = nvidiafb_fillrect; + info->fbops->fb_copyarea = nvidiafb_copyarea; + info->fbops->fb_sync = nvidiafb_sync; + info->pixmap.scan_align = 4; + info->flags &= ~FBINFO_HWACCEL_DISABLED; + NVResetGraphics(info); + } else { + info->fbops->fb_imageblit = cfb_imageblit; + info->fbops->fb_fillrect = cfb_fillrect; + info->fbops->fb_copyarea = cfb_copyarea; + info->fbops->fb_sync = NULL; + info->pixmap.scan_align = 1; + info->flags |= FBINFO_HWACCEL_DISABLED; + } + + par->cursor_reset = 1; + + NVWriteCrtc(par, 0x11, 0xff); + + NVTRACE_LEAVE(); + return 0; +} + +static int nvidiafb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct nvidia_par *par = info->par; + int i; + + NVTRACE_ENTER(); + if (regno >= (1 << info->var.green.length)) + return -EINVAL; + + if (info->var.grayscale) { + /* gray = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + ((u32 *) info->pseudo_palette)[regno] = + (regno << info->var.red.offset) | + (regno << info->var.green.offset) | + (regno << info->var.blue.offset); + } + + switch (info->var.bits_per_pixel) { + case 8: + /* "transparent" stuff is completely ignored. */ + nvidia_write_clut(par, regno, red >> 8, green >> 8, blue >> 8); + break; + case 16: + if (info->var.green.length == 5) { + for (i = 0; i < 8; i++) { + nvidia_write_clut(par, regno * 8 + i, red >> 8, + green >> 8, blue >> 8); + } + } else { + u8 r, g, b; + + if (regno < 32) { + for (i = 0; i < 8; i++) { + nvidia_write_clut(par, regno * 8 + i, + red >> 8, green >> 8, + blue >> 8); + } + } + + nvidia_read_clut(par, regno * 4, &r, &g, &b); + + for (i = 0; i < 4; i++) + nvidia_write_clut(par, regno * 4 + i, r, + green >> 8, b); + } + break; + case 32: + nvidia_write_clut(par, regno, red >> 8, green >> 8, blue >> 8); + break; + default: + /* do nothing */ + break; + } + + NVTRACE_LEAVE(); + return 0; +} + +static int nvidiafb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct nvidia_par *par = info->par; + int memlen, vramlen, mode_valid = 0; + int pitch, err = 0; + + NVTRACE_ENTER(); + + var->transp.offset = 0; + var->transp.length = 0; + + var->xres &= ~7; + + if (var->bits_per_pixel <= 8) + var->bits_per_pixel = 8; + else if (var->bits_per_pixel <= 16) + var->bits_per_pixel = 16; + else + var->bits_per_pixel = 32; + + 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: + var->green.length = (var->green.length < 6) ? 5 : 6; + var->red.length = 5; + var->blue.length = 5; + var->transp.length = 6 - var->green.length; + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 5 + var->green.length; + var->transp.offset = (5 + var->red.offset) & 15; + break; + 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; + var->transp.length = 8; + var->transp.offset = 24; + break; + } + + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + + if (!info->monspecs.hfmax || !info->monspecs.vfmax || + !info->monspecs.dclkmax || !fb_validate_mode(var, info)) + mode_valid = 1; + + /* calculate modeline if supported by monitor */ + if (!mode_valid && info->monspecs.gtf) { + if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info)) + mode_valid = 1; + } + + if (!mode_valid) { + struct fb_videomode *mode; + + mode = fb_find_best_mode(var, &info->modelist); + if (mode) { + fb_videomode_to_var(var, mode); + mode_valid = 1; + } + } + + if (!mode_valid && info->monspecs.modedb_len) + return -EINVAL; + + if (par->fpWidth && par->fpHeight && (par->fpWidth < var->xres || + par->fpHeight < var->yres)) + return -EINVAL; + + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + + var->xres_virtual = (var->xres_virtual + 63) & ~63; + + vramlen = info->fix.smem_len; + pitch = ((var->xres_virtual * var->bits_per_pixel) + 7) / 8; + memlen = pitch * var->yres_virtual; + + if (memlen > vramlen) { + var->yres_virtual = vramlen / pitch; + + if (var->yres_virtual < var->yres) { + var->yres_virtual = var->yres; + var->xres_virtual = vramlen / var->yres_virtual; + var->xres_virtual /= var->bits_per_pixel / 8; + var->xres_virtual &= ~63; + pitch = (var->xres_virtual * + var->bits_per_pixel + 7) / 8; + memlen = pitch * var->yres; + + if (var->xres_virtual < var->xres) { + printk("nvidiafb: required video memory, " + "%d bytes, for %dx%d-%d (virtual) " + "is out of range\n", + memlen, var->xres_virtual, + var->yres_virtual, var->bits_per_pixel); + err = -ENOMEM; + } + } + } + + if (var->accel_flags) { + if (var->yres_virtual > 0x7fff) + var->yres_virtual = 0x7fff; + if (var->xres_virtual > 0x7fff) + var->xres_virtual = 0x7fff; + } + + var->xres_virtual &= ~63; + + NVTRACE_LEAVE(); + + return err; +} + +static int nvidiafb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct nvidia_par *par = info->par; + u32 total; + + total = info->var.yoffset * info->fix.line_length + info->var.xoffset; + + NVSetStartAddress(par, total); + + return 0; +} + +static int nvidiafb_blank(int blank, struct fb_info *info) +{ + struct nvidia_par *par = info->par; + unsigned char tmp, vesa; + + tmp = NVReadSeq(par, 0x01) & ~0x20; /* screen on/off */ + vesa = NVReadCrtc(par, 0x1a) & ~0xc0; /* sync on/off */ + + NVTRACE_ENTER(); + + if (blank) + tmp |= 0x20; + + switch (blank) { + case FB_BLANK_UNBLANK: + case FB_BLANK_NORMAL: + break; + case FB_BLANK_VSYNC_SUSPEND: + vesa |= 0x80; + break; + case FB_BLANK_HSYNC_SUSPEND: + vesa |= 0x40; + break; + case FB_BLANK_POWERDOWN: + vesa |= 0xc0; + break; + } + + NVWriteSeq(par, 0x01, tmp); + NVWriteCrtc(par, 0x1a, vesa); + +#ifdef CONFIG_PMAC_BACKLIGHT + if (par->FlatPanel && _machine == _MACH_Pmac) { + set_backlight_enable(!blank); + } +#endif + + NVTRACE_LEAVE(); + + return 0; +} + +static struct fb_ops nvidia_fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = nvidiafb_check_var, + .fb_set_par = nvidiafb_set_par, + .fb_setcolreg = nvidiafb_setcolreg, + .fb_pan_display = nvidiafb_pan_display, + .fb_blank = nvidiafb_blank, + .fb_fillrect = nvidiafb_fillrect, + .fb_copyarea = nvidiafb_copyarea, + .fb_imageblit = nvidiafb_imageblit, + .fb_cursor = nvidiafb_cursor, + .fb_sync = nvidiafb_sync, +}; + +static int __devinit nvidia_set_fbinfo(struct fb_info *info) +{ + struct fb_monspecs *specs = &info->monspecs; + struct fb_videomode modedb; + struct nvidia_par *par = info->par; + int lpitch; + + NVTRACE_ENTER(); + info->flags = FBINFO_DEFAULT + | FBINFO_HWACCEL_IMAGEBLIT + | FBINFO_HWACCEL_FILLRECT + | FBINFO_HWACCEL_COPYAREA + | FBINFO_HWACCEL_YPAN; + + fb_videomode_to_modelist(info->monspecs.modedb, + info->monspecs.modedb_len, &info->modelist); + fb_var_to_videomode(&modedb, &nvidiafb_default_var); + + if (specs->modedb != NULL) { + /* get preferred timing */ + if (specs->misc & FB_MISC_1ST_DETAIL) { + int i; + + for (i = 0; i < specs->modedb_len; i++) { + if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { + modedb = specs->modedb[i]; + break; + } + } + } else { + /* otherwise, get first mode in database */ + modedb = specs->modedb[0]; + } + + fb_videomode_to_var(&nvidiafb_default_var, &modedb); + nvidiafb_default_var.bits_per_pixel = 8; + } + + if (mode_option) + fb_find_mode(&nvidiafb_default_var, info, mode_option, + specs->modedb, specs->modedb_len, &modedb, 8); + + info->var = nvidiafb_default_var; + info->fix.visual = (info->var.bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + info->pseudo_palette = par->pseudo_palette; + fb_alloc_cmap(&info->cmap, 256, 0); + fb_destroy_modedb(info->monspecs.modedb); + info->monspecs.modedb = NULL; + + /* maximize virtual vertical length */ + lpitch = info->var.xres_virtual * + ((info->var.bits_per_pixel + 7) >> 3); + info->var.yres_virtual = info->fix.smem_len / lpitch; + + info->pixmap.scan_align = 4; + info->pixmap.buf_align = 4; + info->pixmap.size = 8 * 1024; + info->pixmap.flags = FB_PIXMAP_SYSTEM; + + if (!hwcur) + info->fbops->fb_cursor = soft_cursor; + info->var.accel_flags = (!noaccel); + + switch (par->Architecture) { + case NV_ARCH_04: + info->fix.accel = FB_ACCEL_NV4; + break; + case NV_ARCH_10: + info->fix.accel = FB_ACCEL_NV_10; + break; + case NV_ARCH_20: + info->fix.accel = FB_ACCEL_NV_20; + break; + case NV_ARCH_30: + info->fix.accel = FB_ACCEL_NV_30; + break; + case NV_ARCH_40: + info->fix.accel = FB_ACCEL_NV_40; + break; + } + + NVTRACE_LEAVE(); + + return nvidiafb_check_var(&info->var, info); +} + +static u32 __devinit nvidia_get_arch(struct pci_dev *pd) +{ + u32 arch = 0; + + switch (pd->device & 0x0ff0) { + case 0x0100: /* GeForce 256 */ + case 0x0110: /* GeForce2 MX */ + case 0x0150: /* GeForce2 */ + case 0x0170: /* GeForce4 MX */ + case 0x0180: /* GeForce4 MX (8x AGP) */ + case 0x01A0: /* nForce */ + case 0x01F0: /* nForce2 */ + arch = NV_ARCH_10; + break; + case 0x0200: /* GeForce3 */ + case 0x0250: /* GeForce4 Ti */ + case 0x0280: /* GeForce4 Ti (8x AGP) */ + arch = NV_ARCH_20; + break; + case 0x0300: /* GeForceFX 5800 */ + case 0x0310: /* GeForceFX 5600 */ + case 0x0320: /* GeForceFX 5200 */ + case 0x0330: /* GeForceFX 5900 */ + case 0x0340: /* GeForceFX 5700 */ + arch = NV_ARCH_30; + break; + case 0x0040: + case 0x00C0: + case 0x0120: + case 0x0130: + case 0x0140: + case 0x0160: + case 0x01D0: + case 0x0090: + case 0x0210: + case 0x0220: + case 0x0230: + arch = NV_ARCH_40; + break; + case 0x0020: /* TNT, TNT2 */ + arch = NV_ARCH_04; + break; + default: /* unknown architecture */ + break; + } + + return arch; +} + +static int __devinit nvidiafb_probe(struct pci_dev *pd, + const struct pci_device_id *ent) +{ + struct nvidia_par *par; + struct fb_info *info; + unsigned short cmd; + + + NVTRACE_ENTER(); + assert(pd != NULL); + + info = framebuffer_alloc(sizeof(struct nvidia_par), &pd->dev); + + if (!info) + goto err_out; + + par = (struct nvidia_par *)info->par; + par->pci_dev = pd; + + info->pixmap.addr = kmalloc(8 * 1024, GFP_KERNEL); + + if (info->pixmap.addr == NULL) + goto err_out_kfree; + + memset(info->pixmap.addr, 0, 8 * 1024); + + if (pci_enable_device(pd)) { + printk(KERN_ERR PFX "cannot enable PCI device\n"); + goto err_out_enable; + } + + if (pci_request_regions(pd, "nvidiafb")) { + printk(KERN_ERR PFX "cannot request PCI regions\n"); + goto err_out_request; + } + + par->Architecture = nvidia_get_arch(pd); + + par->Chipset = (pd->vendor << 16) | pd->device; + printk(KERN_INFO PFX "nVidia device/chipset %X\n", par->Chipset); + +#ifdef CONFIG_PCI_NAMES + printk(KERN_INFO PFX "%s\n", pd->pretty_name); +#endif + + if (par->Architecture == 0) { + printk(KERN_ERR PFX "unknown NV_ARCH\n"); + goto err_out_free_base0; + } + + sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4); + + par->FlatPanel = flatpanel; + + if (flatpanel == 1) + printk(KERN_INFO PFX "flatpanel support enabled\n"); + + par->CRTCnumber = forceCRTC; + par->FpScale = (!noscale); + par->paneltweak = paneltweak; + + /* enable IO and mem if not already done */ + pci_read_config_word(pd, PCI_COMMAND, &cmd); + cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(pd, PCI_COMMAND, cmd); + + nvidiafb_fix.mmio_start = pci_resource_start(pd, 0); + nvidiafb_fix.smem_start = pci_resource_start(pd, 1); + nvidiafb_fix.mmio_len = pci_resource_len(pd, 0); + + par->REGS = ioremap(nvidiafb_fix.mmio_start, nvidiafb_fix.mmio_len); + + if (!par->REGS) { + printk(KERN_ERR PFX "cannot ioremap MMIO base\n"); + goto err_out_free_base0; + } + + NVCommonSetup(info); + + par->FbAddress = nvidiafb_fix.smem_start; + par->FbMapSize = par->RamAmountKBytes * 1024; + par->FbUsableSize = par->FbMapSize - (128 * 1024); + par->ScratchBufferSize = (par->Architecture < NV_ARCH_10) ? 8 * 1024 : + 16 * 1024; + par->ScratchBufferStart = par->FbUsableSize - par->ScratchBufferSize; + info->screen_base = ioremap(nvidiafb_fix.smem_start, par->FbMapSize); + nvidiafb_fix.smem_len = par->FbUsableSize; + + if (!info->screen_base) { + printk(KERN_ERR PFX "cannot ioremap FB base\n"); + goto err_out_free_base1; + } + + par->FbStart = info->screen_base; + +#ifdef CONFIG_MTRR + if (!nomtrr) { + par->mtrr.vram = mtrr_add(nvidiafb_fix.smem_start, + par->FbMapSize, MTRR_TYPE_WRCOMB, 1); + if (par->mtrr.vram < 0) { + printk(KERN_ERR PFX "unable to setup MTRR\n"); + } else { + par->mtrr.vram_valid = 1; + /* let there be speed */ + printk(KERN_INFO PFX "MTRR set to ON\n"); + } + } +#endif /* CONFIG_MTRR */ + + info->fbops = &nvidia_fb_ops; + info->fix = nvidiafb_fix; + + if (nvidia_set_fbinfo(info) < 0) { + printk(KERN_ERR PFX "error setting initial video mode\n"); + goto err_out_iounmap_fb; + } + + nvidia_save_vga(par, &par->SavedReg); + + if (register_framebuffer(info) < 0) { + printk(KERN_ERR PFX "error registering nVidia framebuffer\n"); + goto err_out_iounmap_fb; + } + + pci_set_drvdata(pd, info); + + printk(KERN_INFO PFX + "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n", + info->fix.id, + par->FbMapSize / (1024 * 1024), info->fix.smem_start); +#ifdef CONFIG_PMAC_BACKLIGHT + if (par->FlatPanel && _machine == _MACH_Pmac) + register_backlight_controller(&nvidia_backlight_controller, + par, "mnca"); +#endif + NVTRACE_LEAVE(); + return 0; + + err_out_iounmap_fb: + iounmap(info->screen_base); + fb_destroy_modedb(info->monspecs.modedb); + nvidia_delete_i2c_busses(par); + err_out_free_base1: + iounmap(par->REGS); + err_out_free_base0: + pci_release_regions(pd); + err_out_request: + pci_disable_device(pd); + err_out_enable: + kfree(info->pixmap.addr); + err_out_kfree: + framebuffer_release(info); + err_out: + return -ENODEV; +} + +static void __exit nvidiafb_remove(struct pci_dev *pd) +{ + struct fb_info *info = pci_get_drvdata(pd); + struct nvidia_par *par = info->par; + + NVTRACE_ENTER(); + if (!info) + return; + + unregister_framebuffer(info); +#ifdef CONFIG_MTRR + if (par->mtrr.vram_valid) + mtrr_del(par->mtrr.vram, info->fix.smem_start, + info->fix.smem_len); +#endif /* CONFIG_MTRR */ + + iounmap(info->screen_base); + fb_destroy_modedb(info->monspecs.modedb); + nvidia_delete_i2c_busses(par); + iounmap(par->REGS); + pci_release_regions(pd); + pci_disable_device(pd); + kfree(info->pixmap.addr); + framebuffer_release(info); + pci_set_drvdata(pd, NULL); + NVTRACE_LEAVE(); +} + +/* ------------------------------------------------------------------------- * + * + * initialization + * + * ------------------------------------------------------------------------- */ + +#ifndef MODULE +static int __devinit nvidiafb_setup(char *options) +{ + char *this_opt; + + NVTRACE_ENTER(); + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "forceCRTC", 9)) { + char *p; + + p = this_opt + 9; + if (!*p || !*(++p)) + continue; + forceCRTC = *p - '0'; + if (forceCRTC < 0 || forceCRTC > 1) + forceCRTC = -1; + } else if (!strncmp(this_opt, "flatpanel", 9)) { + flatpanel = 1; + } else if (!strncmp(this_opt, "hwcur", 5)) { + hwcur = 1; + } else if (!strncmp(this_opt, "noaccel", 6)) { + noaccel = 1; + } else if (!strncmp(this_opt, "noscale", 7)) { + noscale = 1; + } else if (!strncmp(this_opt, "paneltweak:", 11)) { + paneltweak = simple_strtoul(this_opt+11, NULL, 0); +#ifdef CONFIG_MTRR + } else if (!strncmp(this_opt, "nomtrr", 6)) { + nomtrr = 1; +#endif + } else + mode_option = this_opt; + } + NVTRACE_LEAVE(); + return 0; +} +#endif /* !MODULE */ + +static struct pci_driver nvidiafb_driver = { + .name = "nvidiafb", + .id_table = nvidiafb_pci_tbl, + .probe = nvidiafb_probe, + .remove = __exit_p(nvidiafb_remove), +}; + +/* ------------------------------------------------------------------------- * + * + * modularization + * + * ------------------------------------------------------------------------- */ + +static int __devinit nvidiafb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("nvidiafb", &option)) + return -ENODEV; + nvidiafb_setup(option); +#endif + return pci_register_driver(&nvidiafb_driver); +} + +module_init(nvidiafb_init); + +#ifdef MODULE +static void __exit nvidiafb_exit(void) +{ + pci_unregister_driver(&nvidiafb_driver); +} + +module_exit(nvidiafb_exit); + +module_param(flatpanel, int, 0); +MODULE_PARM_DESC(flatpanel, + "Enables experimental flat panel support for some chipsets. " + "(0 or 1=enabled) (default=0)"); +module_param(hwcur, int, 0); +MODULE_PARM_DESC(hwcur, + "Enables hardware cursor implementation. (0 or 1=enabled) " + "(default=0)"); +module_param(noaccel, int, 0); +MODULE_PARM_DESC(noaccel, + "Disables hardware acceleration. (0 or 1=disable) " + "(default=0)"); +module_param(noscale, int, 0); +MODULE_PARM_DESC(noscale, + "Disables screen scaleing. (0 or 1=disable) " + "(default=0, do scaling)"); +module_param(paneltweak, int, 0); +MODULE_PARM_DESC(paneltweak, + "Tweak display settings for flatpanels. " + "(default=0, no tweaks)"); +module_param(forceCRTC, int, 0); +MODULE_PARM_DESC(forceCRTC, + "Forces usage of a particular CRTC in case autodetection " + "fails. (0 or 1) (default=autodetect)"); +#ifdef CONFIG_MTRR +module_param(nomtrr, bool, 0); +MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) " + "(default=0)"); +#endif + +MODULE_AUTHOR("Antonino Daplas"); +MODULE_DESCRIPTION("Framebuffer driver for nVidia graphics chipset"); +MODULE_LICENSE("GPL"); +#endif /* MODULE */ + diff --git a/drivers/video/offb.c b/drivers/video/offb.c new file mode 100644 index 000000000000..42a6591e863f --- /dev/null +++ b/drivers/video/offb.c @@ -0,0 +1,538 @@ +/* + * linux/drivers/video/offb.c -- Open Firmware based frame buffer device + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This driver is partly based on the PowerMac console driver: + * + * Copyright (C) 1996 Paul Mackerras + * + * 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/config.h> +#include <linux/module.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/prom.h> + +#ifdef CONFIG_PPC64 +#include <asm/pci-bridge.h> +#endif + +#ifdef CONFIG_PPC32 +#include <asm/bootx.h> +#endif + +#include "macmodes.h" + +/* Supported palette hacks */ +enum { + cmap_unknown, + cmap_m64, /* ATI Mach64 */ + cmap_r128, /* ATI Rage128 */ + cmap_M3A, /* ATI Rage Mobility M3 Head A */ + cmap_M3B, /* ATI Rage Mobility M3 Head B */ + cmap_radeon, /* ATI Radeon */ + cmap_gxt2000, /* IBM GXT2000 */ +}; + +struct offb_par { + volatile void __iomem *cmap_adr; + volatile void __iomem *cmap_data; + int cmap_type; + int blanked; +}; + +struct offb_par default_par; + + /* + * Interface used by the world + */ + +int offb_init(void); + +static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int offb_blank(int blank, struct fb_info *info); + +#ifdef CONFIG_PPC32 +extern boot_infos_t *boot_infos; +#endif + +static void offb_init_nodriver(struct device_node *); +static void offb_init_fb(const char *name, const char *full_name, + int width, int height, int depth, int pitch, + unsigned long address, struct device_node *dp); + +static struct fb_ops offb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = offb_setcolreg, + .fb_blank = offb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct offb_par *par = (struct offb_par *) info->par; + + if (!par->cmap_adr || regno > 255) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + switch (par->cmap_type) { + case cmap_m64: + writeb(regno, par->cmap_adr); + writeb(red, par->cmap_data); + writeb(green, par->cmap_data); + writeb(blue, par->cmap_data); + break; + case cmap_M3A: + /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32(par->cmap_adr + 0x58, + in_le32(par->cmap_adr + 0x58) & ~0x20); + case cmap_r128: + /* Set palette index & data */ + out_8(par->cmap_adr + 0xb0, regno); + out_le32(par->cmap_adr + 0xb4, + (red << 16 | green << 8 | blue)); + break; + case cmap_M3B: + /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32(par->cmap_adr + 0x58, + in_le32(par->cmap_adr + 0x58) | 0x20); + /* Set palette index & data */ + out_8(par->cmap_adr + 0xb0, regno); + out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue)); + break; + case cmap_radeon: + /* Set palette index & data (could be smarter) */ + out_8(par->cmap_adr + 0xb0, regno); + out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue)); + break; + case cmap_gxt2000: + out_le32((unsigned __iomem *) par->cmap_adr + regno, + (red << 16 | green << 8 | blue)); + break; + } + + if (regno < 16) + switch (info->var.bits_per_pixel) { + case 16: + ((u16 *) (info->pseudo_palette))[regno] = + (regno << 10) | (regno << 5) | regno; + break; + case 32: + { + int i = (regno << 8) | regno; + ((u32 *) (info->pseudo_palette))[regno] = + (i << 16) | i; + break; + } + } + return 0; +} + + /* + * Blank the display. + */ + +static int offb_blank(int blank, struct fb_info *info) +{ + struct offb_par *par = (struct offb_par *) info->par; + int i, j; + + if (!par->cmap_adr) + return 0; + + if (!par->blanked) + if (!blank) + return 0; + + par->blanked = blank; + + if (blank) + for (i = 0; i < 256; i++) { + switch (par->cmap_type) { + case cmap_m64: + writeb(i, par->cmap_adr); + for (j = 0; j < 3; j++) + writeb(0, par->cmap_data); + break; + case cmap_M3A: + /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32(par->cmap_adr + 0x58, + in_le32(par->cmap_adr + 0x58) & ~0x20); + case cmap_r128: + /* Set palette index & data */ + out_8(par->cmap_adr + 0xb0, i); + out_le32(par->cmap_adr + 0xb4, 0); + break; + case cmap_M3B: + /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32(par->cmap_adr + 0x58, + in_le32(par->cmap_adr + 0x58) | 0x20); + /* Set palette index & data */ + out_8(par->cmap_adr + 0xb0, i); + out_le32(par->cmap_adr + 0xb4, 0); + break; + case cmap_radeon: + out_8(par->cmap_adr + 0xb0, i); + out_le32(par->cmap_adr + 0xb4, 0); + break; + case cmap_gxt2000: + out_le32((unsigned __iomem *) par->cmap_adr + i, + 0); + break; + } + } else + fb_set_cmap(&info->cmap, info); + return 0; +} + + /* + * Initialisation + */ + +int __init offb_init(void) +{ + struct device_node *dp = NULL, *boot_disp = NULL; +#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) + struct device_node *macos_display = NULL; +#endif + if (fb_get_options("offb", NULL)) + return -ENODEV; + +#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) + /* If we're booted from BootX... */ + if (boot_infos != 0) { + unsigned long addr = + (unsigned long) boot_infos->dispDeviceBase; + /* find the device node corresponding to the macos display */ + while ((dp = of_find_node_by_type(dp, "display"))) { + int i; + /* + * Grrr... It looks like the MacOS ATI driver + * munges the assigned-addresses property (but + * the AAPL,address value is OK). + */ + if (strncmp(dp->name, "ATY,", 4) == 0 + && dp->n_addrs == 1) { + unsigned int *ap = + (unsigned int *) get_property(dp, + "AAPL,address", + NULL); + if (ap != NULL) { + dp->addrs[0].address = *ap; + dp->addrs[0].size = 0x01000000; + } + } + + /* + * The LTPro on the Lombard powerbook has no addresses + * on the display nodes, they are on their parent. + */ + if (dp->n_addrs == 0 + && device_is_compatible(dp, "ATY,264LTPro")) { + int na; + unsigned int *ap = (unsigned int *) + get_property(dp, "AAPL,address", &na); + if (ap != 0) + for (na /= sizeof(unsigned int); + na > 0; --na, ++ap) + if (*ap <= addr + && addr < + *ap + 0x1000000) + goto foundit; + } + + /* + * See if the display address is in one of the address + * ranges for this display. + */ + for (i = 0; i < dp->n_addrs; ++i) { + if (dp->addrs[i].address <= addr + && addr < + dp->addrs[i].address + + dp->addrs[i].size) + break; + } + if (i < dp->n_addrs) { + foundit: + printk(KERN_INFO "MacOS display is %s\n", + dp->full_name); + macos_display = dp; + break; + } + } + + /* initialize it */ + offb_init_fb(macos_display ? macos_display-> + name : "MacOS display", + macos_display ? macos_display-> + full_name : "MacOS display", + boot_infos->dispDeviceRect[2], + boot_infos->dispDeviceRect[3], + boot_infos->dispDeviceDepth, + boot_infos->dispDeviceRowBytes, addr, NULL); + } +#endif /* defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) */ + + for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) { + if (get_property(dp, "linux,opened", NULL) && + get_property(dp, "linux,boot-display", NULL)) { + boot_disp = dp; + offb_init_nodriver(dp); + } + } + for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) { + if (get_property(dp, "linux,opened", NULL) && + dp != boot_disp) + offb_init_nodriver(dp); + } + + return 0; +} + + +static void __init offb_init_nodriver(struct device_node *dp) +{ + int *pp, i; + unsigned int len; + int width = 640, height = 480, depth = 8, pitch; + unsigned *up; + unsigned long address; + + if ((pp = (int *) get_property(dp, "depth", &len)) != NULL + && len == sizeof(int)) + depth = *pp; + if ((pp = (int *) get_property(dp, "width", &len)) != NULL + && len == sizeof(int)) + width = *pp; + if ((pp = (int *) get_property(dp, "height", &len)) != NULL + && len == sizeof(int)) + height = *pp; + if ((pp = (int *) get_property(dp, "linebytes", &len)) != NULL + && len == sizeof(int)) { + pitch = *pp; + if (pitch == 1) + pitch = 0x1000; + } else + pitch = width; + if ((up = (unsigned *) get_property(dp, "address", &len)) != NULL + && len == sizeof(unsigned)) + address = (u_long) * up; + else { + for (i = 0; i < dp->n_addrs; ++i) + if (dp->addrs[i].size >= + pitch * height * depth / 8) + break; + if (i >= dp->n_addrs) { + printk(KERN_ERR + "no framebuffer address found for %s\n", + dp->full_name); + return; + } + + address = (u_long) dp->addrs[i].address; + +#ifdef CONFIG_PPC64 + address += dp->phb->pci_mem_offset; +#endif + + /* kludge for valkyrie */ + if (strcmp(dp->name, "valkyrie") == 0) + address += 0x1000; + } + offb_init_fb(dp->name, dp->full_name, width, height, depth, + pitch, address, dp); + +} + +static void __init offb_init_fb(const char *name, const char *full_name, + int width, int height, int depth, + int pitch, unsigned long address, + struct device_node *dp) +{ + unsigned long res_size = pitch * height * depth / 8; + struct offb_par *par = &default_par; + unsigned long res_start = address; + 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; + + printk(KERN_INFO + "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n", + width, height, name, address, depth, pitch); + if (depth != 8 && depth != 16 && depth != 32) { + printk(KERN_ERR "%s: can't use depth = %d\n", full_name, + depth); + release_mem_region(res_start, res_size); + return; + } + + size = sizeof(struct fb_info) + sizeof(u32) * 17; + + info = kmalloc(size, GFP_ATOMIC); + + if (info == 0) { + release_mem_region(res_start, res_size); + return; + } + memset(info, 0, size); + + fix = &info->fix; + var = &info->var; + + strcpy(fix->id, "OFfb "); + strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb ")); + fix->id[sizeof(fix->id) - 1] = '\0'; + + var->xres = var->xres_virtual = width; + var->yres = var->yres_virtual = height; + fix->line_length = pitch; + + fix->smem_start = address; + fix->smem_len = pitch * height; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + + par->cmap_type = cmap_unknown; + if (depth == 8) { + /* XXX kludge for ati */ + if (dp && !strncmp(name, "ATY,Rage128", 11)) { + unsigned long regbase = dp->addrs[2].address; + par->cmap_adr = ioremap(regbase, 0x1FFF); + par->cmap_type = cmap_r128; + } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12) + || !strncmp(name, "ATY,RageM3p12A", 14))) { + unsigned long regbase = + dp->parent->addrs[2].address; + par->cmap_adr = ioremap(regbase, 0x1FFF); + par->cmap_type = cmap_M3A; + } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) { + unsigned long regbase = + dp->parent->addrs[2].address; + par->cmap_adr = ioremap(regbase, 0x1FFF); + par->cmap_type = cmap_M3B; + } else if (dp && !strncmp(name, "ATY,Rage6", 9)) { + unsigned long regbase = dp->addrs[1].address; + par->cmap_adr = ioremap(regbase, 0x1FFF); + par->cmap_type = cmap_radeon; + } else if (!strncmp(name, "ATY,", 4)) { + unsigned long base = address & 0xff000000UL; + par->cmap_adr = + ioremap(base + 0x7ff000, 0x1000) + 0xcc0; + par->cmap_data = par->cmap_adr + 1; + par->cmap_type = cmap_m64; + } else if (device_is_compatible(dp, "pci1014,b7")) { + unsigned long regbase = dp->addrs[0].address; + par->cmap_adr = ioremap(regbase + 0x6000, 0x1000); + par->cmap_type = cmap_gxt2000; + } + fix->visual = par->cmap_adr ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_STATIC_PSEUDOCOLOR; + } else + fix->visual = /* par->cmap_adr ? FB_VISUAL_DIRECTCOLOR + : */ FB_VISUAL_TRUECOLOR; + + var->xoffset = var->yoffset = 0; + var->bits_per_pixel = depth; + switch (depth) { + case 8: + var->bits_per_pixel = 8; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 16: /* RGB 555 */ + var->bits_per_pixel = 16; + 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 = 0; + var->transp.length = 0; + break; + case 32: /* RGB 888 */ + var->bits_per_pixel = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + } + var->red.msb_right = var->green.msb_right = var->blue.msb_right = + var->transp.msb_right = 0; + var->grayscale = 0; + var->nonstd = 0; + var->activate = 0; + var->height = var->width = -1; + var->pixclock = 10000; + var->left_margin = var->right_margin = 16; + var->upper_margin = var->lower_margin = 16; + var->hsync_len = var->vsync_len = 8; + var->sync = 0; + var->vmode = FB_VMODE_NONINTERLACED; + + info->fbops = &offb_ops; + info->screen_base = ioremap(address, fix->smem_len); + info->par = par; + info->pseudo_palette = (void *) (info + 1); + info->flags = FBINFO_DEFAULT; + + fb_alloc_cmap(&info->cmap, 256, 0); + + if (register_framebuffer(info) < 0) { + kfree(info); + release_mem_region(res_start, res_size); + return; + } + + printk(KERN_INFO "fb%d: Open Firmware frame buffer device on %s\n", + info->node, full_name); +} + +module_init(offb_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c new file mode 100644 index 000000000000..7808a01493ad --- /dev/null +++ b/drivers/video/p9100.c @@ -0,0 +1,379 @@ +/* p9100.c: P9100 frame buffer driver + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright 1999 Derrick J Brashear (shadow@dementia.org) + * + * Driver layout based loosely on tgafb.c, see that file for credits. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <linux/mm.h> + +#include <asm/io.h> +#include <asm/sbus.h> +#include <asm/oplib.h> +#include <asm/fbio.h> + +#include "sbuslib.h" + +/* + * Local functions. + */ + +static int p9100_setcolreg(unsigned, unsigned, unsigned, unsigned, + unsigned, struct fb_info *); +static int p9100_blank(int, struct fb_info *); + +static int p9100_mmap(struct fb_info *, struct file *, struct vm_area_struct *); +static int p9100_ioctl(struct inode *, struct file *, unsigned int, + unsigned long, struct fb_info *); + +/* + * Frame buffer operations + */ + +static struct fb_ops p9100_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = p9100_setcolreg, + .fb_blank = p9100_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = p9100_mmap, + .fb_ioctl = p9100_ioctl, + .fb_cursor = soft_cursor, +}; + +/* P9100 control registers */ +#define P9100_SYSCTL_OFF 0x0UL +#define P9100_VIDEOCTL_OFF 0x100UL +#define P9100_VRAMCTL_OFF 0x180UL +#define P9100_RAMDAC_OFF 0x200UL +#define P9100_VIDEOCOPROC_OFF 0x400UL + +/* P9100 command registers */ +#define P9100_CMD_OFF 0x0UL + +/* P9100 framebuffer memory */ +#define P9100_FB_OFF 0x0UL + +/* 3 bits: 2=8bpp 3=16bpp 5=32bpp 7=24bpp */ +#define SYS_CONFIG_PIXELSIZE_SHIFT 26 + +#define SCREENPAINT_TIMECTL1_ENABLE_VIDEO 0x20 /* 0 = off, 1 = on */ + +struct p9100_regs { + /* Registers for the system control */ + volatile u32 sys_base; + volatile u32 sys_config; + volatile u32 sys_intr; + volatile u32 sys_int_ena; + volatile u32 sys_alt_rd; + volatile u32 sys_alt_wr; + volatile u32 sys_xxx[58]; + + /* Registers for the video control */ + volatile u32 vid_base; + volatile u32 vid_hcnt; + volatile u32 vid_htotal; + volatile u32 vid_hsync_rise; + volatile u32 vid_hblank_rise; + volatile u32 vid_hblank_fall; + volatile u32 vid_hcnt_preload; + volatile u32 vid_vcnt; + volatile u32 vid_vlen; + volatile u32 vid_vsync_rise; + volatile u32 vid_vblank_rise; + volatile u32 vid_vblank_fall; + volatile u32 vid_vcnt_preload; + volatile u32 vid_screenpaint_addr; + volatile u32 vid_screenpaint_timectl1; + volatile u32 vid_screenpaint_qsfcnt; + volatile u32 vid_screenpaint_timectl2; + volatile u32 vid_xxx[15]; + + /* Registers for the video control */ + volatile u32 vram_base; + volatile u32 vram_memcfg; + volatile u32 vram_refresh_pd; + volatile u32 vram_refresh_cnt; + volatile u32 vram_raslo_max; + volatile u32 vram_raslo_cur; + volatile u32 pwrup_cfg; + volatile u32 vram_xxx[25]; + + /* Registers for IBM RGB528 Palette */ + volatile u32 ramdac_cmap_wridx; + volatile u32 ramdac_palette_data; + volatile u32 ramdac_pixel_mask; + volatile u32 ramdac_palette_rdaddr; + volatile u32 ramdac_idx_lo; + volatile u32 ramdac_idx_hi; + volatile u32 ramdac_idx_data; + volatile u32 ramdac_idx_ctl; + volatile u32 ramdac_xxx[1784]; +}; + +struct p9100_cmd_parameng { + volatile u32 parameng_status; + volatile u32 parameng_bltcmd; + volatile u32 parameng_quadcmd; +}; + +struct p9100_par { + spinlock_t lock; + struct p9100_regs __iomem *regs; + + u32 flags; +#define P9100_FLAG_BLANKED 0x00000001 + + unsigned long physbase; + unsigned long fbsize; + + struct sbus_dev *sdev; + struct list_head list; +}; + +/** + * p9100_setcolreg - Optional function. Sets a color register. + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @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. + * @info: frame buffer info structure + */ +static int p9100_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct p9100_par *par = (struct p9100_par *) info->par; + struct p9100_regs __iomem *regs = par->regs; + unsigned long flags; + + if (regno >= 256) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + spin_lock_irqsave(&par->lock, flags); + + sbus_writel((regno << 16), ®s->ramdac_cmap_wridx); + sbus_writel((red << 16), ®s->ramdac_palette_data); + sbus_writel((green << 16), ®s->ramdac_palette_data); + sbus_writel((blue << 16), ®s->ramdac_palette_data); + + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +/** + * p9100_blank - Optional function. Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + */ +static int +p9100_blank(int blank, struct fb_info *info) +{ + struct p9100_par *par = (struct p9100_par *) info->par; + struct p9100_regs __iomem *regs = par->regs; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&par->lock, flags); + + switch (blank) { + case FB_BLANK_UNBLANK: /* Unblanking */ + val = sbus_readl(®s->vid_screenpaint_timectl1); + val |= SCREENPAINT_TIMECTL1_ENABLE_VIDEO; + sbus_writel(val, ®s->vid_screenpaint_timectl1); + par->flags &= ~P9100_FLAG_BLANKED; + break; + + case FB_BLANK_NORMAL: /* Normal blanking */ + case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ + case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ + case FB_BLANK_POWERDOWN: /* Poweroff */ + val = sbus_readl(®s->vid_screenpaint_timectl1); + val &= ~SCREENPAINT_TIMECTL1_ENABLE_VIDEO; + sbus_writel(val, ®s->vid_screenpaint_timectl1); + par->flags |= P9100_FLAG_BLANKED; + break; + } + + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +static struct sbus_mmap_map p9100_mmap_map[] = { + { CG3_MMAP_OFFSET, 0, SBUS_MMAP_FBSIZE(1) }, + { 0, 0, 0 } +}; + +static int p9100_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) +{ + struct p9100_par *par = (struct p9100_par *)info->par; + + return sbusfb_mmap_helper(p9100_mmap_map, + par->physbase, par->fbsize, + par->sdev->reg_addrs[0].which_io, + vma); +} + +static int p9100_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *info) +{ + struct p9100_par *par = (struct p9100_par *) info->par; + + /* Make it look like a cg3. */ + return sbusfb_ioctl_helper(cmd, arg, info, + FBTYPE_SUN3COLOR, 8, par->fbsize); +} + +/* + * Initialisation + */ + +static void +p9100_init_fix(struct fb_info *info, int linebytes) +{ + struct p9100_par *par = (struct p9100_par *)info->par; + + strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id)); + + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + + info->fix.line_length = linebytes; + + info->fix.accel = FB_ACCEL_SUN_CGTHREE; +} + +struct all_info { + struct fb_info info; + struct p9100_par par; + struct list_head list; +}; +static LIST_HEAD(p9100_list); + +static void p9100_init_one(struct sbus_dev *sdev) +{ + struct all_info *all; + int linebytes; + + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "p9100: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); + + INIT_LIST_HEAD(&all->list); + + spin_lock_init(&all->par.lock); + all->par.sdev = sdev; + + /* This is the framebuffer and the only resource apps can mmap. */ + all->par.physbase = sdev->reg_addrs[2].phys_addr; + + sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); + + linebytes = prom_getintdefault(sdev->prom_node, "linebytes", + all->info.var.xres); + all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + + all->par.regs = sbus_ioremap(&sdev->resource[0], 0, + sizeof(struct p9100_regs), "p9100 regs"); + + all->info.flags = FBINFO_DEFAULT; + all->info.fbops = &p9100_ops; +#ifdef CONFIG_SPARC32 + all->info.screen_base = (char __iomem *) + prom_getintdefault(sdev->prom_node, "address", 0); +#endif + if (!all->info.screen_base) + all->info.screen_base = sbus_ioremap(&sdev->resource[2], 0, + all->par.fbsize, "p9100 ram"); + all->info.par = &all->par; + + p9100_blank(0, &all->info); + + if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { + printk(KERN_ERR "p9100: Could not allocate color map.\n"); + kfree(all); + return; + } + + p9100_init_fix(&all->info, linebytes); + + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "p9100: Could not register framebuffer.\n"); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + return; + } + + list_add(&all->list, &p9100_list); + + printk("p9100: %s at %lx:%lx\n", + sdev->prom_name, + (long) sdev->reg_addrs[0].which_io, + (long) sdev->reg_addrs[0].phys_addr); +} + +int __init p9100_init(void) +{ + struct sbus_bus *sbus; + struct sbus_dev *sdev; + + if (fb_get_options("p9100fb", NULL)) + return -ENODEV; + + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "p9100")) + p9100_init_one(sdev); + } + + return 0; +} + +void __exit p9100_exit(void) +{ + struct list_head *pos, *tmp; + + list_for_each_safe(pos, tmp, &p9100_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } +} + +int __init +p9100_setup(char *arg) +{ + /* No cmdline options yet... */ + return 0; +} + +module_init(p9100_init); + +#ifdef MODULE +module_exit(p9100_exit); +#endif + +MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets"); +MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c new file mode 100644 index 000000000000..3dd1de1539d2 --- /dev/null +++ b/drivers/video/platinumfb.c @@ -0,0 +1,693 @@ +/* + * platinumfb.c -- frame buffer device for the PowerMac 'platinum' display + * + * Copyright (C) 1998 Franz Sirl + * + * Frame buffer structure from: + * drivers/video/controlfb.c -- frame buffer device for + * Apple 'control' display chip. + * Copyright (C) 1998 Dan Jacobowitz + * + * Hardware information from: + * platinum.c: Console support for PowerMac "platinum" display adaptor. + * Copyright (C) 1996 Paul Mackerras and Mark Abene + * + * 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/config.h> +#include <linux/module.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/nvram.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/pgtable.h> +#include <asm/of_device.h> + +#include "macmodes.h" +#include "platinumfb.h" + +static int default_vmode = VMODE_NVRAM; +static int default_cmode = CMODE_NVRAM; + +struct fb_info_platinum { + struct fb_info *info; + + int vmode, cmode; + int xres, yres; + int vxres, vyres; + int xoffset, yoffset; + + struct { + __u8 red, green, blue; + } palette[256]; + u32 pseudo_palette[17]; + + volatile struct cmap_regs __iomem *cmap_regs; + unsigned long cmap_regs_phys; + + volatile struct platinum_regs __iomem *platinum_regs; + unsigned long platinum_regs_phys; + + __u8 __iomem *frame_buffer; + volatile __u8 __iomem *base_frame_buffer; + unsigned long frame_buffer_phys; + + unsigned long total_vram; + int clktype; + int dactype; +}; + +/* + * Frame buffer device API + */ + +static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int platinumfb_blank(int blank_mode, struct fb_info *info); +static int platinumfb_set_par (struct fb_info *info); +static int platinumfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info); + +/* + * internal functions + */ + +static inline int platinum_vram_reqd(int video_mode, int color_mode); +static int read_platinum_sense(struct fb_info_platinum *pinfo); +static void set_platinum_clock(struct fb_info_platinum *pinfo); +static void platinum_set_hardware(struct fb_info_platinum *pinfo); +static int platinum_var_to_par(struct fb_var_screeninfo *var, + struct fb_info_platinum *pinfo, + int check_only); + +/* + * Interface used by the world + */ + +int platinumfb_init(void); +int platinumfb_setup(char*); + +static struct fb_ops platinumfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = platinumfb_check_var, + .fb_set_par = platinumfb_set_par, + .fb_setcolreg = platinumfb_setcolreg, + .fb_blank = platinumfb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +/* + * Checks a var structure + */ +static int platinumfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info) +{ + return platinum_var_to_par(var, info->par, 1); +} + +/* + * Applies current var to display + */ +static int platinumfb_set_par (struct fb_info *info) +{ + struct fb_info_platinum *pinfo = info->par; + struct platinum_regvals *init; + int err, offset = 0x20; + + if((err = platinum_var_to_par(&info->var, pinfo, 0))) { + printk (KERN_ERR "platinumfb_set_par: error calling" + " platinum_var_to_par: %d.\n", err); + return err; + } + + platinum_set_hardware(pinfo); + + init = platinum_reg_init[pinfo->vmode-1]; + + if (pinfo->vmode == 13 && pinfo->cmode > 0) + offset = 0x10; + info->screen_base = pinfo->frame_buffer + init->fb_offset + offset; + info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset; + info->fix.visual = (pinfo->cmode == CMODE_8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode) + offset; + printk("line_length: %x\n", info->fix.line_length); + return 0; +} + +static int platinumfb_blank(int blank, struct fb_info *fb) +{ +/* + * Blank the screen if blank_mode != 0, else unblank. If blank == NULL + * then the caller blanks by setting the CLUT (Color Look Up Table) to all + * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due + * to e.g. a video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + */ +/* [danj] I think there's something fishy about those constants... */ +/* + struct fb_info_platinum *info = (struct fb_info_platinum *) fb; + int ctrl; + + ctrl = ld_le32(&info->platinum_regs->ctrl.r) | 0x33; + if (blank) + --blank_mode; + if (blank & VESA_VSYNC_SUSPEND) + ctrl &= ~3; + if (blank & VESA_HSYNC_SUSPEND) + ctrl &= ~0x30; + out_le32(&info->platinum_regs->ctrl.r, ctrl); +*/ +/* TODO: Figure out how the heck to powerdown this thing! */ + return 0; +} + +static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct fb_info_platinum *pinfo = info->par; + volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs; + + if (regno > 255) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + pinfo->palette[regno].red = red; + pinfo->palette[regno].green = green; + pinfo->palette[regno].blue = blue; + + out_8(&cmap_regs->addr, regno); /* tell clut what addr to fill */ + out_8(&cmap_regs->lut, red); /* send one color channel at */ + out_8(&cmap_regs->lut, green); /* a time... */ + out_8(&cmap_regs->lut, blue); + + if (regno < 16) { + int i; + u32 *pal = info->pseudo_palette; + switch (pinfo->cmode) { + case CMODE_16: + pal[regno] = (regno << 10) | (regno << 5) | regno; + break; + case CMODE_32: + i = (regno << 8) | regno; + pal[regno] = (i << 16) | i; + break; + } + } + + return 0; +} + +static inline int platinum_vram_reqd(int video_mode, int color_mode) +{ + return vmode_attrs[video_mode-1].vres * + (vmode_attrs[video_mode-1].hres * (1<<color_mode) + 0x20) +0x1000; +} + +#define STORE_D2(a, d) { \ + out_8(&cmap_regs->addr, (a+32)); \ + out_8(&cmap_regs->d2, (d)); \ +} + +static void set_platinum_clock(struct fb_info_platinum *pinfo) +{ + volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs; + struct platinum_regvals *init; + + init = platinum_reg_init[pinfo->vmode-1]; + + STORE_D2(6, 0xc6); + out_8(&cmap_regs->addr,3+32); + + if (in_8(&cmap_regs->d2) == 2) { + STORE_D2(7, init->clock_params[pinfo->clktype][0]); + STORE_D2(8, init->clock_params[pinfo->clktype][1]); + STORE_D2(3, 3); + } else { + STORE_D2(4, init->clock_params[pinfo->clktype][0]); + STORE_D2(5, init->clock_params[pinfo->clktype][1]); + STORE_D2(3, 2); + } + + __delay(5000); + STORE_D2(9, 0xa6); +} + + +/* Now how about actually saying, Make it so! */ +/* Some things in here probably don't need to be done each time. */ +static void platinum_set_hardware(struct fb_info_platinum *pinfo) +{ + volatile struct platinum_regs __iomem *platinum_regs = pinfo->platinum_regs; + volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs; + struct platinum_regvals *init; + int i; + int vmode, cmode; + + vmode = pinfo->vmode; + cmode = pinfo->cmode; + + init = platinum_reg_init[vmode - 1]; + + /* Initialize display timing registers */ + out_be32(&platinum_regs->reg[24].r, 7); /* turn display off */ + + for (i = 0; i < 26; ++i) + out_be32(&platinum_regs->reg[i+32].r, init->regs[i]); + + out_be32(&platinum_regs->reg[26+32].r, (pinfo->total_vram == 0x100000 ? + init->offset[cmode] + 4 - cmode : + init->offset[cmode])); + out_be32(&platinum_regs->reg[16].r, (unsigned) pinfo->frame_buffer_phys+init->fb_offset+0x10); + out_be32(&platinum_regs->reg[18].r, init->pitch[cmode]); + out_be32(&platinum_regs->reg[19].r, (pinfo->total_vram == 0x100000 ? + init->mode[cmode+1] : + init->mode[cmode])); + out_be32(&platinum_regs->reg[20].r, (pinfo->total_vram == 0x100000 ? 0x11 : 0x1011)); + out_be32(&platinum_regs->reg[21].r, 0x100); + out_be32(&platinum_regs->reg[22].r, 1); + out_be32(&platinum_regs->reg[23].r, 1); + out_be32(&platinum_regs->reg[26].r, 0xc00); + out_be32(&platinum_regs->reg[27].r, 0x235); + /* out_be32(&platinum_regs->reg[27].r, 0x2aa); */ + + STORE_D2(0, (pinfo->total_vram == 0x100000 ? + init->dacula_ctrl[cmode] & 0xf : + init->dacula_ctrl[cmode])); + STORE_D2(1, 4); + STORE_D2(2, 0); + + set_platinum_clock(pinfo); + + out_be32(&platinum_regs->reg[24].r, 0); /* turn display on */ +} + +/* + * Set misc info vars for this driver + */ +static void __devinit platinum_init_info(struct fb_info *info, struct fb_info_platinum *pinfo) +{ + /* Fill fb_info */ + info->fbops = &platinumfb_ops; + info->pseudo_palette = pinfo->pseudo_palette; + info->flags = FBINFO_DEFAULT; + info->screen_base = pinfo->frame_buffer + 0x20; + + fb_alloc_cmap(&info->cmap, 256, 0); + + /* Fill fix common fields */ + strcpy(info->fix.id, "platinum"); + info->fix.mmio_start = pinfo->platinum_regs_phys; + info->fix.mmio_len = 0x1000; + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.smem_start = pinfo->frame_buffer_phys + 0x20; /* will be updated later */ + info->fix.smem_len = pinfo->total_vram - 0x20; + info->fix.ywrapstep = 0; + info->fix.xpanstep = 0; + info->fix.ypanstep = 0; + info->fix.type_aux = 0; + info->fix.accel = FB_ACCEL_NONE; +} + + +static int __devinit platinum_init_fb(struct fb_info *info) +{ + struct fb_info_platinum *pinfo = info->par; + struct fb_var_screeninfo var; + int sense, rc; + + sense = read_platinum_sense(pinfo); + printk(KERN_INFO "platinumfb: Monitor sense value = 0x%x, ", sense); + + if (default_vmode == VMODE_NVRAM) { + default_vmode = nvram_read_byte(NV_VMODE); + if (default_vmode <= 0 || default_vmode > VMODE_MAX || + !platinum_reg_init[default_vmode-1]) + default_vmode = VMODE_CHOOSE; + } + if (default_vmode == VMODE_CHOOSE) { + default_vmode = mac_map_monitor_sense(sense); + } + if (default_vmode <= 0 || default_vmode > VMODE_MAX) + default_vmode = VMODE_640_480_60; + if (default_cmode == CMODE_NVRAM) + default_cmode = nvram_read_byte(NV_CMODE); + if (default_cmode < CMODE_8 || default_cmode > CMODE_32) + default_cmode = CMODE_8; + /* + * Reduce the pixel size if we don't have enough VRAM. + */ + while(default_cmode > CMODE_8 && + platinum_vram_reqd(default_vmode, default_cmode) > pinfo->total_vram) + default_cmode--; + + printk("platinumfb: Using video mode %d and color mode %d.\n", default_vmode, default_cmode); + + /* Setup default var */ + if (mac_vmode_to_var(default_vmode, default_cmode, &var) < 0) { + /* This shouldn't happen! */ + printk("mac_vmode_to_var(%d, %d,) failed\n", default_vmode, default_cmode); +try_again: + default_vmode = VMODE_640_480_60; + default_cmode = CMODE_8; + if (mac_vmode_to_var(default_vmode, default_cmode, &var) < 0) { + printk(KERN_ERR "platinumfb: mac_vmode_to_var() failed\n"); + return -ENXIO; + } + } + + /* Initialize info structure */ + platinum_init_info(info, pinfo); + + /* Apply default var */ + info->var = var; + var.activate = FB_ACTIVATE_NOW; + rc = fb_set_var(info, &var); + if (rc && (default_vmode != VMODE_640_480_60 || default_cmode != CMODE_8)) + goto try_again; + + /* Register with fbdev layer */ + rc = register_framebuffer(info); + if (rc < 0) + return rc; + + printk(KERN_INFO "fb%d: Apple Platinum frame buffer device\n", info->node); + + return 0; +} + +/* + * Get the monitor sense value. + * Note that this can be called before calibrate_delay, + * so we can't use udelay. + */ +static int read_platinum_sense(struct fb_info_platinum *info) +{ + volatile struct platinum_regs __iomem *platinum_regs = info->platinum_regs; + int sense; + + out_be32(&platinum_regs->reg[23].r, 7); /* turn off drivers */ + __delay(2000); + sense = (~in_be32(&platinum_regs->reg[23].r) & 7) << 8; + + /* drive each sense line low in turn and collect the other 2 */ + out_be32(&platinum_regs->reg[23].r, 3); /* drive A low */ + __delay(2000); + sense |= (~in_be32(&platinum_regs->reg[23].r) & 3) << 4; + out_be32(&platinum_regs->reg[23].r, 5); /* drive B low */ + __delay(2000); + sense |= (~in_be32(&platinum_regs->reg[23].r) & 4) << 1; + sense |= (~in_be32(&platinum_regs->reg[23].r) & 1) << 2; + out_be32(&platinum_regs->reg[23].r, 6); /* drive C low */ + __delay(2000); + sense |= (~in_be32(&platinum_regs->reg[23].r) & 6) >> 1; + + out_be32(&platinum_regs->reg[23].r, 7); /* turn off drivers */ + + return sense; +} + +/* + * This routine takes a user-supplied var, and picks the best vmode/cmode from it. + * It also updates the var structure to the actual mode data obtained + */ +static int platinum_var_to_par(struct fb_var_screeninfo *var, + struct fb_info_platinum *pinfo, + int check_only) +{ + int vmode, cmode; + + if (mac_var_to_vmode(var, &vmode, &cmode) != 0) { + printk(KERN_ERR "platinum_var_to_par: mac_var_to_vmode unsuccessful.\n"); + printk(KERN_ERR "platinum_var_to_par: var->xres = %d\n", var->xres); + printk(KERN_ERR "platinum_var_to_par: var->yres = %d\n", var->yres); + printk(KERN_ERR "platinum_var_to_par: var->xres_virtual = %d\n", var->xres_virtual); + printk(KERN_ERR "platinum_var_to_par: var->yres_virtual = %d\n", var->yres_virtual); + printk(KERN_ERR "platinum_var_to_par: var->bits_per_pixel = %d\n", var->bits_per_pixel); + printk(KERN_ERR "platinum_var_to_par: var->pixclock = %d\n", var->pixclock); + printk(KERN_ERR "platinum_var_to_par: var->vmode = %d\n", var->vmode); + return -EINVAL; + } + + if (!platinum_reg_init[vmode-1]) { + printk(KERN_ERR "platinum_var_to_par, vmode %d not valid.\n", vmode); + return -EINVAL; + } + + if (platinum_vram_reqd(vmode, cmode) > pinfo->total_vram) { + printk(KERN_ERR "platinum_var_to_par, not enough ram for vmode %d, cmode %d.\n", vmode, cmode); + return -EINVAL; + } + + if (mac_vmode_to_var(vmode, cmode, var)) + return -EINVAL; + + if (check_only) + return 0; + + pinfo->vmode = vmode; + pinfo->cmode = cmode; + pinfo->xres = vmode_attrs[vmode-1].hres; + pinfo->yres = vmode_attrs[vmode-1].vres; + pinfo->xoffset = 0; + pinfo->yoffset = 0; + pinfo->vxres = pinfo->xres; + pinfo->vyres = pinfo->yres; + + return 0; +} + + +/* + * Parse user speficied options (`video=platinumfb:') + */ +int __init platinumfb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "vmode:", 6)) { + int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + default_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + int depth = simple_strtoul(this_opt+6, NULL, 0); + switch (depth) { + case 0: + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + case 24: + case 32: + default_cmode = CMODE_32; + break; + } + } + } + return 0; +} + +#ifdef __powerpc__ +#define invalidate_cache(addr) \ + asm volatile("eieio; dcbf 0,%1" \ + : "=m" (*(addr)) : "r" (addr) : "memory"); +#else +#define invalidate_cache(addr) +#endif + +static int __devinit platinumfb_probe(struct of_device* odev, const struct of_match *match) +{ + struct device_node *dp = odev->node; + struct fb_info *info; + struct fb_info_platinum *pinfo; + unsigned long addr, size; + volatile __u8 *fbuffer; + int i, bank0, bank1, bank2, bank3, rc; + + if (dp->n_addrs != 2) { + printk(KERN_ERR "expecting 2 address for platinum (got %d)", dp->n_addrs); + return -ENXIO; + } + printk(KERN_INFO "platinumfb: Found Apple Platinum video hardware\n"); + + info = framebuffer_alloc(sizeof(*pinfo), &odev->dev); + if (info == NULL) + return -ENOMEM; + pinfo = info->par; + + /* Map in frame buffer and registers */ + for (i = 0; i < dp->n_addrs; ++i) { + addr = dp->addrs[i].address; + size = dp->addrs[i].size; + /* Let's assume we can request either all or nothing */ + if (!request_mem_region(addr, size, "platinumfb")) { + framebuffer_release(info); + return -ENXIO; + } + if (size >= 0x400000) { + /* frame buffer - map only 4MB */ + pinfo->frame_buffer_phys = addr; + pinfo->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU); + pinfo->base_frame_buffer = pinfo->frame_buffer; + } else { + /* registers */ + pinfo->platinum_regs_phys = addr; + pinfo->platinum_regs = ioremap(addr, size); + } + } + + pinfo->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ + request_mem_region(pinfo->cmap_regs_phys, 0x1000, "platinumfb cmap"); + pinfo->cmap_regs = ioremap(pinfo->cmap_regs_phys, 0x1000); + + /* Grok total video ram */ + out_be32(&pinfo->platinum_regs->reg[16].r, (unsigned)pinfo->frame_buffer_phys); + out_be32(&pinfo->platinum_regs->reg[20].r, 0x1011); /* select max vram */ + out_be32(&pinfo->platinum_regs->reg[24].r, 0); /* switch in vram */ + + fbuffer = pinfo->base_frame_buffer; + fbuffer[0x100000] = 0x34; + fbuffer[0x100008] = 0x0; + invalidate_cache(&fbuffer[0x100000]); + fbuffer[0x200000] = 0x56; + fbuffer[0x200008] = 0x0; + invalidate_cache(&fbuffer[0x200000]); + fbuffer[0x300000] = 0x78; + fbuffer[0x300008] = 0x0; + invalidate_cache(&fbuffer[0x300000]); + bank0 = 1; /* builtin 1MB vram, always there */ + bank1 = fbuffer[0x100000] == 0x34; + bank2 = fbuffer[0x200000] == 0x56; + bank3 = fbuffer[0x300000] == 0x78; + pinfo->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000; + printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n", (int) (pinfo->total_vram / 1024 / 1024), + bank3, bank2, bank1, bank0); + + /* + * Try to determine whether we have an old or a new DACula. + */ + out_8(&pinfo->cmap_regs->addr, 0x40); + pinfo->dactype = in_8(&pinfo->cmap_regs->d2); + switch (pinfo->dactype) { + case 0x3c: + pinfo->clktype = 1; + printk(KERN_INFO "platinumfb: DACula type 0x3c\n"); + break; + case 0x84: + pinfo->clktype = 0; + printk(KERN_INFO "platinumfb: DACula type 0x84\n"); + break; + default: + pinfo->clktype = 0; + printk(KERN_INFO "platinumfb: Unknown DACula type: %x\n", pinfo->dactype); + break; + } + dev_set_drvdata(&odev->dev, info); + + rc = platinum_init_fb(info); + if (rc != 0) { + dev_set_drvdata(&odev->dev, NULL); + framebuffer_release(info); + } + + return rc; +} + +static int __devexit platinumfb_remove(struct of_device* odev) +{ + struct fb_info *info = dev_get_drvdata(&odev->dev); + struct fb_info_platinum *pinfo = info->par; + struct device_node *dp = odev->node; + unsigned long addr, size; + int i; + + unregister_framebuffer (info); + + /* Unmap frame buffer and registers */ + for (i = 0; i < dp->n_addrs; ++i) { + addr = dp->addrs[i].address; + size = dp->addrs[i].size; + release_mem_region(addr, size); + } + iounmap(pinfo->frame_buffer); + iounmap(pinfo->platinum_regs); + release_mem_region(pinfo->cmap_regs_phys, 0x1000); + iounmap(pinfo->cmap_regs); + + framebuffer_release(info); + + return 0; +} + +static struct of_match platinumfb_match[] = +{ + { + .name = "platinum", + .type = OF_ANY_MATCH, + .compatible = OF_ANY_MATCH, + }, + {}, +}; + +static struct of_platform_driver platinum_driver = +{ + .name = "platinumfb", + .match_table = platinumfb_match, + .probe = platinumfb_probe, + .remove = platinumfb_remove, +}; + +int __init platinumfb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("platinumfb", &option)) + return -ENODEV; + platinumfb_setup(option); +#endif + of_register_driver(&platinum_driver); + + return 0; +} + +void __exit platinumfb_exit(void) +{ + of_unregister_driver(&platinum_driver); +} + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("framebuffer driver for Apple Platinum video"); +module_init(platinumfb_init); + +#ifdef MODULE +module_exit(platinumfb_exit); +#endif diff --git a/drivers/video/platinumfb.h b/drivers/video/platinumfb.h new file mode 100644 index 000000000000..2834fc1c344b --- /dev/null +++ b/drivers/video/platinumfb.h @@ -0,0 +1,366 @@ +/* + * linux/drivers/video/platinumfb-hw.c -- Frame buffer device for the + * Platinum on-board video in PowerMac 7200s (and some clones based + * on the same motherboard.) + * + * Created 09 Feb 1998 by Jon Howell <jonh@cs.dartmouth.edu> + * + * Copyright (C) 1998 Jon Howell + * + * based on drivers/macintosh/platinum.c: Console support + * for PowerMac "platinum" display adaptor. + * Copyright (C) 1996 Paul Mackerras and Mark Abene. + * + * based on skeletonfb.c: + * Created 28 Dec 1997 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. + */ + +/* + * Structure of the registers for the DACula colormap device. + */ +struct cmap_regs { + unsigned char addr; + char pad1[15]; + unsigned char d1; + char pad2[15]; + unsigned char d2; + char pad3[15]; + unsigned char lut; + char pad4[15]; +}; + +/* + * Structure of the registers for the "platinum" display adaptor". + */ +struct preg { /* padded register */ + unsigned r; /* notice this is 32 bits. */ + char pad[12]; +}; + +struct platinum_regs { + struct preg reg[128]; +}; + +/* + * Register initialization tables for the platinum display. + * + * It seems that there are two different types of platinum display + * out there. Older ones use the values in clocksel[1], for which + * the formula for the clock frequency seems to be + * F = 14.3MHz * c0 / (c1 & 0x1f) / (1 << (c1 >> 5)) + * Newer ones use the values in clocksel[0], for which the formula + * seems to be + * F = 15MHz * c0 / ((c1 & 0x1f) + 2) / (1 << (c1 >> 5)) + */ +struct platinum_regvals { + int fb_offset; + int pitch[3]; + unsigned regs[26]; + unsigned char offset[3]; + unsigned char mode[3]; + unsigned char dacula_ctrl[3]; + unsigned char clock_params[2][2]; +}; + +#define DIV2 0x20 +#define DIV4 0x40 +#define DIV8 0x60 +#define DIV16 0x80 + +/* 1280x1024, 75Hz (20) */ +static struct platinum_regvals platinum_reg_init_20 = { + 0x5c00, + { 1312, 2592, 2592 }, + { 0xffc, 4, 0, 0, 0, 0, 0x428, 0, + 0, 0xb3, 0xd3, 0x12, 0x1a5, 0x23, 0x28, 0x2d, + 0x5e, 0x19e, 0x1a4, 0x854, 0x852, 4, 9, 0x50, + 0x850, 0x851 }, { 0x58, 0x5d, 0x5d }, + { 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 }, + {{ 45, 3 }, { 66, 7 }} +}; + +/* 1280x960, 75Hz (19) */ +static struct platinum_regvals platinum_reg_init_19 = { + 0x5c00, + { 1312, 2592, 2592 }, + { 0xffc, 4, 0, 0, 0, 0, 0x428, 0, + 0, 0xb2, 0xd2, 0x12, 0x1a3, 0x23, 0x28, 0x2d, + 0x5c, 0x19c, 0x1a2, 0x7d0, 0x7ce, 4, 9, 0x4c, + 0x7cc, 0x7cd }, { 0x56, 0x5b, 0x5b }, + { 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 }, + {{ 42, 3 }, { 44, 5 }} +}; + +/* 1152x870, 75Hz (18) */ +static struct platinum_regvals platinum_reg_init_18 = { + 0x11b0, + { 1184, 2336, 4640 }, + { 0xff0, 4, 0, 0, 0, 0, 0x38f, 0, + 0, 0x294, 0x16c, 0x20, 0x2d7, 0x3f, 0x49, 0x53, + 0x82, 0x2c2, 0x2d6, 0x726, 0x724, 4, 9, 0x52, + 0x71e, 0x722 }, { 0x74, 0x7c, 0x81 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 26, 0 + DIV2 }, { 42, 6 }} +}; + +/* 1024x768, 75Hz (17) */ +static struct platinum_regvals platinum_reg_init_17 = { + 0x10b0, + { 1056, 2080, 4128 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x254, 0x14b, 0x18, 0x295, 0x2f, 0x32, 0x3b, + 0x80, 0x280, 0x296, 0x648, 0x646, 4, 9, 0x40, + 0x640, 0x644 }, { 0x72, 0x7a, 0x7f }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 54, 3 + DIV2 }, { 67, 12 }} +}; + +/* 1024x768, 75Hz (16) */ +static struct platinum_regvals platinum_reg_init_16 = { + 0x10b0, + { 1056, 2080, 4128 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x250, 0x147, 0x17, 0x28f, 0x2f, 0x35, 0x47, + 0x82, 0x282, 0x28e, 0x640, 0x63e, 4, 9, 0x3c, + 0x63c, 0x63d }, { 0x74, 0x7c, 0x81 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 20, 0 + DIV2 }, { 11, 2 }} +}; + +/* 1024x768, 70Hz (15) */ +static struct platinum_regvals platinum_reg_init_15 = { + 0x10b0, + { 1056, 2080, 4128 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x254, 0x14b, 0x22, 0x297, 0x43, 0x49, 0x5b, + 0x86, 0x286, 0x296, 0x64c, 0x64a, 0xa, 0xf, 0x44, + 0x644, 0x646 }, { 0x78, 0x80, 0x85 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 19, 0 + DIV2 }, { 110, 21 }} +}; + +/* 1024x768, 60Hz (14) */ +static struct platinum_regvals platinum_reg_init_14 = { + 0x10b0, + { 1056, 2080, 4128 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x25a, 0x14f, 0x22, 0x29f, 0x43, 0x49, 0x5b, + 0x8e, 0x28e, 0x29e, 0x64c, 0x64a, 0xa, 0xf, 0x44, + 0x644, 0x646 }, { 0x80, 0x88, 0x8d }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 71, 6 + DIV2 }, { 118, 13 + DIV2 }} +}; + +/* 832x624, 75Hz (13) */ +static struct platinum_regvals platinum_reg_init_13 = { + 0x70, + { 864, 1680, 3360 }, /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */ + { 0xff0, 4, 0, 0, 0, 0, 0x299, 0, + 0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37, + 0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52, + 0x532, 0x533 }, { 0x7c, 0x84, 0x89 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }} +}; + +/* 800x600, 75Hz (12) */ +static struct platinum_regvals platinum_reg_init_12 = { + 0x1010, + { 832, 1632, 3232 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x1ce, 0x108, 0x14, 0x20f, 0x27, 0x30, 0x39, + 0x72, 0x202, 0x20e, 0x4e2, 0x4e0, 4, 9, 0x2e, + 0x4de, 0x4df }, { 0x64, 0x6c, 0x71 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 122, 7 + DIV4 }, { 62, 9 + DIV2 }} +}; + +/* 800x600, 72Hz (11) */ +static struct platinum_regvals platinum_reg_init_11 = { + 0x1010, + { 832, 1632, 3232 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x1ca, 0x104, 0x1e, 0x207, 0x3b, 0x44, 0x4d, + 0x56, 0x1e6, 0x206, 0x534, 0x532, 0xa, 0xe, 0x38, + 0x4e8, 0x4ec }, { 0x48, 0x50, 0x55 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 26, 0 + DIV4 }, { 42, 6 + DIV2 }} +}; + +/* 800x600, 60Hz (10) */ +static struct platinum_regvals platinum_reg_init_10 = { + 0x1010, + { 832, 1632, 3232 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d, + 0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34, + 0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 54, 3 + DIV4 }, { 95, 1 + DIV8 }} +}; + +/* 800x600, 56Hz (9) --unsupported? copy of mode 10 for now... */ +static struct platinum_regvals platinum_reg_init_9 = { + 0x1010, + { 832, 1632, 3232 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d, + 0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34, + 0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 54, 3 + DIV4 }, { 88, 1 + DIV8 }} +}; + +/* 768x576, 50Hz Interlaced-PAL (8) */ +static struct platinum_regvals platinum_reg_init_8 = { + 0x1010, + { 800, 1568, 3104 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36, + 0x47, 0x1c7, 0x1d6, 0x271, 0x270, 4, 9, 0x27, + 0x267, 0x26b }, { 0x39, 0x41, 0x46 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }} +}; + +/* 640x870, 75Hz Portrait (7) */ +static struct platinum_regvals platinum_reg_init_7 = { + 0xb10, + { 672, 1312, 2592 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x176, 0xd0, 0x14, 0x19f, 0x27, 0x2d, 0x3f, + 0x4a, 0x18a, 0x19e, 0x72c, 0x72a, 4, 9, 0x58, + 0x724, 0x72a }, { 0x3c, 0x44, 0x49 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }} +}; + +/* 640x480, 67Hz (6) */ +static struct platinum_regvals platinum_reg_init_6 = { + 0x1010, + { 672, 1312, 2592 }, + { 0xff0, 4, 0, 0, 0, 0, 0x209, 0, + 0, 0x18e, 0xd8, 0x10, 0x1af, 0x1f, 0x25, 0x37, + 0x4a, 0x18a, 0x1ae, 0x41a, 0x418, 4, 9, 0x52, + 0x412, 0x416 }, { 0x3c, 0x44, 0x49 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 99, 4 + DIV8 }, { 42, 5 + DIV4 }} +}; + +/* 640x480, 60Hz (5) */ +static struct platinum_regvals platinum_reg_init_5 = { + 0x1010, + { 672, 1312, 2592 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x15e, 0xc8, 0x18, 0x18f, 0x2f, 0x35, 0x3e, + 0x42, 0x182, 0x18e, 0x41a, 0x418, 2, 7, 0x44, + 0x404, 0x408 }, { 0x34, 0x3c, 0x41 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 26, 0 + DIV8 }, { 14, 2 + DIV4 }} +}; + +/* 640x480, 60Hz Interlaced-NTSC (4) */ +static struct platinum_regvals platinum_reg_init_4 = { + 0x1010, + { 672, 1312, 2592 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30, + 0x37, 0x177, 0x184, 0x20d, 0x20c, 5, 0xb, 0x23, + 0x203, 0x206 }, { 0x29, 0x31, 0x36 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }} +}; + +/* 640x480, 50Hz Interlaced-PAL (3) */ +static struct platinum_regvals platinum_reg_init_3 = { + 0x1010, + { 672, 1312, 2592 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36, + 0x67, 0x1a7, 0x1d6, 0x271, 0x270, 4, 9, 0x57, + 0x237, 0x26b }, { 0x59, 0x61, 0x66 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }} +}; + +/* 512x384, 60Hz (2) */ +static struct platinum_regvals platinum_reg_init_2 = { + 0x1010, + { 544, 1056, 2080 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x25c, 0x140, 0x10, 0x27f, 0x1f, 0x2b, 0x4f, + 0x68, 0x268, 0x27e, 0x32e, 0x32c, 4, 9, 0x2a, + 0x32a, 0x32b }, { 0x5a, 0x62, 0x67 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 33, 2 + DIV8 }, { 79, 9 + DIV8 }} +}; + +/* 512x384, 60Hz Interlaced-NTSC (1) */ +static struct platinum_regvals platinum_reg_init_1 = { + 0x1010, + { 544, 1056, 2080 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30, + 0x57, 0x157, 0x184, 0x20d, 0x20c, 5, 0xb, 0x53, + 0x1d3, 0x206 }, { 0x49, 0x51, 0x56 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }} +}; + +static struct platinum_regvals *platinum_reg_init[VMODE_MAX] = { + &platinum_reg_init_1, + &platinum_reg_init_2, + &platinum_reg_init_3, + &platinum_reg_init_4, + &platinum_reg_init_5, + &platinum_reg_init_6, + &platinum_reg_init_7, + &platinum_reg_init_8, + &platinum_reg_init_9, + &platinum_reg_init_10, + &platinum_reg_init_11, + &platinum_reg_init_12, + &platinum_reg_init_13, + &platinum_reg_init_14, + &platinum_reg_init_15, + &platinum_reg_init_16, + &platinum_reg_init_17, + &platinum_reg_init_18, + &platinum_reg_init_19, + &platinum_reg_init_20 +}; + +struct vmode_attr { + int hres; + int vres; + int vfreq; + int interlaced; +}; + +struct vmode_attr vmode_attrs[VMODE_MAX] = { + {512, 384, 60, 1}, + {512, 384, 60}, + {640, 480, 50, 1}, + {640, 480, 60, 1}, + {640, 480, 60}, + {640, 480, 67}, + {640, 870, 75}, + {768, 576, 50, 1}, + {800, 600, 56}, + {800, 600, 60}, + {800, 600, 72}, + {800, 600, 75}, + {832, 624, 75}, + {1024, 768, 60}, + {1024, 768, 72}, + {1024, 768, 75}, + {1024, 768, 75}, + {1152, 870, 75}, + {1280, 960, 75}, + {1280, 1024, 75} +}; + diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c new file mode 100644 index 000000000000..5dceddedf507 --- /dev/null +++ b/drivers/video/pm2fb.c @@ -0,0 +1,1314 @@ +/* + * Permedia2 framebuffer driver. + * + * 2.5/2.6 driver: + * Copyright (c) 2003 Jim Hague (jim.hague@acm.org) + * + * based on 2.4 driver: + * Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) + * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com) + * + * and additional input from James Simmon's port of Hannu Mallat's tdfx + * driver. + * + * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I + * have no access to other pm2fb implementations. Sparc (and thus + * hopefully other big-endian) devices now work, thanks to a lot of + * testing work by Ron Murray. I have no access to CVision hardware, + * and therefore for now I am omitting the CVision code. + * + * Multiple boards support has been on the TODO list for ages. + * Don't expect this to change. + * + * 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/config.h> +#include <linux/module.h> +#include <linux/moduleparam.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/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <video/permedia2.h> +#include <video/cvisionppc.h> + +#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN) +#error "The endianness of the target host has not been defined." +#endif + +#if !defined(CONFIG_PCI) +#error "Only generic PCI cards supported." +#endif + +#undef PM2FB_MASTER_DEBUG +#ifdef PM2FB_MASTER_DEBUG +#define DPRINTK(a,b...) printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b) +#else +#define DPRINTK(a,b...) +#endif + +/* + * Driver data + */ +static char *mode __devinitdata = NULL; + +/* + * The XFree GLINT driver will (I think to implement hardware cursor + * support on TVP4010 and similar where there is no RAMDAC - see + * comment in set_video) always request +ve sync regardless of what + * the mode requires. This screws me because I have a Sun + * fixed-frequency monitor which absolutely has to have -ve sync. So + * these flags allow the user to specify that requests for +ve sync + * should be silently turned in -ve sync. + */ +static int lowhsync __devinitdata = 0; +static int lowvsync __devinitdata = 0; + +/* + * The hardware state of the graphics card that isn't part of the + * screeninfo. + */ +struct pm2fb_par +{ + pm2type_t type; /* Board type */ + u32 fb_size; /* framebuffer memory size */ + unsigned char __iomem *v_fb; /* virtual address of frame buffer */ + unsigned char __iomem *v_regs;/* virtual address of p_regs */ + u32 memclock; /* memclock */ + u32 video; /* video flags before blanking */ + u32 mem_config; /* MemConfig reg at probe */ + u32 mem_control; /* MemControl reg at probe */ + u32 boot_address; /* BootAddress reg at probe */ +}; + +/* + * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo + * if we don't use modedb. + */ +static struct fb_fix_screeninfo pm2fb_fix __devinitdata = { + .id = "", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .xpanstep = 1, + .ypanstep = 1, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +/* + * Default video mode. In case the modedb doesn't work. + */ +static struct fb_var_screeninfo pm2fb_var __devinitdata = { + /* "640x480, 8 bpp @ 60 Hz */ + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 480, + .bits_per_pixel =8, + .red = {0, 8, 0}, + .blue = {0, 8, 0}, + .green = {0, 8, 0}, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .accel_flags = 0, + .pixclock = 39721, + .left_margin = 40, + .right_margin = 24, + .upper_margin = 32, + .lower_margin = 11, + .hsync_len = 96, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED +}; + +/* + * Utility functions + */ + +inline static u32 RD32(unsigned char __iomem *base, s32 off) +{ + return fb_readl(base + off); +} + +inline static void WR32(unsigned char __iomem *base, s32 off, u32 v) +{ + fb_writel(v, base + off); +} + +inline static u32 pm2_RD(struct pm2fb_par* p, s32 off) +{ + return RD32(p->v_regs, off); +} + +inline static void pm2_WR(struct pm2fb_par* p, s32 off, u32 v) +{ + WR32(p->v_regs, off, v); +} + +inline static u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx) +{ + int index = PM2R_RD_INDEXED_DATA; + switch (p->type) { + case PM2_TYPE_PERMEDIA2: + pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); + break; + case PM2_TYPE_PERMEDIA2V: + pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); + index = PM2VR_RD_INDEXED_DATA; + break; + } + mb(); + return pm2_RD(p, index); +} + +inline static void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) +{ + int index = PM2R_RD_INDEXED_DATA; + switch (p->type) { + case PM2_TYPE_PERMEDIA2: + pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); + break; + case PM2_TYPE_PERMEDIA2V: + pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); + index = PM2VR_RD_INDEXED_DATA; + break; + } + mb(); + pm2_WR(p, index, v); +} + +inline static void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) +{ + pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); + mb(); + pm2_WR(p, PM2VR_RD_INDEXED_DATA, v); +} + +#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT +#define WAIT_FIFO(p,a) +#else +inline static void WAIT_FIFO(struct pm2fb_par* p, u32 a) +{ + while( pm2_RD(p, PM2R_IN_FIFO_SPACE) < a ); + mb(); +} +#endif + +/* + * partial products for the supported horizontal resolutions. + */ +#define PACKPP(p0,p1,p2) (((p2) << 6) | ((p1) << 3) | (p0)) +static const struct { + u16 width; + u16 pp; +} pp_table[] = { + { 32, PACKPP(1, 0, 0) }, { 64, PACKPP(1, 1, 0) }, + { 96, PACKPP(1, 1, 1) }, { 128, PACKPP(2, 1, 1) }, + { 160, PACKPP(2, 2, 1) }, { 192, PACKPP(2, 2, 2) }, + { 224, PACKPP(3, 2, 1) }, { 256, PACKPP(3, 2, 2) }, + { 288, PACKPP(3, 3, 1) }, { 320, PACKPP(3, 3, 2) }, + { 384, PACKPP(3, 3, 3) }, { 416, PACKPP(4, 3, 1) }, + { 448, PACKPP(4, 3, 2) }, { 512, PACKPP(4, 3, 3) }, + { 544, PACKPP(4, 4, 1) }, { 576, PACKPP(4, 4, 2) }, + { 640, PACKPP(4, 4, 3) }, { 768, PACKPP(4, 4, 4) }, + { 800, PACKPP(5, 4, 1) }, { 832, PACKPP(5, 4, 2) }, + { 896, PACKPP(5, 4, 3) }, { 1024, PACKPP(5, 4, 4) }, + { 1056, PACKPP(5, 5, 1) }, { 1088, PACKPP(5, 5, 2) }, + { 1152, PACKPP(5, 5, 3) }, { 1280, PACKPP(5, 5, 4) }, + { 1536, PACKPP(5, 5, 5) }, { 1568, PACKPP(6, 5, 1) }, + { 1600, PACKPP(6, 5, 2) }, { 1664, PACKPP(6, 5, 3) }, + { 1792, PACKPP(6, 5, 4) }, { 2048, PACKPP(6, 5, 5) }, + { 0, 0 } }; + +static u32 partprod(u32 xres) +{ + int i; + + for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++) + ; + if ( pp_table[i].width == 0 ) + DPRINTK("invalid width %u\n", xres); + return pp_table[i].pp; +} + +static u32 to3264(u32 timing, int bpp, int is64) +{ + switch (bpp) { + case 8: + timing >>= 2 + is64; + break; + case 16: + timing >>= 1 + is64; + break; + case 24: + timing = (timing * 3) >> (2 + is64); + break; + case 32: + if (is64) + timing >>= 1; + break; + } + return timing; +} + +static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn, + unsigned char* pp) +{ + unsigned char m; + unsigned char n; + unsigned char p; + u32 f; + s32 curr; + s32 delta = 100000; + + *mm = *nn = *pp = 0; + for (n = 2; n < 15; n++) { + for (m = 2; m; m++) { + f = PM2_REFERENCE_CLOCK * m / n; + if (f >= 150000 && f <= 300000) { + for ( p = 0; p < 5; p++, f >>= 1) { + curr = ( clk > f ) ? clk - f : f - clk; + if ( curr < delta ) { + delta=curr; + *mm=m; + *nn=n; + *pp=p; + } + } + } + } + } +} + +static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn, + unsigned char* pp) +{ + unsigned char m; + unsigned char n; + unsigned char p; + u32 f; + s32 delta = 1000; + + *mm = *nn = *pp = 0; + for (n = 1; n; n++) { + for ( m = 1; m; m++) { + for ( p = 0; p < 2; p++) { + f = PM2_REFERENCE_CLOCK * n / (m * (1 << (p + 1))); + if ( clk > f - delta && clk < f + delta ) { + delta = ( clk > f ) ? clk - f : f - clk; + *mm=m; + *nn=n; + *pp=p; + } + } + } + } +} + +static void clear_palette(struct pm2fb_par* p) { + int i=256; + + WAIT_FIFO(p, 1); + pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0); + wmb(); + while (i--) { + WAIT_FIFO(p, 3); + pm2_WR(p, PM2R_RD_PALETTE_DATA, 0); + pm2_WR(p, PM2R_RD_PALETTE_DATA, 0); + pm2_WR(p, PM2R_RD_PALETTE_DATA, 0); + } +} + +static void reset_card(struct pm2fb_par* p) +{ + if (p->type == PM2_TYPE_PERMEDIA2V) + pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0); + pm2_WR(p, PM2R_RESET_STATUS, 0); + mb(); + while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET) + ; + mb(); +#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT + DPRINTK("FIFO disconnect enabled\n"); + pm2_WR(p, PM2R_FIFO_DISCON, 1); + mb(); +#endif + + /* Restore stashed memory config information from probe */ + WAIT_FIFO(p, 3); + pm2_WR(p, PM2R_MEM_CONTROL, p->mem_control); + pm2_WR(p, PM2R_BOOT_ADDRESS, p->boot_address); + wmb(); + pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config); +} + +static void reset_config(struct pm2fb_par* p) +{ + WAIT_FIFO(p, 52); + pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)& + ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED)); + pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L)); + pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L)); + pm2_WR(p, PM2R_FIFO_CONTROL, 0); + pm2_WR(p, PM2R_APERTURE_ONE, 0); + pm2_WR(p, PM2R_APERTURE_TWO, 0); + pm2_WR(p, PM2R_RASTERIZER_MODE, 0); + pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB); + pm2_WR(p, PM2R_LB_READ_FORMAT, 0); + pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0); + pm2_WR(p, PM2R_LB_READ_MODE, 0); + pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0); + pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0); + pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0); + pm2_WR(p, PM2R_FB_WINDOW_BASE, 0); + pm2_WR(p, PM2R_LB_WINDOW_BASE, 0); + pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L)); + pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L)); + pm2_WR(p, PM2R_FB_READ_PIXEL, 0); + pm2_WR(p, PM2R_DITHER_MODE, 0); + pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0); + pm2_WR(p, PM2R_DEPTH_MODE, 0); + pm2_WR(p, PM2R_STENCIL_MODE, 0); + pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0); + pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0); + pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0); + pm2_WR(p, PM2R_YUV_MODE, 0); + pm2_WR(p, PM2R_COLOR_DDA_MODE, 0); + pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0); + pm2_WR(p, PM2R_FOG_MODE, 0); + pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0); + pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0); + pm2_WR(p, PM2R_STATISTICS_MODE, 0); + pm2_WR(p, PM2R_SCISSOR_MODE, 0); + pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION); + switch (p->type) { + case PM2_TYPE_PERMEDIA2: + pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */ + pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0); + pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8); + break; + case PM2_TYPE_PERMEDIA2V: + pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */ + break; + } + pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0); + pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0); + pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0); + pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0); + pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0); +} + +static void set_aperture(struct pm2fb_par* p, u32 depth) +{ + /* + * The hardware is little-endian. When used in big-endian + * hosts, the on-chip aperture settings are used where + * possible to translate from host to card byte order. + */ + WAIT_FIFO(p, 4); +#ifdef __LITTLE_ENDIAN + pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD); +#else + switch (depth) { + case 24: /* RGB->BGR */ + /* + * We can't use the aperture to translate host to + * card byte order here, so we switch to BGR mode + * in pm2fb_set_par(). + */ + case 8: /* B->B */ + pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD); + break; + case 16: /* HL->LH */ + pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_HALFWORDSWAP); + break; + case 32: /* RGBA->ABGR */ + pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_BYTESWAP); + break; + } +#endif + + // We don't use aperture two, so this may be superflous + pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD); +} + +static void set_color(struct pm2fb_par* p, unsigned char regno, + unsigned char r, unsigned char g, unsigned char b) +{ + WAIT_FIFO(p, 4); + pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, regno); + wmb(); + pm2_WR(p, PM2R_RD_PALETTE_DATA, r); + wmb(); + pm2_WR(p, PM2R_RD_PALETTE_DATA, g); + wmb(); + pm2_WR(p, PM2R_RD_PALETTE_DATA, b); +} + +static void set_memclock(struct pm2fb_par* par, u32 clk) +{ + int i; + unsigned char m, n, p; + + pm2_mnp(clk, &m, &n, &p); + WAIT_FIFO(par, 10); + pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6); + wmb(); + pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m); + pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n); + wmb(); + pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p); + wmb(); + pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS); + rmb(); + for (i = 256; + i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED); + i--) + ; +} + +static void set_pixclock(struct pm2fb_par* par, u32 clk) +{ + int i; + unsigned char m, n, p; + + switch (par->type) { + case PM2_TYPE_PERMEDIA2: + pm2_mnp(clk, &m, &n, &p); + WAIT_FIFO(par, 8); + pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0); + wmb(); + pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m); + pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n); + wmb(); + pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p); + wmb(); + pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS); + rmb(); + for (i = 256; + i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED); + i--) + ; + break; + case PM2_TYPE_PERMEDIA2V: + pm2v_mnp(clk/2, &m, &n, &p); + WAIT_FIFO(par, 8); + pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8); + pm2v_RDAC_WR(par, PM2VI_RD_CLK0_PRESCALE, m); + pm2v_RDAC_WR(par, PM2VI_RD_CLK0_FEEDBACK, n); + pm2v_RDAC_WR(par, PM2VI_RD_CLK0_POSTSCALE, p); + pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); + break; + } +} + +static void set_video(struct pm2fb_par* p, u32 video) { + u32 tmp; + u32 vsync; + + vsync = video; + + DPRINTK("video = 0x%x\n", video); + + /* + * The hardware cursor needs +vsync to recognise vert retrace. + * We may not be using the hardware cursor, but the X Glint + * driver may well. So always set +hsync/+vsync and then set + * the RAMDAC to invert the sync if necessary. + */ + vsync &= ~(PM2F_HSYNC_MASK|PM2F_VSYNC_MASK); + vsync |= PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH; + + WAIT_FIFO(p, 5); + pm2_WR(p, PM2R_VIDEO_CONTROL, vsync); + + switch (p->type) { + case PM2_TYPE_PERMEDIA2: + tmp = PM2F_RD_PALETTE_WIDTH_8; + if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW) + tmp |= 4; /* invert hsync */ + if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW) + tmp |= 8; /* invert vsync */ + pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, tmp); + break; + case PM2_TYPE_PERMEDIA2V: + tmp = 0; + if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW) + tmp |= 1; /* invert hsync */ + if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW) + tmp |= 4; /* invert vsync */ + pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp); + pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); + break; + } +} + +/* + * + */ + +/** + * pm2fb_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 + * + * Checks to see if the hardware supports the state requested by + * var passed in. + * + * Returns negative errno on error, or zero on success. + */ +static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + u32 lpitch; + + if (var->bits_per_pixel != 8 && var->bits_per_pixel != 16 && + var->bits_per_pixel != 24 && var->bits_per_pixel != 32) { + DPRINTK("depth not supported: %u\n", var->bits_per_pixel); + return -EINVAL; + } + + if (var->xres != var->xres_virtual) { + DPRINTK("virtual x resolution != physical x resolution not supported\n"); + return -EINVAL; + } + + if (var->yres > var->yres_virtual) { + DPRINTK("virtual y resolution < physical y resolution not possible\n"); + return -EINVAL; + } + + if (var->xoffset) { + DPRINTK("xoffset not supported\n"); + return -EINVAL; + } + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + DPRINTK("interlace not supported\n"); + return -EINVAL; + } + + var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ + lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); + + if (var->xres < 320 || var->xres > 1600) { + DPRINTK("width not supported: %u\n", var->xres); + return -EINVAL; + } + + if (var->yres < 200 || var->yres > 1200) { + DPRINTK("height not supported: %u\n", var->yres); + return -EINVAL; + } + + if (lpitch * var->yres_virtual > info->fix.smem_len) { + DPRINTK("no memory for screen (%ux%ux%u)\n", + var->xres, var->yres_virtual, var->bits_per_pixel); + return -EINVAL; + } + + if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) { + DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); + return -EINVAL; + } + + switch(var->bits_per_pixel) { + case 8: + var->red.length = var->green.length = var->blue.length = 8; + break; + case 16: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + case 32: + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = 8; + break; + case 24: +#ifdef __BIG_ENDIAN + var->red.offset = 0; + var->blue.offset = 16; +#else + var->red.offset = 16; + var->blue.offset = 0; +#endif + var->green.offset = 8; + var->red.length = var->green.length = var->blue.length = 8; + break; + } + var->height = var->width = -1; + + var->accel_flags = 0; /* Can't mmap if this is on */ + + DPRINTK("Checking graphics mode at %dx%d depth %d\n", + var->xres, var->yres, var->bits_per_pixel); + return 0; +} + +/** + * pm2fb_set_par - Alters the hardware state. + * @info: frame buffer structure that represents a single frame buffer + * + * Using the fb_var_screeninfo in fb_info we set the resolution of the + * this particular framebuffer. + */ +static int pm2fb_set_par(struct fb_info *info) +{ + struct pm2fb_par *par = (struct pm2fb_par *) info->par; + u32 pixclock; + u32 width, height, depth; + u32 hsstart, hsend, hbend, htotal; + u32 vsstart, vsend, vbend, vtotal; + u32 stride; + u32 base; + u32 video = 0; + u32 clrmode = PM2F_RD_COLOR_MODE_RGB | PM2F_RD_GUI_ACTIVE; + u32 txtmap = 0; + u32 pixsize = 0; + u32 clrformat = 0; + u32 xres; + int data64; + + reset_card(par); + reset_config(par); + clear_palette(par); + if ( par->memclock ) + set_memclock(par, par->memclock); + + width = (info->var.xres_virtual + 7) & ~7; + height = info->var.yres_virtual; + depth = (info->var.bits_per_pixel + 7) & ~7; + depth = (depth > 32) ? 32 : depth; + data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V; + + xres = (info->var.xres + 31) & ~31; + pixclock = PICOS2KHZ(info->var.pixclock); + if (pixclock > PM2_MAX_PIXCLOCK) { + DPRINTK("pixclock too high (%uKHz)\n", pixclock); + return -EINVAL; + } + + hsstart = to3264(info->var.right_margin, depth, data64); + hsend = hsstart + to3264(info->var.hsync_len, depth, data64); + hbend = hsend + to3264(info->var.left_margin, depth, data64); + htotal = to3264(xres, depth, data64) + hbend - 1; + vsstart = (info->var.lower_margin) + ? info->var.lower_margin - 1 + : 0; /* FIXME! */ + vsend = info->var.lower_margin + info->var.vsync_len - 1; + vbend = info->var.lower_margin + info->var.vsync_len + info->var.upper_margin; + vtotal = info->var.yres + vbend - 1; + stride = to3264(width, depth, 1); + base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1); + if (data64) + video |= PM2F_DATA_64_ENABLE; + + if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) { + if (lowhsync) { + DPRINTK("ignoring +hsync, using -hsync.\n"); + video |= PM2F_HSYNC_ACT_LOW; + } else + video |= PM2F_HSYNC_ACT_HIGH; + } + else + video |= PM2F_HSYNC_ACT_LOW; + if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) { + if (lowvsync) { + DPRINTK("ignoring +vsync, using -vsync.\n"); + video |= PM2F_VSYNC_ACT_LOW; + } else + video |= PM2F_VSYNC_ACT_HIGH; + } + else + video |= PM2F_VSYNC_ACT_LOW; + if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) { + DPRINTK("interlaced not supported\n"); + return -EINVAL; + } + if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE) + video |= PM2F_LINE_DOUBLE; + if ((info->var.activate & FB_ACTIVATE_MASK)==FB_ACTIVATE_NOW) + video |= PM2F_VIDEO_ENABLE; + par->video = video; + + info->fix.visual = + (depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + info->fix.line_length = info->var.xres * depth / 8; + info->cmap.len = 256; + + /* + * Settings calculated. Now write them out. + */ + if (par->type == PM2_TYPE_PERMEDIA2V) { + WAIT_FIFO(par, 1); + pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); + } + + set_aperture(par, depth); + + mb(); + WAIT_FIFO(par, 19); + pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL, + ( depth == 8 ) ? 0 : PM2F_COLOR_KEY_TEST_OFF); + switch (depth) { + case 8: + pm2_WR(par, PM2R_FB_READ_PIXEL, 0); + clrformat = 0x0e; + break; + case 16: + pm2_WR(par, PM2R_FB_READ_PIXEL, 1); + clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB565; + txtmap = PM2F_TEXTEL_SIZE_16; + pixsize = 1; + clrformat = 0x70; + break; + case 32: + pm2_WR(par, PM2R_FB_READ_PIXEL, 2); + clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGBA8888; + txtmap = PM2F_TEXTEL_SIZE_32; + pixsize = 2; + clrformat = 0x20; + break; + case 24: + pm2_WR(par, PM2R_FB_READ_PIXEL, 4); + clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB888; + txtmap = PM2F_TEXTEL_SIZE_24; + pixsize = 4; + clrformat = 0x20; + break; + } + pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE); + pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres)); + pm2_WR(par, PM2R_LB_READ_MODE, partprod(xres)); + pm2_WR(par, PM2R_TEXTURE_MAP_FORMAT, txtmap | partprod(xres)); + pm2_WR(par, PM2R_H_TOTAL, htotal); + pm2_WR(par, PM2R_HS_START, hsstart); + pm2_WR(par, PM2R_HS_END, hsend); + pm2_WR(par, PM2R_HG_END, hbend); + pm2_WR(par, PM2R_HB_END, hbend); + pm2_WR(par, PM2R_V_TOTAL, vtotal); + pm2_WR(par, PM2R_VS_START, vsstart); + pm2_WR(par, PM2R_VS_END, vsend); + pm2_WR(par, PM2R_VB_END, vbend); + pm2_WR(par, PM2R_SCREEN_STRIDE, stride); + wmb(); + pm2_WR(par, PM2R_WINDOW_ORIGIN, 0); + pm2_WR(par, PM2R_SCREEN_SIZE, (height << 16) | width); + pm2_WR(par, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE); + wmb(); + pm2_WR(par, PM2R_SCREEN_BASE, base); + wmb(); + set_video(par, video); + WAIT_FIFO(par, 4); + switch (par->type) { + case PM2_TYPE_PERMEDIA2: + pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode); + break; + case PM2_TYPE_PERMEDIA2V: + pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize); + pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat); + break; + } + set_pixclock(par, pixclock); + DPRINTK("Setting graphics mode at %dx%d depth %d\n", + info->var.xres, info->var.yres, info->var.bits_per_pixel); + return 0; +} + +/** + * pm2fb_setcolreg - Sets a color register. + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @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. + * @info: frame buffer info structure + * + * Set a single color register. The values supplied have a 16 bit + * magnitude which needs to be scaled in this function for the hardware. + * Pretty much a direct lift from tdfxfb.c. + * + * Returns negative errno on error, or zero on success. + */ +static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct pm2fb_par *par = (struct pm2fb_par *) info->par; + + if (regno >= info->cmap.len) /* no. of hw registers */ + return 1; + /* + * Program hardware... do anything you want with transp + */ + + /* grayscale works only partially under directcolor */ + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + /* Directcolor: + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * {hardwarespecific} contains width of DAC + * cmap[X] is programmed to + * (X << red.offset) | (X << green.offset) | (X << blue.offset) + * RAMDAC[X] is programmed to (red, green, blue) + * + * Pseudocolor: + * uses offset = 0 && length = DAC register width. + * var->{color}.offset is 0 + * var->{color}.length contains widht of DAC + * cmap is not used + * DAC[X] is programmed to (red, green, blue) + * Truecolor: + * does not use RAMDAC (usually has 3 of them). + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * cmap is programmed to + * (red << red.offset) | (green << green.offset) | + * (blue << blue.offset) | (transp << transp.offset) + * RAMDAC does not exist + */ +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + case FB_VISUAL_PSEUDOCOLOR: + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + break; + case FB_VISUAL_DIRECTCOLOR: + /* example here assumes 8 bit DAC. Might be different + * for your hardware */ + red = CNVT_TOHW(red, 8); + green = CNVT_TOHW(green, 8); + blue = CNVT_TOHW(blue, 8); + /* hey, there is bug in transp handling... */ + transp = CNVT_TOHW(transp, 8); + break; + } +#undef CNVT_TOHW + /* Truecolor has hardware independent palette */ + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v; + + if (regno >= 16) + return 1; + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + + switch (info->var.bits_per_pixel) { + case 8: + break; + case 16: + case 24: + case 32: + ((u32*)(info->pseudo_palette))[regno] = v; + break; + } + return 0; + } + else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) + set_color(par, regno, red, green, blue); + + return 0; +} + +/** + * pm2fb_pan_display - Pans the display. + * @var: frame buffer variable screen structure + * @info: frame buffer structure that represents a single frame buffer + * + * Pan (or wrap, depending on the `vmode' field) the display using the + * `xoffset' and `yoffset' fields of the `var' structure. + * If the values don't fit, return -EINVAL. + * + * Returns negative errno on error, or zero on success. + * + */ +static int pm2fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct pm2fb_par *p = (struct pm2fb_par *) info->par; + u32 base; + u32 depth; + u32 xres; + + xres = (var->xres + 31) & ~31; + depth = (var->bits_per_pixel + 7) & ~7; + depth = (depth > 32) ? 32 : depth; + base = to3264(var->yoffset * xres + var->xoffset, depth, 1); + WAIT_FIFO(p, 1); + pm2_WR(p, PM2R_SCREEN_BASE, base); + return 0; +} + +/** + * pm2fb_blank - Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + * + * Blank the screen if blank_mode != 0, else unblank. Return 0 if + * blanking succeeded, != 0 if un-/blanking failed due to e.g. a + * video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + * + * Returns negative errno on error, or zero on success. + * + */ +static int pm2fb_blank(int blank_mode, struct fb_info *info) +{ + struct pm2fb_par *par = (struct pm2fb_par *) info->par; + u32 video = par->video; + + DPRINTK("blank_mode %d\n", blank_mode); + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + /* Screen: On */ + video |= PM2F_VIDEO_ENABLE; + break; + case FB_BLANK_NORMAL: + /* Screen: Off */ + video &= ~PM2F_VIDEO_ENABLE; + break; + case FB_BLANK_VSYNC_SUSPEND: + /* VSync: Off */ + video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW ); + break; + case FB_BLANK_HSYNC_SUSPEND: + /* HSync: Off */ + video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW ); + break; + case FB_BLANK_POWERDOWN: + /* HSync: Off, VSync: Off */ + video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK| PM2F_BLANK_LOW); + break; + } + set_video(par, video); + return 0; +} + +/* ------------ Hardware Independent Functions ------------ */ + +/* + * Frame buffer operations + */ + +static struct fb_ops pm2fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = pm2fb_check_var, + .fb_set_par = pm2fb_set_par, + .fb_setcolreg = pm2fb_setcolreg, + .fb_blank = pm2fb_blank, + .fb_pan_display = pm2fb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +/* + * PCI stuff + */ + + +/** + * Device initialisation + * + * Initialise and allocate resource for PCI device. + * + * @param pdev PCI device. + * @param id PCI device ID. + */ +static int __devinit pm2fb_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pm2fb_par *default_par; + struct fb_info *info; + int size, err; + int err_retval = -ENXIO; + + err = pci_enable_device(pdev); + if ( err ) { + printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err); + return err; + } + + size = sizeof(struct pm2fb_par) + 256 * sizeof(u32); + info = framebuffer_alloc(size, &pdev->dev); + if ( !info ) + return -ENOMEM; + default_par = (struct pm2fb_par *) info->par; + + switch (pdev->device) { + case PCI_DEVICE_ID_TI_TVP4020: + strcpy(pm2fb_fix.id, "TVP4020"); + default_par->type = PM2_TYPE_PERMEDIA2; + break; + case PCI_DEVICE_ID_3DLABS_PERMEDIA2: + strcpy(pm2fb_fix.id, "Permedia2"); + default_par->type = PM2_TYPE_PERMEDIA2; + break; + case PCI_DEVICE_ID_3DLABS_PERMEDIA2V: + strcpy(pm2fb_fix.id, "Permedia2v"); + default_par->type = PM2_TYPE_PERMEDIA2V; + break; + } + + pm2fb_fix.mmio_start = pci_resource_start(pdev, 0); + pm2fb_fix.mmio_len = PM2_REGS_SIZE; + +#if defined(__BIG_ENDIAN) + /* + * PM2 has a 64k register file, mapped twice in 128k. Lower + * map is little-endian, upper map is big-endian. + */ + pm2fb_fix.mmio_start += PM2_REGS_SIZE; + DPRINTK("Adjusting register base for big-endian.\n"); +#endif + DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start); + + /* Registers - request region and map it. */ + if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len, + "pm2fb regbase") ) { + printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n"); + goto err_exit_neither; + } + default_par->v_regs = + ioremap_nocache(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); + if ( !default_par->v_regs ) { + printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n", + pm2fb_fix.id); + release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); + goto err_exit_neither; + } + + /* Stash away memory register info for use when we reset the board */ + default_par->mem_control = pm2_RD(default_par, PM2R_MEM_CONTROL); + default_par->boot_address = pm2_RD(default_par, PM2R_BOOT_ADDRESS); + default_par->mem_config = pm2_RD(default_par, PM2R_MEM_CONFIG); + DPRINTK("MemControl 0x%x BootAddress 0x%x MemConfig 0x%x\n", + default_par->mem_control, default_par->boot_address, + default_par->mem_config); + + /* Now work out how big lfb is going to be. */ + switch(default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) { + case PM2F_MEM_BANKS_1: + default_par->fb_size=0x200000; + break; + case PM2F_MEM_BANKS_2: + default_par->fb_size=0x400000; + break; + case PM2F_MEM_BANKS_3: + default_par->fb_size=0x600000; + break; + case PM2F_MEM_BANKS_4: + default_par->fb_size=0x800000; + break; + } + default_par->memclock = CVPPC_MEMCLOCK; + pm2fb_fix.smem_start = pci_resource_start(pdev, 1); + pm2fb_fix.smem_len = default_par->fb_size; + + /* Linear frame buffer - request region and map it. */ + if ( !request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len, + "pm2fb smem") ) { + printk(KERN_WARNING "pm2fb: Can't reserve smem.\n"); + goto err_exit_mmio; + } + info->screen_base = default_par->v_fb = + ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len); + if ( !default_par->v_fb ) { + printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n"); + release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); + goto err_exit_mmio; + } + + info->fbops = &pm2fb_ops; + info->fix = pm2fb_fix; + info->pseudo_palette = (void *)(default_par + 1); + info->flags = FBINFO_DEFAULT | + FBINFO_HWACCEL_YPAN; + + if (!mode) + mode = "640x480@60"; + + err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8); + if (!err || err == 4) + info->var = pm2fb_var; + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + goto err_exit_all; + + if (register_framebuffer(info) < 0) + goto err_exit_both; + + printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n", + info->node, info->fix.id, default_par->fb_size / 1024); + + /* + * Our driver data + */ + pci_set_drvdata(pdev, info); + + return 0; + + err_exit_all: + fb_dealloc_cmap(&info->cmap); + err_exit_both: + iounmap(info->screen_base); + release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); + err_exit_mmio: + iounmap(default_par->v_regs); + release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); + err_exit_neither: + framebuffer_release(info); + return err_retval; +} + +/** + * Device removal. + * + * Release all device resources. + * + * @param pdev PCI device to clean up. + */ +static void __devexit pm2fb_remove(struct pci_dev *pdev) +{ + struct fb_info* info = pci_get_drvdata(pdev); + struct fb_fix_screeninfo* fix = &info->fix; + struct pm2fb_par *par = info->par; + + unregister_framebuffer(info); + + iounmap(info->screen_base); + release_mem_region(fix->smem_start, fix->smem_len); + iounmap(par->v_regs); + release_mem_region(fix->mmio_start, fix->mmio_len); + + pci_set_drvdata(pdev, NULL); + kfree(info); +} + +static struct pci_device_id pm2fb_id_table[] = { + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, + PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, + 0xff0000, 0 }, + { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, + PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, + 0xff0000, 0 }, + { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, + PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, + 0xff0000, 0 }, + { 0, } +}; + +static struct pci_driver pm2fb_driver = { + .name = "pm2fb", + .id_table = pm2fb_id_table, + .probe = pm2fb_probe, + .remove = __devexit_p(pm2fb_remove), +}; + +MODULE_DEVICE_TABLE(pci, pm2fb_id_table); + + +#ifndef MODULE +/** + * Parse user speficied options. + * + * This is, comma-separated options following `video=pm2fb:'. + */ +static int __init pm2fb_setup(char *options) +{ + char* this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + if(!strcmp(this_opt, "lowhsync")) { + lowhsync = 1; + } else if(!strcmp(this_opt, "lowvsync")) { + lowvsync = 1; + } else { + mode = this_opt; + } + } + return 0; +} +#endif + + +static int __init pm2fb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("pm2fb", &option)) + return -ENODEV; + pm2fb_setup(option); +#endif + + return pci_register_driver(&pm2fb_driver); +} + +module_init(pm2fb_init); + +#ifdef MODULE +/* + * Cleanup + */ + +static void __exit pm2fb_exit(void) +{ + pci_unregister_driver(&pm2fb_driver); +} +#endif + +#ifdef MODULE +module_exit(pm2fb_exit); + +module_param(mode, charp, 0); +MODULE_PARM_DESC(mode, "Preferred video mode e.g. '648x480-8@60'"); +module_param(lowhsync, bool, 0); +MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode"); +module_param(lowvsync, bool, 0); +MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode"); + +MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>"); +MODULE_DESCRIPTION("Permedia2 framebuffer device driver"); +MODULE_LICENSE("GPL"); +#endif diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c new file mode 100644 index 000000000000..8e024aad1b57 --- /dev/null +++ b/drivers/video/pm3fb.c @@ -0,0 +1,3646 @@ +/* + * linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device + * + * Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr> + * Based on code written by: + * Sven Luther, <luther@dpt-info.u-strasbg.fr> + * Alan Hourihane, <alanh@fairlite.demon.co.uk> + * Russel King, <rmk@arm.linux.org.uk> + * Based on linux/drivers/video/skeletonfb.c: + * Copyright (C) 1997 Geert Uytterhoeven + * Based on linux/driver/video/pm2fb.c: + * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) + * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) + * + * 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. + * + * $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $ + * + * CHANGELOG: + * Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update. + * Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2. + * Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16. + * Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings. + * Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes. + * Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix. + * Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG. + * Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL. + * Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning. + * Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option. + * Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support. + * Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates. + * Fri Apr 6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup + * Thu Mar 29 10:56:50 MET DST 2001, v 1.4.0: Module & module options support (note: linux patch changed, 2.2.19 added). + * Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian. + * Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov). + * Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes. + * Thu Mar 8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option. + * Tue Mar 6 21:25:04 CET 2001, v 1.2.1: Better acceleration support. + * Mon Mar 5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove) + * Mon Mar 5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix. + * Sun Mar 4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes. + * Fri Mar 2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4 + * Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested) + * Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode + * Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up + * Mon Feb 26 23:17:36 CET 2001, v 1.0.4: preliminary 2.4.x support, dropped (useless on pm3) partial product, more OF fix + * Mon Feb 26 20:59:05 CET 2001, v 1.0.3: No more shadow register (and wasted memory), endianess fix, use OF-preset resolution by default + * Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix + * Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning + * Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version + */ + +#include <linux/config.h> +#include <linux/module.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/ioport.h> + +#include <video/fbcon.h> +#include <video/fbcon-mfb.h> +#include <video/fbcon-cfb2.h> +#include <video/fbcon-cfb4.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> +#include <video/pm3fb.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_FB_OF +#include <asm/prom.h> +#endif + +/* ************************************* */ +/* ***** The various "global" data ***** */ +/* ************************************* */ + +/* those will need a rework for multiple board support */ +/* Driver name */ +static const char permedia3_name[16] = "Permedia3"; + +/* the fb_par struct, mandatory */ +struct pm3fb_par { + u32 pixclock; /* pixclock in KHz */ + + u32 width; /* width of virtual screen */ + u32 height; /* height of virtual screen */ + + u32 hsstart; /* horiz. sync start */ + u32 hsend; /* horiz. sync end */ + u32 hbend; /* horiz. blank end (also gate end) */ + u32 htotal; /* total width (w/ sync & blank) */ + + u32 vsstart; /* vert. sync start */ + u32 vsend; /* vert. sync end */ + u32 vbend; /* vert. blank end */ + u32 vtotal; /* total height (w/ sync & blank) */ + + u32 stride; /* screen stride */ + u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */ + /* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */ + u32 depth; /* screen depth (8, 12, 15, 16 or 32) */ + u32 video; /* video control (hsync,vsync) */ +}; + +/* memory timings */ +struct pm3fb_timings +{ + unsigned long caps; + unsigned long timings; + unsigned long control; + unsigned long refresh; + unsigned long powerdown; +}; +typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result; +#define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1) +#define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE } + +/* the fb_info struct, mandatory */ +struct pm3fb_info { + struct fb_info_gen gen; + unsigned long board_num; /* internal board number */ + unsigned long use_current; + struct pm3fb_par *current_par; + struct pci_dev *dev; /* PCI device */ + unsigned long board_type; /* index in the cardbase */ + unsigned char *fb_base; /* framebuffer memory base */ + u32 fb_size; /* framebuffer memory size */ + unsigned char *p_fb; /* physical address of frame buffer */ + unsigned char *v_fb; /* virtual address of frame buffer */ + unsigned char *pIOBase; /* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */ + unsigned char *vIOBase; /* address of registers after ioremap() */ + struct { + u8 transp; + u8 red; + u8 green; + u8 blue; + } palette[256]; + union { +#ifdef FBCON_HAS_CFB16 + u16 cmap12[16]; /* RGBA 4444 */ + u16 cmap15[16]; /* RGBA 5551 */ + u16 cmap16[16]; /* RGBA 5650 */ +#endif +#ifdef FBCON_HAS_CFB32 + u32 cmap32[16]; +#endif + } cmap; + struct pm3fb_timings memt; +}; + +/* regular resolution database*/ +static struct { + char name[16]; + struct pm3fb_par user_mode; +} mode_base[] __initdata = { + { + "default-800x600", { + 49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625, + 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, { + "1024x768-74", { + 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38, + 806, 1024, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, { + "1024x768-74-32", { + 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38, + 806, 1024, 0, 32, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_32BIT}}, +/* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/ + { + "SGI1600SW", { + 108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32, + 1056, 1600, 0, 8, + PM3VideoControl_ENABLE| + PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW| + PM3VideoControl_PIXELSIZE_32BIT}}, +/* ##### auto-generated mode, by fbtimings2pm3 */ +/* Generated mode : "640x480-60" */ + { + "640x480-60", { + 25174, 640, 480, 16, 112, 160, 800, 10, 12, 45, + 525, 640, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "640x480-72" */ + { + "640x480-72", { + 31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520, + 640, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "640x480-75" */ + { + "640x480-75", { + 31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500, + 640, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "640x480-90" */ + { + "640x480-90", { + 39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533, + 640, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "640x480-100" */ + { + "640x480-100", { + 44899, 640, 480, 32, 160, 208, 848, 22, 34, 51, + 531, 640, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-48-lace" */ +/* INTERLACED NOT SUPPORTED + {"800x600-48-lace", {35999, 800, 600, 80, 208, 264, 1064, 11, 23, 102, 702, 800, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, + INTERLACED NOT SUPPORTED */ +/* Generated mode : "800x600-56" */ + { + "800x600-56", { + 35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625, + 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-60" */ + { + "800x600-60", { + 40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628, + 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-70" */ + { + "800x600-70", { + 44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36, + 636, 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-72" */ + { + "800x600-72", { + 50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66, + 666, 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-75" */ + { + "800x600-75", { + 49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625, + 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-90" */ + { + "800x600-90", { + 56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635, + 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-100", from /etc/fb.modes */ +/* DISABLED, hsstart == 0 + { + "800x600-100", { + 67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625, + 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +*/ +/* Generated mode : "800x600-100", from ??? */ + { + "800x600-100", { + 69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8, + PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW| + PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1024x768-43-lace" */ +/* INTERLACED NOT SUPPORTED + {"1024x768-43-lace", {44899, 1024, 768, 8, 184, 240, 1264, 1, 9, 49, 817, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, + INTERLACED NOT SUPPORTED */ +/* Generated mode : "1024x768-60" */ + { + "1024x768-60", { + 64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38, + 806, 1024, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1024x768-70" */ + { + "1024x768-70", { + 74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38, + 806, 1024, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1024x768-72" */ + { + "1024x768-72", { + 74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38, + 806, 10224, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1024x768-75" */ + { + "1024x768-75", { + 78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32, + 800, 1024, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1024x768-90" */ + { + "1024x768-90", { + 100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77, + 845, 1024, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1024x768-100", from /etc/fb.modes */ +/* DISABLED, vsstart == 0 + { + "1024x768-100", { + 109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792, + 1024, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +*/ +/* Generated mode : "1024x768-100", from ??? */ + { + "1024x768-100", { + 115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8, + PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW| + PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1152x864-43-lace" */ +/* INTERLACED NOT SUPPORTED + {"1152x864-43-lace", {64998, 1152, 864, 72, 200, 264, 1416, 78, 87, 191, 1055, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, + INTERLACED NOT SUPPORTED */ +/* Generated mode : "1152x864-47-lace" */ +/* INTERLACED NOT SUPPORTED + {"1152x864-47-lace", {64998, 1152, 864, 88, 216, 296, 1448, 30, 39, 83, 947, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, + INTERLACED NOT SUPPORTED */ +/* Generated mode : "1152x864-60" */ + { + "1152x864-60", { + 80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52, + 916, 1152, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1152x864-70" */ + { + "1152x864-70", { + 100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81, + 945, 1152, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1152x864-75" */ + { + "1152x864-75", { + 109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138, + 1002, 1152, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1152x864-80" */ + { + "1152x864-80", { + 109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94, + 958, 1152, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1280x1024-43-lace" */ +/* INTERLACED NOT SUPPORTED + {"1280x1024-43-lace", {80000, 1024, 1024, 80, 160, 320, 1344, 50, 60, 125, 1149, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, + INTERLACED NOT SUPPORTED */ +/* Generated mode : "1280x1024-47-lace" */ +/* INTERLACED NOT SUPPORTED + {"1280x1024-47-lace", {80000, 1280, 1024, 80, 160, 320, 1600, 1, 11, 29, 1053, 1280, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, + INTERLACED NOT SUPPORTED */ +/* Generated mode : "1280x1024-60" */ + { + "1280x1024-60", { + 107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42, + 1066, 1280, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1280x1024-70" */ + { + "1280x1024-70", { + 125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42, + 1066, 1280, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1280x1024-74" */ + { + "1280x1024-74", { + 134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40, + 1064, 1280, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1280x1024-75" */ + { + "1280x1024-75", { + 134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42, + 1066, 1280, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1600x1200-60" */ + { + "1600x1200-60", { + 155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70, + 1270, 1600, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1600x1200-66" */ + { + "1600x1200-66", { + 171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53, + 1253, 1600, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1600x1200-76" */ + { + "1600x1200-76", { + 197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50, + 1250, 1600, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* ##### end of auto-generated mode */ + { + "\0",} +}; + +/* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */ +static struct pm3fb_info fb_info[PM3_MAX_BOARD]; +static struct pm3fb_par current_par[PM3_MAX_BOARD]; +static int current_par_valid[PM3_MAX_BOARD]; +/* to allow explicit filtering of board */ +short bus[PM3_MAX_BOARD]; +short slot[PM3_MAX_BOARD]; +short func[PM3_MAX_BOARD]; +short disable[PM3_MAX_BOARD]; +short noaccel[PM3_MAX_BOARD]; +char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE]; +short depth[PM3_MAX_BOARD]; +short flatpanel[PM3_MAX_BOARD]; +static struct display disp[PM3_MAX_BOARD]; +static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy"; +short printtimings = 0; +short forcesize[PM3_MAX_BOARD]; + +/* ********************* */ +/* ***** prototype ***** */ +/* ********************* */ +/* card-specific */ +static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info); +/* permedia3-specific */ +static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info); +static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info); +static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info); +static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, + unsigned long r); +static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */ + unsigned long refclock, /* In kHz units */ + unsigned char *prescale, /* ClkPreScale */ + unsigned char *feedback, /* ClkFeedBackScale */ + unsigned char *postscale + /* ClkPostScale */ ); +static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc); +static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b); +static void pm3fb_common_init(struct pm3fb_info *l_fb_info); +static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info, + unsigned long depth, int v); +static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info, + unsigned long depth, int v); +static void pm3fb_mapIO(struct pm3fb_info *l_fb_info); +static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info); +#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) +static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info); +#endif +static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info); +static void pm3fb_write_mode(struct pm3fb_info *l_fb_info); +static void pm3fb_read_mode(struct pm3fb_info *l_fb_info, + struct pm3fb_par *curpar); +static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info); +/* accelerated permedia3-specific */ +#ifdef PM3FB_USE_ACCEL +static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info); +static void pm3fb_init_engine(struct pm3fb_info *l_fb_info); +#ifdef FBCON_HAS_CFB32 +static void pm3fb_cfb32_clear(struct vc_data *conp, + struct display *p, + int sy, int sx, int height, int width); +static void pm3fb_cfb32_clear_margins(struct vc_data *conp, + struct display *p, int bottom_only); +#endif /* FBCON_HAS_CFB32 */ +#ifdef FBCON_HAS_CFB16 +static void pm3fb_cfb16_clear(struct vc_data *conp, + struct display *p, + int sy, int sx, int height, int width); +static void pm3fb_cfb16_clear_margins(struct vc_data *conp, + struct display *p, int bottom_only); +#endif /* FBCON_HAS_CFB16 */ +#ifdef FBCON_HAS_CFB8 +static void pm3fb_cfb8_clear(struct vc_data *conp, + struct display *p, + int sy, int sx, int height, int width); +static void pm3fb_cfb8_clear_margins(struct vc_data *conp, + struct display *p, int bottom_only); +#endif /* FBCON_HAS_CFB8 */ +#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) +static void pm3fb_cfbX_bmove(struct display *p, + int sy, int sx, + int dy, int dx, int height, int width); +static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p, + int c, int yy, int xx); +static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, + int xx); +static void pm3fb_cfbX_revc(struct display *p, int xx, int yy); +#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */ +#endif /* PM3FB_USE_ACCEL */ +/* pre-init */ +static void pm3fb_mode_setup(char *mode, unsigned long board_num); +static void pm3fb_pciid_setup(char *pciid, unsigned long board_num); +static char *pm3fb_boardnum_setup(char *options, unsigned long *bn); +static void pm3fb_real_setup(char *options); +/* fbdev */ +static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix, + const void *par, struct fb_info_gen *info); +static int pm3fb_decode_var(const struct fb_var_screeninfo *var, + void *par, struct fb_info_gen *info); +static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d); +static int pm3fb_encode_var(struct fb_var_screeninfo *var, + const void *par, struct fb_info_gen *info); +static void pm3fb_get_par(void *par, struct fb_info_gen *info); +static void pm3fb_set_par(const void *par, struct fb_info_gen *info); +static void pm3fb_set_color(struct pm3fb_info *l_fb_info, + unsigned char regno, unsigned char r, + unsigned char g, unsigned char b); +static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *info); +static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info); +static int pm3fb_blank(int blank_mode, struct fb_info_gen *info); +static void pm3fb_set_disp(const void *par, struct display *disp, + struct fb_info_gen *info); +static void pm3fb_detect(void); +static int pm3fb_pan_display(const struct fb_var_screeninfo *var, + struct fb_info_gen *info); +static int pm3fb_ioctl(struct inode *inode, struct file *file, + u_int cmd, u_long arg, int con, + struct fb_info *info); + + +/* the struct that hold them together */ +struct fbgen_hwswitch pm3fb_switch = { + pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var, + pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, + pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp +}; + +static struct fb_ops pm3fb_ops = { + .owner = THIS_MODULE, + .fb_get_fix = fbgen_get_fix, + .fb_get_var = fbgen_get_var, + .fb_set_var = fbgen_set_var, + .fb_get_cmap = fbgen_get_cmap, + .fb_set_cmap = fbgen_set_cmap, + .fb_setcolreg = pm3fb_setcolreg, + .fb_pan_display =fbgen_pan_display, + .fb_blank = fbgen_blank, + .fb_ioctl = pm3fb_ioctl, +}; + +#ifdef PM3FB_USE_ACCEL +#ifdef FBCON_HAS_CFB32 +static struct display_switch pm3fb_cfb32 = { + fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear, + pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, + NULL /* cursor() */ , NULL /* set_font() */ , + pm3fb_cfb32_clear_margins, + FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ +}; +#endif /* FBCON_HAS_CFB32 */ +#ifdef FBCON_HAS_CFB16 +static struct display_switch pm3fb_cfb16 = { + fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear, + pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, + NULL /* cursor() */ , NULL /* set_font() */ , + pm3fb_cfb16_clear_margins, + FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ +}; +#endif /* FBCON_HAS_CFB16 */ +#ifdef FBCON_HAS_CFB8 +static struct display_switch pm3fb_cfb8 = { + fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear, + pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, + NULL /* cursor() */ , NULL /* set_font() */ , + pm3fb_cfb8_clear_margins, + FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ +}; +#endif /* FBCON_HAS_CFB8 */ +#endif /* PM3FB_USE_ACCEL */ + +/* ****************************** */ +/* ***** card-specific data ***** */ +/* ****************************** */ +struct pm3fb_card_timings { + unsigned long memsize; /* 0 for last value (i.e. default) */ + struct pm3fb_timings memt; +}; + +static struct pm3fb_card_timings t_FormacProFormance3[] = { + { 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} }, + { 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */ +}; + +static struct pm3fb_card_timings t_AppianJeronimo2000[] = { + { 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} }, + { 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */ +}; + +static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = { + { 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} }, + { 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */ +}; + +static struct { + char cardname[32]; /* recognized card name */ + u16 subvendor; /* subvendor of the card */ + u16 subdevice; /* subdevice of the card */ + u8 func; /* function of the card to which the extra init apply */ + void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */ + struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */ +} cardbase[] = { + { "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL }, + { "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL, + t_AppianJeronimo2000 + }, + { "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup, + t_AppianJeronimo2000 + }, + { "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */ + t_FormacProFormance3 + }, + { "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL }, + { "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL, + t_3DLabsOxygenVX1 + }, + { "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL }, + { "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL }, + { "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL }, + { "\0", 0x0, 0x0, 0, NULL, NULL } +}; + +/* ********************************** */ +/* ***** card-specific function ***** */ +/* ********************************** */ +static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info) +{ /* the appian j2000 require more initialization of the second head */ + /* l_fb_info must point to the _second_ head of the J2000 */ + + DTRACE; + + l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */ + + pm3fb_write_memory_timings(l_fb_info); +} + +/* *************************************** */ +/* ***** permedia3-specific function ***** */ +/* *************************************** */ +static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info) +{ + l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps); + l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings); + l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl); + l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh); + l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown); + + if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) || + (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) || + (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) || + (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) || + (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE)) + { + printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num); + return(pm3fb_try_memory_timings(l_fb_info)); + } + return(pm3fb_timing_ok); +} + +static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info) +{ + if (cardbase[l_fb_info->board_type].c_memt) + { + int i = 0, done = 0; + while (!done) + { + if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size) + || !(cardbase[l_fb_info->board_type].c_memt[i].memsize)) + { /* will use the 0-sized timings by default */ + done = 1; + l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt; + printk(KERN_WARNING "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n", + l_fb_info->board_num, + cardbase[l_fb_info->board_type].cardname, + cardbase[l_fb_info->board_type].c_memt[i].memsize); + pm3fb_write_memory_timings(l_fb_info); + return(pm3fb_timing_retry); + } + i++; + } + } else + return(pm3fb_timing_problem); + return(pm3fb_timing_ok); +} + +static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info) +{ + unsigned char m, n, p; + unsigned long clockused; + + PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps); + PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings); + PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control); + PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh); + PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown); + + clockused = + pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m, + &n, &p); + + PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m); + PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n); + PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p); + PM3_WRITE_DAC_REG(PM3RD_KClkControl, + PM3RD_KClkControl_STATE_RUN | + PM3RD_KClkControl_SOURCE_PLL | + PM3RD_KClkControl_ENABLE); + PM3_WRITE_DAC_REG(PM3RD_MClkControl, + PM3RD_MClkControl_STATE_RUN | + PM3RD_MClkControl_SOURCE_KCLK | + PM3RD_MClkControl_ENABLE); + PM3_WRITE_DAC_REG(PM3RD_SClkControl, + PM3RD_SClkControl_STATE_RUN | + PM3RD_SClkControl_SOURCE_PCLK | + PM3RD_SClkControl_ENABLE); +} + +static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, + unsigned long r) +{ + DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)), + "l_fb_info->vIOBase mapped in read dac reg\n"); + PM3_SET_INDEX(r); + mb(); + return (PM3_READ_REG(PM3RD_IndexedData)); +} + +/* Calculating various clock parameter */ +static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */ + unsigned long refclock, /* In kHz units */ + unsigned char *prescale, /* ClkPreScale */ + unsigned char *feedback, /* ClkFeedBackScale */ + unsigned char *postscale + /* ClkPostScale */ ) +{ + int f, pre, post; + unsigned long freq; + long freqerr = 1000; + unsigned long actualclock = 0; + + DTRACE; + + for (f = 1; f < 256; f++) { + for (pre = 1; pre < 256; pre++) { + for (post = 0; post < 5; post++) { + freq = + ((2 * refclock * f) / + (pre * (1 << post))); + if ((reqclock > freq - freqerr) + && (reqclock < freq + freqerr)) { + freqerr = + (reqclock > + freq) ? reqclock - + freq : freq - reqclock; + *feedback = f; + *prescale = pre; + *postscale = post; + actualclock = freq; + } + } + } + } + + return (actualclock); +} + +static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info, + unsigned long depth, int v) +{ + DTRACE; + + switch (depth) { + case 8: + return (v >> 4); + case 12: + case 15: + case 16: + return (v >> 3); + case 32: + return (v >> 2); + } + DPRINTK(1, "Unsupported depth %ld\n", depth); + return (0); +} + +static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info, + unsigned long depth, int v) +{ + DTRACE; + + switch (depth) { + case 8: + return (v << 4); + case 12: + case 15: + case 16: + return (v << 3); + case 32: + return (v << 2); + } + DPRINTK(1, "Unsupported depth %ld\n", depth); + return (0); +} + +static void pm3fb_mapIO(struct pm3fb_info *l_fb_info) +{ + DTRACE; + + l_fb_info->vIOBase = + ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE); + l_fb_info->v_fb = + ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size); + DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n", + (unsigned long) l_fb_info->pIOBase, + (unsigned long) l_fb_info->vIOBase, + (unsigned long) l_fb_info->p_fb, + (unsigned long) l_fb_info->v_fb); +} + +static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info) +{ + DTRACE; + + iounmap(l_fb_info->vIOBase); + iounmap(l_fb_info->v_fb); + l_fb_info->vIOBase = (unsigned char *) -1; + l_fb_info->v_fb = (unsigned char *) -1; +} + +#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) +static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info) +{ + DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0)); + DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1)); + DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n", + PM3_READ_REG(PM3ByAperture1Mode)); + DPRINTK(2, "PM3ByAperture2Mode: 0x%08x\n", + PM3_READ_REG(PM3ByAperture2Mode)); + DPRINTK(2, "PM3ChipConfig: 0x%08x\n", PM3_READ_REG(PM3ChipConfig)); + DPRINTK(2, "PM3FIFODis: 0x%08x\n", PM3_READ_REG(PM3FIFODis)); + DPRINTK(2, "PM3HTotal: 0x%08x\n", PM3_READ_REG(PM3HTotal)); + DPRINTK(2, "PM3HbEnd: 0x%08x\n", PM3_READ_REG(PM3HbEnd)); + DPRINTK(2, "PM3HgEnd: 0x%08x\n", PM3_READ_REG(PM3HgEnd)); + DPRINTK(2, "PM3HsEnd: 0x%08x\n", PM3_READ_REG(PM3HsEnd)); + DPRINTK(2, "PM3HsStart: 0x%08x\n", PM3_READ_REG(PM3HsStart)); + DPRINTK(2, "PM3MemBypassWriteMask: 0x%08x\n", + PM3_READ_REG(PM3MemBypassWriteMask)); + DPRINTK(2, "PM3RD_IndexControl: 0x%08x\n", + PM3_READ_REG(PM3RD_IndexControl)); + DPRINTK(2, "PM3ScreenBase: 0x%08x\n", PM3_READ_REG(PM3ScreenBase)); + DPRINTK(2, "PM3ScreenStride: 0x%08x\n", + PM3_READ_REG(PM3ScreenStride)); + DPRINTK(2, "PM3VClkCtl: 0x%08x\n", PM3_READ_REG(PM3VClkCtl)); + DPRINTK(2, "PM3VTotal: 0x%08x\n", PM3_READ_REG(PM3VTotal)); + DPRINTK(2, "PM3VbEnd: 0x%08x\n", PM3_READ_REG(PM3VbEnd)); + DPRINTK(2, "PM3VideoControl: 0x%08x\n", + PM3_READ_REG(PM3VideoControl)); + DPRINTK(2, "PM3VsEnd: 0x%08x\n", PM3_READ_REG(PM3VsEnd)); + DPRINTK(2, "PM3VsStart: 0x%08x\n", PM3_READ_REG(PM3VsStart)); + + DPRINTK(2, "PM3RD_ColorFormat: %ld\n", + PM3_READ_DAC_REG(PM3RD_ColorFormat)); + DPRINTK(2, "PM3RD_DACControl: %ld\n", + PM3_READ_DAC_REG(PM3RD_DACControl)); + DPRINTK(2, "PM3RD_DClk0FeedbackScale: %ld\n", + PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale)); + DPRINTK(2, "PM3RD_DClk0PostScale: %ld\n", + PM3_READ_DAC_REG(PM3RD_DClk0PostScale)); + DPRINTK(2, "PM3RD_DClk0PreScale: %ld\n", + PM3_READ_DAC_REG(PM3RD_DClk0PreScale)); + DPRINTK(2, "[not set] PM3RD_IndexControl: %ld\n", + PM3_READ_DAC_REG(PM3RD_IndexControl)); + DPRINTK(2, "PM3RD_MiscControl: %ld\n", + PM3_READ_DAC_REG(PM3RD_MiscControl)); + DPRINTK(2, "PM3RD_PixelSize: %ld\n", + PM3_READ_DAC_REG(PM3RD_PixelSize)); + DPRINTK(2, "PM3RD_SyncControl: %ld\n", + PM3_READ_DAC_REG(PM3RD_SyncControl)); +} + +#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) */ +static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info) +{ + u16 subvendor, subdevice; + + if ((!pci_read_config_word + (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor)) + && + (!pci_read_config_word + (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) { + /* well, nothing... */ + } else { + subvendor = subdevice = (u16)-1; + } + + printk(KERN_INFO "pm3fb: memory timings for board #%ld (subvendor: 0x%hx, subdevice: 0x%hx)\n", l_fb_info->board_num, subvendor, subdevice); + printk(KERN_INFO " PM3LocalMemCaps: 0x%08x\n", + PM3_READ_REG(PM3LocalMemCaps)); + printk(KERN_INFO " PM3LocalMemTimings: 0x%08x\n", + PM3_READ_REG(PM3LocalMemTimings)); + printk(KERN_INFO " PM3LocalMemControl: 0x%08x\n", + PM3_READ_REG(PM3LocalMemControl)); + printk(KERN_INFO " PM3LocalMemRefresh: 0x%08x\n", + PM3_READ_REG(PM3LocalMemRefresh)); + printk(KERN_INFO " PM3LocalMemPowerDown: 0x%08x\n", + PM3_READ_REG(PM3LocalMemPowerDown)); +} + +/* write the mode to registers */ +static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) +{ + char tempsync = 0x00, tempmisc = 0x00; + DTRACE; + + PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff); + PM3_SLOW_WRITE_REG(PM3Aperture0, 0x00000000); + PM3_SLOW_WRITE_REG(PM3Aperture1, 0x00000000); + PM3_SLOW_WRITE_REG(PM3FIFODis, 0x00000007); + + PM3_SLOW_WRITE_REG(PM3HTotal, + pm3fb_Shiftbpp(l_fb_info, + l_fb_info->current_par->depth, + l_fb_info->current_par->htotal - + 1)); + PM3_SLOW_WRITE_REG(PM3HsEnd, + pm3fb_Shiftbpp(l_fb_info, + l_fb_info->current_par->depth, + l_fb_info->current_par->hsend)); + PM3_SLOW_WRITE_REG(PM3HsStart, + pm3fb_Shiftbpp(l_fb_info, + l_fb_info->current_par->depth, + l_fb_info->current_par-> + hsstart)); + PM3_SLOW_WRITE_REG(PM3HbEnd, + pm3fb_Shiftbpp(l_fb_info, + l_fb_info->current_par->depth, + l_fb_info->current_par->hbend)); + PM3_SLOW_WRITE_REG(PM3HgEnd, + pm3fb_Shiftbpp(l_fb_info, + l_fb_info->current_par->depth, + l_fb_info->current_par->hbend)); + PM3_SLOW_WRITE_REG(PM3ScreenStride, + pm3fb_Shiftbpp(l_fb_info, + l_fb_info->current_par->depth, + l_fb_info->current_par->stride)); + PM3_SLOW_WRITE_REG(PM3VTotal, l_fb_info->current_par->vtotal - 1); + PM3_SLOW_WRITE_REG(PM3VsEnd, l_fb_info->current_par->vsend - 1); + PM3_SLOW_WRITE_REG(PM3VsStart, + l_fb_info->current_par->vsstart - 1); + PM3_SLOW_WRITE_REG(PM3VbEnd, l_fb_info->current_par->vbend); + + switch (l_fb_info->current_par->depth) { + case 8: + PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, + PM3ByApertureMode_PIXELSIZE_8BIT); + PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, + PM3ByApertureMode_PIXELSIZE_8BIT); + break; + + case 12: + case 15: + case 16: +#ifndef __BIG_ENDIAN + PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, + PM3ByApertureMode_PIXELSIZE_16BIT); + PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, + PM3ByApertureMode_PIXELSIZE_16BIT); +#else + PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, + PM3ByApertureMode_PIXELSIZE_16BIT | + PM3ByApertureMode_BYTESWAP_BADC); + PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, + PM3ByApertureMode_PIXELSIZE_16BIT | + PM3ByApertureMode_BYTESWAP_BADC); +#endif /* ! __BIG_ENDIAN */ + break; + + case 32: +#ifndef __BIG_ENDIAN + PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, + PM3ByApertureMode_PIXELSIZE_32BIT); + PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, + PM3ByApertureMode_PIXELSIZE_32BIT); +#else + PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, + PM3ByApertureMode_PIXELSIZE_32BIT | + PM3ByApertureMode_BYTESWAP_DCBA); + PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, + PM3ByApertureMode_PIXELSIZE_32BIT | + PM3ByApertureMode_BYTESWAP_DCBA); +#endif /* ! __BIG_ENDIAN */ + break; + + default: + DPRINTK(1, "Unsupported depth %d\n", + l_fb_info->current_par->depth); + break; + } + + /* + * Oxygen VX1 - it appears that setting PM3VideoControl and + * then PM3RD_SyncControl to the same SYNC settings undoes + * any net change - they seem to xor together. Only set the + * sync options in PM3RD_SyncControl. --rmk + */ + { + unsigned int video = l_fb_info->current_par->video; + + video &= ~(PM3VideoControl_HSYNC_MASK | + PM3VideoControl_VSYNC_MASK); + video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | + PM3VideoControl_VSYNC_ACTIVE_HIGH; + PM3_SLOW_WRITE_REG(PM3VideoControl, video); + } + PM3_SLOW_WRITE_REG(PM3VClkCtl, + (PM3_READ_REG(PM3VClkCtl) & 0xFFFFFFFC)); + PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base); + PM3_SLOW_WRITE_REG(PM3ChipConfig, + (PM3_READ_REG(PM3ChipConfig) & 0xFFFFFFFD)); + + { + unsigned char m; /* ClkPreScale */ + unsigned char n; /* ClkFeedBackScale */ + unsigned char p; /* ClkPostScale */ + (void)pm3fb_CalculateClock(l_fb_info, l_fb_info->current_par->pixclock, PM3_REF_CLOCK, &m, &n, &p); + + DPRINTK(2, + "Pixclock: %d, Pre: %d, Feedback: %d, Post: %d\n", + l_fb_info->current_par->pixclock, (int) m, (int) n, + (int) p); + + PM3_WRITE_DAC_REG(PM3RD_DClk0PreScale, m); + PM3_WRITE_DAC_REG(PM3RD_DClk0FeedbackScale, n); + PM3_WRITE_DAC_REG(PM3RD_DClk0PostScale, p); + } + /* + PM3_WRITE_DAC_REG(PM3RD_IndexControl, 0x00); + */ + /* + PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00); + */ + if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) == + PM3VideoControl_HSYNC_ACTIVE_HIGH) + tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; + if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) == + PM3VideoControl_VSYNC_ACTIVE_HIGH) + tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; + + PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync); + DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync); + + if (flatpanel[l_fb_info->board_num]) + { + PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE); + PM3_WAIT(2); + PM3_WRITE_REG(PM3VSConfiguration, 0x06); + PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */ + tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE; + } + else + PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00); + + switch (l_fb_info->current_par->depth) { + case 8: + PM3_WRITE_DAC_REG(PM3RD_PixelSize, + PM3RD_PixelSize_8_BIT_PIXELS); + PM3_WRITE_DAC_REG(PM3RD_ColorFormat, + PM3RD_ColorFormat_CI8_COLOR | + PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); + tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; + break; + case 12: + PM3_WRITE_DAC_REG(PM3RD_PixelSize, + PM3RD_PixelSize_16_BIT_PIXELS); + PM3_WRITE_DAC_REG(PM3RD_ColorFormat, + PM3RD_ColorFormat_4444_COLOR | + PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | + PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); + tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | + PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; + break; + case 15: + PM3_WRITE_DAC_REG(PM3RD_PixelSize, + PM3RD_PixelSize_16_BIT_PIXELS); + PM3_WRITE_DAC_REG(PM3RD_ColorFormat, + PM3RD_ColorFormat_5551_FRONT_COLOR | + PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | + PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); + tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | + PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; + break; + case 16: + PM3_WRITE_DAC_REG(PM3RD_PixelSize, + PM3RD_PixelSize_16_BIT_PIXELS); + PM3_WRITE_DAC_REG(PM3RD_ColorFormat, + PM3RD_ColorFormat_565_FRONT_COLOR | + PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | + PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); + tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | + PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; + break; + case 32: + PM3_WRITE_DAC_REG(PM3RD_PixelSize, + PM3RD_PixelSize_32_BIT_PIXELS); + PM3_WRITE_DAC_REG(PM3RD_ColorFormat, + PM3RD_ColorFormat_8888_COLOR | + PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); + tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | + PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; + break; + } + PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc); + + PM3_SHOW_CUR_MODE; +} + +static void pm3fb_read_mode(struct pm3fb_info *l_fb_info, + struct pm3fb_par *curpar) +{ + unsigned long pixsize1, pixsize2, clockused; + unsigned long pre, feedback, post; + + DTRACE; + + clockused = PM3_READ_REG(PM3VClkCtl); + + switch (clockused) { + case 3: + pre = PM3_READ_DAC_REG(PM3RD_DClk3PreScale); + feedback = PM3_READ_DAC_REG(PM3RD_DClk3FeedbackScale); + post = PM3_READ_DAC_REG(PM3RD_DClk3PostScale); + + DPRINTK(2, + "DClk3 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", + pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, + feedback, + post)); + break; + case 2: + pre = PM3_READ_DAC_REG(PM3RD_DClk2PreScale); + feedback = PM3_READ_DAC_REG(PM3RD_DClk2FeedbackScale); + post = PM3_READ_DAC_REG(PM3RD_DClk2PostScale); + + DPRINTK(2, + "DClk2 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", + pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, + feedback, + post)); + break; + case 1: + pre = PM3_READ_DAC_REG(PM3RD_DClk1PreScale); + feedback = PM3_READ_DAC_REG(PM3RD_DClk1FeedbackScale); + post = PM3_READ_DAC_REG(PM3RD_DClk1PostScale); + + DPRINTK(2, + "DClk1 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", + pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, + feedback, + post)); + break; + case 0: + pre = PM3_READ_DAC_REG(PM3RD_DClk0PreScale); + feedback = PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale); + post = PM3_READ_DAC_REG(PM3RD_DClk0PostScale); + + DPRINTK(2, + "DClk0 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", + pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, + feedback, + post)); + break; + default: + pre = feedback = post = 0; + DPRINTK(1, "Unknowk D clock used : %ld\n", clockused); + break; + } + + curpar->pixclock = PM3_SCALE_TO_CLOCK(pre, feedback, post); + + pixsize1 = + PM3ByApertureMode_PIXELSIZE_MASK & + (PM3_READ_REG(PM3ByAperture1Mode)); + pixsize2 = + PM3ByApertureMode_PIXELSIZE_MASK & + (PM3_READ_REG(PM3ByAperture2Mode)); + + DASSERT((pixsize1 == pixsize2), + "pixsize the same in both aperture\n"); + + if (pixsize1 & PM3ByApertureMode_PIXELSIZE_32BIT) + curpar->depth = 32; + else if (pixsize1 & PM3ByApertureMode_PIXELSIZE_16BIT) + { + curpar->depth = 16; + } + else + curpar->depth = 8; + + /* not sure if I need to add one on the next ; it give better result with */ + curpar->htotal = + pm3fb_Unshiftbpp(l_fb_info, curpar->depth, + 1 + PM3_READ_REG(PM3HTotal)); + curpar->hsend = + pm3fb_Unshiftbpp(l_fb_info, curpar->depth, + PM3_READ_REG(PM3HsEnd)); + curpar->hsstart = + pm3fb_Unshiftbpp(l_fb_info, curpar->depth, + PM3_READ_REG(PM3HsStart)); + curpar->hbend = + pm3fb_Unshiftbpp(l_fb_info, curpar->depth, + PM3_READ_REG(PM3HbEnd)); + + curpar->stride = + pm3fb_Unshiftbpp(l_fb_info, curpar->depth, + PM3_READ_REG(PM3ScreenStride)); + + curpar->vtotal = 1 + PM3_READ_REG(PM3VTotal); + curpar->vsend = 1 + PM3_READ_REG(PM3VsEnd); + curpar->vsstart = 1 + PM3_READ_REG(PM3VsStart); + curpar->vbend = PM3_READ_REG(PM3VbEnd); + + curpar->video = PM3_READ_REG(PM3VideoControl); + + curpar->base = PM3_READ_REG(PM3ScreenBase); + curpar->width = curpar->htotal - curpar->hbend; /* make virtual == displayed resolution */ + curpar->height = curpar->vtotal - curpar->vbend; + + DPRINTK(2, "Found : %d * %d, %d Khz, stride is %08x\n", + curpar->width, curpar->height, curpar->pixclock, + curpar->stride); +} + +static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info) +{ + unsigned long memsize = 0, tempBypass, i, temp1, temp2; + u16 subvendor, subdevice; + pm3fb_timing_result ptr; + + DTRACE; + + l_fb_info->fb_size = 64 * 1024 * 1024; /* pm3 aperture always 64 MB */ + pm3fb_mapIO(l_fb_info); /* temporary map IO */ + + DASSERT((l_fb_info->vIOBase != NULL), + "IO successfully mapped before mem detect\n"); + DASSERT((l_fb_info->v_fb != NULL), + "FB successfully mapped before mem detect\n"); + + /* card-specific stuff, *before* accessing *any* FB memory */ + if ((!pci_read_config_word + (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor)) + && + (!pci_read_config_word + (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) { + i = 0; l_fb_info->board_type = 0; + while ((cardbase[i].cardname[0]) && !(l_fb_info->board_type)) { + if ((cardbase[i].subvendor == subvendor) && + (cardbase[i].subdevice == subdevice) && + (cardbase[i].func == PCI_FUNC(l_fb_info->dev->devfn))) { + DPRINTK(2, "Card #%ld is an %s\n", + l_fb_info->board_num, + cardbase[i].cardname); + if (cardbase[i].specific_setup) + cardbase[i].specific_setup(l_fb_info); + l_fb_info->board_type = i; + } + i++; + } + if (!l_fb_info->board_type) { + DPRINTK(1, "Card #%ld is an unknown 0x%04x / 0x%04x\n", + l_fb_info->board_num, subvendor, subdevice); + } + } else { + printk(KERN_ERR "pm3fb: Error: pci_read_config_word failed, board #%ld\n", + l_fb_info->board_num); + } + + if (printtimings) + pm3fb_show_cur_timing(l_fb_info); + + /* card-specific setup is done, we preserve the final + memory timing for future reference */ + if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */ + return(0); + } + + tempBypass = PM3_READ_REG(PM3MemBypassWriteMask); + + DPRINTK(2, "PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass); + + PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xFFFFFFFF); + + /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */ + for (i = 0; i < 32; i++) { + fb_writel(i * 0x00345678, + (l_fb_info->v_fb + (i * 1048576))); + mb(); + temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576))); + + /* Let's check for wrapover, write will fail at 16MB boundary */ + if (temp1 == (i * 0x00345678)) + memsize = i; + else + break; + } + + DPRINTK(2, "First detect pass already got %ld MB\n", memsize + 1); + + if (memsize == i) { + for (i = 0; i < 32; i++) { + /* Clear first 32MB ; 0 is 0, no need to byteswap */ + writel(0x0000000, + (l_fb_info->v_fb + (i * 1048576))); + mb(); + } + + for (i = 32; i < 64; i++) { + fb_writel(i * 0x00345678, + (l_fb_info->v_fb + (i * 1048576))); + mb(); + temp1 = + fb_readl((l_fb_info->v_fb + (i * 1048576))); + temp2 = + fb_readl((l_fb_info->v_fb + + ((i - 32) * 1048576))); + if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) /* different value, different RAM... */ + memsize = i; + else + break; + } + } + + DPRINTK(2, "Second detect pass got %ld MB\n", memsize + 1); + + PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, tempBypass); + + pm3fb_unmapIO(l_fb_info); + memsize = 1048576 * (memsize + 1); + + DPRINTK(2, "Returning 0x%08lx bytes\n", memsize); + + if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize)) + { + printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]); + memsize = 1048576 * forcesize[l_fb_info->board_num]; + } + + l_fb_info->fb_size = memsize; + + if (ptr == pm3fb_timing_retry) + { + printk(KERN_WARNING "pm3fb: retrying memory timings check"); + if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem) + return(0); + } + + return (memsize); +} + +static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc) +{ + int i; + + DTRACE; + + for (i = 0; i < (l_fb_info->fb_size / sizeof(u32)) ; i++) /* clear entire FB memory to black */ + { + fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32)))); + } +} + +static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b) +{ + int i; + + DTRACE; + + for (i = 0; i < 256 ; i++) /* fill color map with white */ + pm3fb_set_color(l_fb_info, i, r, g, b); + +} + +/* common initialisation */ +static void pm3fb_common_init(struct pm3fb_info *l_fb_info) +{ + DTRACE; + + DPRINTK(2, "Initializing board #%ld @ %lx\n", l_fb_info->board_num, + (unsigned long) l_fb_info); + + strcpy(l_fb_info->gen.info.modename, permedia3_name); + disp[l_fb_info->board_num].scrollmode = 0; /* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */ + l_fb_info->gen.parsize = sizeof(struct pm3fb_par); + l_fb_info->gen.info.changevar = NULL; + l_fb_info->gen.info.fbops = &pm3fb_ops; + l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]); + if (fontn[l_fb_info->board_num][0]) + strcpy(l_fb_info->gen.info.fontname, + fontn[l_fb_info->board_num]); + l_fb_info->gen.info.switch_con = &fbgen_switch; + l_fb_info->gen.info.updatevar = &fbgen_update_var; /* */ + l_fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT; + + pm3fb_mapIO(l_fb_info); + + pm3fb_clear_memory(l_fb_info, 0); + pm3fb_clear_colormap(l_fb_info, 0, 0, 0); + + (void) fbgen_get_var(&(disp[l_fb_info->board_num]).var, -1, + &l_fb_info->gen.info); + + if (depth[l_fb_info->board_num]) /* override mode-defined depth */ + { + pm3fb_encode_depth(&(disp[l_fb_info->board_num]).var, depth[l_fb_info->board_num]); + (disp[l_fb_info->board_num]).var.bits_per_pixel = depth2bpp(depth[l_fb_info->board_num]); + } + + (void) fbgen_do_set_var(&(disp[l_fb_info->board_num]).var, 1, + &l_fb_info->gen); + + fbgen_set_disp(-1, &l_fb_info->gen); + + do_install_cmap(0, &l_fb_info->gen.info); + + if (register_framebuffer(&l_fb_info->gen.info) < 0) { + DPRINTK(1, "Couldn't register framebuffer\n"); + return; + } + + PM3_WRITE_DAC_REG(PM3RD_CursorMode, + PM3RD_CursorMode_CURSOR_DISABLE); + + PM3_SHOW_CUR_MODE; + + pm3fb_write_mode(l_fb_info); + + printk("fb%d: %s, using %uK of video memory (%s)\n", + l_fb_info->gen.info.node, + permedia3_name, (u32) (l_fb_info->fb_size >> 10), + cardbase[l_fb_info->board_type].cardname); +} + +/* **************************************************** */ +/* ***** accelerated permedia3-specific functions ***** */ +/* **************************************************** */ +#ifdef PM3FB_USE_ACCEL +static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info) +{ + DTRACE; + + PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync); + PM3_SLOW_WRITE_REG(PM3Sync, 0); + mb(); + do { + while ((PM3_READ_REG(PM3OutFIFOWords)) == 0); + rmb(); + } while ((PM3_READ_REG(PM3OutputFifo)) != PM3Sync_Tag); +} + +static void pm3fb_init_engine(struct pm3fb_info *l_fb_info) +{ + PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync); + PM3_SLOW_WRITE_REG(PM3StatisticMode, 0x0); + PM3_SLOW_WRITE_REG(PM3DeltaMode, 0x0); + PM3_SLOW_WRITE_REG(PM3RasterizerMode, 0x0); + PM3_SLOW_WRITE_REG(PM3ScissorMode, 0x0); + PM3_SLOW_WRITE_REG(PM3LineStippleMode, 0x0); + PM3_SLOW_WRITE_REG(PM3AreaStippleMode, 0x0); + PM3_SLOW_WRITE_REG(PM3GIDMode, 0x0); + PM3_SLOW_WRITE_REG(PM3DepthMode, 0x0); + PM3_SLOW_WRITE_REG(PM3StencilMode, 0x0); + PM3_SLOW_WRITE_REG(PM3StencilData, 0x0); + PM3_SLOW_WRITE_REG(PM3ColorDDAMode, 0x0); + PM3_SLOW_WRITE_REG(PM3TextureCoordMode, 0x0); + PM3_SLOW_WRITE_REG(PM3TextureIndexMode0, 0x0); + PM3_SLOW_WRITE_REG(PM3TextureIndexMode1, 0x0); + PM3_SLOW_WRITE_REG(PM3TextureReadMode, 0x0); + PM3_SLOW_WRITE_REG(PM3LUTMode, 0x0); + PM3_SLOW_WRITE_REG(PM3TextureFilterMode, 0x0); + PM3_SLOW_WRITE_REG(PM3TextureCompositeMode, 0x0); + PM3_SLOW_WRITE_REG(PM3TextureApplicationMode, 0x0); + PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode1, 0x0); + PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode1, 0x0); + PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode0, 0x0); + PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode0, 0x0); + PM3_SLOW_WRITE_REG(PM3FogMode, 0x0); + PM3_SLOW_WRITE_REG(PM3ChromaTestMode, 0x0); + PM3_SLOW_WRITE_REG(PM3AlphaTestMode, 0x0); + PM3_SLOW_WRITE_REG(PM3AntialiasMode, 0x0); + PM3_SLOW_WRITE_REG(PM3YUVMode, 0x0); + PM3_SLOW_WRITE_REG(PM3AlphaBlendColorMode, 0x0); + PM3_SLOW_WRITE_REG(PM3AlphaBlendAlphaMode, 0x0); + PM3_SLOW_WRITE_REG(PM3DitherMode, 0x0); + PM3_SLOW_WRITE_REG(PM3LogicalOpMode, 0x0); + PM3_SLOW_WRITE_REG(PM3RouterMode, 0x0); + PM3_SLOW_WRITE_REG(PM3Window, 0x0); + + PM3_SLOW_WRITE_REG(PM3Config2D, 0x0); + + PM3_SLOW_WRITE_REG(PM3SpanColorMask, 0xffffffff); + + PM3_SLOW_WRITE_REG(PM3XBias, 0x0); + PM3_SLOW_WRITE_REG(PM3YBias, 0x0); + PM3_SLOW_WRITE_REG(PM3DeltaControl, 0x0); + + PM3_SLOW_WRITE_REG(PM3BitMaskPattern, 0xffffffff); + + PM3_SLOW_WRITE_REG(PM3FBDestReadEnables, + PM3FBDestReadEnables_E(0xff) | + PM3FBDestReadEnables_R(0xff) | + PM3FBDestReadEnables_ReferenceAlpha(0xff)); + PM3_SLOW_WRITE_REG(PM3FBDestReadBufferAddr0, 0x0); + PM3_SLOW_WRITE_REG(PM3FBDestReadBufferOffset0, 0x0); + PM3_SLOW_WRITE_REG(PM3FBDestReadBufferWidth0, + PM3FBDestReadBufferWidth_Width(l_fb_info-> + current_par-> + width)); + + PM3_SLOW_WRITE_REG(PM3FBDestReadMode, + PM3FBDestReadMode_ReadEnable | + PM3FBDestReadMode_Enable0); + PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferAddr, 0x0); + PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferOffset, 0x0); + PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferWidth, + PM3FBSourceReadBufferWidth_Width(l_fb_info-> + current_par-> + width)); + PM3_SLOW_WRITE_REG(PM3FBSourceReadMode, + PM3FBSourceReadMode_Blocking | + PM3FBSourceReadMode_ReadEnable); + + { + unsigned long rm = 1; + switch (l_fb_info->current_par->depth) { + case 8: + PM3_SLOW_WRITE_REG(PM3PixelSize, + PM3PixelSize_GLOBAL_8BIT); + break; + case 12: + case 15: + case 16: + PM3_SLOW_WRITE_REG(PM3PixelSize, + PM3PixelSize_GLOBAL_16BIT); + break; + case 32: + PM3_SLOW_WRITE_REG(PM3PixelSize, + PM3PixelSize_GLOBAL_32BIT); + break; + default: + DPRINTK(1, "Unsupported depth %d\n", + l_fb_info->current_par->depth); + break; + } + PM3_SLOW_WRITE_REG(PM3RasterizerMode, rm); + } + + PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff); + PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff); + PM3_SLOW_WRITE_REG(PM3FBWriteMode, + PM3FBWriteMode_WriteEnable | + PM3FBWriteMode_OpaqueSpan | + PM3FBWriteMode_Enable0); + PM3_SLOW_WRITE_REG(PM3FBWriteBufferAddr0, 0x0); + PM3_SLOW_WRITE_REG(PM3FBWriteBufferOffset0, 0x0); + PM3_SLOW_WRITE_REG(PM3FBWriteBufferWidth0, + PM3FBWriteBufferWidth_Width(l_fb_info-> + current_par-> + width)); + + PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 0x0); + { + unsigned long sofb = (8UL * l_fb_info->fb_size) / + ((depth2bpp(l_fb_info->current_par->depth)) + * l_fb_info->current_par->width); /* size in lines of FB */ + if (sofb > 4095) + PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095); + else + PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb); + + switch (l_fb_info->current_par->depth) { + case 8: + PM3_SLOW_WRITE_REG(PM3DitherMode, + (1 << 10) | (2 << 3)); + break; + case 12: + case 15: + case 16: + PM3_SLOW_WRITE_REG(PM3DitherMode, + (1 << 10) | (1 << 3)); + break; + case 32: + PM3_SLOW_WRITE_REG(PM3DitherMode, + (1 << 10) | (0 << 3)); + break; + default: + DPRINTK(1, "Unsupported depth %d\n", + l_fb_info->current_par->depth); + break; + } + } + + PM3_SLOW_WRITE_REG(PM3dXDom, 0x0); + PM3_SLOW_WRITE_REG(PM3dXSub, 0x0); + PM3_SLOW_WRITE_REG(PM3dY, (1 << 16)); + PM3_SLOW_WRITE_REG(PM3StartXDom, 0x0); + PM3_SLOW_WRITE_REG(PM3StartXSub, 0x0); + PM3_SLOW_WRITE_REG(PM3StartY, 0x0); + PM3_SLOW_WRITE_REG(PM3Count, 0x0); + +/* Disable LocalBuffer. better safe than sorry */ + PM3_SLOW_WRITE_REG(PM3LBDestReadMode, 0x0); + PM3_SLOW_WRITE_REG(PM3LBDestReadEnables, 0x0); + PM3_SLOW_WRITE_REG(PM3LBSourceReadMode, 0x0); + PM3_SLOW_WRITE_REG(PM3LBWriteMode, 0x0); + + pm3fb_wait_pm3(l_fb_info); +} + +#ifdef FBCON_HAS_CFB32 +static void pm3fb_cfb32_clear(struct vc_data *conp, + struct display *p, + int sy, int sx, int height, int width) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; + u32 c; + + DTRACE; + + sx = sx * fontwidth(p); + width = width * fontwidth(p); + sy = sy * fontheight(p); + height = height * fontheight(p); + c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; + + /* block fills in 32bpp are hard, but in low res (width <= 1600 :-) + we can use 16bpp operations, but not if NoWriteMask is on (SDRAM) */ + if ((l_fb_info->current_par->width > 1600) || + (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) { + PM3_WAIT(4); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + PM3_WRITE_REG(PM3ForegroundColor, c); + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(sx)) | + (PM3RectanglePosition_YOffset(sy))); + + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(width)) | + (PM3Render2D_Height(height))); + } else { + PM3_WAIT(8); + + PM3_WRITE_REG(PM3FBBlockColor, c); + + PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_16BIT); + + PM3_WRITE_REG(PM3FBWriteBufferWidth0, + PM3FBWriteBufferWidth_Width(l_fb_info-> + current_par-> + width << 1)); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(sx << 1)) | + (PM3RectanglePosition_YOffset(sy))); + + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + (PM3Render2D_Width(width << 1)) | + (PM3Render2D_Height(height))); + + PM3_WRITE_REG(PM3FBWriteBufferWidth0, + PM3FBWriteBufferWidth_Width(l_fb_info-> + current_par-> + width)); + + PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_32BIT); + } + + pm3fb_wait_pm3(l_fb_info); +} + +static void pm3fb_cfb32_clear_margins(struct vc_data *conp, + struct display *p, int bottom_only) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; + int sx, sy; + u32 c; + + DTRACE; + + sx = conp->vc_cols * fontwidth(p); /* right margin */ + sy = conp->vc_rows * fontheight(p); /* bottom margin */ + c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; + + if (!bottom_only) { /* right margin top->bottom */ + PM3_WAIT(4); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + PM3_WRITE_REG(PM3ForegroundColor, c); + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset + (p->var.xoffset + + sx)) | (PM3RectanglePosition_YOffset(p-> + var. + yoffset))); + + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(p->var.xres - sx)) | + (PM3Render2D_Height(p->var.yres))); + } + + /* bottom margin left -> right */ + PM3_WAIT(4); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + PM3_WRITE_REG(PM3ForegroundColor, c); + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(p->var.xoffset)) | + (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); + + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(p->var.xres)) | + (PM3Render2D_Height(p->var.yres - sy))); + + pm3fb_wait_pm3(l_fb_info); +} +#endif /* FBCON_HAS_CFB32 */ +#ifdef FBCON_HAS_CFB16 +static void pm3fb_cfb16_clear(struct vc_data *conp, + struct display *p, + int sy, int sx, int height, int width) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; + u32 c; + + DTRACE; + + sx = sx * fontwidth(p); + width = width * fontwidth(p); + sy = sy * fontheight(p); + height = height * fontheight(p); + c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; + c = c | (c << 16); + + PM3_WAIT(4); + + if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) + PM3_WRITE_REG(PM3ForegroundColor, c); + else + PM3_WRITE_REG(PM3FBBlockColor, c); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(sx)) | + (PM3RectanglePosition_YOffset(sy))); + + if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(width)) | + (PM3Render2D_Height(height))); + else + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + (PM3Render2D_Width(width)) | + (PM3Render2D_Height(height))); + + pm3fb_wait_pm3(l_fb_info); +} + +static void pm3fb_cfb16_clear_margins(struct vc_data *conp, + struct display *p, int bottom_only) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; + int sx, sy; + u32 c; + + DTRACE; + + sx = conp->vc_cols * fontwidth(p); /* right margin */ + sy = conp->vc_rows * fontheight(p); /* bottom margin */ + c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; + c = c | (c << 16); + + if (!bottom_only) { /* right margin top->bottom */ + PM3_WAIT(4); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) + PM3_WRITE_REG(PM3ForegroundColor, c); + else + PM3_WRITE_REG(PM3FBBlockColor, c); + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset + (p->var.xoffset + + sx)) | (PM3RectanglePosition_YOffset(p-> + var. + yoffset))); + if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(p->var.xres - sx)) | + (PM3Render2D_Height(p->var.yres))); + else + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + (PM3Render2D_Width(p->var.xres - sx)) | + (PM3Render2D_Height(p->var.yres))); + } + + /* bottom margin left -> right */ + PM3_WAIT(4); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) + PM3_WRITE_REG(PM3ForegroundColor, c); + else + PM3_WRITE_REG(PM3FBBlockColor, c); + + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(p->var.xoffset)) | + (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); + + if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(p->var.xres)) | + (PM3Render2D_Height(p->var.yres - sy))); + else + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + (PM3Render2D_Width(p->var.xres)) | + (PM3Render2D_Height(p->var.yres - sy))); + + pm3fb_wait_pm3(l_fb_info); +} +#endif /* FBCON_HAS_CFB16 */ +#ifdef FBCON_HAS_CFB8 +static void pm3fb_cfb8_clear(struct vc_data *conp, + struct display *p, + int sy, int sx, int height, int width) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; + u32 c; + + DTRACE; + + sx = sx * fontwidth(p); + width = width * fontwidth(p); + sy = sy * fontheight(p); + height = height * fontheight(p); + + c = attr_bgcol_ec(p, conp); + c |= c << 8; + c |= c << 16; + + PM3_WAIT(4); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + PM3_WRITE_REG(PM3ForegroundColor, c); + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(sx)) | + (PM3RectanglePosition_YOffset(sy))); + + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(width)) | + (PM3Render2D_Height(height))); + + pm3fb_wait_pm3(l_fb_info); +} + +static void pm3fb_cfb8_clear_margins(struct vc_data *conp, + struct display *p, int bottom_only) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; + int sx, sy; + u32 c; + + DTRACE; + + sx = conp->vc_cols * fontwidth(p); /* right margin */ + sy = conp->vc_rows * fontheight(p); /* bottom margin */ + c = attr_bgcol_ec(p, conp); + c |= c << 8; + c |= c << 16; + + if (!bottom_only) { /* right margin top->bottom */ + PM3_WAIT(4); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + PM3_WRITE_REG(PM3ForegroundColor, c); + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset + (p->var.xoffset + + sx)) | (PM3RectanglePosition_YOffset(p-> + var. + yoffset))); + + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(p->var.xres - sx)) | + (PM3Render2D_Height(p->var.yres))); + } + + /* bottom margin left -> right */ + PM3_WAIT(4); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + PM3_WRITE_REG(PM3ForegroundColor, c); + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(p->var.xoffset)) | + (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); + + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(p->var.xres)) | + (PM3Render2D_Height(p->var.yres - sy))); + + pm3fb_wait_pm3(l_fb_info); +} +#endif /* FBCON_HAS_CFB8 */ +#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) +static void pm3fb_cfbX_bmove(struct display *p, + int sy, int sx, + int dy, int dx, int height, int width) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; + int x_align, o_x, o_y; + + DTRACE; + + sx = sx * fontwidth(p); + dx = dx * fontwidth(p); + width = width * fontwidth(p); + sy = sy * fontheight(p); + dy = dy * fontheight(p); + height = height * fontheight(p); + + o_x = sx - dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */ + o_y = sy - dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */ + + x_align = (sx & 0x1f); + + PM3_WAIT(6); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UserScissorEnable | + PM3Config2D_ForegroundROPEnable | + PM3Config2D_Blocking | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + PM3_WRITE_REG(PM3ScissorMinXY, + ((dy & 0x0fff) << 16) | (dx & 0x0fff)); + PM3_WRITE_REG(PM3ScissorMaxXY, + (((dy + height) & 0x0fff) << 16) | + ((dx + width) & 0x0fff)); + + PM3_WRITE_REG(PM3FBSourceReadBufferOffset, + PM3FBSourceReadBufferOffset_XOffset(o_x) | + PM3FBSourceReadBufferOffset_YOffset(o_y)); + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(dx - x_align)) | + (PM3RectanglePosition_YOffset(dy))); + + PM3_WRITE_REG(PM3Render2D, + ((sx > dx) ? PM3Render2D_XPositive : 0) | + ((sy > dy) ? PM3Render2D_YPositive : 0) | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + PM3Render2D_FBSourceReadEnable | + (PM3Render2D_Width(width + x_align)) | + (PM3Render2D_Height(height))); + + pm3fb_wait_pm3(l_fb_info); +} + +static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p, + int c, int yy, int xx) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; + u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0; + u32 fgx, bgx, ldat; + int sx, sy, i; + + DTRACE; + + if (l_fb_info->current_par->depth == 8) + fgx = attr_fgcol(p, c); + else if (depth2bpp(l_fb_info->current_par->depth) == 16) + fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)]; + else + fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)]; + + PM3_COLOR(fgx); + + if (l_fb_info->current_par->depth == 8) + bgx = attr_bgcol(p, c); + else if (depth2bpp(l_fb_info->current_par->depth) == 16) + bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)]; + else + bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)]; + + PM3_COLOR(bgx); + + PM3_WAIT(4); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable | PM3Config2D_OpaqueSpan); + + PM3_WRITE_REG(PM3ForegroundColor, fgx); + PM3_WRITE_REG(PM3FillBackgroundColor, bgx); + + /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */ + /* and 16 bits for fontwidth <= 16 */ + /* same in _putcs, same for Y and fontheight */ + if (fontwidth(p) <= 8) + asx = 2; + else if (fontwidth(p) <= 16) + asx = 3; /* look OK */ + if (fontheight(p) <= 8) + asy = 2; + else if (fontheight(p) <= 16) + asy = 3; /* look OK */ + else if (fontheight(p) <= 32) + asy = 4; /* look OK */ + + sx = xx * fontwidth(p); + sy = yy * fontheight(p); + + if (fontwidth(p) <= 8) + o_x = (8 - (sx & 0x7)) & 0x7; + else if (fontwidth(p) <= 16) + o_x = (16 - (sx & 0xF)) & 0xF; + if (fontheight(p) <= 8) + o_y = (8 - (sy & 0x7)) & 0x7; + else if (fontheight(p) <= 16) + o_y = (16 - (sy & 0xF)) & 0xF; + else if (fontheight(p) <= 32) + o_y = (32 - (sy & 0x1F)) & 0x1F; + + PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */ + (1 << 18) | /* BE */ + 1 | (asx << 1) | (asy << 4) | /* address select x/y */ + (1 << 20)); /* OpaqueSpan */ + + if (fontwidth(p) <= 8) { + cdat = p->fontdata + (c & p->charmask) * fontheight(p); + } else { + cdat = + p->fontdata + + ((c & p->charmask) * (fontheight(p) << 1)); + } + + PM3_WAIT(2 + fontheight(p)); + + for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */ + if (fontwidth(p) <= 8) { + ldat = *cdat++; + } else { /* assume fontwidth <= 16 ATM */ + + ldat = ((*cdat++) << 8); + ldat |= *cdat++; + } + PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat); + } + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(sx)) | + (PM3RectanglePosition_YOffset(sy))); + + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_AreaStippleEnable | + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(fontwidth(p))) | + (PM3Render2D_Height(fontheight(p)))); + + pm3fb_wait_pm3(l_fb_info); +} + +static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, + int xx) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; + u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0; + u32 fgx, bgx, ldat; + int sx, sy, i, j; + u16 sc; + + DTRACE; + + sc = scr_readw(s); + if (l_fb_info->current_par->depth == 8) + fgx = attr_fgcol(p, sc); + else if (depth2bpp(l_fb_info->current_par->depth) == 16) + fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, sc)]; + else + fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, sc)]; + + PM3_COLOR(fgx); + + if (l_fb_info->current_par->depth == 8) + bgx = attr_bgcol(p, sc); + else if (depth2bpp(l_fb_info->current_par->depth) == 16) + bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, sc)]; + else + bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, sc)]; + + PM3_COLOR(bgx); + + PM3_WAIT(4); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable | + PM3Config2D_OpaqueSpan); + + PM3_WRITE_REG(PM3ForegroundColor, fgx); + PM3_WRITE_REG(PM3FillBackgroundColor, bgx); + + /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */ + /* and 16 bits for fontwidth <= 16 */ + /* same in _putc, same for Y and fontheight */ + if (fontwidth(p) <= 8) + asx = 2; + else if (fontwidth(p) <= 16) + asx = 3; /* look OK */ + if (fontheight(p) <= 8) + asy = 2; + else if (fontheight(p) <= 16) + asy = 3; /* look OK */ + else if (fontheight(p) <= 32) + asy = 4; /* look OK */ + + sy = yy * fontheight(p); + + if (fontheight(p) <= 8) + o_y = (8 - (sy & 0x7)) & 0x7; + else if (fontheight(p) <= 16) + o_y = (16 - (sy & 0xF)) & 0xF; + else if (fontheight(p) <= 32) + o_y = (32 - (sy & 0x1F)) & 0x1F; + + for (j = 0; j < count; j++) { + sc = scr_readw(s + j); + if (fontwidth(p) <= 8) + cdat = p->fontdata + + (sc & p->charmask) * fontheight(p); + else + cdat = p->fontdata + + ((sc & p->charmask) * fontheight(p) << 1); + + sx = (xx + j) * fontwidth(p); + + if (fontwidth(p) <= 8) + o_x = (8 - (sx & 0x7)) & 0x7; + else if (fontwidth(p) <= 16) + o_x = (16 - (sx & 0xF)) & 0xF; + + PM3_WAIT(3 + fontheight(p)); + + PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */ + (1 << 18) | /* BE */ + 1 | (asx << 1) | (asy << 4) | /* address select x/y */ + (1 << 20)); /* OpaqueSpan */ + + for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */ + if (fontwidth(p) <= 8) { + ldat = *cdat++; + } else { /* assume fontwidth <= 16 ATM */ + ldat = ((*cdat++) << 8); + ldat |= *cdat++; + } + PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat); + } + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(sx)) | + (PM3RectanglePosition_YOffset(sy))); + + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_AreaStippleEnable | + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(fontwidth(p))) | + (PM3Render2D_Height(fontheight(p)))); + } + pm3fb_wait_pm3(l_fb_info); +} + +static void pm3fb_cfbX_revc(struct display *p, int xx, int yy) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; + + xx = xx * fontwidth(p); + yy = yy * fontheight(p); + + if (l_fb_info->current_par->depth == 8) + { + if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) + PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F); + else + PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F); + } + + PM3_WAIT(3); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0xa)) | /* Oxa is GXinvert */ + PM3Config2D_FBDestReadEnable | + PM3Config2D_FBWriteEnable); + + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(xx)) | + (PM3RectanglePosition_YOffset(yy))); + + PM3_WRITE_REG(PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(fontwidth(p))) | + (PM3Render2D_Height(fontheight(p)))); + + pm3fb_wait_pm3(l_fb_info); + + if (l_fb_info->current_par->depth == 8) + { + if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) + PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF); + else + PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF); + } +} + +#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */ +#endif /* PM3FB_USE_ACCEL */ +/* *********************************** */ +/* ***** pre-init board(s) setup ***** */ +/* *********************************** */ + +static void pm3fb_mode_setup(char *mode, unsigned long board_num) +{ + struct pm3fb_info *l_fb_info = &(fb_info[board_num]); + struct pm3fb_par *l_fb_par = &(current_par[board_num]); + unsigned long i = 0; + + current_par_valid[board_num] = 0; + + if (!strncmp(mode, "current", 7)) { + l_fb_info->use_current = 1; /* default w/ OpenFirmware */ + } else { + while ((mode_base[i].name[0]) + && (!current_par_valid[board_num])) { + if (! + (strncmp + (mode, mode_base[i].name, + strlen(mode_base[i].name)))) { + memcpy(l_fb_par, &(mode_base[i].user_mode), + sizeof(struct pm3fb_par)); + current_par_valid[board_num] = 1; + DPRINTK(2, "Mode set to %s\n", + mode_base[i].name); + } + i++; + } + DASSERT(current_par_valid[board_num], + "Valid mode on command line\n"); + } +} + +static void pm3fb_pciid_setup(char *pciid, unsigned long board_num) +{ + short l_bus = -1, l_slot = -1, l_func = -1; + char *next; + + if (pciid) { + l_bus = simple_strtoul(pciid, &next, 10); + if (next && (next[0] == ':')) { + pciid = next + 1; + l_slot = simple_strtoul(pciid, &next, 10); + if (next && (next[0] == ':')) { + pciid = next + 1; + l_func = + simple_strtoul(pciid, (char **) NULL, + 10); + } + } + } else + return; + + if ((l_bus >= 0) && (l_slot >= 0) && (l_func >= 0)) { + bus[board_num] = l_bus; + slot[board_num] = l_slot; + func[board_num] = l_func; + DPRINTK(2, "Board #%ld will be PciId: %hd:%hd:%hd\n", + board_num, l_bus, l_slot, l_func); + } else { + DPRINTK(1, "Invalid PciId: %hd:%hd:%hd for board #%ld\n", + l_bus, l_slot, l_func, board_num); + } +} + +static void pm3fb_font_setup(char *lf, unsigned long board_num) +{ + unsigned long lfs = strlen(lf); + + if (lfs > (PM3_FONTNAME_SIZE - 1)) { + DPRINTK(1, "Fontname %s too long\n", lf); + return; + } + strlcpy(fontn[board_num], lf, lfs + 1); +} + +static void pm3fb_bootdepth_setup(char *bds, unsigned long board_num) +{ + unsigned long bd = simple_strtoul(bds, (char **) NULL, 10); + + if (!(depth_supported(bd))) { + printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n", + bds, board_num); + return; + } + depth[board_num] = bd; +} + +static void pm3fb_forcesize_setup(char *bds, unsigned long board_num) +{ + unsigned long bd = simple_strtoul(bds, (char **) NULL, 10); + + if (bd > 64) { + printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n", + bds, board_num); + return; + } + forcesize[board_num] = bd; +} + +static char *pm3fb_boardnum_setup(char *options, unsigned long *bn) +{ + char *next; + + if (!(CHAR_IS_NUM(options[0]))) { + (*bn) = 0; + return (options); + } + + (*bn) = simple_strtoul(options, &next, 10); + + if (next && (next[0] == ':') && ((*bn) >= 0) + && ((*bn) <= PM3_MAX_BOARD)) { + DPRINTK(2, "Board_num seen as %ld\n", (*bn)); + return (next + 1); + } else { + (*bn) = 0; + DPRINTK(2, "Board_num default to %ld\n", (*bn)); + return (options); + } +} + +static void pm3fb_real_setup(char *options) +{ + char *next; + unsigned long i, bn; + struct pm3fb_info *l_fb_info; + + DTRACE; + + DPRINTK(2, "Options : %s\n", options); + + for (i = 0; i < PM3_MAX_BOARD; i++) { + l_fb_info = &(fb_info[i]); + memset(l_fb_info, 0, sizeof(struct pm3fb_info)); + l_fb_info->gen.fbhw = &pm3fb_switch; + l_fb_info->board_num = i; + current_par_valid[i] = 0; + slot[i] = -1; + func[i] = -1; + bus[i] = -1; + disable[i] = 0; + noaccel[i] = 0; + fontn[i][0] = '\0'; + depth[i] = 0; + l_fb_info->current_par = &(current_par[i]); + } + + /* eat up prefix pm3fb and whatever is used as separator i.e. :,= */ + if (!strncmp(options, "pm3fb", 5)) { + options += 5; + while (((*options) == ',') || ((*options) == ':') + || ((*options) == '=')) + options++; + } + + while (options) { + bn = 0; + if ((next = strchr(options, ','))) { + (*next) = '\0'; + next++; + } + + if (!strncmp(options, "mode:", 5)) { + options = pm3fb_boardnum_setup(options + 5, &bn); + DPRINTK(2, "Setting mode for board #%ld\n", bn); + pm3fb_mode_setup(options, bn); + } else if (!strncmp(options, "off:", 4)) { + options = pm3fb_boardnum_setup(options + 4, &bn); + DPRINTK(2, "Disabling board #%ld\n", bn); + disable[bn] = 1; + } else if (!strncmp(options, "off", 3)) { /* disable everything */ + for (i = 0; i < PM3_MAX_BOARD; i++) + disable[i] = 1; + } else if (!strncmp(options, "disable:", 8)) { + options = pm3fb_boardnum_setup(options + 8, &bn); + DPRINTK(2, "Disabling board #%ld\n", bn); + disable[bn] = 1; + } else if (!strncmp(options, "pciid:", 6)) { + options = pm3fb_boardnum_setup(options + 6, &bn); + DPRINTK(2, "Setting PciID for board #%ld\n", bn); + pm3fb_pciid_setup(options, bn); + } else if (!strncmp(options, "noaccel:", 8)) { + options = pm3fb_boardnum_setup(options + 8, &bn); + noaccel[bn] = 1; + } else if (!strncmp(options, "font:", 5)) { + options = pm3fb_boardnum_setup(options + 5, &bn); + pm3fb_font_setup(options, bn); + } else if (!strncmp(options, "depth:", 6)) { + options = pm3fb_boardnum_setup(options + 6, &bn); + pm3fb_bootdepth_setup(options, bn); + } else if (!strncmp(options, "printtimings", 12)) { + printtimings = 1; + } else if (!strncmp(options, "flatpanel:", 10)) { + options = pm3fb_boardnum_setup(options + 10, &bn); + flatpanel[bn] = 1; + } else if (!strncmp(options, "forcesize:", 10)) { + options = pm3fb_boardnum_setup(options + 10, &bn); + pm3fb_forcesize_setup(options, bn); + } + options = next; + } +} + +/* ********************************************** */ +/* ***** framebuffer API standard functions ***** */ +/* ********************************************** */ + +static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix, + const void *par, struct fb_info_gen *info) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; + struct pm3fb_par *p = (struct pm3fb_par *) par; + + DTRACE; + + strcpy(fix->id, permedia3_name); + fix->smem_start = (unsigned long)l_fb_info->p_fb; + fix->smem_len = l_fb_info->fb_size; + fix->mmio_start = (unsigned long)l_fb_info->pIOBase; + fix->mmio_len = PM3_REGS_SIZE; +#ifdef PM3FB_USE_ACCEL + if (!(noaccel[l_fb_info->board_num])) + fix->accel = FB_ACCEL_3DLABS_PERMEDIA3; + else +#endif /* PM3FB_USE_ACCEL */ + fix->accel = FB_ACCEL_NONE; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = + (p->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + if (current_par_valid[l_fb_info->board_num]) + fix->line_length = + l_fb_info->current_par->width * + depth2ByPP(l_fb_info->current_par->depth); + else + fix->line_length = 0; + fix->xpanstep = 64 / depth2bpp(p->depth); + fix->ypanstep = 1; + fix->ywrapstep = 0; + return (0); +} + +static int pm3fb_decode_var(const struct fb_var_screeninfo *var, + void *par, struct fb_info_gen *info) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; + struct pm3fb_par *p = (struct pm3fb_par *) par; + struct pm3fb_par temp_p; + u32 xres; + + DTRACE; + + DASSERT((var != NULL), "fb_var_screeninfo* not NULL"); + DASSERT((p != NULL), "pm3fb_par* not NULL"); + DASSERT((l_fb_info != NULL), "pm3fb_info* not NULL"); + + memset(&temp_p, 0, sizeof(struct pm3fb_par)); + temp_p.width = (var->xres_virtual + 7) & ~7; + temp_p.height = var->yres_virtual; + + if (!(depth_supported(var->bits_per_pixel))) /* round unsupported up to a multiple of 8 */ + temp_p.depth = depth2bpp(var->bits_per_pixel); + else + temp_p.depth = var->bits_per_pixel; + + temp_p.depth = (temp_p.depth > 32) ? 32 : temp_p.depth; /* max 32 */ + temp_p.depth = (temp_p.depth == 24) ? 32 : temp_p.depth; /* 24 unsupported, round-up to 32 */ + + if ((temp_p.depth == 16) && (var->red.length == 5) && (var->green.length == 5) && (var->blue.length == 5)) + temp_p.depth = 15; /* RGBA 5551 is stored as depth 15 */ + + if ((temp_p.depth == 16) && (var->red.length == 4) && (var->green.length == 4) && (var->blue.length == 4)) + temp_p.depth = 12; /* RGBA 4444 is stored as depth 12 */ + + + DPRINTK(2, + "xres: %d, yres: %d, vxres: %d, vyres: %d ; xoffset:%d, yoffset: %d\n", + var->xres, var->yres, var->xres_virtual, var->yres_virtual, + var->xoffset, var->yoffset); + + xres = (var->xres + 31) & ~31; + if (temp_p.width < xres + var->xoffset) + temp_p.width = xres + var->xoffset; + if (temp_p.height < var->yres + var->yoffset) + temp_p.height = var->yres + var->yoffset; + + if (temp_p.width > 2048) { + DPRINTK(1, "virtual width not supported: %u\n", + temp_p.width); + return (-EINVAL); + } + if (var->yres < 200) { + DPRINTK(1, "height not supported: %u\n", (u32) var->yres); + return (-EINVAL); + } + if (temp_p.height < 200 || temp_p.height > 4095) { + DPRINTK(1, "virtual height not supported: %u\n", + temp_p.height); + return (-EINVAL); + } + if (!(depth_supported(temp_p.depth))) { + DPRINTK(1, "depth not supported: %u\n", temp_p.depth); + return (-EINVAL); + } + if ((temp_p.width * temp_p.height * depth2ByPP(temp_p.depth)) > + l_fb_info->fb_size) { + DPRINTK(1, "no memory for screen (%ux%ux%u)\n", + temp_p.width, temp_p.height, temp_p.depth); + return (-EINVAL); + } + + if ((!var->pixclock) || + (!var->right_margin) || + (!var->hsync_len) || + (!var->left_margin) || + (!var->lower_margin) || + (!var->vsync_len) || (!var->upper_margin) + ) { + unsigned long i = 0, done = 0; + printk(KERN_WARNING "pm3fb: refusing to use a likely wrong timing\n"); + + while ((mode_base[i].user_mode.width) && !done) { + if ((mode_base[i].user_mode.width == temp_p.width) + && (mode_base[i].user_mode.height == + temp_p.height)) { + printk(KERN_NOTICE "pm3fb: using close match %s\n", + mode_base[i].name); + temp_p = mode_base[i].user_mode; + done = 1; + } + i++; + } + if (!done) + return (-EINVAL); + } else { + temp_p.pixclock = PICOS2KHZ(var->pixclock); + if (temp_p.pixclock > PM3_MAX_PIXCLOCK) { + DPRINTK(1, "pixclock too high (%uKHz)\n", + temp_p.pixclock); + return (-EINVAL); + } + + temp_p.hsstart = var->right_margin; + temp_p.hsend = var->right_margin + var->hsync_len; + temp_p.hbend = + var->right_margin + var->hsync_len + var->left_margin; + temp_p.htotal = xres + temp_p.hbend; + + temp_p.vsstart = var->lower_margin; + temp_p.vsend = var->lower_margin + var->vsync_len; + temp_p.vbend = + var->lower_margin + var->vsync_len + var->upper_margin; + temp_p.vtotal = var->yres + temp_p.vbend; + + temp_p.stride = temp_p.width; + + DPRINTK(2, "Using %d * %d, %d Khz, stride is %08x\n", + temp_p.width, temp_p.height, temp_p.pixclock, + temp_p.stride); + + temp_p.base = + pm3fb_Shiftbpp(l_fb_info, temp_p.depth, + (var->yoffset * xres) + var->xoffset); + + temp_p.video = 0; + + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_HIGH; + else + temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_LOW; + + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_HIGH; + else + temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_LOW; + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + DPRINTK(1, "Interlaced mode not supported\n\n"); + return (-EINVAL); + } + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) + temp_p.video |= PM3VideoControl_LINE_DOUBLE_ON; + else + temp_p.video |= PM3VideoControl_LINE_DOUBLE_OFF; + + if (var->activate == FB_ACTIVATE_NOW) + temp_p.video |= PM3VideoControl_ENABLE; + else { + temp_p.video |= PM3VideoControl_DISABLE; + DPRINTK(2, "PM3Video disabled\n"); + } + + switch (temp_p.depth) { + case 8: + temp_p.video |= PM3VideoControl_PIXELSIZE_8BIT; + break; + case 12: + case 15: + case 16: + temp_p.video |= PM3VideoControl_PIXELSIZE_16BIT; + break; + case 32: + temp_p.video |= PM3VideoControl_PIXELSIZE_32BIT; + break; + default: + DPRINTK(1, "Unsupported depth\n"); + break; + } + } + (*p) = temp_p; + +#ifdef PM3FB_USE_ACCEL + if (var->accel_flags & FB_ACCELF_TEXT) + noaccel[l_fb_info->board_num] = 0; + else + noaccel[l_fb_info->board_num] = 1; +#endif /* PM3FB_USE_ACCEL */ + + return (0); +} + +static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d) +{ + switch (d) { + case 8: + var->red.length = var->green.length = var->blue.length = 8; + var->red.offset = var->green.offset = var->blue.offset = 0; + var->transp.offset = var->transp.length = 0; + break; + + case 12: + var->red.offset = 8; + var->red.length = 4; + var->green.offset = 4; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; + var->transp.offset = 12; + var->transp.length = 4; + break; + + case 15: + 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; + break; + + case 16: + 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 = var->transp.length = 0; + break; + + case 32: + var->transp.offset = 24; + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = var->green.length = + var->blue.length = var->transp.length = 8; + break; + + default: + DPRINTK(1, "Unsupported depth %ld\n", d); + break; + } +} + +static int pm3fb_encode_var(struct fb_var_screeninfo *var, + const void *par, struct fb_info_gen *info) +{ + struct pm3fb_par *p = (struct pm3fb_par *) par; + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; + + u32 base; + + DTRACE; + + DASSERT((var != NULL), "fb_var_screeninfo* not NULL"); + DASSERT((p != NULL), "pm3fb_par* not NULL"); + DASSERT((info != NULL), "fb_info_gen* not NULL"); + + memset(var, 0, sizeof(struct fb_var_screeninfo)); + +#ifdef PM3FB_USE_ACCEL + if (!(noaccel[l_fb_info->board_num])) + var->accel_flags |= FB_ACCELF_TEXT; +#endif /* PM3FB_USE_ACCEL */ + + var->xres_virtual = p->width; + var->yres_virtual = p->height; + var->xres = p->htotal - p->hbend; + var->yres = p->vtotal - p->vbend; + + DPRINTK(2, "xres = %d, yres : %d\n", var->xres, var->yres); + + var->right_margin = p->hsstart; + var->hsync_len = p->hsend - p->hsstart; + var->left_margin = p->hbend - p->hsend; + var->lower_margin = p->vsstart; + var->vsync_len = p->vsend - p->vsstart; + var->upper_margin = p->vbend - p->vsend; + var->bits_per_pixel = depth2bpp(p->depth); + + pm3fb_encode_depth(var, p->depth); + + base = pm3fb_Unshiftbpp(l_fb_info, p->depth, p->base); + + var->xoffset = base % var->xres; + var->yoffset = base / var->xres; + + var->height = var->width = -1; + + var->pixclock = KHZ2PICOS(p->pixclock); + + if ((p->video & PM3VideoControl_HSYNC_MASK) == + PM3VideoControl_HSYNC_ACTIVE_HIGH) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if ((p->video & PM3VideoControl_VSYNC_MASK) == + PM3VideoControl_VSYNC_ACTIVE_HIGH) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + if (p->video & PM3VideoControl_LINE_DOUBLE_ON) + var->vmode = FB_VMODE_DOUBLE; + + return (0); +} + +static void pm3fb_get_par(void *par, struct fb_info_gen *info) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; + + DTRACE; + + if (!current_par_valid[l_fb_info->board_num]) { + if (l_fb_info->use_current) + pm3fb_read_mode(l_fb_info, l_fb_info->current_par); + else + memcpy(l_fb_info->current_par, + &(mode_base[0].user_mode), + sizeof(struct pm3fb_par)); + current_par_valid[l_fb_info->board_num] = 1; + } + *((struct pm3fb_par *) par) = *(l_fb_info->current_par); +} + +static void pm3fb_set_par(const void *par, struct fb_info_gen *info) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; + + DTRACE; + + *(l_fb_info->current_par) = *((struct pm3fb_par *) par); + current_par_valid[l_fb_info->board_num] = 1; + + pm3fb_write_mode(l_fb_info); + +#ifdef PM3FB_USE_ACCEL + pm3fb_init_engine(l_fb_info); +#endif /* PM3FB_USE_ACCEL */ +} + +static void pm3fb_set_color(struct pm3fb_info *l_fb_info, + unsigned char regno, unsigned char r, + unsigned char g, unsigned char b) +{ + DTRACE; + + PM3_SLOW_WRITE_REG(PM3RD_PaletteWriteAddress, regno); + PM3_SLOW_WRITE_REG(PM3RD_PaletteData, r); + PM3_SLOW_WRITE_REG(PM3RD_PaletteData, g); + PM3_SLOW_WRITE_REG(PM3RD_PaletteData, b); +} + +static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *info) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; + + DTRACE; + + if (regno < 256) { + *red = + l_fb_info->palette[regno].red << 8 | l_fb_info-> + palette[regno].red; + *green = + l_fb_info->palette[regno].green << 8 | l_fb_info-> + palette[regno].green; + *blue = + l_fb_info->palette[regno].blue << 8 | l_fb_info-> + palette[regno].blue; + *transp = + l_fb_info->palette[regno].transp << 8 | l_fb_info-> + palette[regno].transp; + } + return (regno > 255); +} + +static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; + + DTRACE; + + if (regno < 16) { + switch (l_fb_info->current_par->depth) { +#ifdef FBCON_HAS_CFB8 + case 8: + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 12: + l_fb_info->cmap.cmap12[regno] = + (((u32) red & 0xf000) >> 4) | + (((u32) green & 0xf000) >> 8) | + (((u32) blue & 0xf000) >> 12); + break; + + case 15: + l_fb_info->cmap.cmap15[regno] = + (((u32) red & 0xf800) >> 1) | + (((u32) green & 0xf800) >> 6) | + (((u32) blue & 0xf800) >> 11); + break; + + case 16: + l_fb_info->cmap.cmap16[regno] = + ((u32) red & 0xf800) | + (((u32) green & 0xfc00) >> 5) | + (((u32) blue & 0xf800) >> 11); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + l_fb_info->cmap.cmap32[regno] = + (((u32) transp & 0xff00) << 16) | + (((u32) red & 0xff00) << 8) | + (((u32) green & 0xff00)) | + (((u32) blue & 0xff00) >> 8); + break; +#endif + default: + DPRINTK(1, "bad depth %u\n", + l_fb_info->current_par->depth); + break; + } + } + if (regno < 256) { + l_fb_info->palette[regno].red = red >> 8; + l_fb_info->palette[regno].green = green >> 8; + l_fb_info->palette[regno].blue = blue >> 8; + l_fb_info->palette[regno].transp = transp >> 8; + if (l_fb_info->current_par->depth == 8) + pm3fb_set_color(l_fb_info, regno, red >> 8, + green >> 8, blue >> 8); + } + return (regno > 255); +} + +static int pm3fb_blank(int blank_mode, struct fb_info_gen *info) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; + u32 video; + + DTRACE; + + if (!current_par_valid[l_fb_info->board_num]) + return (1); + + video = l_fb_info->current_par->video; + + /* + * Oxygen VX1 - it appears that setting PM3VideoControl and + * then PM3RD_SyncControl to the same SYNC settings undoes + * any net change - they seem to xor together. Only set the + * sync options in PM3RD_SyncControl. --rmk + */ + video &= ~(PM3VideoControl_HSYNC_MASK | + PM3VideoControl_VSYNC_MASK); + video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | + PM3VideoControl_VSYNC_ACTIVE_HIGH; + + if (blank_mode > 0) { + switch (blank_mode - 1) { + + case VESA_NO_BLANKING: /* FIXME */ + video = video & ~(PM3VideoControl_ENABLE); + break; + + case VESA_HSYNC_SUSPEND: + video = video & ~(PM3VideoControl_HSYNC_MASK | + PM3VideoControl_BLANK_ACTIVE_LOW); + break; + case VESA_VSYNC_SUSPEND: + video = video & ~(PM3VideoControl_VSYNC_MASK | + PM3VideoControl_BLANK_ACTIVE_LOW); + break; + case VESA_POWERDOWN: + video = video & ~(PM3VideoControl_HSYNC_MASK | + PM3VideoControl_VSYNC_MASK | + PM3VideoControl_BLANK_ACTIVE_LOW); + break; + default: + DPRINTK(1, "Unsupported blanking %d\n", + blank_mode); + return (1); + break; + } + } + + PM3_SLOW_WRITE_REG(PM3VideoControl, video); + + return (0); +} + +static void pm3fb_set_disp(const void *par, struct display *disp, + struct fb_info_gen *info) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; + struct pm3fb_par *p = (struct pm3fb_par *) par; + u32 flags; + + DTRACE; + + local_irq_save(flags); + info->info.screen_base = l_fb_info->v_fb; + switch (p->depth) { +#ifdef FBCON_HAS_CFB8 + case 8: +#ifdef PM3FB_USE_ACCEL + if (!(noaccel[l_fb_info->board_num])) + disp->dispsw = &pm3fb_cfb8; + else +#endif /* PM3FB_USE_ACCEL */ + disp->dispsw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 12: +#ifdef PM3FB_USE_ACCEL + if (!(noaccel[l_fb_info->board_num])) + disp->dispsw = &pm3fb_cfb16; + else +#endif /* PM3FB_USE_ACCEL */ + disp->dispsw = &fbcon_cfb16; + disp->dispsw_data = l_fb_info->cmap.cmap12; + break; + case 15: +#ifdef PM3FB_USE_ACCEL + if (!(noaccel[l_fb_info->board_num])) + disp->dispsw = &pm3fb_cfb16; + else +#endif /* PM3FB_USE_ACCEL */ + disp->dispsw = &fbcon_cfb16; + disp->dispsw_data = l_fb_info->cmap.cmap15; + break; + case 16: +#ifdef PM3FB_USE_ACCEL + if (!(noaccel[l_fb_info->board_num])) + disp->dispsw = &pm3fb_cfb16; + else +#endif /* PM3FB_USE_ACCEL */ + disp->dispsw = &fbcon_cfb16; + disp->dispsw_data = l_fb_info->cmap.cmap16; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: +#ifdef PM3FB_USE_ACCEL + if (!(noaccel[l_fb_info->board_num])) + disp->dispsw = &pm3fb_cfb32; + else +#endif /* PM3FB_USE_ACCEL */ + disp->dispsw = &fbcon_cfb32; + disp->dispsw_data = l_fb_info->cmap.cmap32; + break; +#endif /* FBCON_HAS_CFB32 */ + default: + disp->dispsw = &fbcon_dummy; + DPRINTK(1, "Invalid depth, using fbcon_dummy\n"); + break; + } + local_irq_restore(flags); +} + +/* */ +static void pm3fb_detect(void) +{ + struct pci_dev *dev_array[PM3_MAX_BOARD]; + struct pci_dev *dev = NULL; + struct pm3fb_info *l_fb_info = &(fb_info[0]); + unsigned long i, j, done; + + DTRACE; + + for (i = 0; i < PM3_MAX_BOARD; i++) { + dev_array[i] = NULL; + fb_info[i].dev = NULL; + } + + dev = + pci_find_device(PCI_VENDOR_ID_3DLABS, + PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev); + + for (i = 0; ((i < PM3_MAX_BOARD) && dev); i++) { + dev_array[i] = dev; + dev = + pci_find_device(PCI_VENDOR_ID_3DLABS, + PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev); + } + + if (dev) { /* more than PM3_MAX_BOARD */ + printk(KERN_WARNING "pm3fb: Warning: more than %d boards found\n", + PM3_MAX_BOARD); + } + + if (!dev_array[0]) { /* not a single board, abort */ + return; + } + + /* allocate user-defined boards */ + for (i = 0; i < PM3_MAX_BOARD; i++) { + if ((bus[i] >= 0) && (slot[i] >= 0) && (func[i] >= 0)) { + for (j = 0; j < PM3_MAX_BOARD; j++) { + if ((dev_array[j] != NULL) && + (dev_array[j]->bus->number == bus[i]) + && (PCI_SLOT(dev_array[j]->devfn) == + slot[i]) + && (PCI_FUNC(dev_array[j]->devfn) == + func[i])) { + fb_info[i].dev = dev_array[j]; + dev_array[j] = NULL; + } + } + } + } + /* allocate remaining boards */ + for (i = 0; i < PM3_MAX_BOARD; i++) { + if (fb_info[i].dev == NULL) { + done = 0; + for (j = 0; ((j < PM3_MAX_BOARD) && (!done)); j++) { + if (dev_array[j] != NULL) { + fb_info[i].dev = dev_array[j]; + dev_array[j] = NULL; + done = 1; + } + } + } + } + + /* at that point, all PCI Permedia3 are detected and allocated */ + /* now, initialize... or not */ + for (i = 0; i < PM3_MAX_BOARD; i++) { + l_fb_info = &(fb_info[i]); + if ((l_fb_info->dev) && (!disable[i])) { /* PCI device was found and not disabled by user */ + DPRINTK(2, + "found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n", + (unsigned long) l_fb_info->dev, + (unsigned long) l_fb_info->dev->vendor, + (unsigned long) l_fb_info->dev->device, + (unsigned long) + pci_resource_start(l_fb_info->dev, 0), + (unsigned long) + pci_resource_start(l_fb_info->dev, 1), + (unsigned long) + pci_resource_start(l_fb_info->dev, 2), + (unsigned long) + pci_resource_start(l_fb_info->dev, 3), + (unsigned long) + pci_resource_start(l_fb_info->dev, 4), + (unsigned long) + pci_resource_start(l_fb_info->dev, 5), + (unsigned long) l_fb_info->dev->irq); + + l_fb_info->pIOBase = + (unsigned char *) + pci_resource_start(l_fb_info->dev, 0); +#ifdef __BIG_ENDIAN + l_fb_info->pIOBase += PM3_REGS_SIZE; +#endif + l_fb_info->vIOBase = (unsigned char *) -1; + l_fb_info->p_fb = + (unsigned char *) + pci_resource_start(l_fb_info->dev, 1); + l_fb_info->v_fb = (unsigned char *) -1; + + if (!request_mem_region + ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */ + "pm3fb")) { + printk + (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n", + l_fb_info->board_num); + continue; + } + if (!request_mem_region + ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE, + "pm3fb I/O regs")) { + printk + (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n", + l_fb_info->board_num); + continue; + } + if (forcesize[l_fb_info->board_num]) + l_fb_info->fb_size = forcesize[l_fb_info->board_num]; + + l_fb_info->fb_size = + pm3fb_size_memory(l_fb_info); + if (l_fb_info->fb_size) { + (void) pci_enable_device(l_fb_info->dev); + pm3fb_common_init(l_fb_info); + } else + printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num); + } + } +} + +static int pm3fb_pan_display(const struct fb_var_screeninfo *var, + struct fb_info_gen *info) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; + + DTRACE; + + if (!current_par_valid[l_fb_info->board_num]) + return -EINVAL; + + l_fb_info->current_par->base = /* in 128 bits chunk - i.e. AFTER Shiftbpp */ + pm3fb_Shiftbpp(l_fb_info, + l_fb_info->current_par->depth, + (var->yoffset * l_fb_info->current_par->width) + + var->xoffset); + PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base); + return 0; +} + +static int pm3fb_ioctl(struct inode *inode, struct file *file, + u_int cmd, u_long arg, int con, + struct fb_info *info) +{ + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; + u32 cm, i; +#ifdef PM3FB_MASTER_DEBUG + char cc[3]; +#endif /* PM3FB_MASTER_DEBUG */ + + switch(cmd) + { +#ifdef PM3FB_MASTER_DEBUG + case PM3FBIO_CLEARMEMORY: + if (copy_from_user(&cm, (void *)arg, sizeof(u32))) + return(-EFAULT); + pm3fb_clear_memory(l_fb_info, cm); + return(0); + break; + + case PM3FBIO_CLEARCMAP: + if (copy_from_user(cc, (void*)arg, 3 * sizeof(char))) + return(-EFAULT); + pm3fb_clear_colormap(l_fb_info, cc[0], cc[1], cc[2]); + return(0); + break; +#endif /* PM3FB_MASTER_DEBUG */ + + case PM3FBIO_RESETCHIP: + cm = 1; + PM3_SLOW_WRITE_REG(PM3ResetStatus, 1); + for (i = 0 ; (i < 10000) && cm ; i++) + { + PM3_DELAY(10); + cm = PM3_READ_REG(PM3ResetStatus); + } + if (cm) + { + printk(KERN_ERR "pm3fb: chip reset failed with status 0x%x\n", cm); + return(-EIO); + } + /* first thing first, reload memory timings */ + pm3fb_write_memory_timings(l_fb_info); +#ifdef PM3FB_USE_ACCEL + pm3fb_init_engine(l_fb_info); +#endif /* PM3FB_USE_ACCEL */ + pm3fb_write_mode(l_fb_info); + return(0); + break; + + default: + DPRINTK(2, "unknown ioctl: %d (%x)\n", cmd, cmd); + return(-EINVAL); + } +} + +/* ****************************************** */ +/* ***** standard FB API init functions ***** */ +/* ****************************************** */ + +int __init pm3fb_setup(char *options) +{ + long opsi = strlen(options); + + DTRACE; + + memcpy(g_options, options, + ((opsi + 1) > + PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1)); + g_options[PM3_OPTIONS_SIZE - 1] = 0; + + return (0); +} + +int __init pm3fb_init(void) +{ + DTRACE; + + DPRINTK(2, "This is pm3fb.c, CVS version: $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $"); + + pm3fb_real_setup(g_options); + + pm3fb_detect(); + + if (!fb_info[0].dev) { /* not even one board ??? */ + DPRINTK(1, "No PCI Permedia3 board detected\n"); + } + return (0); +} + +/* ************************* */ +/* **** Module support ***** */ +/* ************************* */ + +#ifdef MODULE +MODULE_AUTHOR("Romain Dolbeau"); +MODULE_DESCRIPTION("Permedia3 framebuffer device driver"); +static char *mode[PM3_MAX_BOARD]; +MODULE_PARM(mode,PM3_MAX_BOARD_MODULE_ARRAY_STRING); +MODULE_PARM_DESC(mode,"video mode"); +MODULE_PARM(disable,PM3_MAX_BOARD_MODULE_ARRAY_SHORT); +MODULE_PARM_DESC(disable,"disable board"); +static short off[PM3_MAX_BOARD]; +MODULE_PARM(off,PM3_MAX_BOARD_MODULE_ARRAY_SHORT); +MODULE_PARM_DESC(off,"disable board"); +static char *pciid[PM3_MAX_BOARD]; +MODULE_PARM(pciid,PM3_MAX_BOARD_MODULE_ARRAY_STRING); +MODULE_PARM_DESC(pciid,"board PCI Id"); +MODULE_PARM(noaccel,PM3_MAX_BOARD_MODULE_ARRAY_SHORT); +MODULE_PARM_DESC(noaccel,"disable accel"); +static char *font[PM3_MAX_BOARD]; +MODULE_PARM(font,PM3_MAX_BOARD_MODULE_ARRAY_STRING); +MODULE_PARM_DESC(font,"choose font"); +MODULE_PARM(depth,PM3_MAX_BOARD_MODULE_ARRAY_SHORT); +MODULE_PARM_DESC(depth,"boot-time depth"); +MODULE_PARM(printtimings, "h"); +MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)"); +MODULE_PARM(forcesize, PM3_MAX_BOARD_MODULE_ARRAY_SHORT); +MODULE_PARM_DESC(forcesize, "force specified memory size"); +/* +MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards") +MODULE_GENERIC_TABLE(gtype,name) +MODULE_DEVICE_TABLE(type,name) +*/ + +void pm3fb_build_options(void) +{ + int i; + char ts[128]; + + strcpy(g_options, "pm3fb"); + for (i = 0; i < PM3_MAX_BOARD ; i++) + { + if (mode[i]) + { + sprintf(ts, ",mode:%d:%s", i, mode[i]); + strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); + } + if (disable[i] || off[i]) + { + sprintf(ts, ",disable:%d:", i); + strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); + } + if (pciid[i]) + { + sprintf(ts, ",pciid:%d:%s", i, pciid[i]); + strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); + } + if (noaccel[i]) + { + sprintf(ts, ",noaccel:%d:", i); + strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); + } + if (font[i]) + { + sprintf(ts, ",font:%d:%s", i, font[i]); + strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); + } + if (depth[i]) + { + sprintf(ts, ",depth:%d:%d", i, depth[i]); + strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); + } + } + g_options[PM3_OPTIONS_SIZE - 1] = '\0'; + DPRINTK(1, "pm3fb use options: %s\n", g_options); +} + +int init_module(void) +{ + DTRACE; + + pm3fb_build_options(); + + pm3fb_init(); + + return (0); +} + +void cleanup_module(void) +{ + DTRACE; + { + unsigned long i; + struct pm3fb_info *l_fb_info; + for (i = 0; i < PM3_MAX_BOARD; i++) { + l_fb_info = &(fb_info[i]); + if ((l_fb_info->dev != NULL) + && (!(disable[l_fb_info->board_num]))) { + if (l_fb_info->vIOBase != + (unsigned char *) -1) { + pm3fb_unmapIO(l_fb_info); + release_mem_region(l_fb_info->p_fb, + l_fb_info-> + fb_size); + release_mem_region(l_fb_info-> + pIOBase, + PM3_REGS_SIZE); + } + unregister_framebuffer(&l_fb_info->gen. + info); + } + } + } + return; +} +#endif /* MODULE */ diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c new file mode 100644 index 000000000000..3e00ad7f2e31 --- /dev/null +++ b/drivers/video/pmag-aa-fb.c @@ -0,0 +1,514 @@ +/* + * linux/drivers/video/pmag-aa-fb.c + * Copyright 2002 Karsten Merker <merker@debian.org> + * + * PMAG-AA TurboChannel framebuffer card support ... derived from + * pmag-ba-fb.c, which is Copyright (C) 1999, 2000, 2001 by + * Michael Engel <engel@unix-ag.org>, Karsten Merker <merker@debian.org> + * and Harald Koerfgen <hkoerfg@web.de>, which itself is derived from + * "HP300 Topcat framebuffer support (derived from macfb of all things) + * Phil Blundell <philb@gnu.org> 1998" + * + * 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. + * + * 2002-09-28 Karsten Merker <merker@linuxtag.org> + * Version 0.01: First try to get a PMAG-AA running. + * + * 2003-02-24 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> + * Version 0.02: Major code cleanup. + * + * 2003-09-21 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> + * Hardware cursor support. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <linux/console.h> + +#include <asm/bootinfo.h> +#include <asm/dec/machtype.h> +#include <asm/dec/tc.h> + +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> + +#include "bt455.h" +#include "bt431.h" + +/* Version information */ +#define DRIVER_VERSION "0.02" +#define DRIVER_AUTHOR "Karsten Merker <merker@linuxtag.org>" +#define DRIVER_DESCRIPTION "PMAG-AA Framebuffer Driver" + +/* Prototypes */ +static int aafb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); + +/* + * Bt455 RAM DAC register base offset (rel. to TC slot base address). + */ +#define PMAG_AA_BT455_OFFSET 0x100000 + +/* + * Bt431 cursor generator offset (rel. to TC slot base address). + */ +#define PMAG_AA_BT431_OFFSET 0x180000 + +/* + * Begin of PMAG-AA framebuffer memory relative to TC slot address, + * resolution is 1280x1024x1 (8 bits deep, but only LSB is used). + */ +#define PMAG_AA_ONBOARD_FBMEM_OFFSET 0x200000 + +struct aafb_cursor { + struct timer_list timer; + int enable; + int on; + int vbl_cnt; + int blink_rate; + u16 x, y, width, height; +}; + +#define CURSOR_TIMER_FREQ (HZ / 50) +#define CURSOR_BLINK_RATE (20) +#define CURSOR_DRAW_DELAY (2) + +struct aafb_info { + struct fb_info info; + struct display disp; + struct aafb_cursor cursor; + struct bt455_regs *bt455; + struct bt431_regs *bt431; + unsigned long fb_start; + unsigned long fb_size; + unsigned long fb_line_length; +}; + +/* + * Max 3 TURBOchannel slots -> max 3 PMAG-AA. + */ +static struct aafb_info my_fb_info[3]; + +static struct aafb_par { +} current_par; + +static int currcon = -1; + +static void aafb_set_cursor(struct aafb_info *info, int on) +{ + struct aafb_cursor *c = &info->cursor; + + if (on) { + bt431_position_cursor(info->bt431, c->x, c->y); + bt431_enable_cursor(info->bt431); + } else + bt431_erase_cursor(info->bt431); +} + +static void aafbcon_cursor(struct display *disp, int mode, int x, int y) +{ + struct aafb_info *info = (struct aafb_info *)disp->fb_info; + struct aafb_cursor *c = &info->cursor; + + x *= fontwidth(disp); + y *= fontheight(disp); + + if (c->x == x && c->y == y && (mode == CM_ERASE) == !c->enable) + return; + + c->enable = 0; + if (c->on) + aafb_set_cursor(info, 0); + c->x = x - disp->var.xoffset; + c->y = y - disp->var.yoffset; + + switch (mode) { + case CM_ERASE: + c->on = 0; + break; + case CM_DRAW: + case CM_MOVE: + if (c->on) + aafb_set_cursor(info, c->on); + else + c->vbl_cnt = CURSOR_DRAW_DELAY; + c->enable = 1; + break; + } +} + +static int aafbcon_set_font(struct display *disp, int width, int height) +{ + struct aafb_info *info = (struct aafb_info *)disp->fb_info; + struct aafb_cursor *c = &info->cursor; + u8 fgc = ~attr_bgcol_ec(disp, disp->conp); + + if (width > 64 || height > 64 || width < 0 || height < 0) + return -EINVAL; + + c->height = height; + c->width = width; + + bt431_set_font(info->bt431, fgc, width, height); + + return 1; +} + +static void aafb_cursor_timer_handler(unsigned long data) +{ + struct aafb_info *info = (struct aafb_info *)data; + struct aafb_cursor *c = &info->cursor; + + if (!c->enable) + goto out; + + if (c->vbl_cnt && --c->vbl_cnt == 0) { + c->on ^= 1; + aafb_set_cursor(info, c->on); + c->vbl_cnt = c->blink_rate; + } + +out: + c->timer.expires = jiffies + CURSOR_TIMER_FREQ; + add_timer(&c->timer); +} + +static void __init aafb_cursor_init(struct aafb_info *info) +{ + struct aafb_cursor *c = &info->cursor; + + c->enable = 1; + c->on = 1; + c->x = c->y = 0; + c->width = c->height = 0; + c->vbl_cnt = CURSOR_DRAW_DELAY; + c->blink_rate = CURSOR_BLINK_RATE; + + init_timer(&c->timer); + c->timer.data = (unsigned long)info; + c->timer.function = aafb_cursor_timer_handler; + mod_timer(&c->timer, jiffies + CURSOR_TIMER_FREQ); +} + +static void __exit aafb_cursor_exit(struct aafb_info *info) +{ + struct aafb_cursor *c = &info->cursor; + + del_timer_sync(&c->timer); +} + +static struct display_switch aafb_switch8 = { + .setup = fbcon_cfb8_setup, + .bmove = fbcon_cfb8_bmove, + .clear = fbcon_cfb8_clear, + .putc = fbcon_cfb8_putc, + .putcs = fbcon_cfb8_putcs, + .revc = fbcon_cfb8_revc, + .cursor = aafbcon_cursor, + .set_font = aafbcon_set_font, + .clear_margins = fbcon_cfb8_clear_margins, + .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; + +static void aafb_get_par(struct aafb_par *par) +{ + *par = current_par; +} + +static int aafb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct aafb_info *ip = (struct aafb_info *)info; + + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "PMAG-AA"); + fix->smem_start = ip->fb_start; + fix->smem_len = ip->fb_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->ypanstep = 1; + fix->ywrapstep = 1; + fix->visual = FB_VISUAL_MONO10; + fix->line_length = 1280; + fix->accel = FB_ACCEL_NONE; + + return 0; +} + +static void aafb_set_disp(struct display *disp, int con, + struct aafb_info *info) +{ + struct fb_fix_screeninfo fix; + + disp->fb_info = &info->info; + aafb_set_var(&disp->var, con, &info->info); + if (disp->conp && disp->conp->vc_sw && disp->conp->vc_sw->con_cursor) + disp->conp->vc_sw->con_cursor(disp->conp, CM_ERASE); + disp->dispsw = &aafb_switch8; + disp->dispsw_data = 0; + + aafb_get_fix(&fix, con, &info->info); + disp->screen_base = (u8 *) fix.smem_start; + disp->visual = fix.visual; + disp->type = fix.type; + disp->type_aux = fix.type_aux; + disp->ypanstep = fix.ypanstep; + disp->ywrapstep = fix.ywrapstep; + disp->line_length = fix.line_length; + disp->next_line = 2048; + disp->can_soft_blank = 1; + disp->inverse = 0; + disp->scrollmode = SCROLL_YREDRAW; + + aafbcon_set_font(disp, fontwidth(disp), fontheight(disp)); +} + +static int aafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + static u16 color[2] = {0x0000, 0x000f}; + static struct fb_cmap aafb_cmap = {0, 2, color, color, color, NULL}; + + fb_copy_cmap(&aafb_cmap, cmap, kspc ? 0 : 2); + return 0; +} + +static int aafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + u16 color[2] = {0x0000, 0x000f}; + + if (cmap->start == 0 + && cmap->len == 2 + && memcmp(cmap->red, color, sizeof(color)) == 0 + && memcmp(cmap->green, color, sizeof(color)) == 0 + && memcmp(cmap->blue, color, sizeof(color)) == 0 + && cmap->transp == NULL) + return 0; + else + return -EINVAL; +} + +static int aafb_ioctl(struct inode *inode, struct file *file, u32 cmd, + unsigned long arg, int con, struct fb_info *info) +{ + /* TODO: Not yet implemented */ + return -ENOIOCTLCMD; +} + +static int aafb_switch(int con, struct fb_info *info) +{ + struct aafb_info *ip = (struct aafb_info *)info; + struct display *old = (currcon < 0) ? &ip->disp : (fb_display + currcon); + struct display *new = (con < 0) ? &ip->disp : (fb_display + con); + + if (old->conp && old->conp->vc_sw && old->conp->vc_sw->con_cursor) + old->conp->vc_sw->con_cursor(old->conp, CM_ERASE); + + /* Set the current console. */ + currcon = con; + aafb_set_disp(new, con, ip); + + return 0; +} + +static void aafb_encode_var(struct fb_var_screeninfo *var, + struct aafb_par *par) +{ + var->xres = 1280; + var->yres = 1024; + var->xres_virtual = 2048; + var->yres_virtual = 1024; + var->xoffset = 0; + var->yoffset = 0; + var->bits_per_pixel = 8; + var->grayscale = 1; + var->red.offset = 0; + var->red.length = 0; + var->red.msb_right = 0; + var->green.offset = 0; + var->green.length = 1; + var->green.msb_right = 0; + var->blue.offset = 0; + var->blue.length = 0; + var->blue.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->nonstd = 0; + var->activate &= ~FB_ACTIVATE_MASK & FB_ACTIVATE_NOW; + var->accel_flags = 0; + var->sync = FB_SYNC_ON_GREEN; + var->vmode &= ~FB_VMODE_MASK & FB_VMODE_NONINTERLACED; +} + +static int aafb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + if (con < 0) { + struct aafb_par par; + + memset(var, 0, sizeof(struct fb_var_screeninfo)); + aafb_get_par(&par); + aafb_encode_var(var, &par); + } else + *var = info->var; + + return 0; +} + +static int aafb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct aafb_par par; + + aafb_get_par(&par); + aafb_encode_var(var, &par); + info->var = *var; + + return 0; +} + +static int aafb_update_var(int con, struct fb_info *info) +{ + struct aafb_info *ip = (struct aafb_info *)info; + struct display *disp = (con < 0) ? &ip->disp : (fb_display + con); + + if (con == currcon) + aafbcon_cursor(disp, CM_ERASE, ip->cursor.x, ip->cursor.y); + + return 0; +} + +/* 0 unblanks, any other blanks. */ + +static void aafb_blank(int blank, struct fb_info *info) +{ + struct aafb_info *ip = (struct aafb_info *)info; + u8 val = blank ? 0x00 : 0x0f; + + bt455_write_cmap_entry(ip->bt455, 1, val, val, val); + aafbcon_cursor(&ip->disp, CM_ERASE, ip->cursor.x, ip->cursor.y); +} + +static struct fb_ops aafb_ops = { + .owner = THIS_MODULE, + .fb_get_fix = aafb_get_fix, + .fb_get_var = aafb_get_var, + .fb_set_var = aafb_set_var, + .fb_get_cmap = aafb_get_cmap, + .fb_set_cmap = aafb_set_cmap, + .fb_ioctl = aafb_ioctl +}; + +static int __init init_one(int slot) +{ + unsigned long base_addr = get_tc_base_addr(slot); + struct aafb_info *ip = &my_fb_info[slot]; + + memset(ip, 0, sizeof(struct aafb_info)); + + /* + * Framebuffer display memory base address and friends. + */ + ip->bt455 = (struct bt455_regs *) (base_addr + PMAG_AA_BT455_OFFSET); + ip->bt431 = (struct bt431_regs *) (base_addr + PMAG_AA_BT431_OFFSET); + ip->fb_start = base_addr + PMAG_AA_ONBOARD_FBMEM_OFFSET; + ip->fb_size = 2048 * 1024; /* fb_fix_screeninfo.smem_length + seems to be physical */ + ip->fb_line_length = 2048; + + /* + * Let there be consoles.. + */ + strcpy(ip->info.modename, "PMAG-AA"); + ip->info.node = -1; + ip->info.flags = FBINFO_FLAG_DEFAULT; + ip->info.fbops = &aafb_ops; + ip->info.disp = &ip->disp; + ip->info.changevar = NULL; + ip->info.switch_con = &aafb_switch; + ip->info.updatevar = &aafb_update_var; + ip->info.blank = &aafb_blank; + + aafb_set_disp(&ip->disp, currcon, ip); + + /* + * Configure the RAM DACs. + */ + bt455_erase_cursor(ip->bt455); + + /* Init colormap. */ + bt455_write_cmap_entry(ip->bt455, 0, 0x00, 0x00, 0x00); + bt455_write_cmap_entry(ip->bt455, 1, 0x0f, 0x0f, 0x0f); + + /* Init hardware cursor. */ + bt431_init_cursor(ip->bt431); + aafb_cursor_init(ip); + + /* Clear the screen. */ + memset ((void *)ip->fb_start, 0, ip->fb_size); + + if (register_framebuffer(&ip->info) < 0) + return -EINVAL; + + printk(KERN_INFO "fb%d: %s frame buffer in TC slot %d\n", + GET_FB_IDX(ip->info.node), ip->info.modename, slot); + + return 0; +} + +static int __exit exit_one(int slot) +{ + struct aafb_info *ip = &my_fb_info[slot]; + + if (unregister_framebuffer(&ip->info) < 0) + return -EINVAL; + + return 0; +} + +/* + * Initialise the framebuffer. + */ +int __init pmagaafb_init(void) +{ + int sid; + int found = 0; + + while ((sid = search_tc_card("PMAG-AA")) >= 0) { + found = 1; + claim_tc_card(sid); + init_one(sid); + } + + return found ? 0 : -ENXIO; +} + +static void __exit pmagaafb_exit(void) +{ + int sid; + + while ((sid = search_tc_card("PMAG-AA")) >= 0) { + exit_one(sid); + release_tc_card(sid); + } +} + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); +MODULE_LICENSE("GPL"); +#ifdef MODULE +module_init(pmagaafb_init); +module_exit(pmagaafb_exit); +#endif diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c new file mode 100644 index 000000000000..f8095588e99d --- /dev/null +++ b/drivers/video/pmag-ba-fb.c @@ -0,0 +1,182 @@ +/* + * linux/drivers/video/pmag-ba-fb.c + * + * PMAG-BA TurboChannel framebuffer card support ... derived from: + * "HP300 Topcat framebuffer support (derived from macfb of all things) + * Phil Blundell <philb@gnu.org> 1998", the original code can be + * found in the file hpfb.c in the same directory. + * + * Based on digital document: + * "PMAG-BA TURBOchannel Color Frame Buffer + * Functional Specification", Revision 1.2, August 27, 1990 + * + * DECstation related code Copyright (C) 1999, 2000, 2001 by + * Michael Engel <engel@unix-ag.org>, + * Karsten Merker <merker@linuxtag.org> and + * Harald Koerfgen. + * 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/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <asm/bootinfo.h> +#include <asm/dec/machtype.h> +#include <asm/dec/tc.h> +#include <video/pmag-ba-fb.h> + +struct pmag_ba_ramdac_regs { + unsigned char addr_low; + unsigned char pad0[3]; + unsigned char addr_hi; + unsigned char pad1[3]; + unsigned char data; + unsigned char pad2[3]; + unsigned char cmap; +}; + +/* + * Max 3 TURBOchannel slots -> max 3 PMAG-BA :) + */ +static struct fb_info pmagba_fb_info[3]; + +static struct fb_var_screeninfo pmagbafb_defined = { + .xres = 1024, + .yres = 864, + .xres_virtual = 1024, + .yres_virtual = 864, + .bits_per_pixel = 8, + .red.length = 8, + .green.length = 8, + .blue.length = 8, + .activate = FB_ACTIVATE_NOW, + .height = 274, + .width = 195, + .accel = FB_ACCEL_NONE, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo pmagbafb_fix = { + .id = "PMAG-BA", + .smem_len = (1024 * 864), + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .line_length = 1024, +}; + +/* + * Turn hardware cursor off + */ +void pmagbafb_erase_cursor(struct pmag_ba_ramdac_regs *bt459_regs) +{ + bt459_regs->addr_low = 0; + bt459_regs->addr_hi = 3; + bt459_regs->data = 0; +} + +/* + * Set the palette. + */ +static int pmagbafb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct pmag_ba_ramdac_regs *bt459_regs = (struct pmag_ba_ramdac_regs *) info->par; + + if (regno >= info->cmap.len) + return 1; + + red >>= 8; /* The cmap fields are 16 bits */ + green >>= 8; /* wide, but the harware colormap */ + blue >>= 8; /* registers are only 8 bits wide */ + + bt459_regs->addr_low = (__u8) regno; + bt459_regs->addr_hi = 0; + bt459_regs->cmap = red; + bt459_regs->cmap = green; + bt459_regs->cmap = blue; + return 0; +} + +static struct fb_ops pmagbafb_ops = { + .owner = THIS_MODULE, + .fb_get_fix = gen_get_fix, + .fb_get_var = gen_get_var, + .fb_setcolreg = pmagbafb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +int __init pmagbafb_init_one(int slot) +{ + unsigned long base_addr = get_tc_base_addr(slot); + struct fb_info *info = &pmagba_fb_info[slot]; + struct display *disp = &pmagba_disp[slot]; + + printk("PMAG-BA framebuffer in slot %d\n", slot); + /* + * Framebuffer display memory base address and friends + */ + pmagbafb_fix.smem_start = base_addr + PMAG_BA_ONBOARD_FBMEM_OFFSET; + info->par = (base_addr + PMAG_BA_BT459_OFFSET); + + /* + * Configure the Bt459 RAM DAC + */ + pmagbafb_erase_cursor((struct pmag_ba_ramdac_regs *) info->par); + + /* + * Let there be consoles.. + */ + info->fbops = &pmagbafb_ops; + info->var = pmagbafb_defined; + info->fix = pmagbafb_fix; + info->screen_base = pmagbafb_fix.smem_start; + info->flags = FBINFO_DEFAULT; + + fb_alloc_cmap(&fb_info.cmap, 256, 0); + + if (register_framebuffer(info) < 0) + return 1; + return 0; +} + +/* + * Initialise the framebuffer + */ + +int __init pmagbafb_init(void) +{ + int sid; + int found = 0; + + if (fb_get_options("pmagbafb", NULL)) + return -ENODEV; + + if (TURBOCHANNEL) { + while ((sid = search_tc_card("PMAG-BA")) >= 0) { + found = 1; + claim_tc_card(sid); + pmagbafb_init_one(sid); + } + return found ? 0 : -ENODEV; + } else { + return -ENODEV; + } +} + +module_init(pmagbafb_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c new file mode 100644 index 000000000000..d14eaee91cff --- /dev/null +++ b/drivers/video/pmagb-b-fb.c @@ -0,0 +1,182 @@ +/* + * linux/drivers/video/pmagb-b-fb.c + * + * PMAGB-B TurboChannel framebuffer card support ... derived from: + * "HP300 Topcat framebuffer support (derived from macfb of all things) + * Phil Blundell <philb@gnu.org> 1998", the original code can be + * found in the file hpfb.c in the same directory. + * + * DECstation related code Copyright (C) 1999, 2000, 2001 by + * Michael Engel <engel@unix-ag.org>, + * Karsten Merker <merker@linuxtag.org> and + * Harald Koerfgen. + * 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. + * + */ + +/* + * We currently only support the PMAGB-B in high resolution mode + * as I know of no way to detect low resolution mode set via jumper. + * KM, 2001/01/07 + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <asm/bootinfo.h> +#include <asm/dec/machtype.h> +#include <asm/dec/tc.h> +#include <video/pmagb-b-fb.h> + +struct pmagb_b_ramdac_regs { + unsigned char addr_low; + unsigned char pad0[3]; + unsigned char addr_hi; + unsigned char pad1[3]; + unsigned char data; + unsigned char pad2[3]; + unsigned char cmap; +}; + +/* + * Max 3 TURBOchannel slots -> max 3 PMAGB-B :) + */ +static struct fb_info pmagbb_fb_info[3]; + +static struct fb_var_screeninfo pmagbbfb_defined = { + .xres = 1280, + .yres = 1024, + .xres_virtual = 1280, + .yres_virtual = 1024, + .bits_per_pixel = 8, + .red.length = 8, + .green.length = 8, + .blue.length = 8, + .activate = FB_ACTIVATE_NOW, + .height = 274, + .width = 195, + .accel_flags = FB_ACCEL_NONE, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo pmagbafb_fix = { + .id = "PMAGB-BA", + .smem_len = (1280 * 1024), + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .line_length = 1280, +} + +/* + * Turn hardware cursor off + */ +void pmagbbfb_erase_cursor(struct pmagb_b_ramdac_regs *bt459_regs) +{ + bt459_regs->addr_low = 0; + bt459_regs->addr_hi = 3; + bt459_regs->data = 0; +} + +/* + * Set the palette. + */ +static int pmagbbfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct pmagb_b_ramdac_regs *bt459_regs = (struct pmagb_b_ramdac_regs *) info->par; + + if (regno >= info->cmap.len) + return 1; + + red >>= 8; /* The cmap fields are 16 bits */ + green >>= 8; /* wide, but the harware colormap */ + blue >>= 8; /* registers are only 8 bits wide */ + + bt459_regs->addr_low = (__u8) regno; + bt459_regs->addr_hi = 0; + bt459_regs->cmap = red; + bt459_regs->cmap = green; + bt459_regs->cmap = blue; + return 0; +} + +static struct fb_ops pmagbbfb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = pmagbbfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +int __init pmagbbfb_init_one(int slot) +{ + unsigned long base_addr = get_tc_base_addr(slot); + struct fb_info *info = &pmagbb_fb_info[slot]; + + printk("PMAGB-BA framebuffer in slot %d\n", slot); + /* + * Framebuffer display memory base address and friends + */ + pmagbbfb_fix.smem_start = base_addr + PMAGB_B_ONBOARD_FBMEM_OFFSET; + info->par = (base_addr + PMAGB_B_BT459_OFFSET); + + /* + * Configure the Bt459 RAM DAC + */ + pmagbbfb_erase_cursor((struct pmagb_b_ramdac_regs *) info->par); + + /* + * Let there be consoles.. + */ + info->fbops = &pmagbbfb_ops; + info->var = pmagbbfb_defined; + info->fix = pmagbbfb_fix; + info->screen_base = pmagbbfb_fix.smem_start; + info->flags = FBINFO_DEFAULT; + + fb_alloc_cmap(&fb_info.cmap, 256, 0); + + if (register_framebuffer(info) < 0) + return 1; + return 0; +} + +/* + * Initialise the framebuffer + */ + +int __init pmagbbfb_init(void) +{ + int sid; + int found = 0; + + if (fb_get_options("pmagbbfb", NULL)) + return -ENODEV; + + if (TURBOCHANNEL) { + while ((sid = search_tc_card("PMAGB-BA")) >= 0) { + found = 1; + claim_tc_card(sid); + pmagbbfb_init_one(sid); + } + return found ? 0 : -ENODEV; + } else { + return -ENODEV; + } +} + +module_init(pmagbbfb_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c new file mode 100644 index 000000000000..31c547fd383b --- /dev/null +++ b/drivers/video/pvr2fb.c @@ -0,0 +1,1125 @@ +/* drivers/video/pvr2fb.c + * + * Frame buffer and fbcon support for the NEC PowerVR2 found within the Sega + * Dreamcast. + * + * Copyright (c) 2001 M. R. Brown <mrbrown@0xd6.org> + * Copyright (c) 2001, 2002, 2003, 2004, 2005 Paul Mundt <lethal@linux-sh.org> + * + * This file is part of the LinuxDC project (linuxdc.sourceforge.net). + * + */ + +/* + * This driver is mostly based on the excellent amifb and vfb sources. It uses + * an odd scheme for converting hardware values to/from framebuffer values, + * here are some hacked-up formulas: + * + * The Dreamcast has screen offsets from each side of its four borders and + * the start offsets of the display window. I used these values to calculate + * 'pseudo' values (think of them as placeholders) for the fb video mode, so + * that when it came time to convert these values back into their hardware + * values, I could just add mode- specific offsets to get the correct mode + * settings: + * + * left_margin = diwstart_h - borderstart_h; + * right_margin = borderstop_h - (diwstart_h + xres); + * upper_margin = diwstart_v - borderstart_v; + * lower_margin = borderstop_v - (diwstart_h + yres); + * + * hsync_len = borderstart_h + (hsync_total - borderstop_h); + * vsync_len = borderstart_v + (vsync_total - borderstop_v); + * + * Then, when it's time to convert back to hardware settings, the only + * constants are the borderstart_* offsets, all other values are derived from + * the fb video mode: + * + * // PAL + * borderstart_h = 116; + * borderstart_v = 44; + * ... + * borderstop_h = borderstart_h + hsync_total - hsync_len; + * ... + * diwstart_v = borderstart_v - upper_margin; + * + * However, in the current implementation, the borderstart values haven't had + * the benefit of being fully researched, so some modes may be broken. + */ + +#undef DEBUG + +#include <linux/module.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/delay.h> +#include <linux/config.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> + +#ifdef CONFIG_SH_DREAMCAST +#include <asm/machvec.h> +#include <asm/mach/sysasic.h> +#endif + +#ifdef CONFIG_SH_DMA +#include <linux/pagemap.h> +#include <asm/mach/dma.h> +#include <asm/dma.h> +#endif + +#ifdef CONFIG_SH_STORE_QUEUES +#include <asm/uaccess.h> +#include <asm/cpu/sq.h> +#endif + +#ifndef PCI_DEVICE_ID_NEC_NEON250 +# define PCI_DEVICE_ID_NEC_NEON250 0x0067 +#endif + +/* 2D video registers */ +#define DISP_BASE par->mmio_base +#define DISP_BRDRCOLR (DISP_BASE + 0x40) +#define DISP_DIWMODE (DISP_BASE + 0x44) +#define DISP_DIWADDRL (DISP_BASE + 0x50) +#define DISP_DIWADDRS (DISP_BASE + 0x54) +#define DISP_DIWSIZE (DISP_BASE + 0x5c) +#define DISP_SYNCCONF (DISP_BASE + 0xd0) +#define DISP_BRDRHORZ (DISP_BASE + 0xd4) +#define DISP_SYNCSIZE (DISP_BASE + 0xd8) +#define DISP_BRDRVERT (DISP_BASE + 0xdc) +#define DISP_DIWCONF (DISP_BASE + 0xe8) +#define DISP_DIWHSTRT (DISP_BASE + 0xec) +#define DISP_DIWVSTRT (DISP_BASE + 0xf0) + +/* Pixel clocks, one for TV output, doubled for VGA output */ +#define TV_CLK 74239 +#define VGA_CLK 37119 + +/* This is for 60Hz - the VTOTAL is doubled for interlaced modes */ +#define PAL_HTOTAL 863 +#define PAL_VTOTAL 312 +#define NTSC_HTOTAL 857 +#define NTSC_VTOTAL 262 + +/* Supported cable types */ +enum { CT_VGA, CT_NONE, CT_RGB, CT_COMPOSITE }; + +/* Supported video output types */ +enum { VO_PAL, VO_NTSC, VO_VGA }; + +/* Supported palette types */ +enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 }; + +struct pvr2_params { unsigned int val; char *name; }; +static struct pvr2_params cables[] __initdata = { + { CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" }, +}; + +static struct pvr2_params outputs[] __initdata = { + { VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" }, +}; + +/* + * This describes the current video mode + */ + +static struct pvr2fb_par { + unsigned int hsync_total; /* Clocks/line */ + unsigned int vsync_total; /* Lines/field */ + unsigned int borderstart_h; + unsigned int borderstop_h; + unsigned int borderstart_v; + unsigned int borderstop_v; + unsigned int diwstart_h; /* Horizontal offset of the display field */ + unsigned int diwstart_v; /* Vertical offset of the display field, for + interlaced modes, this is the long field */ + unsigned long disp_start; /* Address of image within VRAM */ + unsigned char is_interlaced; /* Is the display interlaced? */ + unsigned char is_doublescan; /* Are scanlines output twice? (doublescan) */ + unsigned char is_lowres; /* Is horizontal pixel-doubling enabled? */ + + unsigned long mmio_base; /* MMIO base */ +} *currentpar; + +static struct fb_info *fb_info; + +static struct fb_fix_screeninfo pvr2_fix __initdata = { + .id = "NEC PowerVR2", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .ypanstep = 1, + .ywrapstep = 1, + .accel = FB_ACCEL_NONE, +}; + +static struct fb_var_screeninfo pvr2_var __initdata = { + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 480, + .bits_per_pixel =16, + .red = { 11, 5, 0 }, + .green = { 5, 6, 0 }, + .blue = { 0, 5, 0 }, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static int cable_type = CT_VGA; +static int video_output = VO_VGA; + +static int nopan = 0; +static int nowrap = 1; + +/* + * We do all updating, blanking, etc. during the vertical retrace period + */ +static unsigned int do_vmode_full = 0; /* Change the video mode */ +static unsigned int do_vmode_pan = 0; /* Update the video mode */ +static short do_blank = 0; /* (Un)Blank the screen */ + +static unsigned int is_blanked = 0; /* Is the screen blanked? */ + +#ifdef CONFIG_SH_STORE_QUEUES +static struct sq_mapping *pvr2fb_map; +#endif + +#ifdef CONFIG_SH_DMA +static unsigned int shdma = PVR2_CASCADE_CHAN; +static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS; +#endif + +/* Interface used by the world */ + +int pvr2fb_setup(char*); + +static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info); +static int pvr2fb_blank(int blank, struct fb_info *info); +static unsigned long get_line_length(int xres_virtual, int bpp); +static void set_color_bitfields(struct fb_var_screeninfo *var); +static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); +static int pvr2fb_set_par(struct fb_info *info); +static void pvr2_update_display(struct fb_info *info); +static void pvr2_init_display(struct fb_info *info); +static void pvr2_do_blank(void); +static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp); +static int pvr2_init_cable(void); +static int pvr2_get_param(const struct pvr2_params *p, const char *s, + int val, int size); +static ssize_t pvr2fb_write(struct file *file, const char *buf, + size_t count, loff_t *ppos); + +static struct fb_ops pvr2fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = pvr2fb_setcolreg, + .fb_blank = pvr2fb_blank, + .fb_check_var = pvr2fb_check_var, + .fb_set_par = pvr2fb_set_par, +#ifdef CONFIG_SH_DMA + .fb_write = pvr2fb_write, +#endif + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +static struct fb_videomode pvr2_modedb[] __initdata = { + /* + * Broadcast video modes (PAL and NTSC). I'm unfamiliar with + * PAL-M and PAL-N, but from what I've read both modes parallel PAL and + * NTSC, so it shouldn't be a problem (I hope). + */ + + { + /* 640x480 @ 60Hz interlaced (NTSC) */ + "ntsc_640x480i", 60, 640, 480, TV_CLK, 38, 33, 0, 18, 146, 26, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x240 @ 60Hz (NTSC) */ + /* XXX: Broken! Don't use... */ + "ntsc_640x240", 60, 640, 240, TV_CLK, 38, 33, 0, 0, 146, 22, + FB_SYNC_BROADCAST, FB_VMODE_YWRAP + }, { + /* 640x480 @ 60hz (VGA) */ + "vga_640x480", 60, 640, 480, VGA_CLK, 38, 33, 0, 18, 146, 26, + 0, FB_VMODE_YWRAP + }, +}; + +#define NUM_TOTAL_MODES ARRAY_SIZE(pvr2_modedb) + +#define DEFMODE_NTSC 0 +#define DEFMODE_PAL 0 +#define DEFMODE_VGA 2 + +static int defmode = DEFMODE_NTSC; +static char *mode_option __initdata = NULL; + +static inline void pvr2fb_set_pal_type(unsigned int type) +{ + struct pvr2fb_par *par = (struct pvr2fb_par *)fb_info->par; + + fb_writel(type, par->mmio_base + 0x108); +} + +static inline void pvr2fb_set_pal_entry(struct pvr2fb_par *par, + unsigned int regno, + unsigned int val) +{ + fb_writel(val, par->mmio_base + 0x1000 + (4 * regno)); +} + +static int pvr2fb_blank(int blank, struct fb_info *info) +{ + do_blank = blank ? blank : -1; + return 0; +} + +static inline unsigned long get_line_length(int xres_virtual, int bpp) +{ + return (unsigned long)((((xres_virtual*bpp)+31)&~31) >> 3); +} + +static void set_color_bitfields(struct fb_var_screeninfo *var) +{ + switch (var->bits_per_pixel) { + case 16: /* RGB 565 */ + pvr2fb_set_pal_type(PAL_RGB565); + 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 */ + var->red.offset = 16; var->red.length = 8; + var->green.offset = 8; var->green.length = 8; + var->blue.offset = 0; var->blue.length = 8; + var->transp.offset = 0; var->transp.length = 0; + break; + case 32: /* ARGB 8888 */ + pvr2fb_set_pal_type(PAL_ARGB8888); + var->red.offset = 16; var->red.length = 8; + var->green.offset = 8; var->green.length = 8; + var->blue.offset = 0; var->blue.length = 8; + var->transp.offset = 24; var->transp.length = 8; + break; + } +} + +static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info) +{ + struct pvr2fb_par *par = (struct pvr2fb_par *)info->par; + unsigned int tmp; + + if (regno > info->cmap.len) + return 1; + + /* + * We only support the hardware palette for 16 and 32bpp. It's also + * expected that the palette format has been set by the time we get + * here, so we don't waste time setting it again. + */ + switch (info->var.bits_per_pixel) { + case 16: /* RGB 565 */ + tmp = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + + pvr2fb_set_pal_entry(par, regno, tmp); + ((u16*)(info->pseudo_palette))[regno] = tmp; + break; + case 24: /* RGB 888 */ + red >>= 8; green >>= 8; blue >>= 8; + ((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue; + break; + case 32: /* ARGB 8888 */ + red >>= 8; green >>= 8; blue >>= 8; + tmp = (transp << 24) | (red << 16) | (green << 8) | blue; + + pvr2fb_set_pal_entry(par, regno, tmp); + ((u32*)(info->pseudo_palette))[regno] = tmp; + break; + default: + pr_debug("Invalid bit depth %d?!?\n", info->var.bits_per_pixel); + return 1; + } + + return 0; +} + +static int pvr2fb_set_par(struct fb_info *info) +{ + struct pvr2fb_par *par = (struct pvr2fb_par *)info->par; + struct fb_var_screeninfo *var = &info->var; + unsigned long line_length; + unsigned int vtotal; + + /* + * XXX: It's possible that a user could use a VGA box, change the cable + * type in hardware (i.e. switch from VGA<->composite), then change + * modes (i.e. switching to another VT). If that happens we should + * automagically change the output format to cope, but currently I + * don't have a VGA box to make sure this works properly. + */ + cable_type = pvr2_init_cable(); + if (cable_type == CT_VGA && video_output != VO_VGA) + video_output = VO_VGA; + + var->vmode &= FB_VMODE_MASK; + if (var->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA) + par->is_interlaced = 1; + /* + * XXX: Need to be more creative with this (i.e. allow doublecan for + * PAL/NTSC output). + */ + if (var->vmode & FB_VMODE_DOUBLE && video_output == VO_VGA) + par->is_doublescan = 1; + + par->hsync_total = var->left_margin + var->xres + var->right_margin + + var->hsync_len; + par->vsync_total = var->upper_margin + var->yres + var->lower_margin + + var->vsync_len; + + if (var->sync & FB_SYNC_BROADCAST) { + vtotal = par->vsync_total; + if (par->is_interlaced) + vtotal /= 2; + if (vtotal > (PAL_VTOTAL + NTSC_VTOTAL)/2) { + /* XXX: Check for start values here... */ + /* XXX: Check hardware for PAL-compatibility */ + par->borderstart_h = 116; + par->borderstart_v = 44; + } else { + /* NTSC video output */ + par->borderstart_h = 126; + par->borderstart_v = 18; + } + } else { + /* VGA mode */ + /* XXX: What else needs to be checked? */ + /* + * XXX: We have a little freedom in VGA modes, what ranges + * should be here (i.e. hsync/vsync totals, etc.)? + */ + par->borderstart_h = 126; + par->borderstart_v = 40; + } + + /* Calculate the remainding offsets */ + par->diwstart_h = par->borderstart_h + var->left_margin; + par->diwstart_v = par->borderstart_v + var->upper_margin; + par->borderstop_h = par->diwstart_h + var->xres + + var->right_margin; + par->borderstop_v = par->diwstart_v + var->yres + + var->lower_margin; + + if (!par->is_interlaced) + par->borderstop_v /= 2; + if (info->var.xres < 640) + par->is_lowres = 1; + + line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); + par->disp_start = info->fix.smem_start + (line_length * var->yoffset) * line_length; + info->fix.line_length = line_length; + return 0; +} + +static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct pvr2fb_par *par = (struct pvr2fb_par *)info->par; + unsigned int vtotal, hsync_total; + unsigned long line_length; + + if (var->pixclock != TV_CLK && var->pixclock != VGA_CLK) { + pr_debug("Invalid pixclock value %d\n", var->pixclock); + return -EINVAL; + } + + if (var->xres < 320) + var->xres = 320; + if (var->yres < 240) + var->yres = 240; + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + if (var->bits_per_pixel <= 16) + var->bits_per_pixel = 16; + else if (var->bits_per_pixel <= 24) + var->bits_per_pixel = 24; + else if (var->bits_per_pixel <= 32) + var->bits_per_pixel = 32; + + set_color_bitfields(var); + + if (var->vmode & FB_VMODE_YWRAP) { + if (var->xoffset || var->yoffset < 0 || + var->yoffset >= var->yres_virtual) { + var->xoffset = var->yoffset = 0; + } else { + if (var->xoffset > var->xres_virtual - var->xres || + var->yoffset > var->yres_virtual - var->yres || + var->xoffset < 0 || var->yoffset < 0) + var->xoffset = var->yoffset = 0; + } + } else { + var->xoffset = var->yoffset = 0; + } + + /* + * XXX: Need to be more creative with this (i.e. allow doublecan for + * PAL/NTSC output). + */ + if (var->yres < 480 && video_output == VO_VGA) + var->vmode |= FB_VMODE_DOUBLE; + + if (video_output != VO_VGA) { + var->sync |= FB_SYNC_BROADCAST; + var->vmode |= FB_VMODE_INTERLACED; + } else { + var->sync &= ~FB_SYNC_BROADCAST; + var->vmode &= ~FB_VMODE_INTERLACED; + var->vmode |= pvr2_var.vmode; + } + + if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_TEST) { + var->right_margin = par->borderstop_h - + (par->diwstart_h + var->xres); + var->left_margin = par->diwstart_h - par->borderstart_h; + var->hsync_len = par->borderstart_h + + (par->hsync_total - par->borderstop_h); + + var->upper_margin = par->diwstart_v - par->borderstart_v; + var->lower_margin = par->borderstop_v - + (par->diwstart_v + var->yres); + var->vsync_len = par->borderstop_v + + (par->vsync_total - par->borderstop_v); + } + + hsync_total = var->left_margin + var->xres + var->right_margin + + var->hsync_len; + vtotal = var->upper_margin + var->yres + var->lower_margin + + var->vsync_len; + + if (var->sync & FB_SYNC_BROADCAST) { + if (var->vmode & FB_VMODE_INTERLACED) + vtotal /= 2; + if (vtotal > (PAL_VTOTAL + NTSC_VTOTAL)/2) { + /* PAL video output */ + /* XXX: Should be using a range here ... ? */ + if (hsync_total != PAL_HTOTAL) { + pr_debug("invalid hsync total for PAL\n"); + return -EINVAL; + } + } else { + /* NTSC video output */ + if (hsync_total != NTSC_HTOTAL) { + pr_debug("invalid hsync total for NTSC\n"); + return -EINVAL; + } + } + } + + /* Check memory sizes */ + line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); + if (line_length * var->yres_virtual > info->fix.smem_len) + return -ENOMEM; + + return 0; +} + +static void pvr2_update_display(struct fb_info *info) +{ + struct pvr2fb_par *par = (struct pvr2fb_par *) info->par; + struct fb_var_screeninfo *var = &info->var; + + /* Update the start address of the display image */ + fb_writel(par->disp_start, DISP_DIWADDRL); + fb_writel(par->disp_start + + get_line_length(var->xoffset+var->xres, var->bits_per_pixel), + DISP_DIWADDRS); +} + +/* + * Initialize the video mode. Currently, the 16bpp and 24bpp modes aren't + * very stable. It's probably due to the fact that a lot of the 2D video + * registers are still undocumented. + */ + +static void pvr2_init_display(struct fb_info *info) +{ + struct pvr2fb_par *par = (struct pvr2fb_par *) info->par; + struct fb_var_screeninfo *var = &info->var; + unsigned int diw_height, diw_width, diw_modulo = 1; + unsigned int bytesperpixel = var->bits_per_pixel >> 3; + + /* hsync and vsync totals */ + fb_writel((par->vsync_total << 16) | par->hsync_total, DISP_SYNCSIZE); + + /* column height, modulo, row width */ + /* since we're "panning" within vram, we need to offset things based + * on the offset from the virtual x start to our real gfx. */ + if (video_output != VO_VGA && par->is_interlaced) + diw_modulo += info->fix.line_length / 4; + diw_height = (par->is_interlaced ? var->yres / 2 : var->yres); + diw_width = get_line_length(var->xres, var->bits_per_pixel) / 4; + fb_writel((diw_modulo << 20) | (--diw_height << 10) | --diw_width, + DISP_DIWSIZE); + + /* display address, long and short fields */ + fb_writel(par->disp_start, DISP_DIWADDRL); + fb_writel(par->disp_start + + get_line_length(var->xoffset+var->xres, var->bits_per_pixel), + DISP_DIWADDRS); + + /* border horizontal, border vertical, border color */ + fb_writel((par->borderstart_h << 16) | par->borderstop_h, DISP_BRDRHORZ); + fb_writel((par->borderstart_v << 16) | par->borderstop_v, DISP_BRDRVERT); + fb_writel(0, DISP_BRDRCOLR); + + /* display window start position */ + fb_writel(par->diwstart_h, DISP_DIWHSTRT); + fb_writel((par->diwstart_v << 16) | par->diwstart_v, DISP_DIWVSTRT); + + /* misc. settings */ + fb_writel((0x16 << 16) | par->is_lowres, DISP_DIWCONF); + + /* clock doubler (for VGA), scan doubler, display enable */ + fb_writel(((video_output == VO_VGA) << 23) | + (par->is_doublescan << 1) | 1, DISP_DIWMODE); + + /* bits per pixel */ + fb_writel(fb_readl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE); + + /* video enable, color sync, interlace, + * hsync and vsync polarity (currently unused) */ + fb_writel(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF); +} + +/* Simulate blanking by making the border cover the entire screen */ + +#define BLANK_BIT (1<<3) + +static void pvr2_do_blank(void) +{ + struct pvr2fb_par *par = currentpar; + unsigned long diwconf; + + diwconf = fb_readl(DISP_DIWCONF); + if (do_blank > 0) + fb_writel(diwconf | BLANK_BIT, DISP_DIWCONF); + else + fb_writel(diwconf & ~BLANK_BIT, DISP_DIWCONF); + + is_blanked = do_blank > 0 ? do_blank : 0; +} + +static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp) +{ + struct fb_info *info = dev_id; + + if (do_vmode_pan || do_vmode_full) + pvr2_update_display(info); + if (do_vmode_full) + pvr2_init_display(info); + if (do_vmode_pan) + do_vmode_pan = 0; + if (do_vmode_full) + do_vmode_full = 0; + if (do_blank) { + pvr2_do_blank(); + do_blank = 0; + } + return IRQ_HANDLED; +} + +/* + * Determine the cable type and initialize the cable output format. Don't do + * anything if the cable type has been overidden (via "cable:XX"). + */ + +#define PCTRA 0xff80002c +#define PDTRA 0xff800030 +#define VOUTC 0xa0702c00 + +static int pvr2_init_cable(void) +{ + if (cable_type < 0) { + fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000, + PCTRA); + cable_type = (fb_readw(PDTRA) >> 8) & 3; + } + + /* Now select the output format (either composite or other) */ + /* XXX: Save the previous val first, as this reg is also AICA + related */ + if (cable_type == CT_COMPOSITE) + fb_writel(3 << 8, VOUTC); + else + fb_writel(0, VOUTC); + + return cable_type; +} + +#ifdef CONFIG_SH_DMA +static ssize_t pvr2fb_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + unsigned long dst, start, end, len; + unsigned int nr_pages; + struct page **pages; + int ret, i; + + nr_pages = (count + PAGE_SIZE - 1) >> PAGE_SHIFT; + + pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); + if (!pages) + return -ENOMEM; + + down_read(¤t->mm->mmap_sem); + ret = get_user_pages(current, current->mm, (unsigned long)buf, + nr_pages, WRITE, 0, pages, NULL); + up_read(¤t->mm->mmap_sem); + + if (ret < nr_pages) { + nr_pages = ret; + ret = -EINVAL; + goto out_unmap; + } + + dma_configure_channel(shdma, 0x12c1); + + dst = (unsigned long)fb_info->screen_base + *ppos; + start = (unsigned long)page_address(pages[0]); + end = (unsigned long)page_address(pages[nr_pages]); + len = nr_pages << PAGE_SHIFT; + + /* Half-assed contig check */ + if (start + len == end) { + /* As we do this in one shot, it's either all or nothing.. */ + if ((*ppos + len) > fb_info->fix.smem_len) { + ret = -ENOSPC; + goto out_unmap; + } + + dma_write(shdma, start, 0, len); + dma_write(pvr2dma, 0, dst, len); + dma_wait_for_completion(pvr2dma); + + goto out; + } + + /* Not contiguous, writeout per-page instead.. */ + for (i = 0; i < nr_pages; i++, dst += PAGE_SIZE) { + if ((*ppos + (i << PAGE_SHIFT)) > fb_info->fix.smem_len) { + ret = -ENOSPC; + goto out_unmap; + } + + dma_write_page(shdma, (unsigned long)page_address(pages[i]), 0); + dma_write_page(pvr2dma, 0, dst); + dma_wait_for_completion(pvr2dma); + } + +out: + *ppos += count; + ret = count; + +out_unmap: + for (i = 0; i < nr_pages; i++) + page_cache_release(pages[i]); + + kfree(pages); + + return ret; +} +#endif /* CONFIG_SH_DMA */ + +/** + * pvr2fb_common_init + * + * Common init code for the PVR2 chips. + * + * This mostly takes care of the common aspects of the fb setup and + * registration. It's expected that the board-specific init code has + * already setup pvr2_fix with something meaningful at this point. + * + * Device info reporting is also done here, as well as picking a sane + * default from the modedb. For board-specific modelines, simply define + * a per-board modedb. + * + * Also worth noting is that the cable and video output types are likely + * always going to be VGA for the PCI-based PVR2 boards, but we leave this + * in for flexibility anyways. Who knows, maybe someone has tv-out on a + * PCI-based version of these things ;-) + */ +static int __init pvr2fb_common_init(void) +{ + struct pvr2fb_par *par = currentpar; + unsigned long modememused, rev; + + fb_info->screen_base = ioremap_nocache(pvr2_fix.smem_start, + pvr2_fix.smem_len); + + if (!fb_info->screen_base) { + printk(KERN_ERR "pvr2fb: Failed to remap smem space\n"); + goto out_err; + } + + par->mmio_base = (unsigned long)ioremap_nocache(pvr2_fix.mmio_start, + pvr2_fix.mmio_len); + if (!par->mmio_base) { + printk(KERN_ERR "pvr2fb: Failed to remap mmio space\n"); + goto out_err; + } + + fb_memset((unsigned long)fb_info->screen_base, 0, pvr2_fix.smem_len); + + pvr2_fix.ypanstep = nopan ? 0 : 1; + pvr2_fix.ywrapstep = nowrap ? 0 : 1; + + fb_info->fbops = &pvr2fb_ops; + fb_info->fix = pvr2_fix; + fb_info->par = currentpar; + fb_info->pseudo_palette = (void *)(fb_info->par + 1); + fb_info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + + if (video_output == VO_VGA) + defmode = DEFMODE_VGA; + + if (!mode_option) + mode_option = "640x480@60"; + + if (!fb_find_mode(&fb_info->var, fb_info, mode_option, pvr2_modedb, + NUM_TOTAL_MODES, &pvr2_modedb[defmode], 16)) + fb_info->var = pvr2_var; + + fb_alloc_cmap(&fb_info->cmap, 256, 0); + + if (register_framebuffer(fb_info) < 0) + goto out_err; + + modememused = get_line_length(fb_info->var.xres_virtual, + fb_info->var.bits_per_pixel); + modememused *= fb_info->var.yres_virtual; + + rev = fb_readl(par->mmio_base + 0x04); + + printk("fb%d: %s (rev %ld.%ld) frame buffer device, using %ldk/%ldk of video memory\n", + fb_info->node, fb_info->fix.id, (rev >> 4) & 0x0f, rev & 0x0f, + modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10)); + printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", + fb_info->node, fb_info->var.xres, fb_info->var.yres, + fb_info->var.bits_per_pixel, + get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel), + (char *)pvr2_get_param(cables, NULL, cable_type, 3), + (char *)pvr2_get_param(outputs, NULL, video_output, 3)); + +#ifdef CONFIG_SH_STORE_QUEUES + printk(KERN_NOTICE "fb%d: registering with SQ API\n", fb_info->node); + + pvr2fb_map = sq_remap(fb_info->fix.smem_start, fb_info->fix.smem_len, + fb_info->fix.id); + + printk(KERN_NOTICE "fb%d: Mapped video memory to SQ addr 0x%lx\n", + fb_info->node, pvr2fb_map->sq_addr); +#endif + + return 0; + +out_err: + if (fb_info->screen_base) + iounmap(fb_info->screen_base); + if (par->mmio_base) + iounmap((void *)par->mmio_base); + + return -ENXIO; +} + +#ifdef CONFIG_SH_DREAMCAST +static int __init pvr2fb_dc_init(void) +{ + if (!mach_is_dreamcast()) + return -ENXIO; + + /* Make a guess at the monitor based on the attached cable */ + if (pvr2_init_cable() == CT_VGA) { + fb_info->monspecs.hfmin = 30000; + fb_info->monspecs.hfmax = 70000; + fb_info->monspecs.vfmin = 60; + fb_info->monspecs.vfmax = 60; + } else { + /* Not VGA, using a TV (taken from acornfb) */ + fb_info->monspecs.hfmin = 15469; + fb_info->monspecs.hfmax = 15781; + fb_info->monspecs.vfmin = 49; + fb_info->monspecs.vfmax = 51; + } + + /* + * XXX: This needs to pull default video output via BIOS or other means + */ + if (video_output < 0) { + if (cable_type == CT_VGA) { + video_output = VO_VGA; + } else { + video_output = VO_NTSC; + } + } + + /* + * Nothing exciting about the DC PVR2 .. only a measly 8MiB. + */ + pvr2_fix.smem_start = 0xa5000000; /* RAM starts here */ + pvr2_fix.smem_len = 8 << 20; + + pvr2_fix.mmio_start = 0xa05f8000; /* registers start here */ + pvr2_fix.mmio_len = 0x2000; + + if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0, + "pvr2 VBL handler", fb_info)) { + return -EBUSY; + } + +#ifdef CONFIG_SH_DMA + if (request_dma(pvr2dma, "pvr2") != 0) { + free_irq(HW_EVENT_VSYNC, 0); + return -EBUSY; + } +#endif + + return pvr2fb_common_init(); +} + +static void pvr2fb_dc_exit(void) +{ + free_irq(HW_EVENT_VSYNC, 0); +#ifdef CONFIG_SH_DMA + free_dma(pvr2dma); +#endif +} +#endif /* CONFIG_SH_DREAMCAST */ + +#ifdef CONFIG_PCI +static int __devinit pvr2fb_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int ret; + + ret = pci_enable_device(pdev); + if (ret) { + printk(KERN_ERR "pvr2fb: PCI enable failed\n"); + return ret; + } + + ret = pci_request_regions(pdev, "pvr2fb"); + if (ret) { + printk(KERN_ERR "pvr2fb: PCI request regions failed\n"); + return ret; + } + + /* + * Slightly more exciting than the DC PVR2 .. 16MiB! + */ + pvr2_fix.smem_start = pci_resource_start(pdev, 0); + pvr2_fix.smem_len = pci_resource_len(pdev, 0); + + pvr2_fix.mmio_start = pci_resource_start(pdev, 1); + pvr2_fix.mmio_len = pci_resource_len(pdev, 1); + + fb_info->device = &pdev->dev; + + return pvr2fb_common_init(); +} + +static void __devexit pvr2fb_pci_remove(struct pci_dev *pdev) +{ + pci_release_regions(pdev); +} + +static struct pci_device_id pvr2fb_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NEON250, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, pvr2fb_pci_tbl); + +static struct pci_driver pvr2fb_pci_driver = { + .name = "pvr2fb", + .id_table = pvr2fb_pci_tbl, + .probe = pvr2fb_pci_probe, + .remove = __devexit_p(pvr2fb_pci_remove), +}; + +static int __init pvr2fb_pci_init(void) +{ + return pci_register_driver(&pvr2fb_pci_driver); +} + +static void pvr2fb_pci_exit(void) +{ + pci_unregister_driver(&pvr2fb_pci_driver); +} +#endif /* CONFIG_PCI */ + +static int __init pvr2_get_param(const struct pvr2_params *p, const char *s, + int val, int size) +{ + int i; + + for (i = 0 ; i < size ; i++ ) { + if (s != NULL) { + if (!strnicmp(p[i].name, s, strlen(s))) + return p[i].val; + } else { + if (p[i].val == val) + return (int)p[i].name; + } + } + return -1; +} + +/* + * Parse command arguments. Supported arguments are: + * inverse Use inverse color maps + * cable:composite|rgb|vga Override the video cable type + * output:NTSC|PAL|VGA Override the video output format + * + * <xres>x<yres>[-<bpp>][@<refresh>] or, + * <name>[-<bpp>][@<refresh>] Startup using this video mode + */ + +#ifndef MODULE +int __init pvr2fb_setup(char *options) +{ + char *this_opt; + char cable_arg[80]; + char output_arg[80]; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ","))) { + if (!*this_opt) + continue; + if (!strcmp(this_opt, "inverse")) { + fb_invert_cmaps(); + } else if (!strncmp(this_opt, "cable:", 6)) { + strcpy(cable_arg, this_opt + 6); + } else if (!strncmp(this_opt, "output:", 7)) { + strcpy(output_arg, this_opt + 7); + } else if (!strncmp(this_opt, "nopan", 5)) { + nopan = 1; + } else if (!strncmp(this_opt, "nowrap", 6)) { + nowrap = 1; + } else { + mode_option = this_opt; + } + } + + if (*cable_arg) + cable_type = pvr2_get_param(cables, cable_arg, 0, 3); + if (*output_arg) + video_output = pvr2_get_param(outputs, output_arg, 0, 3); + + return 0; +} +#endif + +static struct pvr2_board { + int (*init)(void); + void (*exit)(void); + char name[16]; +} board_list[] = { +#ifdef CONFIG_SH_DREAMCAST + { pvr2fb_dc_init, pvr2fb_dc_exit, "Sega DC PVR2" }, +#endif +#ifdef CONFIG_PCI + { pvr2fb_pci_init, pvr2fb_pci_exit, "PCI PVR2" }, +#endif + { 0, }, +}; + +int __init pvr2fb_init(void) +{ + int i, ret = -ENODEV; + int size; + +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("pvr2fb", &option)) + return -ENODEV; + pvr2fb_setup(option); +#endif + size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32); + + fb_info = kmalloc(size, GFP_KERNEL); + if (!fb_info) { + printk(KERN_ERR "Failed to allocate memory for fb_info\n"); + return -ENOMEM; + } + + memset(fb_info, 0, size); + + currentpar = (struct pvr2fb_par *)(fb_info + 1); + + for (i = 0; i < ARRAY_SIZE(board_list); i++) { + struct pvr2_board *pvr_board = board_list + i; + + if (!pvr_board->init) + continue; + + ret = pvr_board->init(); + + if (ret != 0) { + printk(KERN_ERR "pvr2fb: Failed init of %s device\n", + pvr_board->name); + kfree(fb_info); + break; + } + } + + return ret; +} + +static void __exit pvr2fb_exit(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(board_list); i++) { + struct pvr2_board *pvr_board = board_list + i; + + if (pvr_board->exit) + pvr_board->exit(); + } + +#ifdef CONFIG_SH_STORE_QUEUES + sq_unmap(pvr2fb_map); +#endif + + unregister_framebuffer(fb_info); + kfree(fb_info); +} + +module_init(pvr2fb_init); +module_exit(pvr2fb_exit); + +MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); +MODULE_DESCRIPTION("Framebuffer driver for NEC PowerVR 2 based graphics boards"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c new file mode 100644 index 000000000000..483ad9bab539 --- /dev/null +++ b/drivers/video/pxafb.c @@ -0,0 +1,1390 @@ +/* + * linux/drivers/video/pxafb.c + * + * Copyright (C) 1999 Eric A. Thomas. + * Copyright (C) 2004 Jean-Frederic Clere. + * Copyright (C) 2004 Ian Campbell. + * Copyright (C) 2004 Jeff Lackey. + * Based on sa1100fb.c Copyright (C) 1999 Eric A. Thomas + * which in turn is + * Based on acornfb.c Copyright (C) Russell King. + * + * 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 PXA250/210 LCD Controller Frame Buffer Driver + * + * Please direct your questions and comments on this driver to the following + * email address: + * + * linux-arm-kernel@lists.arm.linux.org.uk + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/cpufreq.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/bitfield.h> +#include <asm/arch/pxafb.h> + +/* + * Complain if VAR is out of range. + */ +#define DEBUG_VAR 1 + +#include "pxafb.h" + +/* Bits which should not be set in machine configuration structures */ +#define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM|LCCR0_BM|LCCR0_QDM|LCCR0_DIS|LCCR0_EFM|LCCR0_IUM|LCCR0_SFM|LCCR0_LDM|LCCR0_ENB) +#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP) + +static void (*pxafb_backlight_power)(int); +static void (*pxafb_lcd_power)(int); + +static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *); +static void set_ctrlr_state(struct pxafb_info *fbi, u_int state); + +#ifdef CONFIG_FB_PXA_PARAMETERS +#define PXAFB_OPTIONS_SIZE 256 +static char g_options[PXAFB_OPTIONS_SIZE] __initdata = ""; +#endif + +static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state) +{ + unsigned long flags; + + local_irq_save(flags); + /* + * We need to handle two requests being made at the same time. + * There are two important cases: + * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE) + * We must perform the unblanking, which will do our REENABLE for us. + * 2. When we are blanking, but immediately unblank before we have + * blanked. We do the "REENABLE" thing here as well, just to be sure. + */ + if (fbi->task_state == C_ENABLE && state == C_REENABLE) + state = (u_int) -1; + if (fbi->task_state == C_DISABLE && state == C_ENABLE) + state = C_REENABLE; + + if (state != (u_int)-1) { + fbi->task_state = state; + schedule_work(&fbi->task); + } + local_irq_restore(flags); +} + +static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int +pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, + u_int trans, struct fb_info *info) +{ + struct pxafb_info *fbi = (struct pxafb_info *)info; + u_int val, ret = 1; + + if (regno < fbi->palette_size) { + if (fbi->fb.var.grayscale) { + val = ((blue >> 8) & 0x00ff); + } else { + val = ((red >> 0) & 0xf800); + val |= ((green >> 5) & 0x07e0); + val |= ((blue >> 11) & 0x001f); + } + fbi->palette_cpu[regno] = val; + ret = 0; + } + return ret; +} + +static int +pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int trans, struct fb_info *info) +{ + struct pxafb_info *fbi = (struct pxafb_info *)info; + unsigned int val; + int ret = 1; + + /* + * If inverse mode was selected, invert all the colours + * rather than the register number. The register number + * is what you poke into the framebuffer to produce the + * colour you requested. + */ + if (fbi->cmap_inverse) { + red = 0xffff - red; + green = 0xffff - green; + blue = 0xffff - blue; + } + + /* + * If greyscale is true, then we convert the RGB value + * to greyscale no matter what visual we are using. + */ + if (fbi->fb.var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + + switch (fbi->fb.fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* + * 16-bit True Colour. We encode the RGB value + * according to the RGB bitfield information. + */ + if (regno < 16) { + u32 *pal = fbi->fb.pseudo_palette; + + val = chan_to_field(red, &fbi->fb.var.red); + val |= chan_to_field(green, &fbi->fb.var.green); + val |= chan_to_field(blue, &fbi->fb.var.blue); + + pal[regno] = val; + ret = 0; + } + break; + + case FB_VISUAL_STATIC_PSEUDOCOLOR: + case FB_VISUAL_PSEUDOCOLOR: + ret = pxafb_setpalettereg(regno, red, green, blue, trans, info); + break; + } + + return ret; +} + +/* + * pxafb_bpp_to_lccr3(): + * Convert a bits per pixel value to the correct bit pattern for LCCR3 + */ +static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var) +{ + int ret = 0; + switch (var->bits_per_pixel) { + case 1: ret = LCCR3_1BPP; break; + case 2: ret = LCCR3_2BPP; break; + case 4: ret = LCCR3_4BPP; break; + case 8: ret = LCCR3_8BPP; break; + case 16: ret = LCCR3_16BPP; break; + } + return ret; +} + +#ifdef CONFIG_CPU_FREQ +/* + * pxafb_display_dma_period() + * Calculate the minimum period (in picoseconds) between two DMA + * requests for the LCD controller. If we hit this, it means we're + * doing nothing but LCD DMA. + */ +static unsigned int pxafb_display_dma_period(struct fb_var_screeninfo *var) +{ + /* + * Period = pixclock * bits_per_byte * bytes_per_transfer + * / memory_bits_per_pixel; + */ + return var->pixclock * 8 * 16 / var->bits_per_pixel; +} + +extern unsigned int get_clk_frequency_khz(int info); +#endif + +/* + * pxafb_check_var(): + * Get the video params out of 'var'. If a value doesn't fit, round it up, + * if it's too big, return -EINVAL. + * + * Round up in the following order: bits_per_pixel, xres, + * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, + * bitfields, horizontal timing, vertical timing. + */ +static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct pxafb_info *fbi = (struct pxafb_info *)info; + + if (var->xres < MIN_XRES) + var->xres = MIN_XRES; + if (var->yres < MIN_YRES) + var->yres = MIN_YRES; + if (var->xres > fbi->max_xres) + var->xres = fbi->max_xres; + if (var->yres > fbi->max_yres) + var->yres = fbi->max_yres; + var->xres_virtual = + max(var->xres_virtual, var->xres); + var->yres_virtual = + max(var->yres_virtual, var->yres); + + /* + * Setup the RGB parameters for this display. + * + * The pixel packing format is described on page 7-11 of the + * PXA2XX Developer's Manual. + */ + if (var->bits_per_pixel == 16) { + 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 = var->transp.length = 0; + } else { + var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + } + +#ifdef CONFIG_CPU_FREQ + DPRINTK("dma period = %d ps, clock = %d kHz\n", + pxafb_display_dma_period(var), + get_clk_frequency_khz(0)); +#endif + + return 0; +} + +static inline void pxafb_set_truecolor(u_int is_true_color) +{ + DPRINTK("true_color = %d\n", is_true_color); + // do your machine-specific setup if needed +} + +/* + * pxafb_set_par(): + * Set the user defined part of the display for the specified console + */ +static int pxafb_set_par(struct fb_info *info) +{ + struct pxafb_info *fbi = (struct pxafb_info *)info; + struct fb_var_screeninfo *var = &info->var; + unsigned long palette_mem_size; + + DPRINTK("set_par\n"); + + if (var->bits_per_pixel == 16) + fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR; + else if (!fbi->cmap_static) + fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; + else { + /* + * Some people have weird ideas about wanting static + * pseudocolor maps. I suspect their user space + * applications are broken. + */ + fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; + } + + fbi->fb.fix.line_length = var->xres_virtual * + var->bits_per_pixel / 8; + if (var->bits_per_pixel == 16) + fbi->palette_size = 0; + else + fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel; + + palette_mem_size = fbi->palette_size * sizeof(u16); + + DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size); + + fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); + fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size; + + /* + * Set (any) board control register to handle new color depth + */ + pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR); + + if (fbi->fb.var.bits_per_pixel == 16) + fb_dealloc_cmap(&fbi->fb.cmap); + else + fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0); + + pxafb_activate_var(var, fbi); + + return 0; +} + +/* + * Formal definition of the VESA spec: + * On + * This refers to the state of the display when it is in full operation + * Stand-By + * This defines an optional operating state of minimal power reduction with + * the shortest recovery time + * Suspend + * This refers to a level of power management in which substantial power + * reduction is achieved by the display. The display can have a longer + * recovery time from this state than from the Stand-by state + * Off + * This indicates that the display is consuming the lowest level of power + * and is non-operational. Recovery from this state may optionally require + * the user to manually power on the monitor + * + * Now, the fbdev driver adds an additional state, (blank), where they + * turn off the video (maybe by colormap tricks), but don't mess with the + * video itself: think of it semantically between on and Stand-By. + * + * So here's what we should do in our fbdev blank routine: + * + * VESA_NO_BLANKING (mode 0) Video on, front/back light on + * VESA_VSYNC_SUSPEND (mode 1) Video on, front/back light off + * VESA_HSYNC_SUSPEND (mode 2) Video on, front/back light off + * VESA_POWERDOWN (mode 3) Video off, front/back light off + * + * This will match the matrox implementation. + */ + +/* + * pxafb_blank(): + * Blank the display by setting all palette values to zero. Note, the + * 16 bpp mode does not really use the palette, so this will not + * blank the display in all modes. + */ +static int pxafb_blank(int blank, struct fb_info *info) +{ + struct pxafb_info *fbi = (struct pxafb_info *)info; + int i; + + DPRINTK("pxafb_blank: blank=%d\n", blank); + + switch (blank) { + case FB_BLANK_POWERDOWN: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_NORMAL: + if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR || + fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) + for (i = 0; i < fbi->palette_size; i++) + pxafb_setpalettereg(i, 0, 0, 0, 0, info); + + pxafb_schedule_work(fbi, C_DISABLE); + //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); + break; + + case FB_BLANK_UNBLANK: + //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); + if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR || + fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) + fb_set_cmap(&fbi->fb.cmap, info); + pxafb_schedule_work(fbi, C_ENABLE); + } + return 0; +} + +static int pxafb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + struct pxafb_info *fbi = (struct pxafb_info *)info; + unsigned long off = vma->vm_pgoff << PAGE_SHIFT; + + if (off < info->fix.smem_len) { + vma->vm_pgoff += 1; + return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu, + fbi->map_dma, fbi->map_size); + } + return -EINVAL; +} + +static struct fb_ops pxafb_ops = { + .owner = THIS_MODULE, + .fb_check_var = pxafb_check_var, + .fb_set_par = pxafb_set_par, + .fb_setcolreg = pxafb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_blank = pxafb_blank, + .fb_cursor = soft_cursor, + .fb_mmap = pxafb_mmap, +}; + +/* + * Calculate the PCD value from the clock rate (in picoseconds). + * We take account of the PPCR clock setting. + * From PXA Developer's Manual: + * + * PixelClock = LCLK + * ------------- + * 2 ( PCD + 1 ) + * + * PCD = LCLK + * ------------- - 1 + * 2(PixelClock) + * + * Where: + * LCLK = LCD/Memory Clock + * PCD = LCCR3[7:0] + * + * PixelClock here is in Hz while the pixclock argument given is the + * period in picoseconds. Hence PixelClock = 1 / ( pixclock * 10^-12 ) + * + * The function get_lclk_frequency_10khz returns LCLK in units of + * 10khz. Calling the result of this function lclk gives us the + * following + * + * PCD = (lclk * 10^4 ) * ( pixclock * 10^-12 ) + * -------------------------------------- - 1 + * 2 + * + * Factoring the 10^4 and 10^-12 out gives 10^-8 == 1 / 100000000 as used below. + */ +static inline unsigned int get_pcd(unsigned int pixclock) +{ + unsigned long long pcd; + + /* FIXME: Need to take into account Double Pixel Clock mode + * (DPC) bit? or perhaps set it based on the various clock + * speeds */ + + pcd = (unsigned long long)get_lcdclk_frequency_10khz() * pixclock; + pcd /= 100000000 * 2; + /* no need for this, since we should subtract 1 anyway. they cancel */ + /* pcd += 1; */ /* make up for integer math truncations */ + return (unsigned int)pcd; +} + +/* + * pxafb_activate_var(): + * Configures LCD Controller based on entries in var parameter. Settings are + * only written to the controller if changes were made. + */ +static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi) +{ + struct pxafb_lcd_reg new_regs; + u_long flags; + u_int lines_per_panel, pcd = get_pcd(var->pixclock); + + DPRINTK("Configuring PXA LCD\n"); + + DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n", + var->xres, var->hsync_len, + var->left_margin, var->right_margin); + DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n", + var->yres, var->vsync_len, + var->upper_margin, var->lower_margin); + DPRINTK("var: pixclock=%d pcd=%d\n", var->pixclock, pcd); + +#if DEBUG_VAR + if (var->xres < 16 || var->xres > 1024) + printk(KERN_ERR "%s: invalid xres %d\n", + fbi->fb.fix.id, var->xres); + switch(var->bits_per_pixel) { + case 1: + case 2: + case 4: + case 8: + case 16: + break; + default: + printk(KERN_ERR "%s: invalid bit depth %d\n", + fbi->fb.fix.id, var->bits_per_pixel); + break; + } + if (var->hsync_len < 1 || var->hsync_len > 64) + printk(KERN_ERR "%s: invalid hsync_len %d\n", + fbi->fb.fix.id, var->hsync_len); + if (var->left_margin < 1 || var->left_margin > 255) + printk(KERN_ERR "%s: invalid left_margin %d\n", + fbi->fb.fix.id, var->left_margin); + if (var->right_margin < 1 || var->right_margin > 255) + printk(KERN_ERR "%s: invalid right_margin %d\n", + fbi->fb.fix.id, var->right_margin); + if (var->yres < 1 || var->yres > 1024) + printk(KERN_ERR "%s: invalid yres %d\n", + fbi->fb.fix.id, var->yres); + if (var->vsync_len < 1 || var->vsync_len > 64) + printk(KERN_ERR "%s: invalid vsync_len %d\n", + fbi->fb.fix.id, var->vsync_len); + if (var->upper_margin < 0 || var->upper_margin > 255) + printk(KERN_ERR "%s: invalid upper_margin %d\n", + fbi->fb.fix.id, var->upper_margin); + if (var->lower_margin < 0 || var->lower_margin > 255) + printk(KERN_ERR "%s: invalid lower_margin %d\n", + fbi->fb.fix.id, var->lower_margin); +#endif + + new_regs.lccr0 = fbi->lccr0 | + (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | + LCCR0_QDM | LCCR0_BM | LCCR0_OUM); + + new_regs.lccr1 = + LCCR1_DisWdth(var->xres) + + LCCR1_HorSnchWdth(var->hsync_len) + + LCCR1_BegLnDel(var->left_margin) + + LCCR1_EndLnDel(var->right_margin); + + /* + * If we have a dual scan LCD, we need to halve + * the YRES parameter. + */ + lines_per_panel = var->yres; + if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual) + lines_per_panel /= 2; + + new_regs.lccr2 = + LCCR2_DisHght(lines_per_panel) + + LCCR2_VrtSnchWdth(var->vsync_len) + + LCCR2_BegFrmDel(var->upper_margin) + + LCCR2_EndFrmDel(var->lower_margin); + + new_regs.lccr3 = fbi->lccr3 | + pxafb_bpp_to_lccr3(var) | + (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) | + (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL); + + if (pcd) + new_regs.lccr3 |= LCCR3_PixClkDiv(pcd); + + DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0); + DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1); + DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2); + DPRINTK("nlccr3 = 0x%08x\n", new_regs.lccr3); + + /* Update shadow copy atomically */ + local_irq_save(flags); + + /* setup dma descriptors */ + fbi->dmadesc_fblow_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 3*16); + fbi->dmadesc_fbhigh_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 2*16); + fbi->dmadesc_palette_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 1*16); + + fbi->dmadesc_fblow_dma = fbi->palette_dma - 3*16; + fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16; + fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16; + +#define BYTES_PER_PANEL (lines_per_panel * fbi->fb.fix.line_length) + + /* populate descriptors */ + fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma; + fbi->dmadesc_fblow_cpu->fsadr = fbi->screen_dma + BYTES_PER_PANEL; + fbi->dmadesc_fblow_cpu->fidr = 0; + fbi->dmadesc_fblow_cpu->ldcmd = BYTES_PER_PANEL; + + fbi->fdadr1 = fbi->dmadesc_fblow_dma; /* only used in dual-panel mode */ + + fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma; + fbi->dmadesc_fbhigh_cpu->fidr = 0; + fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL; + + fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma; + fbi->dmadesc_palette_cpu->fidr = 0; + fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL; + + if (var->bits_per_pixel == 16) { + /* palette shouldn't be loaded in true-color mode */ + fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma; + fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */ + /* init it to something, even though we won't be using it */ + fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_palette_dma; + } else { + fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma; + fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma; + fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */ + } + +#if 0 + DPRINTK("fbi->dmadesc_fblow_cpu = 0x%p\n", fbi->dmadesc_fblow_cpu); + DPRINTK("fbi->dmadesc_fbhigh_cpu = 0x%p\n", fbi->dmadesc_fbhigh_cpu); + DPRINTK("fbi->dmadesc_palette_cpu = 0x%p\n", fbi->dmadesc_palette_cpu); + DPRINTK("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma); + DPRINTK("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma); + DPRINTK("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma); + + DPRINTK("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr); + DPRINTK("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr); + DPRINTK("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr); + + DPRINTK("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr); + DPRINTK("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr); + DPRINTK("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr); + + DPRINTK("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd); + DPRINTK("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd); + DPRINTK("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd); +#endif + + fbi->reg_lccr0 = new_regs.lccr0; + fbi->reg_lccr1 = new_regs.lccr1; + fbi->reg_lccr2 = new_regs.lccr2; + fbi->reg_lccr3 = new_regs.lccr3; + local_irq_restore(flags); + + /* + * Only update the registers if the controller is enabled + * and something has changed. + */ + if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) || + (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) || + (FDADR0 != fbi->fdadr0) || (FDADR1 != fbi->fdadr1)) + pxafb_schedule_work(fbi, C_REENABLE); + + return 0; +} + +/* + * NOTE! The following functions are purely helpers for set_ctrlr_state. + * Do not call them directly; set_ctrlr_state does the correct serialisation + * to ensure that things happen in the right way 100% of time time. + * -- rmk + */ +static inline void __pxafb_backlight_power(struct pxafb_info *fbi, int on) +{ + DPRINTK("backlight o%s\n", on ? "n" : "ff"); + + if (pxafb_backlight_power) + pxafb_backlight_power(on); +} + +static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on) +{ + DPRINTK("LCD power o%s\n", on ? "n" : "ff"); + + if (pxafb_lcd_power) + pxafb_lcd_power(on); +} + +static void pxafb_setup_gpio(struct pxafb_info *fbi) +{ + int gpio, ldd_bits; + unsigned int lccr0 = fbi->lccr0; + + /* + * setup is based on type of panel supported + */ + + /* 4 bit interface */ + if ((lccr0 & LCCR0_CMS) == LCCR0_Mono && + (lccr0 & LCCR0_SDS) == LCCR0_Sngl && + (lccr0 & LCCR0_DPD) == LCCR0_4PixMono) + ldd_bits = 4; + + /* 8 bit interface */ + else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono && + ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) || + ((lccr0 & LCCR0_CMS) == LCCR0_Color && + (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl)) + ldd_bits = 8; + + /* 16 bit interface */ + else if ((lccr0 & LCCR0_CMS) == LCCR0_Color && + ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act)) + ldd_bits = 16; + + else { + printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n"); + return; + } + + for (gpio = 58; ldd_bits; gpio++, ldd_bits--) + pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT); + pxa_gpio_mode(GPIO74_LCD_FCLK_MD); + pxa_gpio_mode(GPIO75_LCD_LCLK_MD); + pxa_gpio_mode(GPIO76_LCD_PCLK_MD); + pxa_gpio_mode(GPIO77_LCD_ACBIAS_MD); +} + +static void pxafb_enable_controller(struct pxafb_info *fbi) +{ + DPRINTK("Enabling LCD controller\n"); + DPRINTK("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr0); + DPRINTK("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr1); + DPRINTK("reg_lccr0 0x%08x\n", (unsigned int) fbi->reg_lccr0); + DPRINTK("reg_lccr1 0x%08x\n", (unsigned int) fbi->reg_lccr1); + DPRINTK("reg_lccr2 0x%08x\n", (unsigned int) fbi->reg_lccr2); + DPRINTK("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3); + + /* Sequence from 11.7.10 */ + LCCR3 = fbi->reg_lccr3; + LCCR2 = fbi->reg_lccr2; + LCCR1 = fbi->reg_lccr1; + LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB; + + FDADR0 = fbi->fdadr0; + FDADR1 = fbi->fdadr1; + LCCR0 |= LCCR0_ENB; + + DPRINTK("FDADR0 0x%08x\n", (unsigned int) FDADR0); + DPRINTK("FDADR1 0x%08x\n", (unsigned int) FDADR1); + DPRINTK("LCCR0 0x%08x\n", (unsigned int) LCCR0); + DPRINTK("LCCR1 0x%08x\n", (unsigned int) LCCR1); + DPRINTK("LCCR2 0x%08x\n", (unsigned int) LCCR2); + DPRINTK("LCCR3 0x%08x\n", (unsigned int) LCCR3); +} + +static void pxafb_disable_controller(struct pxafb_info *fbi) +{ + DECLARE_WAITQUEUE(wait, current); + + DPRINTK("Disabling LCD controller\n"); + + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&fbi->ctrlr_wait, &wait); + + LCSR = 0xffffffff; /* Clear LCD Status Register */ + LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */ + LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ + + schedule_timeout(20 * HZ / 1000); + remove_wait_queue(&fbi->ctrlr_wait, &wait); +} + +/* + * pxafb_handle_irq: Handle 'LCD DONE' interrupts. + */ +static irqreturn_t pxafb_handle_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pxafb_info *fbi = dev_id; + unsigned int lcsr = LCSR; + + if (lcsr & LCSR_LDD) { + LCCR0 |= LCCR0_LDM; + wake_up(&fbi->ctrlr_wait); + } + + LCSR = lcsr; + return IRQ_HANDLED; +} + +/* + * This function must be called from task context only, since it will + * sleep when disabling the LCD controller, or if we get two contending + * processes trying to alter state. + */ +static void set_ctrlr_state(struct pxafb_info *fbi, u_int state) +{ + u_int old_state; + + down(&fbi->ctrlr_sem); + + old_state = fbi->state; + + /* + * Hack around fbcon initialisation. + */ + if (old_state == C_STARTUP && state == C_REENABLE) + state = C_ENABLE; + + switch (state) { + case C_DISABLE_CLKCHANGE: + /* + * Disable controller for clock change. If the + * controller is already disabled, then do nothing. + */ + if (old_state != C_DISABLE && old_state != C_DISABLE_PM) { + fbi->state = state; + //TODO __pxafb_lcd_power(fbi, 0); + pxafb_disable_controller(fbi); + } + break; + + case C_DISABLE_PM: + case C_DISABLE: + /* + * Disable controller + */ + if (old_state != C_DISABLE) { + fbi->state = state; + __pxafb_backlight_power(fbi, 0); + __pxafb_lcd_power(fbi, 0); + if (old_state != C_DISABLE_CLKCHANGE) + pxafb_disable_controller(fbi); + } + break; + + case C_ENABLE_CLKCHANGE: + /* + * Enable the controller after clock change. Only + * do this if we were disabled for the clock change. + */ + if (old_state == C_DISABLE_CLKCHANGE) { + fbi->state = C_ENABLE; + pxafb_enable_controller(fbi); + //TODO __pxafb_lcd_power(fbi, 1); + } + break; + + case C_REENABLE: + /* + * Re-enable the controller only if it was already + * enabled. This is so we reprogram the control + * registers. + */ + if (old_state == C_ENABLE) { + pxafb_disable_controller(fbi); + pxafb_setup_gpio(fbi); + pxafb_enable_controller(fbi); + } + break; + + case C_ENABLE_PM: + /* + * Re-enable the controller after PM. This is not + * perfect - think about the case where we were doing + * a clock change, and we suspended half-way through. + */ + if (old_state != C_DISABLE_PM) + break; + /* fall through */ + + case C_ENABLE: + /* + * Power up the LCD screen, enable controller, and + * turn on the backlight. + */ + if (old_state != C_ENABLE) { + fbi->state = C_ENABLE; + pxafb_setup_gpio(fbi); + pxafb_enable_controller(fbi); + __pxafb_lcd_power(fbi, 1); + __pxafb_backlight_power(fbi, 1); + } + break; + } + up(&fbi->ctrlr_sem); +} + +/* + * Our LCD controller task (which is called when we blank or unblank) + * via keventd. + */ +static void pxafb_task(void *dummy) +{ + struct pxafb_info *fbi = dummy; + u_int state = xchg(&fbi->task_state, -1); + + set_ctrlr_state(fbi, state); +} + +#ifdef CONFIG_CPU_FREQ +/* + * CPU clock speed change handler. We need to adjust the LCD timing + * parameters when the CPU clock is adjusted by the power management + * subsystem. + * + * TODO: Determine why f->new != 10*get_lclk_frequency_10khz() + */ +static int +pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data) +{ + struct pxafb_info *fbi = TO_INF(nb, freq_transition); + //TODO struct cpufreq_freqs *f = data; + u_int pcd; + + switch (val) { + case CPUFREQ_PRECHANGE: + set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE); + break; + + case CPUFREQ_POSTCHANGE: + pcd = get_pcd(fbi->fb.var.pixclock); + fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); + set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE); + break; + } + return 0; +} + +static int +pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data) +{ + struct pxafb_info *fbi = TO_INF(nb, freq_policy); + struct fb_var_screeninfo *var = &fbi->fb.var; + struct cpufreq_policy *policy = data; + + switch (val) { + case CPUFREQ_ADJUST: + case CPUFREQ_INCOMPATIBLE: + printk(KERN_DEBUG "min dma period: %d ps, " + "new clock %d kHz\n", pxafb_display_dma_period(var), + policy->max); + // TODO: fill in min/max values + break; +#if 0 + case CPUFREQ_NOTIFY: + printk(KERN_ERR "%s: got CPUFREQ_NOTIFY\n", __FUNCTION__); + do {} while(0); + /* todo: panic if min/max values aren't fulfilled + * [can't really happen unless there's a bug in the + * CPU policy verification process * + */ + break; +#endif + } + return 0; +} +#endif + +#ifdef CONFIG_PM +/* + * Power management hooks. Note that we won't be called from IRQ context, + * unlike the blank functions above, so we may sleep. + */ +static int pxafb_suspend(struct device *dev, u32 state, u32 level) +{ + struct pxafb_info *fbi = dev_get_drvdata(dev); + + if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) + set_ctrlr_state(fbi, C_DISABLE_PM); + return 0; +} + +static int pxafb_resume(struct device *dev, u32 level) +{ + struct pxafb_info *fbi = dev_get_drvdata(dev); + + if (level == RESUME_ENABLE) + set_ctrlr_state(fbi, C_ENABLE_PM); + return 0; +} +#else +#define pxafb_suspend NULL +#define pxafb_resume NULL +#endif + +/* + * pxafb_map_video_memory(): + * Allocates the DRAM memory for the frame buffer. This buffer is + * remapped into a non-cached, non-buffered, memory region to + * allow palette and pixel writes to occur without flushing the + * cache. Once this area is remapped, all virtual memory + * access to the video memory should occur at the new region. + */ +static int __init pxafb_map_video_memory(struct pxafb_info *fbi) +{ + u_long palette_mem_size; + + /* + * We reserve one page for the palette, plus the size + * of the framebuffer. + */ + fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); + fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, + &fbi->map_dma, GFP_KERNEL); + + if (fbi->map_cpu) { + /* prevent initial garbage on screen */ + memset(fbi->map_cpu, 0, fbi->map_size); + fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE; + fbi->screen_dma = fbi->map_dma + PAGE_SIZE; + /* + * FIXME: this is actually the wrong thing to place in + * smem_start. But fbdev suffers from the problem that + * it needs an API which doesn't exist (in this case, + * dma_writecombine_mmap) + */ + fbi->fb.fix.smem_start = fbi->screen_dma; + + fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16; + + palette_mem_size = fbi->palette_size * sizeof(u16); + DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size); + + fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); + fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size; + } + + return fbi->map_cpu ? 0 : -ENOMEM; +} + +static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev) +{ + struct pxafb_info *fbi; + void *addr; + struct pxafb_mach_info *inf = dev->platform_data; + + /* Alloc the pxafb_info and pseudo_palette in one step */ + fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL); + if (!fbi) + return NULL; + + memset(fbi, 0, sizeof(struct pxafb_info)); + fbi->dev = dev; + + strcpy(fbi->fb.fix.id, PXA_NAME); + + fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS; + fbi->fb.fix.type_aux = 0; + fbi->fb.fix.xpanstep = 0; + fbi->fb.fix.ypanstep = 0; + fbi->fb.fix.ywrapstep = 0; + fbi->fb.fix.accel = FB_ACCEL_NONE; + + fbi->fb.var.nonstd = 0; + fbi->fb.var.activate = FB_ACTIVATE_NOW; + fbi->fb.var.height = -1; + fbi->fb.var.width = -1; + fbi->fb.var.accel_flags = 0; + fbi->fb.var.vmode = FB_VMODE_NONINTERLACED; + + fbi->fb.fbops = &pxafb_ops; + fbi->fb.flags = FBINFO_DEFAULT; + fbi->fb.node = -1; + + addr = fbi; + addr = addr + sizeof(struct pxafb_info); + fbi->fb.pseudo_palette = addr; + + fbi->max_xres = inf->xres; + fbi->fb.var.xres = inf->xres; + fbi->fb.var.xres_virtual = inf->xres; + fbi->max_yres = inf->yres; + fbi->fb.var.yres = inf->yres; + fbi->fb.var.yres_virtual = inf->yres; + fbi->max_bpp = inf->bpp; + fbi->fb.var.bits_per_pixel = inf->bpp; + fbi->fb.var.pixclock = inf->pixclock; + fbi->fb.var.hsync_len = inf->hsync_len; + fbi->fb.var.left_margin = inf->left_margin; + fbi->fb.var.right_margin = inf->right_margin; + fbi->fb.var.vsync_len = inf->vsync_len; + fbi->fb.var.upper_margin = inf->upper_margin; + fbi->fb.var.lower_margin = inf->lower_margin; + fbi->fb.var.sync = inf->sync; + fbi->fb.var.grayscale = inf->cmap_greyscale; + fbi->cmap_inverse = inf->cmap_inverse; + fbi->cmap_static = inf->cmap_static; + fbi->lccr0 = inf->lccr0; + fbi->lccr3 = inf->lccr3; + fbi->state = C_STARTUP; + fbi->task_state = (u_char)-1; + fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres * + fbi->max_bpp / 8; + + init_waitqueue_head(&fbi->ctrlr_wait); + INIT_WORK(&fbi->task, pxafb_task, fbi); + init_MUTEX(&fbi->ctrlr_sem); + + return fbi; +} + +#ifdef CONFIG_FB_PXA_PARAMETERS +static int __init pxafb_parse_options(struct device *dev, char *options) +{ + struct pxafb_mach_info *inf = dev->platform_data; + char *this_opt; + + if (!options || !*options) + return 0; + + dev_dbg(dev, "options are \"%s\"\n", options ? options : "null"); + + /* could be made table driven or similar?... */ + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "mode:", 5)) { + const char *name = this_opt+5; + unsigned int namelen = strlen(name); + int res_specified = 0, bpp_specified = 0; + unsigned int xres = 0, yres = 0, bpp = 0; + int yres_specified = 0; + int i; + for (i = namelen-1; i >= 0; i--) { + switch (name[i]) { + case '-': + namelen = i; + if (!bpp_specified && !yres_specified) { + bpp = simple_strtoul(&name[i+1], NULL, 0); + bpp_specified = 1; + } else + goto done; + break; + case 'x': + if (!yres_specified) { + yres = simple_strtoul(&name[i+1], NULL, 0); + yres_specified = 1; + } else + goto done; + break; + case '0'...'9': + break; + default: + goto done; + } + } + if (i < 0 && yres_specified) { + xres = simple_strtoul(name, NULL, 0); + res_specified = 1; + } + done: + if (res_specified) { + dev_info(dev, "overriding resolution: %dx%d\n", xres, yres); + inf->xres = xres; inf->yres = yres; + } + if (bpp_specified) + switch (bpp) { + case 1: + case 2: + case 4: + case 8: + case 16: + inf->bpp = bpp; + dev_info(dev, "overriding bit depth: %d\n", bpp); + break; + default: + dev_err(dev, "Depth %d is not valid\n", bpp); + } + } else if (!strncmp(this_opt, "pixclock:", 9)) { + inf->pixclock = simple_strtoul(this_opt+9, NULL, 0); + dev_info(dev, "override pixclock: %ld\n", inf->pixclock); + } else if (!strncmp(this_opt, "left:", 5)) { + inf->left_margin = simple_strtoul(this_opt+5, NULL, 0); + dev_info(dev, "override left: %u\n", inf->left_margin); + } else if (!strncmp(this_opt, "right:", 6)) { + inf->right_margin = simple_strtoul(this_opt+6, NULL, 0); + dev_info(dev, "override right: %u\n", inf->right_margin); + } else if (!strncmp(this_opt, "upper:", 6)) { + inf->upper_margin = simple_strtoul(this_opt+6, NULL, 0); + dev_info(dev, "override upper: %u\n", inf->upper_margin); + } else if (!strncmp(this_opt, "lower:", 6)) { + inf->lower_margin = simple_strtoul(this_opt+6, NULL, 0); + dev_info(dev, "override lower: %u\n", inf->lower_margin); + } else if (!strncmp(this_opt, "hsynclen:", 9)) { + inf->hsync_len = simple_strtoul(this_opt+9, NULL, 0); + dev_info(dev, "override hsynclen: %u\n", inf->hsync_len); + } else if (!strncmp(this_opt, "vsynclen:", 9)) { + inf->vsync_len = simple_strtoul(this_opt+9, NULL, 0); + dev_info(dev, "override vsynclen: %u\n", inf->vsync_len); + } else if (!strncmp(this_opt, "hsync:", 6)) { + if (simple_strtoul(this_opt+6, NULL, 0) == 0) { + dev_info(dev, "override hsync: Active Low\n"); + inf->sync &= ~FB_SYNC_HOR_HIGH_ACT; + } else { + dev_info(dev, "override hsync: Active High\n"); + inf->sync |= FB_SYNC_HOR_HIGH_ACT; + } + } else if (!strncmp(this_opt, "vsync:", 6)) { + if (simple_strtoul(this_opt+6, NULL, 0) == 0) { + dev_info(dev, "override vsync: Active Low\n"); + inf->sync &= ~FB_SYNC_VERT_HIGH_ACT; + } else { + dev_info(dev, "override vsync: Active High\n"); + inf->sync |= FB_SYNC_VERT_HIGH_ACT; + } + } else if (!strncmp(this_opt, "dpc:", 4)) { + if (simple_strtoul(this_opt+4, NULL, 0) == 0) { + dev_info(dev, "override double pixel clock: false\n"); + inf->lccr3 &= ~LCCR3_DPC; + } else { + dev_info(dev, "override double pixel clock: true\n"); + inf->lccr3 |= LCCR3_DPC; + } + } else if (!strncmp(this_opt, "outputen:", 9)) { + if (simple_strtoul(this_opt+9, NULL, 0) == 0) { + dev_info(dev, "override output enable: active low\n"); + inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL; + } else { + dev_info(dev, "override output enable: active high\n"); + inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH; + } + } else if (!strncmp(this_opt, "pixclockpol:", 12)) { + if (simple_strtoul(this_opt+12, NULL, 0) == 0) { + dev_info(dev, "override pixel clock polarity: falling edge\n"); + inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg; + } else { + dev_info(dev, "override pixel clock polarity: rising edge\n"); + inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg; + } + } else if (!strncmp(this_opt, "color", 5)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color; + } else if (!strncmp(this_opt, "mono", 4)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono; + } else if (!strncmp(this_opt, "active", 6)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act; + } else if (!strncmp(this_opt, "passive", 7)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas; + } else if (!strncmp(this_opt, "single", 6)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl; + } else if (!strncmp(this_opt, "dual", 4)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual; + } else if (!strncmp(this_opt, "4pix", 4)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono; + } else if (!strncmp(this_opt, "8pix", 4)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono; + } else { + dev_err(dev, "unknown option: %s\n", this_opt); + return -EINVAL; + } + } + return 0; + +} +#endif + +int __init pxafb_probe(struct device *dev) +{ + struct pxafb_info *fbi; + struct pxafb_mach_info *inf; + int ret; + + dev_dbg(dev, "pxafb_probe\n"); + + inf = dev->platform_data; + ret = -ENOMEM; + fbi = NULL; + if (!inf) + goto failed; + +#ifdef CONFIG_FB_PXA_PARAMETERS + ret = pxafb_parse_options(dev, g_options); + if (ret < 0) + goto failed; +#endif + +#ifdef DEBUG_VAR + /* Check for various illegal bit-combinations. Currently only + * a warning is given. */ + + if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK) + dev_warn(dev, "machine LCCR0 setting contains illegal bits: %08x\n", + inf->lccr0 & LCCR0_INVALID_CONFIG_MASK); + if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK) + dev_warn(dev, "machine LCCR3 setting contains illegal bits: %08x\n", + inf->lccr3 & LCCR3_INVALID_CONFIG_MASK); + if (inf->lccr0 & LCCR0_DPD && + ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas || + (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl || + (inf->lccr0 & LCCR0_CMS) != LCCR0_Mono)) + dev_warn(dev, "Double Pixel Data (DPD) mode is only valid in passive mono" + " single panel mode\n"); + if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act && + (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual) + dev_warn(dev, "Dual panel only valid in passive mode\n"); + if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas && + (inf->upper_margin || inf->lower_margin)) + dev_warn(dev, "Upper and lower margins must be 0 in passive mode\n"); +#endif + + dev_dbg(dev, "got a %dx%dx%d LCD\n",inf->xres, inf->yres, inf->bpp); + if (inf->xres == 0 || inf->yres == 0 || inf->bpp == 0) { + dev_err(dev, "Invalid resolution or bit depth\n"); + ret = -EINVAL; + goto failed; + } + pxafb_backlight_power = inf->pxafb_backlight_power; + pxafb_lcd_power = inf->pxafb_lcd_power; + fbi = pxafb_init_fbinfo(dev); + if (!fbi) { + dev_err(dev, "Failed to initialize framebuffer device\n"); + ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc + goto failed; + } + + /* Initialize video memory */ + ret = pxafb_map_video_memory(fbi); + if (ret) { + dev_err(dev, "Failed to allocate video RAM: %d\n", ret); + ret = -ENOMEM; + goto failed; + } + /* enable LCD controller clock */ + pxa_set_cken(CKEN16_LCD, 1); + + ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT, "LCD", fbi); + if (ret) { + dev_err(dev, "request_irq failed: %d\n", ret); + ret = -EBUSY; + goto failed; + } + + /* + * This makes sure that our colour bitfield + * descriptors are correctly initialised. + */ + pxafb_check_var(&fbi->fb.var, &fbi->fb); + pxafb_set_par(&fbi->fb); + + dev_set_drvdata(dev, fbi); + + ret = register_framebuffer(&fbi->fb); + if (ret < 0) { + dev_err(dev, "Failed to register framebuffer device: %d\n", ret); + goto failed; + } + +#ifdef CONFIG_PM + // TODO +#endif + +#ifdef CONFIG_CPU_FREQ + fbi->freq_transition.notifier_call = pxafb_freq_transition; + fbi->freq_policy.notifier_call = pxafb_freq_policy; + cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); + cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER); +#endif + + /* + * Ok, now enable the LCD controller + */ + set_ctrlr_state(fbi, C_ENABLE); + + return 0; + +failed: + dev_set_drvdata(dev, NULL); + kfree(fbi); + return ret; +} + +static struct device_driver pxafb_driver = { + .name = "pxa2xx-fb", + .bus = &platform_bus_type, + .probe = pxafb_probe, +#ifdef CONFIG_PM + .suspend = pxafb_suspend, + .resume = pxafb_resume, +#endif +}; + +#ifndef MODULE +int __devinit pxafb_setup(char *options) +{ +# ifdef CONFIG_FB_PXA_PARAMETERS + strlcpy(g_options, options, sizeof(g_options)); +# endif + return 0; +} +#else +# ifdef CONFIG_FB_PXA_PARAMETERS +module_param_string(options, g_options, sizeof(g_options), 0); +MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)"); +# endif +#endif + +int __devinit pxafb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("pxafb", &option)) + return -ENODEV; + pxafb_setup(option); +#endif + return driver_register(&pxafb_driver); +} + +module_init(pxafb_init); + +MODULE_DESCRIPTION("loadable framebuffer driver for PXA"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h new file mode 100644 index 000000000000..de15fec5f82f --- /dev/null +++ b/drivers/video/pxafb.h @@ -0,0 +1,129 @@ +#ifndef __PXAFB_H__ +#define __PXAFB_H__ + +/* + * linux/drivers/video/pxafb.h + * -- Intel PXA250/210 LCD Controller Frame Buffer Device + * + * Copyright (C) 1999 Eric A. Thomas. + * Copyright (C) 2004 Jean-Frederic Clere. + * Copyright (C) 2004 Ian Campbell. + * Copyright (C) 2004 Jeff Lackey. + * Based on sa1100fb.c Copyright (C) 1999 Eric A. Thomas + * which in turn is + * Based on acornfb.c Copyright (C) Russell King. + * + * 2001-08-03: Cliff Brake <cbrake@acclent.com> + * - ported SA1100 code to PXA + * + * 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. + */ + +/* Shadows for LCD controller registers */ +struct pxafb_lcd_reg { + unsigned int lccr0; + unsigned int lccr1; + unsigned int lccr2; + unsigned int lccr3; +}; + +/* PXA LCD DMA descriptor */ +struct pxafb_dma_descriptor { + unsigned int fdadr; + unsigned int fsadr; + unsigned int fidr; + unsigned int ldcmd; +}; + +struct pxafb_info { + struct fb_info fb; + struct device *dev; + + u_int max_bpp; + u_int max_xres; + u_int max_yres; + + /* + * These are the addresses we mapped + * the framebuffer memory region to. + */ + /* raw memory addresses */ + dma_addr_t map_dma; /* physical */ + u_char * map_cpu; /* virtual */ + u_int map_size; + + /* addresses of pieces placed in raw buffer */ + u_char * screen_cpu; /* virtual address of frame buffer */ + dma_addr_t screen_dma; /* physical address of frame buffer */ + u16 * palette_cpu; /* virtual address of palette memory */ + dma_addr_t palette_dma; /* physical address of palette memory */ + u_int palette_size; + + /* DMA descriptors */ + struct pxafb_dma_descriptor * dmadesc_fblow_cpu; + dma_addr_t dmadesc_fblow_dma; + struct pxafb_dma_descriptor * dmadesc_fbhigh_cpu; + dma_addr_t dmadesc_fbhigh_dma; + struct pxafb_dma_descriptor * dmadesc_palette_cpu; + dma_addr_t dmadesc_palette_dma; + + dma_addr_t fdadr0; + dma_addr_t fdadr1; + + u_int lccr0; + u_int lccr3; + u_int cmap_inverse:1, + cmap_static:1, + unused:30; + + u_int reg_lccr0; + u_int reg_lccr1; + u_int reg_lccr2; + u_int reg_lccr3; + + volatile u_char state; + volatile u_char task_state; + struct semaphore ctrlr_sem; + wait_queue_head_t ctrlr_wait; + struct work_struct task; + +#ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; + struct notifier_block freq_policy; +#endif +}; + +#define TO_INF(ptr,member) container_of(ptr,struct pxafb_info,member) + +/* + * These are the actions for set_ctrlr_state + */ +#define C_DISABLE (0) +#define C_ENABLE (1) +#define C_DISABLE_CLKCHANGE (2) +#define C_ENABLE_CLKCHANGE (3) +#define C_REENABLE (4) +#define C_DISABLE_PM (5) +#define C_ENABLE_PM (6) +#define C_STARTUP (7) + +#define PXA_NAME "PXA" + +/* + * Debug macros + */ +#if DEBUG +# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + +/* + * Minimum X and Y resolutions + */ +#define MIN_XRES 64 +#define MIN_YRES 64 + +#endif /* __PXAFB_H__ */ diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c new file mode 100644 index 000000000000..71b69da0c40d --- /dev/null +++ b/drivers/video/q40fb.c @@ -0,0 +1,160 @@ +/* + * linux/drivers/video/q40fb.c -- Q40 frame buffer device + * + * Copyright (C) 2001 + * + * Richard Zidlicky <rz@linux-m68k.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/kernel.h> +#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/interrupt.h> + +#include <asm/uaccess.h> +#include <asm/setup.h> +#include <asm/segment.h> +#include <asm/system.h> +#include <asm/q40_master.h> +#include <linux/fb.h> +#include <linux/module.h> +#include <asm/pgtable.h> + +#define Q40_PHYS_SCREEN_ADDR 0xFE800000 + +static struct fb_fix_screeninfo q40fb_fix __initdata = { + .id = "Q40", + .smem_len = 1024*1024, + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .line_length = 1024*2, + .accel = FB_ACCEL_NONE, +}; + +static struct fb_var_screeninfo q40fb_var __initdata = { + .xres = 1024, + .yres = 512, + .xres_virtual = 1024, + .yres_virtual = 512, + .bits_per_pixel = 16, + .red = {6, 5, 0}, + .green = {11, 5, 0}, + .blue = {0, 6, 0}, + .activate = FB_ACTIVATE_NOW, + .height = 230, + .width = 300, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + /* + * Set a single color register. The values supplied have a 16 bit + * magnitude. + * Return != 0 for invalid regno. + */ + + if (regno > 255) + return 1; + red>>=11; + green>>=11; + blue>>=10; + + if (regno < 16) { + ((u32 *)info->pseudo_palette)[regno] = ((red & 31) <<6) | + ((green & 31) << 11) | + (blue & 63); + } + return 0; +} + +static struct fb_ops q40fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = q40fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +static int __init q40fb_probe(struct device *device) +{ + struct platform_device *dev = to_platform_device(device); + struct fb_info *info; + + if (!MACH_IS_Q40) + return -ENXIO; + + /* mapped in q40/config.c */ + q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR; + + info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); + if (!info) + return -ENOMEM; + + info->var = q40fb_var; + info->fix = q40fb_fix; + info->fbops = &q40fb_ops; + info->flags = FBINFO_DEFAULT; /* not as module for now */ + info->pseudo_palette = info->par; + info->par = NULL; + info->screen_base = (char *) q40fb_fix.smem_start; + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + framebuffer_release(info); + return -ENOMEM; + } + + master_outb(3, DISPLAY_CONTROL_REG); + + if (register_framebuffer(info) < 0) { + printk(KERN_ERR "Unable to register Q40 frame buffer\n"); + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + return -EINVAL; + } + + printk(KERN_INFO "fb%d: Q40 frame buffer alive and kicking !\n", + info->node); + return 0; +} + +static struct device_driver q40fb_driver = { + .name = "q40fb", + .bus = &platform_bus_type, + .probe = q40fb_probe, +}; + +static struct platform_device q40fb_device = { + .name = "q40fb", +}; + +int __init q40fb_init(void) +{ + int ret = 0; + + if (fb_get_options("q40fb", NULL)) + return -ENODEV; + + ret = driver_register(&q40fb_driver); + + if (!ret) { + ret = platform_device_register(&q40fb_device); + if (ret) + driver_unregister(&q40fb_driver); + } + return ret; +} + +module_init(q40fb_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c new file mode 100644 index 000000000000..d9a084e77a63 --- /dev/null +++ b/drivers/video/radeonfb.c @@ -0,0 +1,3168 @@ +/* + * drivers/video/radeonfb.c + * framebuffer driver for ATI Radeon chipset video boards + * + * Copyright 2000 Ani Joshi <ajoshi@kernel.crashing.org> + * + * + * ChangeLog: + * 2000-08-03 initial version 0.0.1 + * 2000-09-10 more bug fixes, public release 0.0.5 + * 2001-02-19 mode bug fixes, 0.0.7 + * 2001-07-05 fixed scrolling issues, engine initialization, + * and minor mode tweaking, 0.0.9 + * 2001-09-07 Radeon VE support, Nick Kurshev + * blanking, pan_display, and cmap fixes, 0.1.0 + * 2001-10-10 Radeon 7500 and 8500 support, and experimental + * flat panel support, 0.1.1 + * 2001-11-17 Radeon M6 (ppc) support, Daniel Berlin, 0.1.2 + * 2001-11-18 DFP fixes, Kevin Hendricks, 0.1.3 + * 2001-11-29 more cmap, backlight fixes, Benjamin Herrenschmidt + * 2002-01-18 DFP panel detection via BIOS, Michael Clark, 0.1.4 + * 2002-06-02 console switching, mode set fixes, accel fixes + * 2002-06-03 MTRR support, Peter Horton, 0.1.5 + * 2002-09-21 rv250, r300, m9 initial support, + * added mirror option, 0.1.6 + * + * Special thanks to ATI DevRel team for their hardware donations. + * + */ + + +#define RADEON_VERSION "0.1.6" + + +#include <linux/config.h> +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/vmalloc.h> + +#include <asm/io.h> +#include <asm/uaccess.h> +#if defined(__powerpc__) +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#include "macmodes.h" + +#ifdef CONFIG_NVRAM +#include <linux/nvram.h> +#endif + +#ifdef CONFIG_PMAC_BACKLIGHT +#include <asm/backlight.h> +#endif + +#ifdef CONFIG_BOOTX_TEXT +#include <asm/btext.h> +#endif + +#ifdef CONFIG_ADB_PMU +#include <linux/adb.h> +#include <linux/pmu.h> +#endif + +#endif /* __powerpc__ */ + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include <video/radeon.h> +#include <linux/radeonfb.h> + +#define DEBUG 1 + +#if DEBUG +#define RTRACE printk +#else +#define RTRACE if(0) printk +#endif + +// XXX +#undef CONFIG_PMAC_PBOOK + + +enum radeon_chips { + RADEON_QD, + RADEON_QE, + RADEON_QF, + RADEON_QG, + RADEON_QY, + RADEON_QZ, + RADEON_LW, + RADEON_LX, + RADEON_LY, + RADEON_LZ, + RADEON_QL, + RADEON_QN, + RADEON_QO, + RADEON_Ql, + RADEON_BB, + RADEON_QW, + RADEON_QX, + RADEON_Id, + RADEON_Ie, + RADEON_If, + RADEON_Ig, + RADEON_Ya, + RADEON_Yd, + RADEON_Ld, + RADEON_Le, + RADEON_Lf, + RADEON_Lg, + RADEON_ND, + RADEON_NE, + RADEON_NF, + RADEON_NG, + RADEON_QM +}; + +enum radeon_arch { + RADEON_R100, + RADEON_RV100, + RADEON_R200, + RADEON_RV200, + RADEON_RV250, + RADEON_R300, + RADEON_M6, + RADEON_M7, + RADEON_M9 +}; + +static struct radeon_chip_info { + const char *name; + unsigned char arch; +} radeon_chip_info[] __devinitdata = { + { "QD", RADEON_R100 }, + { "QE", RADEON_R100 }, + { "QF", RADEON_R100 }, + { "QG", RADEON_R100 }, + { "VE QY", RADEON_RV100 }, + { "VE QZ", RADEON_RV100 }, + { "M7 LW", RADEON_M7 }, + { "M7 LX", RADEON_M7 }, + { "M6 LY", RADEON_M6 }, + { "M6 LZ", RADEON_M6 }, + { "8500 QL", RADEON_R200 }, + { "8500 QN", RADEON_R200 }, + { "8500 QO", RADEON_R200 }, + { "8500 Ql", RADEON_R200 }, + { "8500 BB", RADEON_R200 }, + { "7500 QW", RADEON_RV200 }, + { "7500 QX", RADEON_RV200 }, + { "9000 Id", RADEON_RV250 }, + { "9000 Ie", RADEON_RV250 }, + { "9000 If", RADEON_RV250 }, + { "9000 Ig", RADEON_RV250 }, + { "M9 Ld", RADEON_M9 }, + { "M9 Le", RADEON_M9 }, + { "M9 Lf", RADEON_M9 }, + { "M9 Lg", RADEON_M9 }, + { "9700 ND", RADEON_R300 }, + { "9700 NE", RADEON_R300 }, + { "9700 NF", RADEON_R300 }, + { "9700 NG", RADEON_R300 }, + { "9100 QM", RADEON_R200 } +}; + + +enum radeon_montype +{ + MT_NONE, + MT_CRT, /* CRT */ + MT_LCD, /* LCD */ + MT_DFP, /* DVI */ + MT_CTV, /* composite TV */ + MT_STV /* S-Video out */ +}; + + +static struct pci_device_id radeonfb_pci_table[] = { + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QD}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QE}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QF}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QG}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QY, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QY}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QZ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QZ}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LW}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LX}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LY, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LY}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LZ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LZ}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QL}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QN, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QN}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QO}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ql, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ql}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_BB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_BB}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QW}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QX}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Id}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ie, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ie}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_If, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_If}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ig, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ig}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ya, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ya}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Yd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Yd}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ld, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ld}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Le, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Le}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Lf, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Lf}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Lg, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Lg}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_ND, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_ND}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NE}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NF}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NG}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QM}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, radeonfb_pci_table); + + +typedef struct { + u16 reg; + u32 val; +} reg_val; + + +/* these common regs are cleared before mode setting so they do not + * interfere with anything + */ +static reg_val common_regs[] = { + { OVR_CLR, 0 }, + { OVR_WID_LEFT_RIGHT, 0 }, + { OVR_WID_TOP_BOTTOM, 0 }, + { OV0_SCALE_CNTL, 0 }, + { SUBPIC_CNTL, 0 }, + { VIPH_CONTROL, 0 }, + { I2C_CNTL_1, 0 }, + { GEN_INT_CNTL, 0 }, + { CAP0_TRIG_CNTL, 0 }, +}; + +static reg_val common_regs_m6[] = { + { OVR_CLR, 0 }, + { OVR_WID_LEFT_RIGHT, 0 }, + { OVR_WID_TOP_BOTTOM, 0 }, + { OV0_SCALE_CNTL, 0 }, + { SUBPIC_CNTL, 0 }, + { GEN_INT_CNTL, 0 }, + { CAP0_TRIG_CNTL, 0 } +}; + +typedef struct { + u8 clock_chip_type; + u8 struct_size; + u8 accelerator_entry; + u8 VGA_entry; + u16 VGA_table_offset; + u16 POST_table_offset; + u16 XCLK; + u16 MCLK; + u8 num_PLL_blocks; + u8 size_PLL_blocks; + u16 PCLK_ref_freq; + u16 PCLK_ref_divider; + u32 PCLK_min_freq; + u32 PCLK_max_freq; + u16 MCLK_ref_freq; + u16 MCLK_ref_divider; + u32 MCLK_min_freq; + u32 MCLK_max_freq; + u16 XCLK_ref_freq; + u16 XCLK_ref_divider; + u32 XCLK_min_freq; + u32 XCLK_max_freq; +} __attribute__ ((packed)) PLL_BLOCK; + + +struct pll_info { + int ppll_max; + int ppll_min; + int xclk; + int ref_div; + int ref_clk; +}; + + +struct ram_info { + int ml; + int mb; + int trcd; + int trp; + int twr; + int cl; + int tr2w; + int loop_latency; + int rloop; +}; + + +struct radeon_regs { + /* CRTC regs */ + u32 crtc_h_total_disp; + u32 crtc_h_sync_strt_wid; + u32 crtc_v_total_disp; + u32 crtc_v_sync_strt_wid; + u32 crtc_pitch; + u32 crtc_gen_cntl; + u32 crtc_ext_cntl; + u32 dac_cntl; + + u32 flags; + u32 pix_clock; + int xres, yres; + + /* DDA regs */ + u32 dda_config; + u32 dda_on_off; + + /* PLL regs */ + u32 ppll_div_3; + u32 ppll_ref_div; + u32 vclk_ecp_cntl; + + /* Flat panel regs */ + u32 fp_crtc_h_total_disp; + u32 fp_crtc_v_total_disp; + u32 fp_gen_cntl; + u32 fp_h_sync_strt_wid; + u32 fp_horz_stretch; + u32 fp_panel_cntl; + u32 fp_v_sync_strt_wid; + u32 fp_vert_stretch; + u32 lvds_gen_cntl; + u32 lvds_pll_cntl; + u32 tmds_crc; + u32 tmds_transmitter_cntl; + +#if defined(__BIG_ENDIAN) + u32 surface_cntl; +#endif +}; + + +struct radeonfb_info { + struct fb_info info; + + struct radeon_regs state; + struct radeon_regs init_state; + + char name[32]; + char ram_type[12]; + + unsigned long mmio_base_phys; + unsigned long fb_base_phys; + + void __iomem *mmio_base; + void __iomem *fb_base; + + struct pci_dev *pdev; + + unsigned char *EDID; + unsigned char __iomem *bios_seg; + + u32 pseudo_palette[17]; + struct { u8 red, green, blue, pad; } palette[256]; + + int chipset; + unsigned char arch; + int video_ram; + u8 rev; + int pitch, bpp, depth; + int xres, yres, pixclock; + int xres_virtual, yres_virtual; + u32 accel_flags; + + int use_default_var; + int got_dfpinfo; + + int hasCRTC2; + int crtDisp_type; + int dviDisp_type; + + int panel_xres, panel_yres; + int clock; + int hOver_plus, hSync_width, hblank; + int vOver_plus, vSync_width, vblank; + int hAct_high, vAct_high, interlaced; + int synct, misc; + + u32 dp_gui_master_cntl; + + struct pll_info pll; + int pll_output_freq, post_div, fb_div; + + struct ram_info ram; + + int mtrr_hdl; + +#ifdef CONFIG_PMAC_PBOOK + int pm_reg; + u32 save_regs[64]; + u32 mdll, mdll2; +#endif /* CONFIG_PMAC_PBOOK */ + int asleep; + + struct radeonfb_info *next; +}; + + +static struct fb_var_screeninfo radeonfb_default_var = { + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 39721, 40, 24, 32, 11, 96, 2, + 0, FB_VMODE_NONINTERLACED +}; + +/* + * IO macros + */ + +#define INREG8(addr) readb((rinfo->mmio_base)+addr) +#define OUTREG8(addr,val) writeb(val, (rinfo->mmio_base)+addr) +#define INREG(addr) readl((rinfo->mmio_base)+addr) +#define OUTREG(addr,val) writel(val, (rinfo->mmio_base)+addr) + +#define OUTPLL(addr,val) \ + do { \ + OUTREG8(CLOCK_CNTL_INDEX, (addr & 0x0000003f) | 0x00000080); \ + OUTREG(CLOCK_CNTL_DATA, val); \ + } while(0) + +#define OUTPLLP(addr,val,mask) \ + do { \ + unsigned int _tmp = INPLL(addr); \ + _tmp &= (mask); \ + _tmp |= (val); \ + OUTPLL(addr, _tmp); \ + } while (0) + +#define OUTREGP(addr,val,mask) \ + do { \ + unsigned int _tmp = INREG(addr); \ + _tmp &= (mask); \ + _tmp |= (val); \ + OUTREG(addr, _tmp); \ + } while (0) + + +static __inline__ u32 _INPLL(struct radeonfb_info *rinfo, u32 addr) +{ + OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f); + return (INREG(CLOCK_CNTL_DATA)); +} + +#define INPLL(addr) _INPLL(rinfo, addr) + +#define PRIMARY_MONITOR(rinfo) ((rinfo->dviDisp_type != MT_NONE) && \ + (rinfo->dviDisp_type != MT_STV) && \ + (rinfo->dviDisp_type != MT_CTV) ? \ + rinfo->dviDisp_type : rinfo->crtDisp_type) + +static char *GET_MON_NAME(int type) +{ + char *pret = NULL; + + switch (type) { + case MT_NONE: + pret = "no"; + break; + case MT_CRT: + pret = "CRT"; + break; + case MT_DFP: + pret = "DFP"; + break; + case MT_LCD: + pret = "LCD"; + break; + case MT_CTV: + pret = "CTV"; + break; + case MT_STV: + pret = "STV"; + break; + } + + return pret; +} + + +/* + * 2D engine routines + */ + +static __inline__ void radeon_engine_flush (struct radeonfb_info *rinfo) +{ + int i; + + /* initiate flush */ + OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL, + ~RB2D_DC_FLUSH_ALL); + + for (i=0; i < 2000000; i++) { + if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY)) + break; + } +} + + +static __inline__ void _radeon_fifo_wait (struct radeonfb_info *rinfo, int entries) +{ + int i; + + for (i=0; i<2000000; i++) + if ((INREG(RBBM_STATUS) & 0x7f) >= entries) + return; +} + + +static __inline__ void _radeon_engine_idle (struct radeonfb_info *rinfo) +{ + int i; + + /* ensure FIFO is empty before waiting for idle */ + _radeon_fifo_wait (rinfo, 64); + + for (i=0; i<2000000; i++) { + if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) { + radeon_engine_flush (rinfo); + return; + } + } +} + + +#define radeon_engine_idle() _radeon_engine_idle(rinfo) +#define radeon_fifo_wait(entries) _radeon_fifo_wait(rinfo,entries) + + + +/* + * helper routines + */ + +static __inline__ u32 radeon_get_dstbpp(u16 depth) +{ + switch (depth) { + case 8: + return DST_8BPP; + case 15: + return DST_15BPP; + case 16: + return DST_16BPP; + case 32: + return DST_32BPP; + default: + return 0; + } +} + + +static inline int var_to_depth(const struct fb_var_screeninfo *var) +{ + if (var->bits_per_pixel != 16) + return var->bits_per_pixel; + return (var->green.length == 6) ? 16 : 15; +} + + +static void _radeon_engine_reset(struct radeonfb_info *rinfo) +{ + u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset; + + radeon_engine_flush (rinfo); + + clock_cntl_index = INREG(CLOCK_CNTL_INDEX); + mclk_cntl = INPLL(MCLK_CNTL); + + OUTPLL(MCLK_CNTL, (mclk_cntl | + FORCEON_MCLKA | + FORCEON_MCLKB | + FORCEON_YCLKA | + FORCEON_YCLKB | + FORCEON_MC | + FORCEON_AIC)); + rbbm_soft_reset = INREG(RBBM_SOFT_RESET); + + OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset | + SOFT_RESET_CP | + SOFT_RESET_HI | + SOFT_RESET_SE | + SOFT_RESET_RE | + SOFT_RESET_PP | + SOFT_RESET_E2 | + SOFT_RESET_RB); + INREG(RBBM_SOFT_RESET); + OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset & (u32) + ~(SOFT_RESET_CP | + SOFT_RESET_HI | + SOFT_RESET_SE | + SOFT_RESET_RE | + SOFT_RESET_PP | + SOFT_RESET_E2 | + SOFT_RESET_RB)); + INREG(RBBM_SOFT_RESET); + + OUTPLL(MCLK_CNTL, mclk_cntl); + OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index); + OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset); + + return; +} + +#define radeon_engine_reset() _radeon_engine_reset(rinfo) + + +static __inline__ int round_div(int num, int den) +{ + return (num + (den / 2)) / den; +} + + + +static __inline__ int min_bits_req(int val) +{ + int bits_req = 0; + + if (val == 0) + bits_req = 1; + + while (val) { + val >>= 1; + bits_req++; + } + + return (bits_req); +} + + +static __inline__ int _max(int val1, int val2) +{ + if (val1 >= val2) + return val1; + else + return val2; +} + + + +/* + * globals + */ + +#ifndef MODULE +static char *mode_option; +#endif + +static char noaccel = 0; +static char mirror = 0; +static int panel_yres = 0; +static char force_dfp = 0; +static struct radeonfb_info *board_list = NULL; +static char nomtrr = 0; + +/* + * prototypes + */ + +static void radeon_save_state (struct radeonfb_info *rinfo, + struct radeon_regs *save); +static void radeon_engine_init (struct radeonfb_info *rinfo); +static void radeon_write_mode (struct radeonfb_info *rinfo, + struct radeon_regs *mode); +static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo); +static int __devinit radeon_init_disp (struct radeonfb_info *rinfo); +static int radeon_init_disp_var (struct radeonfb_info *rinfo, struct fb_var_screeninfo *var); +static void __iomem *radeon_find_rom(struct radeonfb_info *rinfo); +static void radeon_get_pllinfo(struct radeonfb_info *rinfo, void __iomem *bios_seg); +static void radeon_get_moninfo (struct radeonfb_info *rinfo); +static int radeon_get_dfpinfo (struct radeonfb_info *rinfo); +static int radeon_get_dfpinfo_BIOS(struct radeonfb_info *rinfo); +static void radeon_get_EDID(struct radeonfb_info *rinfo); +static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo); +static void radeon_update_default_var(struct radeonfb_info *rinfo); + +#ifdef CONFIG_PPC_OF + +static int radeon_read_OF (struct radeonfb_info *rinfo); +static int radeon_get_EDID_OF(struct radeonfb_info *rinfo); +extern struct device_node *pci_device_to_OF_node(struct pci_dev *dev); + +#ifdef CONFIG_PMAC_PBOOK +int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier radeon_sleep_notifier = { + radeon_sleep_notify, SLEEP_LEVEL_VIDEO, +}; +#endif /* CONFIG_PMAC_PBOOK */ +#ifdef CONFIG_PMAC_BACKLIGHT +static int radeon_set_backlight_enable(int on, int level, void *data); +static int radeon_set_backlight_level(int level, void *data); +static struct backlight_controller radeon_backlight_controller = { + radeon_set_backlight_enable, + radeon_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ + +#endif /* CONFIG_PPC_OF */ + + +static void __iomem *radeon_find_rom(struct radeonfb_info *rinfo) +{ +#if defined(__i386__) + u32 segstart; + char __iomem *rom_base; + char __iomem *rom; + int stage; + int i,j; + char aty_rom_sig[] = "761295520"; + char *radeon_sig[] = { + "RG6", + "RADEON" + }; + + for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { + + stage = 1; + + rom_base = ioremap(segstart, 0x1000); + + if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa)) + stage = 2; + + + if (stage != 2) { + iounmap(rom_base); + continue; + } + + rom = rom_base; + + for (i = 0; (i < 128 - strlen(aty_rom_sig)) && (stage != 3); i++) { + if (aty_rom_sig[0] == *rom) + if (strncmp(aty_rom_sig, rom, + strlen(aty_rom_sig)) == 0) + stage = 3; + rom++; + } + if (stage != 3) { + iounmap(rom_base); + continue; + } + rom = rom_base; + + for (i = 0; (i < 512) && (stage != 4); i++) { + for(j = 0;j < sizeof(radeon_sig)/sizeof(char *);j++) { + if (radeon_sig[j][0] == *rom) + if (strncmp(radeon_sig[j], rom, + strlen(radeon_sig[j])) == 0) { + stage = 4; + break; + } + } + rom++; + } + if (stage != 4) { + iounmap(rom_base); + continue; + } + + return rom_base; + } +#endif + return NULL; +} + + + + +static void radeon_get_pllinfo(struct radeonfb_info *rinfo, void __iomem *bios_seg) +{ + void __iomem *bios_header; + void __iomem *header_ptr; + u16 bios_header_offset, pll_info_offset; + PLL_BLOCK pll; + + if (bios_seg) { + bios_header = bios_seg + 0x48L; + header_ptr = bios_header; + + bios_header_offset = readw(header_ptr); + bios_header = bios_seg + bios_header_offset; + bios_header += 0x30; + + header_ptr = bios_header; + pll_info_offset = readw(header_ptr); + header_ptr = bios_seg + pll_info_offset; + + memcpy_fromio(&pll, header_ptr, 50); + + rinfo->pll.xclk = (u32)pll.XCLK; + rinfo->pll.ref_clk = (u32)pll.PCLK_ref_freq; + rinfo->pll.ref_div = (u32)pll.PCLK_ref_divider; + rinfo->pll.ppll_min = pll.PCLK_min_freq; + rinfo->pll.ppll_max = pll.PCLK_max_freq; + + printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from BIOS\n", + rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk); + } else { +#ifdef CONFIG_PPC_OF + if (radeon_read_OF(rinfo)) { + unsigned int tmp, Nx, M, ref_div, xclk; + + tmp = INPLL(M_SPLL_REF_FB_DIV); + ref_div = INPLL(PPLL_REF_DIV) & 0x3ff; + + Nx = (tmp & 0xff00) >> 8; + M = (tmp & 0xff); + xclk = ((((2 * Nx * rinfo->pll.ref_clk) + (M)) / + (2 * M))); + + rinfo->pll.xclk = xclk; + rinfo->pll.ref_div = ref_div; + rinfo->pll.ppll_min = 12000; + rinfo->pll.ppll_max = 35000; + + printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from OF\n", + rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk); + + return; + } +#endif + /* no BIOS or BIOS not found, use defaults */ + switch (rinfo->chipset) { + case PCI_DEVICE_ID_ATI_RADEON_QW: + case PCI_DEVICE_ID_ATI_RADEON_QX: + rinfo->pll.ppll_max = 35000; + rinfo->pll.ppll_min = 12000; + rinfo->pll.xclk = 23000; + rinfo->pll.ref_div = 12; + rinfo->pll.ref_clk = 2700; + break; + case PCI_DEVICE_ID_ATI_RADEON_QL: + case PCI_DEVICE_ID_ATI_RADEON_QN: + case PCI_DEVICE_ID_ATI_RADEON_QO: + case PCI_DEVICE_ID_ATI_RADEON_Ql: + case PCI_DEVICE_ID_ATI_RADEON_BB: + rinfo->pll.ppll_max = 35000; + rinfo->pll.ppll_min = 12000; + rinfo->pll.xclk = 27500; + rinfo->pll.ref_div = 12; + rinfo->pll.ref_clk = 2700; + break; + case PCI_DEVICE_ID_ATI_RADEON_Id: + case PCI_DEVICE_ID_ATI_RADEON_Ie: + case PCI_DEVICE_ID_ATI_RADEON_If: + case PCI_DEVICE_ID_ATI_RADEON_Ig: + rinfo->pll.ppll_max = 35000; + rinfo->pll.ppll_min = 12000; + rinfo->pll.xclk = 25000; + rinfo->pll.ref_div = 12; + rinfo->pll.ref_clk = 2700; + break; + case PCI_DEVICE_ID_ATI_RADEON_ND: + case PCI_DEVICE_ID_ATI_RADEON_NE: + case PCI_DEVICE_ID_ATI_RADEON_NF: + case PCI_DEVICE_ID_ATI_RADEON_NG: + rinfo->pll.ppll_max = 40000; + rinfo->pll.ppll_min = 20000; + rinfo->pll.xclk = 27000; + rinfo->pll.ref_div = 12; + rinfo->pll.ref_clk = 2700; + break; + case PCI_DEVICE_ID_ATI_RADEON_QD: + case PCI_DEVICE_ID_ATI_RADEON_QE: + case PCI_DEVICE_ID_ATI_RADEON_QF: + case PCI_DEVICE_ID_ATI_RADEON_QG: + default: + rinfo->pll.ppll_max = 35000; + rinfo->pll.ppll_min = 12000; + rinfo->pll.xclk = 16600; + rinfo->pll.ref_div = 67; + rinfo->pll.ref_clk = 2700; + break; + } + + printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d defaults\n", + rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk); + } +} + + +static void radeon_get_moninfo (struct radeonfb_info *rinfo) +{ + unsigned int tmp; + + if (force_dfp) { + rinfo->dviDisp_type = MT_DFP; + return; + } + + tmp = INREG(BIOS_4_SCRATCH); + printk(KERN_DEBUG "radeon_get_moninfo: bios 4 scratch = %x\n", tmp); + + if (rinfo->hasCRTC2) { + /* primary DVI port */ + if (tmp & 0x08) + rinfo->dviDisp_type = MT_DFP; + else if (tmp & 0x4) + rinfo->dviDisp_type = MT_LCD; + else if (tmp & 0x200) + rinfo->dviDisp_type = MT_CRT; + else if (tmp & 0x10) + rinfo->dviDisp_type = MT_CTV; + else if (tmp & 0x20) + rinfo->dviDisp_type = MT_STV; + + /* secondary CRT port */ + if (tmp & 0x2) + rinfo->crtDisp_type = MT_CRT; + else if (tmp & 0x800) + rinfo->crtDisp_type = MT_DFP; + else if (tmp & 0x400) + rinfo->crtDisp_type = MT_LCD; + else if (tmp & 0x1000) + rinfo->crtDisp_type = MT_CTV; + else if (tmp & 0x2000) + rinfo->crtDisp_type = MT_STV; + } else { + rinfo->dviDisp_type = MT_NONE; + + tmp = INREG(FP_GEN_CNTL); + + if (tmp & FP_EN_TMDS) + rinfo->crtDisp_type = MT_DFP; + else + rinfo->crtDisp_type = MT_CRT; + } +} + + + +static void radeon_get_EDID(struct radeonfb_info *rinfo) +{ +#ifdef CONFIG_PPC_OF + if (!radeon_get_EDID_OF(rinfo)) + RTRACE("radeonfb: could not retrieve EDID from OF\n"); +#else + /* XXX use other methods later */ +#endif +} + + +#ifdef CONFIG_PPC_OF +static int radeon_get_EDID_OF(struct radeonfb_info *rinfo) +{ + struct device_node *dp; + unsigned char *pedid = NULL; + static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", NULL }; + int i; + + dp = pci_device_to_OF_node(rinfo->pdev); + while (dp != NULL) { + for (i = 0; propnames[i] != NULL; ++i) { + pedid = (unsigned char *) + get_property(dp, propnames[i], NULL); + if (pedid != NULL) { + rinfo->EDID = pedid; + return 1; + } + } + dp = dp->child; + } + return 0; +} +#endif /* CONFIG_PPC_OF */ + + +static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo) +{ + unsigned char *block = rinfo->EDID; + + if (!block) + return 0; + + /* jump to the detailed timing block section */ + block += 54; + + rinfo->clock = (block[0] + (block[1] << 8)); + rinfo->panel_xres = (block[2] + ((block[4] & 0xf0) << 4)); + rinfo->hblank = (block[3] + ((block[4] & 0x0f) << 8)); + rinfo->panel_yres = (block[5] + ((block[7] & 0xf0) << 4)); + rinfo->vblank = (block[6] + ((block[7] & 0x0f) << 8)); + rinfo->hOver_plus = (block[8] + ((block[11] & 0xc0) << 2)); + rinfo->hSync_width = (block[9] + ((block[11] & 0x30) << 4)); + rinfo->vOver_plus = ((block[10] >> 4) + ((block[11] & 0x0c) << 2)); + rinfo->vSync_width = ((block[10] & 0x0f) + ((block[11] & 0x03) << 4)); + rinfo->interlaced = ((block[17] & 0x80) >> 7); + rinfo->synct = ((block[17] & 0x18) >> 3); + rinfo->misc = ((block[17] & 0x06) >> 1); + rinfo->hAct_high = rinfo->vAct_high = 0; + if (rinfo->synct == 3) { + if (rinfo->misc & 2) + rinfo->hAct_high = 1; + if (rinfo->misc & 1) + rinfo->vAct_high = 1; + } + + printk("radeonfb: detected DFP panel size from EDID: %dx%d\n", + rinfo->panel_xres, rinfo->panel_yres); + + rinfo->got_dfpinfo = 1; + + return 1; +} + + +static void radeon_update_default_var(struct radeonfb_info *rinfo) +{ + struct fb_var_screeninfo *var = &radeonfb_default_var; + + var->xres = rinfo->panel_xres; + var->yres = rinfo->panel_yres; + var->xres_virtual = rinfo->panel_xres; + var->yres_virtual = rinfo->panel_yres; + var->xoffset = var->yoffset = 0; + var->bits_per_pixel = 8; + var->pixclock = 100000000 / rinfo->clock; + var->left_margin = (rinfo->hblank - rinfo->hOver_plus - rinfo->hSync_width); + var->right_margin = rinfo->hOver_plus; + var->upper_margin = (rinfo->vblank - rinfo->vOver_plus - rinfo->vSync_width); + var->lower_margin = rinfo->vOver_plus; + var->hsync_len = rinfo->hSync_width; + var->vsync_len = rinfo->vSync_width; + var->sync = 0; + if (rinfo->synct == 3) { + if (rinfo->hAct_high) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (rinfo->vAct_high) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + } + + var->vmode = 0; + if (rinfo->interlaced) + var->vmode |= FB_VMODE_INTERLACED; + + rinfo->use_default_var = 1; +} + + +static int radeon_get_dfpinfo_BIOS(struct radeonfb_info *rinfo) +{ + char __iomem *fpbiosstart, *tmp, *tmp0; + char stmp[30]; + int i; + + if (!rinfo->bios_seg) + return 0; + + if (!(fpbiosstart = rinfo->bios_seg + readw(rinfo->bios_seg + 0x48))) { + printk("radeonfb: Failed to detect DFP panel info using BIOS\n"); + return 0; + } + + if (!(tmp = rinfo->bios_seg + readw(fpbiosstart + 0x40))) { + printk("radeonfb: Failed to detect DFP panel info using BIOS\n"); + return 0; + } + + for(i=0; i<24; i++) + stmp[i] = readb(tmp+i+1); + stmp[24] = 0; + printk("radeonfb: panel ID string: %s\n", stmp); + rinfo->panel_xres = readw(tmp + 25); + rinfo->panel_yres = readw(tmp + 27); + printk("radeonfb: detected DFP panel size from BIOS: %dx%d\n", + rinfo->panel_xres, rinfo->panel_yres); + + for(i=0; i<32; i++) { + tmp0 = rinfo->bios_seg + readw(tmp+64+i*2); + if (tmp0 == 0) + break; + if ((readw(tmp0) == rinfo->panel_xres) && + (readw(tmp0+2) == rinfo->panel_yres)) { + rinfo->hblank = (readw(tmp0+17) - readw(tmp0+19)) * 8; + rinfo->hOver_plus = ((readw(tmp0+21) - readw(tmp0+19) -1) * 8) & 0x7fff; + rinfo->hSync_width = readb(tmp0+23) * 8; + rinfo->vblank = readw(tmp0+24) - readw(tmp0+26); + rinfo->vOver_plus = (readw(tmp0+28) & 0x7ff) - readw(tmp0+26); + rinfo->vSync_width = (readw(tmp0+28) & 0xf800) >> 11; + rinfo->clock = readw(tmp0+9); + + rinfo->got_dfpinfo = 1; + return 1; + } + } + + return 0; +} + + + +static int radeon_get_dfpinfo (struct radeonfb_info *rinfo) +{ + unsigned int tmp; + unsigned short a, b; + + if (radeon_get_dfpinfo_BIOS(rinfo)) + radeon_update_default_var(rinfo); + + if (radeon_dfp_parse_EDID(rinfo)) + radeon_update_default_var(rinfo); + + if (!rinfo->got_dfpinfo) { + /* + * it seems all else has failed now and we + * resort to probing registers for our DFP info + */ + if (panel_yres) { + rinfo->panel_yres = panel_yres; + } else { + tmp = INREG(FP_VERT_STRETCH); + tmp &= 0x00fff000; + rinfo->panel_yres = (unsigned short)(tmp >> 0x0c) + 1; + } + + switch (rinfo->panel_yres) { + case 480: + rinfo->panel_xres = 640; + break; + case 600: + rinfo->panel_xres = 800; + break; + case 768: +#if defined(__powerpc__) + if (rinfo->dviDisp_type == MT_LCD) + rinfo->panel_xres = 1152; + else +#endif + rinfo->panel_xres = 1024; + break; + case 1024: + rinfo->panel_xres = 1280; + break; + case 1050: + rinfo->panel_xres = 1400; + break; + case 1200: + rinfo->panel_xres = 1600; + break; + default: + printk("radeonfb: Failed to detect DFP panel size\n"); + return 0; + } + + printk("radeonfb: detected DFP panel size from registers: %dx%d\n", + rinfo->panel_xres, rinfo->panel_yres); + + tmp = INREG(FP_CRTC_H_TOTAL_DISP); + a = (tmp & FP_CRTC_H_TOTAL_MASK) + 4; + b = (tmp & 0x01ff0000) >> FP_CRTC_H_DISP_SHIFT; + rinfo->hblank = (a - b + 1) * 8; + + tmp = INREG(FP_H_SYNC_STRT_WID); + rinfo->hOver_plus = (unsigned short) ((tmp & FP_H_SYNC_STRT_CHAR_MASK) >> + FP_H_SYNC_STRT_CHAR_SHIFT) - b - 1; + rinfo->hOver_plus *= 8; + rinfo->hSync_width = (unsigned short) ((tmp & FP_H_SYNC_WID_MASK) >> + FP_H_SYNC_WID_SHIFT); + rinfo->hSync_width *= 8; + tmp = INREG(FP_CRTC_V_TOTAL_DISP); + a = (tmp & FP_CRTC_V_TOTAL_MASK) + 1; + b = (tmp & FP_CRTC_V_DISP_MASK) >> FP_CRTC_V_DISP_SHIFT; + rinfo->vblank = a - b /* + 24 */ ; + + tmp = INREG(FP_V_SYNC_STRT_WID); + rinfo->vOver_plus = (unsigned short) (tmp & FP_V_SYNC_STRT_MASK) + - b + 1; + rinfo->vSync_width = (unsigned short) ((tmp & FP_V_SYNC_WID_MASK) >> + FP_V_SYNC_WID_SHIFT); + + return 1; + } + + return 1; +} + + +#ifdef CONFIG_PPC_OF +static int radeon_read_OF (struct radeonfb_info *rinfo) +{ + struct device_node *dp; + unsigned int *xtal; + + dp = pci_device_to_OF_node(rinfo->pdev); + + xtal = (unsigned int *) get_property(dp, "ATY,RefCLK", NULL); + + rinfo->pll.ref_clk = *xtal / 10; + + if (*xtal) + return 1; + else + return 0; +} +#endif + + +static void radeon_engine_init (struct radeonfb_info *rinfo) +{ + u32 temp; + + /* disable 3D engine */ + OUTREG(RB3D_CNTL, 0); + + radeon_engine_reset (); + + radeon_fifo_wait (1); + OUTREG(RB2D_DSTCACHE_MODE, 0); + + radeon_fifo_wait (1); + temp = INREG(DEFAULT_PITCH_OFFSET); + OUTREG(DEFAULT_PITCH_OFFSET, ((temp & 0xc0000000) | + (rinfo->pitch << 0x16))); + + radeon_fifo_wait (1); + OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN); + + radeon_fifo_wait (1); + OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX | + DEFAULT_SC_BOTTOM_MAX)); + + temp = radeon_get_dstbpp(rinfo->depth); + rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS); + radeon_fifo_wait (1); + OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl | + GMC_BRUSH_SOLID_COLOR | + GMC_SRC_DATATYPE_COLOR)); + + radeon_fifo_wait (7); + + /* clear line drawing regs */ + OUTREG(DST_LINE_START, 0); + OUTREG(DST_LINE_END, 0); + + /* set brush color regs */ + OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff); + OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000); + + /* set source color regs */ + OUTREG(DP_SRC_FRGD_CLR, 0xffffffff); + OUTREG(DP_SRC_BKGD_CLR, 0x00000000); + + /* default write mask */ + OUTREG(DP_WRITE_MSK, 0xffffffff); + + radeon_engine_idle (); +} + + +static int __devinit radeon_init_disp (struct radeonfb_info *rinfo) +{ + struct fb_info *info = &rinfo->info; + struct fb_var_screeninfo var; + + var = radeonfb_default_var; + if ((radeon_init_disp_var(rinfo, &var)) < 0) + return -1; + + rinfo->depth = var_to_depth(&var); + rinfo->bpp = var.bits_per_pixel; + + info->var = var; + fb_alloc_cmap(&info->cmap, 256, 0); + + var.activate = FB_ACTIVATE_NOW; + return 0; +} + + +static int radeon_init_disp_var (struct radeonfb_info *rinfo, + struct fb_var_screeninfo *var) +{ +#ifndef MODULE + if (mode_option) + fb_find_mode (var, &rinfo->info, mode_option, + NULL, 0, NULL, 8); + else +#endif + if (rinfo->use_default_var) + /* We will use the modified default far */ + *var = radeonfb_default_var; + else + + fb_find_mode (var, &rinfo->info, "640x480-8@60", + NULL, 0, NULL, 0); + + if (noaccel) + var->accel_flags &= ~FB_ACCELF_TEXT; + else + var->accel_flags |= FB_ACCELF_TEXT; + + return 0; +} + + +static int radeon_do_maximize(struct radeonfb_info *rinfo, + struct fb_var_screeninfo *var, + struct fb_var_screeninfo *v, + int nom, int den) +{ + static struct { + int xres, yres; + } modes[] = { + {1600, 1280}, + {1280, 1024}, + {1024, 768}, + {800, 600}, + {640, 480}, + {-1, -1} + }; + int i; + + /* use highest possible virtual resolution */ + if (v->xres_virtual == -1 && v->yres_virtual == -1) { + printk("radeonfb: using max available virtual resolution\n"); + for (i=0; modes[i].xres != -1; i++) { + if (modes[i].xres * nom / den * modes[i].yres < + rinfo->video_ram / 2) + break; + } + if (modes[i].xres == -1) { + printk("radeonfb: could not find virtual resolution that fits into video memory!\n"); + return -EINVAL; + } + v->xres_virtual = modes[i].xres; + v->yres_virtual = modes[i].yres; + + printk("radeonfb: virtual resolution set to max of %dx%d\n", + v->xres_virtual, v->yres_virtual); + } else if (v->xres_virtual == -1) { + v->xres_virtual = (rinfo->video_ram * den / + (nom * v->yres_virtual * 2)) & ~15; + } else if (v->yres_virtual == -1) { + v->xres_virtual = (v->xres_virtual + 15) & ~15; + v->yres_virtual = rinfo->video_ram * den / + (nom * v->xres_virtual *2); + } else { + if (v->xres_virtual * nom / den * v->yres_virtual > + rinfo->video_ram) { + return -EINVAL; + } + } + + if (v->xres_virtual * nom / den >= 8192) { + v->xres_virtual = 8192 * den / nom - 16; + } + + if (v->xres_virtual < v->xres) + return -EINVAL; + + if (v->yres_virtual < v->yres) + return -EINVAL; + + return 0; +} + + +static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info->par; + struct fb_var_screeninfo v; + int nom, den; + + memcpy (&v, var, sizeof (v)); + + switch (v.bits_per_pixel) { + case 0 ... 8: + v.bits_per_pixel = 8; + break; + case 9 ... 16: + v.bits_per_pixel = 16; + break; + case 17 ... 24: +#if 0 /* Doesn't seem to work */ + v.bits_per_pixel = 24; + break; +#endif + return -EINVAL; + case 25 ... 32: + v.bits_per_pixel = 32; + break; + default: + return -EINVAL; + } + + switch (var_to_depth(&v)) { + case 8: + nom = den = 1; + v.red.offset = v.green.offset = v.blue.offset = 0; + v.red.length = v.green.length = v.blue.length = 8; + v.transp.offset = v.transp.length = 0; + break; + case 15: + nom = 2; + den = 1; + v.red.offset = 10; + v.green.offset = 5; + v.blue.offset = 0; + v.red.length = v.green.length = v.blue.length = 5; + v.transp.offset = v.transp.length = 0; + break; + case 16: + nom = 2; + den = 1; + v.red.offset = 11; + v.green.offset = 5; + v.blue.offset = 0; + v.red.length = 5; + v.green.length = 6; + v.blue.length = 5; + v.transp.offset = v.transp.length = 0; + break; + case 24: + nom = 4; + den = 1; + v.red.offset = 16; + v.green.offset = 8; + v.blue.offset = 0; + v.red.length = v.blue.length = v.green.length = 8; + v.transp.offset = v.transp.length = 0; + break; + case 32: + nom = 4; + den = 1; + v.red.offset = 16; + v.green.offset = 8; + v.blue.offset = 0; + v.red.length = v.blue.length = v.green.length = 8; + v.transp.offset = 24; + v.transp.length = 8; + break; + default: + printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + + if (radeon_do_maximize(rinfo, var, &v, nom, den) < 0) + return -EINVAL; + + if (v.xoffset < 0) + v.xoffset = 0; + if (v.yoffset < 0) + v.yoffset = 0; + + if (v.xoffset > v.xres_virtual - v.xres) + v.xoffset = v.xres_virtual - v.xres - 1; + + if (v.yoffset > v.yres_virtual - v.yres) + v.yoffset = v.yres_virtual - v.yres - 1; + + v.red.msb_right = v.green.msb_right = v.blue.msb_right = + v.transp.offset = v.transp.length = + v.transp.msb_right = 0; + + if (noaccel) + v.accel_flags = 0; + + memcpy(var, &v, sizeof(v)); + + return 0; +} + + +static int radeonfb_pan_display (struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + + if ((var->xoffset + var->xres > var->xres_virtual) + || (var->yoffset + var->yres > var->yres_virtual)) + return -EINVAL; + + if (rinfo->asleep) + return 0; + + OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset) + * var->bits_per_pixel / 8) & ~7); + return 0; +} + + +static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + unsigned int tmp; + u32 value = 0; + int rc; + + switch (cmd) { + /* + * TODO: set mirror accordingly for non-Mobility chipsets with 2 CRTC's + */ + case FBIO_RADEON_SET_MIRROR: + switch (rinfo->arch) { + case RADEON_R100: + case RADEON_RV100: + case RADEON_R200: + case RADEON_RV200: + case RADEON_RV250: + case RADEON_R300: + return -EINVAL; + default: + /* RADEON M6, RADEON_M7, RADEON_M9 */ + break; + } + + rc = get_user(value, (__u32 __user *)arg); + + if (rc) + return rc; + + if (value & 0x01) { + tmp = INREG(LVDS_GEN_CNTL); + + tmp |= (LVDS_ON | LVDS_BLON); + } else { + tmp = INREG(LVDS_GEN_CNTL); + + tmp &= ~(LVDS_ON | LVDS_BLON); + } + + OUTREG(LVDS_GEN_CNTL, tmp); + + if (value & 0x02) { + tmp = INREG(CRTC_EXT_CNTL); + tmp |= CRTC_CRT_ON; + + mirror = 1; + } else { + tmp = INREG(CRTC_EXT_CNTL); + tmp &= ~CRTC_CRT_ON; + + mirror = 0; + } + + OUTREG(CRTC_EXT_CNTL, tmp); + + break; + case FBIO_RADEON_GET_MIRROR: + switch (rinfo->arch) { + case RADEON_R100: + case RADEON_RV100: + case RADEON_R200: + case RADEON_RV200: + case RADEON_RV250: + case RADEON_R300: + return -EINVAL; + default: + /* RADEON M6, RADEON_M7, RADEON_M9 */ + break; + } + + tmp = INREG(LVDS_GEN_CNTL); + if ((LVDS_ON | LVDS_BLON) & tmp) + value |= 0x01; + + tmp = INREG(CRTC_EXT_CNTL); + if (CRTC_CRT_ON & tmp) + value |= 0x02; + + return put_user(value, (__u32 __user *)arg); + default: + return -EINVAL; + } + + return -EINVAL; +} + + +static int radeonfb_blank (int blank, struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + u32 val = INREG(CRTC_EXT_CNTL); + u32 val2 = INREG(LVDS_GEN_CNTL); + + if (rinfo->asleep) + return 0; + +#ifdef CONFIG_PMAC_BACKLIGHT + if (rinfo->dviDisp_type == MT_LCD && _machine == _MACH_Pmac) { + set_backlight_enable(!blank); + return 0; + } +#endif + + /* reset it */ + val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS | + CRTC_VSYNC_DIS); + val2 &= ~(LVDS_DISPLAY_DIS); + + switch (blank) { + case FB_BLANK_UNBLANK: + case FB_BLANK_NORMAL: + break; + case FB_BLANK_VSYNC_SUSPEND: + val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS); + break; + case FB_BLANK_HSYNC_SUSPEND: + val |= (CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS); + break; + case FB_BLANK_POWERDOWN: + val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | + CRTC_HSYNC_DIS); + val2 |= (LVDS_DISPLAY_DIS); + break; + } + + switch (rinfo->dviDisp_type) { + case MT_LCD: + OUTREG(LVDS_GEN_CNTL, val2); + break; + case MT_CRT: + default: + OUTREG(CRTC_EXT_CNTL, val); + break; + } + + /* let fbcon do a soft blank for us */ + return (blank == FB_BLANK_NORMAL) ? 1 : 0; +} + + +static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *) info; + u32 pindex, vclk_cntl; + unsigned int i; + + if (regno > 255) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + rinfo->palette[regno].red = red; + rinfo->palette[regno].green = green; + rinfo->palette[regno].blue = blue; + + /* default */ + pindex = regno; + + if (!rinfo->asleep) { + vclk_cntl = INPLL(VCLK_ECP_CNTL); + OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb); + + if (rinfo->bpp == 16) { + pindex = regno * 8; + + if (rinfo->depth == 16 && regno > 63) + return 1; + if (rinfo->depth == 15 && regno > 31) + return 1; + + /* For 565, the green component is mixed one order below */ + if (rinfo->depth == 16) { + OUTREG(PALETTE_INDEX, pindex>>1); + OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) | + (green << 8) | (rinfo->palette[regno>>1].blue)); + green = rinfo->palette[regno<<1].green; + } + } + + if (rinfo->depth != 16 || regno < 32) { + OUTREG(PALETTE_INDEX, pindex); + OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue); + } + + OUTPLL(VCLK_ECP_CNTL, vclk_cntl); + } + if (regno < 16) { + switch (rinfo->depth) { + case 15: + ((u16 *) (info->pseudo_palette))[regno] = + (regno << 10) | (regno << 5) | regno; + break; + case 16: + ((u16 *) (info->pseudo_palette))[regno] = + (regno << 11) | (regno << 6) | regno; + break; + case 24: + ((u32 *) (info->pseudo_palette))[regno] = + (regno << 16) | (regno << 8) | regno; + break; + case 32: + i = (regno << 8) | regno; + ((u32 *) (info->pseudo_palette))[regno] = + (i << 16) | i; + break; + } + } + return 0; +} + + + +static void radeon_save_state (struct radeonfb_info *rinfo, + struct radeon_regs *save) +{ + /* CRTC regs */ + save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL); + save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL); + save->dac_cntl = INREG(DAC_CNTL); + save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP); + save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID); + save->crtc_v_total_disp = INREG(CRTC_V_TOTAL_DISP); + save->crtc_v_sync_strt_wid = INREG(CRTC_V_SYNC_STRT_WID); + save->crtc_pitch = INREG(CRTC_PITCH); +#if defined(__BIG_ENDIAN) + save->surface_cntl = INREG(SURFACE_CNTL); +#endif + + /* FP regs */ + save->fp_crtc_h_total_disp = INREG(FP_CRTC_H_TOTAL_DISP); + save->fp_crtc_v_total_disp = INREG(FP_CRTC_V_TOTAL_DISP); + save->fp_gen_cntl = INREG(FP_GEN_CNTL); + save->fp_h_sync_strt_wid = INREG(FP_H_SYNC_STRT_WID); + save->fp_horz_stretch = INREG(FP_HORZ_STRETCH); + save->fp_v_sync_strt_wid = INREG(FP_V_SYNC_STRT_WID); + save->fp_vert_stretch = INREG(FP_VERT_STRETCH); + save->lvds_gen_cntl = INREG(LVDS_GEN_CNTL); + save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL); + save->tmds_crc = INREG(TMDS_CRC); + save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL); + save->vclk_ecp_cntl = INPLL(VCLK_ECP_CNTL); +} + + + +static int radeonfb_set_par (struct fb_info *info) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *)info->par; + struct fb_var_screeninfo *mode = &info->var; + struct radeon_regs newmode; + int hTotal, vTotal, hSyncStart, hSyncEnd, + hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync; + u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5}; + u8 hsync_fudge_fp[] = {2, 2, 0, 0, 5, 5}; + u32 dotClock = 1000000000 / mode->pixclock, + sync, h_sync_pol, v_sync_pol; + int freq = dotClock / 10; /* x 100 */ + int xclk_freq, vclk_freq, xclk_per_trans, xclk_per_trans_precise; + int useable_precision, roff, ron; + int min_bits, format = 0; + int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid; + int primary_mon = PRIMARY_MONITOR(rinfo); + int depth = var_to_depth(mode); + int accel = (mode->accel_flags & FB_ACCELF_TEXT) != 0; + + rinfo->xres = mode->xres; + rinfo->yres = mode->yres; + rinfo->xres_virtual = mode->xres_virtual; + rinfo->yres_virtual = mode->yres_virtual; + rinfo->pixclock = mode->pixclock; + + hSyncStart = mode->xres + mode->right_margin; + hSyncEnd = hSyncStart + mode->hsync_len; + hTotal = hSyncEnd + mode->left_margin; + + vSyncStart = mode->yres + mode->lower_margin; + vSyncEnd = vSyncStart + mode->vsync_len; + vTotal = vSyncEnd + mode->upper_margin; + + if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { + if (rinfo->panel_xres < mode->xres) + rinfo->xres = mode->xres = rinfo->panel_xres; + if (rinfo->panel_yres < mode->yres) + rinfo->yres = mode->yres = rinfo->panel_yres; + + hTotal = mode->xres + rinfo->hblank; + hSyncStart = mode->xres + rinfo->hOver_plus; + hSyncEnd = hSyncStart + rinfo->hSync_width; + + vTotal = mode->yres + rinfo->vblank; + vSyncStart = mode->yres + rinfo->vOver_plus; + vSyncEnd = vSyncStart + rinfo->vSync_width; + } + + sync = mode->sync; + h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + + RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n", + hSyncStart, hSyncEnd, hTotal); + RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n", + vSyncStart, vSyncEnd, vTotal); + + hsync_wid = (hSyncEnd - hSyncStart) / 8; + vsync_wid = vSyncEnd - vSyncStart; + if (hsync_wid == 0) + hsync_wid = 1; + else if (hsync_wid > 0x3f) /* max */ + hsync_wid = 0x3f; + + if (vsync_wid == 0) + vsync_wid = 1; + else if (vsync_wid > 0x1f) /* max */ + vsync_wid = 0x1f; + + hSyncPol = mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + vSyncPol = mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + + cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; + + format = radeon_get_dstbpp(depth); + bytpp = mode->bits_per_pixel >> 3; + + if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) + hsync_fudge = hsync_fudge_fp[format-1]; + else + hsync_fudge = hsync_adj_tab[format-1]; + + hsync_start = hSyncStart - 8 + hsync_fudge; + + newmode.crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | + (format << 8); + + if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { + newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN; + if (mirror) + newmode.crtc_ext_cntl |= CRTC_CRT_ON; + + newmode.crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN | + CRTC_INTERLACE_EN); + } else { + newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN | + CRTC_CRT_ON; + } + + newmode.dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN | + DAC_8BIT_EN; + + newmode.crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) | + (((mode->xres / 8) - 1) << 16)); + + newmode.crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) | + (hsync_wid << 16) | (h_sync_pol << 23)); + + newmode.crtc_v_total_disp = ((vTotal - 1) & 0xffff) | + ((mode->yres - 1) << 16); + + newmode.crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) | + (vsync_wid << 16) | (v_sync_pol << 23)); + + if (accel) { + /* We first calculate the engine pitch */ + rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f) + & ~(0x3f)) >> 6; + + /* Then, re-multiply it to get the CRTC pitch */ + newmode.crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8); + } else + newmode.crtc_pitch = (mode->xres_virtual >> 3); + newmode.crtc_pitch |= (newmode.crtc_pitch << 16); + +#if defined(__BIG_ENDIAN) + /* + * 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 + + rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f) + & ~(0x3f)) / 64; + + RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", + newmode.crtc_h_total_disp, newmode.crtc_h_sync_strt_wid); + RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", + newmode.crtc_v_total_disp, newmode.crtc_v_sync_strt_wid); + + newmode.xres = mode->xres; + newmode.yres = mode->yres; + + rinfo->bpp = mode->bits_per_pixel; + rinfo->depth = depth; + + if (freq > rinfo->pll.ppll_max) + freq = rinfo->pll.ppll_max; + if (freq*12 < rinfo->pll.ppll_min) + freq = rinfo->pll.ppll_min / 12; + + { + struct { + int divider; + int bitvalue; + } *post_div, + post_divs[] = { + { 1, 0 }, + { 2, 1 }, + { 4, 2 }, + { 8, 3 }, + { 3, 4 }, + { 16, 5 }, + { 6, 6 }, + { 12, 7 }, + { 0, 0 }, + }; + + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + rinfo->pll_output_freq = post_div->divider * freq; + if (rinfo->pll_output_freq >= rinfo->pll.ppll_min && + rinfo->pll_output_freq <= rinfo->pll.ppll_max) + break; + } + + rinfo->post_div = post_div->divider; + rinfo->fb_div = round_div(rinfo->pll.ref_div*rinfo->pll_output_freq, + rinfo->pll.ref_clk); + newmode.ppll_ref_div = rinfo->pll.ref_div; + newmode.ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16); + } + newmode.vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl; + +#ifdef CONFIG_PPC_OF + /* 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_PPC_OF */ + + RTRACE("post div = 0x%x\n", rinfo->post_div); + RTRACE("fb_div = 0x%x\n", rinfo->fb_div); + RTRACE("ppll_div_3 = 0x%x\n", newmode.ppll_div_3); + + /* DDA */ + vclk_freq = round_div(rinfo->pll.ref_clk * rinfo->fb_div, + rinfo->pll.ref_div * rinfo->post_div); + xclk_freq = rinfo->pll.xclk; + + xclk_per_trans = round_div(xclk_freq * 128, vclk_freq * mode->bits_per_pixel); + + min_bits = min_bits_req(xclk_per_trans); + useable_precision = min_bits + 1; + + xclk_per_trans_precise = round_div((xclk_freq * 128) << (11 - useable_precision), + vclk_freq * mode->bits_per_pixel); + + ron = (4 * rinfo->ram.mb + 3 * _max(rinfo->ram.trcd - 2, 0) + + 2 * rinfo->ram.trp + rinfo->ram.twr + rinfo->ram.cl + rinfo->ram.tr2w + + xclk_per_trans) << (11 - useable_precision); + roff = xclk_per_trans_precise * (32 - 4); + + RTRACE("ron = %d, roff = %d\n", ron, roff); + RTRACE("vclk_freq = %d, per = %d\n", vclk_freq, xclk_per_trans_precise); + + if ((ron + rinfo->ram.rloop) >= roff) { + printk("radeonfb: error ron out of range\n"); + return -EINVAL; + } + + newmode.dda_config = (xclk_per_trans_precise | + (useable_precision << 16) | + (rinfo->ram.rloop << 20)); + newmode.dda_on_off = (ron << 16) | roff; + + if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { + unsigned int hRatio, vRatio; + + /* We force the pixel clock to be always enabled. Allowing it + * to be power managed during blanking would save power, but has + * nasty interactions with the 2D engine & sleep code that haven't + * been solved yet. --BenH + */ + newmode.vclk_ecp_cntl &= ~PIXCLK_DAC_ALWAYS_ONb; + + if (mode->xres > rinfo->panel_xres) + mode->xres = rinfo->panel_xres; + if (mode->yres > rinfo->panel_yres) + mode->yres = rinfo->panel_yres; + + newmode.fp_horz_stretch = (((rinfo->panel_xres / 8) - 1) + << HORZ_PANEL_SHIFT); + newmode.fp_vert_stretch = ((rinfo->panel_yres - 1) + << VERT_PANEL_SHIFT); + + if (mode->xres != rinfo->panel_xres) { + hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX, + rinfo->panel_xres); + newmode.fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) | + (newmode.fp_horz_stretch & + (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH | + HORZ_AUTO_RATIO_INC))); + newmode.fp_horz_stretch |= (HORZ_STRETCH_BLEND | + HORZ_STRETCH_ENABLE); + } + newmode.fp_horz_stretch &= ~HORZ_AUTO_RATIO; + + if (mode->yres != rinfo->panel_yres) { + vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX, + rinfo->panel_yres); + newmode.fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) | + (newmode.fp_vert_stretch & + (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED))); + newmode.fp_vert_stretch |= (VERT_STRETCH_BLEND | + VERT_STRETCH_ENABLE); + } + newmode.fp_vert_stretch &= ~VERT_AUTO_RATIO_EN; + + newmode.fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32) + ~(FP_SEL_CRTC2 | + FP_RMX_HVSYNC_CONTROL_EN | + FP_DFP_SYNC_SEL | + FP_CRT_SYNC_SEL | + FP_CRTC_LOCK_8DOT | + FP_USE_SHADOW_EN | + FP_CRTC_USE_SHADOW_VEND | + FP_CRT_SYNC_ALT)); + + newmode.fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR | + FP_CRTC_DONT_SHADOW_HEND); + + newmode.lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl; + newmode.lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl; + newmode.tmds_crc = rinfo->init_state.tmds_crc; + newmode.tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl; + + if (primary_mon == MT_LCD) { + newmode.lvds_gen_cntl |= (LVDS_ON | LVDS_BLON); + newmode.fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN); + } else { + /* DFP */ + newmode.fp_gen_cntl |= (FP_FPON | FP_TMDS_EN); + newmode.tmds_transmitter_cntl = (TMDS_RAN_PAT_RST | + TMDS_ICHCSEL | TMDS_PLL_EN) & + ~(TMDS_PLLRST); + newmode.crtc_ext_cntl &= ~CRTC_CRT_ON; + } + + newmode.fp_crtc_h_total_disp = (((rinfo->hblank / 8) & 0x3ff) | + (((mode->xres / 8) - 1) << 16)); + newmode.fp_crtc_v_total_disp = (rinfo->vblank & 0xffff) | + ((mode->yres - 1) << 16); + newmode.fp_h_sync_strt_wid = ((rinfo->hOver_plus & 0x1fff) | + (hsync_wid << 16) | (h_sync_pol << 23)); + newmode.fp_v_sync_strt_wid = ((rinfo->vOver_plus & 0xfff) | + (vsync_wid << 16) | (v_sync_pol << 23)); + } + + /* do it! */ + if (!rinfo->asleep) { + radeon_write_mode (rinfo, &newmode); + /* (re)initialize the engine */ + if (noaccel) + radeon_engine_init (rinfo); + + } + /* Update fix */ + if (accel) + info->fix.line_length = rinfo->pitch*64; + else + info->fix.line_length = mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8); + info->fix.visual = rinfo->depth == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + +#ifdef CONFIG_BOOTX_TEXT + /* Update debug text engine */ + btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres, + rinfo->depth, info->fix.line_length); +#endif + + return 0; +} + + +static void radeon_write_mode (struct radeonfb_info *rinfo, + struct radeon_regs *mode) +{ + int i; + int primary_mon = PRIMARY_MONITOR(rinfo); + + radeonfb_blank(VESA_POWERDOWN, (struct fb_info *)rinfo); + + + if (rinfo->arch == RADEON_M6) { + for (i=0; i<8; i++) + OUTREG(common_regs_m6[i].reg, common_regs_m6[i].val); + } else { + for (i=0; i<9; i++) + OUTREG(common_regs[i].reg, common_regs[i].val); + } + + OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl); + OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl, + CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS); + OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING); + OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp); + OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid); + OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp); + OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid); + OUTREG(CRTC_OFFSET, 0); + OUTREG(CRTC_OFFSET_CNTL, 0); + OUTREG(CRTC_PITCH, mode->crtc_pitch); + +#if defined(__BIG_ENDIAN) + OUTREG(SURFACE_CNTL, mode->surface_cntl); +#endif + + while ((INREG(CLOCK_CNTL_INDEX) & PPLL_DIV_SEL_MASK) != + PPLL_DIV_SEL_MASK) { + OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, 0xffff); + } + + OUTPLLP(PPLL_CNTL, PPLL_RESET, 0xffff); + + while ((INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK) != + (mode->ppll_ref_div & PPLL_REF_DIV_MASK)) { + OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK); + } + + while ((INPLL(PPLL_DIV_3) & PPLL_FB3_DIV_MASK) != + (mode->ppll_div_3 & PPLL_FB3_DIV_MASK)) { + OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK); + } + + while ((INPLL(PPLL_DIV_3) & PPLL_POST3_DIV_MASK) != + (mode->ppll_div_3 & PPLL_POST3_DIV_MASK)) { + OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK); + } + + OUTPLL(HTOTAL_CNTL, 0); + + OUTPLLP(PPLL_CNTL, 0, ~PPLL_RESET); + +// OUTREG(DDA_CONFIG, mode->dda_config); +// OUTREG(DDA_ON_OFF, mode->dda_on_off); + + if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { + OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp); + OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp); + OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid); + OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid); + OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch); + OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch); + OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl); + OUTREG(TMDS_CRC, mode->tmds_crc); + OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl); + + if (primary_mon == MT_LCD) { + unsigned int tmp = INREG(LVDS_GEN_CNTL); + + mode->lvds_gen_cntl &= ~LVDS_STATE_MASK; + mode->lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_STATE_MASK); + + if ((tmp & (LVDS_ON | LVDS_BLON)) == + (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON))) { + OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl); + } else { + if (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) { + udelay(1000); + OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl); + } else { + OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl | + LVDS_BLON); + udelay(1000); + OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl); + } + } + } + } + + radeonfb_blank(VESA_NO_BLANKING, (struct fb_info *)rinfo); + + OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl); + + return; +} + +static struct fb_ops radeonfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = radeonfb_check_var, + .fb_set_par = radeonfb_set_par, + .fb_setcolreg = radeonfb_setcolreg, + .fb_pan_display = radeonfb_pan_display, + .fb_blank = radeonfb_blank, + .fb_ioctl = radeonfb_ioctl, +#if 0 + .fb_fillrect = radeonfb_fillrect, + .fb_copyarea = radeonfb_copyarea, + .fb_imageblit = radeonfb_imageblit, + .fb_rasterimg = radeonfb_rasterimg, +#else + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +#endif + .fb_cursor = soft_cursor, +}; + + +static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo) +{ + struct fb_info *info; + + info = &rinfo->info; + + info->par = rinfo; + info->pseudo_palette = rinfo->pseudo_palette; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + info->fbops = &radeonfb_ops; + info->screen_base = rinfo->fb_base; + + /* Fill fix common fields */ + strlcpy(info->fix.id, rinfo->name, sizeof(info->fix.id)); + info->fix.smem_start = rinfo->fb_base_phys; + info->fix.smem_len = rinfo->video_ram; + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.xpanstep = 8; + info->fix.ypanstep = 1; + info->fix.ywrapstep = 0; + info->fix.type_aux = 0; + info->fix.mmio_start = rinfo->mmio_base_phys; + info->fix.mmio_len = RADEON_REGSIZE; + if (noaccel) + info->fix.accel = FB_ACCEL_NONE; + else + info->fix.accel = FB_ACCEL_ATI_RADEON; + + if (radeon_init_disp (rinfo) < 0) + return -1; + + return 0; +} + + +#ifdef CONFIG_PMAC_BACKLIGHT + +/* TODO: Dbl check these tables, we don't go up to full ON backlight + * in these, possibly because we noticed MacOS doesn't, but I'd prefer + * having some more official numbers from ATI + */ +static int backlight_conv_m6[] = { + 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, + 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 +}; +static int backlight_conv_m7[] = { + 0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81, + 0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9 +}; + +#define BACKLIGHT_LVDS_OFF +#undef BACKLIGHT_DAC_OFF + +/* We turn off the LCD completely instead of just dimming the backlight. + * This provides some greater power saving and the display is useless + * without backlight anyway. + */ + +static int radeon_set_backlight_enable(int on, int level, void *data) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *)data; + unsigned int lvds_gen_cntl = INREG(LVDS_GEN_CNTL); + int* conv_table; + + /* 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; + + lvds_gen_cntl |= (LVDS_BL_MOD_EN | LVDS_BLON); + if (on && (level > BACKLIGHT_OFF)) { + lvds_gen_cntl |= LVDS_DIGON; + if (!(lvds_gen_cntl & LVDS_ON)) { + lvds_gen_cntl &= ~LVDS_BLON; + OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); + (void)INREG(LVDS_GEN_CNTL); + mdelay(10); + lvds_gen_cntl |= LVDS_BLON; + OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); + } + lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; + lvds_gen_cntl |= (conv_table[level] << + LVDS_BL_MOD_LEVEL_SHIFT); + lvds_gen_cntl |= (LVDS_ON | LVDS_EN); + lvds_gen_cntl &= ~LVDS_DISPLAY_DIS; + } else { + lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; + lvds_gen_cntl |= (conv_table[0] << + LVDS_BL_MOD_LEVEL_SHIFT); + lvds_gen_cntl |= LVDS_DISPLAY_DIS; + OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); + udelay(10); + lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGON); + } + + OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); + rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; + rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK); + + return 0; +} + +static int radeon_set_backlight_level(int level, void *data) +{ + return radeon_set_backlight_enable(1, level, data); +} +#endif /* CONFIG_PMAC_BACKLIGHT */ + + +#ifdef CONFIG_PMAC_PBOOK + +static u32 dbg_clk; + +/* + * Radeon M6 Power Management code. This code currently only supports + * the mobile chips, it's based from some informations provided by ATI + * along with hours of tracing of MacOS drivers + */ + +static void radeon_pm_save_regs(struct radeonfb_info *rinfo) +{ + rinfo->save_regs[0] = INPLL(PLL_PWRMGT_CNTL); + rinfo->save_regs[1] = INPLL(CLK_PWRMGT_CNTL); + rinfo->save_regs[2] = INPLL(MCLK_CNTL); + rinfo->save_regs[3] = INPLL(SCLK_CNTL); + rinfo->save_regs[4] = INPLL(CLK_PIN_CNTL); + rinfo->save_regs[5] = INPLL(VCLK_ECP_CNTL); + rinfo->save_regs[6] = INPLL(PIXCLKS_CNTL); + rinfo->save_regs[7] = INPLL(MCLK_MISC); + rinfo->save_regs[8] = INPLL(P2PLL_CNTL); + + rinfo->save_regs[9] = INREG(DISP_MISC_CNTL); + rinfo->save_regs[10] = INREG(DISP_PWR_MAN); + rinfo->save_regs[11] = INREG(LVDS_GEN_CNTL); + rinfo->save_regs[12] = INREG(LVDS_PLL_CNTL); + rinfo->save_regs[13] = INREG(TV_DAC_CNTL); + rinfo->save_regs[14] = INREG(BUS_CNTL1); + rinfo->save_regs[15] = INREG(CRTC_OFFSET_CNTL); + rinfo->save_regs[16] = INREG(AGP_CNTL); + rinfo->save_regs[17] = (INREG(CRTC_GEN_CNTL) & 0xfdffffff) | 0x04000000; + rinfo->save_regs[18] = (INREG(CRTC2_GEN_CNTL) & 0xfdffffff) | 0x04000000; + rinfo->save_regs[19] = INREG(GPIOPAD_A); + rinfo->save_regs[20] = INREG(GPIOPAD_EN); + rinfo->save_regs[21] = INREG(GPIOPAD_MASK); + rinfo->save_regs[22] = INREG(ZV_LCDPAD_A); + rinfo->save_regs[23] = INREG(ZV_LCDPAD_EN); + rinfo->save_regs[24] = INREG(ZV_LCDPAD_MASK); + rinfo->save_regs[25] = INREG(GPIO_VGA_DDC); + rinfo->save_regs[26] = INREG(GPIO_DVI_DDC); + rinfo->save_regs[27] = INREG(GPIO_MONID); + rinfo->save_regs[28] = INREG(GPIO_CRT2_DDC); + + rinfo->save_regs[29] = INREG(SURFACE_CNTL); + rinfo->save_regs[30] = INREG(MC_FB_LOCATION); + rinfo->save_regs[31] = INREG(DISPLAY_BASE_ADDR); + rinfo->save_regs[32] = INREG(MC_AGP_LOCATION); + rinfo->save_regs[33] = INREG(CRTC2_DISPLAY_BASE_ADDR); +} + +static void radeon_pm_restore_regs(struct radeonfb_info *rinfo) +{ + OUTPLL(P2PLL_CNTL, rinfo->save_regs[8] & 0xFFFFFFFE); /* First */ + + OUTPLL(PLL_PWRMGT_CNTL, rinfo->save_regs[0]); + OUTPLL(CLK_PWRMGT_CNTL, rinfo->save_regs[1]); + OUTPLL(MCLK_CNTL, rinfo->save_regs[2]); + OUTPLL(SCLK_CNTL, rinfo->save_regs[3]); + OUTPLL(CLK_PIN_CNTL, rinfo->save_regs[4]); + OUTPLL(VCLK_ECP_CNTL, rinfo->save_regs[5]); + OUTPLL(PIXCLKS_CNTL, rinfo->save_regs[6]); + OUTPLL(MCLK_MISC, rinfo->save_regs[7]); + + OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]); + OUTREG(DISP_PWR_MAN, rinfo->save_regs[10]); + OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11]); + OUTREG(LVDS_PLL_CNTL,rinfo->save_regs[12]); + OUTREG(TV_DAC_CNTL, rinfo->save_regs[13]); + OUTREG(BUS_CNTL1, rinfo->save_regs[14]); + OUTREG(CRTC_OFFSET_CNTL, rinfo->save_regs[15]); + OUTREG(AGP_CNTL, rinfo->save_regs[16]); + OUTREG(CRTC_GEN_CNTL, rinfo->save_regs[17]); + OUTREG(CRTC2_GEN_CNTL, rinfo->save_regs[18]); + + // wait VBL before that one ? + OUTPLL(P2PLL_CNTL, rinfo->save_regs[8]); + + OUTREG(GPIOPAD_A, rinfo->save_regs[19]); + OUTREG(GPIOPAD_EN, rinfo->save_regs[20]); + OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]); + OUTREG(ZV_LCDPAD_A, rinfo->save_regs[22]); + OUTREG(ZV_LCDPAD_EN, rinfo->save_regs[23]); + OUTREG(ZV_LCDPAD_MASK, rinfo->save_regs[24]); + OUTREG(GPIO_VGA_DDC, rinfo->save_regs[25]); + OUTREG(GPIO_DVI_DDC, rinfo->save_regs[26]); + OUTREG(GPIO_MONID, rinfo->save_regs[27]); + OUTREG(GPIO_CRT2_DDC, rinfo->save_regs[28]); +} + +static void radeon_pm_disable_iopad(struct radeonfb_info *rinfo) +{ + OUTREG(GPIOPAD_MASK, 0x0001ffff); + OUTREG(GPIOPAD_EN, 0x00000400); + OUTREG(GPIOPAD_A, 0x00000000); + OUTREG(ZV_LCDPAD_MASK, 0x00000000); + OUTREG(ZV_LCDPAD_EN, 0x00000000); + OUTREG(ZV_LCDPAD_A, 0x00000000); + OUTREG(GPIO_VGA_DDC, 0x00030000); + OUTREG(GPIO_DVI_DDC, 0x00000000); + OUTREG(GPIO_MONID, 0x00030000); + OUTREG(GPIO_CRT2_DDC, 0x00000000); +} + +static void radeon_pm_program_v2clk(struct radeonfb_info *rinfo) +{ +// +// u32 reg; +// +// OUTPLL(P2PLL_REF_DIV, 0x0c); +// +// .../... figure out what macos does here +} + +static void radeon_pm_low_current(struct radeonfb_info *rinfo) +{ + u32 reg; + + reg = INREG(BUS_CNTL1); + reg &= ~BUS_CNTL1_MOBILE_PLATFORM_SEL_MASK; + reg |= BUS_CNTL1_AGPCLK_VALID | (1<<BUS_CNTL1_MOBILE_PLATFORM_SEL_SHIFT); + OUTREG(BUS_CNTL1, reg); + + reg = INPLL(PLL_PWRMGT_CNTL); + reg |= PLL_PWRMGT_CNTL_SPLL_TURNOFF | PLL_PWRMGT_CNTL_PPLL_TURNOFF | + PLL_PWRMGT_CNTL_P2PLL_TURNOFF | PLL_PWRMGT_CNTL_TVPLL_TURNOFF; + reg &= ~PLL_PWRMGT_CNTL_SU_MCLK_USE_BCLK; + reg &= ~PLL_PWRMGT_CNTL_MOBILE_SU; + OUTPLL(PLL_PWRMGT_CNTL, reg); + +// reg = INPLL(TV_PLL_CNTL1); +// reg |= TV_PLL_CNTL1__TVPLL_RESET | TV_PLL_CNTL1__TVPLL_SLEEP; +// OUTPLL(TV_PLL_CNTL1, reg); + + reg = INREG(TV_DAC_CNTL); + reg &= ~(TV_DAC_CNTL_BGADJ_MASK |TV_DAC_CNTL_DACADJ_MASK); + reg |=TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD | TV_DAC_CNTL_GDACPD | + TV_DAC_CNTL_BDACPD | + (8<<TV_DAC_CNTL_BGADJ__SHIFT) | (8<<TV_DAC_CNTL_DACADJ__SHIFT); + OUTREG(TV_DAC_CNTL, reg); + + reg = INREG(TMDS_TRANSMITTER_CNTL); + reg &= ~(TMDS_PLL_EN |TMDS_PLLRST); + OUTREG(TMDS_TRANSMITTER_CNTL, reg); + +// lvds_pll_cntl = regr32(g, LVDS_PLL_CNTL); +// lvds_pll_cntl &= ~LVDS_PLL_CNTL__LVDS_PLL_EN; +// lvds_pll_cntl |= LVDS_PLL_CNTL__LVDS_PLL_RESET; +// regw32(g, LVDS_PLL_CNTL, lvds_pll_cntl); + + reg = INREG(DAC_CNTL); + reg &= ~DAC_CMP_EN; + OUTREG(DAC_CNTL, reg); + + reg = INREG(DAC_CNTL2); + reg &= ~DAC2_CMP_EN; + OUTREG(DAC_CNTL2, reg); + + reg = INREG(TV_DAC_CNTL); + reg &= ~TV_DAC_CNTL_DETECT; + OUTREG(TV_DAC_CNTL, reg); +} + +static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo) +{ + /* This code is disabled. It does what is in the pm_init + * function of the MacOS driver code ATI sent me. However, + * it doesn't fix my sleep problem, and is causing other issues + * on wakeup (bascially the machine dying when switching consoles + * I haven't had time to investigate this yet + */ +#if 0 + u32 disp_misc_cntl; + u32 disp_pwr_man; + u32 temp; + + // set SPLL, MPLL, PPLL, P2PLL, TVPLL, SCLK, MCLK, PCLK, P2CLK, + // TCLK and TEST_MODE to 0 + temp = INPLL(CLK_PWRMGT_CNTL); + OUTPLL(CLK_PWRMGT_CNTL , temp & ~0xc00002ff); + + // Turn on Power Management + temp = INPLL(CLK_PWRMGT_CNTL); + OUTPLL(CLK_PWRMGT_CNTL , temp | 0x00000400); + + // Turn off display clock if using mobile chips + temp = INPLL(CLK_PWRMGT_CNTL); + OUTREG(CLK_PWRMGT_CNTL , temp | 0x00100000); + + // Force PIXCLK_ALWAYS_ON and PIXCLK_DAC_ALWAYS_ON + temp = INPLL(VCLK_ECP_CNTL); + OUTPLL(VCLK_ECP_CNTL, temp & ~0x000000c0); + + // Force ECP_FORCE_ON to 1 + temp = INPLL(VCLK_ECP_CNTL); + OUTPLL(VCLK_ECP_CNTL, temp | 0x00040000); + + // Force PIXCLK_BLEND_ALWAYS_ON and PIXCLK_GV_ALWAYS_ON + temp = INPLL(PIXCLKS_CNTL); + OUTPLL(PIXCLKS_CNTL, temp & ~0x00001800); + + // Forcing SCLK_CNTL to ON + OUTPLL(SCLK_CNTL, (INPLL(SCLK_CNTL)& 0x00000007) | 0xffff8000 ); + + // Set PM control over XTALIN pad + temp = INPLL(CLK_PIN_CNTL); + OUTPLL(CLK_PIN_CNTL, temp | 0x00080000); + + // Force MCLK and YCLK and MC as dynamic + temp = INPLL(MCLK_CNTL); + OUTPLL(MCLK_CNTL, temp & 0xffeaffff); + + // PLL_TURNOFF + temp = INPLL(PLL_PWRMGT_CNTL); + OUTPLL(PLL_PWRMGT_CNTL, temp | 0x0000001f); + + // set MOBILE_SU to 1 if M6 or DDR64 is detected + temp = INPLL(PLL_PWRMGT_CNTL); + OUTPLL(PLL_PWRMGT_CNTL, temp | 0x00010000); + + // select PM access mode (PM_MODE_SEL) (use ACPI mode) +// temp = INPLL(PLL_PWRMGT_CNTL); +// OUTPLL(PLL_PWRMGT_CNTL, temp | 0x00002000); + temp = INPLL(PLL_PWRMGT_CNTL); + OUTPLL(PLL_PWRMGT_CNTL, temp & ~0x00002000); + + // set DISP_MISC_CNTL register + disp_misc_cntl = INREG(DISP_MISC_CNTL); + disp_misc_cntl &= ~( DISP_MISC_CNTL_SOFT_RESET_GRPH_PP | + DISP_MISC_CNTL_SOFT_RESET_SUBPIC_PP | + DISP_MISC_CNTL_SOFT_RESET_OV0_PP | + DISP_MISC_CNTL_SOFT_RESET_GRPH_SCLK | + DISP_MISC_CNTL_SOFT_RESET_SUBPIC_SCLK | + DISP_MISC_CNTL_SOFT_RESET_OV0_SCLK | + DISP_MISC_CNTL_SOFT_RESET_GRPH2_PP | + DISP_MISC_CNTL_SOFT_RESET_GRPH2_SCLK | + DISP_MISC_CNTL_SOFT_RESET_LVDS | + DISP_MISC_CNTL_SOFT_RESET_TMDS | + DISP_MISC_CNTL_SOFT_RESET_DIG_TMDS | + DISP_MISC_CNTL_SOFT_RESET_TV); + OUTREG(DISP_MISC_CNTL, disp_misc_cntl); + + // set DISP_PWR_MAN register + disp_pwr_man = INREG(DISP_PWR_MAN); + // clau - 9.29.2000 - changes made to bit23:18 to set to 1 as requested by George + disp_pwr_man |= (DISP_PWR_MAN_DIG_TMDS_ENABLE_RST | + DISP_PWR_MAN_TV_ENABLE_RST | + // DISP_PWR_MAN_AUTO_PWRUP_EN | + DISP_PWR_MAN_DISP_D3_GRPH_RST | + DISP_PWR_MAN_DISP_D3_SUBPIC_RST | + DISP_PWR_MAN_DISP_D3_OV0_RST | + DISP_PWR_MAN_DISP_D1D2_GRPH_RST | + DISP_PWR_MAN_DISP_D1D2_SUBPIC_RST | + DISP_PWR_MAN_DISP_D1D2_OV0_RST); + disp_pwr_man &= ~(DISP_PWR_MAN_DISP_PWR_MAN_D3_CRTC_EN | + DISP_PWR_MAN_DISP2_PWR_MAN_D3_CRTC2_EN| + DISP_PWR_MAN_DISP_D3_RST | + DISP_PWR_MAN_DISP_D3_REG_RST); + OUTREG(DISP_PWR_MAN, disp_pwr_man); + + // clau - 10.24.2000 + // - add in setting for BUS_CNTL1 b27:26 = 0x01 and b31 = 0x1 + // - add in setting for AGP_CNTL b7:0 = 0x20 + // - add in setting for DVI_DDC_DATA_OUT_EN b17:16 = 0x0 + + // the following settings (two lines) are applied at a later part of this function, only on mobile platform + // requres -mobile flag + OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & 0xf3ffffff) | 0x04000000); + OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) | 0x80000000); + OUTREG(AGP_CNTL, (INREG(AGP_CNTL) & 0xffffff00) | 0x20); + OUTREG(GPIO_DVI_DDC, INREG(GPIO_DVI_DDC) & 0xfffcffff); + + // yulee - 12.12.2000 + // A12 only + // EN_MCLK_TRISTATE_IN_SUSPEND@MCLK_MISC = 1 + // ACCESS_REGS_IN_SUSPEND@CLK_PIN_CNTL = 0 + // only on mobile platform + OUTPLL(MCLK_MISC, INPLL(MCLK_MISC) | 0x00040000 ); + + // yulee -12.12.2000 + // AGPCLK_VALID@BUS_CNTL1 = 1 + // MOBILE_PLATFORM_SEL@BUS_CNTL1 = 01 + // CRTC_STEREO_SYNC_OUT_EN@CRTC_OFFSET_CNTL = 0 + // CG_CLK_TO_OUTPIN@CLK_PIN_CNTL = 0 + // only on mobile platform + OUTPLL(CLK_PIN_CNTL, INPLL(CLK_PIN_CNTL ) & 0xFFFFF7FF ); + OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1 ) & 0xF3FFFFFF) | 0x84000000 ); + OUTREG(CRTC_OFFSET_CNTL, INREG(CRTC_OFFSET_CNTL ) & 0xFFEFFFFF ); + + mdelay(100); +#endif + + /* Disable CRTCs */ + OUTREG(CRTC_GEN_CNTL, (INREG(CRTC_GEN_CNTL) & ~CRTC_EN) | CRTC_DISP_REQ_EN_B); + OUTREG(CRTC2_GEN_CNTL, (INREG(CRTC2_GEN_CNTL) & ~CRTC2_EN) | CRTC2_DISP_REQ_EN_B); + (void)INREG(CRTC2_GEN_CNTL); + mdelay(17); +} + +static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend) +{ + u16 pwr_cmd; + + if (!rinfo->pm_reg) + return; + + /* Set the chip into appropriate suspend mode (we use D2, + * D3 would require a compete re-initialization of the chip, + * including PCI config registers, clocks, AGP conf, ...) + */ + if (suspend) { + /* According to ATI, we should program V2CLK here, I have + * to verify what's up exactly + */ + /* Save some registers */ + radeon_pm_save_regs(rinfo); + + /* Check that on M7 too, might work might not. M7 may also + * need explicit enabling of PM + */ + if (rinfo->arch == RADEON_M6) { + /* Program V2CLK */ + radeon_pm_program_v2clk(rinfo); + + /* Disable IO PADs */ + radeon_pm_disable_iopad(rinfo); + + /* Set low current */ + radeon_pm_low_current(rinfo); + + /* Prepare chip for power management */ + radeon_pm_setup_for_suspend(rinfo); + + /* Reset the MDLL */ + OUTPLL(MDLL_CKO, INPLL(MDLL_CKO) | MCKOA_RESET); + (void)INPLL(MDLL_RDCKA); + OUTPLL(MDLL_CKO, INPLL(MDLL_CKO) & ~MCKOA_RESET); + (void)INPLL(MDLL_RDCKA); + } + + /* Switch PCI power managment to D2. */ + for (;;) { + pci_read_config_word( + rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, + &pwr_cmd); + if (pwr_cmd & 2) + break; + pci_write_config_word( + rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, + (pwr_cmd & ~PCI_PM_CTRL_STATE_MASK) | 2); + mdelay(500); + } + } else { + /* Switch back PCI powermanagment to D0 */ + mdelay(200); + pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, 0); + mdelay(500); + + dbg_clk = INPLL(1); + + /* Do we need that on M7 ? */ + if (rinfo->arch == RADEON_M6) { + /* Restore the MDLL */ + OUTPLL(MDLL_CKO, INPLL(MDLL_CKO) & ~MCKOA_RESET); + (void)INPLL(MDLL_CKO); + } + + /* Restore some registers */ + radeon_pm_restore_regs(rinfo); + } +} + +/* + * Save the contents of the framebuffer when we go to sleep, + * and restore it when we wake up again. + */ + +int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + struct radeonfb_info *rinfo; + + for (rinfo = board_list; rinfo != NULL; rinfo = rinfo->next) { + struct fb_fix_screeninfo fix; + int nb; + struct display *disp; + + disp = (rinfo->currcon < 0) ? rinfo->info.disp : &fb_display[rinfo->currcon]; + + switch (rinfo->arch) { + case RADEON_M6: + case RADEON_M7: + case RADEON_M9: + break; + default: + return PBOOK_SLEEP_REFUSE; + } + + radeonfb_get_fix(&fix, fg_console, (struct fb_info *)rinfo); + nb = fb_display[fg_console].var.yres * fix.line_length; + + switch (when) { + case PBOOK_SLEEP_NOW: + acquire_console_sem(); + disp->dispsw = &fbcon_dummy; + + if (!noaccel) { + /* Make sure engine is reset */ + radeon_engine_reset(); + radeon_engine_idle(); + } + + /* Blank display and LCD */ + radeonfb_blank(VESA_POWERDOWN+1, + (struct fb_info *)rinfo); + + /* Sleep */ + rinfo->asleep = 1; + radeon_set_suspend(rinfo, 1); + release_console_sem(); + + break; + case PBOOK_WAKE: + acquire_console_sem(); + /* Wakeup */ + radeon_set_suspend(rinfo, 0); + + if (!noaccel) + radeon_engine_init(rinfo); + rinfo->asleep = 0; + radeon_set_dispsw(rinfo, disp); + radeon_load_video_mode(rinfo, &disp->var); + do_install_cmap(rinfo->currcon < 0 ? 0 : rinfo->currcon, + (struct fb_info *)rinfo); + + radeonfb_blank(0, (struct fb_info *)rinfo); + release_console_sem(); + printk("CLK_PIN_CNTL on wakeup was: %08x\n", dbg_clk); + break; + } + } + + return PBOOK_SLEEP_OK; +} + +#endif /* CONFIG_PMAC_PBOOK */ + +static int radeonfb_pci_register (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct radeonfb_info *rinfo; + struct radeon_chip_info *rci = &radeon_chip_info[ent->driver_data]; + u32 tmp; + + RTRACE("radeonfb_pci_register BEGIN\n"); + + /* Enable device in PCI config */ + if (pci_enable_device(pdev) != 0) { + printk(KERN_ERR "radeonfb: Cannot enable PCI device\n"); + return -ENODEV; + } + + rinfo = kmalloc (sizeof (struct radeonfb_info), GFP_KERNEL); + if (!rinfo) { + printk ("radeonfb: could not allocate memory\n"); + return -ENODEV; + } + + memset (rinfo, 0, sizeof (struct radeonfb_info)); + //info = &rinfo->info; + rinfo->pdev = pdev; + strcpy(rinfo->name, rci->name); + rinfo->arch = rci->arch; + + /* Set base addrs */ + rinfo->fb_base_phys = pci_resource_start (pdev, 0); + rinfo->mmio_base_phys = pci_resource_start (pdev, 2); + + /* request the mem regions */ + if (!request_mem_region (rinfo->fb_base_phys, + pci_resource_len(pdev, 0), "radeonfb")) { + printk ("radeonfb: cannot reserve FB region\n"); + kfree (rinfo); + return -ENODEV; + } + + if (!request_mem_region (rinfo->mmio_base_phys, + pci_resource_len(pdev, 2), "radeonfb")) { + printk ("radeonfb: cannot reserve MMIO region\n"); + release_mem_region (rinfo->fb_base_phys, + pci_resource_len(pdev, 0)); + kfree (rinfo); + return -ENODEV; + } + + /* map the regions */ + rinfo->mmio_base = ioremap (rinfo->mmio_base_phys, RADEON_REGSIZE); + if (!rinfo->mmio_base) { + printk ("radeonfb: cannot map MMIO\n"); + release_mem_region (rinfo->mmio_base_phys, + pci_resource_len(pdev, 2)); + release_mem_region (rinfo->fb_base_phys, + pci_resource_len(pdev, 0)); + kfree (rinfo); + return -ENODEV; + } + + rinfo->chipset = pdev->device; + + switch (rinfo->arch) { + case RADEON_R100: + rinfo->hasCRTC2 = 0; + break; + default: + /* all the rest have it */ + rinfo->hasCRTC2 = 1; + break; + } +#if 0 + if (rinfo->arch == RADEON_M7) { + /* + * Noticed some errors in accel with M7, will have to work these out... + */ + noaccel = 1; + } +#endif + if (mirror) + printk("radeonfb: mirroring display to CRT\n"); + + /* framebuffer size */ + tmp = INREG(CONFIG_MEMSIZE); + + /* mem size is bits [28:0], mask off the rest */ + rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK; + + /* ram type */ + tmp = INREG(MEM_SDRAM_MODE_REG); + switch ((MEM_CFG_TYPE & tmp) >> 30) { + case 0: + /* SDR SGRAM (2:1) */ + strcpy(rinfo->ram_type, "SDR SGRAM"); + rinfo->ram.ml = 4; + rinfo->ram.mb = 4; + rinfo->ram.trcd = 1; + rinfo->ram.trp = 2; + rinfo->ram.twr = 1; + rinfo->ram.cl = 2; + rinfo->ram.loop_latency = 16; + rinfo->ram.rloop = 16; + + break; + case 1: + /* DDR SGRAM */ + strcpy(rinfo->ram_type, "DDR SGRAM"); + rinfo->ram.ml = 4; + rinfo->ram.mb = 4; + rinfo->ram.trcd = 3; + rinfo->ram.trp = 3; + rinfo->ram.twr = 2; + rinfo->ram.cl = 3; + rinfo->ram.tr2w = 1; + rinfo->ram.loop_latency = 16; + rinfo->ram.rloop = 16; + + break; + default: + /* 64-bit SDR SGRAM */ + strcpy(rinfo->ram_type, "SDR SGRAM 64"); + rinfo->ram.ml = 4; + rinfo->ram.mb = 8; + rinfo->ram.trcd = 3; + rinfo->ram.trp = 3; + rinfo->ram.twr = 1; + rinfo->ram.cl = 3; + rinfo->ram.tr2w = 1; + rinfo->ram.loop_latency = 17; + rinfo->ram.rloop = 17; + + break; + } + + rinfo->bios_seg = radeon_find_rom(rinfo); + radeon_get_pllinfo(rinfo, rinfo->bios_seg); + + /* + * Hack to get around some busted production M6's + * reporting no ram + */ + if (rinfo->video_ram == 0) { + switch (pdev->device) { + case PCI_DEVICE_ID_ATI_RADEON_LY: + case PCI_DEVICE_ID_ATI_RADEON_LZ: + rinfo->video_ram = 8192 * 1024; + break; + default: + break; + } + } + + + RTRACE("radeonfb: probed %s %dk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024)); + +#if !defined(__powerpc__) + radeon_get_moninfo(rinfo); +#else + switch (pdev->device) { + case PCI_DEVICE_ID_ATI_RADEON_LW: + case PCI_DEVICE_ID_ATI_RADEON_LX: + case PCI_DEVICE_ID_ATI_RADEON_LY: + case PCI_DEVICE_ID_ATI_RADEON_LZ: + rinfo->dviDisp_type = MT_LCD; + break; + default: + radeon_get_moninfo(rinfo); + break; + } +#endif + + radeon_get_EDID(rinfo); + + if ((rinfo->dviDisp_type == MT_DFP) || (rinfo->dviDisp_type == MT_LCD) || + (rinfo->crtDisp_type == MT_DFP)) { + if (!radeon_get_dfpinfo(rinfo)) { + iounmap(rinfo->mmio_base); + release_mem_region (rinfo->mmio_base_phys, + pci_resource_len(pdev, 2)); + release_mem_region (rinfo->fb_base_phys, + pci_resource_len(pdev, 0)); + kfree (rinfo); + return -ENODEV; + } + } + + rinfo->fb_base = ioremap (rinfo->fb_base_phys, rinfo->video_ram); + if (!rinfo->fb_base) { + printk ("radeonfb: cannot map FB\n"); + iounmap(rinfo->mmio_base); + release_mem_region (rinfo->mmio_base_phys, + pci_resource_len(pdev, 2)); + release_mem_region (rinfo->fb_base_phys, + pci_resource_len(pdev, 0)); + kfree (rinfo); + return -ENODEV; + } + + /* I SHOULD FIX THAT CRAP ! I should probably mimmic XFree DRI + * driver setup here. + * + * On PPC, OF based cards setup the internal memory + * mapping in strange ways. We change it so that the + * framebuffer is mapped at 0 and given half of the card's + * address space (2Gb). AGP is mapped high (0xe0000000) and + * can use up to 512Mb. Once DRI is fully implemented, we + * will have to setup the PCI remapper to remap the agp_special_page + * memory page somewhere between those regions so that the card + * use a normal PCI bus master cycle to access the ring read ptr. + * --BenH. + */ +#ifdef CONFIG_ALL_PPC + if (rinfo->hasCRTC2) + OUTREG(CRTC2_GEN_CNTL, + (INREG(CRTC2_GEN_CNTL) & ~CRTC2_EN) | CRTC2_DISP_REQ_EN_B); + OUTREG(CRTC_EXT_CNTL, INREG(CRTC_EXT_CNTL) | CRTC_DISPLAY_DIS); + OUTREG(MC_FB_LOCATION, 0x7fff0000); + OUTREG(MC_AGP_LOCATION, 0xffffe000); + OUTREG(DISPLAY_BASE_ADDR, 0x00000000); + if (rinfo->hasCRTC2) + OUTREG(CRTC2_DISPLAY_BASE_ADDR, 0x00000000); + OUTREG(SRC_OFFSET, 0x00000000); + OUTREG(DST_OFFSET, 0x00000000); + mdelay(10); + OUTREG(CRTC_EXT_CNTL, INREG(CRTC_EXT_CNTL) & ~CRTC_DISPLAY_DIS); +#endif /* CONFIG_ALL_PPC */ + + /* save current mode regs before we switch into the new one + * so we can restore this upon __exit + */ + radeon_save_state (rinfo, &rinfo->init_state); + + /* set all the vital stuff */ + radeon_set_fbinfo (rinfo); + + pci_set_drvdata(pdev, rinfo); + rinfo->next = board_list; + board_list = rinfo; + ((struct fb_info *) rinfo)->device = &pdev->dev; + if (register_framebuffer ((struct fb_info *) rinfo) < 0) { + printk ("radeonfb: could not register framebuffer\n"); + iounmap(rinfo->fb_base); + iounmap(rinfo->mmio_base); + release_mem_region (rinfo->mmio_base_phys, + pci_resource_len(pdev, 2)); + release_mem_region (rinfo->fb_base_phys, + pci_resource_len(pdev, 0)); + kfree (rinfo); + return -ENODEV; + } + +#ifdef CONFIG_MTRR + rinfo->mtrr_hdl = nomtrr ? -1 : mtrr_add(rinfo->fb_base_phys, + rinfo->video_ram, + MTRR_TYPE_WRCOMB, 1); +#endif + +#ifdef CONFIG_PMAC_BACKLIGHT + if (rinfo->dviDisp_type == MT_LCD) + register_backlight_controller(&radeon_backlight_controller, + rinfo, "ati"); +#endif + +#ifdef CONFIG_PMAC_PBOOK + if (rinfo->dviDisp_type == MT_LCD) { + rinfo->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); + pmu_register_sleep_notifier(&radeon_sleep_notifier); + } +#endif + + printk ("radeonfb: ATI Radeon %s %s %d MB\n", rinfo->name, rinfo->ram_type, + (rinfo->video_ram/(1024*1024))); + + if (rinfo->hasCRTC2) { + printk("radeonfb: DVI port %s monitor connected\n", + GET_MON_NAME(rinfo->dviDisp_type)); + printk("radeonfb: CRT port %s monitor connected\n", + GET_MON_NAME(rinfo->crtDisp_type)); + } else { + printk("radeonfb: CRT port %s monitor connected\n", + GET_MON_NAME(rinfo->crtDisp_type)); + } + + RTRACE("radeonfb_pci_register END\n"); + + return 0; +} + + + +static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev) +{ + struct radeonfb_info *rinfo = pci_get_drvdata(pdev); + + if (!rinfo) + return; + + /* restore original state + * + * Doesn't quite work yet, possibly because of the PPC hacking + * I do on startup, disable for now. --BenH + */ + radeon_write_mode (rinfo, &rinfo->init_state); + +#ifdef CONFIG_MTRR + if (rinfo->mtrr_hdl >= 0) + mtrr_del(rinfo->mtrr_hdl, 0, 0); +#endif + + unregister_framebuffer ((struct fb_info *) rinfo); + + iounmap(rinfo->mmio_base); + iounmap(rinfo->fb_base); + + release_mem_region (rinfo->mmio_base_phys, + pci_resource_len(pdev, 2)); + release_mem_region (rinfo->fb_base_phys, + pci_resource_len(pdev, 0)); + + kfree (rinfo); +} + + +static struct pci_driver radeonfb_driver = { + .name = "radeonfb", + .id_table = radeonfb_pci_table, + .probe = radeonfb_pci_register, + .remove = __devexit_p(radeonfb_pci_unregister), +}; + +#ifndef MODULE +static int __init radeonfb_old_setup (char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep (&options, ",")) != NULL) { + if (!*this_opt) + continue; + if (!strncmp(this_opt, "noaccel", 7)) { + noaccel = 1; + } else if (!strncmp(this_opt, "mirror", 6)) { + mirror = 1; + } else if (!strncmp(this_opt, "dfp", 3)) { + force_dfp = 1; + } else if (!strncmp(this_opt, "panel_yres:", 11)) { + panel_yres = simple_strtoul((this_opt+11), NULL, 0); + } else if (!strncmp(this_opt, "nomtrr", 6)) { + nomtrr = 1; + } else + mode_option = this_opt; + } + + return 0; +} +#endif /* MODULE */ + +static int __init radeonfb_old_init (void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("radeonfb_old", &option)) + return -ENODEV; + radeonfb_old_setup(option); +#endif + return pci_register_driver (&radeonfb_driver); +} + + +static void __exit radeonfb_old_exit (void) +{ + pci_unregister_driver (&radeonfb_driver); +} + +module_init(radeonfb_old_init); +module_exit(radeonfb_old_exit); + + +MODULE_AUTHOR("Ani Joshi"); +MODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c new file mode 100644 index 000000000000..5e2c64f622cb --- /dev/null +++ b/drivers/video/retz3fb.c @@ -0,0 +1,1587 @@ +/* + * Linux/drivers/video/retz3fb.c -- RetinaZ3 frame buffer device + * + * Copyright (C) 1997 Jes Sorensen + * + * This file is based on the CyberVision64 frame buffer device and + * the generic Cirrus Logic driver. + * + * cyberfb.c: Copyright (C) 1996 Martin Apel, + * Geert Uytterhoeven + * clgen.c: Copyright (C) 1996 Frank Neumann + * + * History: + * - 22 Jan 97: Initial work + * - 14 Feb 97: Screen initialization works somewhat, still only + * 8-bit packed pixel is supported. + * + * 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/kernel.h> +#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/zorro.h> +#include <linux/init.h> + +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/pgtable.h> +#include <asm/io.h> + +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> + +#include "retz3fb.h" + +/* #define DEBUG if(1) */ +#define DEBUG if(0) + +/* + * Reserve space for one pattern line. + * + * For the time being we only support 4MB boards! + */ + +#define PAT_MEM_SIZE 16*3 +#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE) + +struct retz3fb_par { + int xres; + int yres; + int xres_vir; + int yres_vir; + int xoffset; + int yoffset; + int bpp; + + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + + int pixclock; + int left_margin; /* time from sync to picture */ + int right_margin; /* time from picture to sync */ + int upper_margin; /* time from sync to picture */ + int lower_margin; + int hsync_len; /* length of horizontal sync */ + int vsync_len; /* length of vertical sync */ + int vmode; + + int accel; +}; + +struct display_data { + long h_total; /* Horizontal Total */ + long h_sstart; /* Horizontal Sync Start */ + long h_sstop; /* Horizontal Sync Stop */ + long h_bstart; /* Horizontal Blank Start */ + long h_bstop; /* Horizontal Blank Stop */ + long h_dispend; /* Horizontal Display End */ + long v_total; /* Vertical Total */ + long v_sstart; /* Vertical Sync Start */ + long v_sstop; /* Vertical Sync Stop */ + long v_bstart; /* Vertical Blank Start */ + long v_bstop; /* Vertical Blank Stop */ + long v_dispend; /* Horizontal Display End */ +}; + +struct retz3_fb_info { + struct fb_info info; + unsigned char *base; + unsigned char *fbmem; + unsigned long fbsize; + volatile unsigned char *regs; + unsigned long physfbmem; + unsigned long physregs; + int current_par_valid; /* set to 0 by memset */ + int blitbusy; + struct display disp; + struct retz3fb_par current_par; + unsigned char color_table [256][3]; +}; + + +static char fontname[40] __initdata = { 0 }; + +#define retz3info(info) ((struct retz3_fb_info *)(info)) +#define fbinfo(info) ((struct fb_info *)(info)) + + +/* + * Frame Buffer Name + */ + +static char retz3fb_name[16] = "RetinaZ3"; + + +/* + * A small info on how to convert XFree86 timing values into fb + * timings - by Frank Neumann: + * +An XFree86 mode line consists of the following fields: + "800x600" 50 800 856 976 1040 600 637 643 666 + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + +The fields in the fb_var_screeninfo structure are: + unsigned long pixclock; * pixel clock in ps (pico seconds) * + unsigned long left_margin; * time from sync to picture * + unsigned long right_margin; * time from picture to sync * + unsigned long upper_margin; * time from sync to picture * + unsigned long lower_margin; + unsigned long hsync_len; * length of horizontal sync * + unsigned long vsync_len; * length of vertical sync * + +1) Pixelclock: + xfree: in MHz + fb: In Picoseconds (ps) + + pixclock = 1000000 / DCF + +2) horizontal timings: + left_margin = HFL - SH2 + right_margin = SH1 - HR + hsync_len = SH2 - SH1 + +3) vertical timings: + upper_margin = VFL - SV2 + lower_margin = SV1 - VR + vsync_len = SV2 - SV1 + +Good examples for VESA timings can be found in the XFree86 source tree, +under "programs/Xserver/hw/xfree86/doc/modeDB.txt". +*/ + +/* + * Predefined Video Modes + */ + +static struct { + const char *name; + struct fb_var_screeninfo var; +} retz3fb_predefined[] __initdata = { + /* + * NB: it is very important to adjust the pixel-clock to the color-depth. + */ + + { + "640x480", { /* 640x480, 8 bpp */ + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, 39722, 48, 16, 33, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED + } + }, + /* + ModeLine "800x600" 36 800 824 896 1024 600 601 603 625 + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + */ + { + "800x600", { /* 800x600, 8 bpp */ + 800, 600, 800, 600, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 27778, 64, 24, 22, 1, 120, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + }, + { + "800x600-60", { /* 800x600, 8 bpp */ + 800, 600, 800, 600, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 25000, 88, 40, 23, 1, 128, 4, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + }, + { + "800x600-70", { /* 800x600, 8 bpp */ + 800, 600, 800, 600, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 22272, 40, 24, 15, 9, 144, 12, + FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED + } + }, + /* + ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + */ + { + "1024x768i", { /* 1024x768, 8 bpp, interlaced */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 22222, 40, 40, 32, 9, 160, 8, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED + } + }, + { + "1024x768", { + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + }, + { + "640x480-16", { /* 640x480, 16 bpp */ + 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, 38461/2, 28, 32, 12, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED + } + }, + { + "640x480-24", { /* 640x480, 24 bpp */ + 640, 480, 640, 480, 0, 0, 24, 0, + {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0}, + 0, 0, -1, -1, 0, 38461/3, 28, 32, 12, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED + } + }, +}; + + +#define NUM_TOTAL_MODES ARRAY_SIZE(retz3fb_predefined) + +static struct fb_var_screeninfo retz3fb_default; + +static int z3fb_inverse = 0; +static int z3fb_mode __initdata = 0; + + +/* + * Interface used by the world + */ + +int retz3fb_setup(char *options); + +static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int retz3fb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int retz3fb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int retz3fb_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info); +static int retz3fb_blank(int blank, struct fb_info *info); + + +/* + * Interface to the low level console driver + */ + +int retz3fb_init(void); +static int z3fb_switch(int con, struct fb_info *info); +static int z3fb_updatevar(int con, struct fb_info *info); + + +/* + * Text console acceleration + */ + +#ifdef FBCON_HAS_CFB8 +static struct display_switch fbcon_retz3_8; +#endif + + +/* + * Accelerated Functions used by the low level console driver + */ + +static void retz3_bitblt(struct display *p, + unsigned short curx, unsigned short cury, unsigned + short destx, unsigned short desty, unsigned short + width, unsigned short height, unsigned short cmd, + unsigned short mask); + +/* + * Hardware Specific Routines + */ + +static int retz3_encode_fix(struct fb_info *info, + struct fb_fix_screeninfo *fix, + struct retz3fb_par *par); +static int retz3_decode_var(struct fb_var_screeninfo *var, + struct retz3fb_par *par); +static int retz3_encode_var(struct fb_var_screeninfo *var, + struct retz3fb_par *par); +static int retz3_getcolreg(unsigned int regno, unsigned int *red, + unsigned int *green, unsigned int *blue, + unsigned int *transp, struct fb_info *info); + +/* + * Internal routines + */ + +static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par); +static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par); +static int do_fb_set_var(struct fb_info *info, + struct fb_var_screeninfo *var, int isactive); +static void retz3fb_set_disp(int con, struct fb_info *info); +static int get_video_mode(const char *name); + + +/* -------------------- Hardware specific routines ------------------------- */ + +static unsigned short find_fq(unsigned int freq) +{ + unsigned long f; + long tmp; + long prev = 0x7fffffff; + long n2, n1 = 3; + unsigned long m; + unsigned short res = 0; + + if (freq <= 31250000) + n2 = 3; + else if (freq <= 62500000) + n2 = 2; + else if (freq <= 125000000) + n2 = 1; + else if (freq <= 250000000) + n2 = 0; + else + return 0; + + + do { + f = freq >> (10 - n2); + + m = (f * n1) / (14318180/1024); + + if (m > 129) + break; + + tmp = (((m * 14318180) >> n2) / n1) - freq; + if (tmp < 0) + tmp = -tmp; + + if (tmp < prev) { + prev = tmp; + res = (((n2 << 5) | (n1-2)) << 8) | (m-2); + } + + } while ( (++n1) <= 21); + + return res; +} + + +static int retz3_set_video(struct fb_info *info, + struct fb_var_screeninfo *var, + struct retz3fb_par *par) +{ + volatile unsigned char *regs = retz3info(info)->regs; + unsigned int freq; + + int xres, hfront, hsync, hback; + int yres, vfront, vsync, vback; + unsigned char tmp; + unsigned short best_freq; + struct display_data data; + + short clocksel = 0; /* Apparantly this is always zero */ + + int bpp = var->bits_per_pixel; + + /* + * XXX + */ + if (bpp == 24) + return 0; + + if ((bpp != 8) && (bpp != 16) && (bpp != 24)) + return -EFAULT; + + par->xoffset = 0; + par->yoffset = 0; + + xres = var->xres * bpp / 4; + hfront = var->right_margin * bpp / 4; + hsync = var->hsync_len * bpp / 4; + hback = var->left_margin * bpp / 4; + + if (var->vmode & FB_VMODE_DOUBLE) + { + yres = var->yres * 2; + vfront = var->lower_margin * 2; + vsync = var->vsync_len * 2; + vback = var->upper_margin * 2; + } + else if (var->vmode & FB_VMODE_INTERLACED) + { + yres = (var->yres + 1) / 2; + vfront = (var->lower_margin + 1) / 2; + vsync = (var->vsync_len + 1) / 2; + vback = (var->upper_margin + 1) / 2; + } + else + { + yres = var->yres; /* -1 ? */ + vfront = var->lower_margin; + vsync = var->vsync_len; + vback = var->upper_margin; + } + + data.h_total = (hback / 8) + (xres / 8) + + (hfront / 8) + (hsync / 8) - 1 /* + 1 */; + data.h_dispend = ((xres + bpp - 1)/ 8) - 1; + data.h_bstart = xres / 8 - 1 /* + 1 */; + + data.h_bstop = data.h_total+1 + 2 + 1; + data.h_sstart = (xres / 8) + (hfront / 8) + 1; + data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1; + + data.v_total = yres + vfront + vsync + vback - 1; + + data.v_dispend = yres - 1; + data.v_bstart = yres - 1; + + data.v_bstop = data.v_total; + data.v_sstart = yres + vfront - 1 - 2; + data.v_sstop = yres + vfront + vsync - 1; + +#if 0 /* testing */ + + printk("HBS: %i\n", data.h_bstart); + printk("HSS: %i\n", data.h_sstart); + printk("HSE: %i\n", data.h_sstop); + printk("HBE: %i\n", data.h_bstop); + printk("HT: %i\n", data.h_total); + + printk("hsync: %i\n", hsync); + printk("hfront: %i\n", hfront); + printk("hback: %i\n", hback); + + printk("VBS: %i\n", data.v_bstart); + printk("VSS: %i\n", data.v_sstart); + printk("VSE: %i\n", data.v_sstop); + printk("VBE: %i\n", data.v_bstop); + printk("VT: %i\n", data.v_total); + + printk("vsync: %i\n", vsync); + printk("vfront: %i\n", vfront); + printk("vback: %i\n", vback); +#endif + + if (data.v_total >= 1024) + printk(KERN_ERR "MAYDAY: v_total >= 1024; bailing out!\n"); + + reg_w(regs, GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04)); + reg_w(regs, GREG_FEATURE_CONTROL_W, 0x00); + + seq_w(regs, SEQ_RESET, 0x00); + seq_w(regs, SEQ_RESET, 0x03); /* reset sequencer logic */ + + /* + * CLOCKING_MODE bits: + * 2: This one is only set for certain text-modes, wonder if + * it may be for EGA-lines? (it was referred to as CLKDIV2) + * (The CL drivers sets it to 0x21 with the comment: + * FullBandwidth (video off) and 8/9 dot clock) + */ + seq_w(regs, SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */); + + seq_w(regs, SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */ + seq_w(regs, SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */ + seq_w(regs, SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/ + seq_w(regs, SEQ_RESET, 0x01); + seq_w(regs, SEQ_RESET, 0x03); + + seq_w(regs, SEQ_EXTENDED_ENABLE, 0x05); + + seq_w(regs, SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */ + seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00); + seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00); + seq_w(regs, SEQ_LINEAR_0, 0x4a); + seq_w(regs, SEQ_LINEAR_1, 0x00); + + seq_w(regs, SEQ_SEC_HOST_OFF_HI, 0x00); + seq_w(regs, SEQ_SEC_HOST_OFF_LO, 0x00); + seq_w(regs, SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40); + + /* + * The lower 4 bits (0-3) are used to set the font-width for + * text-mode - DON'T try to set this for gfx-mode. + */ + seq_w(regs, SEQ_EXT_CLOCK_MODE, 0x10); + seq_w(regs, SEQ_EXT_VIDEO_ADDR, 0x03); + + /* + * Extended Pixel Control: + * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?) + * bit 1: (Packed/Nibble Pixel Format ?) + * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp + */ + seq_w(regs, SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4)); + + seq_w(regs, SEQ_BUS_WIDTH_FEEDB, 0x04); + seq_w(regs, SEQ_COLOR_EXP_WFG, 0x01); + seq_w(regs, SEQ_COLOR_EXP_WBG, 0x00); + seq_w(regs, SEQ_EXT_RW_CONTROL, 0x00); + seq_w(regs, SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8))); + seq_w(regs, SEQ_COLOR_KEY_CNTL, 0x40); + seq_w(regs, SEQ_COLOR_KEY_MATCH0, 0x00); + seq_w(regs, SEQ_COLOR_KEY_MATCH1, 0x00); + seq_w(regs, SEQ_COLOR_KEY_MATCH2, 0x00); + seq_w(regs, SEQ_CRC_CONTROL, 0x00); + seq_w(regs, SEQ_PERF_SELECT, 0x10); + seq_w(regs, SEQ_ACM_APERTURE_1, 0x00); + seq_w(regs, SEQ_ACM_APERTURE_2, 0x30); + seq_w(regs, SEQ_ACM_APERTURE_3, 0x00); + seq_w(regs, SEQ_MEMORY_MAP_CNTL, 0x03); + + + /* unlock register CRT0..CRT7 */ + crt_w(regs, CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20); + + /* Zuerst zu schreibende Werte nur per printk ausgeben */ + DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total); + crt_w(regs, CRT_HOR_TOTAL, data.h_total & 0xff); + + DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend); + crt_w(regs, CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff); + + DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart); + crt_w(regs, CRT_START_HOR_BLANK, data.h_bstart & 0xff); + + DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32); + crt_w(regs, CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f)); + + DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart); + crt_w(regs, CRT_START_HOR_RETR, data.h_sstart & 0xff); + + tmp = (data.h_sstop & 0x1f); + if (data.h_bstop & 0x20) + tmp |= 0x80; + DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp); + crt_w(regs, CRT_END_HOR_RETR, tmp); + + DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff); + crt_w(regs, CRT_VER_TOTAL, (data.v_total & 0xff)); + + tmp = 0x10; /* LineCompare bit #9 */ + if (data.v_total & 256) + tmp |= 0x01; + if (data.v_dispend & 256) + tmp |= 0x02; + if (data.v_sstart & 256) + tmp |= 0x04; + if (data.v_bstart & 256) + tmp |= 0x08; + if (data.v_total & 512) + tmp |= 0x20; + if (data.v_dispend & 512) + tmp |= 0x40; + if (data.v_sstart & 512) + tmp |= 0x80; + DEBUG printk("CRT_OVERFLOW: %d\n", tmp); + crt_w(regs, CRT_OVERFLOW, tmp); + + crt_w(regs, CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */ + + tmp = 0x40; /* LineCompare bit #8 */ + if (data.v_bstart & 512) + tmp |= 0x20; + if (var->vmode & FB_VMODE_DOUBLE) + tmp |= 0x80; + DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp); + crt_w(regs, CRT_MAX_SCAN_LINE, tmp); + + crt_w(regs, CRT_CURSOR_START, 0x00); + crt_w(regs, CRT_CURSOR_END, 8 & 0x1f); /* font height */ + + crt_w(regs, CRT_START_ADDR_HIGH, 0x00); + crt_w(regs, CRT_START_ADDR_LOW, 0x00); + + crt_w(regs, CRT_CURSOR_LOC_HIGH, 0x00); + crt_w(regs, CRT_CURSOR_LOC_LOW, 0x00); + + DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff); + crt_w(regs, CRT_START_VER_RETR, (data.v_sstart & 0xff)); + +#if 1 + /* 5 refresh cycles per scanline */ + DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16); + crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20)); +#else + DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16); + crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32)); +#endif + DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff); + crt_w(regs, CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff)); + + DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff); + crt_w(regs, CRT_START_VER_BLANK, (data.v_bstart & 0xff)); + + DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff); + crt_w(regs, CRT_END_VER_BLANK, (data.v_bstop & 0xff)); + + DEBUG printk("CRT_MODE_CONTROL: 0xe3\n"); + crt_w(regs, CRT_MODE_CONTROL, 0xe3); + + DEBUG printk("CRT_LINE_COMPARE: 0xff\n"); + crt_w(regs, CRT_LINE_COMPARE, 0xff); + + tmp = (var->xres_virtual / 8) * (bpp / 8); + crt_w(regs, CRT_OFFSET, tmp); + + crt_w(regs, CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */ + + tmp = 0x20; /* Enable extended end bits */ + if (data.h_total & 0x100) + tmp |= 0x01; + if ((data.h_dispend) & 0x100) + tmp |= 0x02; + if (data.h_bstart & 0x100) + tmp |= 0x04; + if (data.h_sstart & 0x100) + tmp |= 0x08; + if (var->vmode & FB_VMODE_INTERLACED) + tmp |= 0x10; + DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp); + crt_w(regs, CRT_EXT_HOR_TIMING1, tmp); + + tmp = 0x00; + if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100) + tmp |= 0x10; + crt_w(regs, CRT_EXT_START_ADDR, tmp); + + tmp = 0x00; + if (data.h_total & 0x200) + tmp |= 0x01; + if ((data.h_dispend) & 0x200) + tmp |= 0x02; + if (data.h_bstart & 0x200) + tmp |= 0x04; + if (data.h_sstart & 0x200) + tmp |= 0x08; + tmp |= ((data.h_bstop & 0xc0) >> 2); + tmp |= ((data.h_sstop & 0x60) << 1); + crt_w(regs, CRT_EXT_HOR_TIMING2, tmp); + DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp); + + tmp = 0x10; /* Line compare bit 10 */ + if (data.v_total & 0x400) + tmp |= 0x01; + if ((data.v_dispend) & 0x400) + tmp |= 0x02; + if (data.v_bstart & 0x400) + tmp |= 0x04; + if (data.v_sstart & 0x400) + tmp |= 0x08; + tmp |= ((data.v_bstop & 0x300) >> 3); + if (data.v_sstop & 0x10) + tmp |= 0x80; + crt_w(regs, CRT_EXT_VER_TIMING, tmp); + DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp); + + crt_w(regs, CRT_MONITOR_POWER, 0x00); + + /* + * Convert from ps to Hz. + */ + freq = 2000000000 / var->pixclock; + freq = freq * 500; + + best_freq = find_fq(freq); + pll_w(regs, 0x02, best_freq); + best_freq = find_fq(61000000); + pll_w(regs, 0x0a, best_freq); + pll_w(regs, 0x0e, 0x22); + + gfx_w(regs, GFX_SET_RESET, 0x00); + gfx_w(regs, GFX_ENABLE_SET_RESET, 0x00); + gfx_w(regs, GFX_COLOR_COMPARE, 0x00); + gfx_w(regs, GFX_DATA_ROTATE, 0x00); + gfx_w(regs, GFX_READ_MAP_SELECT, 0x00); + gfx_w(regs, GFX_GRAPHICS_MODE, 0x00); + gfx_w(regs, GFX_MISC, 0x05); + gfx_w(regs, GFX_COLOR_XCARE, 0x0f); + gfx_w(regs, GFX_BITMASK, 0xff); + + reg_r(regs, ACT_ADDRESS_RESET); + attr_w(regs, ACT_PALETTE0 , 0x00); + attr_w(regs, ACT_PALETTE1 , 0x01); + attr_w(regs, ACT_PALETTE2 , 0x02); + attr_w(regs, ACT_PALETTE3 , 0x03); + attr_w(regs, ACT_PALETTE4 , 0x04); + attr_w(regs, ACT_PALETTE5 , 0x05); + attr_w(regs, ACT_PALETTE6 , 0x06); + attr_w(regs, ACT_PALETTE7 , 0x07); + attr_w(regs, ACT_PALETTE8 , 0x08); + attr_w(regs, ACT_PALETTE9 , 0x09); + attr_w(regs, ACT_PALETTE10, 0x0a); + attr_w(regs, ACT_PALETTE11, 0x0b); + attr_w(regs, ACT_PALETTE12, 0x0c); + attr_w(regs, ACT_PALETTE13, 0x0d); + attr_w(regs, ACT_PALETTE14, 0x0e); + attr_w(regs, ACT_PALETTE15, 0x0f); + reg_r(regs, ACT_ADDRESS_RESET); + + attr_w(regs, ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */ + + attr_w(regs, ACT_OVERSCAN_COLOR, 0x00); + attr_w(regs, ACT_COLOR_PLANE_ENA, 0x0f); + attr_w(regs, ACT_HOR_PEL_PANNING, 0x00); + attr_w(regs, ACT_COLOR_SELECT, 0x00); + + reg_r(regs, ACT_ADDRESS_RESET); + reg_w(regs, ACT_DATA, 0x20); + + reg_w(regs, VDAC_MASK, 0xff); + + /* + * Extended palette addressing ??? + */ + switch (bpp){ + case 8: + reg_w(regs, 0x83c6, 0x00); + break; + case 16: + reg_w(regs, 0x83c6, 0x60); + break; + case 24: + reg_w(regs, 0x83c6, 0xe0); + break; + default: + printk(KERN_INFO "Illegal color-depth: %i\n", bpp); + } + + reg_w(regs, VDAC_ADDRESS, 0x00); + + seq_w(regs, SEQ_MAP_MASK, 0x0f ); + + return 0; +} + + +/* + * This function should fill in the `fix' structure based on the + * values in the `par' structure. + */ + +static int retz3_encode_fix(struct fb_info *info, + struct fb_fix_screeninfo *fix, + struct retz3fb_par *par) +{ + struct retz3_fb_info *zinfo = retz3info(info); + + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, retz3fb_name); + fix->smem_start = zinfo->physfbmem; + fix->smem_len = zinfo->fbsize; + fix->mmio_start = zinfo->physregs; + fix->mmio_len = 0x00c00000; + + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + if (par->bpp == 8) + fix->visual = FB_VISUAL_PSEUDOCOLOR; + else + fix->visual = FB_VISUAL_TRUECOLOR; + + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = 0; + + fix->accel = FB_ACCEL_NCR_77C32BLT; + + return 0; +} + + +/* + * Get the video params out of `var'. If a value doesn't fit, round + * it up, if it's too big, return -EINVAL. + */ + +static int retz3_decode_var(struct fb_var_screeninfo *var, + struct retz3fb_par *par) +{ + par->xres = var->xres; + par->yres = var->yres; + par->xres_vir = var->xres_virtual; + par->yres_vir = var->yres_virtual; + par->bpp = var->bits_per_pixel; + par->pixclock = var->pixclock; + par->vmode = var->vmode; + + par->red = var->red; + par->green = var->green; + par->blue = var->blue; + par->transp = var->transp; + + par->left_margin = var->left_margin; + par->right_margin = var->right_margin; + par->upper_margin = var->upper_margin; + par->lower_margin = var->lower_margin; + par->hsync_len = var->hsync_len; + par->vsync_len = var->vsync_len; + + if (var->accel_flags & FB_ACCELF_TEXT) + par->accel = FB_ACCELF_TEXT; + else + par->accel = 0; + + return 0; +} + + +/* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static int retz3_encode_var(struct fb_var_screeninfo *var, + struct retz3fb_par *par) +{ + memset(var, 0, sizeof(struct fb_var_screeninfo)); + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->xres_vir; + var->yres_virtual = par->yres_vir; + var->xoffset = 0; + var->yoffset = 0; + + var->bits_per_pixel = par->bpp; + var->grayscale = 0; + + var->red = par->red; + var->green = par->green; + var->blue = par->blue; + var->transp = par->transp; + + var->nonstd = 0; + var->activate = 0; + + var->height = -1; + var->width = -1; + + var->accel_flags = (par->accel && par->bpp == 8) ? FB_ACCELF_TEXT : 0; + + var->pixclock = par->pixclock; + + var->sync = 0; /* ??? */ + var->left_margin = par->left_margin; + var->right_margin = par->right_margin; + var->upper_margin = par->upper_margin; + var->lower_margin = par->lower_margin; + var->hsync_len = par->hsync_len; + var->vsync_len = par->vsync_len; + + var->vmode = par->vmode; + return 0; +} + + +/* + * Set a single color register. Return != 0 for invalid regno. + */ + +static int retz3fb_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info) +{ + struct retz3_fb_info *zinfo = retz3info(info); + volatile unsigned char *regs = zinfo->regs; + + /* We'll get to this */ + + if (regno > 255) + return 1; + + red >>= 10; + green >>= 10; + blue >>= 10; + + zinfo->color_table[regno][0] = red; + zinfo->color_table[regno][1] = green; + zinfo->color_table[regno][2] = blue; + + reg_w(regs, VDAC_ADDRESS_W, regno); + reg_w(regs, VDAC_DATA, red); + reg_w(regs, VDAC_DATA, green); + reg_w(regs, VDAC_DATA, blue); + + return 0; +} + + +/* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int retz3_getcolreg(unsigned int regno, unsigned int *red, + unsigned int *green, unsigned int *blue, + unsigned int *transp, struct fb_info *info) +{ + struct retz3_fb_info *zinfo = retz3info(info); + int t; + + if (regno > 255) + return 1; + t = zinfo->color_table[regno][0]; + *red = (t<<10) | (t<<4) | (t>>2); + t = zinfo->color_table[regno][1]; + *green = (t<<10) | (t<<4) | (t>>2); + t = zinfo->color_table[regno][2]; + *blue = (t<<10) | (t<<4) | (t>>2); + *transp = 0; + return 0; +} + + +static inline void retz3_busy(struct display *p) +{ + struct retz3_fb_info *zinfo = retz3info(p->fb_info); + volatile unsigned char *acm = zinfo->base + ACM_OFFSET; + unsigned char blt_status; + + if (zinfo->blitbusy) { + do{ + blt_status = *((acm) + (ACM_START_STATUS + 2)); + }while ((blt_status & 1) == 0); + zinfo->blitbusy = 0; + } +} + + +static void retz3_bitblt (struct display *p, + unsigned short srcx, unsigned short srcy, + unsigned short destx, unsigned short desty, + unsigned short width, unsigned short height, + unsigned short cmd, unsigned short mask) +{ + struct fb_var_screeninfo *var = &p->var; + struct retz3_fb_info *zinfo = retz3info(p->fb_info); + volatile unsigned long *acm = (unsigned long *)(zinfo->base + ACM_OFFSET); + unsigned long *pattern = (unsigned long *)(zinfo->fbmem + PAT_MEM_OFF); + + unsigned short mod; + unsigned long tmp; + unsigned long pat, src, dst; + + int i, xres_virtual = var->xres_virtual; + short bpp = (var->bits_per_pixel & 0xff); + + if (bpp < 8) + bpp = 8; + + tmp = mask | (mask << 16); + + retz3_busy(p); + + i = 0; + do{ + *pattern++ = tmp; + }while(i++ < bpp/4); + + tmp = cmd << 8; + *(acm + ACM_RASTEROP_ROTATION/4) = tmp; + + mod = 0xc0c2; + + pat = 8 * PAT_MEM_OFF; + dst = bpp * (destx + desty * xres_virtual); + + /* + * Source is not set for clear. + */ + if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) { + src = bpp * (srcx + srcy * xres_virtual); + + if (destx > srcx) { + mod &= ~0x8000; + src += bpp * (width - 1); + dst += bpp * (width - 1); + pat += bpp * 2; + } + if (desty > srcy) { + mod &= ~0x4000; + src += bpp * (height - 1) * xres_virtual; + dst += bpp * (height - 1) * xres_virtual; + pat += bpp * 4; + } + + *(acm + ACM_SOURCE/4) = cpu_to_le32(src); + } + + *(acm + ACM_PATTERN/4) = cpu_to_le32(pat); + + *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst); + + tmp = mod << 16; + *(acm + ACM_CONTROL/4) = tmp; + + tmp = width | (height << 16); + + *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp); + + *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00; + *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01; + zinfo->blitbusy = 1; +} + +#if 0 +/* + * Move cursor to x, y + */ +static void retz3_MoveCursor (unsigned short x, unsigned short y) +{ + /* Guess we gotta deal with the cursor at some point */ +} +#endif + + +/* + * Fill the hardware's `par' structure. + */ + +static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par) +{ + struct retz3_fb_info *zinfo = retz3info(info); + + if (zinfo->current_par_valid) + *par = zinfo->current_par; + else + retz3_decode_var(&retz3fb_default, par); +} + + +static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par) +{ + struct retz3_fb_info *zinfo = retz3info(info); + + zinfo->current_par = *par; + zinfo->current_par_valid = 1; +} + + +static int do_fb_set_var(struct fb_info *info, + struct fb_var_screeninfo *var, int isactive) +{ + int err, activate; + struct retz3fb_par par; + struct retz3_fb_info *zinfo = retz3info(info); + + if ((err = retz3_decode_var(var, &par))) + return err; + activate = var->activate; + + /* XXX ... what to do about isactive ? */ + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) + retz3fb_set_par(info, &par); + retz3_encode_var(var, &par); + var->activate = activate; + + retz3_set_video(info, var, &zinfo->current_par); + + return 0; +} + +/* + * Get the Fixed Part of the Display + */ + +static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct retz3fb_par par; + int error = 0; + + if (con == -1) + retz3fb_get_par(info, &par); + else + error = retz3_decode_var(&fb_display[con].var, &par); + return(error ? error : retz3_encode_fix(info, fix, &par)); +} + + +/* + * Get the User Defined Part of the Display + */ + +static int retz3fb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct retz3fb_par par; + int error = 0; + + if (con == -1) { + retz3fb_get_par(info, &par); + error = retz3_encode_var(var, &par); + } else + *var = fb_display[con].var; + return error; +} + + +static void retz3fb_set_disp(int con, struct fb_info *info) +{ + struct fb_fix_screeninfo fix; + struct display *display; + struct retz3_fb_info *zinfo = retz3info(info); + + if (con >= 0) + display = &fb_display[con]; + else + display = &zinfo->disp; /* used during initialization */ + + retz3fb_get_fix(&fix, con, info); + + if (con == -1) + con = 0; + + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->can_soft_blank = 1; + display->inverse = z3fb_inverse; + + /* + * This seems to be about 20% faster. + */ + display->scrollmode = SCROLL_YREDRAW; + + switch (display->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + if (display->var.accel_flags & FB_ACCELF_TEXT) { + display->dispsw = &fbcon_retz3_8; + retz3_set_video(info, &display->var, &zinfo->current_par); + } else + display->dispsw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + display->dispsw = &fbcon_cfb16; + break; +#endif + default: + display->dispsw = &fbcon_dummy; + break; + } +} + + +/* + * Set the User Defined Part of the Display + */ + +static int retz3fb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel; + struct display *display; + struct retz3_fb_info *zinfo = retz3info(info); + + if (con >= 0) + display = &fb_display[con]; + else + display = &zinfo->disp; /* used during initialization */ + + if ((err = do_fb_set_var(info, var, con == info->currcon))) + return err; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres = display->var.xres; + oldyres = display->var.yres; + oldvxres = display->var.xres_virtual; + oldvyres = display->var.yres_virtual; + oldbpp = display->var.bits_per_pixel; + oldaccel = display->var.accel_flags; + display->var = *var; + + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || + oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel || + oldaccel != var->accel_flags) { + + struct fb_fix_screeninfo fix; + retz3fb_get_fix(&fix, con, info); + + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->can_soft_blank = 1; + display->inverse = z3fb_inverse; + switch (display->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + if (var->accel_flags & FB_ACCELF_TEXT) { + display->dispsw = &fbcon_retz3_8; + } else + display->dispsw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + display->dispsw = &fbcon_cfb16; + break; +#endif + default: + display->dispsw = &fbcon_dummy; + break; + } + /* + * We still need to find a way to tell the X + * server that the video mem has been fiddled with + * so it redraws the entire screen when switching + * between X and a text console. + */ + retz3_set_video(info, var, &zinfo->current_par); + + if (info->changevar) + (*info->changevar)(con); + } + + if (oldbpp != var->bits_per_pixel) { + if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) + return err; + do_install_cmap(con, info); + } + } + return 0; +} + + +/* + * Get the Colormap + */ + +static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + if (con == info->currcon) /* current console? */ + return(fb_get_cmap(cmap, kspc, retz3_getcolreg, info)); + else if (fb_display[con].cmap.len) /* non default colormap? */ + 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; +} + +/* + * Blank the display. + */ + +static int retz3fb_blank(int blank, struct fb_info *info) +{ + struct retz3_fb_info *zinfo = retz3info(info); + volatile unsigned char *regs = retz3info(info)->regs; + short i; + + if (blank) + for (i = 0; i < 256; i++){ + reg_w(regs, VDAC_ADDRESS_W, i); + reg_w(regs, VDAC_DATA, 0); + reg_w(regs, VDAC_DATA, 0); + reg_w(regs, VDAC_DATA, 0); + } + else + for (i = 0; i < 256; i++){ + reg_w(regs, VDAC_ADDRESS_W, i); + reg_w(regs, VDAC_DATA, zinfo->color_table[i][0]); + reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]); + reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]); + } + return 0; +} + +static struct fb_ops retz3fb_ops = { + .owner = THIS_MODULE, + .fb_get_fix = retz3fb_get_fix, + .fb_get_var = retz3fb_get_var, + .fb_set_var = retz3fb_set_var, + .fb_get_cmap = retz3fb_get_cmap, + .fb_set_cmap = gen_set_cmap, + .fb_setcolreg = retz3fb_setcolreg, + .fb_blank = retz3fb_blank, +}; + +int __init retz3fb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + if (!strcmp(this_opt, "inverse")) { + z3fb_inverse = 1; + fb_invert_cmaps(); + } else if (!strncmp(this_opt, "font:", 5)) { + strlcpy(fontname, this_opt+5, sizeof(fontname)); + } else + z3fb_mode = get_video_mode(this_opt); + } + return 0; +} + + +/* + * Initialization + */ + +int __init retz3fb_init(void) +{ + unsigned long board_addr, board_size; + struct zorro_dev *z = NULL; + volatile unsigned char *regs; + struct retz3fb_par par; + struct retz3_fb_info *zinfo; + struct fb_info *fb_info; + short i; + int res = -ENXIO; + + while ((z = zorro_find_device(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, z))) { + board_addr = z->resource.start; + board_size = z->resource.end-z->resource.start+1; + if (!request_mem_region(board_addr, 0x0c00000, + "ncr77c32blt")) { + continue; + if (!request_mem_region(board_addr+VIDEO_MEM_OFFSET, + 0x00400000, "RAM")) + release_mem_region(board_addr, 0x00c00000); + continue; + } + if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info), + GFP_KERNEL))) + return -ENOMEM; + memset(zinfo, 0, sizeof(struct retz3_fb_info)); + + zinfo->base = ioremap(board_addr, board_size); + zinfo->regs = zinfo->base; + zinfo->fbmem = zinfo->base + VIDEO_MEM_OFFSET; + /* Get memory size - for now we asume it's a 4MB board */ + zinfo->fbsize = 0x00400000; /* 4 MB */ + zinfo->physregs = board_addr; + zinfo->physfbmem = board_addr + VIDEO_MEM_OFFSET; + + fb_info = fbinfo(zinfo); + + for (i = 0; i < 256; i++){ + for (i = 0; i < 256; i++){ + zinfo->color_table[i][0] = i; + zinfo->color_table[i][1] = i; + zinfo->color_table[i][2] = i; + } + } + + regs = zinfo->regs; + /* Disable hardware cursor */ + seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00); + + retz3fb_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info); + retz3fb_setcolreg (254, 0, 0, 0, 0, fb_info); + + strcpy(fb_info->modename, retz3fb_name); + fb_info->changevar = NULL; + fb_info->fbops = &retz3fb_ops; + fb_info->screen_base = zinfo->fbmem; + fb_info->disp = &zinfo->disp; + fb_info->currcon = -1; + fb_info->switch_con = &z3fb_switch; + fb_info->updatevar = &z3fb_updatevar; + fb_info->flags = FBINFO_FLAG_DEFAULT; + strlcpy(fb_info->fontname, fontname, sizeof(fb_info->fontname)); + + if (z3fb_mode == -1) + retz3fb_default = retz3fb_predefined[0].var; + + retz3_decode_var(&retz3fb_default, &par); + retz3_encode_var(&retz3fb_default, &par); + + do_fb_set_var(fb_info, &retz3fb_default, 0); + retz3fb_get_var(&zinfo->disp.var, -1, fb_info); + + retz3fb_set_disp(-1, fb_info); + + do_install_cmap(0, fb_info); + + if (register_framebuffer(fb_info) < 0) + return -EINVAL; + + printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of " + "video memory\n", fb_info->node, + fb_info->modename, zinfo->fbsize>>10); + + /* FIXME: This driver cannot be unloaded yet */ + res = 0; + } + return res; +} + + +static int z3fb_switch(int con, struct fb_info *info) +{ + /* Do we have to save the colormap? */ + if (fb_display[info->currcon].cmap.len) + fb_get_cmap(&fb_display[info->currcon].cmap, 1, + retz3_getcolreg, info); + + do_fb_set_var(info, &fb_display[con].var, 1); + info->currcon = con; + /* Install new colormap */ + do_install_cmap(con, info); + return 0; +} + + +/* + * Update the `var' structure (called by fbcon.c) + * + * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. + * Since it's called by a kernel driver, no range checking is done. + */ + +static int z3fb_updatevar(int con, struct fb_info *info) +{ + return 0; +} + +/* + * Get a Video Mode + */ + +static int __init get_video_mode(const char *name) +{ + short i; + + for (i = 0; i < NUM_TOTAL_MODES; i++) + if (!strcmp(name, retz3fb_predefined[i].name)){ + retz3fb_default = retz3fb_predefined[i].var; + return i; + } + return -1; +} + + +#ifdef MODULE +MODULE_LICENSE("GPL"); + +int init_module(void) +{ + return retz3fb_init(); +} +#endif + + +/* + * Text console acceleration + */ + +#ifdef FBCON_HAS_CFB8 +static void retz3_8_bmove(struct display *p, int sy, int sx, + int dy, int dx, int height, int width) +{ + int fontwidth = fontwidth(p); + + sx *= fontwidth; + dx *= fontwidth; + width *= fontwidth; + + retz3_bitblt(p, + (unsigned short)sx, + (unsigned short)(sy*fontheight(p)), + (unsigned short)dx, + (unsigned short)(dy*fontheight(p)), + (unsigned short)width, + (unsigned short)(height*fontheight(p)), + Z3BLTcopy, + 0xffff); +} + +static void retz3_8_clear(struct vc_data *conp, struct display *p, + int sy, int sx, int height, int width) +{ + unsigned short col; + int fontwidth = fontwidth(p); + + sx *= fontwidth; + width *= fontwidth; + + col = attr_bgcol_ec(p, conp); + col &= 0xff; + col |= (col << 8); + + retz3_bitblt(p, + (unsigned short)sx, + (unsigned short)(sy*fontheight(p)), + (unsigned short)sx, + (unsigned short)(sy*fontheight(p)), + (unsigned short)width, + (unsigned short)(height*fontheight(p)), + Z3BLTset, + col); +} + + +static void retz3_putc(struct vc_data *conp, struct display *p, int c, + int yy, int xx) +{ + retz3_busy(p); + fbcon_cfb8_putc(conp, p, c, yy, xx); +} + + +static void retz3_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, + int yy, int xx) +{ + retz3_busy(p); + fbcon_cfb8_putcs(conp, p, s, count, yy, xx); +} + + +static void retz3_revc(struct display *p, int xx, int yy) +{ + retz3_busy(p); + fbcon_cfb8_revc(p, xx, yy); +} + + +static void retz3_clear_margins(struct vc_data* conp, struct display* p, + int bottom_only) +{ + retz3_busy(p); + fbcon_cfb8_clear_margins(conp, p, bottom_only); +} + + +static struct display_switch fbcon_retz3_8 = { + .setup = fbcon_cfb8_setup, + .bmove = retz3_8_bmove, + .clear = retz3_8_clear, + .putc = retz3_putc, + .putcs = retz3_putcs, + .revc = retz3_revc, + .clear_margins = retz3_clear_margins, + .fontwidthmask = FONTWIDTH(8) +}; +#endif diff --git a/drivers/video/retz3fb.h b/drivers/video/retz3fb.h new file mode 100644 index 000000000000..5cc751067720 --- /dev/null +++ b/drivers/video/retz3fb.h @@ -0,0 +1,286 @@ +/* + * linux/drivers/video/retz3fb.h -- Defines and macros for the RetinaZ3 frame + * buffer device + * + * Copyright (C) 1997 Jes Sorensen + * + * History: + * - 22 Jan 97: Initial work + * + * + * 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. + */ + +/* + * Macros to read and write to registers. + */ +#define reg_w(regs, reg,dat) (*(regs + reg) = dat) +#define reg_r(regs, reg) (*(regs + reg)) + +/* + * Macro to access the sequencer. + */ +#define seq_w(regs, sreg, sdat) \ + do{ reg_w(regs, SEQ_IDX, sreg); reg_w(regs, SEQ_DATA, sdat); } while(0) + +/* + * Macro to access the CRT controller. + */ +#define crt_w(regs, creg, cdat) \ + do{ reg_w(regs, CRT_IDX, creg); reg_w(regs, CRT_DATA, cdat); } while(0) + +/* + * Macro to access the graphics controller. + */ +#define gfx_w(regs, greg, gdat) \ + do{ reg_w(regs, GFX_IDX, greg); reg_w(regs, GFX_DATA, gdat); } while(0) + +/* + * Macro to access the attribute controller. + */ +#define attr_w(regs, areg, adat) \ + do{ reg_w(regs, ACT_IDX, areg); reg_w(regs, ACT_DATA, adat); } while(0) + +/* + * Macro to access the pll. + */ +#define pll_w(regs, preg, pdat) \ + do{ reg_w(regs, PLL_IDX, preg); \ + reg_w(regs, PLL_DATA, (pdat & 0xff)); \ + reg_w(regs, PLL_DATA, (pdat >> 8));\ + } while(0) + +/* + * Offsets + */ +#define VIDEO_MEM_OFFSET 0x00c00000 +#define ACM_OFFSET 0x00b00000 + +/* + * Accelerator Control Menu + */ +#define ACM_PRIMARY_OFFSET 0x00 +#define ACM_SECONDARY_OFFSET 0x04 +#define ACM_MODE_CONTROL 0x08 +#define ACM_CURSOR_POSITION 0x0c +#define ACM_START_STATUS 0x30 +#define ACM_CONTROL 0x34 +#define ACM_RASTEROP_ROTATION 0x38 +#define ACM_BITMAP_DIMENSION 0x3c +#define ACM_DESTINATION 0x40 +#define ACM_SOURCE 0x44 +#define ACM_PATTERN 0x48 +#define ACM_FOREGROUND 0x4c +#define ACM_BACKGROUND 0x50 + +/* + * Video DAC addresses + */ +#define VDAC_ADDRESS 0x03c8 +#define VDAC_ADDRESS_W 0x03c8 +#define VDAC_ADDRESS_R 0x03c7 +#define VDAC_STATE 0x03c7 +#define VDAC_DATA 0x03c9 +#define VDAC_MASK 0x03c6 + +/* + * Sequencer + */ +#define SEQ_IDX 0x03c4 /* Sequencer Index */ +#define SEQ_DATA 0x03c5 +#define SEQ_RESET 0x00 +#define SEQ_CLOCKING_MODE 0x01 +#define SEQ_MAP_MASK 0x02 +#define SEQ_CHAR_MAP_SELECT 0x03 +#define SEQ_MEMORY_MODE 0x04 +#define SEQ_EXTENDED_ENABLE 0x05 /* NCR extensions */ +#define SEQ_UNKNOWN1 0x06 +#define SEQ_UNKNOWN2 0x07 +#define SEQ_CHIP_ID 0x08 +#define SEQ_UNKNOWN3 0x09 +#define SEQ_CURSOR_COLOR1 0x0a +#define SEQ_CURSOR_COLOR0 0x0b +#define SEQ_CURSOR_CONTROL 0x0c +#define SEQ_CURSOR_X_LOC_HI 0x0d +#define SEQ_CURSOR_X_LOC_LO 0x0e +#define SEQ_CURSOR_Y_LOC_HI 0x0f +#define SEQ_CURSOR_Y_LOC_LO 0x10 +#define SEQ_CURSOR_X_INDEX 0x11 +#define SEQ_CURSOR_Y_INDEX 0x12 +#define SEQ_CURSOR_STORE_HI 0x13 +#define SEQ_CURSOR_STORE_LO 0x14 +#define SEQ_CURSOR_ST_OFF_HI 0x15 +#define SEQ_CURSOR_ST_OFF_LO 0x16 +#define SEQ_CURSOR_PIXELMASK 0x17 +#define SEQ_PRIM_HOST_OFF_HI 0x18 +#define SEQ_PRIM_HOST_OFF_LO 0x19 +#define SEQ_LINEAR_0 0x1a +#define SEQ_LINEAR_1 0x1b +#define SEQ_SEC_HOST_OFF_HI 0x1c +#define SEQ_SEC_HOST_OFF_LO 0x1d +#define SEQ_EXTENDED_MEM_ENA 0x1e +#define SEQ_EXT_CLOCK_MODE 0x1f +#define SEQ_EXT_VIDEO_ADDR 0x20 +#define SEQ_EXT_PIXEL_CNTL 0x21 +#define SEQ_BUS_WIDTH_FEEDB 0x22 +#define SEQ_PERF_SELECT 0x23 +#define SEQ_COLOR_EXP_WFG 0x24 +#define SEQ_COLOR_EXP_WBG 0x25 +#define SEQ_EXT_RW_CONTROL 0x26 +#define SEQ_MISC_FEATURE_SEL 0x27 +#define SEQ_COLOR_KEY_CNTL 0x28 +#define SEQ_COLOR_KEY_MATCH0 0x29 +#define SEQ_COLOR_KEY_MATCH1 0x2a +#define SEQ_COLOR_KEY_MATCH2 0x2b +#define SEQ_UNKNOWN6 0x2c +#define SEQ_CRC_CONTROL 0x2d +#define SEQ_CRC_DATA_LOW 0x2e +#define SEQ_CRC_DATA_HIGH 0x2f +#define SEQ_MEMORY_MAP_CNTL 0x30 +#define SEQ_ACM_APERTURE_1 0x31 +#define SEQ_ACM_APERTURE_2 0x32 +#define SEQ_ACM_APERTURE_3 0x33 +#define SEQ_BIOS_UTILITY_0 0x3e +#define SEQ_BIOS_UTILITY_1 0x3f + +/* + * Graphics Controller + */ +#define GFX_IDX 0x03ce +#define GFX_DATA 0x03cf +#define GFX_SET_RESET 0x00 +#define GFX_ENABLE_SET_RESET 0x01 +#define GFX_COLOR_COMPARE 0x02 +#define GFX_DATA_ROTATE 0x03 +#define GFX_READ_MAP_SELECT 0x04 +#define GFX_GRAPHICS_MODE 0x05 +#define GFX_MISC 0x06 +#define GFX_COLOR_XCARE 0x07 +#define GFX_BITMASK 0x08 + +/* + * CRT Controller + */ +#define CRT_IDX 0x03d4 +#define CRT_DATA 0x03d5 +#define CRT_HOR_TOTAL 0x00 +#define CRT_HOR_DISP_ENA_END 0x01 +#define CRT_START_HOR_BLANK 0x02 +#define CRT_END_HOR_BLANK 0x03 +#define CRT_START_HOR_RETR 0x04 +#define CRT_END_HOR_RETR 0x05 +#define CRT_VER_TOTAL 0x06 +#define CRT_OVERFLOW 0x07 +#define CRT_PRESET_ROW_SCAN 0x08 +#define CRT_MAX_SCAN_LINE 0x09 +#define CRT_CURSOR_START 0x0a +#define CRT_CURSOR_END 0x0b +#define CRT_START_ADDR_HIGH 0x0c +#define CRT_START_ADDR_LOW 0x0d +#define CRT_CURSOR_LOC_HIGH 0x0e +#define CRT_CURSOR_LOC_LOW 0x0f +#define CRT_START_VER_RETR 0x10 +#define CRT_END_VER_RETR 0x11 +#define CRT_VER_DISP_ENA_END 0x12 +#define CRT_OFFSET 0x13 +#define CRT_UNDERLINE_LOC 0x14 +#define CRT_START_VER_BLANK 0x15 +#define CRT_END_VER_BLANK 0x16 +#define CRT_MODE_CONTROL 0x17 +#define CRT_LINE_COMPARE 0x18 +#define CRT_UNKNOWN1 0x19 +#define CRT_UNKNOWN2 0x1a +#define CRT_UNKNOWN3 0x1b +#define CRT_UNKNOWN4 0x1c +#define CRT_UNKNOWN5 0x1d +#define CRT_UNKNOWN6 0x1e +#define CRT_UNKNOWN7 0x1f +#define CRT_UNKNOWN8 0x20 +#define CRT_UNKNOWN9 0x21 +#define CRT_UNKNOWN10 0x22 +#define CRT_UNKNOWN11 0x23 +#define CRT_UNKNOWN12 0x24 +#define CRT_UNKNOWN13 0x25 +#define CRT_UNKNOWN14 0x26 +#define CRT_UNKNOWN15 0x27 +#define CRT_UNKNOWN16 0x28 +#define CRT_UNKNOWN17 0x29 +#define CRT_UNKNOWN18 0x2a +#define CRT_UNKNOWN19 0x2b +#define CRT_UNKNOWN20 0x2c +#define CRT_UNKNOWN21 0x2d +#define CRT_UNKNOWN22 0x2e +#define CRT_UNKNOWN23 0x2f +#define CRT_EXT_HOR_TIMING1 0x30 /* NCR crt extensions */ +#define CRT_EXT_START_ADDR 0x31 +#define CRT_EXT_HOR_TIMING2 0x32 +#define CRT_EXT_VER_TIMING 0x33 +#define CRT_MONITOR_POWER 0x34 + +/* + * General Registers + */ +#define GREG_STATUS0_R 0x03c2 +#define GREG_STATUS1_R 0x03da +#define GREG_MISC_OUTPUT_R 0x03cc +#define GREG_MISC_OUTPUT_W 0x03c2 +#define GREG_FEATURE_CONTROL_R 0x03ca +#define GREG_FEATURE_CONTROL_W 0x03da +#define GREG_POS 0x0102 + +/* + * Attribute Controller + */ +#define ACT_IDX 0x03C0 +#define ACT_ADDRESS_R 0x03C0 +#define ACT_DATA 0x03C0 +#define ACT_ADDRESS_RESET 0x03DA +#define ACT_PALETTE0 0x00 +#define ACT_PALETTE1 0x01 +#define ACT_PALETTE2 0x02 +#define ACT_PALETTE3 0x03 +#define ACT_PALETTE4 0x04 +#define ACT_PALETTE5 0x05 +#define ACT_PALETTE6 0x06 +#define ACT_PALETTE7 0x07 +#define ACT_PALETTE8 0x08 +#define ACT_PALETTE9 0x09 +#define ACT_PALETTE10 0x0A +#define ACT_PALETTE11 0x0B +#define ACT_PALETTE12 0x0C +#define ACT_PALETTE13 0x0D +#define ACT_PALETTE14 0x0E +#define ACT_PALETTE15 0x0F +#define ACT_ATTR_MODE_CNTL 0x10 +#define ACT_OVERSCAN_COLOR 0x11 +#define ACT_COLOR_PLANE_ENA 0x12 +#define ACT_HOR_PEL_PANNING 0x13 +#define ACT_COLOR_SELECT 0x14 + +/* + * PLL + */ +#define PLL_IDX 0x83c8 +#define PLL_DATA 0x83c9 + +/* + * Blitter operations + */ +#define Z3BLTclear 0x00 /* 0 */ +#define Z3BLTand 0x80 /* src AND dst */ +#define Z3BLTandReverse 0x40 /* src AND NOT dst */ +#define Z3BLTcopy 0xc0 /* src */ +#define Z3BLTandInverted 0x20 /* NOT src AND dst */ +#define Z3BLTnoop 0xa0 /* dst */ +#define Z3BLTxor 0x60 /* src XOR dst */ +#define Z3BLTor 0xe0 /* src OR dst */ +#define Z3BLTnor 0x10 /* NOT src AND NOT dst */ +#define Z3BLTequiv 0x90 /* NOT src XOR dst */ +#define Z3BLTinvert 0x50 /* NOT dst */ +#define Z3BLTorReverse 0xd0 /* src OR NOT dst */ +#define Z3BLTcopyInverted 0x30 /* NOT src */ +#define Z3BLTorInverted 0xb0 /* NOT src OR dst */ +#define Z3BLTnand 0x70 /* NOT src OR NOT dst */ +#define Z3BLTset 0xf0 /* 1 */ diff --git a/drivers/video/riva/Makefile b/drivers/video/riva/Makefile new file mode 100644 index 000000000000..8898c9915b02 --- /dev/null +++ b/drivers/video/riva/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the Riva framebuffer driver +# + +obj-$(CONFIG_FB_RIVA) += rivafb.o + +rivafb-objs := fbdev.o riva_hw.o nv_driver.o + +ifdef CONFIG_FB_RIVA_I2C + rivafb-objs += rivafb-i2c.o +endif diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c new file mode 100644 index 000000000000..b0c886de0404 --- /dev/null +++ b/drivers/video/riva/fbdev.c @@ -0,0 +1,2229 @@ +/* + * linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver + * + * Maintained by Ani Joshi <ajoshi@shell.unixbox.com> + * + * Copyright 1999-2000 Jeff Garzik + * + * Contributors: + * + * Ani Joshi: Lots of debugging and cleanup work, really helped + * get the driver going + * + * Ferenc Bakonyi: Bug fixes, cleanup, modularization + * + * Jindrich Makovicka: Accel code help, hw cursor, mtrr + * + * Paul Richards: Bug fixes, updates + * + * Initial template from skeletonfb.c, created 28 Dec 1997 by Geert Uytterhoeven + * Includes riva_hw.c from nVidia, see copyright below. + * KGI code provided the basis for state storage, init, and mode switching. + * + * 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. + * + * Known bugs and issues: + * restoring text mode fails + * doublescan modes are broken + */ + +#include <linux/config.h> +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif +#ifdef CONFIG_PPC_OF +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#endif +#ifdef CONFIG_PMAC_BACKLIGHT +#include <asm/backlight.h> +#endif + +#include "rivafb.h" +#include "nvreg.h" + +#ifndef CONFIG_PCI /* sanity check */ +#error This driver requires PCI support. +#endif + +/* version number of this driver */ +#define RIVAFB_VERSION "0.9.5b" + +/* ------------------------------------------------------------------------- * + * + * various helpful macros and constants + * + * ------------------------------------------------------------------------- */ +#ifdef CONFIG_FB_RIVA_DEBUG +#define NVTRACE printk +#else +#define NVTRACE if(0) printk +#endif + +#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __FUNCTION__) +#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __FUNCTION__) + +#ifdef CONFIG_FB_RIVA_DEBUG +#define assert(expr) \ + if(!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n",\ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + BUG(); \ + } +#else +#define assert(expr) +#endif + +#define PFX "rivafb: " + +/* macro that allows you to set overflow bits */ +#define SetBitField(value,from,to) SetBF(to,GetBF(value,from)) +#define SetBit(n) (1<<(n)) +#define Set8Bits(value) ((value)&0xff) + +/* HW cursor parameters */ +#define MAX_CURS 32 + +/* ------------------------------------------------------------------------- * + * + * prototypes + * + * ------------------------------------------------------------------------- */ + +static int rivafb_blank(int blank, struct fb_info *info); + +/* ------------------------------------------------------------------------- * + * + * card identification + * + * ------------------------------------------------------------------------- */ + +static struct pci_device_id rivafb_pci_tbl[] = { + { PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + // NF2/IGP version, GeForce 4 MX, NV18 + { PCI_VENDOR_ID_NVIDIA, 0x01f0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl); + +/* ------------------------------------------------------------------------- * + * + * global variables + * + * ------------------------------------------------------------------------- */ + +/* command line data, set in rivafb_setup() */ +static int flatpanel __devinitdata = -1; /* Autodetect later */ +static int forceCRTC __devinitdata = -1; +static int noaccel __devinitdata = 0; +#ifdef CONFIG_MTRR +static int nomtrr __devinitdata = 0; +#endif + +static char *mode_option __devinitdata = NULL; +static int strictmode = 0; + +static struct fb_fix_screeninfo __devinitdata rivafb_fix = { + .type = FB_TYPE_PACKED_PIXELS, + .xpanstep = 1, + .ypanstep = 1, +}; + +static struct fb_var_screeninfo __devinitdata rivafb_default_var = { + .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}, + .transp = {0, 0, 0}, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .pixclock = 39721, + .left_margin = 40, + .right_margin = 24, + .upper_margin = 32, + .lower_margin = 11, + .hsync_len = 96, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED +}; + +/* from GGI */ +static const struct riva_regs reg_template = { + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ATTR */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x01, 0x0F, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* CRT */ + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, /* 0x10 */ + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */ + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, /* 0x40 */ + }, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, /* GRA */ + 0xFF}, + {0x03, 0x01, 0x0F, 0x00, 0x0E}, /* SEQ */ + 0xEB /* MISC */ +}; + +/* + * Backlight control + */ +#ifdef CONFIG_PMAC_BACKLIGHT + +static int riva_backlight_levels[] = { + 0x158, + 0x192, + 0x1c6, + 0x200, + 0x234, + 0x268, + 0x2a2, + 0x2d6, + 0x310, + 0x344, + 0x378, + 0x3b2, + 0x3e6, + 0x41a, + 0x454, + 0x534, +}; + +static int riva_set_backlight_enable(int on, int level, void *data); +static int riva_set_backlight_level(int level, void *data); +static struct backlight_controller riva_backlight_controller = { + riva_set_backlight_enable, + riva_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ + +/* ------------------------------------------------------------------------- * + * + * MMIO access macros + * + * ------------------------------------------------------------------------- */ + +static inline void CRTCout(struct riva_par *par, unsigned char index, + unsigned char val) +{ + VGA_WR08(par->riva.PCIO, 0x3d4, index); + VGA_WR08(par->riva.PCIO, 0x3d5, val); +} + +static inline unsigned char CRTCin(struct riva_par *par, + unsigned char index) +{ + VGA_WR08(par->riva.PCIO, 0x3d4, index); + return (VGA_RD08(par->riva.PCIO, 0x3d5)); +} + +static inline void GRAout(struct riva_par *par, unsigned char index, + unsigned char val) +{ + VGA_WR08(par->riva.PVIO, 0x3ce, index); + VGA_WR08(par->riva.PVIO, 0x3cf, val); +} + +static inline unsigned char GRAin(struct riva_par *par, + unsigned char index) +{ + VGA_WR08(par->riva.PVIO, 0x3ce, index); + return (VGA_RD08(par->riva.PVIO, 0x3cf)); +} + +static inline void SEQout(struct riva_par *par, unsigned char index, + unsigned char val) +{ + VGA_WR08(par->riva.PVIO, 0x3c4, index); + VGA_WR08(par->riva.PVIO, 0x3c5, val); +} + +static inline unsigned char SEQin(struct riva_par *par, + unsigned char index) +{ + VGA_WR08(par->riva.PVIO, 0x3c4, index); + return (VGA_RD08(par->riva.PVIO, 0x3c5)); +} + +static inline void ATTRout(struct riva_par *par, unsigned char index, + unsigned char val) +{ + VGA_WR08(par->riva.PCIO, 0x3c0, index); + VGA_WR08(par->riva.PCIO, 0x3c0, val); +} + +static inline unsigned char ATTRin(struct riva_par *par, + unsigned char index) +{ + VGA_WR08(par->riva.PCIO, 0x3c0, index); + return (VGA_RD08(par->riva.PCIO, 0x3c1)); +} + +static inline void MISCout(struct riva_par *par, unsigned char val) +{ + VGA_WR08(par->riva.PVIO, 0x3c2, val); +} + +static inline unsigned char MISCin(struct riva_par *par) +{ + return (VGA_RD08(par->riva.PVIO, 0x3cc)); +} + +static u8 byte_rev[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + +static inline void reverse_order(u32 *l) +{ + u8 *a = (u8 *)l; + *a = byte_rev[*a], a++; + *a = byte_rev[*a], a++; + *a = byte_rev[*a], a++; + *a = byte_rev[*a]; +} + +/* ------------------------------------------------------------------------- * + * + * cursor stuff + * + * ------------------------------------------------------------------------- */ + +/** + * rivafb_load_cursor_image - load cursor image to hardware + * @data: address to monochrome bitmap (1 = foreground color, 0 = background) + * @par: pointer to private data + * @w: width of cursor image in pixels + * @h: height of cursor image in scanlines + * @bg: background color (ARGB1555) - alpha bit determines opacity + * @fg: foreground color (ARGB1555) + * + * DESCRIPTiON: + * Loads cursor image based on a monochrome source and mask bitmap. The + * image bits determines the color of the pixel, 0 for background, 1 for + * foreground. Only the affected region (as determined by @w and @h + * parameters) will be updated. + * + * CALLED FROM: + * rivafb_cursor() + */ +static void rivafb_load_cursor_image(struct riva_par *par, u8 *data8, + u16 bg, u16 fg, u32 w, u32 h) +{ + int i, j, k = 0; + u32 b, tmp; + u32 *data = (u32 *)data8; + bg = le16_to_cpu(bg); + fg = le16_to_cpu(fg); + + w = (w + 1) & ~1; + + for (i = 0; i < h; i++) { + b = *data++; + reverse_order(&b); + + for (j = 0; j < w/2; j++) { + tmp = 0; +#if defined (__BIG_ENDIAN) + tmp = (b & (1 << 31)) ? fg << 16 : bg << 16; + b <<= 1; + tmp |= (b & (1 << 31)) ? fg : bg; + b <<= 1; +#else + tmp = (b & 1) ? fg : bg; + b >>= 1; + tmp |= (b & 1) ? fg << 16 : bg << 16; + b >>= 1; +#endif + writel(tmp, &par->riva.CURSOR[k++]); + } + k += (MAX_CURS - w)/2; + } +} + +/* ------------------------------------------------------------------------- * + * + * general utility functions + * + * ------------------------------------------------------------------------- */ + +/** + * riva_wclut - set CLUT entry + * @chip: pointer to RIVA_HW_INST object + * @regnum: register number + * @red: red component + * @green: green component + * @blue: blue component + * + * DESCRIPTION: + * Sets color register @regnum. + * + * CALLED FROM: + * rivafb_setcolreg() + */ +static void riva_wclut(RIVA_HW_INST *chip, + unsigned char regnum, unsigned char red, + unsigned char green, unsigned char blue) +{ + VGA_WR08(chip->PDIO, 0x3c8, regnum); + VGA_WR08(chip->PDIO, 0x3c9, red); + VGA_WR08(chip->PDIO, 0x3c9, green); + VGA_WR08(chip->PDIO, 0x3c9, blue); +} + +/** + * riva_rclut - read fromCLUT register + * @chip: pointer to RIVA_HW_INST object + * @regnum: register number + * @red: red component + * @green: green component + * @blue: blue component + * + * DESCRIPTION: + * Reads red, green, and blue from color register @regnum. + * + * CALLED FROM: + * rivafb_setcolreg() + */ +static void riva_rclut(RIVA_HW_INST *chip, + unsigned char regnum, unsigned char *red, + unsigned char *green, unsigned char *blue) +{ + + VGA_WR08(chip->PDIO, 0x3c7, regnum); + *red = VGA_RD08(chip->PDIO, 0x3c9); + *green = VGA_RD08(chip->PDIO, 0x3c9); + *blue = VGA_RD08(chip->PDIO, 0x3c9); +} + +/** + * riva_save_state - saves current chip state + * @par: pointer to riva_par object containing info for current riva board + * @regs: pointer to riva_regs object + * + * DESCRIPTION: + * Saves current chip state to @regs. + * + * CALLED FROM: + * rivafb_probe() + */ +/* from GGI */ +static void riva_save_state(struct riva_par *par, struct riva_regs *regs) +{ + int i; + + NVTRACE_ENTER(); + par->riva.LockUnlock(&par->riva, 0); + + par->riva.UnloadStateExt(&par->riva, ®s->ext); + + regs->misc_output = MISCin(par); + + for (i = 0; i < NUM_CRT_REGS; i++) + regs->crtc[i] = CRTCin(par, i); + + for (i = 0; i < NUM_ATC_REGS; i++) + regs->attr[i] = ATTRin(par, i); + + for (i = 0; i < NUM_GRC_REGS; i++) + regs->gra[i] = GRAin(par, i); + + for (i = 0; i < NUM_SEQ_REGS; i++) + regs->seq[i] = SEQin(par, i); + NVTRACE_LEAVE(); +} + +/** + * riva_load_state - loads current chip state + * @par: pointer to riva_par object containing info for current riva board + * @regs: pointer to riva_regs object + * + * DESCRIPTION: + * Loads chip state from @regs. + * + * CALLED FROM: + * riva_load_video_mode() + * rivafb_probe() + * rivafb_remove() + */ +/* from GGI */ +static void riva_load_state(struct riva_par *par, struct riva_regs *regs) +{ + RIVA_HW_STATE *state = ®s->ext; + int i; + + NVTRACE_ENTER(); + CRTCout(par, 0x11, 0x00); + + par->riva.LockUnlock(&par->riva, 0); + + par->riva.LoadStateExt(&par->riva, state); + + MISCout(par, regs->misc_output); + + for (i = 0; i < NUM_CRT_REGS; i++) { + switch (i) { + case 0x19: + case 0x20 ... 0x40: + break; + default: + CRTCout(par, i, regs->crtc[i]); + } + } + + for (i = 0; i < NUM_ATC_REGS; i++) + ATTRout(par, i, regs->attr[i]); + + for (i = 0; i < NUM_GRC_REGS; i++) + GRAout(par, i, regs->gra[i]); + + for (i = 0; i < NUM_SEQ_REGS; i++) + SEQout(par, i, regs->seq[i]); + NVTRACE_LEAVE(); +} + +/** + * riva_load_video_mode - calculate timings + * @info: pointer to fb_info object containing info for current riva board + * + * DESCRIPTION: + * Calculate some timings and then send em off to riva_load_state(). + * + * CALLED FROM: + * rivafb_set_par() + */ +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; + + NVTRACE_ENTER(); + /* time to calculate */ + rivafb_blank(1, info); + + bpp = info->var.bits_per_pixel; + if (bpp == 16 && info->var.green.length == 5) + bpp = 15; + width = info->var.xres_virtual; + hDisplaySize = info->var.xres; + hDisplay = (hDisplaySize / 8) - 1; + hStart = (hDisplaySize + info->var.right_margin) / 8 - 1; + 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 - 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; + vEnd = info->var.yres + info->var.lower_margin + + 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)); + + if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + vTotal |= 1; + + 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 (hBlankStart); + newmode.crtc[0x3] = SetBitField (hBlankEnd, 4: 0, 4:0) | SetBit (7); + newmode.crtc[0x4] = Set8Bits (hStart); + 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 (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 (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); + 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); + + if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + int tmp = (hTotal >> 1) & ~1; + newmode.ext.interlace = Set8Bits(tmp); + newmode.ext.horiz |= SetBitField(tmp, 8:8,4:4); + } else + newmode.ext.interlace = 0xff; /* interlace off */ + + if (par->riva.Architecture >= NV_ARCH_10) + par->riva.CURSOR = (U032 __iomem *)(info->screen_base + par->riva.CursorStart); + + if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) + newmode.misc_output &= ~0x40; + else + newmode.misc_output |= 0x40; + if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) + newmode.misc_output &= ~0x80; + else + newmode.misc_output |= 0x80; + + par->riva.CalcStateExt(&par->riva, &newmode.ext, bpp, width, + hDisplaySize, height, dotClock); + + newmode.ext.scale = NV_RD32(par->riva.PRAMDAC, 0x00000848) & + 0xfff000ff; + if (par->FlatPanel == 1) { + newmode.ext.pixel |= (1 << 7); + newmode.ext.scale |= (1 << 8); + } + if (par->SecondCRTC) { + newmode.ext.head = NV_RD32(par->riva.PCRTC0, 0x00000860) & + ~0x00001000; + newmode.ext.head2 = NV_RD32(par->riva.PCRTC0, 0x00002860) | + 0x00001000; + newmode.ext.crtcOwner = 3; + newmode.ext.pllsel |= 0x20000800; + newmode.ext.vpll2 = newmode.ext.vpll; + } else if (par->riva.twoHeads) { + newmode.ext.head = NV_RD32(par->riva.PCRTC0, 0x00000860) | + 0x00001000; + newmode.ext.head2 = NV_RD32(par->riva.PCRTC0, 0x00002860) & + ~0x00001000; + newmode.ext.crtcOwner = 0; + newmode.ext.vpll2 = NV_RD32(par->riva.PRAMDAC0, 0x00000520); + } + 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); + NVTRACE_LEAVE(); +} + +static void riva_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb) +{ + NVTRACE_ENTER(); + var->xres = var->xres_virtual = modedb->xres; + var->yres = modedb->yres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + var->xoffset = var->yoffset = 0; + var->pixclock = modedb->pixclock; + var->left_margin = modedb->left_margin; + var->right_margin = modedb->right_margin; + var->upper_margin = modedb->upper_margin; + var->lower_margin = modedb->lower_margin; + var->hsync_len = modedb->hsync_len; + var->vsync_len = modedb->vsync_len; + var->sync = modedb->sync; + var->vmode = modedb->vmode; + NVTRACE_LEAVE(); +} + +/** + * rivafb_do_maximize - + * @info: pointer to fb_info object containing info for current riva board + * @var: + * @nom: + * @den: + * + * DESCRIPTION: + * . + * + * RETURNS: + * -EINVAL on failure, 0 on success + * + * + * CALLED FROM: + * rivafb_check_var() + */ +static int rivafb_do_maximize(struct fb_info *info, + struct fb_var_screeninfo *var, + int nom, int den) +{ + static struct { + int xres, yres; + } modes[] = { + {1600, 1280}, + {1280, 1024}, + {1024, 768}, + {800, 600}, + {640, 480}, + {-1, -1} + }; + int i; + + NVTRACE_ENTER(); + /* use highest possible virtual resolution */ + if (var->xres_virtual == -1 && var->yres_virtual == -1) { + printk(KERN_WARNING PFX + "using maximum available virtual resolution\n"); + for (i = 0; modes[i].xres != -1; i++) { + if (modes[i].xres * nom / den * modes[i].yres < + info->fix.smem_len) + break; + } + if (modes[i].xres == -1) { + printk(KERN_ERR PFX + "could not find a virtual resolution that fits into video memory!!\n"); + NVTRACE("EXIT - EINVAL error\n"); + return -EINVAL; + } + var->xres_virtual = modes[i].xres; + var->yres_virtual = modes[i].yres; + + printk(KERN_INFO PFX + "virtual resolution set to maximum of %dx%d\n", + var->xres_virtual, var->yres_virtual); + } else if (var->xres_virtual == -1) { + var->xres_virtual = (info->fix.smem_len * den / + (nom * var->yres_virtual)) & ~15; + printk(KERN_WARNING PFX + "setting virtual X resolution to %d\n", var->xres_virtual); + } else if (var->yres_virtual == -1) { + var->xres_virtual = (var->xres_virtual + 15) & ~15; + var->yres_virtual = info->fix.smem_len * den / + (nom * var->xres_virtual); + printk(KERN_WARNING PFX + "setting virtual Y resolution to %d\n", var->yres_virtual); + } else { + var->xres_virtual = (var->xres_virtual + 15) & ~15; + if (var->xres_virtual * nom / den * var->yres_virtual > info->fix.smem_len) { + printk(KERN_ERR PFX + "mode %dx%dx%d rejected...resolution too high to fit into video memory!\n", + var->xres, var->yres, var->bits_per_pixel); + NVTRACE("EXIT - EINVAL error\n"); + return -EINVAL; + } + } + + if (var->xres_virtual * nom / den >= 8192) { + printk(KERN_WARNING PFX + "virtual X resolution (%d) is too high, lowering to %d\n", + var->xres_virtual, 8192 * den / nom - 16); + var->xres_virtual = 8192 * den / nom - 16; + } + + if (var->xres_virtual < var->xres) { + printk(KERN_ERR PFX + "virtual X resolution (%d) is smaller than real\n", var->xres_virtual); + return -EINVAL; + } + + if (var->yres_virtual < var->yres) { + printk(KERN_ERR PFX + "virtual Y resolution (%d) is smaller than real\n", var->yres_virtual); + return -EINVAL; + } + if (var->yres_virtual > 0x7fff/nom) + var->yres_virtual = 0x7fff/nom; + if (var->xres_virtual > 0x7fff/nom) + var->xres_virtual = 0x7fff/nom; + NVTRACE_LEAVE(); + return 0; +} + +static void +riva_set_pattern(struct riva_par *par, int clr0, int clr1, int pat0, int pat1) +{ + RIVA_FIFO_FREE(par->riva, Patt, 4); + NV_WR32(&par->riva.Patt->Color0, 0, clr0); + NV_WR32(&par->riva.Patt->Color1, 0, clr1); + NV_WR32(par->riva.Patt->Monochrome, 0, pat0); + NV_WR32(par->riva.Patt->Monochrome, 4, pat1); +} + +/* acceleration routines */ +static inline void wait_for_idle(struct riva_par *par) +{ + while (par->riva.Busy(&par->riva)); +} + +/* + * Set ROP. Translate X rop into ROP3. Internal routine. + */ +static void +riva_set_rop_solid(struct riva_par *par, int rop) +{ + riva_set_pattern(par, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); + RIVA_FIFO_FREE(par->riva, Rop, 1); + NV_WR32(&par->riva.Rop->Rop3, 0, rop); + +} + +static void riva_setup_accel(struct fb_info *info) +{ + struct riva_par *par = (struct riva_par *) info->par; + + RIVA_FIFO_FREE(par->riva, Clip, 2); + NV_WR32(&par->riva.Clip->TopLeft, 0, 0x0); + NV_WR32(&par->riva.Clip->WidthHeight, 0, + (info->var.xres_virtual & 0xffff) | + (info->var.yres_virtual << 16)); + riva_set_rop_solid(par, 0xcc); + wait_for_idle(par); +} + +/** + * riva_get_cmap_len - query current color map length + * @var: standard kernel fb changeable data + * + * DESCRIPTION: + * Get current color map length. + * + * RETURNS: + * Length of color map + * + * CALLED FROM: + * rivafb_setcolreg() + */ +static int riva_get_cmap_len(const struct fb_var_screeninfo *var) +{ + int rc = 256; /* reasonable default */ + + switch (var->green.length) { + case 8: + rc = 256; /* 256 entries (2^8), 8 bpp and RGB8888 */ + break; + case 5: + rc = 32; /* 32 entries (2^5), 16 bpp, RGB555 */ + break; + case 6: + rc = 64; /* 64 entries (2^6), 16 bpp, RGB565 */ + break; + default: + /* should not occur */ + break; + } + return rc; +} + +/* ------------------------------------------------------------------------- * + * + * Backlight operations + * + * ------------------------------------------------------------------------- */ + +#ifdef CONFIG_PMAC_BACKLIGHT +static int riva_set_backlight_enable(int on, int level, void *data) +{ + struct riva_par *par = (struct riva_par *)data; + U032 tmp_pcrt, tmp_pmc; + + tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF; + tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC; + if(on && (level > BACKLIGHT_OFF)) { + tmp_pcrt |= 0x1; + tmp_pmc |= (1 << 31); // backlight bit + tmp_pmc |= riva_backlight_levels[level-1] << 16; // level + } + par->riva.PCRTC0[0x081C/4] = tmp_pcrt; + par->riva.PMC[0x10F0/4] = tmp_pmc; + return 0; +} + +static int riva_set_backlight_level(int level, void *data) +{ + return riva_set_backlight_enable(1, level, data); +} +#endif /* CONFIG_PMAC_BACKLIGHT */ + +/* ------------------------------------------------------------------------- * + * + * framebuffer operations + * + * ------------------------------------------------------------------------- */ + +static int rivafb_open(struct fb_info *info, int user) +{ + struct riva_par *par = (struct riva_par *) info->par; + int cnt = atomic_read(&par->ref_count); + + NVTRACE_ENTER(); + if (!cnt) { +#ifdef CONFIG_X86 + memset(&par->state, 0, sizeof(struct vgastate)); + par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS; + /* save the DAC for Riva128 */ + if (par->riva.Architecture == NV_ARCH_03) + par->state.flags |= VGA_SAVE_CMAP; + save_vga(&par->state); +#endif + /* vgaHWunlock() + riva unlock (0x7F) */ + CRTCout(par, 0x11, 0xFF); + par->riva.LockUnlock(&par->riva, 0); + + riva_save_state(par, &par->initial_state); + } + atomic_inc(&par->ref_count); + NVTRACE_LEAVE(); + return 0; +} + +static int rivafb_release(struct fb_info *info, int user) +{ + struct riva_par *par = (struct riva_par *) info->par; + int cnt = atomic_read(&par->ref_count); + + NVTRACE_ENTER(); + if (!cnt) + return -EINVAL; + if (cnt == 1) { + par->riva.LockUnlock(&par->riva, 0); + par->riva.LoadStateExt(&par->riva, &par->initial_state.ext); + riva_load_state(par, &par->initial_state); +#ifdef CONFIG_X86 + restore_vga(&par->state); +#endif + par->riva.LockUnlock(&par->riva, 1); + } + atomic_dec(&par->ref_count); + NVTRACE_LEAVE(); + return 0; +} + +static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct fb_videomode *mode; + struct riva_par *par = (struct riva_par *) info->par; + int nom, den; /* translating from pixels->bytes */ + int mode_valid = 0; + + NVTRACE_ENTER(); + switch (var->bits_per_pixel) { + case 1 ... 8: + var->red.offset = var->green.offset = var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = 8; + var->bits_per_pixel = 8; + nom = den = 1; + break; + case 9 ... 15: + var->green.length = 5; + /* fall through */ + case 16: + var->bits_per_pixel = 16; + /* The Riva128 supports RGB555 only */ + if (par->riva.Architecture == NV_ARCH_03) + var->green.length = 5; + if (var->green.length == 5) { + /* 0rrrrrgg gggbbbbb */ + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + } else { + /* rrrrrggg gggbbbbb */ + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + } + nom = 2; + den = 1; + break; + case 17 ... 32: + var->red.length = var->green.length = var->blue.length = 8; + var->bits_per_pixel = 32; + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + nom = 4; + den = 1; + break; + default: + printk(KERN_ERR PFX + "mode %dx%dx%d rejected...color depth not supported.\n", + var->xres, var->yres, var->bits_per_pixel); + NVTRACE("EXIT, returning -EINVAL\n"); + return -EINVAL; + } + + if (!strictmode) { + if (!info->monspecs.vfmax || !info->monspecs.hfmax || + !info->monspecs.dclkmax || !fb_validate_mode(var, info)) + mode_valid = 1; + } + + /* calculate modeline if supported by monitor */ + if (!mode_valid && info->monspecs.gtf) { + if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info)) + mode_valid = 1; + } + + if (!mode_valid) { + mode = fb_find_best_mode(var, &info->modelist); + if (mode) { + riva_update_var(var, mode); + mode_valid = 1; + } + } + + if (!mode_valid && info->monspecs.modedb_len) + return -EINVAL; + + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual <= var->yres) + var->yres_virtual = -1; + if (rivafb_do_maximize(info, var, nom, den) < 0) + return -EINVAL; + + if (var->xoffset < 0) + var->xoffset = 0; + if (var->yoffset < 0) + var->yoffset = 0; + + /* truncate xoffset and yoffset to maximum if too high */ + if (var->xoffset > var->xres_virtual - var->xres) + var->xoffset = var->xres_virtual - var->xres - 1; + + if (var->yoffset > var->yres_virtual - var->yres) + var->yoffset = var->yres_virtual - var->yres - 1; + + var->red.msb_right = + var->green.msb_right = + var->blue.msb_right = + var->transp.offset = var->transp.length = var->transp.msb_right = 0; + NVTRACE_LEAVE(); + return 0; +} + +static int rivafb_set_par(struct fb_info *info) +{ + struct riva_par *par = (struct riva_par *) info->par; + + NVTRACE_ENTER(); + /* vgaHWunlock() + riva unlock (0x7F) */ + CRTCout(par, 0x11, 0xFF); + par->riva.LockUnlock(&par->riva, 0); + riva_load_video_mode(info); + if(!(info->flags & FBINFO_HWACCEL_DISABLED)) + riva_setup_accel(info); + + par->cursor_reset = 1; + info->fix.line_length = (info->var.xres_virtual * (info->var.bits_per_pixel >> 3)); + info->fix.visual = (info->var.bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + + if (info->flags & FBINFO_HWACCEL_DISABLED) + info->pixmap.scan_align = 1; + else + info->pixmap.scan_align = 4; + NVTRACE_LEAVE(); + return 0; +} + +/** + * rivafb_pan_display + * @var: standard kernel fb changeable data + * @con: TODO + * @info: pointer to fb_info object containing info for current riva board + * + * DESCRIPTION: + * Pan (or wrap, depending on the `vmode' field) the display using the + * `xoffset' and `yoffset' fields of the `var' structure. + * If the values don't fit, return -EINVAL. + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ +static int rivafb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct riva_par *par = (struct riva_par *)info->par; + unsigned int base; + + NVTRACE_ENTER(); + if (var->xoffset > (var->xres_virtual - var->xres)) + return -EINVAL; + if (var->yoffset > (var->yres_virtual - var->yres)) + return -EINVAL; + + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset < 0 + || var->yoffset >= info->var.yres_virtual + || var->xoffset) return -EINVAL; + } else { + if (var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + } + + base = var->yoffset * info->fix.line_length + var->xoffset; + + par->riva.SetStartAddress(&par->riva, base); + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + NVTRACE_LEAVE(); + return 0; +} + +static int rivafb_blank(int blank, struct fb_info *info) +{ + struct riva_par *par= (struct riva_par *)info->par; + unsigned char tmp, vesa; + + tmp = SEQin(par, 0x01) & ~0x20; /* screen on/off */ + vesa = CRTCin(par, 0x1a) & ~0xc0; /* sync on/off */ + + NVTRACE_ENTER(); + + if (blank) + tmp |= 0x20; + + switch (blank) { + case FB_BLANK_UNBLANK: + case FB_BLANK_NORMAL: + break; + case FB_BLANK_VSYNC_SUSPEND: + vesa |= 0x80; + break; + case FB_BLANK_HSYNC_SUSPEND: + vesa |= 0x40; + break; + case FB_BLANK_POWERDOWN: + vesa |= 0xc0; + break; + } + + SEQout(par, 0x01, tmp); + CRTCout(par, 0x1a, vesa); + +#ifdef CONFIG_PMAC_BACKLIGHT + if ( par->FlatPanel && _machine == _MACH_Pmac) { + set_backlight_enable(!blank); + } +#endif + + NVTRACE_LEAVE(); + + return 0; +} + +/** + * rivafb_setcolreg + * @regno: register index + * @red: red component + * @green: green component + * @blue: blue component + * @transp: transparency + * @info: pointer to fb_info object containing info for current riva board + * + * DESCRIPTION: + * Set a single color register. The values supplied have a 16 bit + * magnitude. + * + * RETURNS: + * Return != 0 for invalid regno. + * + * CALLED FROM: + * fbcmap.c:fb_set_cmap() + */ +static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct riva_par *par = (struct riva_par *)info->par; + RIVA_HW_INST *chip = &par->riva; + int i; + + if (regno >= riva_get_cmap_len(&info->var)) + return -EINVAL; + + if (info->var.grayscale) { + /* gray = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = + (red * 77 + green * 151 + blue * 28) >> 8; + } + + if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + ((u32 *) info->pseudo_palette)[regno] = + (regno << info->var.red.offset) | + (regno << info->var.green.offset) | + (regno << info->var.blue.offset); + /* + * The Riva128 2D engine requires color information in + * TrueColor format even if framebuffer is in DirectColor + */ + if (par->riva.Architecture == NV_ARCH_03) { + switch (info->var.bits_per_pixel) { + case 16: + par->palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 32: + par->palette[regno] = ((red & 0xff00) << 8) | + ((green & 0xff00)) | + ((blue & 0xff00) >> 8); + break; + } + } + } + + switch (info->var.bits_per_pixel) { + case 8: + /* "transparent" stuff is completely ignored. */ + riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8); + break; + case 16: + if (info->var.green.length == 5) { + for (i = 0; i < 8; i++) { + riva_wclut(chip, regno*8+i, red >> 8, + green >> 8, blue >> 8); + } + } else { + u8 r, g, b; + + if (regno < 32) { + for (i = 0; i < 8; i++) { + riva_wclut(chip, regno*8+i, + red >> 8, green >> 8, + blue >> 8); + } + } + riva_rclut(chip, regno*4, &r, &g, &b); + for (i = 0; i < 4; i++) + riva_wclut(chip, regno*4+i, r, + green >> 8, b); + } + break; + case 32: + riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8); + break; + default: + /* do nothing */ + break; + } + return 0; +} + +/** + * rivafb_fillrect - hardware accelerated color fill function + * @info: pointer to fb_info structure + * @rect: pointer to fb_fillrect structure + * + * DESCRIPTION: + * This function fills up a region of framebuffer memory with a solid + * color with a choice of two different ROP's, copy or invert. + * + * CALLED FROM: + * framebuffer hook + */ +static void rivafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct riva_par *par = (struct riva_par *) info->par; + u_int color, rop = 0; + + if ((info->flags & FBINFO_HWACCEL_DISABLED)) { + cfb_fillrect(info, rect); + return; + } + + if (info->var.bits_per_pixel == 8) + color = rect->color; + else { + if (par->riva.Architecture != NV_ARCH_03) + color = ((u32 *)info->pseudo_palette)[rect->color]; + else + color = par->palette[rect->color]; + } + + switch (rect->rop) { + case ROP_XOR: + rop = 0x66; + break; + case ROP_COPY: + default: + rop = 0xCC; + break; + } + + riva_set_rop_solid(par, rop); + + RIVA_FIFO_FREE(par->riva, Bitmap, 1); + NV_WR32(&par->riva.Bitmap->Color1A, 0, color); + + RIVA_FIFO_FREE(par->riva, Bitmap, 2); + NV_WR32(&par->riva.Bitmap->UnclippedRectangle[0].TopLeft, 0, + (rect->dx << 16) | rect->dy); + mb(); + NV_WR32(&par->riva.Bitmap->UnclippedRectangle[0].WidthHeight, 0, + (rect->width << 16) | rect->height); + mb(); + riva_set_rop_solid(par, 0xcc); + +} + +/** + * rivafb_copyarea - hardware accelerated blit function + * @info: pointer to fb_info structure + * @region: pointer to fb_copyarea structure + * + * DESCRIPTION: + * This copies an area of pixels from one location to another + * + * CALLED FROM: + * framebuffer hook + */ +static void rivafb_copyarea(struct fb_info *info, const struct fb_copyarea *region) +{ + struct riva_par *par = (struct riva_par *) info->par; + + if ((info->flags & FBINFO_HWACCEL_DISABLED)) { + cfb_copyarea(info, region); + return; + } + + RIVA_FIFO_FREE(par->riva, Blt, 3); + NV_WR32(&par->riva.Blt->TopLeftSrc, 0, + (region->sy << 16) | region->sx); + NV_WR32(&par->riva.Blt->TopLeftDst, 0, + (region->dy << 16) | region->dx); + mb(); + NV_WR32(&par->riva.Blt->WidthHeight, 0, + (region->height << 16) | region->width); + mb(); +} + +static inline void convert_bgcolor_16(u32 *col) +{ + *col = ((*col & 0x0000F800) << 8) + | ((*col & 0x00007E0) << 5) + | ((*col & 0x0000001F) << 3) + | 0xFF000000; + mb(); +} + +/** + * rivafb_imageblit: hardware accelerated color expand function + * @info: pointer to fb_info structure + * @image: pointer to fb_image structure + * + * DESCRIPTION: + * If the source is a monochrome bitmap, the function fills up a a region + * of framebuffer memory with pixels whose color is determined by the bit + * setting of the bitmap, 1 - foreground, 0 - background. + * + * If the source is not a monochrome bitmap, color expansion is not done. + * In this case, it is channeled to a software function. + * + * CALLED FROM: + * framebuffer hook + */ +static void rivafb_imageblit(struct fb_info *info, + const struct fb_image *image) +{ + struct riva_par *par = (struct riva_par *) info->par; + u32 fgx = 0, bgx = 0, width, tmp; + u8 *cdat = (u8 *) image->data; + volatile u32 __iomem *d; + int i, size; + + if ((info->flags & FBINFO_HWACCEL_DISABLED) || image->depth != 1) { + cfb_imageblit(info, image); + return; + } + + switch (info->var.bits_per_pixel) { + case 8: + fgx = image->fg_color; + bgx = image->bg_color; + break; + case 16: + case 32: + if (par->riva.Architecture != NV_ARCH_03) { + fgx = ((u32 *)info->pseudo_palette)[image->fg_color]; + bgx = ((u32 *)info->pseudo_palette)[image->bg_color]; + } else { + fgx = par->palette[image->fg_color]; + bgx = par->palette[image->bg_color]; + } + if (info->var.green.length == 6) + convert_bgcolor_16(&bgx); + break; + } + + RIVA_FIFO_FREE(par->riva, Bitmap, 7); + NV_WR32(&par->riva.Bitmap->ClipE.TopLeft, 0, + (image->dy << 16) | (image->dx & 0xFFFF)); + NV_WR32(&par->riva.Bitmap->ClipE.BottomRight, 0, + (((image->dy + image->height) << 16) | + ((image->dx + image->width) & 0xffff))); + NV_WR32(&par->riva.Bitmap->Color0E, 0, bgx); + NV_WR32(&par->riva.Bitmap->Color1E, 0, fgx); + NV_WR32(&par->riva.Bitmap->WidthHeightInE, 0, + (image->height << 16) | ((image->width + 31) & ~31)); + NV_WR32(&par->riva.Bitmap->WidthHeightOutE, 0, + (image->height << 16) | ((image->width + 31) & ~31)); + NV_WR32(&par->riva.Bitmap->PointE, 0, + (image->dy << 16) | (image->dx & 0xFFFF)); + + d = &par->riva.Bitmap->MonochromeData01E; + + width = (image->width + 31)/32; + size = width * image->height; + while (size >= 16) { + RIVA_FIFO_FREE(par->riva, Bitmap, 16); + for (i = 0; i < 16; i++) { + tmp = *((u32 *)cdat); + cdat = (u8 *)((u32 *)cdat + 1); + reverse_order(&tmp); + NV_WR32(d, i*4, tmp); + } + size -= 16; + } + if (size) { + RIVA_FIFO_FREE(par->riva, Bitmap, size); + for (i = 0; i < size; i++) { + tmp = *((u32 *) cdat); + cdat = (u8 *)((u32 *)cdat + 1); + reverse_order(&tmp); + NV_WR32(d, i*4, tmp); + } + } +} + +/** + * rivafb_cursor - hardware cursor function + * @info: pointer to info structure + * @cursor: pointer to fbcursor structure + * + * DESCRIPTION: + * A cursor function that supports displaying a cursor image via hardware. + * Within the kernel, copy and invert rops are supported. If exported + * to user space, only the copy rop will be supported. + * + * CALLED FROM + * framebuffer hook + */ +static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct riva_par *par = (struct riva_par *) info->par; + u8 data[MAX_CURS * MAX_CURS/8]; + u16 fg, bg; + int i, set = cursor->set; + + if (cursor->image.width > MAX_CURS || + cursor->image.height > MAX_CURS) + return soft_cursor(info, cursor); + + par->riva.ShowHideCursor(&par->riva, 0); + + if (par->cursor_reset) { + set = FB_CUR_SETALL; + par->cursor_reset = 0; + } + + if (set & FB_CUR_SETSIZE) + memset_io(par->riva.CURSOR, 0, MAX_CURS * MAX_CURS * 2); + + if (set & FB_CUR_SETPOS) { + u32 xx, yy, temp; + + yy = cursor->image.dy - info->var.yoffset; + xx = cursor->image.dx - info->var.xoffset; + temp = xx & 0xFFFF; + temp |= yy << 16; + + NV_WR32(par->riva.PRAMDAC, 0x0000300, temp); + } + + + if (set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) { + u32 bg_idx = cursor->image.bg_color; + u32 fg_idx = cursor->image.fg_color; + u32 s_pitch = (cursor->image.width+7) >> 3; + u32 d_pitch = MAX_CURS/8; + u8 *dat = (u8 *) cursor->image.data; + u8 *msk = (u8 *) cursor->mask; + u8 *src; + + src = kmalloc(s_pitch * cursor->image.height, GFP_ATOMIC); + + if (src) { + switch (cursor->rop) { + case ROP_XOR: + for (i = 0; i < s_pitch * cursor->image.height; + i++) + src[i] = dat[i] ^ msk[i]; + break; + case ROP_COPY: + default: + for (i = 0; i < s_pitch * cursor->image.height; + i++) + src[i] = dat[i] & msk[i]; + break; + } + + fb_sysmove_buf_aligned(info, &info->pixmap, data, + d_pitch, src, s_pitch, + cursor->image.height); + + bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) | + ((info->cmap.green[bg_idx] & 0xf8) << 2) | + ((info->cmap.blue[bg_idx] & 0xf8) >> 3) | + 1 << 15; + + fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) | + ((info->cmap.green[fg_idx] & 0xf8) << 2) | + ((info->cmap.blue[fg_idx] & 0xf8) >> 3) | + 1 << 15; + + par->riva.LockUnlock(&par->riva, 0); + + rivafb_load_cursor_image(par, data, bg, fg, + cursor->image.width, + cursor->image.height); + kfree(src); + } + } + + if (cursor->enable) + par->riva.ShowHideCursor(&par->riva, 1); + + return 0; +} + +static int rivafb_sync(struct fb_info *info) +{ + struct riva_par *par = (struct riva_par *)info->par; + + wait_for_idle(par); + return 0; +} + +/* ------------------------------------------------------------------------- * + * + * initialization helper functions + * + * ------------------------------------------------------------------------- */ + +/* kernel interface */ +static struct fb_ops riva_fb_ops = { + .owner = THIS_MODULE, + .fb_open = rivafb_open, + .fb_release = rivafb_release, + .fb_check_var = rivafb_check_var, + .fb_set_par = rivafb_set_par, + .fb_setcolreg = rivafb_setcolreg, + .fb_pan_display = rivafb_pan_display, + .fb_blank = rivafb_blank, + .fb_fillrect = rivafb_fillrect, + .fb_copyarea = rivafb_copyarea, + .fb_imageblit = rivafb_imageblit, + .fb_cursor = rivafb_cursor, + .fb_sync = rivafb_sync, +}; + +static int __devinit riva_set_fbinfo(struct fb_info *info) +{ + unsigned int cmap_len; + struct riva_par *par = (struct riva_par *) info->par; + + NVTRACE_ENTER(); + info->flags = FBINFO_DEFAULT + | FBINFO_HWACCEL_XPAN + | FBINFO_HWACCEL_YPAN + | FBINFO_HWACCEL_COPYAREA + | FBINFO_HWACCEL_FILLRECT + | FBINFO_HWACCEL_IMAGEBLIT; + + /* Accel seems to not work properly on NV30 yet...*/ + if ((par->riva.Architecture == NV_ARCH_30) || noaccel) { + printk(KERN_DEBUG PFX "disabling acceleration\n"); + info->flags |= FBINFO_HWACCEL_DISABLED; + } + + info->var = rivafb_default_var; + info->fix.visual = (info->var.bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + + info->pseudo_palette = par->pseudo_palette; + + cmap_len = riva_get_cmap_len(&info->var); + fb_alloc_cmap(&info->cmap, cmap_len, 0); + + info->pixmap.size = 8 * 1024; + info->pixmap.buf_align = 4; + info->pixmap.flags = FB_PIXMAP_SYSTEM; + info->var.yres_virtual = -1; + NVTRACE_LEAVE(); + return (rivafb_check_var(&info->var, info)); +} + +#ifdef CONFIG_PPC_OF +static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd) +{ + struct riva_par *par = (struct riva_par *) info->par; + struct device_node *dp; + unsigned char *pedid = NULL; + unsigned char *disptype = NULL; + static char *propnames[] = { + "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL }; + int i; + + NVTRACE_ENTER(); + dp = pci_device_to_OF_node(pd); + for (; dp != NULL; dp = dp->child) { + disptype = (unsigned char *)get_property(dp, "display-type", NULL); + if (disptype == NULL) + continue; + if (strncmp(disptype, "LCD", 3) != 0) + continue; + for (i = 0; propnames[i] != NULL; ++i) { + pedid = (unsigned char *) + get_property(dp, propnames[i], NULL); + if (pedid != NULL) { + par->EDID = pedid; + NVTRACE("LCD found.\n"); + return 1; + } + } + } + NVTRACE_LEAVE(); + return 0; +} +#endif /* CONFIG_PPC_OF */ + +#if defined(CONFIG_FB_RIVA_I2C) && !defined(CONFIG_PPC_OF) +static int __devinit riva_get_EDID_i2c(struct fb_info *info) +{ + struct riva_par *par = (struct riva_par *) info->par; + struct fb_var_screeninfo var; + int i; + + NVTRACE_ENTER(); + riva_create_i2c_busses(par); + for (i = 0; i < par->bus; i++) { + riva_probe_i2c_connector(par, i+1, &par->EDID); + if (par->EDID && !fb_parse_edid(par->EDID, &var)) { + printk(PFX "Found EDID Block from BUS %i\n", i); + break; + } + } + + NVTRACE_LEAVE(); + return (par->EDID) ? 1 : 0; +} +#endif /* CONFIG_FB_RIVA_I2C */ + +static void __devinit riva_update_default_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct fb_monspecs *specs = &info->monspecs; + struct fb_videomode modedb; + + NVTRACE_ENTER(); + /* respect mode options */ + if (mode_option) { + fb_find_mode(var, info, mode_option, + specs->modedb, specs->modedb_len, + NULL, 8); + } else if (specs->modedb != NULL) { + /* get preferred timing */ + if (info->monspecs.misc & FB_MISC_1ST_DETAIL) { + int i; + + for (i = 0; i < specs->modedb_len; i++) { + if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { + modedb = specs->modedb[i]; + break; + } + } + } else { + /* otherwise, get first mode in database */ + modedb = specs->modedb[0]; + } + var->bits_per_pixel = 8; + riva_update_var(var, &modedb); + } + NVTRACE_LEAVE(); +} + + +static void __devinit riva_get_EDID(struct fb_info *info, struct pci_dev *pdev) +{ + NVTRACE_ENTER(); +#ifdef CONFIG_PPC_OF + if (!riva_get_EDID_OF(info, pdev)) + printk(PFX "could not retrieve EDID from OF\n"); +#elif CONFIG_FB_RIVA_I2C + if (!riva_get_EDID_i2c(info)) + printk(PFX "could not retrieve EDID from DDC/I2C\n"); +#endif + NVTRACE_LEAVE(); +} + + +static void __devinit riva_get_edidinfo(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &rivafb_default_var; + struct riva_par *par = (struct riva_par *) info->par; + + fb_edid_to_monspecs(par->EDID, &info->monspecs); + fb_videomode_to_modelist(info->monspecs.modedb, info->monspecs.modedb_len, + &info->modelist); + riva_update_default_var(var, info); + + /* if user specified flatpanel, we respect that */ + if (info->monspecs.input & FB_DISP_DDI) + par->FlatPanel = 1; +} + +/* ------------------------------------------------------------------------- * + * + * PCI bus + * + * ------------------------------------------------------------------------- */ + +static u32 __devinit riva_get_arch(struct pci_dev *pd) +{ + u32 arch = 0; + + switch (pd->device & 0x0ff0) { + case 0x0100: /* GeForce 256 */ + case 0x0110: /* GeForce2 MX */ + case 0x0150: /* GeForce2 */ + case 0x0170: /* GeForce4 MX */ + case 0x0180: /* GeForce4 MX (8x AGP) */ + case 0x01A0: /* nForce */ + case 0x01F0: /* nForce2 */ + arch = NV_ARCH_10; + break; + case 0x0200: /* GeForce3 */ + case 0x0250: /* GeForce4 Ti */ + case 0x0280: /* GeForce4 Ti (8x AGP) */ + arch = NV_ARCH_20; + break; + case 0x0300: /* GeForceFX 5800 */ + case 0x0310: /* GeForceFX 5600 */ + case 0x0320: /* GeForceFX 5200 */ + case 0x0330: /* GeForceFX 5900 */ + case 0x0340: /* GeForceFX 5700 */ + arch = NV_ARCH_30; + break; + case 0x0020: /* TNT, TNT2 */ + arch = NV_ARCH_04; + break; + case 0x0010: /* Riva128 */ + arch = NV_ARCH_03; + break; + default: /* unknown architecture */ + break; + } + return arch; +} + +static int __devinit rivafb_probe(struct pci_dev *pd, + const struct pci_device_id *ent) +{ + struct riva_par *default_par; + struct fb_info *info; + int ret; + + NVTRACE_ENTER(); + assert(pd != NULL); + + info = framebuffer_alloc(sizeof(struct riva_par), &pd->dev); + if (!info) { + printk (KERN_ERR PFX "could not allocate memory\n"); + ret = -ENOMEM; + goto err_ret; + } + default_par = (struct riva_par *) info->par; + default_par->pdev = pd; + + info->pixmap.addr = kmalloc(8 * 1024, GFP_KERNEL); + if (info->pixmap.addr == NULL) { + ret = -ENOMEM; + goto err_framebuffer_release; + } + memset(info->pixmap.addr, 0, 8 * 1024); + + ret = pci_enable_device(pd); + if (ret < 0) { + printk(KERN_ERR PFX "cannot enable PCI device\n"); + goto err_free_pixmap; + } + + ret = pci_request_regions(pd, "rivafb"); + if (ret < 0) { + printk(KERN_ERR PFX "cannot request PCI regions\n"); + goto err_disable_device; + } + + default_par->riva.Architecture = riva_get_arch(pd); + + default_par->Chipset = (pd->vendor << 16) | pd->device; + printk(KERN_INFO PFX "nVidia device/chipset %X\n",default_par->Chipset); + +#ifdef CONFIG_PCI_NAMES + printk(KERN_INFO PFX "%s\n", pd->pretty_name); +#endif + + if(default_par->riva.Architecture == 0) { + printk(KERN_ERR PFX "unknown NV_ARCH\n"); + ret=-ENODEV; + goto err_release_region; + } + if(default_par->riva.Architecture == NV_ARCH_10 || + default_par->riva.Architecture == NV_ARCH_20 || + default_par->riva.Architecture == NV_ARCH_30) { + sprintf(rivafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4); + } else { + sprintf(rivafb_fix.id, "NV%x", default_par->riva.Architecture); + } + + default_par->FlatPanel = flatpanel; + if (flatpanel == 1) + printk(KERN_INFO PFX "flatpanel support enabled\n"); + default_par->forceCRTC = forceCRTC; + + rivafb_fix.mmio_len = pci_resource_len(pd, 0); + rivafb_fix.smem_len = pci_resource_len(pd, 1); + + { + /* enable IO and mem if not already done */ + unsigned short cmd; + + pci_read_config_word(pd, PCI_COMMAND, &cmd); + cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(pd, PCI_COMMAND, cmd); + } + + rivafb_fix.mmio_start = pci_resource_start(pd, 0); + rivafb_fix.smem_start = pci_resource_start(pd, 1); + + default_par->ctrl_base = ioremap(rivafb_fix.mmio_start, + rivafb_fix.mmio_len); + if (!default_par->ctrl_base) { + printk(KERN_ERR PFX "cannot ioremap MMIO base\n"); + ret = -EIO; + goto err_release_region; + } + + switch (default_par->riva.Architecture) { + case NV_ARCH_03: + /* Riva128's PRAMIN is in the "framebuffer" space + * Since these cards were never made with more than 8 megabytes + * we can safely allocate this separately. + */ + default_par->riva.PRAMIN = ioremap(rivafb_fix.smem_start + 0x00C00000, 0x00008000); + if (!default_par->riva.PRAMIN) { + printk(KERN_ERR PFX "cannot ioremap PRAMIN region\n"); + ret = -EIO; + goto err_iounmap_ctrl_base; + } + break; + case NV_ARCH_04: + case NV_ARCH_10: + case NV_ARCH_20: + case NV_ARCH_30: + default_par->riva.PCRTC0 = + (u32 __iomem *)(default_par->ctrl_base + 0x00600000); + default_par->riva.PRAMIN = + (u32 __iomem *)(default_par->ctrl_base + 0x00710000); + break; + } + riva_common_setup(default_par); + + if (default_par->riva.Architecture == NV_ARCH_03) { + default_par->riva.PCRTC = default_par->riva.PCRTC0 + = default_par->riva.PGRAPH; + } + + rivafb_fix.smem_len = riva_get_memlen(default_par) * 1024; + default_par->dclk_max = riva_get_maxdclk(default_par) * 1000; + 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"); + ret = -EIO; + goto err_iounmap_pramin; + } + +#ifdef CONFIG_MTRR + if (!nomtrr) { + default_par->mtrr.vram = mtrr_add(rivafb_fix.smem_start, + rivafb_fix.smem_len, + MTRR_TYPE_WRCOMB, 1); + if (default_par->mtrr.vram < 0) { + printk(KERN_ERR PFX "unable to setup MTRR\n"); + } else { + default_par->mtrr.vram_valid = 1; + /* let there be speed */ + printk(KERN_INFO PFX "RIVA MTRR set to ON\n"); + } + } +#endif /* CONFIG_MTRR */ + + info->fbops = &riva_fb_ops; + info->fix = rivafb_fix; + riva_get_EDID(info, pd); + riva_get_edidinfo(info); + + ret=riva_set_fbinfo(info); + if (ret < 0) { + printk(KERN_ERR PFX "error setting initial video mode\n"); + goto err_iounmap_screen_base; + } + + fb_destroy_modedb(info->monspecs.modedb); + info->monspecs.modedb = NULL; + ret = register_framebuffer(info); + if (ret < 0) { + printk(KERN_ERR PFX + "error registering riva framebuffer\n"); + goto err_iounmap_screen_base; + } + + pci_set_drvdata(pd, info); + + printk(KERN_INFO PFX + "PCI nVidia %s framebuffer ver %s (%dMB @ 0x%lX)\n", + info->fix.id, + RIVAFB_VERSION, + info->fix.smem_len / (1024 * 1024), + info->fix.smem_start); +#ifdef CONFIG_PMAC_BACKLIGHT + if (default_par->FlatPanel && _machine == _MACH_Pmac) + register_backlight_controller(&riva_backlight_controller, + default_par, "mnca"); +#endif + NVTRACE_LEAVE(); + return 0; + +err_iounmap_screen_base: +#ifdef CONFIG_FB_RIVA_I2C + riva_delete_i2c_busses((struct riva_par *) info->par); +#endif + iounmap(info->screen_base); +err_iounmap_pramin: + if (default_par->riva.Architecture == NV_ARCH_03) + iounmap(default_par->riva.PRAMIN); +err_iounmap_ctrl_base: + iounmap(default_par->ctrl_base); +err_release_region: + pci_release_regions(pd); +err_disable_device: + pci_disable_device(pd); +err_free_pixmap: + kfree(info->pixmap.addr); +err_framebuffer_release: + framebuffer_release(info); +err_ret: + return ret; +} + +static void __exit rivafb_remove(struct pci_dev *pd) +{ + struct fb_info *info = pci_get_drvdata(pd); + struct riva_par *par = (struct riva_par *) info->par; + + NVTRACE_ENTER(); + if (!info) + return; + +#ifdef CONFIG_FB_RIVA_I2C + riva_delete_i2c_busses(par); + kfree(par->EDID); +#endif + + unregister_framebuffer(info); +#ifdef CONFIG_MTRR + if (par->mtrr.vram_valid) + mtrr_del(par->mtrr.vram, info->fix.smem_start, + info->fix.smem_len); +#endif /* CONFIG_MTRR */ + + iounmap(par->ctrl_base); + iounmap(info->screen_base); + if (par->riva.Architecture == NV_ARCH_03) + iounmap(par->riva.PRAMIN); + pci_release_regions(pd); + pci_disable_device(pd); + kfree(info->pixmap.addr); + framebuffer_release(info); + pci_set_drvdata(pd, NULL); + NVTRACE_LEAVE(); +} + +/* ------------------------------------------------------------------------- * + * + * initialization + * + * ------------------------------------------------------------------------- */ + +#ifndef MODULE +static int __init rivafb_setup(char *options) +{ + char *this_opt; + + NVTRACE_ENTER(); + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "forceCRTC", 9)) { + char *p; + + p = this_opt + 9; + if (!*p || !*(++p)) continue; + forceCRTC = *p - '0'; + if (forceCRTC < 0 || forceCRTC > 1) + forceCRTC = -1; + } else if (!strncmp(this_opt, "flatpanel", 9)) { + flatpanel = 1; +#ifdef CONFIG_MTRR + } else if (!strncmp(this_opt, "nomtrr", 6)) { + nomtrr = 1; +#endif + } else if (!strncmp(this_opt, "strictmode", 10)) { + strictmode = 1; + } else if (!strncmp(this_opt, "noaccel", 7)) { + noaccel = 1; + } else + mode_option = this_opt; + } + NVTRACE_LEAVE(); + return 0; +} +#endif /* !MODULE */ + +static struct pci_driver rivafb_driver = { + .name = "rivafb", + .id_table = rivafb_pci_tbl, + .probe = rivafb_probe, + .remove = __exit_p(rivafb_remove), +}; + + + +/* ------------------------------------------------------------------------- * + * + * modularization + * + * ------------------------------------------------------------------------- */ + +static int __devinit rivafb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("rivafb", &option)) + return -ENODEV; + rivafb_setup(option); +#endif + return pci_register_driver(&rivafb_driver); +} + + +module_init(rivafb_init); + +#ifdef MODULE +static void __exit rivafb_exit(void) +{ + pci_unregister_driver(&rivafb_driver); +} + +module_exit(rivafb_exit); +#endif /* MODULE */ + +module_param(noaccel, bool, 0); +MODULE_PARM_DESC(noaccel, "bool: disable acceleration"); +module_param(flatpanel, int, 0); +MODULE_PARM_DESC(flatpanel, "Enables experimental flat panel support for some chipsets. (0 or 1=enabled) (default=0)"); +module_param(forceCRTC, int, 0); +MODULE_PARM_DESC(forceCRTC, "Forces usage of a particular CRTC in case autodetection fails. (0 or 1) (default=autodetect)"); +#ifdef CONFIG_MTRR +module_param(nomtrr, bool, 0); +MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) (default=0)"); +#endif +module_param(strictmode, bool, 0); +MODULE_PARM_DESC(strictmode, "Only use video modes from EDID"); + +MODULE_AUTHOR("Ani Joshi, maintainer"); +MODULE_DESCRIPTION("Framebuffer driver for nVidia Riva 128, TNT, TNT2, and the GeForce series"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/riva/nv4ref.h b/drivers/video/riva/nv4ref.h new file mode 100644 index 000000000000..3b5f9117c37d --- /dev/null +++ b/drivers/video/riva/nv4ref.h @@ -0,0 +1,2445 @@ + /***************************************************************************\ +|* *| +|* Copyright 1993-1998 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 1993-1998 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL licensing note -- nVidia is allowing a liberal interpretation of + * the documentation restriction above, to merely say that this nVidia's + * copyright and disclaimer should be included with all code derived + * from this source. -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 + */ + + /***************************************************************************\ +|* Modified 1999 by Fredrik Reite (fredrik@reite.com) *| + \***************************************************************************/ + + +#ifndef __NV4REF_H__ +#define __NV4REF_H__ + +/* Magic values to lock/unlock extended regs */ +#define NV_CIO_SR_LOCK_INDEX 0x0000001F /* */ +#define NV_CIO_SR_UNLOCK_RW_VALUE 0x00000057 /* */ +#define NV_CIO_SR_UNLOCK_RO_VALUE 0x00000075 /* */ +#define NV_CIO_SR_LOCK_VALUE 0x00000099 /* */ + +#define UNLOCK_EXT_MAGIC 0x57 +#define LOCK_EXT_MAGIC 0x99 /* Any value other than 0x57 will do */ + +#define LOCK_EXT_INDEX 0x6 + +#define NV_PCRTC_HORIZ_TOTAL 0x00 +#define NV_PCRTC_HORIZ_DISPLAY_END 0x01 +#define NV_PCRTC_HORIZ_BLANK_START 0x02 + +#define NV_PCRTC_HORIZ_BLANK_END 0x03 +#define NV_PCRTC_HORIZ_BLANK_END_EVRA 7:7 +#define NV_PCRTC_HORIZ_BLANK_END_DISPLAY_END_SKEW 6:5 +#define NV_PCRTC_HORIZ_BLANK_END_HORIZ_BLANK_END 4:0 + +#define NV_PCRTC_HORIZ_RETRACE_START 0x04 + +#define NV_PCRTC_HORIZ_RETRACE_END 0x05 +#define NV_PCRTC_HORIZ_RETRACE_END_HORIZ_BLANK_END_5 7:7 +#define NV_PCRTC_HORIZ_RETRACE_END_HORIZ_RETRACE_SKEW 6:5 +#define NV_PCRTC_HORIZ_RETRACE_END_HORIZ_RETRACE_END 4:0 + +#define NV_PCRTC_VERT_TOTAL 0x06 + +#define NV_PCRTC_OVERFLOW 0x07 +#define NV_PCRTC_OVERFLOW_VERT_RETRACE_START_9 7:7 +#define NV_PCRTC_OVERFLOW_VERT_DISPLAY_END_9 6:6 +#define NV_PCRTC_OVERFLOW_VERT_TOTAL_9 5:5 +#define NV_PCRTC_OVERFLOW_LINE_COMPARE_8 4:4 +#define NV_PCRTC_OVERFLOW_VERT_BLANK_START_8 3:3 +#define NV_PCRTC_OVERFLOW_VERT_RETRACE_START_8 2:2 +#define NV_PCRTC_OVERFLOW_VERT_DISPLAY_END_8 1:1 +#define NV_PCRTC_OVERFLOW_VERT_TOTAL_8 0:0 + +#define NV_PCRTC_PRESET_ROW_SCAN 0x08 + +#define NV_PCRTC_MAX_SCAN_LINE 0x09 +#define NV_PCRTC_MAX_SCAN_LINE_DOUBLE_SCAN 7:7 +#define NV_PCRTC_MAX_SCAN_LINE_LINE_COMPARE_9 6:6 +#define NV_PCRTC_MAX_SCAN_LINE_VERT_BLANK_START_9 5:5 +#define NV_PCRTC_MAX_SCAN_LINE_MAX_SCAN_LINE 4:0 + +#define NV_PCRTC_CURSOR_START 0x0A +#define NV_PCRTC_CURSOR_END 0x0B +#define NV_PCRTC_START_ADDR_HIGH 0x0C +#define NV_PCRTC_START_ADDR_LOW 0x0D +#define NV_PCRTC_CURSOR_LOCATION_HIGH 0x0E +#define NV_PCRTC_CURSOR_LOCATION_LOW 0x0F + +#define NV_PCRTC_VERT_RETRACE_START 0x10 +#define NV_PCRTC_VERT_RETRACE_END 0x11 +#define NV_PCRTC_VERT_DISPLAY_END 0x12 +#define NV_PCRTC_OFFSET 0x13 +#define NV_PCRTC_UNDERLINE_LOCATION 0x14 +#define NV_PCRTC_VERT_BLANK_START 0x15 +#define NV_PCRTC_VERT_BLANK_END 0x16 +#define NV_PCRTC_MODE_CONTROL 0x17 +#define NV_PCRTC_LINE_COMPARE 0x18 + +/* Extended offset and start address */ +#define NV_PCRTC_REPAINT0 0x19 +#define NV_PCRTC_REPAINT0_OFFSET_10_8 7:5 +#define NV_PCRTC_REPAINT0_START_ADDR_20_16 4:0 + +/* Horizonal extended bits */ +#define NV_PCRTC_HORIZ_EXTRA 0x2d +#define NV_PCRTC_HORIZ_EXTRA_INTER_HALF_START_8 4:4 +#define NV_PCRTC_HORIZ_EXTRA_HORIZ_RETRACE_START_8 3:3 +#define NV_PCRTC_HORIZ_EXTRA_HORIZ_BLANK_START_8 2:2 +#define NV_PCRTC_HORIZ_EXTRA_DISPLAY_END_8 1:1 +#define NV_PCRTC_HORIZ_EXTRA_DISPLAY_TOTAL_8 0:0 + +/* Assorted extra bits */ +#define NV_PCRTC_EXTRA 0x25 +#define NV_PCRTC_EXTRA_OFFSET_11 5:5 +#define NV_PCRTC_EXTRA_HORIZ_BLANK_END_6 4:4 +#define NV_PCRTC_EXTRA_VERT_BLANK_START_10 3:3 +#define NV_PCRTC_EXTRA_VERT_RETRACE_START_10 2:2 +#define NV_PCRTC_EXTRA_VERT_DISPLAY_END_10 1:1 +#define NV_PCRTC_EXTRA_VERT_TOTAL_10 0:0 + +/* Controls how much data the refresh fifo requests */ +#define NV_PCRTC_FIFO_CONTROL 0x1b +#define NV_PCRTC_FIFO_CONTROL_UNDERFLOW_WARN 7:7 +#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH 2:0 +#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_8 0x0 +#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_32 0x1 +#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_64 0x2 +#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_128 0x3 +#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_256 0x4 + +/* When the fifo occupancy falls below *twice* the watermark, + * the refresh fifo will start to be refilled. If this value is + * too low, you will get junk on the screen. Too high, and performance + * will suffer. Watermark in units of 8 bytes + */ +#define NV_PCRTC_FIFO 0x20 +#define NV_PCRTC_FIFO_RESET 7:7 +#define NV_PCRTC_FIFO_WATERMARK 5:0 + +/* Various flags */ +#define NV_PCRTC_REPAINT1 0x1a +#define NV_PCRTC_REPAINT1_HSYNC 7:7 +#define NV_PCRTC_REPAINT1_HYSNC_DISABLE 0x01 +#define NV_PCRTC_REPAINT1_HYSNC_ENABLE 0x00 +#define NV_PCRTC_REPAINT1_VSYNC 6:6 +#define NV_PCRTC_REPAINT1_VYSNC_DISABLE 0x01 +#define NV_PCRTC_REPAINT1_VYSNC_ENABLE 0x00 +#define NV_PCRTC_REPAINT1_COMPATIBLE_TEXT 4:4 +#define NV_PCRTC_REPAINT1_COMPATIBLE_TEXT_ENABLE 0x01 +#define NV_PCRTC_REPAINT1_COMPATIBLE_TEXT_DISABLE 0x00 +#define NV_PCRTC_REPAINT1_LARGE_SCREEN 2:2 +#define NV_PCRTC_REPAINT1_LARGE_SCREEN_DISABLE 0x01 +#define NV_PCRTC_REPAINT1_LARGE_SCREEN_ENABLE 0x00 /* >=1280 */ +#define NV_PCRTC_REPAINT1_PALETTE_WIDTH 1:1 +#define NV_PCRTC_REPAINT1_PALETTE_WIDTH_8BITS 0x00 +#define NV_PCRTC_REPAINT1_PALETTE_WIDTH_6BITS 0x01 + +#define NV_PCRTC_GRCURSOR0 0x30 +#define NV_PCRTC_GRCURSOR0_START_ADDR_21_16 5:0 + +#define NV_PCRTC_GRCURSOR1 0x31 +#define NV_PCRTC_GRCURSOR1_START_ADDR_15_11 7:3 +#define NV_PCRTC_GRCURSOR1_SCAN_DBL 1:1 +#define NV_PCRTC_GRCURSOR1_SCAN_DBL_DISABLE 0 +#define NV_PCRTC_GRCURSOR1_SCAN_DBL_ENABLE 1 +#define NV_PCRTC_GRCURSOR1_CURSOR 0:0 +#define NV_PCRTC_GRCURSOR1_CURSOR_DISABLE 0 +#define NV_PCRTC_GRCURSOR1_CURSOR_ENABLE 1 + +/* Controls what the format of the framebuffer is */ +#define NV_PCRTC_PIXEL 0x28 +#define NV_PCRTC_PIXEL_MODE 7:7 +#define NV_PCRTC_PIXEL_MODE_TV 0x01 +#define NV_PCRTC_PIXEL_MODE_VGA 0x00 +#define NV_PCRTC_PIXEL_TV_MODE 6:6 +#define NV_PCRTC_PIXEL_TV_MODE_NTSC 0x00 +#define NV_PCRTC_PIXEL_TV_MODE_PAL 0x01 +#define NV_PCRTC_PIXEL_TV_HORIZ_ADJUST 5:3 +#define NV_PCRTC_PIXEL_FORMAT 1:0 +#define NV_PCRTC_PIXEL_FORMAT_VGA 0x00 +#define NV_PCRTC_PIXEL_FORMAT_8BPP 0x01 +#define NV_PCRTC_PIXEL_FORMAT_16BPP 0x02 +#define NV_PCRTC_PIXEL_FORMAT_32BPP 0x03 + +/* RAMDAC registers and fields */ +#define NV_PRAMDAC 0x00680FFF:0x00680000 /* RW--D */ +#define NV_PRAMDAC_GRCURSOR_START_POS 0x00680300 /* RW-4R */ +#define NV_PRAMDAC_GRCURSOR_START_POS_X 11:0 /* RWXSF */ +#define NV_PRAMDAC_GRCURSOR_START_POS_Y 27:16 /* RWXSF */ +#define NV_PRAMDAC_NVPLL_COEFF 0x00680500 /* RW-4R */ +#define NV_PRAMDAC_NVPLL_COEFF_MDIV 7:0 /* RWIUF */ +#define NV_PRAMDAC_NVPLL_COEFF_NDIV 15:8 /* RWIUF */ +#define NV_PRAMDAC_NVPLL_COEFF_PDIV 18:16 /* RWIVF */ +#define NV_PRAMDAC_MPLL_COEFF 0x00680504 /* RW-4R */ +#define NV_PRAMDAC_MPLL_COEFF_MDIV 7:0 /* RWIUF */ +#define NV_PRAMDAC_MPLL_COEFF_NDIV 15:8 /* RWIUF */ +#define NV_PRAMDAC_MPLL_COEFF_PDIV 18:16 /* RWIVF */ +#define NV_PRAMDAC_VPLL_COEFF 0x00680508 /* RW-4R */ +#define NV_PRAMDAC_VPLL_COEFF_MDIV 7:0 /* RWIUF */ +#define NV_PRAMDAC_VPLL_COEFF_NDIV 15:8 /* RWIUF */ +#define NV_PRAMDAC_VPLL_COEFF_PDIV 18:16 /* RWIVF */ +#define NV_PRAMDAC_PLL_COEFF_SELECT 0x0068050C /* RW-4R */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_DLL_BYPASS 4:4 /* RWIVF */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_DLL_BYPASS_FALSE 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_DLL_BYPASS_TRUE 0x00000001 /* RW--V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_SOURCE 8:8 /* RWIVF */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_SOURCE_DEFAULT 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_SOURCE_PROG 0x00000001 /* RW--V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_BYPASS 12:12 /* RWIVF */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_BYPASS_FALSE 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_BYPASS_TRUE 0x00000001 /* RW--V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE 16:16 /* RWIVF */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE_DEFAULT 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE_PROG 0x00000001 /* RW--V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_BYPASS 20:20 /* RWIVF */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_BYPASS_FALSE 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_BYPASS_TRUE 0x00000001 /* RW--V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE 25:24 /* RWIVF */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE_VPLL 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE_VIP 0x00000001 /* RW--V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE_XTALOSC 0x00000002 /* RW--V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO 28:28 /* RWIVF */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO_DB1 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO_DB2 0x00000001 /* RW--V */ +#define NV_PRAMDAC_GENERAL_CONTROL 0x00680600 /* RW-4R */ +#define NV_PRAMDAC_GENERAL_CONTROL_FF_COEFF 1:0 /* RWIVF */ +#define NV_PRAMDAC_GENERAL_CONTROL_FF_COEFF_DEF 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_GENERAL_CONTROL_IDC_MODE 4:4 /* RWIVF */ +#define NV_PRAMDAC_GENERAL_CONTROL_IDC_MODE_GAMMA 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_GENERAL_CONTROL_IDC_MODE_INDEX 0x00000001 /* RW--V */ +#define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE 8:8 /* RWIVF */ +#define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_NOTSE 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL 0x00000001 /* RW--V */ +#define NV_PRAMDAC_GENERAL_CONTROL_565_MODE 12:12 /* RWIVF */ +#define NV_PRAMDAC_GENERAL_CONTROL_565_MODE_NOTSEL 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_GENERAL_CONTROL_565_MODE_SEL 0x00000001 /* RW--V */ +#define NV_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL 16:16 /* RWIVF */ +#define NV_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL_OFF 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL_ON 0x00000001 /* RW--V */ +#define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION 17:17 /* RWIVF */ +#define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_37OHM 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_75OHM 0x00000001 /* RW--V */ +#define NV_PRAMDAC_GENERAL_CONTROL_BPC 20:20 /* RWIVF */ +#define NV_PRAMDAC_GENERAL_CONTROL_BPC_6BITS 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS 0x00000001 /* RW--V */ +#define NV_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP 24:24 /* RWIVF */ +#define NV_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP_DIS 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP_EN 0x00000001 /* RW--V */ +#define NV_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK 28:28 /* RWIVF */ +#define NV_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK_EN 0x00000000 /* RWI-V */ +#define NV_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK_DIS 0x00000001 /* RW--V */ + +/* Master Control */ +#define NV_PMC 0x00000FFF:0x00000000 /* RW--D */ +#define NV_PMC_BOOT_0 0x00000000 /* R--4R */ +#define NV_PMC_BOOT_0_MINOR_REVISION 3:0 /* C--VF */ +#define NV_PMC_BOOT_0_MINOR_REVISION_0 0x00000000 /* C---V */ +#define NV_PMC_BOOT_0_MAJOR_REVISION 7:4 /* C--VF */ +#define NV_PMC_BOOT_0_MAJOR_REVISION_A 0x00000000 /* C---V */ +#define NV_PMC_BOOT_0_MAJOR_REVISION_B 0x00000001 /* ----V */ +#define NV_PMC_BOOT_0_IMPLEMENTATION 11:8 /* C--VF */ +#define NV_PMC_BOOT_0_IMPLEMENTATION_NV4_0 0x00000000 /* C---V */ +#define NV_PMC_BOOT_0_ARCHITECTURE 15:12 /* C--VF */ +#define NV_PMC_BOOT_0_ARCHITECTURE_NV0 0x00000000 /* ----V */ +#define NV_PMC_BOOT_0_ARCHITECTURE_NV1 0x00000001 /* ----V */ +#define NV_PMC_BOOT_0_ARCHITECTURE_NV2 0x00000002 /* ----V */ +#define NV_PMC_BOOT_0_ARCHITECTURE_NV3 0x00000003 /* ----V */ +#define NV_PMC_BOOT_0_ARCHITECTURE_NV4 0x00000004 /* C---V */ +#define NV_PMC_BOOT_0_FIB_REVISION 19:16 /* C--VF */ +#define NV_PMC_BOOT_0_FIB_REVISION_0 0x00000000 /* C---V */ +#define NV_PMC_BOOT_0_MASK_REVISION 23:20 /* C--VF */ +#define NV_PMC_BOOT_0_MASK_REVISION_A 0x00000000 /* C---V */ +#define NV_PMC_BOOT_0_MASK_REVISION_B 0x00000001 /* ----V */ +#define NV_PMC_BOOT_0_MANUFACTURER 27:24 /* C--UF */ +#define NV_PMC_BOOT_0_MANUFACTURER_NVIDIA 0x00000000 /* C---V */ +#define NV_PMC_BOOT_0_FOUNDRY 31:28 /* C--VF */ +#define NV_PMC_BOOT_0_FOUNDRY_SGS 0x00000000 /* ----V */ +#define NV_PMC_BOOT_0_FOUNDRY_HELIOS 0x00000001 /* ----V */ +#define NV_PMC_BOOT_0_FOUNDRY_TSMC 0x00000002 /* C---V */ +#define NV_PMC_INTR_0 0x00000100 /* RW-4R */ +#define NV_PMC_INTR_0_PMEDIA 4:4 /* R--VF */ +#define NV_PMC_INTR_0_PMEDIA_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PMC_INTR_0_PMEDIA_PENDING 0x00000001 /* R---V */ +#define NV_PMC_INTR_0_PFIFO 8:8 /* R--VF */ +#define NV_PMC_INTR_0_PFIFO_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PMC_INTR_0_PFIFO_PENDING 0x00000001 /* R---V */ +#define NV_PMC_INTR_0_PGRAPH 12:12 /* R--VF */ +#define NV_PMC_INTR_0_PGRAPH_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PMC_INTR_0_PGRAPH_PENDING 0x00000001 /* R---V */ +#define NV_PMC_INTR_0_PVIDEO 16:16 /* R--VF */ +#define NV_PMC_INTR_0_PVIDEO_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PMC_INTR_0_PVIDEO_PENDING 0x00000001 /* R---V */ +#define NV_PMC_INTR_0_PTIMER 20:20 /* R--VF */ +#define NV_PMC_INTR_0_PTIMER_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PMC_INTR_0_PTIMER_PENDING 0x00000001 /* R---V */ +#define NV_PMC_INTR_0_PCRTC 24:24 /* R--VF */ +#define NV_PMC_INTR_0_PCRTC_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PMC_INTR_0_PCRTC_PENDING 0x00000001 /* R---V */ +#define NV_PMC_INTR_0_PBUS 28:28 /* R--VF */ +#define NV_PMC_INTR_0_PBUS_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PMC_INTR_0_PBUS_PENDING 0x00000001 /* R---V */ +#define NV_PMC_INTR_0_SOFTWARE 31:31 /* RWIVF */ +#define NV_PMC_INTR_0_SOFTWARE_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PMC_INTR_0_SOFTWARE_PENDING 0x00000001 /* RW--V */ +#define NV_PMC_INTR_EN_0 0x00000140 /* RW-4R */ +#define NV_PMC_INTR_EN_0_INTA 1:0 /* RWIVF */ +#define NV_PMC_INTR_EN_0_INTA_DISABLED 0x00000000 /* RWI-V */ +#define NV_PMC_INTR_EN_0_INTA_HARDWARE 0x00000001 /* RW--V */ +#define NV_PMC_INTR_EN_0_INTA_SOFTWARE 0x00000002 /* RW--V */ +#define NV_PMC_INTR_READ_0 0x00000160 /* R--4R */ +#define NV_PMC_INTR_READ_0_INTA 0:0 /* R--VF */ +#define NV_PMC_INTR_READ_0_INTA_LOW 0x00000000 /* R---V */ +#define NV_PMC_INTR_READ_0_INTA_HIGH 0x00000001 /* R---V */ +#define NV_PMC_ENABLE 0x00000200 /* RW-4R */ +#define NV_PMC_ENABLE_PMEDIA 4:4 /* RWIVF */ +#define NV_PMC_ENABLE_PMEDIA_DISABLED 0x00000000 /* RWI-V */ +#define NV_PMC_ENABLE_PMEDIA_ENABLED 0x00000001 /* RW--V */ +#define NV_PMC_ENABLE_PFIFO 8:8 /* RWIVF */ +#define NV_PMC_ENABLE_PFIFO_DISABLED 0x00000000 /* RWI-V */ +#define NV_PMC_ENABLE_PFIFO_ENABLED 0x00000001 /* RW--V */ +#define NV_PMC_ENABLE_PGRAPH 12:12 /* RWIVF */ +#define NV_PMC_ENABLE_PGRAPH_DISABLED 0x00000000 /* RWI-V */ +#define NV_PMC_ENABLE_PGRAPH_ENABLED 0x00000001 /* RW--V */ +#define NV_PMC_ENABLE_PPMI 16:16 /* RWIVF */ +#define NV_PMC_ENABLE_PPMI_DISABLED 0x00000000 /* RWI-V */ +#define NV_PMC_ENABLE_PPMI_ENABLED 0x00000001 /* RW--V */ +#define NV_PMC_ENABLE_PFB 20:20 /* RWIVF */ +#define NV_PMC_ENABLE_PFB_DISABLED 0x00000000 /* RW--V */ +#define NV_PMC_ENABLE_PFB_ENABLED 0x00000001 /* RWI-V */ +#define NV_PMC_ENABLE_PCRTC 24:24 /* RWIVF */ +#define NV_PMC_ENABLE_PCRTC_DISABLED 0x00000000 /* RW--V */ +#define NV_PMC_ENABLE_PCRTC_ENABLED 0x00000001 /* RWI-V */ +#define NV_PMC_ENABLE_PVIDEO 28:28 /* RWIVF */ +#define NV_PMC_ENABLE_PVIDEO_DISABLED 0x00000000 /* RWI-V */ +#define NV_PMC_ENABLE_PVIDEO_ENABLED 0x00000001 /* RW--V */ + +/* dev_timer.ref */ +#define NV_PTIMER 0x00009FFF:0x00009000 /* RW--D */ +#define NV_PTIMER_INTR_0 0x00009100 /* RW-4R */ +#define NV_PTIMER_INTR_0_ALARM 0:0 /* RWXVF */ +#define NV_PTIMER_INTR_0_ALARM_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PTIMER_INTR_0_ALARM_PENDING 0x00000001 /* R---V */ +#define NV_PTIMER_INTR_0_ALARM_RESET 0x00000001 /* -W--V */ +#define NV_PTIMER_INTR_EN_0 0x00009140 /* RW-4R */ +#define NV_PTIMER_INTR_EN_0_ALARM 0:0 /* RWIVF */ +#define NV_PTIMER_INTR_EN_0_ALARM_DISABLED 0x00000000 /* RWI-V */ +#define NV_PTIMER_INTR_EN_0_ALARM_ENABLED 0x00000001 /* RW--V */ +#define NV_PTIMER_NUMERATOR 0x00009200 /* RW-4R */ +#define NV_PTIMER_NUMERATOR_VALUE 15:0 /* RWIUF */ +#define NV_PTIMER_NUMERATOR_VALUE_0 0x00000000 /* RWI-V */ +#define NV_PTIMER_DENOMINATOR 0x00009210 /* RW-4R */ +#define NV_PTIMER_DENOMINATOR_VALUE 15:0 /* RWIUF */ +#define NV_PTIMER_DENOMINATOR_VALUE_0 0x00000000 /* RWI-V */ +#define NV_PTIMER_TIME_0 0x00009400 /* RW-4R */ +#define NV_PTIMER_TIME_0_NSEC 31:5 /* RWXUF */ +#define NV_PTIMER_TIME_1 0x00009410 /* RW-4R */ +#define NV_PTIMER_TIME_1_NSEC 28:0 /* RWXUF */ +#define NV_PTIMER_ALARM_0 0x00009420 /* RW-4R */ +#define NV_PTIMER_ALARM_0_NSEC 31:5 /* RWXUF */ + +/* dev_fifo.ref */ +#define NV_PFIFO 0x00003FFF:0x00002000 /* RW--D */ +#define NV_PFIFO_DELAY_0 0x00002040 /* RW-4R */ +#define NV_PFIFO_DELAY_0_WAIT_RETRY 9:0 /* RWIUF */ +#define NV_PFIFO_DELAY_0_WAIT_RETRY_0 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_TIMESLICE 0x00002044 /* RW-4R */ +#define NV_PFIFO_DMA_TIMESLICE_SELECT 16:0 /* RWIUF */ +#define NV_PFIFO_DMA_TIMESLICE_SELECT_1 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_TIMESLICE_SELECT_16K 0x00003fff /* RW--V */ +#define NV_PFIFO_DMA_TIMESLICE_SELECT_32K 0x00007fff /* RW--V */ +#define NV_PFIFO_DMA_TIMESLICE_SELECT_64K 0x0000ffff /* RW--V */ +#define NV_PFIFO_DMA_TIMESLICE_SELECT_128K 0x0001ffff /* RW--V */ +#define NV_PFIFO_DMA_TIMESLICE_TIMEOUT 24:24 /* RWIUF */ +#define NV_PFIFO_DMA_TIMESLICE_TIMEOUT_DISABLED 0x00000000 /* RW--V */ +#define NV_PFIFO_DMA_TIMESLICE_TIMEOUT_ENABLED 0x00000001 /* RWI-V */ +#define NV_PFIFO_PIO_TIMESLICE 0x00002048 /* RW-4R */ +#define NV_PFIFO_PIO_TIMESLICE_SELECT 16:0 /* RWIUF */ +#define NV_PFIFO_PIO_TIMESLICE_SELECT_1 0x00000000 /* RWI-V */ +#define NV_PFIFO_PIO_TIMESLICE_SELECT_16K 0x00003fff /* RW--V */ +#define NV_PFIFO_PIO_TIMESLICE_SELECT_32K 0x00007fff /* RW--V */ +#define NV_PFIFO_PIO_TIMESLICE_SELECT_64K 0x0000ffff /* RW--V */ +#define NV_PFIFO_PIO_TIMESLICE_SELECT_128K 0x0001ffff /* RW--V */ +#define NV_PFIFO_PIO_TIMESLICE_TIMEOUT 24:24 /* RWIUF */ +#define NV_PFIFO_PIO_TIMESLICE_TIMEOUT_DISABLED 0x00000000 /* RW--V */ +#define NV_PFIFO_PIO_TIMESLICE_TIMEOUT_ENABLED 0x00000001 /* RWI-V */ +#define NV_PFIFO_TIMESLICE 0x0000204C /* RW-4R */ +#define NV_PFIFO_TIMESLICE_TIMER 17:0 /* RWIUF */ +#define NV_PFIFO_TIMESLICE_TIMER_EXPIRED 0x0003FFFF /* RWI-V */ +#define NV_PFIFO_NEXT_CHANNEL 0x00002050 /* RW-4R */ +#define NV_PFIFO_NEXT_CHANNEL_CHID 3:0 /* RWXUF */ +#define NV_PFIFO_NEXT_CHANNEL_MODE 8:8 /* RWXVF */ +#define NV_PFIFO_NEXT_CHANNEL_MODE_PIO 0x00000000 /* RW--V */ +#define NV_PFIFO_NEXT_CHANNEL_MODE_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_NEXT_CHANNEL_SWITCH 12:12 /* RWIVF */ +#define NV_PFIFO_NEXT_CHANNEL_SWITCH_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_NEXT_CHANNEL_SWITCH_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DEBUG_0 0x00002080 /* R--4R */ +#define NV_PFIFO_DEBUG_0_CACHE_ERROR0 0:0 /* R-XVF */ +#define NV_PFIFO_DEBUG_0_CACHE_ERROR0_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PFIFO_DEBUG_0_CACHE_ERROR0_PENDING 0x00000001 /* R---V */ +#define NV_PFIFO_DEBUG_0_CACHE_ERROR1 4:4 /* R-XVF */ +#define NV_PFIFO_DEBUG_0_CACHE_ERROR1_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PFIFO_DEBUG_0_CACHE_ERROR1_PENDING 0x00000001 /* R---V */ +#define NV_PFIFO_INTR_0 0x00002100 /* RW-4R */ +#define NV_PFIFO_INTR_0_CACHE_ERROR 0:0 /* RWXVF */ +#define NV_PFIFO_INTR_0_CACHE_ERROR_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PFIFO_INTR_0_CACHE_ERROR_PENDING 0x00000001 /* R---V */ +#define NV_PFIFO_INTR_0_CACHE_ERROR_RESET 0x00000001 /* -W--V */ +#define NV_PFIFO_INTR_0_RUNOUT 4:4 /* RWXVF */ +#define NV_PFIFO_INTR_0_RUNOUT_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PFIFO_INTR_0_RUNOUT_PENDING 0x00000001 /* R---V */ +#define NV_PFIFO_INTR_0_RUNOUT_RESET 0x00000001 /* -W--V */ +#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW 8:8 /* RWXVF */ +#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW_PENDING 0x00000001 /* R---V */ +#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW_RESET 0x00000001 /* -W--V */ +#define NV_PFIFO_INTR_0_DMA_PUSHER 12:12 /* RWXVF */ +#define NV_PFIFO_INTR_0_DMA_PUSHER_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PFIFO_INTR_0_DMA_PUSHER_PENDING 0x00000001 /* R---V */ +#define NV_PFIFO_INTR_0_DMA_PUSHER_RESET 0x00000001 /* -W--V */ +#define NV_PFIFO_INTR_0_DMA_PT 16:16 /* RWXVF */ +#define NV_PFIFO_INTR_0_DMA_PT_NOT_PENDING 0x00000000 /* R---V */ +#define NV_PFIFO_INTR_0_DMA_PT_PENDING 0x00000001 /* R---V */ +#define NV_PFIFO_INTR_0_DMA_PT_RESET 0x00000001 /* -W--V */ +#define NV_PFIFO_INTR_EN_0 0x00002140 /* RW-4R */ +#define NV_PFIFO_INTR_EN_0_CACHE_ERROR 0:0 /* RWIVF */ +#define NV_PFIFO_INTR_EN_0_CACHE_ERROR_DISABLED 0x00000000 /* RWI-V */ +#define NV_PFIFO_INTR_EN_0_CACHE_ERROR_ENABLED 0x00000001 /* RW--V */ +#define NV_PFIFO_INTR_EN_0_RUNOUT 4:4 /* RWIVF */ +#define NV_PFIFO_INTR_EN_0_RUNOUT_DISABLED 0x00000000 /* RWI-V */ +#define NV_PFIFO_INTR_EN_0_RUNOUT_ENABLED 0x00000001 /* RW--V */ +#define NV_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW 8:8 /* RWIVF */ +#define NV_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW_DISABLED 0x00000000 /* RWI-V */ +#define NV_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW_ENABLED 0x00000001 /* RW--V */ +#define NV_PFIFO_INTR_EN_0_DMA_PUSHER 12:12 /* RWIVF */ +#define NV_PFIFO_INTR_EN_0_DMA_PUSHER_DISABLED 0x00000000 /* RWI-V */ +#define NV_PFIFO_INTR_EN_0_DMA_PUSHER_ENABLED 0x00000001 /* RW--V */ +#define NV_PFIFO_INTR_EN_0_DMA_PT 16:16 /* RWIVF */ +#define NV_PFIFO_INTR_EN_0_DMA_PT_DISABLED 0x00000000 /* RWI-V */ +#define NV_PFIFO_INTR_EN_0_DMA_PT_ENABLED 0x00000001 /* RW--V */ +#define NV_PFIFO_RAMHT 0x00002210 /* RW-4R */ +#define NV_PFIFO_RAMHT_BASE_ADDRESS 8:4 /* RWIUF */ +#define NV_PFIFO_RAMHT_BASE_ADDRESS_10000 0x00000010 /* RWI-V */ +#define NV_PFIFO_RAMHT_SIZE 17:16 /* RWIUF */ +#define NV_PFIFO_RAMHT_SIZE_4K 0x00000000 /* RWI-V */ +#define NV_PFIFO_RAMHT_SIZE_8K 0x00000001 /* RW--V */ +#define NV_PFIFO_RAMHT_SIZE_16K 0x00000002 /* RW--V */ +#define NV_PFIFO_RAMHT_SIZE_32K 0x00000003 /* RW--V */ +#define NV_PFIFO_RAMHT_SEARCH 25:24 /* RWIUF */ +#define NV_PFIFO_RAMHT_SEARCH_16 0x00000000 /* RWI-V */ +#define NV_PFIFO_RAMHT_SEARCH_32 0x00000001 /* RW--V */ +#define NV_PFIFO_RAMHT_SEARCH_64 0x00000002 /* RW--V */ +#define NV_PFIFO_RAMHT_SEARCH_128 0x00000003 /* RW--V */ +#define NV_PFIFO_RAMFC 0x00002214 /* RW-4R */ +#define NV_PFIFO_RAMFC_BASE_ADDRESS 8:1 /* RWIUF */ +#define NV_PFIFO_RAMFC_BASE_ADDRESS_11000 0x00000088 /* RWI-V */ +#define NV_PFIFO_RAMRO 0x00002218 /* RW-4R */ +#define NV_PFIFO_RAMRO_BASE_ADDRESS 8:1 /* RWIUF */ +#define NV_PFIFO_RAMRO_BASE_ADDRESS_11200 0x00000089 /* RWI-V */ +#define NV_PFIFO_RAMRO_BASE_ADDRESS_12000 0x00000090 /* RW--V */ +#define NV_PFIFO_RAMRO_SIZE 16:16 /* RWIVF */ +#define NV_PFIFO_RAMRO_SIZE_512 0x00000000 /* RWI-V */ +#define NV_PFIFO_RAMRO_SIZE_8K 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHES 0x00002500 /* RW-4R */ +#define NV_PFIFO_CACHES_REASSIGN 0:0 /* RWIVF */ +#define NV_PFIFO_CACHES_REASSIGN_DISABLED 0x00000000 /* RWI-V */ +#define NV_PFIFO_CACHES_REASSIGN_ENABLED 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHES_DMA_SUSPEND 4:4 /* R--VF */ +#define NV_PFIFO_CACHES_DMA_SUSPEND_IDLE 0x00000000 /* R---V */ +#define NV_PFIFO_CACHES_DMA_SUSPEND_BUSY 0x00000001 /* R---V */ +#define NV_PFIFO_MODE 0x00002504 /* RW-4R */ +#define NV_PFIFO_MODE_CHANNEL_0 0:0 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_0_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_0_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_1 1:1 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_1_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_1_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_2 2:2 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_2_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_2_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_3 3:3 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_3_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_3_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_4 4:4 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_4_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_4_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_5 5:5 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_5_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_5_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_6 6:6 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_6_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_6_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_7 7:7 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_7_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_7_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_8 8:8 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_8_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_8_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_9 9:9 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_9_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_9_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_10 10:10 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_10_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_10_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_11 11:11 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_11_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_11_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_12 12:12 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_12_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_12_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_13 13:13 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_13_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_13_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_14 14:14 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_14_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_14_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_MODE_CHANNEL_15 15:15 /* RWIVF */ +#define NV_PFIFO_MODE_CHANNEL_15_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_MODE_CHANNEL_15_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA 0x00002508 /* RW-4R */ +#define NV_PFIFO_DMA_CHANNEL_0 0:0 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_0_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_0_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_1 1:1 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_1_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_1_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_2 2:2 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_2_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_2_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_3 3:3 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_3_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_3_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_4 4:4 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_4_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_4_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_5 5:5 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_5_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_5_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_6 6:6 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_6_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_6_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_7 7:7 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_7_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_7_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_8 8:8 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_8_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_8_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_9 9:9 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_9_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_9_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_10 10:10 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_10_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_10_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_11 11:11 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_11_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_11_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_12 12:12 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_12_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_12_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_13 13:13 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_13_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_13_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_14 14:14 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_14_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_14_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_DMA_CHANNEL_15 15:15 /* RWIVF */ +#define NV_PFIFO_DMA_CHANNEL_15_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PFIFO_DMA_CHANNEL_15_PENDING 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE 0x0000250C /* RW-4R */ +#define NV_PFIFO_SIZE_CHANNEL_0 0:0 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_0_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_0_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_1 1:1 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_1_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_1_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_2 2:2 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_2_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_2_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_3 3:3 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_3_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_3_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_4 4:4 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_4_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_4_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_5 5:5 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_5_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_5_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_6 6:6 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_6_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_6_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_7 7:7 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_7_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_7_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_8 8:8 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_8_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_8_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_9 9:9 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_9_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_9_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_10 10:10 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_10_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_10_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_11 11:11 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_11_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_11_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_12 12:12 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_12_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_12_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_13 13:13 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_13_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_13_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_14 14:14 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_14_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_14_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_SIZE_CHANNEL_15 15:15 /* RWIVF */ +#define NV_PFIFO_SIZE_CHANNEL_15_124_BYTES 0x00000000 /* RWI-V */ +#define NV_PFIFO_SIZE_CHANNEL_15_512_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE0_PUSH0 0x00003000 /* RW-4R */ +#define NV_PFIFO_CACHE0_PUSH0_ACCESS 0:0 /* RWIVF */ +#define NV_PFIFO_CACHE0_PUSH0_ACCESS_DISABLED 0x00000000 /* RWI-V */ +#define NV_PFIFO_CACHE0_PUSH0_ACCESS_ENABLED 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_PUSH0 0x00003200 /* RW-4R */ +#define NV_PFIFO_CACHE1_PUSH0_ACCESS 0:0 /* RWIVF */ +#define NV_PFIFO_CACHE1_PUSH0_ACCESS_DISABLED 0x00000000 /* RWI-V */ +#define NV_PFIFO_CACHE1_PUSH0_ACCESS_ENABLED 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE0_PUSH1 0x00003004 /* RW-4R */ +#define NV_PFIFO_CACHE0_PUSH1_CHID 3:0 /* RWXUF */ +#define NV_PFIFO_CACHE1_PUSH1 0x00003204 /* RW-4R */ +#define NV_PFIFO_CACHE1_PUSH1_CHID 3:0 /* RWXUF */ +#define NV_PFIFO_CACHE1_PUSH1_MODE 8:8 /* RWIVF */ +#define NV_PFIFO_CACHE1_PUSH1_MODE_PIO 0x00000000 /* RWI-V */ +#define NV_PFIFO_CACHE1_PUSH1_MODE_DMA 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_PUSH 0x00003220 /* RW-4R */ +#define NV_PFIFO_CACHE1_DMA_PUSH_ACCESS 0:0 /* RWIVF */ +#define NV_PFIFO_CACHE1_DMA_PUSH_ACCESS_DISABLED 0x00000000 /* RWI-V */ +#define NV_PFIFO_CACHE1_DMA_PUSH_ACCESS_ENABLED 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_PUSH_STATE 4:4 /* R--VF */ +#define NV_PFIFO_CACHE1_DMA_PUSH_STATE_IDLE 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE1_DMA_PUSH_STATE_BUSY 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE1_DMA_PUSH_BUFFER 8:8 /* R--VF */ +#define NV_PFIFO_CACHE1_DMA_PUSH_BUFFER_NOT_EMPTY 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE1_DMA_PUSH_BUFFER_EMPTY 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE1_DMA_PUSH_STATUS 12:12 /* RWIVF */ +#define NV_PFIFO_CACHE1_DMA_PUSH_STATUS_RUNNING 0x00000000 /* RWI-V */ +#define NV_PFIFO_CACHE1_DMA_PUSH_STATUS_SUSPENDED 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH 0x00003224 /* RW-4R */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG 7:3 /* RWIUF */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x00000003 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x00000004 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x00000005 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x00000006 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x00000007 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x00000008 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x00000009 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0x0000000A /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0x0000000B /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0x0000000C /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0x0000000D /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0x0000000E /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0x0000000F /* RWI-V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x00000010 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x00000011 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x00000012 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x00000013 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x00000014 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x00000015 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x00000016 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x00000017 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x00000018 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x00000019 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x0000001A /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x0000001B /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x0000001C /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x0000001D /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x0000001E /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x0000001F /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE 15:13 /* RWIUF */ +#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x00000003 /* RWI-V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x00000004 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x00000005 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x00000006 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x00000007 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 19:16 /* RWIUF */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0 0x00000000 /* RWI-V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3 0x00000003 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 0x00000004 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5 0x00000005 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6 0x00000006 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7 0x00000007 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 0x00000008 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9 0x00000009 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10 0x0000000A /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11 0x0000000B /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12 0x0000000C /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13 0x0000000D /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14 0x0000000E /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15 0x0000000F /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_PUT 0x00003240 /* RW-4R */ +#define NV_PFIFO_CACHE1_DMA_PUT_OFFSET 28:2 /* RWXUF */ +#define NV_PFIFO_CACHE1_DMA_GET 0x00003244 /* RW-4R */ +#define NV_PFIFO_CACHE1_DMA_GET_OFFSET 28:2 /* RWXUF */ +#define NV_PFIFO_CACHE1_DMA_STATE 0x00003228 /* RW-4R */ +#define NV_PFIFO_CACHE1_DMA_STATE_METHOD 12:2 /* RWXUF */ +#define NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL 15:13 /* RWXUF */ +#define NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT 28:18 /* RWIUF */ +#define NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT_0 0x00000000 /* RWI-V */ +#define NV_PFIFO_CACHE1_DMA_STATE_ERROR 31:30 /* RWXUF */ +#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_NONE 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_NON_CACHE 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_PROTECTION 0x00000003 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_INSTANCE 0x0000322C /* RW-4R */ +#define NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS 15:0 /* RWXUF */ +#define NV_PFIFO_CACHE1_DMA_CTL 0x00003230 /* RW-4R */ +#define NV_PFIFO_CACHE1_DMA_CTL_ADJUST 11:2 /* RWXUF */ +#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE 12:12 /* RWXUF */ +#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE_NOT_PRESENT 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE_PRESENT 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY 13:13 /* RWXUF */ +#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY_NOT_LINEAR 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY_LINEAR 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_CTL_TARGET_NODE 17:16 /* RWXUF */ +#define NV_PFIFO_CACHE1_DMA_CTL_TARGET_NODE_PCI 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_CTL_TARGET_NODE_AGP 0x00000003 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_CTL_AT_INFO 31:31 /* RWIUF */ +#define NV_PFIFO_CACHE1_DMA_CTL_AT_INFO_INVALID 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_CTL_AT_INFO_VALID 0x00000001 /* RWI-V */ +#define NV_PFIFO_CACHE1_DMA_LIMIT 0x00003234 /* RW-4R */ +#define NV_PFIFO_CACHE1_DMA_LIMIT_OFFSET 28:2 /* RWXUF */ +#define NV_PFIFO_CACHE1_DMA_TLB_TAG 0x00003238 /* RW-4R */ +#define NV_PFIFO_CACHE1_DMA_TLB_TAG_ADDRESS 28:12 /* RWXUF */ +#define NV_PFIFO_CACHE1_DMA_TLB_TAG_STATE 0:0 /* RWIUF */ +#define NV_PFIFO_CACHE1_DMA_TLB_TAG_STATE_INVALID 0x00000000 /* RWI-V */ +#define NV_PFIFO_CACHE1_DMA_TLB_TAG_STATE_VALID 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_DMA_TLB_PTE 0x0000323C /* RW-4R */ +#define NV_PFIFO_CACHE1_DMA_TLB_PTE_FRAME_ADDRESS 31:12 /* RWXUF */ +#define NV_PFIFO_CACHE0_PULL0 0x00003050 /* RW-4R */ +#define NV_PFIFO_CACHE0_PULL0_ACCESS 0:0 /* RWIVF */ +#define NV_PFIFO_CACHE0_PULL0_ACCESS_DISABLED 0x00000000 /* RWI-V */ +#define NV_PFIFO_CACHE0_PULL0_ACCESS_ENABLED 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE0_PULL0_HASH 4:4 /* R-XVF */ +#define NV_PFIFO_CACHE0_PULL0_HASH_SUCCEEDED 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE0_PULL0_HASH_FAILED 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE0_PULL0_DEVICE 8:8 /* R-XVF */ +#define NV_PFIFO_CACHE0_PULL0_DEVICE_HARDWARE 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE0_PULL0_DEVICE_SOFTWARE 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE0_PULL0_HASH_STATE 12:12 /* R-XVF */ +#define NV_PFIFO_CACHE0_PULL0_HASH_STATE_IDLE 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE0_PULL0_HASH_STATE_BUSY 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE1_PULL0 0x00003250 /* RW-4R */ +#define NV_PFIFO_CACHE1_PULL0_ACCESS 0:0 /* RWIVF */ +#define NV_PFIFO_CACHE1_PULL0_ACCESS_DISABLED 0x00000000 /* RWI-V */ +#define NV_PFIFO_CACHE1_PULL0_ACCESS_ENABLED 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_PULL0_HASH 4:4 /* R-XVF */ +#define NV_PFIFO_CACHE1_PULL0_HASH_SUCCEEDED 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE1_PULL0_DEVICE 8:8 /* R-XVF */ +#define NV_PFIFO_CACHE1_PULL0_DEVICE_HARDWARE 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE1_PULL0_DEVICE_SOFTWARE 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE1_PULL0_HASH_STATE 12:12 /* R-XVF */ +#define NV_PFIFO_CACHE1_PULL0_HASH_STATE_IDLE 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE1_PULL0_HASH_STATE_BUSY 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE0_PULL1 0x00003054 /* RW-4R */ +#define NV_PFIFO_CACHE0_PULL1_ENGINE 1:0 /* RWXUF */ +#define NV_PFIFO_CACHE0_PULL1_ENGINE_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE0_PULL1_ENGINE_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE0_PULL1_ENGINE_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_PULL1 0x00003254 /* RW-4R */ +#define NV_PFIFO_CACHE1_PULL1_ENGINE 1:0 /* RWXUF */ +#define NV_PFIFO_CACHE1_PULL1_ENGINE_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_PULL1_ENGINE_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_PULL1_ENGINE_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE0_HASH 0x00003058 /* RW-4R */ +#define NV_PFIFO_CACHE0_HASH_INSTANCE 15:0 /* RWXUF */ +#define NV_PFIFO_CACHE0_HASH_VALID 16:16 /* RWXVF */ +#define NV_PFIFO_CACHE1_HASH 0x00003258 /* RW-4R */ +#define NV_PFIFO_CACHE1_HASH_INSTANCE 15:0 /* RWXUF */ +#define NV_PFIFO_CACHE1_HASH_VALID 16:16 /* RWXVF */ +#define NV_PFIFO_CACHE0_STATUS 0x00003014 /* R--4R */ +#define NV_PFIFO_CACHE0_STATUS_LOW_MARK 4:4 /* R--VF */ +#define NV_PFIFO_CACHE0_STATUS_LOW_MARK_NOT_EMPTY 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE0_STATUS_LOW_MARK_EMPTY 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE0_STATUS_HIGH_MARK 8:8 /* R--VF */ +#define NV_PFIFO_CACHE0_STATUS_HIGH_MARK_NOT_FULL 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE0_STATUS_HIGH_MARK_FULL 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE1_STATUS 0x00003214 /* R--4R */ +#define NV_PFIFO_CACHE1_STATUS_LOW_MARK 4:4 /* R--VF */ +#define NV_PFIFO_CACHE1_STATUS_LOW_MARK_NOT_EMPTY 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE1_STATUS_LOW_MARK_EMPTY 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE1_STATUS_HIGH_MARK 8:8 /* R--VF */ +#define NV_PFIFO_CACHE1_STATUS_HIGH_MARK_NOT_FULL 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE1_STATUS_HIGH_MARK_FULL 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE1_STATUS1 0x00003218 /* R--4R */ +#define NV_PFIFO_CACHE1_STATUS1_RANOUT 0:0 /* R-XVF */ +#define NV_PFIFO_CACHE1_STATUS1_RANOUT_FALSE 0x00000000 /* R---V */ +#define NV_PFIFO_CACHE1_STATUS1_RANOUT_TRUE 0x00000001 /* R---V */ +#define NV_PFIFO_CACHE0_PUT 0x00003010 /* RW-4R */ +#define NV_PFIFO_CACHE0_PUT_ADDRESS 2:2 /* RWXUF */ +#define NV_PFIFO_CACHE1_PUT 0x00003210 /* RW-4R */ +#define NV_PFIFO_CACHE1_PUT_ADDRESS 9:2 /* RWXUF */ +#define NV_PFIFO_CACHE0_GET 0x00003070 /* RW-4R */ +#define NV_PFIFO_CACHE0_GET_ADDRESS 2:2 /* RWXUF */ +#define NV_PFIFO_CACHE1_GET 0x00003270 /* RW-4R */ +#define NV_PFIFO_CACHE1_GET_ADDRESS 9:2 /* RWXUF */ +#define NV_PFIFO_CACHE0_ENGINE 0x00003080 /* RW-4R */ +#define NV_PFIFO_CACHE0_ENGINE_0 1:0 /* RWXUF */ +#define NV_PFIFO_CACHE0_ENGINE_0_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_0_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_0_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_1 5:4 /* RWXUF */ +#define NV_PFIFO_CACHE0_ENGINE_1_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_1_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_1_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_2 9:8 /* RWXUF */ +#define NV_PFIFO_CACHE0_ENGINE_2_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_2_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_2_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_3 13:12 /* RWXUF */ +#define NV_PFIFO_CACHE0_ENGINE_3_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_3_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_3_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_4 17:16 /* RWXUF */ +#define NV_PFIFO_CACHE0_ENGINE_4_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_4_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_4_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_5 21:20 /* RWXUF */ +#define NV_PFIFO_CACHE0_ENGINE_5_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_5_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_5_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_6 25:24 /* RWXUF */ +#define NV_PFIFO_CACHE0_ENGINE_6_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_6_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_6_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_7 29:28 /* RWXUF */ +#define NV_PFIFO_CACHE0_ENGINE_7_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_7_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE0_ENGINE_7_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE 0x00003280 /* RW-4R */ +#define NV_PFIFO_CACHE1_ENGINE_0 1:0 /* RWXUF */ +#define NV_PFIFO_CACHE1_ENGINE_0_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_0_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_0_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_1 5:4 /* RWXUF */ +#define NV_PFIFO_CACHE1_ENGINE_1_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_1_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_1_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_2 9:8 /* RWXUF */ +#define NV_PFIFO_CACHE1_ENGINE_2_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_2_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_2_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_3 13:12 /* RWXUF */ +#define NV_PFIFO_CACHE1_ENGINE_3_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_3_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_3_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_4 17:16 /* RWXUF */ +#define NV_PFIFO_CACHE1_ENGINE_4_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_4_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_4_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_5 21:20 /* RWXUF */ +#define NV_PFIFO_CACHE1_ENGINE_5_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_5_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_5_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_6 25:24 /* RWXUF */ +#define NV_PFIFO_CACHE1_ENGINE_6_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_6_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_6_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_7 29:28 /* RWXUF */ +#define NV_PFIFO_CACHE1_ENGINE_7_SW 0x00000000 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_7_GRAPHICS 0x00000001 /* RW--V */ +#define NV_PFIFO_CACHE1_ENGINE_7_DVD 0x00000002 /* RW--V */ +#define NV_PFIFO_CACHE0_METHOD(i) (0x00003100+(i)*8) /* RW-4A */ +#define NV_PFIFO_CACHE0_METHOD__SIZE_1 1 /* */ +#define NV_PFIFO_CACHE0_METHOD_ADDRESS 12:2 /* RWXUF */ +#define NV_PFIFO_CACHE0_METHOD_SUBCHANNEL 15:13 /* RWXUF */ +#define NV_PFIFO_CACHE1_METHOD(i) (0x00003800+(i)*8) /* RW-4A */ +#define NV_PFIFO_CACHE1_METHOD__SIZE_1 128 /* */ +#define NV_PFIFO_CACHE1_METHOD_ADDRESS 12:2 /* RWXUF */ +#define NV_PFIFO_CACHE1_METHOD_SUBCHANNEL 15:13 /* RWXUF */ +#define NV_PFIFO_CACHE1_METHOD_ALIAS(i) (0x00003C00+(i)*8) /* RW-4A */ +#define NV_PFIFO_CACHE1_METHOD_ALIAS__SIZE_1 128 /* */ +#define NV_PFIFO_CACHE0_DATA(i) (0x00003104+(i)*8) /* RW-4A */ +#define NV_PFIFO_CACHE0_DATA__SIZE_1 1 /* */ +#define NV_PFIFO_CACHE0_DATA_VALUE 31:0 /* RWXVF */ +#define NV_PFIFO_CACHE1_DATA(i) (0x00003804+(i)*8) /* RW-4A */ +#define NV_PFIFO_CACHE1_DATA__SIZE_1 128 /* */ +#define NV_PFIFO_CACHE1_DATA_VALUE 31:0 /* RWXVF */ +#define NV_PFIFO_CACHE1_DATA_ALIAS(i) (0x00003C04+(i)*8) /* RW-4A */ +#define NV_PFIFO_CACHE1_DATA_ALIAS__SIZE_1 128 /* */ +#define NV_PFIFO_DEVICE(i) (0x00002800+(i)*4) /* R--4A */ +#define NV_PFIFO_DEVICE__SIZE_1 128 /* */ +#define NV_PFIFO_DEVICE_CHID 3:0 /* R--UF */ +#define NV_PFIFO_DEVICE_SWITCH 24:24 /* R--VF */ +#define NV_PFIFO_DEVICE_SWITCH_UNAVAILABLE 0x00000000 /* R---V */ +#define NV_PFIFO_DEVICE_SWITCH_AVAILABLE 0x00000001 /* R---V */ +#define NV_PFIFO_RUNOUT_STATUS 0x00002400 /* R--4R */ +#define NV_PFIFO_RUNOUT_STATUS_RANOUT 0:0 /* R--VF */ +#define NV_PFIFO_RUNOUT_STATUS_RANOUT_FALSE 0x00000000 /* R---V */ +#define NV_PFIFO_RUNOUT_STATUS_RANOUT_TRUE 0x00000001 /* R---V */ +#define NV_PFIFO_RUNOUT_STATUS_LOW_MARK 4:4 /* R--VF */ +#define NV_PFIFO_RUNOUT_STATUS_LOW_MARK_NOT_EMPTY 0x00000000 /* R---V */ +#define NV_PFIFO_RUNOUT_STATUS_LOW_MARK_EMPTY 0x00000001 /* R---V */ +#define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK 8:8 /* R--VF */ +#define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK_NOT_FULL 0x00000000 /* R---V */ +#define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK_FULL 0x00000001 /* R---V */ +#define NV_PFIFO_RUNOUT_PUT 0x00002410 /* RW-4R */ +#define NV_PFIFO_RUNOUT_PUT_ADDRESS 12:3 /* RWXUF */ +#define NV_PFIFO_RUNOUT_PUT_ADDRESS__SIZE_0 8:3 /* RWXUF */ +#define NV_PFIFO_RUNOUT_PUT_ADDRESS__SIZE_1 12:3 /* RWXUF */ +#define NV_PFIFO_RUNOUT_GET 0x00002420 /* RW-4R */ +#define NV_PFIFO_RUNOUT_GET_ADDRESS 13:3 /* RWXUF */ +/* dev_graphics.ref */ +#define NV_PGRAPH 0x00401FFF:0x00400000 /* RW--D */ +#define NV_PGRAPH_DEBUG_0 0x00400080 /* RW-4R */ +#define NV_PGRAPH_DEBUG_1 0x00400084 /* RW-4R */ +#define NV_PGRAPH_DEBUG_2 0x00400088 /* RW-4R */ +#define NV_PGRAPH_DEBUG_3 0x0040008C /* RW-4R */ +#define NV_PGRAPH_INTR 0x00400100 /* RW-4R */ +#define NV_PGRAPH_INTR_NOTIFY 0:0 /* RWIVF */ +#define NV_PGRAPH_INTR_NOTIFY_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_INTR_NOTIFY_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_INTR_NOTIFY_RESET 0x00000001 /* -W--C */ +#define NV_PGRAPH_INTR_MISSING_HW 4:4 /* RWIVF */ +#define NV_PGRAPH_INTR_MISSING_HW_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_INTR_MISSING_HW_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_INTR_MISSING_HW_RESET 0x00000001 /* -W--C */ +#define NV_PGRAPH_INTR_TLB_PRESENT_A 8:8 /* RWIVF */ +#define NV_PGRAPH_INTR_TLB_PRESENT_A_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_INTR_TLB_PRESENT_A_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_INTR_TLB_PRESENT_A_RESET 0x00000001 /* -W--C */ +#define NV_PGRAPH_INTR_TLB_PRESENT_B 9:9 /* RWIVF */ +#define NV_PGRAPH_INTR_TLB_PRESENT_B_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_INTR_TLB_PRESENT_B_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_INTR_TLB_PRESENT_B_RESET 0x00000001 /* -W--C */ +#define NV_PGRAPH_INTR_CONTEXT_SWITCH 12:12 /* RWIVF */ +#define NV_PGRAPH_INTR_CONTEXT_SWITCH_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_INTR_CONTEXT_SWITCH_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_INTR_CONTEXT_SWITCH_RESET 0x00000001 /* -W--C */ +#define NV_PGRAPH_INTR_BUFFER_NOTIFY 16:16 /* RWIVF */ +#define NV_PGRAPH_INTR_BUFFER_NOTIFY_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_INTR_BUFFER_NOTIFY_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_INTR_BUFFER_NOTIFY_RESET 0x00000001 /* -W--C */ +#define NV_PGRAPH_NSTATUS 0x00400104 /* RW-4R */ +#define NV_PGRAPH_NSTATUS_STATE_IN_USE 11:11 /* RWIVF */ +#define NV_PGRAPH_NSTATUS_STATE_IN_USE_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PGRAPH_NSTATUS_STATE_IN_USE_PENDING 0x00000001 /* RW--V */ +#define NV_PGRAPH_NSTATUS_INVALID_STATE 12:12 /* RWIVF */ +#define NV_PGRAPH_NSTATUS_INVALID_STATE_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PGRAPH_NSTATUS_INVALID_STATE_PENDING 0x00000001 /* RW--V */ +#define NV_PGRAPH_NSTATUS_BAD_ARGUMENT 13:13 /* RWIVF */ +#define NV_PGRAPH_NSTATUS_BAD_ARGUMENT_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PGRAPH_NSTATUS_BAD_ARGUMENT_PENDING 0x00000001 /* RW--V */ +#define NV_PGRAPH_NSTATUS_PROTECTION_FAULT 14:14 /* RWIVF */ +#define NV_PGRAPH_NSTATUS_PROTECTION_FAULT_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PGRAPH_NSTATUS_PROTECTION_FAULT_PENDING 0x00000001 /* RW--V */ +#define NV_PGRAPH_NSOURCE 0x00400108 /* R--4R */ +#define NV_PGRAPH_NSOURCE_NOTIFICATION 0:0 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_NOTIFICATION_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_NOTIFICATION_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_DATA_ERROR 1:1 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_DATA_ERROR_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_DATA_ERROR_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_PROTECTION_ERROR 2:2 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_PROTECTION_ERROR_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_PROTECTION_ERROR_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_RANGE_EXCEPTION 3:3 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_RANGE_EXCEPTION_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_RANGE_EXCEPTION_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_LIMIT_COLOR 4:4 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_LIMIT_COLOR_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_LIMIT_COLOR_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_LIMIT_ZETA_ 5:5 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_LIMIT_ZETA_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_LIMIT_ZETA_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_ILLEGAL_MTHD 6:6 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_ILLEGAL_MTHD_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_ILLEGAL_MTHD_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_DMA_R_PROTECTION 7:7 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_DMA_R_PROTECTION_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_DMA_R_PROTECTION_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_DMA_W_PROTECTION 8:8 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_DMA_W_PROTECTION_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_DMA_W_PROTECTION_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_FORMAT_EXCEPTION 9:9 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_FORMAT_EXCEPTION_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_FORMAT_EXCEPTION_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_PATCH_EXCEPTION 10:10 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_PATCH_EXCEPTION_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_PATCH_EXCEPTION_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_STATE_INVALID 11:11 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_STATE_INVALID_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_STATE_INVALID_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_DOUBLE_NOTIFY 12:12 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_DOUBLE_NOTIFY_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_DOUBLE_NOTIFY_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_NOTIFY_IN_USE 13:13 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_NOTIFY_IN_USE_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_NOTIFY_IN_USE_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_METHOD_CNT 14:14 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_METHOD_CNT_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_METHOD_CNT_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_NSOURCE_BFR_NOTIFICATION 15:15 /* R-IVF */ +#define NV_PGRAPH_NSOURCE_BFR_NOTIFICATION_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_NSOURCE_BFR_NOTIFICATION_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_INTR_EN 0x00400140 /* RW-4R */ +#define NV_PGRAPH_INTR_EN_NOTIFY 0:0 /* RWIVF */ +#define NV_PGRAPH_INTR_EN_NOTIFY_DISABLED 0x00000000 /* RWI-V */ +#define NV_PGRAPH_INTR_EN_NOTIFY_ENABLED 0x00000001 /* RW--V */ +#define NV_PGRAPH_INTR_EN_MISSING_HW 4:4 /* RWIVF */ +#define NV_PGRAPH_INTR_EN_MISSING_HW_DISABLED 0x00000000 /* RWI-V */ +#define NV_PGRAPH_INTR_EN_MISSING_HW_ENABLED 0x00000001 /* RW--V */ +#define NV_PGRAPH_INTR_EN_TLB_PRESENT_A 8:8 /* RWIVF */ +#define NV_PGRAPH_INTR_EN_TLB_PRESENT_A_DISABLED 0x00000000 /* RWI-V */ +#define NV_PGRAPH_INTR_EN_TLB_PRESENT_A_ENABLED 0x00000001 /* RW--V */ +#define NV_PGRAPH_INTR_EN_TLB_PRESENT_B 9:9 /* RWIVF */ +#define NV_PGRAPH_INTR_EN_TLB_PRESENT_B_DISABLED 0x00000000 /* RWI-V */ +#define NV_PGRAPH_INTR_EN_TLB_PRESENT_B_ENABLED 0x00000001 /* RW--V */ +#define NV_PGRAPH_INTR_EN_CONTEXT_SWITCH 12:12 /* RWIVF */ +#define NV_PGRAPH_INTR_EN_CONTEXT_SWITCH_DISABLED 0x00000000 /* RWI-V */ +#define NV_PGRAPH_INTR_EN_CONTEXT_SWITCH_ENABLED 0x00000001 /* RW--V */ +#define NV_PGRAPH_INTR_EN_BUFFER_NOTIFY 16:16 /* RWIVF */ +#define NV_PGRAPH_INTR_EN_BUFFER_NOTIFY_DISABLED 0x00000000 /* RWI-V */ +#define NV_PGRAPH_INTR_EN_BUFFER_NOTIFY_ENABLED 0x00000001 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1 0x00400160 /* RW-4R */ +#define NV_PGRAPH_CTX_SWITCH1_GRCLASS 7:0 /* RWXVF */ +#define NV_PGRAPH_CTX_SWITCH1_CHROMA_KEY 12:12 /* RWXUF */ +#define NV_PGRAPH_CTX_SWITCH1_CHROMA_KEY_DISABLE 0x00000000 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_CHROMA_KEY_ENABLE 0x00000001 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_USER_CLIP 13:13 /* RWXUF */ +#define NV_PGRAPH_CTX_SWITCH1_USER_CLIP_DISABLE 0x00000000 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_USER_CLIP_ENABLE 0x00000001 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_SWIZZLE 14:14 /* RWXUF */ +#define NV_PGRAPH_CTX_SWITCH1_SWIZZLE_DISABLE 0x00000000 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_SWIZZLE_ENABLE 0x00000001 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG 17:15 /* RWXUF */ +#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY_AND 0x00000000 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_ROP_AND 0x00000001 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_BLEND_AND 0x00000002 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY 0x00000003 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY_PRE 0x00000004 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_BLEND_PRE 0x00000005 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_PATCH_STATUS 24:24 /* RWXUF */ +#define NV_PGRAPH_CTX_SWITCH1_PATCH_STATUS_INVALID 0x00000000 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_PATCH_STATUS_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE 25:25 /* RWXUF */ +#define NV_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE_INVALID 0x00000000 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET 31:31 /* CWIVF */ +#define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET_IGNORE 0x00000000 /* CWI-V */ +#define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET_ENABLED 0x00000001 /* -W--T */ +#define NV_PGRAPH_CTX_SWITCH2 0x00400164 /* RW-4R */ +#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT 1:0 /* RWXUF */ +#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT_INVALID 0x00 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT_CGA6_M1 0x01 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT_LE_M1 0x02 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT 13:8 /* RWXUF */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_INVALID 0x00 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y8 0x01 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16A8Y8 0x02 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X24Y8 0x03 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A1R5G5B5 0x06 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X1R5G5B5 0x07 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16A1R5G5B5 0x08 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X17R5G5B5 0x09 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_R5G6B5 0x0A /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A16R5G6B5 0x0B /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16R5G6B5 0x0C /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A8R8G8B8 0x0D /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X8R8G8B8 0x0E /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y16 0x0F /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A16Y16 0x10 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16Y16 0x11 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_V8YB8U8YA8 0x12 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_YB8V8YA8U8 0x13 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y32 0x14 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH2_NOTIFY_INSTANCE 31:16 /* RWXUF */ +#define NV_PGRAPH_CTX_SWITCH2_NOTIFY_INSTANCE_INVALID 0x0000 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH3 0x00400168 /* RW-4R */ +#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_0 15:0 /* RWXUF */ +#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_0_INVALID 0x0000 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_1 31:16 /* RWXUF */ +#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_1_INVALID 0x0000 /* RW--V */ +#define NV_PGRAPH_CTX_SWITCH4 0x0040016C /* RW-4R */ +#define NV_PGRAPH_CTX_SWITCH4_USER_INSTANCE 15:0 /* RWXUF */ +#define NV_PGRAPH_CTX_SWITCH4_USER_INSTANCE_INVALID 0x0000 /* RW--V */ +#define NV_PGRAPH_CTX_CACHE1(i) (0x00400180+(i)*4) /* RW-4A */ +#define NV_PGRAPH_CTX_CACHE1__SIZE_1 8 /* */ +#define NV_PGRAPH_CTX_CACHE1_GRCLASS 7:0 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE1_CHROMA_KEY 12:12 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE1_USER_CLIP 13:13 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE1_SWIZZLE 14:14 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE1_PATCH_CONFIG 19:15 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE1_SPARE1 20:20 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE1_PATCH_STATUS 24:24 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE1_CONTEXT_SURFACE 25:25 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE2(i) (0x004001a0+(i)*4) /* RW-4A */ +#define NV_PGRAPH_CTX_CACHE2__SIZE_1 8 /* */ +#define NV_PGRAPH_CTX_CACHE2_MONO_FORMAT 1:0 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE2_COLOR_FORMAT 13:8 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE2_NOTIFY_INSTANCE 31:16 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE3(i) (0x004001c0+(i)*4) /* RW-4A */ +#define NV_PGRAPH_CTX_CACHE3__SIZE_1 8 /* */ +#define NV_PGRAPH_CTX_CACHE3_DMA_INSTANCE_0 15:0 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE3_DMA_INSTANCE_1 31:16 /* RWXVF */ +#define NV_PGRAPH_CTX_CACHE4(i) (0x004001e0+(i)*4) /* RW-4A */ +#define NV_PGRAPH_CTX_CACHE4__SIZE_1 8 /* */ +#define NV_PGRAPH_CTX_CACHE4_USER_INSTANCE 15:0 /* RWXVF */ +#define NV_PGRAPH_CTX_CONTROL 0x00400170 /* RW-4R */ +#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME 1:0 /* RWIVF */ +#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_33US 0x00000000 /* RWI-V */ +#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_262US 0x00000001 /* RW--V */ +#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_2MS 0x00000002 /* RW--V */ +#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_17MS 0x00000003 /* RW--V */ +#define NV_PGRAPH_CTX_CONTROL_TIME 8:8 /* RWIVF */ +#define NV_PGRAPH_CTX_CONTROL_TIME_EXPIRED 0x00000000 /* RWI-V */ +#define NV_PGRAPH_CTX_CONTROL_TIME_NOT_EXPIRED 0x00000001 /* RW--V */ +#define NV_PGRAPH_CTX_CONTROL_CHID 16:16 /* RWIVF */ +#define NV_PGRAPH_CTX_CONTROL_CHID_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_CTX_CONTROL_CHID_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_CTX_CONTROL_CHANGE 20:20 /* R--VF */ +#define NV_PGRAPH_CTX_CONTROL_CHANGE_UNAVAILABLE 0x00000000 /* R---V */ +#define NV_PGRAPH_CTX_CONTROL_CHANGE_AVAILABLE 0x00000001 /* R---V */ +#define NV_PGRAPH_CTX_CONTROL_SWITCHING 24:24 /* RWIVF */ +#define NV_PGRAPH_CTX_CONTROL_SWITCHING_IDLE 0x00000000 /* RWI-V */ +#define NV_PGRAPH_CTX_CONTROL_SWITCHING_BUSY 0x00000001 /* RW--V */ +#define NV_PGRAPH_CTX_CONTROL_DEVICE 28:28 /* RWIVF */ +#define NV_PGRAPH_CTX_CONTROL_DEVICE_DISABLED 0x00000000 /* RWI-V */ +#define NV_PGRAPH_CTX_CONTROL_DEVICE_ENABLED 0x00000001 /* RW--V */ +#define NV_PGRAPH_CTX_USER 0x00400174 /* RW-4R */ +#define NV_PGRAPH_CTX_USER_SUBCH 15:13 /* RWIVF */ +#define NV_PGRAPH_CTX_USER_SUBCH_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_CTX_USER_CHID 27:24 /* RWIVF */ +#define NV_PGRAPH_CTX_USER_CHID_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_FIFO 0x00400720 /* RW-4R */ +#define NV_PGRAPH_FIFO_ACCESS 0:0 /* RWIVF */ +#define NV_PGRAPH_FIFO_ACCESS_DISABLED 0x00000000 /* RW--V */ +#define NV_PGRAPH_FIFO_ACCESS_ENABLED 0x00000001 /* RWI-V */ +#define NV_PGRAPH_FFINTFC_FIFO_0(i) (0x00400730+(i)*4) /* RW-4A */ +#define NV_PGRAPH_FFINTFC_FIFO_0__SIZE_1 4 /* */ +#define NV_PGRAPH_FFINTFC_FIFO_0_TAG 0:0 /* RWXVF */ +#define NV_PGRAPH_FFINTFC_FIFO_0_TAG_MTHD 0x00000000 /* RW--V */ +#define NV_PGRAPH_FFINTFC_FIFO_0_TAG_CHSW 0x00000001 /* RW--V */ +#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH 3:1 /* RWXVF */ +#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_0 0x00000000 /* RW--V */ +#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_1 0x00000001 /* RW--V */ +#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_2 0x00000002 /* RW--V */ +#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_3 0x00000003 /* RW--V */ +#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_4 0x00000004 /* RW--V */ +#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_5 0x00000005 /* RW--V */ +#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_6 0x00000006 /* RW--V */ +#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_7 0x00000007 /* RW--V */ +#define NV_PGRAPH_FFINTFC_FIFO_0_MTHD 14:4 /* RWXVF */ +#define NV_PGRAPH_FFINTFC_FIFO_0_MTHD_CTX_SWITCH 0x00000000 /* RW--V */ +#define NV_PGRAPH_FFINTFC_FIFO_1(i) (0x00400740+(i)*4) /* RW-4A */ +#define NV_PGRAPH_FFINTFC_FIFO_1__SIZE_1 4 /* */ +#define NV_PGRAPH_FFINTFC_FIFO_1_ARGUMENT 31:0 /* RWXVF */ +#define NV_PGRAPH_FFINTFC_FIFO_PTR 0x00400750 /* RW-4R */ +#define NV_PGRAPH_FFINTFC_FIFO_PTR_WRITE 2:0 /* RWIVF */ +#define NV_PGRAPH_FFINTFC_FIFO_PTR_WRITE_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_FFINTFC_FIFO_PTR_READ 6:4 /* RWIVF */ +#define NV_PGRAPH_FFINTFC_FIFO_PTR_READ_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_FFINTFC_ST2 0x00400754 /* RW-4R */ +#define NV_PGRAPH_FFINTFC_ST2_STATUS 0:0 /* RWIVF */ +#define NV_PGRAPH_FFINTFC_ST2_STATUS_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_FFINTFC_ST2_STATUS_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_MTHD 11:1 /* RWIVF */ +#define NV_PGRAPH_FFINTFC_ST2_MTHD_CTX_SWITCH 0x00000000 /* RWI-V */ +#define NV_PGRAPH_FFINTFC_ST2_SUBCH 14:12 /* RWIVF */ +#define NV_PGRAPH_FFINTFC_ST2_SUBCH_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_FFINTFC_ST2_SUBCH_1 0x00000001 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_SUBCH_2 0x00000002 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_SUBCH_3 0x00000003 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_SUBCH_4 0x00000004 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_SUBCH_5 0x00000005 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_SUBCH_6 0x00000006 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_SUBCH_7 0x00000007 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID 18:15 /* RWIVF */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_1 0x00000001 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_2 0x00000002 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_3 0x00000003 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_4 0x00000004 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_5 0x00000005 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_6 0x00000006 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_7 0x00000007 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_8 0x00000008 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_9 0x00000009 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_10 0x0000000A /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_11 0x0000000B /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_12 0x0000000C /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_13 0x0000000D /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_14 0x0000000E /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_15 0x0000000F /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_STATUS 19:19 /* RWIVF */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_STATUS_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_FFINTFC_ST2_CHID_STATUS_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_FFINTFC_ST2_D 0x00400758 /* RW-4R */ +#define NV_PGRAPH_FFINTFC_ST2_D_ARGUMENT 31:0 /* RWIVF */ +#define NV_PGRAPH_FFINTFC_ST2_D_ARGUMENT_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATUS 0x00400700 /* R--4R */ +#define NV_PGRAPH_STATUS_STATE 0:0 /* R-IVF */ +#define NV_PGRAPH_STATUS_STATE_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_STATE_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_XY_LOGIC 4:4 /* R-IVF */ +#define NV_PGRAPH_STATUS_XY_LOGIC_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_XY_LOGIC_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_FE 5:5 /* R-IVF */ +#define NV_PGRAPH_STATUS_FE_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_FE_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_RASTERIZER 6:6 /* R-IVF */ +#define NV_PGRAPH_STATUS_RASTERIZER_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_RASTERIZER_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_PORT_NOTIFY 8:8 /* R-IVF */ +#define NV_PGRAPH_STATUS_PORT_NOTIFY_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_PORT_NOTIFY_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_PORT_REGISTER 12:12 /* R-IVF */ +#define NV_PGRAPH_STATUS_PORT_REGISTER_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_PORT_REGISTER_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_PORT_DMA 16:16 /* R-IVF */ +#define NV_PGRAPH_STATUS_PORT_DMA_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_PORT_DMA_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_DMA_ENGINE 17:17 /* R-IVF */ +#define NV_PGRAPH_STATUS_DMA_ENGINE_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_DMA_ENGINE_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_DMA_NOTIFY 20:20 /* R-IVF */ +#define NV_PGRAPH_STATUS_DMA_NOTIFY_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_DMA_NOTIFY_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_DMA_BUFFER_NOTIFY 21:21 /* R-IVF */ +#define NV_PGRAPH_STATUS_DMA_BUFFER_NOTIFY_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_DMA_BUFFER_NOTIFY_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_D3D 24:24 /* R-IVF */ +#define NV_PGRAPH_STATUS_D3D_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_D3D_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_CACHE 25:25 /* R-IVF */ +#define NV_PGRAPH_STATUS_CACHE_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_CACHE_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_LIGHTING 26:26 /* R-IVF */ +#define NV_PGRAPH_STATUS_LIGHTING_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_LIGHTING_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_PREROP 27:27 /* R-IVF */ +#define NV_PGRAPH_STATUS_PREROP_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_PREROP_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_ROP 28:28 /* R-IVF */ +#define NV_PGRAPH_STATUS_ROP_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_ROP_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_STATUS_PORT_USER 29:29 /* R-IVF */ +#define NV_PGRAPH_STATUS_PORT_USER_IDLE 0x00000000 /* R-I-V */ +#define NV_PGRAPH_STATUS_PORT_USER_BUSY 0x00000001 /* R---V */ +#define NV_PGRAPH_TRAPPED_ADDR 0x00400704 /* R--4R */ +#define NV_PGRAPH_TRAPPED_ADDR_MTHD 12:2 /* R-XUF */ +#define NV_PGRAPH_TRAPPED_ADDR_SUBCH 15:13 /* R-XUF */ +#define NV_PGRAPH_TRAPPED_ADDR_CHID 27:24 /* R-XUF */ +#define NV_PGRAPH_TRAPPED_DATA 0x00400708 /* R--4R */ +#define NV_PGRAPH_TRAPPED_DATA_VALUE 31:0 /* R-XVF */ +#define NV_PGRAPH_SURFACE 0x0040070C /* RW-4R */ +#define NV_PGRAPH_SURFACE_TYPE 1:0 /* RWIVF */ +#define NV_PGRAPH_SURFACE_TYPE_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_SURFACE_TYPE_NON_SWIZZLE 0x00000001 /* RW--V */ +#define NV_PGRAPH_SURFACE_TYPE_SWIZZLE 0x00000002 /* RW--V */ +#define NV_PGRAPH_NOTIFY 0x00400714 /* RW-4R */ +#define NV_PGRAPH_NOTIFY_BUFFER_REQ 0:0 /* RWIVF */ +#define NV_PGRAPH_NOTIFY_BUFFER_REQ_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PGRAPH_NOTIFY_BUFFER_REQ_PENDING 0x00000001 /* RW--V */ +#define NV_PGRAPH_NOTIFY_BUFFER_STYLE 8:8 /* RWIVF */ +#define NV_PGRAPH_NOTIFY_BUFFER_STYLE_WRITE_ONLY 0x00000000 /* RWI-V */ +#define NV_PGRAPH_NOTIFY_BUFFER_STYLE_WRITE_THEN_AWAKEN 0x00000001 /* RW--V */ +#define NV_PGRAPH_NOTIFY_REQ 16:16 /* RWIVF */ +#define NV_PGRAPH_NOTIFY_REQ_NOT_PENDING 0x00000000 /* RWI-V */ +#define NV_PGRAPH_NOTIFY_REQ_PENDING 0x00000001 /* RW--V */ +#define NV_PGRAPH_NOTIFY_STYLE 20:20 /* RWIVF */ +#define NV_PGRAPH_NOTIFY_STYLE_WRITE_ONLY 0x00000000 /* RWI-V */ +#define NV_PGRAPH_NOTIFY_STYLE_WRITE_THEN_AWAKEN 0x00000001 /* RW--V */ +#define NV_PGRAPH_BOFFSET(i) (0x00400640+(i)*4) /* RW-4A */ +#define NV_PGRAPH_BOFFSET__SIZE_1 6 /* */ +#define NV_PGRAPH_BOFFSET_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BOFFSET_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BOFFSET0 0x00400640 /* RW-4R */ +#define NV_PGRAPH_BOFFSET0__ALIAS_1 NV_PGRAPH_BOFFSET(0) /* */ +#define NV_PGRAPH_BOFFSET0_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BOFFSET0_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BOFFSET1 0x00400644 /* RW-4R */ +#define NV_PGRAPH_BOFFSET1__ALIAS_1 NV_PGRAPH_BOFFSET(1) /* */ +#define NV_PGRAPH_BOFFSET1_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BOFFSET1_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BOFFSET2 0x00400648 /* RW-4R */ +#define NV_PGRAPH_BOFFSET2__ALIAS_1 NV_PGRAPH_BOFFSET(2) /* */ +#define NV_PGRAPH_BOFFSET2_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BOFFSET2_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BOFFSET3 0x0040064C /* RW-4R */ +#define NV_PGRAPH_BOFFSET3__ALIAS_1 NV_PGRAPH_BOFFSET(3) /* */ +#define NV_PGRAPH_BOFFSET3_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BOFFSET3_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BOFFSET4 0x00400650 /* RW-4R */ +#define NV_PGRAPH_BOFFSET4__ALIAS_1 NV_PGRAPH_BOFFSET(4) /* */ +#define NV_PGRAPH_BOFFSET4_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BOFFSET4_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BOFFSET5 0x00400654 /* RW-4R */ +#define NV_PGRAPH_BOFFSET5__ALIAS_1 NV_PGRAPH_BOFFSET(5) /* */ +#define NV_PGRAPH_BOFFSET5_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BOFFSET5_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BBASE(i) (0x00400658+(i)*4) /* RW-4A */ +#define NV_PGRAPH_BBASE__SIZE_1 6 /* */ +#define NV_PGRAPH_BBASE_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BBASE_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BBASE0 0x00400658 /* RW-4R */ +#define NV_PGRAPH_BBASE0__ALIAS_1 NV_PGRAPH_BBASE(0) /* */ +#define NV_PGRAPH_BBASE0_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BBASE0_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BBASE1 0x0040065c /* RW-4R */ +#define NV_PGRAPH_BBASE1__ALIAS_1 NV_PGRAPH_BBASE(1) /* */ +#define NV_PGRAPH_BBASE1_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BBASE1_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BBASE2 0x00400660 /* RW-4R */ +#define NV_PGRAPH_BBASE2__ALIAS_1 NV_PGRAPH_BBASE(2) /* */ +#define NV_PGRAPH_BBASE2_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BBASE2_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BBASE3 0x00400664 /* RW-4R */ +#define NV_PGRAPH_BBASE3__ALIAS_1 NV_PGRAPH_BBASE(3) /* */ +#define NV_PGRAPH_BBASE3_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BBASE3_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BBASE4 0x00400668 /* RW-4R */ +#define NV_PGRAPH_BBASE4__ALIAS_1 NV_PGRAPH_BBASE(4) /* */ +#define NV_PGRAPH_BBASE4_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BBASE4_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BBASE5 0x0040066C /* RW-4R */ +#define NV_PGRAPH_BBASE5__ALIAS_1 NV_PGRAPH_BBASE(5) /* */ +#define NV_PGRAPH_BBASE5_LINADRS 23:0 /* RWIUF */ +#define NV_PGRAPH_BBASE5_LINADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPITCH(i) (0x00400670+(i)*4) /* RW-4A */ +#define NV_PGRAPH_BPITCH__SIZE_1 5 /* */ +#define NV_PGRAPH_BPITCH_VALUE 12:0 /* RWIUF */ +#define NV_PGRAPH_BPITCH_VALUE_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPITCH0 0x00400670 /* RW-4R */ +#define NV_PGRAPH_BPITCH0__ALIAS_1 NV_PGRAPH_BPITCH(0) /* */ +#define NV_PGRAPH_BPITCH0_VALUE 12:0 /* RWIUF */ +#define NV_PGRAPH_BPITCH0_VALUE_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPITCH1 0x00400674 /* RW-4R */ +#define NV_PGRAPH_BPITCH1__ALIAS_1 NV_PGRAPH_BPITCH(1) /* */ +#define NV_PGRAPH_BPITCH1_VALUE 12:0 /* RWIUF */ +#define NV_PGRAPH_BPITCH1_VALUE_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPITCH2 0x00400678 /* RW-4R */ +#define NV_PGRAPH_BPITCH2__ALIAS_1 NV_PGRAPH_BPITCH(2) /* */ +#define NV_PGRAPH_BPITCH2_VALUE 12:0 /* RWIUF */ +#define NV_PGRAPH_BPITCH2_VALUE_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPITCH3 0x0040067C /* RW-4R */ +#define NV_PGRAPH_BPITCH3__ALIAS_1 NV_PGRAPH_BPITCH(3) /* */ +#define NV_PGRAPH_BPITCH3_VALUE 12:0 /* RWIUF */ +#define NV_PGRAPH_BPITCH3_VALUE_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPITCH4 0x00400680 /* RW-4R */ +#define NV_PGRAPH_BPITCH4__ALIAS_1 NV_PGRAPH_BPITCH(4) /* */ +#define NV_PGRAPH_BPITCH4_VALUE 12:0 /* RWIUF */ +#define NV_PGRAPH_BPITCH4_VALUE_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BLIMIT(i) (0x00400684+(i)*4) /* RW-4A */ +#define NV_PGRAPH_BLIMIT__SIZE_1 6 /* */ +#define NV_PGRAPH_BLIMIT_VALUE 23:0 /* RWXUF */ +#define NV_PGRAPH_BLIMIT_TYPE 31:31 /* RWIVF */ +#define NV_PGRAPH_BLIMIT_TYPE_IN_MEMORY 0x00000000 /* RW--V */ +#define NV_PGRAPH_BLIMIT_TYPE_NULL 0x00000001 /* RWI-V */ +#define NV_PGRAPH_BLIMIT0 0x00400684 /* RW-4R */ +#define NV_PGRAPH_BLIMIT0__ALIAS_1 NV_PGRAPH_BLIMIT(0) /* */ +#define NV_PGRAPH_BLIMIT0_VALUE 23:0 /* RWXUF */ +#define NV_PGRAPH_BLIMIT0_TYPE 31:31 /* RWIVF */ +#define NV_PGRAPH_BLIMIT0_TYPE_IN_MEMORY 0x00000000 /* RW--V */ +#define NV_PGRAPH_BLIMIT0_TYPE_NULL 0x00000001 /* RWI-V */ +#define NV_PGRAPH_BLIMIT1 0x00400688 /* RW-4R */ +#define NV_PGRAPH_BLIMIT1__ALIAS_1 NV_PGRAPH_BLIMIT(1) /* */ +#define NV_PGRAPH_BLIMIT1_VALUE 23:0 /* RWXUF */ +#define NV_PGRAPH_BLIMIT1_TYPE 31:31 /* RWIVF */ +#define NV_PGRAPH_BLIMIT1_TYPE_IN_MEMORY 0x00000000 /* RW--V */ +#define NV_PGRAPH_BLIMIT1_TYPE_NULL 0x00000001 /* RWI-V */ +#define NV_PGRAPH_BLIMIT2 0x0040068c /* RW-4R */ +#define NV_PGRAPH_BLIMIT2__ALIAS_1 NV_PGRAPH_BLIMIT(2) /* */ +#define NV_PGRAPH_BLIMIT2_VALUE 23:0 /* RWXUF */ +#define NV_PGRAPH_BLIMIT2_TYPE 31:31 /* RWIVF */ +#define NV_PGRAPH_BLIMIT2_TYPE_IN_MEMORY 0x00000000 /* RW--V */ +#define NV_PGRAPH_BLIMIT2_TYPE_NULL 0x00000001 /* RWI-V */ +#define NV_PGRAPH_BLIMIT3 0x00400690 /* RW-4R */ +#define NV_PGRAPH_BLIMIT3__ALIAS_1 NV_PGRAPH_BLIMIT(3) /* */ +#define NV_PGRAPH_BLIMIT3_VALUE 23:0 /* RWXUF */ +#define NV_PGRAPH_BLIMIT3_TYPE 31:31 /* RWIVF */ +#define NV_PGRAPH_BLIMIT3_TYPE_IN_MEMORY 0x00000000 /* RW--V */ +#define NV_PGRAPH_BLIMIT3_TYPE_NULL 0x00000001 /* RWI-V */ +#define NV_PGRAPH_BLIMIT4 0x00400694 /* RW-4R */ +#define NV_PGRAPH_BLIMIT4__ALIAS_1 NV_PGRAPH_BLIMIT(4) /* */ +#define NV_PGRAPH_BLIMIT4_VALUE 23:0 /* RWXUF */ +#define NV_PGRAPH_BLIMIT4_TYPE 31:31 /* RWIVF */ +#define NV_PGRAPH_BLIMIT4_TYPE_IN_MEMORY 0x00000000 /* RW--V */ +#define NV_PGRAPH_BLIMIT4_TYPE_NULL 0x00000001 /* RWI-V */ +#define NV_PGRAPH_BLIMIT5 0x00400698 /* RW-4R */ +#define NV_PGRAPH_BLIMIT5__ALIAS_1 NV_PGRAPH_BLIMIT(5) /* */ +#define NV_PGRAPH_BLIMIT5_VALUE 23:0 /* RWXUF */ +#define NV_PGRAPH_BLIMIT5_TYPE 31:31 /* RWIVF */ +#define NV_PGRAPH_BLIMIT5_TYPE_IN_MEMORY 0x00000000 /* RW--V */ +#define NV_PGRAPH_BLIMIT5_TYPE_NULL 0x00000001 /* RWI-V */ +#define NV_PGRAPH_BSWIZZLE2 0x0040069c /* RW-4R */ +#define NV_PGRAPH_BSWIZZLE2_WIDTH 19:16 /* RWIUF */ +#define NV_PGRAPH_BSWIZZLE2_WIDTH_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BSWIZZLE2_HEIGHT 27:24 /* RWIUF */ +#define NV_PGRAPH_BSWIZZLE2_HEIGHT_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BSWIZZLE5 0x004006a0 /* RW-4R */ +#define NV_PGRAPH_BSWIZZLE5_WIDTH 19:16 /* RWIUF */ +#define NV_PGRAPH_BSWIZZLE5_WIDTH_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BSWIZZLE5_HEIGHT 27:24 /* RWIUF */ +#define NV_PGRAPH_BSWIZZLE5_HEIGHT_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPIXEL 0x00400724 /* RW-4R */ +#define NV_PGRAPH_BPIXEL_DEPTH0 3:0 /* RWIVF */ +#define NV_PGRAPH_BPIXEL_DEPTH0_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_Y8 0x00000001 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_A1R5G5B5 0x00000004 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_R5G6B5 0x00000005 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_Y16 0x00000006 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_A8R8G8B8 0x0000000c /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_Y32 0x0000000d /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_V8YB8U8YA8 0x0000000e /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH0_YB8V8YA8U8 0x0000000f /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1 7:4 /* RWIVF */ +#define NV_PGRAPH_BPIXEL_DEPTH1_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_Y8 0x00000001 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_A1R5G5B5 0x00000004 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_R5G6B5 0x00000005 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_Y16 0x00000006 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_A8R8G8B8 0x0000000c /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_Y32 0x0000000d /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_V8YB8U8YA8 0x0000000e /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH1_YB8V8YA8U8 0x0000000f /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2 11:8 /* RWIVF */ +#define NV_PGRAPH_BPIXEL_DEPTH2_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_Y8 0x00000001 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_A1R5G5B5 0x00000004 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_R5G6B5 0x00000005 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_Y16 0x00000006 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_A8R8G8B8 0x0000000c /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_Y32 0x0000000d /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_V8YB8U8YA8 0x0000000e /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH2_YB8V8YA8U8 0x0000000f /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3 15:12 /* RWIVF */ +#define NV_PGRAPH_BPIXEL_DEPTH3_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_Y8 0x00000001 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_A1R5G5B5 0x00000004 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_R5G6B5 0x00000005 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_Y16 0x00000006 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_A8R8G8B8 0x0000000c /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_Y32 0x0000000d /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_V8YB8U8YA8 0x0000000e /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH3_YB8V8YA8U8 0x0000000f /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4 19:16 /* RWIVF */ +#define NV_PGRAPH_BPIXEL_DEPTH4_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_Y8 0x00000001 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_A1R5G5B5 0x00000004 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_R5G6B5 0x00000005 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_Y16 0x00000006 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_A8R8G8B8 0x0000000c /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_Y32 0x0000000d /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_V8YB8U8YA8 0x0000000e /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH4_YB8V8YA8U8 0x0000000f /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5 23:20 /* RWIVF */ +#define NV_PGRAPH_BPIXEL_DEPTH5_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_Y8 0x00000001 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_A1R5G5B5 0x00000004 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_R5G6B5 0x00000005 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_Y16 0x00000006 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_A8R8G8B8 0x0000000c /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_Y32 0x0000000d /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_V8YB8U8YA8 0x0000000e /* RW--V */ +#define NV_PGRAPH_BPIXEL_DEPTH5_YB8V8YA8U8 0x0000000f /* RW--V */ +#define NV_PGRAPH_LIMIT_VIOL_PIX 0x00400610 /* RW-4R */ +#define NV_PGRAPH_LIMIT_VIOL_PIX_ADRS 23:0 /* RWIVF */ +#define NV_PGRAPH_LIMIT_VIOL_PIX_ADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_LIMIT_VIOL_PIX_BLIT 29:29 /* RWIVF */ +#define NV_PGRAPH_LIMIT_VIOL_PIX_BLIT_NO_VIOL 0x00000000 /* RWI-V */ +#define NV_PGRAPH_LIMIT_VIOL_PIX_BLIT_VIOL 0x00000001 /* RW--V */ +#define NV_PGRAPH_LIMIT_VIOL_PIX_LIMIT 30:30 /* RWIVF */ +#define NV_PGRAPH_LIMIT_VIOL_PIX_LIMIT_NO_VIOL 0x00000000 /* RWI-V */ +#define NV_PGRAPH_LIMIT_VIOL_PIX_LIMIT_VIOL 0x00000001 /* RW--V */ +#define NV_PGRAPH_LIMIT_VIOL_PIX_OVRFLW 31:31 /* RWIVF */ +#define NV_PGRAPH_LIMIT_VIOL_PIX_OVRFLW_NO_VIOL 0x00000000 /* RWI-V */ +#define NV_PGRAPH_LIMIT_VIOL_PIX_OVRFLW_VIOL 0x00000001 /* RW--V */ +#define NV_PGRAPH_LIMIT_VIOL_Z 0x00400614 /* RW-4R */ +#define NV_PGRAPH_LIMIT_VIOL_Z_ADRS 23:0 /* RWIVF */ +#define NV_PGRAPH_LIMIT_VIOL_Z_ADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_LIMIT_VIOL_Z_LIMIT 30:30 /* RWIVF */ +#define NV_PGRAPH_LIMIT_VIOL_Z_LIMIT_NO_VIOL 0x00000000 /* RWI-V */ +#define NV_PGRAPH_LIMIT_VIOL_Z_LIMIT_VIOL 0x00000001 /* RW--V */ +#define NV_PGRAPH_LIMIT_VIOL_Z_OVRFLW 31:31 /* RWIVF */ +#define NV_PGRAPH_LIMIT_VIOL_Z_OVRFLW_NO_VIOL 0x00000000 /* RWI-V */ +#define NV_PGRAPH_LIMIT_VIOL_Z_OVRFLW_VIOL 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE 0x00400710 /* RW-4R */ +#define NV_PGRAPH_STATE_BUFFER_0 0:0 /* RWIVF */ +#define NV_PGRAPH_STATE_BUFFER_0_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_BUFFER_0_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_BUFFER_1 1:1 /* RWIVF */ +#define NV_PGRAPH_STATE_BUFFER_1_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_BUFFER_1_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_BUFFER_2 2:2 /* RWIVF */ +#define NV_PGRAPH_STATE_BUFFER_2_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_BUFFER_2_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_BUFFER_3 3:3 /* RWIVF */ +#define NV_PGRAPH_STATE_BUFFER_3_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_BUFFER_3_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_BUFFER_4 4:4 /* RWIVF */ +#define NV_PGRAPH_STATE_BUFFER_4_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_BUFFER_4_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_BUFFER_5 5:5 /* RWIVF */ +#define NV_PGRAPH_STATE_BUFFER_5_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_BUFFER_5_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_PITCH_0 8:8 /* RWIVF */ +#define NV_PGRAPH_STATE_PITCH_0_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_PITCH_0_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_PITCH_1 9:9 /* RWIVF */ +#define NV_PGRAPH_STATE_PITCH_1_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_PITCH_1_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_PITCH_2 10:10 /* RWIVF */ +#define NV_PGRAPH_STATE_PITCH_2_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_PITCH_2_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_PITCH_3 11:11 /* RWIVF */ +#define NV_PGRAPH_STATE_PITCH_3_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_PITCH_3_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_PITCH_4 12:12 /* RWIVF */ +#define NV_PGRAPH_STATE_PITCH_4_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_PITCH_4_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_CHROMA_COLOR 16:16 /* RWIVF */ +#define NV_PGRAPH_STATE_CHROMA_COLOR_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_CHROMA_COLOR_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_CHROMA_COLORFMT 17:17 /* RWIVF */ +#define NV_PGRAPH_STATE_CHROMA_COLORFMT_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_CHROMA_COLORFMT_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_CPATTERN_COLORFMT 20:20 /* RWIVF */ +#define NV_PGRAPH_STATE_CPATTERN_COLORFMT_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_CPATTERN_COLORFMT_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_CPATTERN_MONOFMT 21:21 /* RWIVF */ +#define NV_PGRAPH_STATE_CPATTERN_MONOFMT_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_CPATTERN_MONOFMT_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_CPATTERN_SELECT 22:22 /* RWIVF */ +#define NV_PGRAPH_STATE_CPATTERN_SELECT_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_CPATTERN_SELECT_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_PATTERN_COLOR0 24:24 /* RWIVF */ +#define NV_PGRAPH_STATE_PATTERN_COLOR0_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_PATTERN_COLOR0_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_PATTERN_COLOR1 25:25 /* RWIVF */ +#define NV_PGRAPH_STATE_PATTERN_COLOR1_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_PATTERN_COLOR1_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_PATTERN_PATT0 26:26 /* RWIVF */ +#define NV_PGRAPH_STATE_PATTERN_PATT0_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_PATTERN_PATT0_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_STATE_PATTERN_PATT1 27:27 /* RWIVF */ +#define NV_PGRAPH_STATE_PATTERN_PATT1_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_STATE_PATTERN_PATT1_VALID 0x00000001 /* RW--V */ +#define NV_PGRAPH_CACHE_INDEX 0x00400728 /* RW-4R */ +#define NV_PGRAPH_CACHE_INDEX_BANK 2:2 /* RWXVF */ +#define NV_PGRAPH_CACHE_INDEX_BANK_10 0x00000000 /* RW--V */ +#define NV_PGRAPH_CACHE_INDEX_BANK_32 0x00000001 /* RW--V */ +#define NV_PGRAPH_CACHE_INDEX_ADRS 12:3 /* RWXVF */ +#define NV_PGRAPH_CACHE_INDEX_ADRS_0 0x00000000 /* RW--V */ +#define NV_PGRAPH_CACHE_INDEX_ADRS_1024 0x00000400 /* RW--V */ +#define NV_PGRAPH_CACHE_INDEX_OP 14:13 /* RWXVF */ +#define NV_PGRAPH_CACHE_INDEX_OP_WR_CACHE 0x00000000 /* RW--V */ +#define NV_PGRAPH_CACHE_INDEX_OP_RD_CACHE 0x00000001 /* RW--V */ +#define NV_PGRAPH_CACHE_INDEX_OP_RD_INDEX 0x00000002 /* RW--V */ +#define NV_PGRAPH_CACHE_RAM 0x0040072c /* RW-4R */ +#define NV_PGRAPH_CACHE_RAM_VALUE 31:0 /* RWXVF */ +#define NV_PGRAPH_DMA_PITCH 0x00400760 /* RW-4R */ +#define NV_PGRAPH_DMA_PITCH_S0 15:0 /* RWXSF */ +#define NV_PGRAPH_DMA_PITCH_S1 31:16 /* RWXSF */ +#define NV_PGRAPH_DVD_COLORFMT 0x00400764 /* RW-4R */ +#define NV_PGRAPH_DVD_COLORFMT_IMAGE 5:0 /* RWNVF */ +#define NV_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_INVALID 0x00 /* RWN-V */ +#define NV_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_LE_V8YB8U8YA8 0x12 /* RW--V */ +#define NV_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_LE_YB8V8YA8U8 0x13 /* RW--V */ +#define NV_PGRAPH_DVD_COLORFMT_OVLY 9:8 /* RWNVF */ +#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_INVALID 0x00 /* RWN-V */ +#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_LE_A8Y8U8V8 0x01 /* RW--V */ +#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_LE_A4V6YB6A4U6YA6 0x02 /* RW--V */ +#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_TRANSPARENT 0x03 /* RW--V */ +#define NV_PGRAPH_SCALED_FORMAT 0x00400768 /* RW-4R */ +#define NV_PGRAPH_SCALED_FORMAT_ORIGIN 17:16 /* RWIVF */ +#define NV_PGRAPH_SCALED_FORMAT_ORIGIN_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_SCALED_FORMAT_ORIGIN_CENTER 0x00000001 /* RW--V */ +#define NV_PGRAPH_SCALED_FORMAT_ORIGIN_CORNER 0x00000002 /* RW--V */ +#define NV_PGRAPH_SCALED_FORMAT_INTERPOLATOR 24:24 /* RWIVF */ +#define NV_PGRAPH_SCALED_FORMAT_INTERPOLATOR_ZOH 0x00000000 /* RWI-V */ +#define NV_PGRAPH_SCALED_FORMAT_INTERPOLATOR_FOH 0x00000001 /* RW--V */ +#define NV_PGRAPH_PATT_COLOR0 0x00400800 /* RW-4R */ +#define NV_PGRAPH_PATT_COLOR0_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_PATT_COLOR1 0x00400804 /* RW-4R */ +#define NV_PGRAPH_PATT_COLOR1_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_PATT_COLORRAM(i) (0x00400900+(i)*4) /* R--4A */ +#define NV_PGRAPH_PATT_COLORRAM__SIZE_1 64 /* */ +#define NV_PGRAPH_PATT_COLORRAM_VALUE 23:0 /* R--UF */ +#define NV_PGRAPH_PATTERN(i) (0x00400808+(i)*4) /* RW-4A */ +#define NV_PGRAPH_PATTERN__SIZE_1 2 /* */ +#define NV_PGRAPH_PATTERN_BITMAP 31:0 /* RWXVF */ +#define NV_PGRAPH_PATTERN_SHAPE 0x00400810 /* RW-4R */ +#define NV_PGRAPH_PATTERN_SHAPE_VALUE 1:0 /* RWXVF */ +#define NV_PGRAPH_PATTERN_SHAPE_VALUE_8X_8Y 0x00000000 /* RW--V */ +#define NV_PGRAPH_PATTERN_SHAPE_VALUE_64X_1Y 0x00000001 /* RW--V */ +#define NV_PGRAPH_PATTERN_SHAPE_VALUE_1X_64Y 0x00000002 /* RW--V */ +#define NV_PGRAPH_PATTERN_SHAPE_SELECT 4:4 /* RWXVF */ +#define NV_PGRAPH_PATTERN_SHAPE_SELECT_2COLOR 0x00000000 /* RW--V */ +#define NV_PGRAPH_PATTERN_SHAPE_SELECT_FULLCOLOR 0x00000001 /* RW--V */ +#define NV_PGRAPH_MONO_COLOR0 0x00400600 /* RW-4R */ +#define NV_PGRAPH_MONO_COLOR0_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_ROP3 0x00400604 /* RW-4R */ +#define NV_PGRAPH_ROP3_VALUE 7:0 /* RWXVF */ +#define NV_PGRAPH_CHROMA 0x00400814 /* RW-4R */ +#define NV_PGRAPH_CHROMA_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_BETA_AND 0x00400608 /* RW-4R */ +#define NV_PGRAPH_BETA_AND_VALUE_FRACTION 30:23 /* RWXUF */ +#define NV_PGRAPH_BETA_PREMULT 0x0040060c /* RW-4R */ +#define NV_PGRAPH_BETA_PREMULT_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_CONTROL0 0x00400818 /* RW-4R */ +#define NV_PGRAPH_CONTROL1 0x0040081c /* RW-4R */ +#define NV_PGRAPH_CONTROL2 0x00400820 /* RW-4R */ +#define NV_PGRAPH_BLEND 0x00400824 /* RW-4R */ +#define NV_PGRAPH_DPRAM_INDEX 0x00400828 /* RW-4R */ +#define NV_PGRAPH_DPRAM_INDEX_ADRS 6:0 /* RWIVF */ +#define NV_PGRAPH_DPRAM_INDEX_ADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_DPRAM_INDEX_SELECT 10:8 /* RWIVF */ +#define NV_PGRAPH_DPRAM_INDEX_SELECT_ADRS_0 0x00000000 /* RWI-V */ +#define NV_PGRAPH_DPRAM_INDEX_SELECT_ADRS_1 0x00000001 /* RW--V */ +#define NV_PGRAPH_DPRAM_INDEX_SELECT_DATA_0 0x00000002 /* RW--V */ +#define NV_PGRAPH_DPRAM_INDEX_SELECT_DATA_1 0x00000003 /* RW--V */ +#define NV_PGRAPH_DPRAM_INDEX_SELECT_WE_0 0x00000004 /* RW--V */ +#define NV_PGRAPH_DPRAM_INDEX_SELECT_WE_1 0x00000005 /* RW--V */ +#define NV_PGRAPH_DPRAM_INDEX_SELECT_ALPHA_0 0x00000006 /* RW--V */ +#define NV_PGRAPH_DPRAM_INDEX_SELECT_ALPHA_1 0x00000007 /* RW--V */ +#define NV_PGRAPH_DPRAM_DATA 0x0040082c /* RW-4R */ +#define NV_PGRAPH_DPRAM_DATA_VALUE 31:0 /* RWXVF */ +#define NV_PGRAPH_DPRAM_ADRS_0 0x0040082c /* RW-4R */ +#define NV_PGRAPH_DPRAM_ADRS_0__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */ +#define NV_PGRAPH_DPRAM_ADRS_0_VALUE 19:0 /* RWXVF */ +#define NV_PGRAPH_DPRAM_ADRS_1 0x0040082c /* RW-4R */ +#define NV_PGRAPH_DPRAM_ADRS_1__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */ +#define NV_PGRAPH_DPRAM_ADRS_1_VALUE 19:0 /* RWXVF */ +#define NV_PGRAPH_DPRAM_DATA_0 0x0040082c /* RW-4R */ +#define NV_PGRAPH_DPRAM_DATA_0__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */ +#define NV_PGRAPH_DPRAM_DATA_0_VALUE 31:0 /* RWXVF */ +#define NV_PGRAPH_DPRAM_DATA_1 0x0040082c /* RW-4R */ +#define NV_PGRAPH_DPRAM_DATA_1__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */ +#define NV_PGRAPH_DPRAM_DATA_1_VALUE 31:0 /* RWXVF */ +#define NV_PGRAPH_DPRAM_WE_0 0x0040082c /* RW-4R */ +#define NV_PGRAPH_DPRAM_WE_0__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */ +#define NV_PGRAPH_DPRAM_WE_0_VALUE 23:0 /* RWXVF */ +#define NV_PGRAPH_DPRAM_WE_1 0x0040082c /* RW-4R */ +#define NV_PGRAPH_DPRAM_WE_1__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */ +#define NV_PGRAPH_DPRAM_WE_1_VALUE 23:0 /* RWXVF */ +#define NV_PGRAPH_DPRAM_ALPHA_0 0x0040082c /* RW-4R */ +#define NV_PGRAPH_DPRAM_ALPHA_0__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */ +#define NV_PGRAPH_DPRAM_ALPHA_0_VALUE 31:0 /* RWXVF */ +#define NV_PGRAPH_DPRAM_ALPHA_1 0x0040082c /* RW-4R */ +#define NV_PGRAPH_DPRAM_ALPHA_1__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */ +#define NV_PGRAPH_DPRAM_ALPHA_1_VALUE 31:0 /* RWXVF */ +#define NV_PGRAPH_STORED_FMT 0x00400830 /* RW-4R */ +#define NV_PGRAPH_STORED_FMT_MONO0 5:0 /* RWXVF */ +#define NV_PGRAPH_STORED_FMT_PATT0 13:8 /* RWXVF */ +#define NV_PGRAPH_STORED_FMT_PATT1 21:16 /* RWXVF */ +#define NV_PGRAPH_STORED_FMT_CHROMA 29:24 /* RWXVF */ +#define NV_PGRAPH_FORMATS 0x00400618 /* RW-4R */ +#define NV_PGRAPH_FORMATS_ROP 2:0 /* R-XVF */ +#define NV_PGRAPH_FORMATS_ROP_Y8 0x00000000 /* -W--V */ +#define NV_PGRAPH_FORMATS_ROP_RGB15 0x00000001 /* -W--V */ +#define NV_PGRAPH_FORMATS_ROP_RGB16 0x00000002 /* -W--V */ +#define NV_PGRAPH_FORMATS_ROP_Y16 0x00000003 /* -W--V */ +#define NV_PGRAPH_FORMATS_ROP_INVALID 0x00000004 /* -W--V */ +#define NV_PGRAPH_FORMATS_ROP_RGB24 0x00000005 /* -W--V */ +#define NV_PGRAPH_FORMATS_ROP_RGB30 0x00000006 /* -W--V */ +#define NV_PGRAPH_FORMATS_ROP_Y32 0x00000007 /* -W--V */ +#define NV_PGRAPH_FORMATS_SRC 9:4 /* R-XVF */ +#define NV_PGRAPH_FORMATS_SRC_INVALID 0x00000000 /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_Y8 0x00000001 /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_X16A8Y8 0x00000002 /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_X24Y8 0x00000003 /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_A1R5G5B5 0x00000006 /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_X1R5G5B5 0x00000007 /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_X16A1R5G5B5 0x00000008 /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_X17R5G5B5 0x00000009 /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_R5G6B5 0x0000000A /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_A16R5G6B5 0x0000000B /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_X16R5G6B5 0x0000000C /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_A8R8G8B8 0x0000000D /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_X8R8G8B8 0x0000000E /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_Y16 0x0000000F /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_A16Y16 0x00000010 /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_X16Y16 0x00000011 /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_V8YB8U8YA8 0x00000012 /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_YB8V8YA8U8 0x00000013 /* RW--V */ +#define NV_PGRAPH_FORMATS_SRC_LE_Y32 0x00000014 /* RW--V */ +#define NV_PGRAPH_FORMATS_FB 15:12 /* R-XVF */ +#define NV_PGRAPH_FORMATS_FB_INVALID 0x00000000 /* RWI-V */ +#define NV_PGRAPH_FORMATS_FB_Y8 0x00000001 /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_A1R5G5B5 0x00000004 /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_R5G6B5 0x00000005 /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_Y16 0x00000006 /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_A8R8G8B8 0x0000000c /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_Y32 0x0000000d /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_V8YB8U8YA8 0x0000000e /* RW--V */ +#define NV_PGRAPH_FORMATS_FB_YB8V8YA8U8 0x0000000f /* RW--V */ +#define NV_PGRAPH_ABS_X_RAM(i) (0x00400400+(i)*4) /* RW-4A */ +#define NV_PGRAPH_ABS_X_RAM__SIZE_1 32 /* */ +#define NV_PGRAPH_ABS_X_RAM_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_X_RAM_BPORT(i) (0x00400c00+(i)*4) /* R--4A */ +#define NV_PGRAPH_X_RAM_BPORT__SIZE_1 32 /* */ +#define NV_PGRAPH_X_RAM_BPORT_VALUE 31:0 /* R--UF */ +#define NV_PGRAPH_ABS_Y_RAM(i) (0x00400480+(i)*4) /* RW-4A */ +#define NV_PGRAPH_ABS_Y_RAM__SIZE_1 32 /* */ +#define NV_PGRAPH_ABS_Y_RAM_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_Y_RAM_BPORT(i) (0x00400c80+(i)*4) /* R--4A */ +#define NV_PGRAPH_Y_RAM_BPORT__SIZE_1 32 /* */ +#define NV_PGRAPH_Y_RAM_BPORT_VALUE 31:0 /* R--UF */ +#define NV_PGRAPH_XY_LOGIC_MISC0 0x00400514 /* RW-4R */ +#define NV_PGRAPH_XY_LOGIC_MISC0_COUNTER 17:0 /* RWBUF */ +#define NV_PGRAPH_XY_LOGIC_MISC0_COUNTER_0 0x00000000 /* RWB-V */ +#define NV_PGRAPH_XY_LOGIC_MISC0_DIMENSION 20:20 /* RWVVF */ +#define NV_PGRAPH_XY_LOGIC_MISC0_DIMENSION_NONZERO 0x00000000 /* RWV-V */ +#define NV_PGRAPH_XY_LOGIC_MISC0_DIMENSION_ZERO 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC0_INDEX 31:28 /* RWBUF */ +#define NV_PGRAPH_XY_LOGIC_MISC0_INDEX_0 0x00000000 /* RWB-V */ +#define NV_PGRAPH_XY_LOGIC_MISC1 0x00400518 /* RW-4R */ +#define NV_PGRAPH_XY_LOGIC_MISC1_INITIAL 0:0 /* RWNVF */ +#define NV_PGRAPH_XY_LOGIC_MISC1_INITIAL_NEEDED 0x00000000 /* RWN-V */ +#define NV_PGRAPH_XY_LOGIC_MISC1_INITIAL_DONE 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX 4:4 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX_NOTNULL 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX_NULL 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY 5:5 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY_NOTNULL 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY_NULL 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX 12:12 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX_UUMAX 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX_IMAGEMAX 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX 16:16 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX_UUMAX 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX_IMAGEMAX 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA 20:20 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA_CLIPMAX 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA_IMAGEMAX 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC2 0x0040051C /* RW-4R */ +#define NV_PGRAPH_XY_LOGIC_MISC2_HANDOFF 0:0 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC2_HANDOFF_DISABLE 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC2_HANDOFF_ENABLE 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX 4:4 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX_NOTNULL 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX_NULL 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY 5:5 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY_NOTNULL 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY_NULL 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX 12:12 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX_UCMAX 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX_IMAGEMAX 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX 16:16 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX_UCMAX 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX_IMAGEMAX 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA 20:20 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA_CLIPMAX 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA_IMAGEMAX 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC3 0x00400520 /* RW-4R */ +#define NV_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0 0:0 /* RWXVF */ +#define NV_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0_NULL 0x00000000 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0_TRUE 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY 4:4 /* RWXVF */ +#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY_NULL 0x00000000 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY_TRUE 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX 8:8 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX_NULL 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX_TRUE 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG 12:12 /* RWIVF */ +#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG_NULL 0x00000000 /* RWI-V */ +#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG_TRUE 0x00000001 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_DIMX 22:16 /* RWXUF */ +#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_DIMX_0 0x00000000 /* RW--V */ +#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_WDIMX 30:24 /* RWXUF */ +#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_WDIMX_0 0x00000000 /* RW--V */ +#define NV_PGRAPH_X_MISC 0x00400500 /* RW-4R */ +#define NV_PGRAPH_X_MISC_BIT33_0 0:0 /* RWNVF */ +#define NV_PGRAPH_X_MISC_BIT33_0_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_X_MISC_BIT33_1 1:1 /* RWNVF */ +#define NV_PGRAPH_X_MISC_BIT33_1_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_X_MISC_BIT33_2 2:2 /* RWNVF */ +#define NV_PGRAPH_X_MISC_BIT33_2_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_X_MISC_BIT33_3 3:3 /* RWNVF */ +#define NV_PGRAPH_X_MISC_BIT33_3_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_X_MISC_RANGE_0 4:4 /* RWNVF */ +#define NV_PGRAPH_X_MISC_RANGE_0_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_X_MISC_RANGE_1 5:5 /* RWNVF */ +#define NV_PGRAPH_X_MISC_RANGE_1_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_X_MISC_RANGE_2 6:6 /* RWNVF */ +#define NV_PGRAPH_X_MISC_RANGE_2_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_X_MISC_RANGE_3 7:7 /* RWNVF */ +#define NV_PGRAPH_X_MISC_RANGE_3_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_X_MISC_ADDER_OUTPUT 29:28 /* RWXVF */ +#define NV_PGRAPH_X_MISC_ADDER_OUTPUT_EQ_0 0x00000000 /* RW--V */ +#define NV_PGRAPH_X_MISC_ADDER_OUTPUT_LT_0 0x00000001 /* RW--V */ +#define NV_PGRAPH_X_MISC_ADDER_OUTPUT_GT_0 0x00000002 /* RW--V */ +#define NV_PGRAPH_Y_MISC 0x00400504 /* RW-4R */ +#define NV_PGRAPH_Y_MISC_BIT33_0 0:0 /* RWNVF */ +#define NV_PGRAPH_Y_MISC_BIT33_0_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_Y_MISC_BIT33_1 1:1 /* RWNVF */ +#define NV_PGRAPH_Y_MISC_BIT33_1_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_Y_MISC_BIT33_2 2:2 /* RWNVF */ +#define NV_PGRAPH_Y_MISC_BIT33_2_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_Y_MISC_BIT33_3 3:3 /* RWNVF */ +#define NV_PGRAPH_Y_MISC_BIT33_3_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_Y_MISC_RANGE_0 4:4 /* RWNVF */ +#define NV_PGRAPH_Y_MISC_RANGE_0_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_Y_MISC_RANGE_1 5:5 /* RWNVF */ +#define NV_PGRAPH_Y_MISC_RANGE_1_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_Y_MISC_RANGE_2 6:6 /* RWNVF */ +#define NV_PGRAPH_Y_MISC_RANGE_2_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_Y_MISC_RANGE_3 7:7 /* RWNVF */ +#define NV_PGRAPH_Y_MISC_RANGE_3_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT 29:28 /* RWXVF */ +#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT_EQ_0 0x00000000 /* RW--V */ +#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT_LT_0 0x00000001 /* RW--V */ +#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT_GT_0 0x00000002 /* RW--V */ +#define NV_PGRAPH_ABS_UCLIP_XMIN 0x0040053C /* RW-4R */ +#define NV_PGRAPH_ABS_UCLIP_XMIN_VALUE 15:0 /* RWXSF */ +#define NV_PGRAPH_ABS_UCLIP_XMAX 0x00400544 /* RW-4R */ +#define NV_PGRAPH_ABS_UCLIP_XMAX_VALUE 17:0 /* RWXSF */ +#define NV_PGRAPH_ABS_UCLIP_YMIN 0x00400540 /* RW-4R */ +#define NV_PGRAPH_ABS_UCLIP_YMIN_VALUE 15:0 /* RWXSF */ +#define NV_PGRAPH_ABS_UCLIP_YMAX 0x00400548 /* RW-4R */ +#define NV_PGRAPH_ABS_UCLIP_YMAX_VALUE 17:0 /* RWXSF */ +#define NV_PGRAPH_ABS_UCLIPA_XMIN 0x00400560 /* RW-4R */ +#define NV_PGRAPH_ABS_UCLIPA_XMIN_VALUE 15:0 /* RWXSF */ +#define NV_PGRAPH_ABS_UCLIPA_XMAX 0x00400568 /* RW-4R */ +#define NV_PGRAPH_ABS_UCLIPA_XMAX_VALUE 17:0 /* RWXSF */ +#define NV_PGRAPH_ABS_UCLIPA_YMIN 0x00400564 /* RW-4R */ +#define NV_PGRAPH_ABS_UCLIPA_YMIN_VALUE 15:0 /* RWXSF */ +#define NV_PGRAPH_ABS_UCLIPA_YMAX 0x0040056C /* RW-4R */ +#define NV_PGRAPH_ABS_UCLIPA_YMAX_VALUE 17:0 /* RWXSF */ +#define NV_PGRAPH_SOURCE_COLOR 0x0040050C /* RW-4R */ +#define NV_PGRAPH_SOURCE_COLOR_VALUE 31:0 /* RWNVF */ +#define NV_PGRAPH_SOURCE_COLOR_VALUE_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_VALID1 0x00400508 /* RW-4R */ +#define NV_PGRAPH_VALID1_VLD 22:0 /* RWNVF */ +#define NV_PGRAPH_VALID1_VLD_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_VALID1_CLIP_MIN 28:28 /* RWIVF */ +#define NV_PGRAPH_VALID1_CLIP_MIN_NO_ERROR 0x00000000 /* RWI-V */ +#define NV_PGRAPH_VALID1_CLIP_MIN_ONLY 0x00000001 /* RW--V */ +#define NV_PGRAPH_VALID1_CLIPA_MIN 29:29 /* RWIVF */ +#define NV_PGRAPH_VALID1_CLIPA_MIN_NO_ERROR 0x00000000 /* RWI-V */ +#define NV_PGRAPH_VALID1_CLIPA_MIN_ONLY 0x00000001 /* RW--V */ +#define NV_PGRAPH_VALID1_CLIP_MAX 30:30 /* RWIVF */ +#define NV_PGRAPH_VALID1_CLIP_MAX_NO_ERROR 0x00000000 /* RWI-V */ +#define NV_PGRAPH_VALID1_CLIP_MAX_ONLY 0x00000001 /* RW--V */ +#define NV_PGRAPH_VALID1_CLIPA_MAX 31:31 /* RWIVF */ +#define NV_PGRAPH_VALID1_CLIPA_MAX_NO_ERROR 0x00000000 /* RWI-V */ +#define NV_PGRAPH_VALID1_CLIPA_MAX_ONLY 0x00000001 /* RW--V */ +#define NV_PGRAPH_VALID2 0x00400578 /* RW-4R */ +#define NV_PGRAPH_VALID2_VLD2 28:0 /* RWNVF */ +#define NV_PGRAPH_VALID2_VLD2_0 0x00000000 /* RWN-V */ +#define NV_PGRAPH_ABS_ICLIP_XMAX 0x00400534 /* RW-4R */ +#define NV_PGRAPH_ABS_ICLIP_XMAX_VALUE 17:0 /* RWXSF */ +#define NV_PGRAPH_ABS_ICLIP_YMAX 0x00400538 /* RW-4R */ +#define NV_PGRAPH_ABS_ICLIP_YMAX_VALUE 17:0 /* RWXSF */ +#define NV_PGRAPH_CLIPX_0 0x00400524 /* RW-4R */ +#define NV_PGRAPH_CLIPX_0_CLIP0_MIN 1:0 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP0_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP0_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP0_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP0_MAX 3:2 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP0_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP0_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP0_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP1_MIN 5:4 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP1_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP1_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP1_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP1_MAX 7:6 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP1_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP1_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP1_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP2_MIN 9:8 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP2_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP2_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP2_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP2_MAX 11:10 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP2_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP2_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP2_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP3_MIN 13:12 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP3_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP3_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP3_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP3_MAX 15:14 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP3_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP3_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP3_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP4_MIN 17:16 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP4_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP4_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP4_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP4_MAX 19:18 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP4_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP4_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP4_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP5_MIN 21:20 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP5_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP5_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP5_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP5_MAX 23:22 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP5_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP5_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP5_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP6_MIN 25:24 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP6_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP6_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP6_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP6_MAX 27:26 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP6_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP6_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP6_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP7_MIN 29:28 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP7_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP7_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP7_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP7_MAX 31:30 /* RWNVF */ +#define NV_PGRAPH_CLIPX_0_CLIP7_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_0_CLIP7_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_0_CLIP7_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1 0x00400528 /* RW-4R */ +#define NV_PGRAPH_CLIPX_1_CLIP8_MIN 1:0 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP8_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP8_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP8_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP8_MAX 3:2 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP8_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP8_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP8_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP9_MIN 5:4 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP9_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP9_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP9_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP9_MAX 7:6 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP9_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP9_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP9_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP10_MIN 9:8 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP10_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP10_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP10_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP10_MAX 11:10 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP10_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP10_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP10_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP11_MIN 13:12 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP11_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP11_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP11MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP11_MAX 15:14 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP11_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP11_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP11_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP12_MIN 17:16 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP12_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP12_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP12_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP12_MAX 19:18 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP12_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP12_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP12_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP13_MIN 21:20 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP13_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP13_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP13_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP13_MAX 23:22 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP13_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP13_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP13_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP14_MIN 25:24 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP14_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP14_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP14_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP14_MAX 27:26 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP14_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP14_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP14_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP15_MIN 29:28 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP15_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP15_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP15_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP15_MAX 31:30 /* RWNVF */ +#define NV_PGRAPH_CLIPX_1_CLIP15_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPX_1_CLIP15_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPX_1_CLIP15_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0 0x0040052c /* RW-4R */ +#define NV_PGRAPH_CLIPY_0_CLIP0_MIN 1:0 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP0_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP0_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP0_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP0_MAX 3:2 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP0_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP0_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP0_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP1_MIN 5:4 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP1_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP1_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP1_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP1_MAX 7:6 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP1_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP1_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP1_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP2_MIN 9:8 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP2_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP2_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP2_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP2_MAX 11:10 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP2_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP2_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP2_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP3_MIN 13:12 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP3_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP3_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP3_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP3_MAX 15:14 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP3_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP3_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP3_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP4_MIN 17:16 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP4_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP4_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP4_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP4_MAX 19:18 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP4_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP4_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP4_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP5_MIN 21:20 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP5_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP5_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP5_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP5_MAX 23:22 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP5_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP5_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP5_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP6_MIN 25:24 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP6_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP6_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP6_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP6_MAX 27:26 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP6_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP6_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP6_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP7_MIN 29:28 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP7_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP7_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP7_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP7_MAX 31:30 /* RWNVF */ +#define NV_PGRAPH_CLIPY_0_CLIP7_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_0_CLIP7_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_0_CLIP7_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1 0x00400530 /* RW-4R */ +#define NV_PGRAPH_CLIPY_1_CLIP8_MIN 1:0 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP8_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP8_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP8_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP8_MAX 3:2 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP8_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP8_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP8_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP9_MIN 5:4 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP9_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP9_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP9_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP9_MAX 7:6 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP9_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP9_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP9_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP10_MIN 9:8 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP10_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP10_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP10_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP10_MAX 11:10 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP10_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP10_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP10_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP11_MIN 13:12 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP11_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP11_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP11MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP11_MAX 15:14 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP11_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP11_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP11_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP12_MIN 17:16 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP12_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP12_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP12_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP12_MAX 19:18 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP12_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP12_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP12_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP13_MIN 21:20 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP13_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP13_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP13_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP13_MAX 23:22 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP13_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP13_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP13_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP14_MIN 25:24 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP14_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP14_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP14_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP14_MAX 27:26 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP14_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP14_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP14_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP15_MIN 29:28 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP15_MIN_GT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP15_MIN_LT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP15_MIN_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP15_MAX 31:30 /* RWNVF */ +#define NV_PGRAPH_CLIPY_1_CLIP15_MAX_LT 0x00000000 /* RW--V */ +#define NV_PGRAPH_CLIPY_1_CLIP15_MAX_GT 0x00000001 /* RWN-V */ +#define NV_PGRAPH_CLIPY_1_CLIP15_MAX_EQ 0x00000002 /* RW--V */ +#define NV_PGRAPH_MISC24_0 0x00400510 /* RW-4R */ +#define NV_PGRAPH_MISC24_0_VALUE 23:0 /* RWXUF */ +#define NV_PGRAPH_MISC24_1 0x00400570 /* RW-4R */ +#define NV_PGRAPH_MISC24_1_VALUE 23:0 /* RWXUF */ +#define NV_PGRAPH_MISC24_2 0x00400574 /* RW-4R */ +#define NV_PGRAPH_MISC24_2_VALUE 23:0 /* RWXUF */ +#define NV_PGRAPH_PASSTHRU_0 0x0040057C /* RW-4R */ +#define NV_PGRAPH_PASSTHRU_0_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_PASSTHRU_1 0x00400580 /* RW-4R */ +#define NV_PGRAPH_PASSTHRU_1_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_PASSTHRU_2 0x00400584 /* RW-4R */ +#define NV_PGRAPH_PASSTHRU_2_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_U_RAM(i) (0x00400d00+(i)*4) /* RW-4A */ +#define NV_PGRAPH_U_RAM__SIZE_1 16 /* */ +#define NV_PGRAPH_U_RAM_VALUE 31:6 /* RWXFF */ +#define NV_PGRAPH_V_RAM(i) (0x00400d40+(i)*4) /* RW-4A */ +#define NV_PGRAPH_V_RAM__SIZE_1 16 /* */ +#define NV_PGRAPH_V_RAM_VALUE 31:6 /* RWXFF */ +#define NV_PGRAPH_M_RAM(i) (0x00400d80+(i)*4) /* RW-4A */ +#define NV_PGRAPH_M_RAM__SIZE_1 16 /* */ +#define NV_PGRAPH_M_RAM_VALUE 31:6 /* RWXFF */ +#define NV_PGRAPH_DMA_START_0 0x00401000 /* RW-4R */ +#define NV_PGRAPH_DMA_START_0_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_DMA_START_1 0x00401004 /* RW-4R */ +#define NV_PGRAPH_DMA_START_1_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_DMA_LENGTH 0x00401008 /* RW-4R */ +#define NV_PGRAPH_DMA_LENGTH_VALUE 21:0 /* RWXUF */ +#define NV_PGRAPH_DMA_MISC 0x0040100C /* RW-4R */ +#define NV_PGRAPH_DMA_MISC_COUNT 15:0 /* RWXUF */ +#define NV_PGRAPH_DMA_MISC_FMT_SRC 18:16 /* RWXVF */ +#define NV_PGRAPH_DMA_MISC_FMT_DST 22:20 /* RWXVF */ +#define NV_PGRAPH_DMA_DATA_0 0x00401020 /* RW-4R */ +#define NV_PGRAPH_DMA_DATA_0_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_DMA_DATA_1 0x00401024 /* RW-4R */ +#define NV_PGRAPH_DMA_DATA_1_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_DMA_RM 0x00401030 /* RW-4R */ +#define NV_PGRAPH_DMA_RM_ASSIST_A 0:0 /* RWIVF */ +#define NV_PGRAPH_DMA_RM_ASSIST_A_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_DMA_RM_ASSIST_A_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_DMA_RM_ASSIST_A_RESET 0x00000001 /* -W--C */ +#define NV_PGRAPH_DMA_RM_ASSIST_B 1:1 /* RWIVF */ +#define NV_PGRAPH_DMA_RM_ASSIST_B_NOT_PENDING 0x00000000 /* R-I-V */ +#define NV_PGRAPH_DMA_RM_ASSIST_B_PENDING 0x00000001 /* R---V */ +#define NV_PGRAPH_DMA_RM_ASSIST_B_RESET 0x00000001 /* -W--C */ +#define NV_PGRAPH_DMA_RM_WRITE_REQ 4:4 /* CWIVF */ +#define NV_PGRAPH_DMA_RM_WRITE_REQ_NOT_PENDING 0x00000000 /* CWI-V */ +#define NV_PGRAPH_DMA_RM_WRITE_REQ_PENDING 0x00000001 /* -W--T */ +#define NV_PGRAPH_DMA_A_XLATE_INST 0x00401040 /* RW-4R */ +#define NV_PGRAPH_DMA_A_XLATE_INST_VALUE 15:0 /* RWXUF */ +#define NV_PGRAPH_DMA_A_CONTROL 0x00401044 /* RW-4R */ +#define NV_PGRAPH_DMA_A_CONTROL_PAGE_TABLE 12:12 /* RWIVF */ +#define NV_PGRAPH_DMA_A_CONTROL_PAGE_TABLE_NOT_PRESENT 0x00000000 /* RWI-V */ +#define NV_PGRAPH_DMA_A_CONTROL_PAGE_TABLE_PRESENT 0x00000001 /* RW--V */ +#define NV_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY 13:13 /* RWXVF */ +#define NV_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY_NOT_LINEAR 0x00000000 /* RW--V */ +#define NV_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY_LINEAR 0x00000001 /* RW--V */ +#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE 17:16 /* RWXUF */ +#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE_NVM 0x00000000 /* RW--V */ +#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE_PCI 0x00000002 /* RW--V */ +#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE_AGP 0x00000003 /* RW--V */ +#define NV_PGRAPH_DMA_A_CONTROL_ADJUST 31:20 /* RWXUF */ +#define NV_PGRAPH_DMA_A_LIMIT 0x00401048 /* RW-4R */ +#define NV_PGRAPH_DMA_A_LIMIT_OFFSET 31:0 /* RWXUF */ +#define NV_PGRAPH_DMA_A_TLB_PTE 0x0040104C /* RW-4R */ +#define NV_PGRAPH_DMA_A_TLB_PTE_ACCESS 1:1 /* RWXVF */ +#define NV_PGRAPH_DMA_A_TLB_PTE_ACCESS_READ_ONLY 0x00000000 /* RW--V */ +#define NV_PGRAPH_DMA_A_TLB_PTE_ACCESS_READ_WRITE 0x00000001 /* RW--V */ +#define NV_PGRAPH_DMA_A_TLB_PTE_FRAME_ADDRESS 31:12 /* RWXUF */ +#define NV_PGRAPH_DMA_A_TLB_TAG 0x00401050 /* RW-4R */ +#define NV_PGRAPH_DMA_A_TLB_TAG_ADDRESS 31:12 /* RWXUF */ +#define NV_PGRAPH_DMA_A_ADJ_OFFSET 0x00401054 /* RW-4R */ +#define NV_PGRAPH_DMA_A_ADJ_OFFSET_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_DMA_A_OFFSET 0x00401058 /* RW-4R */ +#define NV_PGRAPH_DMA_A_OFFSET_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_DMA_A_SIZE 0x0040105C /* RW-4R */ +#define NV_PGRAPH_DMA_A_SIZE_VALUE 24:0 /* RWXUF */ +#define NV_PGRAPH_DMA_A_Y_SIZE 0x00401060 /* RW-4R */ +#define NV_PGRAPH_DMA_A_Y_SIZE_VALUE 10:0 /* RWXUF */ +#define NV_PGRAPH_DMA_B_XLATE_INST 0x00401080 /* RW-4R */ +#define NV_PGRAPH_DMA_B_XLATE_INST_VALUE 15:0 /* RWXUF */ +#define NV_PGRAPH_DMA_B_CONTROL 0x00401084 /* RW-4R */ +#define NV_PGRAPH_DMA_B_CONTROL_PAGE_TABLE 12:12 /* RWIVF */ +#define NV_PGRAPH_DMA_B_CONTROL_PAGE_TABLE_NOT_PRESENT 0x00000000 /* RWI-V */ +#define NV_PGRAPH_DMA_B_CONTROL_PAGE_TABLE_PRESENT 0x00000001 /* RW--V */ +#define NV_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY 13:13 /* RWXVF */ +#define NV_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY_NOT_LINEAR 0x00000000 /* RW--V */ +#define NV_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY_LINEAR 0x00000001 /* RW--V */ +#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE 17:16 /* RWXUF */ +#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE_NVM 0x00000000 /* RW--V */ +#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE_PCI 0x00000002 /* RW--V */ +#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE_AGP 0x00000003 /* RW--V */ +#define NV_PGRAPH_DMA_B_CONTROL_ADJUST 31:20 /* RWXUF */ +#define NV_PGRAPH_DMA_B_LIMIT 0x00401088 /* RW-4R */ +#define NV_PGRAPH_DMA_B_LIMIT_OFFSET 31:0 /* RWXUF */ +#define NV_PGRAPH_DMA_B_TLB_PTE 0x0040108C /* RW-4R */ +#define NV_PGRAPH_DMA_B_TLB_PTE_ACCESS 1:1 /* RWXVF */ +#define NV_PGRAPH_DMA_B_TLB_PTE_ACCESS_READ_ONLY 0x00000000 /* RW--V */ +#define NV_PGRAPH_DMA_B_TLB_PTE_ACCESS_READ_WRITE 0x00000001 /* RW--V */ +#define NV_PGRAPH_DMA_B_TLB_PTE_FRAME_ADDRESS 31:12 /* RWXUF */ +#define NV_PGRAPH_DMA_B_TLB_TAG 0x00401090 /* RW-4R */ +#define NV_PGRAPH_DMA_B_TLB_TAG_ADDRESS 31:12 /* RWXUF */ +#define NV_PGRAPH_DMA_B_ADJ_OFFSET 0x00401094 /* RW-4R */ +#define NV_PGRAPH_DMA_B_ADJ_OFFSET_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_DMA_B_OFFSET 0x00401098 /* RW-4R */ +#define NV_PGRAPH_DMA_B_OFFSET_VALUE 31:0 /* RWXUF */ +#define NV_PGRAPH_DMA_B_SIZE 0x0040109C /* RW-4R */ +#define NV_PGRAPH_DMA_B_SIZE_VALUE 24:0 /* RWXUF */ +#define NV_PGRAPH_DMA_B_Y_SIZE 0x004010A0 /* RW-4R */ +#define NV_PGRAPH_DMA_B_Y_SIZE_VALUE 10:0 /* RWXUF */ + +/* Framebuffer registers */ +#define NV_PFB 0x00100FFF:0x00100000 /* RW--D */ +#define NV_PFB_BOOT_0 0x00100000 /* RW-4R */ +#define NV_PFB_BOOT_0_RAM_AMOUNT 1:0 /* RW-VF */ +#define NV_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000 /* RW--V */ +#define NV_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001 /* RW--V */ +#define NV_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002 /* RW--V */ +#define NV_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003 /* RW--V */ +#define NV_PFB_BOOT_0_RAM_WIDTH_128 2:2 /* RW-VF */ +#define NV_PFB_BOOT_0_RAM_WIDTH_128_OFF 0x00000000 /* RW--V */ +#define NV_PFB_BOOT_0_RAM_WIDTH_128_ON 0x00000001 /* RW--V */ +#define NV_PFB_BOOT_0_RAM_TYPE 4:3 /* RW-VF */ +#define NV_PFB_BOOT_0_RAM_TYPE_256K 0x00000000 /* RW--V */ +#define NV_PFB_BOOT_0_RAM_TYPE_512K_2BANK 0x00000001 /* RW--V */ +#define NV_PFB_BOOT_0_RAM_TYPE_512K_4BANK 0x00000002 /* RW--V */ +#define NV_PFB_BOOT_0_RAM_TYPE_1024K_2BANK 0x00000003 /* RW--V */ +#define NV_PFB_CONFIG_0 0x00100200 /* RW-4R */ +#define NV_PFB_CONFIG_0_TYPE 14:0 /* RWIVF */ +#define NV_PFB_CONFIG_0_TYPE_OLD1024_FIXED_8BPP 0x00000120 /* RW--V */ +#define NV_PFB_CONFIG_0_TYPE_OLD1024_FIXED_16BPP 0x00000220 /* RW--V */ +#define NV_PFB_CONFIG_0_TYPE_OLD1024_FIXED_32BPP 0x00000320 /* RW--V */ +#define NV_PFB_CONFIG_0_TYPE_OLD1024_VAR_8BPP 0x00004120 /* RW--V */ +#define NV_PFB_CONFIG_0_TYPE_OLD1024_VAR_16BPP 0x00004220 /* RW--V */ +#define NV_PFB_CONFIG_0_TYPE_OLD1024_VAR_32BPP 0x00004320 /* RW--V */ +#define NV_PFB_CONFIG_0_TYPE_TETRIS 0x00002000 /* RW--V */ +#define NV_PFB_CONFIG_0_TYPE_NOTILING 0x00001114 /* RWI-V */ +#define NV_PFB_CONFIG_0_TETRIS_MODE 17:15 /* RWI-F */ +#define NV_PFB_CONFIG_0_TETRIS_MODE_PASS 0x00000000 /* RWI-V */ +#define NV_PFB_CONFIG_0_TETRIS_MODE_1 0x00000001 /* RW--V */ +#define NV_PFB_CONFIG_0_TETRIS_MODE_2 0x00000002 /* RW--V */ +#define NV_PFB_CONFIG_0_TETRIS_MODE_3 0x00000003 /* RW--V */ +#define NV_PFB_CONFIG_0_TETRIS_MODE_4 0x00000004 /* RW--V */ +#define NV_PFB_CONFIG_0_TETRIS_MODE_5 0x00000005 /* RW--V */ +#define NV_PFB_CONFIG_0_TETRIS_MODE_6 0x00000006 /* RW--V */ +#define NV_PFB_CONFIG_0_TETRIS_MODE_7 0x00000007 /* RW--V */ +#define NV_PFB_CONFIG_0_TETRIS_SHIFT 19:18 /* RWI-F */ +#define NV_PFB_CONFIG_0_TETRIS_SHIFT_0 0x00000000 /* RWI-V */ +#define NV_PFB_CONFIG_0_TETRIS_SHIFT_1 0x00000001 /* RW--V */ +#define NV_PFB_CONFIG_0_TETRIS_SHIFT_2 0x00000002 /* RW--V */ +#define NV_PFB_CONFIG_0_BANK_SWAP 22:20 /* RWI-F */ +#define NV_PFB_CONFIG_0_BANK_SWAP_OFF 0x00000000 /* RWI-V */ +#define NV_PFB_CONFIG_0_BANK_SWAP_1M 0x00000001 /* RW--V */ +#define NV_PFB_CONFIG_0_BANK_SWAP_2M 0x00000005 /* RW--V */ +#define NV_PFB_CONFIG_0_BANK_SWAP_4M 0x00000007 /* RW--V */ +#define NV_PFB_CONFIG_0_UNUSED 23:23 /* RW-VF */ +#define NV_PFB_CONFIG_0_SCRAMBLE_EN 29:29 /* RWIVF */ +#define NV_PFB_CONFIG_0_SCRAMBLE_EN_INIT 0x00000000 /* RW--V */ +#define NV_PFB_CONFIG_0_SCRAMBLE_ACTIVE 0x00000001 /* RW--V */ +#define NV_PFB_CONFIG_0_PRAMIN_WR 28:28 /* RWIVF */ +#define NV_PFB_CONFIG_0_PRAMIN_WR_INIT 0x00000000 /* RW--V */ +#define NV_PFB_CONFIG_0_PRAMIN_WR_DISABLED 0x00000001 /* RW--V */ +#define NV_PFB_CONFIG_0_PRAMIN_WR_MASK 27:24 /* RWIVF */ +#define NV_PFB_CONFIG_0_PRAMIN_WR_MASK_INIT 0x00000000 /* RWI-V */ +#define NV_PFB_CONFIG_0_PRAMIN_WR_MASK_CLEAR 0x0000000f /* RWI-V */ +#define NV_PFB_CONFIG_1 0x00100204 /* RW-4R */ +#define NV_PFB_RTL 0x00100300 /* RW-4R */ +#define NV_PFB_RTL_H 0:0 /* RWIUF */ +#define NV_PFB_RTL_H_DEFAULT 0x00000000 /* RWI-V */ +#define NV_PFB_RTL_MC 1:1 /* RWIUF */ +#define NV_PFB_RTL_MC_DEFAULT 0x00000000 /* RWI-V */ +#define NV_PFB_RTL_V 2:2 /* RWIUF */ +#define NV_PFB_RTL_V_DEFAULT 0x00000000 /* RWI-V */ +#define NV_PFB_RTL_G 3:3 /* RWIUF */ +#define NV_PFB_RTL_G_DEFAULT 0x00000000 /* RWI-V */ +#define NV_PFB_RTL_GB 4:4 /* RWIUF */ +#define NV_PFB_RTL_GB_DEFAULT 0x00000000 /* RWI-V */ +#define NV_PFB_CONFIG_0_RESOLUTION 5:0 /* RWIVF */ +#define NV_PFB_CONFIG_0_RESOLUTION_320_PIXELS 0x0000000a /* RW--V */ +#define NV_PFB_CONFIG_0_RESOLUTION_400_PIXELS 0x0000000d /* RW--V */ +#define NV_PFB_CONFIG_0_RESOLUTION_480_PIXELS 0x0000000f /* RW--V */ +#define NV_PFB_CONFIG_0_RESOLUTION_512_PIXELS 0x00000010 /* RW--V */ +#define NV_PFB_CONFIG_0_RESOLUTION_640_PIXELS 0x00000014 /* RW--V */ +#define NV_PFB_CONFIG_0_RESOLUTION_800_PIXELS 0x00000019 /* RW--V */ +#define NV_PFB_CONFIG_0_RESOLUTION_960_PIXELS 0x0000001e /* RW--V */ +#define NV_PFB_CONFIG_0_RESOLUTION_1024_PIXELS 0x00000020 /* RW--V */ +#define NV_PFB_CONFIG_0_RESOLUTION_1152_PIXELS 0x00000024 /* RW--V */ +#define NV_PFB_CONFIG_0_RESOLUTION_1280_PIXELS 0x00000028 /* RW--V */ +#define NV_PFB_CONFIG_0_RESOLUTION_1600_PIXELS 0x00000032 /* RW--V */ +#define NV_PFB_CONFIG_0_RESOLUTION_DEFAULT 0x00000014 /* RWI-V */ +#define NV_PFB_CONFIG_0_PIXEL_DEPTH 9:8 /* RWIVF */ +#define NV_PFB_CONFIG_0_PIXEL_DEPTH_8_BITS 0x00000001 /* RW--V */ +#define NV_PFB_CONFIG_0_PIXEL_DEPTH_16_BITS 0x00000002 /* RW--V */ +#define NV_PFB_CONFIG_0_PIXEL_DEPTH_32_BITS 0x00000003 /* RW--V */ +#define NV_PFB_CONFIG_0_PIXEL_DEPTH_DEFAULT 0x00000001 /* RWI-V */ +#define NV_PFB_CONFIG_0_TILING 12:12 /* RWIVF */ +#define NV_PFB_CONFIG_0_TILING_ENABLED 0x00000000 /* RW--V */ +#define NV_PFB_CONFIG_0_TILING_DISABLED 0x00000001 /* RWI-V */ +#define NV_PFB_CONFIG_1_SGRAM100 3:3 /* RWIVF */ +#define NV_PFB_CONFIG_1_SGRAM100_ENABLED 0x00000000 /* RWI-V */ +#define NV_PFB_CONFIG_1_SGRAM100_DISABLED 0x00000001 /* RW--V */ +#define NV_PFB_DEBUG_0_CKE_ALWAYSON 29:29 /* RWIVF */ +#define NV_PFB_DEBUG_0_CKE_ALWAYSON_OFF 0x00000000 /* RW--V */ +#define NV_PFB_DEBUG_0_CKE_ALWAYSON_ON 0x00000001 /* RWI-V */ + +#define NV_PEXTDEV 0x00101FFF:0x00101000 /* RW--D */ +#define NV_PEXTDEV_BOOT_0 0x00101000 /* R--4R */ +#define NV_PEXTDEV_BOOT_0_STRAP_BUS_SPEED 0:0 /* R-XVF */ +#define NV_PEXTDEV_BOOT_0_STRAP_BUS_SPEED_33MHZ 0x00000000 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_BUS_SPEED_66MHZ 0x00000001 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR 1:1 /* R-XVF */ +#define NV_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR_NO_BIOS 0x00000000 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR_BIOS 0x00000001 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE 3:2 /* R-XVF */ +#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_256K 0x00000000 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_512K_2BANK 0x00000001 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_512K_4BANK 0x00000002 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_1024K_2BANK 0x00000003 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH 4:4 /* R-XVF */ +#define NV_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH_64 0x00000000 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH_128 0x00000001 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_BUS_TYPE 5:5 /* R-XVF */ +#define NV_PEXTDEV_BOOT_0_STRAP_BUS_TYPE_PCI 0x00000000 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_BUS_TYPE_AGP 0x00000001 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_CRYSTAL 6:6 /* R-XVF */ +#define NV_PEXTDEV_BOOT_0_STRAP_CRYSTAL_13500K 0x00000000 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_CRYSTAL_14318180 0x00000001 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE 8:7 /* R-XVF */ +#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_SECAM 0x00000000 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_NTSC 0x00000001 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_PAL 0x00000002 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_DISABLED 0x00000003 /* R---V */ +#define NV_PEXTDEV_BOOT_0_STRAP_OVERWRITE 11:11 /* RWIVF */ +#define NV_PEXTDEV_BOOT_0_STRAP_OVERWRITE_DISABLED 0x00000000 /* RWI-V */ +#define NV_PEXTDEV_BOOT_0_STRAP_OVERWRITE_ENABLED 0x00000001 /* RW--V */ + +/* Extras */ +#define NV_PRAMIN 0x007FFFFF:0x00700000 /* RW--M */ +/*#define NV_PRAMIN 0x00FFFFFF:0x00C00000*/ +#define NV_PNVM 0x01FFFFFF:0x01000000 /* RW--M */ +/*#define NV_PNVM 0x00BFFFFF:0x00800000*/ +#define NV_CHAN0 0x0080ffff:0x00800000 + +/* FIFO subchannels */ +#define NV_UROP 0x43 +#define NV_UCHROMA 0x57 +#define NV_UCLIP 0x19 +#define NV_UPATT 0x18 +#define NV_ULIN 0x5C +#define NV_UTRI 0x5D +#define NV_URECT 0x5E +#define NV_UBLIT 0x5F +#define NV_UGLYPH 0x4B + +#endif /*__NV4REF_H__*/ + diff --git a/drivers/video/riva/nv_driver.c b/drivers/video/riva/nv_driver.c new file mode 100644 index 000000000000..be630a0ccfd4 --- /dev/null +++ b/drivers/video/riva/nv_driver.c @@ -0,0 +1,425 @@ +/* $XConsortium: nv_driver.c /main/3 1996/10/28 05:13:37 kaleb $ */ +/* + * Copyright 1996-1997 David J. McKay + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * DAVID J. MCKAY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * GPL licensing note -- nVidia is allowing a liberal interpretation of + * the documentation restriction above, to merely say that this nVidia's + * copyright and disclaimer should be included with all code derived + * from this source. -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 + */ + +/* Hacked together from mga driver and 3.3.4 NVIDIA driver by Jarno Paananen + <jpaana@s2.org> */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_setup.c,v 1.18 2002/08/0 +5 20:47:06 mvojkovi Exp $ */ + +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include "nv_type.h" +#include "rivafb.h" +#include "nvreg.h" + + +#ifndef CONFIG_PCI /* sanity check */ +#error This driver requires PCI support. +#endif + +#define PFX "rivafb: " + +static inline unsigned char MISCin(struct riva_par *par) +{ + return (VGA_RD08(par->riva.PVIO, 0x3cc)); +} + +static Bool +riva_is_connected(struct riva_par *par, Bool second) +{ + volatile U032 __iomem *PRAMDAC = par->riva.PRAMDAC0; + U032 reg52C, reg608; + Bool present; + + if(second) PRAMDAC += 0x800; + + reg52C = NV_RD32(PRAMDAC, 0x052C); + reg608 = NV_RD32(PRAMDAC, 0x0608); + + NV_WR32(PRAMDAC, 0x0608, reg608 & ~0x00010000); + + NV_WR32(PRAMDAC, 0x052C, reg52C & 0x0000FEEE); + mdelay(1); + NV_WR32(PRAMDAC, 0x052C, NV_RD32(PRAMDAC, 0x052C) | 1); + + NV_WR32(par->riva.PRAMDAC0, 0x0610, 0x94050140); + NV_WR32(par->riva.PRAMDAC0, 0x0608, 0x00001000); + + mdelay(1); + + present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? TRUE : FALSE; + + NV_WR32(par->riva.PRAMDAC0, 0x0608, + NV_RD32(par->riva.PRAMDAC0, 0x0608) & 0x0000EFFF); + + NV_WR32(PRAMDAC, 0x052C, reg52C); + NV_WR32(PRAMDAC, 0x0608, reg608); + + return present; +} + +static void +riva_override_CRTC(struct riva_par *par) +{ + printk(KERN_INFO PFX + "Detected CRTC controller %i being used\n", + par->SecondCRTC ? 1 : 0); + + if(par->forceCRTC != -1) { + printk(KERN_INFO PFX + "Forcing usage of CRTC %i\n", par->forceCRTC); + par->SecondCRTC = par->forceCRTC; + } +} + +static void +riva_is_second(struct riva_par *par) +{ + if (par->FlatPanel == 1) { + switch(par->Chipset & 0xffff) { + case 0x0174: + case 0x0175: + case 0x0176: + case 0x0177: + case 0x0179: + case 0x017C: + case 0x017D: + case 0x0186: + case 0x0187: + /* this might not be a good default for the chips below */ + case 0x0286: + case 0x028C: + case 0x0316: + case 0x0317: + case 0x031A: + case 0x031B: + case 0x031C: + case 0x031D: + case 0x031E: + case 0x031F: + case 0x0324: + case 0x0325: + case 0x0328: + case 0x0329: + case 0x032C: + case 0x032D: + par->SecondCRTC = TRUE; + break; + default: + par->SecondCRTC = FALSE; + break; + } + } else { + if(riva_is_connected(par, 0)) { + + if (NV_RD32(par->riva.PRAMDAC0, 0x0000052C) & 0x100) + par->SecondCRTC = TRUE; + else + par->SecondCRTC = FALSE; + } else + if (riva_is_connected(par, 1)) { + if(NV_RD32(par->riva.PRAMDAC0, 0x0000252C) & 0x100) + par->SecondCRTC = TRUE; + else + par->SecondCRTC = FALSE; + } else /* default */ + par->SecondCRTC = FALSE; + } + riva_override_CRTC(par); +} + +unsigned long riva_get_memlen(struct riva_par *par) +{ + RIVA_HW_INST *chip = &par->riva; + unsigned long memlen = 0; + unsigned int chipset = par->Chipset; + struct pci_dev* dev; + int amt; + + switch (chip->Architecture) { + case NV_ARCH_03: + if (NV_RD32(chip->PFB, 0x00000000) & 0x00000020) { + if (((NV_RD32(chip->PMC, 0x00000000) & 0xF0) == 0x20) + && ((NV_RD32(chip->PMC, 0x00000000)&0x0F)>=0x02)) { + /* + * SDRAM 128 ZX. + */ + switch (NV_RD32(chip->PFB,0x00000000) & 0x03) { + case 2: + memlen = 1024 * 4; + break; + case 1: + memlen = 1024 * 2; + break; + default: + memlen = 1024 * 8; + break; + } + } else { + memlen = 1024 * 8; + } + } else { + /* + * SGRAM 128. + */ + switch (NV_RD32(chip->PFB, 0x00000000) & 0x00000003) { + case 0: + memlen = 1024 * 8; + break; + case 2: + memlen = 1024 * 4; + break; + default: + memlen = 1024 * 2; + break; + } + } + break; + case NV_ARCH_04: + if (NV_RD32(chip->PFB, 0x00000000) & 0x00000100) { + memlen = ((NV_RD32(chip->PFB, 0x00000000)>>12)&0x0F) * + 1024 * 2 + 1024 * 2; + } else { + switch (NV_RD32(chip->PFB, 0x00000000) & 0x00000003) { + case 0: + memlen = 1024 * 32; + break; + case 1: + memlen = 1024 * 4; + break; + case 2: + memlen = 1024 * 8; + break; + case 3: + default: + memlen = 1024 * 16; + break; + } + } + break; + case NV_ARCH_10: + case NV_ARCH_20: + case NV_ARCH_30: + if(chipset == NV_CHIP_IGEFORCE2) { + + dev = pci_find_slot(0, 1); + pci_read_config_dword(dev, 0x7C, &amt); + memlen = (((amt >> 6) & 31) + 1) * 1024; + } else if (chipset == NV_CHIP_0x01F0) { + dev = pci_find_slot(0, 1); + pci_read_config_dword(dev, 0x84, &amt); + memlen = (((amt >> 4) & 127) + 1) * 1024; + } else { + switch ((NV_RD32(chip->PFB, 0x0000020C) >> 20) & + 0x000000FF){ + case 0x02: + memlen = 1024 * 2; + break; + case 0x04: + memlen = 1024 * 4; + break; + case 0x08: + memlen = 1024 * 8; + break; + case 0x10: + memlen = 1024 * 16; + break; + case 0x20: + memlen = 1024 * 32; + break; + case 0x40: + memlen = 1024 * 64; + break; + case 0x80: + memlen = 1024 * 128; + break; + default: + memlen = 1024 * 16; + break; + } + } + break; + } + return memlen; +} + +unsigned long riva_get_maxdclk(struct riva_par *par) +{ + RIVA_HW_INST *chip = &par->riva; + unsigned long dclk = 0; + + switch (chip->Architecture) { + case NV_ARCH_03: + if (NV_RD32(chip->PFB, 0x00000000) & 0x00000020) { + if (((NV_RD32(chip->PMC, 0x00000000) & 0xF0) == 0x20) + && ((NV_RD32(chip->PMC,0x00000000)&0x0F) >= 0x02)) { + /* + * SDRAM 128 ZX. + */ + dclk = 800000; + } else { + dclk = 1000000; + } + } else { + /* + * SGRAM 128. + */ + dclk = 1000000; + } + break; + case NV_ARCH_04: + case NV_ARCH_10: + case NV_ARCH_20: + case NV_ARCH_30: + switch ((NV_RD32(chip->PFB, 0x00000000) >> 3) & 0x00000003) { + case 3: + dclk = 800000; + break; + default: + dclk = 1000000; + break; + } + break; + } + return dclk; +} + +void +riva_common_setup(struct riva_par *par) +{ + par->riva.EnableIRQ = 0; + par->riva.PRAMDAC0 = + (volatile U032 __iomem *)(par->ctrl_base + 0x00680000); + par->riva.PFB = + (volatile U032 __iomem *)(par->ctrl_base + 0x00100000); + par->riva.PFIFO = + (volatile U032 __iomem *)(par->ctrl_base + 0x00002000); + par->riva.PGRAPH = + (volatile U032 __iomem *)(par->ctrl_base + 0x00400000); + par->riva.PEXTDEV = + (volatile U032 __iomem *)(par->ctrl_base + 0x00101000); + par->riva.PTIMER = + (volatile U032 __iomem *)(par->ctrl_base + 0x00009000); + par->riva.PMC = + (volatile U032 __iomem *)(par->ctrl_base + 0x00000000); + par->riva.FIFO = + (volatile U032 __iomem *)(par->ctrl_base + 0x00800000); + par->riva.PCIO0 = par->ctrl_base + 0x00601000; + par->riva.PDIO0 = par->ctrl_base + 0x00681000; + par->riva.PVIO = par->ctrl_base + 0x000C0000; + + par->riva.IO = (MISCin(par) & 0x01) ? 0x3D0 : 0x3B0; + + if (par->FlatPanel == -1) { + switch (par->Chipset & 0xffff) { + case 0x0112: /* known laptop chips */ + case 0x0174: + case 0x0175: + case 0x0176: + case 0x0177: + case 0x0179: + case 0x017C: + case 0x017D: + case 0x0186: + case 0x0187: + case 0x0286: + case 0x028C: + case 0x0316: + case 0x0317: + case 0x031A: + case 0x031B: + case 0x031C: + case 0x031D: + case 0x031E: + case 0x031F: + case 0x0324: + case 0x0325: + case 0x0328: + case 0x0329: + case 0x032C: + case 0x032D: + printk(KERN_INFO PFX + "On a laptop. Assuming Digital Flat Panel\n"); + par->FlatPanel = 1; + break; + default: + break; + } + } + + switch (par->Chipset & 0x0ff0) { + case 0x0110: + if (par->Chipset == NV_CHIP_GEFORCE2_GO) + par->SecondCRTC = TRUE; +#if defined(__powerpc__) + if (par->FlatPanel == 1) + par->SecondCRTC = TRUE; +#endif + riva_override_CRTC(par); + break; + case 0x0170: + case 0x0180: + case 0x01F0: + case 0x0250: + case 0x0280: + case 0x0300: + case 0x0310: + case 0x0320: + case 0x0330: + case 0x0340: + riva_is_second(par); + break; + default: + break; + } + + if (par->SecondCRTC) { + par->riva.PCIO = par->riva.PCIO0 + 0x2000; + par->riva.PCRTC = par->riva.PCRTC0 + 0x800; + par->riva.PRAMDAC = par->riva.PRAMDAC0 + 0x800; + par->riva.PDIO = par->riva.PDIO0 + 0x2000; + } else { + par->riva.PCIO = par->riva.PCIO0; + par->riva.PCRTC = par->riva.PCRTC0; + par->riva.PRAMDAC = par->riva.PRAMDAC0; + par->riva.PDIO = par->riva.PDIO0; + } + + if (par->FlatPanel == -1) { + /* Fix me, need x86 DDC code */ + par->FlatPanel = 0; + } + par->riva.flatPanel = (par->FlatPanel > 0) ? TRUE : FALSE; + + RivaGetConfig(&par->riva, par->Chipset); +} + 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/nvreg.h b/drivers/video/riva/nvreg.h new file mode 100644 index 000000000000..abfc167ae8d8 --- /dev/null +++ b/drivers/video/riva/nvreg.h @@ -0,0 +1,188 @@ +/* $XConsortium: nvreg.h /main/2 1996/10/28 05:13:41 kaleb $ */ +/* + * Copyright 1996-1997 David J. McKay + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * DAVID J. MCKAY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/nv/nvreg.h,v 3.2.2.1 1998/01/18 10:35:36 hohndel Exp $ */ + +#ifndef __NVREG_H_ +#define __NVREG_H_ + +/* Little macro to construct bitmask for contiguous ranges of bits */ +#define BITMASK(t,b) (((unsigned)(1U << (((t)-(b)+1)))-1) << (b)) +#define MASKEXPAND(mask) BITMASK(1?mask,0?mask) + +/* Macro to set specific bitfields (mask has to be a macro x:y) ! */ +#define SetBF(mask,value) ((value) << (0?mask)) +#define GetBF(var,mask) (((unsigned)((var) & MASKEXPAND(mask))) >> (0?mask) ) + +#define MaskAndSetBF(var,mask,value) (var)=(((var)&(~MASKEXPAND(mask)) \ + | SetBF(mask,value))) + +#define DEVICE_BASE(device) (0?NV##_##device) +#define DEVICE_SIZE(device) ((1?NV##_##device) - DEVICE_BASE(device)+1) + +/* This is where we will have to have conditional compilation */ +#define DEVICE_ACCESS(device,reg) \ + nvCONTROL[(NV_##device##_##reg)/4] + +#define DEVICE_WRITE(device,reg,value) DEVICE_ACCESS(device,reg)=(value) +#define DEVICE_READ(device,reg) DEVICE_ACCESS(device,reg) +#define DEVICE_PRINT(device,reg) \ + ErrorF("NV_"#device"_"#reg"=#%08lx\n",DEVICE_ACCESS(device,reg)) +#define DEVICE_DEF(device,mask,value) \ + SetBF(NV_##device##_##mask,NV_##device##_##mask##_##value) +#define DEVICE_VALUE(device,mask,value) SetBF(NV_##device##_##mask,value) +#define DEVICE_MASK(device,mask) MASKEXPAND(NV_##device##_##mask) + +#define PDAC_Write(reg,value) DEVICE_WRITE(PDAC,reg,value) +#define PDAC_Read(reg) DEVICE_READ(PDAC,reg) +#define PDAC_Print(reg) DEVICE_PRINT(PDAC,reg) +#define PDAC_Def(mask,value) DEVICE_DEF(PDAC,mask,value) +#define PDAC_Val(mask,value) DEVICE_VALUE(PDAC,mask,value) +#define PDAC_Mask(mask) DEVICE_MASK(PDAC,mask) + +#define PFB_Write(reg,value) DEVICE_WRITE(PFB,reg,value) +#define PFB_Read(reg) DEVICE_READ(PFB,reg) +#define PFB_Print(reg) DEVICE_PRINT(PFB,reg) +#define PFB_Def(mask,value) DEVICE_DEF(PFB,mask,value) +#define PFB_Val(mask,value) DEVICE_VALUE(PFB,mask,value) +#define PFB_Mask(mask) DEVICE_MASK(PFB,mask) + +#define PRM_Write(reg,value) DEVICE_WRITE(PRM,reg,value) +#define PRM_Read(reg) DEVICE_READ(PRM,reg) +#define PRM_Print(reg) DEVICE_PRINT(PRM,reg) +#define PRM_Def(mask,value) DEVICE_DEF(PRM,mask,value) +#define PRM_Val(mask,value) DEVICE_VALUE(PRM,mask,value) +#define PRM_Mask(mask) DEVICE_MASK(PRM,mask) + +#define PGRAPH_Write(reg,value) DEVICE_WRITE(PGRAPH,reg,value) +#define PGRAPH_Read(reg) DEVICE_READ(PGRAPH,reg) +#define PGRAPH_Print(reg) DEVICE_PRINT(PGRAPH,reg) +#define PGRAPH_Def(mask,value) DEVICE_DEF(PGRAPH,mask,value) +#define PGRAPH_Val(mask,value) DEVICE_VALUE(PGRAPH,mask,value) +#define PGRAPH_Mask(mask) DEVICE_MASK(PGRAPH,mask) + +#define PDMA_Write(reg,value) DEVICE_WRITE(PDMA,reg,value) +#define PDMA_Read(reg) DEVICE_READ(PDMA,reg) +#define PDMA_Print(reg) DEVICE_PRINT(PDMA,reg) +#define PDMA_Def(mask,value) DEVICE_DEF(PDMA,mask,value) +#define PDMA_Val(mask,value) DEVICE_VALUE(PDMA,mask,value) +#define PDMA_Mask(mask) DEVICE_MASK(PDMA,mask) + +#define PTIMER_Write(reg,value) DEVICE_WRITE(PTIMER,reg,value) +#define PTIMER_Read(reg) DEVICE_READ(PTIMER,reg) +#define PTIMER_Print(reg) DEVICE_PRINT(PTIMER,reg) +#define PTIMER_Def(mask,value) DEVICE_DEF(PTIMER,mask,value) +#define PTIMER_Val(mask,value) DEVICE_VALUE(PTIEMR,mask,value) +#define PTIMER_Mask(mask) DEVICE_MASK(PTIMER,mask) + +#define PEXTDEV_Write(reg,value) DEVICE_WRITE(PEXTDEV,reg,value) +#define PEXTDEV_Read(reg) DEVICE_READ(PEXTDEV,reg) +#define PEXTDEV_Print(reg) DEVICE_PRINT(PEXTDEV,reg) +#define PEXTDEV_Def(mask,value) DEVICE_DEF(PEXTDEV,mask,value) +#define PEXTDEV_Val(mask,value) DEVICE_VALUE(PEXTDEV,mask,value) +#define PEXTDEV_Mask(mask) DEVICE_MASK(PEXTDEV,mask) + +#define PFIFO_Write(reg,value) DEVICE_WRITE(PFIFO,reg,value) +#define PFIFO_Read(reg) DEVICE_READ(PFIFO,reg) +#define PFIFO_Print(reg) DEVICE_PRINT(PFIFO,reg) +#define PFIFO_Def(mask,value) DEVICE_DEF(PFIFO,mask,value) +#define PFIFO_Val(mask,value) DEVICE_VALUE(PFIFO,mask,value) +#define PFIFO_Mask(mask) DEVICE_MASK(PFIFO,mask) + +#define PRAM_Write(reg,value) DEVICE_WRITE(PRAM,reg,value) +#define PRAM_Read(reg) DEVICE_READ(PRAM,reg) +#define PRAM_Print(reg) DEVICE_PRINT(PRAM,reg) +#define PRAM_Def(mask,value) DEVICE_DEF(PRAM,mask,value) +#define PRAM_Val(mask,value) DEVICE_VALUE(PRAM,mask,value) +#define PRAM_Mask(mask) DEVICE_MASK(PRAM,mask) + +#define PRAMFC_Write(reg,value) DEVICE_WRITE(PRAMFC,reg,value) +#define PRAMFC_Read(reg) DEVICE_READ(PRAMFC,reg) +#define PRAMFC_Print(reg) DEVICE_PRINT(PRAMFC,reg) +#define PRAMFC_Def(mask,value) DEVICE_DEF(PRAMFC,mask,value) +#define PRAMFC_Val(mask,value) DEVICE_VALUE(PRAMFC,mask,value) +#define PRAMFC_Mask(mask) DEVICE_MASK(PRAMFC,mask) + +#define PMC_Write(reg,value) DEVICE_WRITE(PMC,reg,value) +#define PMC_Read(reg) DEVICE_READ(PMC,reg) +#define PMC_Print(reg) DEVICE_PRINT(PMC,reg) +#define PMC_Def(mask,value) DEVICE_DEF(PMC,mask,value) +#define PMC_Val(mask,value) DEVICE_VALUE(PMC,mask,value) +#define PMC_Mask(mask) DEVICE_MASK(PMC,mask) + +#define PMC_Write(reg,value) DEVICE_WRITE(PMC,reg,value) +#define PMC_Read(reg) DEVICE_READ(PMC,reg) +#define PMC_Print(reg) DEVICE_PRINT(PMC,reg) +#define PMC_Def(mask,value) DEVICE_DEF(PMC,mask,value) +#define PMC_Val(mask,value) DEVICE_VALUE(PMC,mask,value) +#define PMC_Mask(mask) DEVICE_MASK(PMC,mask) + + +#define PBUS_Write(reg,value) DEVICE_WRITE(PBUS,reg,value) +#define PBUS_Read(reg) DEVICE_READ(PBUS,reg) +#define PBUS_Print(reg) DEVICE_PRINT(PBUS,reg) +#define PBUS_Def(mask,value) DEVICE_DEF(PBUS,mask,value) +#define PBUS_Val(mask,value) DEVICE_VALUE(PBUS,mask,value) +#define PBUS_Mask(mask) DEVICE_MASK(PBUS,mask) + + +#define PRAMDAC_Write(reg,value) DEVICE_WRITE(PRAMDAC,reg,value) +#define PRAMDAC_Read(reg) DEVICE_READ(PRAMDAC,reg) +#define PRAMDAC_Print(reg) DEVICE_PRINT(PRAMDAC,reg) +#define PRAMDAC_Def(mask,value) DEVICE_DEF(PRAMDAC,mask,value) +#define PRAMDAC_Val(mask,value) DEVICE_VALUE(PRAMDAC,mask,value) +#define PRAMDAC_Mask(mask) DEVICE_MASK(PRAMDAC,mask) + + +#define PDAC_ReadExt(reg) \ + ((PDAC_Write(INDEX_LO,(NV_PDAC_EXT_##reg) & 0xff)),\ + (PDAC_Write(INDEX_HI,((NV_PDAC_EXT_##reg) >> 8) & 0xff)),\ + (PDAC_Read(INDEX_DATA))) + +#define PDAC_WriteExt(reg,value)\ + ((PDAC_Write(INDEX_LO,(NV_PDAC_EXT_##reg) & 0xff)),\ + (PDAC_Write(INDEX_HI,((NV_PDAC_EXT_##reg) >> 8) & 0xff)),\ + (PDAC_Write(INDEX_DATA,(value)))) + +#define CRTC_Write(index,value) outb((index), 0x3d4); outb(value, 0x3d5) +#define CRTC_Read(index) (outb(index, 0x3d4),inb(0x3d5)) + +#define PCRTC_Write(index,value) CRTC_Write(NV_PCRTC_##index,value) +#define PCRTC_Read(index) CRTC_Read(NV_PCRTC_##index) + +#define PCRTC_Def(mask,value) DEVICE_DEF(PCRTC,mask,value) +#define PCRTC_Val(mask,value) DEVICE_VALUE(PCRTC,mask,value) +#define PCRTC_Mask(mask) DEVICE_MASK(PCRTC,mask) + +#define SR_Write(index,value) outb(0x3c4,(index));outb(0x3c5,value) +#define SR_Read(index) (outb(0x3c4,index),inb(0x3c5)) + +extern volatile unsigned *nvCONTROL; + +typedef enum {NV1,NV3,NV4,NumNVChips} NVChipType; + +NVChipType GetChipType(void); + +#endif + + diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c new file mode 100644 index 000000000000..b6f8690b96c9 --- /dev/null +++ b/drivers/video/riva/riva_hw.c @@ -0,0 +1,2259 @@ + /***************************************************************************\ +|* *| +|* Copyright 1993-1999 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 1993-1999 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL licensing note -- nVidia is allowing a liberal interpretation of + * the documentation restriction above, to merely say that this nVidia's + * copyright and disclaimer should be included with all code derived + * from this source. -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.c,v 1.33 2002/08/05 20:47:06 mvojkovi Exp $ */ + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/pci_ids.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. + */ +static int nv3Busy +( + RIVA_HW_INST *chip +) +{ + return ((NV_RD32(&chip->Rop->FifoFree, 0) < chip->FifoEmptyCount) || + NV_RD32(&chip->PGRAPH[0x000006B0/4], 0) & 0x01); +} +static int nv4Busy +( + RIVA_HW_INST *chip +) +{ + return ((NV_RD32(&chip->Rop->FifoFree, 0) < chip->FifoEmptyCount) || + NV_RD32(&chip->PGRAPH[0x00000700/4], 0) & 0x01); +} +static int nv10Busy +( + RIVA_HW_INST *chip +) +{ + return ((NV_RD32(&chip->Rop->FifoFree, 0) < chip->FifoEmptyCount) || + NV_RD32(&chip->PGRAPH[0x00000700/4], 0) & 0x01); +} + +static void vgaLockUnlock +( + RIVA_HW_INST *chip, + int Lock +) +{ + 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 nv3LockUnlock +( + RIVA_HW_INST *chip, + int Lock +) +{ + VGA_WR08(chip->PVIO, 0x3C4, 0x06); + VGA_WR08(chip->PVIO, 0x3C5, Lock ? 0x99 : 0x57); + vgaLockUnlock(chip, Lock); +} +static void nv4LockUnlock +( + RIVA_HW_INST *chip, + int Lock +) +{ + VGA_WR08(chip->PCIO, 0x3D4, 0x1F); + VGA_WR08(chip->PCIO, 0x3D5, Lock ? 0x99 : 0x57); + vgaLockUnlock(chip, Lock); +} + +static int ShowHideCursor +( + RIVA_HW_INST *chip, + int ShowHide +) +{ + 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 (cursor & 0x01); +} + +/****************************************************************************\ +* * +* The video arbitration routines calculate some "magic" numbers. Fixes * +* the snow seen when accessing the framebuffer without it. * +* It just works (I hope). * +* * +\****************************************************************************/ + +#define DEFAULT_GR_LWM 100 +#define DEFAULT_VID_LWM 100 +#define DEFAULT_GR_BURST_SIZE 256 +#define DEFAULT_VID_BURST_SIZE 128 +#define VIDEO 0 +#define GRAPHICS 1 +#define MPORT 2 +#define ENGINE 3 +#define GFIFO_SIZE 320 +#define GFIFO_SIZE_128 256 +#define MFIFO_SIZE 120 +#define VFIFO_SIZE 256 + +typedef struct { + int gdrain_rate; + int vdrain_rate; + int mdrain_rate; + int gburst_size; + int vburst_size; + char vid_en; + char gr_en; + int wcmocc, wcgocc, wcvocc, wcvlwm, wcglwm; + int by_gfacc; + char vid_only_once; + char gr_only_once; + char first_vacc; + char first_gacc; + char first_macc; + int vocc; + int gocc; + int mocc; + char cur; + char engine_en; + char converged; + int priority; +} nv3_arb_info; +typedef struct { + int graphics_lwm; + int video_lwm; + int graphics_burst_size; + int video_burst_size; + int graphics_hi_priority; + int media_hi_priority; + int rtl_values; + int valid; +} nv3_fifo_info; +typedef struct { + char pix_bpp; + char enable_video; + char gr_during_vid; + char enable_mp; + int memory_width; + int video_scale; + int pclk_khz; + int mclk_khz; + int mem_page_miss; + int mem_latency; + char mem_aligned; +} nv3_sim_state; +typedef struct { + int graphics_lwm; + int video_lwm; + int graphics_burst_size; + int video_burst_size; + int valid; +} nv4_fifo_info; +typedef struct { + int pclk_khz; + int mclk_khz; + int nvclk_khz; + char mem_page_miss; + char mem_latency; + int memory_width; + char enable_video; + char gr_during_vid; + char pix_bpp; + char mem_aligned; + char enable_mp; +} nv4_sim_state; +typedef struct { + int graphics_lwm; + int video_lwm; + int graphics_burst_size; + int video_burst_size; + int valid; +} nv10_fifo_info; +typedef struct { + int pclk_khz; + int mclk_khz; + int nvclk_khz; + char mem_page_miss; + char mem_latency; + int memory_type; + int memory_width; + char enable_video; + char gr_during_vid; + char pix_bpp; + char mem_aligned; + char enable_mp; +} nv10_sim_state; +static int nv3_iterate(nv3_fifo_info *res_info, nv3_sim_state * state, nv3_arb_info *ainfo) +{ + int iter = 0; + int tmp; + int vfsize, mfsize, gfsize; + int mburst_size = 32; + int mmisses, gmisses, vmisses; + int misses; + int vlwm, glwm, mlwm; + int last, next, cur; + int max_gfsize ; + long ns; + + vlwm = 0; + glwm = 0; + mlwm = 0; + vfsize = 0; + gfsize = 0; + cur = ainfo->cur; + mmisses = 2; + gmisses = 2; + vmisses = 2; + if (ainfo->gburst_size == 128) max_gfsize = GFIFO_SIZE_128; + else max_gfsize = GFIFO_SIZE; + max_gfsize = GFIFO_SIZE; + while (1) + { + if (ainfo->vid_en) + { + if (ainfo->wcvocc > ainfo->vocc) ainfo->wcvocc = ainfo->vocc; + if (ainfo->wcvlwm > vlwm) ainfo->wcvlwm = vlwm ; + ns = 1000000 * ainfo->vburst_size/(state->memory_width/8)/state->mclk_khz; + vfsize = ns * ainfo->vdrain_rate / 1000000; + vfsize = ainfo->wcvlwm - ainfo->vburst_size + vfsize; + } + if (state->enable_mp) + { + if (ainfo->wcmocc > ainfo->mocc) ainfo->wcmocc = ainfo->mocc; + } + if (ainfo->gr_en) + { + if (ainfo->wcglwm > glwm) ainfo->wcglwm = glwm ; + if (ainfo->wcgocc > ainfo->gocc) ainfo->wcgocc = ainfo->gocc; + ns = 1000000 * (ainfo->gburst_size/(state->memory_width/8))/state->mclk_khz; + gfsize = (ns * (long) ainfo->gdrain_rate)/1000000; + gfsize = ainfo->wcglwm - ainfo->gburst_size + gfsize; + } + mfsize = 0; + if (!state->gr_during_vid && ainfo->vid_en) + if (ainfo->vid_en && (ainfo->vocc < 0) && !ainfo->vid_only_once) + next = VIDEO; + else if (ainfo->mocc < 0) + next = MPORT; + else if (ainfo->gocc< ainfo->by_gfacc) + next = GRAPHICS; + else return (0); + else switch (ainfo->priority) + { + case VIDEO: + if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once) + next = VIDEO; + else if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once) + next = GRAPHICS; + else if (ainfo->mocc<0) + next = MPORT; + else return (0); + break; + case GRAPHICS: + if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once) + next = GRAPHICS; + else if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once) + next = VIDEO; + else if (ainfo->mocc<0) + next = MPORT; + else return (0); + break; + default: + if (ainfo->mocc<0) + next = MPORT; + else if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once) + next = GRAPHICS; + else if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once) + next = VIDEO; + else return (0); + break; + } + last = cur; + cur = next; + iter++; + switch (cur) + { + case VIDEO: + if (last==cur) misses = 0; + else if (ainfo->first_vacc) misses = vmisses; + else misses = 1; + ainfo->first_vacc = 0; + if (last!=cur) + { + ns = 1000000 * (vmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz; + vlwm = ns * ainfo->vdrain_rate/ 1000000; + vlwm = ainfo->vocc - vlwm; + } + ns = 1000000*(misses*state->mem_page_miss + ainfo->vburst_size)/(state->memory_width/8)/state->mclk_khz; + ainfo->vocc = ainfo->vocc + ainfo->vburst_size - ns*ainfo->vdrain_rate/1000000; + ainfo->gocc = ainfo->gocc - ns*ainfo->gdrain_rate/1000000; + ainfo->mocc = ainfo->mocc - ns*ainfo->mdrain_rate/1000000; + break; + case GRAPHICS: + if (last==cur) misses = 0; + else if (ainfo->first_gacc) misses = gmisses; + else misses = 1; + ainfo->first_gacc = 0; + if (last!=cur) + { + ns = 1000000*(gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz ; + glwm = ns * ainfo->gdrain_rate/1000000; + glwm = ainfo->gocc - glwm; + } + ns = 1000000*(misses*state->mem_page_miss + ainfo->gburst_size/(state->memory_width/8))/state->mclk_khz; + ainfo->vocc = ainfo->vocc + 0 - ns*ainfo->vdrain_rate/1000000; + ainfo->gocc = ainfo->gocc + ainfo->gburst_size - ns*ainfo->gdrain_rate/1000000; + ainfo->mocc = ainfo->mocc + 0 - ns*ainfo->mdrain_rate/1000000; + break; + default: + if (last==cur) misses = 0; + else if (ainfo->first_macc) misses = mmisses; + else misses = 1; + ainfo->first_macc = 0; + ns = 1000000*(misses*state->mem_page_miss + mburst_size/(state->memory_width/8))/state->mclk_khz; + ainfo->vocc = ainfo->vocc + 0 - ns*ainfo->vdrain_rate/1000000; + ainfo->gocc = ainfo->gocc + 0 - ns*ainfo->gdrain_rate/1000000; + ainfo->mocc = ainfo->mocc + mburst_size - ns*ainfo->mdrain_rate/1000000; + break; + } + if (iter>100) + { + ainfo->converged = 0; + return (1); + } + ns = 1000000*ainfo->gburst_size/(state->memory_width/8)/state->mclk_khz; + tmp = ns * ainfo->gdrain_rate/1000000; + if (abs(ainfo->gburst_size) + ((abs(ainfo->wcglwm) + 16 ) & ~0x7) - tmp > max_gfsize) + { + ainfo->converged = 0; + return (1); + } + ns = 1000000*ainfo->vburst_size/(state->memory_width/8)/state->mclk_khz; + tmp = ns * ainfo->vdrain_rate/1000000; + if (abs(ainfo->vburst_size) + (abs(ainfo->wcvlwm + 32) & ~0xf) - tmp> VFIFO_SIZE) + { + ainfo->converged = 0; + return (1); + } + if (abs(ainfo->gocc) > max_gfsize) + { + ainfo->converged = 0; + return (1); + } + if (abs(ainfo->vocc) > VFIFO_SIZE) + { + ainfo->converged = 0; + return (1); + } + if (abs(ainfo->mocc) > MFIFO_SIZE) + { + ainfo->converged = 0; + return (1); + } + if (abs(vfsize) > VFIFO_SIZE) + { + ainfo->converged = 0; + return (1); + } + if (abs(gfsize) > max_gfsize) + { + ainfo->converged = 0; + return (1); + } + if (abs(mfsize) > MFIFO_SIZE) + { + ainfo->converged = 0; + return (1); + } + } +} +static char nv3_arb(nv3_fifo_info * res_info, nv3_sim_state * state, nv3_arb_info *ainfo) +{ + long ens, vns, mns, gns; + int mmisses, gmisses, vmisses, eburst_size, mburst_size; + int refresh_cycle; + + refresh_cycle = 0; + refresh_cycle = 2*(state->mclk_khz/state->pclk_khz) + 5; + mmisses = 2; + if (state->mem_aligned) gmisses = 2; + else gmisses = 3; + vmisses = 2; + eburst_size = state->memory_width * 1; + mburst_size = 32; + gns = 1000000 * (gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz; + ainfo->by_gfacc = gns*ainfo->gdrain_rate/1000000; + ainfo->wcmocc = 0; + ainfo->wcgocc = 0; + ainfo->wcvocc = 0; + ainfo->wcvlwm = 0; + ainfo->wcglwm = 0; + ainfo->engine_en = 1; + ainfo->converged = 1; + if (ainfo->engine_en) + { + ens = 1000000*(state->mem_page_miss + eburst_size/(state->memory_width/8) +refresh_cycle)/state->mclk_khz; + ainfo->mocc = state->enable_mp ? 0-ens*ainfo->mdrain_rate/1000000 : 0; + ainfo->vocc = ainfo->vid_en ? 0-ens*ainfo->vdrain_rate/1000000 : 0; + ainfo->gocc = ainfo->gr_en ? 0-ens*ainfo->gdrain_rate/1000000 : 0; + ainfo->cur = ENGINE; + ainfo->first_vacc = 1; + ainfo->first_gacc = 1; + ainfo->first_macc = 1; + nv3_iterate(res_info, state,ainfo); + } + if (state->enable_mp) + { + mns = 1000000 * (mmisses*state->mem_page_miss + mburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz; + ainfo->mocc = state->enable_mp ? 0 : mburst_size - mns*ainfo->mdrain_rate/1000000; + ainfo->vocc = ainfo->vid_en ? 0 : 0- mns*ainfo->vdrain_rate/1000000; + ainfo->gocc = ainfo->gr_en ? 0: 0- mns*ainfo->gdrain_rate/1000000; + ainfo->cur = MPORT; + ainfo->first_vacc = 1; + ainfo->first_gacc = 1; + ainfo->first_macc = 0; + nv3_iterate(res_info, state,ainfo); + } + if (ainfo->gr_en) + { + ainfo->first_vacc = 1; + ainfo->first_gacc = 0; + ainfo->first_macc = 1; + gns = 1000000*(gmisses*state->mem_page_miss + ainfo->gburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz; + ainfo->gocc = ainfo->gburst_size - gns*ainfo->gdrain_rate/1000000; + ainfo->vocc = ainfo->vid_en? 0-gns*ainfo->vdrain_rate/1000000 : 0; + ainfo->mocc = state->enable_mp ? 0-gns*ainfo->mdrain_rate/1000000: 0; + ainfo->cur = GRAPHICS; + nv3_iterate(res_info, state,ainfo); + } + if (ainfo->vid_en) + { + ainfo->first_vacc = 0; + ainfo->first_gacc = 1; + ainfo->first_macc = 1; + vns = 1000000*(vmisses*state->mem_page_miss + ainfo->vburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz; + ainfo->vocc = ainfo->vburst_size - vns*ainfo->vdrain_rate/1000000; + ainfo->gocc = ainfo->gr_en? (0-vns*ainfo->gdrain_rate/1000000) : 0; + ainfo->mocc = state->enable_mp? 0-vns*ainfo->mdrain_rate/1000000 :0 ; + ainfo->cur = VIDEO; + nv3_iterate(res_info, state, ainfo); + } + if (ainfo->converged) + { + res_info->graphics_lwm = (int)abs(ainfo->wcglwm) + 16; + res_info->video_lwm = (int)abs(ainfo->wcvlwm) + 32; + res_info->graphics_burst_size = ainfo->gburst_size; + res_info->video_burst_size = ainfo->vburst_size; + res_info->graphics_hi_priority = (ainfo->priority == GRAPHICS); + res_info->media_hi_priority = (ainfo->priority == MPORT); + if (res_info->video_lwm > 160) + { + res_info->graphics_lwm = 256; + res_info->video_lwm = 128; + res_info->graphics_burst_size = 64; + res_info->video_burst_size = 64; + res_info->graphics_hi_priority = 0; + res_info->media_hi_priority = 0; + ainfo->converged = 0; + return (0); + } + if (res_info->video_lwm > 128) + { + res_info->video_lwm = 128; + } + return (1); + } + else + { + res_info->graphics_lwm = 256; + res_info->video_lwm = 128; + res_info->graphics_burst_size = 64; + res_info->video_burst_size = 64; + res_info->graphics_hi_priority = 0; + res_info->media_hi_priority = 0; + return (0); + } +} +static char nv3_get_param(nv3_fifo_info *res_info, nv3_sim_state * state, nv3_arb_info *ainfo) +{ + int done, g,v, p; + + done = 0; + for (p=0; p < 2; p++) + { + for (g=128 ; g > 32; g= g>> 1) + { + for (v=128; v >=32; v = v>> 1) + { + ainfo->priority = p; + ainfo->gburst_size = g; + ainfo->vburst_size = v; + done = nv3_arb(res_info, state,ainfo); + if (done && (g==128)) + if ((res_info->graphics_lwm + g) > 256) + done = 0; + if (done) + goto Done; + } + } + } + + Done: + return done; +} +static void nv3CalcArbitration +( + nv3_fifo_info * res_info, + nv3_sim_state * state +) +{ + nv3_fifo_info save_info; + nv3_arb_info ainfo; + char res_gr, res_vid; + + ainfo.gr_en = 1; + ainfo.vid_en = state->enable_video; + ainfo.vid_only_once = 0; + ainfo.gr_only_once = 0; + ainfo.gdrain_rate = (int) state->pclk_khz * (state->pix_bpp/8); + ainfo.vdrain_rate = (int) state->pclk_khz * 2; + if (state->video_scale != 0) + ainfo.vdrain_rate = ainfo.vdrain_rate/state->video_scale; + ainfo.mdrain_rate = 33000; + res_info->rtl_values = 0; + if (!state->gr_during_vid && state->enable_video) + { + ainfo.gr_only_once = 1; + ainfo.gr_en = 1; + ainfo.gdrain_rate = 0; + res_vid = nv3_get_param(res_info, state, &ainfo); + res_vid = ainfo.converged; + save_info.video_lwm = res_info->video_lwm; + save_info.video_burst_size = res_info->video_burst_size; + ainfo.vid_en = 1; + ainfo.vid_only_once = 1; + ainfo.gr_en = 1; + ainfo.gdrain_rate = (int) state->pclk_khz * (state->pix_bpp/8); + ainfo.vdrain_rate = 0; + res_gr = nv3_get_param(res_info, state, &ainfo); + res_gr = ainfo.converged; + res_info->video_lwm = save_info.video_lwm; + res_info->video_burst_size = save_info.video_burst_size; + res_info->valid = res_gr & res_vid; + } + else + { + if (!ainfo.gr_en) ainfo.gdrain_rate = 0; + if (!ainfo.vid_en) ainfo.vdrain_rate = 0; + res_gr = nv3_get_param(res_info, state, &ainfo); + res_info->valid = ainfo.converged; + } +} +static void nv3UpdateArbitrationSettings +( + unsigned VClk, + unsigned pixelDepth, + unsigned *burst, + unsigned *lwm, + RIVA_HW_INST *chip +) +{ + nv3_fifo_info fifo_data; + nv3_sim_state sim_data; + unsigned int M, N, P, pll, MClk; + + pll = NV_RD32(&chip->PRAMDAC0[0x00000504/4], 0); + M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; + MClk = (N * chip->CrystalFreqKHz / M) >> P; + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 0; + sim_data.enable_mp = 0; + sim_data.video_scale = 1; + sim_data.memory_width = (NV_RD32(&chip->PEXTDEV[0x00000000/4], 0) & 0x10) ? + 128 : 64; + sim_data.memory_width = 128; + + sim_data.mem_latency = 9; + sim_data.mem_aligned = 1; + sim_data.mem_page_miss = 11; + sim_data.gr_during_vid = 0; + sim_data.pclk_khz = VClk; + sim_data.mclk_khz = MClk; + nv3CalcArbitration(&fifo_data, &sim_data); + if (fifo_data.valid) + { + int b = fifo_data.graphics_burst_size >> 4; + *burst = 0; + while (b >>= 1) + (*burst)++; + *lwm = fifo_data.graphics_lwm >> 3; + } + else + { + *lwm = 0x24; + *burst = 0x2; + } +} +static void nv4CalcArbitration +( + nv4_fifo_info *fifo, + nv4_sim_state *arb +) +{ + int data, pagemiss, cas,width, video_enable, color_key_enable, bpp, align; + int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs; + int found, mclk_extra, mclk_loop, cbs, m1, p1; + int mclk_freq, pclk_freq, nvclk_freq, mp_enable; + int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate; + int vpm_us, us_video, vlwm, video_fill_us, cpm_us, us_crt,clwm; + int craw, vraw; + + fifo->valid = 1; + pclk_freq = arb->pclk_khz; + mclk_freq = arb->mclk_khz; + nvclk_freq = arb->nvclk_khz; + pagemiss = arb->mem_page_miss; + cas = arb->mem_latency; + width = arb->memory_width >> 6; + video_enable = arb->enable_video; + color_key_enable = arb->gr_during_vid; + bpp = arb->pix_bpp; + align = arb->mem_aligned; + mp_enable = arb->enable_mp; + clwm = 0; + vlwm = 0; + cbs = 128; + pclks = 2; + nvclks = 2; + nvclks += 2; + nvclks += 1; + mclks = 5; + mclks += 3; + mclks += 1; + mclks += cas; + mclks += 1; + mclks += 1; + mclks += 1; + mclks += 1; + mclk_extra = 3; + nvclks += 2; + nvclks += 1; + nvclks += 1; + nvclks += 1; + if (mp_enable) + mclks+=4; + nvclks += 0; + pclks += 0; + found = 0; + vbs = 0; + while (found != 1) + { + fifo->valid = 1; + found = 1; + mclk_loop = mclks+mclk_extra; + us_m = mclk_loop *1000*1000 / mclk_freq; + us_n = nvclks*1000*1000 / nvclk_freq; + us_p = nvclks*1000*1000 / pclk_freq; + if (video_enable) + { + video_drain_rate = pclk_freq * 2; + crtc_drain_rate = pclk_freq * bpp/8; + vpagemiss = 2; + vpagemiss += 1; + crtpagemiss = 2; + vpm_us = (vpagemiss * pagemiss)*1000*1000/mclk_freq; + if (nvclk_freq * 2 > mclk_freq * width) + video_fill_us = cbs*1000*1000 / 16 / nvclk_freq ; + else + video_fill_us = cbs*1000*1000 / (8 * width) / mclk_freq; + us_video = vpm_us + us_m + us_n + us_p + video_fill_us; + vlwm = us_video * video_drain_rate/(1000*1000); + vlwm++; + vbs = 128; + if (vlwm > 128) vbs = 64; + if (vlwm > (256-64)) vbs = 32; + if (nvclk_freq * 2 > mclk_freq * width) + video_fill_us = vbs *1000*1000/ 16 / nvclk_freq ; + else + video_fill_us = vbs*1000*1000 / (8 * width) / mclk_freq; + cpm_us = crtpagemiss * pagemiss *1000*1000/ mclk_freq; + us_crt = + us_video + +video_fill_us + +cpm_us + +us_m + us_n +us_p + ; + clwm = us_crt * crtc_drain_rate/(1000*1000); + clwm++; + } + else + { + crtc_drain_rate = pclk_freq * bpp/8; + crtpagemiss = 2; + crtpagemiss += 1; + cpm_us = crtpagemiss * pagemiss *1000*1000/ mclk_freq; + us_crt = cpm_us + us_m + us_n + us_p ; + clwm = us_crt * crtc_drain_rate/(1000*1000); + clwm++; + } + m1 = clwm + cbs - 512; + p1 = m1 * pclk_freq / mclk_freq; + p1 = p1 * bpp / 8; + if ((p1 < m1) && (m1 > 0)) + { + fifo->valid = 0; + found = 0; + if (mclk_extra ==0) found = 1; + mclk_extra--; + } + else if (video_enable) + { + if ((clwm > 511) || (vlwm > 255)) + { + fifo->valid = 0; + found = 0; + if (mclk_extra ==0) found = 1; + mclk_extra--; + } + } + else + { + if (clwm > 519) + { + fifo->valid = 0; + found = 0; + if (mclk_extra ==0) found = 1; + mclk_extra--; + } + } + craw = clwm; + vraw = vlwm; + if (clwm < 384) clwm = 384; + if (vlwm < 128) vlwm = 128; + data = (int)(clwm); + fifo->graphics_lwm = data; + fifo->graphics_burst_size = 128; + data = (int)((vlwm+15)); + fifo->video_lwm = data; + fifo->video_burst_size = vbs; + } +} +static void nv4UpdateArbitrationSettings +( + unsigned VClk, + unsigned pixelDepth, + unsigned *burst, + unsigned *lwm, + RIVA_HW_INST *chip +) +{ + nv4_fifo_info fifo_data; + nv4_sim_state sim_data; + unsigned int M, N, P, pll, MClk, NVClk, cfg1; + + pll = NV_RD32(&chip->PRAMDAC0[0x00000504/4], 0); + M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; + MClk = (N * chip->CrystalFreqKHz / M) >> P; + pll = NV_RD32(&chip->PRAMDAC0[0x00000500/4], 0); + M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; + NVClk = (N * chip->CrystalFreqKHz / M) >> P; + cfg1 = NV_RD32(&chip->PFB[0x00000204/4], 0); + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 0; + sim_data.enable_mp = 0; + sim_data.memory_width = (NV_RD32(&chip->PEXTDEV[0x00000000/4], 0) & 0x10) ? + 128 : 64; + sim_data.mem_latency = (char)cfg1 & 0x0F; + sim_data.mem_aligned = 1; + sim_data.mem_page_miss = (char)(((cfg1 >> 4) &0x0F) + ((cfg1 >> 31) & 0x01)); + sim_data.gr_during_vid = 0; + sim_data.pclk_khz = VClk; + sim_data.mclk_khz = MClk; + sim_data.nvclk_khz = NVClk; + nv4CalcArbitration(&fifo_data, &sim_data); + if (fifo_data.valid) + { + int b = fifo_data.graphics_burst_size >> 4; + *burst = 0; + while (b >>= 1) + (*burst)++; + *lwm = fifo_data.graphics_lwm >> 3; + } +} +static void nv10CalcArbitration +( + nv10_fifo_info *fifo, + nv10_sim_state *arb +) +{ + int data, pagemiss, cas,width, video_enable, color_key_enable, bpp, align; + int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs; + int nvclk_fill, us_extra; + int found, mclk_extra, mclk_loop, cbs, m1; + int mclk_freq, pclk_freq, nvclk_freq, mp_enable; + int us_m, us_m_min, us_n, us_p, video_drain_rate, crtc_drain_rate; + int vus_m, vus_n, vus_p; + int vpm_us, us_video, vlwm, cpm_us, us_crt,clwm; + int clwm_rnd_down; + int craw, m2us, us_pipe, us_pipe_min, vus_pipe, p1clk, p2; + int pclks_2_top_fifo, min_mclk_extra; + int us_min_mclk_extra; + + fifo->valid = 1; + pclk_freq = arb->pclk_khz; /* freq in KHz */ + mclk_freq = arb->mclk_khz; + nvclk_freq = arb->nvclk_khz; + pagemiss = arb->mem_page_miss; + cas = arb->mem_latency; + width = arb->memory_width/64; + video_enable = arb->enable_video; + color_key_enable = arb->gr_during_vid; + bpp = arb->pix_bpp; + align = arb->mem_aligned; + mp_enable = arb->enable_mp; + clwm = 0; + vlwm = 1024; + + cbs = 512; + vbs = 512; + + pclks = 4; /* lwm detect. */ + + nvclks = 3; /* lwm -> sync. */ + nvclks += 2; /* fbi bus cycles (1 req + 1 busy) */ + + mclks = 1; /* 2 edge sync. may be very close to edge so just put one. */ + + mclks += 1; /* arb_hp_req */ + mclks += 5; /* ap_hp_req tiling pipeline */ + + mclks += 2; /* tc_req latency fifo */ + mclks += 2; /* fb_cas_n_ memory request to fbio block */ + mclks += 7; /* sm_d_rdv data returned from fbio block */ + + /* fb.rd.d.Put_gc need to accumulate 256 bits for read */ + if (arb->memory_type == 0) + if (arb->memory_width == 64) /* 64 bit bus */ + mclks += 4; + else + mclks += 2; + else + if (arb->memory_width == 64) /* 64 bit bus */ + mclks += 2; + else + mclks += 1; + + if ((!video_enable) && (arb->memory_width == 128)) + { + mclk_extra = (bpp == 32) ? 31 : 42; /* Margin of error */ + min_mclk_extra = 17; + } + else + { + mclk_extra = (bpp == 32) ? 8 : 4; /* Margin of error */ + /* mclk_extra = 4; */ /* Margin of error */ + min_mclk_extra = 18; + } + + nvclks += 1; /* 2 edge sync. may be very close to edge so just put one. */ + nvclks += 1; /* fbi_d_rdv_n */ + nvclks += 1; /* Fbi_d_rdata */ + nvclks += 1; /* crtfifo load */ + + if(mp_enable) + mclks+=4; /* Mp can get in with a burst of 8. */ + /* Extra clocks determined by heuristics */ + + nvclks += 0; + pclks += 0; + found = 0; + while(found != 1) { + fifo->valid = 1; + found = 1; + mclk_loop = mclks+mclk_extra; + us_m = mclk_loop *1000*1000 / mclk_freq; /* Mclk latency in us */ + us_m_min = mclks * 1000*1000 / mclk_freq; /* Minimum Mclk latency in us */ + us_min_mclk_extra = min_mclk_extra *1000*1000 / mclk_freq; + us_n = nvclks*1000*1000 / nvclk_freq;/* nvclk latency in us */ + us_p = pclks*1000*1000 / pclk_freq;/* nvclk latency in us */ + us_pipe = us_m + us_n + us_p; + us_pipe_min = us_m_min + us_n + us_p; + us_extra = 0; + + vus_m = mclk_loop *1000*1000 / mclk_freq; /* Mclk latency in us */ + vus_n = (4)*1000*1000 / nvclk_freq;/* nvclk latency in us */ + vus_p = 0*1000*1000 / pclk_freq;/* pclk latency in us */ + vus_pipe = vus_m + vus_n + vus_p; + + if(video_enable) { + video_drain_rate = pclk_freq * 4; /* MB/s */ + crtc_drain_rate = pclk_freq * bpp/8; /* MB/s */ + + vpagemiss = 1; /* self generating page miss */ + vpagemiss += 1; /* One higher priority before */ + + crtpagemiss = 2; /* self generating page miss */ + if(mp_enable) + crtpagemiss += 1; /* if MA0 conflict */ + + vpm_us = (vpagemiss * pagemiss)*1000*1000/mclk_freq; + + us_video = vpm_us + vus_m; /* Video has separate read return path */ + + cpm_us = crtpagemiss * pagemiss *1000*1000/ mclk_freq; + us_crt = + us_video /* Wait for video */ + +cpm_us /* CRT Page miss */ + +us_m + us_n +us_p /* other latency */ + ; + + clwm = us_crt * crtc_drain_rate/(1000*1000); + clwm++; /* fixed point <= float_point - 1. Fixes that */ + } else { + crtc_drain_rate = pclk_freq * bpp/8; /* bpp * pclk/8 */ + + crtpagemiss = 1; /* self generating page miss */ + crtpagemiss += 1; /* MA0 page miss */ + if(mp_enable) + crtpagemiss += 1; /* if MA0 conflict */ + cpm_us = crtpagemiss * pagemiss *1000*1000/ mclk_freq; + us_crt = cpm_us + us_m + us_n + us_p ; + clwm = us_crt * crtc_drain_rate/(1000*1000); + clwm++; /* fixed point <= float_point - 1. Fixes that */ + + /* + // + // Another concern, only for high pclks so don't do this + // with video: + // What happens if the latency to fetch the cbs is so large that + // fifo empties. In that case we need to have an alternate clwm value + // based off the total burst fetch + // + us_crt = (cbs * 1000 * 1000)/ (8*width)/mclk_freq ; + us_crt = us_crt + us_m + us_n + us_p + (4 * 1000 * 1000)/mclk_freq; + clwm_mt = us_crt * crtc_drain_rate/(1000*1000); + clwm_mt ++; + if(clwm_mt > clwm) + clwm = clwm_mt; + */ + /* Finally, a heuristic check when width == 64 bits */ + if(width == 1){ + nvclk_fill = nvclk_freq * 8; + if(crtc_drain_rate * 100 >= nvclk_fill * 102) + clwm = 0xfff; /*Large number to fail */ + + else if(crtc_drain_rate * 100 >= nvclk_fill * 98) { + clwm = 1024; + cbs = 512; + us_extra = (cbs * 1000 * 1000)/ (8*width)/mclk_freq ; + } + } + } + + + /* + Overfill check: + + */ + + clwm_rnd_down = ((int)clwm/8)*8; + if (clwm_rnd_down < clwm) + clwm += 8; + + m1 = clwm + cbs - 1024; /* Amount of overfill */ + m2us = us_pipe_min + us_min_mclk_extra; + pclks_2_top_fifo = (1024-clwm)/(8*width); + + /* pclk cycles to drain */ + p1clk = m2us * pclk_freq/(1000*1000); + p2 = p1clk * bpp / 8; /* bytes drained. */ + + if((p2 < m1) && (m1 > 0)) { + fifo->valid = 0; + found = 0; + if(min_mclk_extra == 0) { + if(cbs <= 32) { + found = 1; /* Can't adjust anymore! */ + } else { + cbs = cbs/2; /* reduce the burst size */ + } + } else { + min_mclk_extra--; + } + } else { + if (clwm > 1023){ /* Have some margin */ + fifo->valid = 0; + found = 0; + if(min_mclk_extra == 0) + found = 1; /* Can't adjust anymore! */ + else + min_mclk_extra--; + } + } + craw = clwm; + + if(clwm < (1024-cbs+8)) clwm = 1024-cbs+8; + data = (int)(clwm); + /* printf("CRT LWM: %f bytes, prog: 0x%x, bs: 256\n", clwm, data ); */ + fifo->graphics_lwm = data; fifo->graphics_burst_size = cbs; + + /* printf("VID LWM: %f bytes, prog: 0x%x, bs: %d\n, ", vlwm, data, vbs ); */ + fifo->video_lwm = 1024; fifo->video_burst_size = 512; + } +} +static void nv10UpdateArbitrationSettings +( + unsigned VClk, + unsigned pixelDepth, + unsigned *burst, + unsigned *lwm, + RIVA_HW_INST *chip +) +{ + nv10_fifo_info fifo_data; + nv10_sim_state sim_data; + unsigned int M, N, P, pll, MClk, NVClk, cfg1; + + pll = NV_RD32(&chip->PRAMDAC0[0x00000504/4], 0); + M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; + MClk = (N * chip->CrystalFreqKHz / M) >> P; + pll = NV_RD32(&chip->PRAMDAC0[0x00000500/4], 0); + M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; + NVClk = (N * chip->CrystalFreqKHz / M) >> P; + cfg1 = NV_RD32(&chip->PFB[0x00000204/4], 0); + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 0; + sim_data.enable_mp = 0; + sim_data.memory_type = (NV_RD32(&chip->PFB[0x00000200/4], 0) & 0x01) ? + 1 : 0; + sim_data.memory_width = (NV_RD32(&chip->PEXTDEV[0x00000000/4], 0) & 0x10) ? + 128 : 64; + sim_data.mem_latency = (char)cfg1 & 0x0F; + sim_data.mem_aligned = 1; + sim_data.mem_page_miss = (char)(((cfg1 >> 4) &0x0F) + ((cfg1 >> 31) & 0x01)); + sim_data.gr_during_vid = 0; + sim_data.pclk_khz = VClk; + sim_data.mclk_khz = MClk; + sim_data.nvclk_khz = NVClk; + nv10CalcArbitration(&fifo_data, &sim_data); + if (fifo_data.valid) + { + int b = fifo_data.graphics_burst_size >> 4; + *burst = 0; + while (b >>= 1) + (*burst)++; + *lwm = fifo_data.graphics_lwm >> 3; + } +} + +static void nForceUpdateArbitrationSettings +( + unsigned VClk, + unsigned pixelDepth, + unsigned *burst, + unsigned *lwm, + RIVA_HW_INST *chip +) +{ + nv10_fifo_info fifo_data; + nv10_sim_state sim_data; + unsigned int M, N, P, pll, MClk, NVClk; + unsigned int uMClkPostDiv; + struct pci_dev *dev; + + dev = pci_find_slot(0, 3); + pci_read_config_dword(dev, 0x6C, &uMClkPostDiv); + uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf; + + if(!uMClkPostDiv) uMClkPostDiv = 4; + MClk = 400000 / uMClkPostDiv; + + pll = NV_RD32(&chip->PRAMDAC0[0x00000500/4], 0); + M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; + NVClk = (N * chip->CrystalFreqKHz / M) >> P; + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 0; + sim_data.enable_mp = 0; + + dev = pci_find_slot(0, 1); + pci_read_config_dword(dev, 0x7C, &sim_data.memory_type); + sim_data.memory_type = (sim_data.memory_type >> 12) & 1; + + sim_data.memory_width = 64; + sim_data.mem_latency = 3; + sim_data.mem_aligned = 1; + sim_data.mem_page_miss = 10; + sim_data.gr_during_vid = 0; + sim_data.pclk_khz = VClk; + sim_data.mclk_khz = MClk; + sim_data.nvclk_khz = NVClk; + nv10CalcArbitration(&fifo_data, &sim_data); + if (fifo_data.valid) + { + int b = fifo_data.graphics_burst_size >> 4; + *burst = 0; + while (b >>= 1) + (*burst)++; + *lwm = fifo_data.graphics_lwm >> 3; + } +} + +/****************************************************************************\ +* * +* RIVA Mode State Routines * +* * +\****************************************************************************/ + +/* + * Calculate the Video Clock parameters for the PLL. + */ +static int CalcVClock +( + int clockIn, + int *clockOut, + int *mOut, + int *nOut, + int *pOut, + RIVA_HW_INST *chip +) +{ + unsigned lowM, highM, highP; + unsigned DeltaNew, DeltaOld; + unsigned VClk, Freq; + unsigned M, N, P; + + DeltaOld = 0xFFFFFFFF; + + VClk = (unsigned)clockIn; + + if (chip->CrystalFreqKHz == 13500) + { + lowM = 7; + highM = 13 - (chip->Architecture == NV_ARCH_03); + } + else + { + lowM = 8; + highM = 14 - (chip->Architecture == NV_ARCH_03); + } + + highP = 4 - (chip->Architecture == NV_ARCH_03); + for (P = 0; P <= highP; P ++) + { + Freq = VClk << P; + if ((Freq >= 128000) && (Freq <= chip->MaxVClockFreqKHz)) + { + for (M = lowM; M <= highM; M++) + { + N = (VClk << P) * M / chip->CrystalFreqKHz; + if(N <= 255) { + Freq = (chip->CrystalFreqKHz * N / M) >> P; + if (Freq > VClk) + DeltaNew = Freq - VClk; + else + DeltaNew = VClk - Freq; + if (DeltaNew < DeltaOld) + { + *mOut = M; + *nOut = N; + *pOut = P; + *clockOut = Freq; + DeltaOld = DeltaNew; + } + } + } + } + } + return (DeltaOld != 0xFFFFFFFF); +} +/* + * Calculate extended mode parameters (SVGA) and save in a + * mode state structure. + */ +static void CalcStateExt +( + RIVA_HW_INST *chip, + RIVA_HW_STATE *state, + int bpp, + int width, + int hDisplaySize, + int height, + int dotClock +) +{ + int pixelDepth, VClk, m, n, p; + /* + * Save mode parameters. + */ + state->bpp = bpp; /* this is not bitsPerPixel, it's 8,15,16,32 */ + state->width = width; + state->height = height; + /* + * Extended RIVA registers. + */ + pixelDepth = (bpp + 1)/8; + CalcVClock(dotClock, &VClk, &m, &n, &p, chip); + + switch (chip->Architecture) + { + case NV_ARCH_03: + nv3UpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), + chip); + state->cursor0 = 0x00; + state->cursor1 = 0x78; + state->cursor2 = 0x00000000; + state->pllsel = 0x10010100; + state->config = ((width + 31)/32) + | (((pixelDepth > 2) ? 3 : pixelDepth) << 8) + | 0x1000; + state->general = 0x00100100; + state->repaint1 = hDisplaySize < 1280 ? 0x06 : 0x02; + break; + case NV_ARCH_04: + nv4UpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), + chip); + state->cursor0 = 0x00; + state->cursor1 = 0xFC; + state->cursor2 = 0x00000000; + state->pllsel = 0x10000700; + state->config = 0x00001114; + state->general = bpp == 16 ? 0x00101100 : 0x00100100; + state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; + break; + case NV_ARCH_10: + case NV_ARCH_20: + case NV_ARCH_30: + if((chip->Chipset == NV_CHIP_IGEFORCE2) || + (chip->Chipset == NV_CHIP_0x01F0)) + { + nForceUpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), + chip); + } else { + nv10UpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), + chip); + } + state->cursor0 = 0x80 | (chip->CursorStart >> 17); + state->cursor1 = (chip->CursorStart >> 11) << 2; + state->cursor2 = chip->CursorStart >> 24; + state->pllsel = 0x10000700; + state->config = NV_RD32(&chip->PFB[0x00000200/4], 0); + state->general = bpp == 16 ? 0x00101100 : 0x00100100; + state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; + break; + } + + /* Paul Richards: below if block borks things in kernel for some reason */ + /* Tony: Below is needed to set hardware in DirectColor */ + if((bpp != 8) && (chip->Architecture != NV_ARCH_03)) + state->general |= 0x00000030; + + state->vpll = (p << 16) | (n << 8) | m; + state->repaint0 = (((width/8)*pixelDepth) & 0x700) >> 3; + state->pixel = pixelDepth > 2 ? 3 : pixelDepth; + state->offset0 = + state->offset1 = + state->offset2 = + state->offset3 = 0; + state->pitch0 = + state->pitch1 = + state->pitch2 = + state->pitch3 = pixelDepth * width; +} +/* + * Load fixed function state and pre-calculated/stored state. + */ +#if 0 +#define LOAD_FIXED_STATE(tbl,dev) \ + for (i = 0; i < sizeof(tbl##Table##dev)/8; i++) \ + chip->dev[tbl##Table##dev[i][0]] = tbl##Table##dev[i][1] +#define LOAD_FIXED_STATE_8BPP(tbl,dev) \ + for (i = 0; i < sizeof(tbl##Table##dev##_8BPP)/8; i++) \ + chip->dev[tbl##Table##dev##_8BPP[i][0]] = tbl##Table##dev##_8BPP[i][1] +#define LOAD_FIXED_STATE_15BPP(tbl,dev) \ + for (i = 0; i < sizeof(tbl##Table##dev##_15BPP)/8; i++) \ + chip->dev[tbl##Table##dev##_15BPP[i][0]] = tbl##Table##dev##_15BPP[i][1] +#define LOAD_FIXED_STATE_16BPP(tbl,dev) \ + for (i = 0; i < sizeof(tbl##Table##dev##_16BPP)/8; i++) \ + chip->dev[tbl##Table##dev##_16BPP[i][0]] = tbl##Table##dev##_16BPP[i][1] +#define LOAD_FIXED_STATE_32BPP(tbl,dev) \ + for (i = 0; i < sizeof(tbl##Table##dev##_32BPP)/8; i++) \ + chip->dev[tbl##Table##dev##_32BPP[i][0]] = tbl##Table##dev##_32BPP[i][1] +#endif + +#define LOAD_FIXED_STATE(tbl,dev) \ + for (i = 0; i < sizeof(tbl##Table##dev)/8; i++) \ + NV_WR32(&chip->dev[tbl##Table##dev[i][0]], 0, tbl##Table##dev[i][1]) +#define LOAD_FIXED_STATE_8BPP(tbl,dev) \ + for (i = 0; i < sizeof(tbl##Table##dev##_8BPP)/8; i++) \ + NV_WR32(&chip->dev[tbl##Table##dev##_8BPP[i][0]], 0, tbl##Table##dev##_8BPP[i][1]) +#define LOAD_FIXED_STATE_15BPP(tbl,dev) \ + for (i = 0; i < sizeof(tbl##Table##dev##_15BPP)/8; i++) \ + NV_WR32(&chip->dev[tbl##Table##dev##_15BPP[i][0]], 0, tbl##Table##dev##_15BPP[i][1]) +#define LOAD_FIXED_STATE_16BPP(tbl,dev) \ + for (i = 0; i < sizeof(tbl##Table##dev##_16BPP)/8; i++) \ + NV_WR32(&chip->dev[tbl##Table##dev##_16BPP[i][0]], 0, tbl##Table##dev##_16BPP[i][1]) +#define LOAD_FIXED_STATE_32BPP(tbl,dev) \ + for (i = 0; i < sizeof(tbl##Table##dev##_32BPP)/8; i++) \ + NV_WR32(&chip->dev[tbl##Table##dev##_32BPP[i][0]], 0, tbl##Table##dev##_32BPP[i][1]) + +static void UpdateFifoState +( + RIVA_HW_INST *chip +) +{ + int i; + + switch (chip->Architecture) + { + case NV_ARCH_04: + LOAD_FIXED_STATE(nv4,FIFO); + chip->Tri03 = NULL; + chip->Tri05 = (RivaTexturedTriangle05 __iomem *)&(chip->FIFO[0x0000E000/4]); + break; + case NV_ARCH_10: + case NV_ARCH_20: + case NV_ARCH_30: + /* + * Initialize state for the RivaTriangle3D05 routines. + */ + LOAD_FIXED_STATE(nv10tri05,PGRAPH); + LOAD_FIXED_STATE(nv10,FIFO); + chip->Tri03 = NULL; + chip->Tri05 = (RivaTexturedTriangle05 __iomem *)&(chip->FIFO[0x0000E000/4]); + break; + } +} +static void LoadStateExt +( + RIVA_HW_INST *chip, + RIVA_HW_STATE *state +) +{ + int i; + + /* + * Load HW fixed function state. + */ + LOAD_FIXED_STATE(Riva,PMC); + LOAD_FIXED_STATE(Riva,PTIMER); + switch (chip->Architecture) + { + case NV_ARCH_03: + /* + * Make sure frame buffer config gets set before loading PRAMIN. + */ + NV_WR32(chip->PFB, 0x00000200, state->config); + LOAD_FIXED_STATE(nv3,PFIFO); + LOAD_FIXED_STATE(nv3,PRAMIN); + LOAD_FIXED_STATE(nv3,PGRAPH); + switch (state->bpp) + { + case 15: + case 16: + LOAD_FIXED_STATE_15BPP(nv3,PRAMIN); + LOAD_FIXED_STATE_15BPP(nv3,PGRAPH); + chip->Tri03 = (RivaTexturedTriangle03 __iomem *)&(chip->FIFO[0x0000E000/4]); + break; + case 24: + case 32: + LOAD_FIXED_STATE_32BPP(nv3,PRAMIN); + LOAD_FIXED_STATE_32BPP(nv3,PGRAPH); + chip->Tri03 = NULL; + break; + case 8: + default: + LOAD_FIXED_STATE_8BPP(nv3,PRAMIN); + LOAD_FIXED_STATE_8BPP(nv3,PGRAPH); + chip->Tri03 = NULL; + break; + } + for (i = 0x00000; i < 0x00800; i++) + NV_WR32(&chip->PRAMIN[0x00000502 + i], 0, (i << 12) | 0x03); + NV_WR32(chip->PGRAPH, 0x00000630, state->offset0); + NV_WR32(chip->PGRAPH, 0x00000634, state->offset1); + NV_WR32(chip->PGRAPH, 0x00000638, state->offset2); + NV_WR32(chip->PGRAPH, 0x0000063C, state->offset3); + NV_WR32(chip->PGRAPH, 0x00000650, state->pitch0); + NV_WR32(chip->PGRAPH, 0x00000654, state->pitch1); + NV_WR32(chip->PGRAPH, 0x00000658, state->pitch2); + NV_WR32(chip->PGRAPH, 0x0000065C, state->pitch3); + break; + case NV_ARCH_04: + /* + * Make sure frame buffer config gets set before loading PRAMIN. + */ + NV_WR32(chip->PFB, 0x00000200, state->config); + LOAD_FIXED_STATE(nv4,PFIFO); + LOAD_FIXED_STATE(nv4,PRAMIN); + LOAD_FIXED_STATE(nv4,PGRAPH); + switch (state->bpp) + { + case 15: + LOAD_FIXED_STATE_15BPP(nv4,PRAMIN); + LOAD_FIXED_STATE_15BPP(nv4,PGRAPH); + chip->Tri03 = (RivaTexturedTriangle03 __iomem *)&(chip->FIFO[0x0000E000/4]); + break; + case 16: + LOAD_FIXED_STATE_16BPP(nv4,PRAMIN); + LOAD_FIXED_STATE_16BPP(nv4,PGRAPH); + chip->Tri03 = (RivaTexturedTriangle03 __iomem *)&(chip->FIFO[0x0000E000/4]); + break; + case 24: + case 32: + LOAD_FIXED_STATE_32BPP(nv4,PRAMIN); + LOAD_FIXED_STATE_32BPP(nv4,PGRAPH); + chip->Tri03 = NULL; + break; + case 8: + default: + LOAD_FIXED_STATE_8BPP(nv4,PRAMIN); + LOAD_FIXED_STATE_8BPP(nv4,PGRAPH); + chip->Tri03 = NULL; + break; + } + NV_WR32(chip->PGRAPH, 0x00000640, state->offset0); + NV_WR32(chip->PGRAPH, 0x00000644, state->offset1); + NV_WR32(chip->PGRAPH, 0x00000648, state->offset2); + NV_WR32(chip->PGRAPH, 0x0000064C, state->offset3); + NV_WR32(chip->PGRAPH, 0x00000670, state->pitch0); + NV_WR32(chip->PGRAPH, 0x00000674, state->pitch1); + NV_WR32(chip->PGRAPH, 0x00000678, state->pitch2); + NV_WR32(chip->PGRAPH, 0x0000067C, state->pitch3); + break; + case NV_ARCH_10: + case NV_ARCH_20: + case NV_ARCH_30: + if(chip->twoHeads) { + VGA_WR08(chip->PCIO, 0x03D4, 0x44); + VGA_WR08(chip->PCIO, 0x03D5, state->crtcOwner); + chip->LockUnlock(chip, 0); + } + + LOAD_FIXED_STATE(nv10,PFIFO); + LOAD_FIXED_STATE(nv10,PRAMIN); + LOAD_FIXED_STATE(nv10,PGRAPH); + switch (state->bpp) + { + case 15: + LOAD_FIXED_STATE_15BPP(nv10,PRAMIN); + LOAD_FIXED_STATE_15BPP(nv10,PGRAPH); + chip->Tri03 = (RivaTexturedTriangle03 __iomem *)&(chip->FIFO[0x0000E000/4]); + break; + case 16: + LOAD_FIXED_STATE_16BPP(nv10,PRAMIN); + LOAD_FIXED_STATE_16BPP(nv10,PGRAPH); + chip->Tri03 = (RivaTexturedTriangle03 __iomem *)&(chip->FIFO[0x0000E000/4]); + break; + case 24: + case 32: + LOAD_FIXED_STATE_32BPP(nv10,PRAMIN); + LOAD_FIXED_STATE_32BPP(nv10,PGRAPH); + chip->Tri03 = NULL; + break; + case 8: + default: + LOAD_FIXED_STATE_8BPP(nv10,PRAMIN); + LOAD_FIXED_STATE_8BPP(nv10,PGRAPH); + chip->Tri03 = NULL; + break; + } + + if(chip->Architecture == NV_ARCH_10) { + NV_WR32(chip->PGRAPH, 0x00000640, state->offset0); + NV_WR32(chip->PGRAPH, 0x00000644, state->offset1); + NV_WR32(chip->PGRAPH, 0x00000648, state->offset2); + NV_WR32(chip->PGRAPH, 0x0000064C, state->offset3); + NV_WR32(chip->PGRAPH, 0x00000670, state->pitch0); + NV_WR32(chip->PGRAPH, 0x00000674, state->pitch1); + NV_WR32(chip->PGRAPH, 0x00000678, state->pitch2); + NV_WR32(chip->PGRAPH, 0x0000067C, state->pitch3); + NV_WR32(chip->PGRAPH, 0x00000680, state->pitch3); + } else { + NV_WR32(chip->PGRAPH, 0x00000820, state->offset0); + NV_WR32(chip->PGRAPH, 0x00000824, state->offset1); + NV_WR32(chip->PGRAPH, 0x00000828, state->offset2); + NV_WR32(chip->PGRAPH, 0x0000082C, state->offset3); + NV_WR32(chip->PGRAPH, 0x00000850, state->pitch0); + NV_WR32(chip->PGRAPH, 0x00000854, state->pitch1); + NV_WR32(chip->PGRAPH, 0x00000858, state->pitch2); + NV_WR32(chip->PGRAPH, 0x0000085C, state->pitch3); + NV_WR32(chip->PGRAPH, 0x00000860, state->pitch3); + NV_WR32(chip->PGRAPH, 0x00000864, state->pitch3); + NV_WR32(chip->PGRAPH, 0x000009A4, NV_RD32(chip->PFB, 0x00000200)); + NV_WR32(chip->PGRAPH, 0x000009A8, NV_RD32(chip->PFB, 0x00000204)); + } + if(chip->twoHeads) { + NV_WR32(chip->PCRTC0, 0x00000860, state->head); + NV_WR32(chip->PCRTC0, 0x00002860, state->head2); + } + NV_WR32(chip->PRAMDAC, 0x00000404, NV_RD32(chip->PRAMDAC, 0x00000404) | (1 << 25)); + + NV_WR32(chip->PMC, 0x00008704, 1); + NV_WR32(chip->PMC, 0x00008140, 0); + NV_WR32(chip->PMC, 0x00008920, 0); + NV_WR32(chip->PMC, 0x00008924, 0); + NV_WR32(chip->PMC, 0x00008908, 0x01ffffff); + NV_WR32(chip->PMC, 0x0000890C, 0x01ffffff); + NV_WR32(chip->PMC, 0x00001588, 0); + + NV_WR32(chip->PFB, 0x00000240, 0); + NV_WR32(chip->PFB, 0x00000250, 0); + NV_WR32(chip->PFB, 0x00000260, 0); + NV_WR32(chip->PFB, 0x00000270, 0); + NV_WR32(chip->PFB, 0x00000280, 0); + NV_WR32(chip->PFB, 0x00000290, 0); + NV_WR32(chip->PFB, 0x000002A0, 0); + NV_WR32(chip->PFB, 0x000002B0, 0); + + NV_WR32(chip->PGRAPH, 0x00000B00, NV_RD32(chip->PFB, 0x00000240)); + NV_WR32(chip->PGRAPH, 0x00000B04, NV_RD32(chip->PFB, 0x00000244)); + NV_WR32(chip->PGRAPH, 0x00000B08, NV_RD32(chip->PFB, 0x00000248)); + NV_WR32(chip->PGRAPH, 0x00000B0C, NV_RD32(chip->PFB, 0x0000024C)); + NV_WR32(chip->PGRAPH, 0x00000B10, NV_RD32(chip->PFB, 0x00000250)); + NV_WR32(chip->PGRAPH, 0x00000B14, NV_RD32(chip->PFB, 0x00000254)); + NV_WR32(chip->PGRAPH, 0x00000B18, NV_RD32(chip->PFB, 0x00000258)); + NV_WR32(chip->PGRAPH, 0x00000B1C, NV_RD32(chip->PFB, 0x0000025C)); + NV_WR32(chip->PGRAPH, 0x00000B20, NV_RD32(chip->PFB, 0x00000260)); + NV_WR32(chip->PGRAPH, 0x00000B24, NV_RD32(chip->PFB, 0x00000264)); + NV_WR32(chip->PGRAPH, 0x00000B28, NV_RD32(chip->PFB, 0x00000268)); + NV_WR32(chip->PGRAPH, 0x00000B2C, NV_RD32(chip->PFB, 0x0000026C)); + NV_WR32(chip->PGRAPH, 0x00000B30, NV_RD32(chip->PFB, 0x00000270)); + NV_WR32(chip->PGRAPH, 0x00000B34, NV_RD32(chip->PFB, 0x00000274)); + NV_WR32(chip->PGRAPH, 0x00000B38, NV_RD32(chip->PFB, 0x00000278)); + NV_WR32(chip->PGRAPH, 0x00000B3C, NV_RD32(chip->PFB, 0x0000027C)); + NV_WR32(chip->PGRAPH, 0x00000B40, NV_RD32(chip->PFB, 0x00000280)); + NV_WR32(chip->PGRAPH, 0x00000B44, NV_RD32(chip->PFB, 0x00000284)); + NV_WR32(chip->PGRAPH, 0x00000B48, NV_RD32(chip->PFB, 0x00000288)); + NV_WR32(chip->PGRAPH, 0x00000B4C, NV_RD32(chip->PFB, 0x0000028C)); + NV_WR32(chip->PGRAPH, 0x00000B50, NV_RD32(chip->PFB, 0x00000290)); + NV_WR32(chip->PGRAPH, 0x00000B54, NV_RD32(chip->PFB, 0x00000294)); + NV_WR32(chip->PGRAPH, 0x00000B58, NV_RD32(chip->PFB, 0x00000298)); + NV_WR32(chip->PGRAPH, 0x00000B5C, NV_RD32(chip->PFB, 0x0000029C)); + NV_WR32(chip->PGRAPH, 0x00000B60, NV_RD32(chip->PFB, 0x000002A0)); + NV_WR32(chip->PGRAPH, 0x00000B64, NV_RD32(chip->PFB, 0x000002A4)); + NV_WR32(chip->PGRAPH, 0x00000B68, NV_RD32(chip->PFB, 0x000002A8)); + NV_WR32(chip->PGRAPH, 0x00000B6C, NV_RD32(chip->PFB, 0x000002AC)); + NV_WR32(chip->PGRAPH, 0x00000B70, NV_RD32(chip->PFB, 0x000002B0)); + NV_WR32(chip->PGRAPH, 0x00000B74, NV_RD32(chip->PFB, 0x000002B4)); + NV_WR32(chip->PGRAPH, 0x00000B78, NV_RD32(chip->PFB, 0x000002B8)); + NV_WR32(chip->PGRAPH, 0x00000B7C, NV_RD32(chip->PFB, 0x000002BC)); + NV_WR32(chip->PGRAPH, 0x00000F40, 0x10000000); + NV_WR32(chip->PGRAPH, 0x00000F44, 0x00000000); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00000040); + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000008); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00000200); + for (i = 0; i < (3*16); i++) + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00000040); + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00000800); + for (i = 0; i < (16*16); i++) + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000); + NV_WR32(chip->PGRAPH, 0x00000F40, 0x30000000); + NV_WR32(chip->PGRAPH, 0x00000F44, 0x00000004); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00006400); + for (i = 0; i < (59*4); i++) + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00006800); + for (i = 0; i < (47*4); i++) + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00006C00); + for (i = 0; i < (3*4); i++) + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00007000); + for (i = 0; i < (19*4); i++) + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00007400); + for (i = 0; i < (12*4); i++) + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00007800); + for (i = 0; i < (12*4); i++) + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00004400); + for (i = 0; i < (8*4); i++) + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00000000); + for (i = 0; i < 16; i++) + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000); + NV_WR32(chip->PGRAPH, 0x00000F50, 0x00000040); + for (i = 0; i < 4; i++) + NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000); + + NV_WR32(chip->PCRTC, 0x00000810, state->cursorConfig); + + if(chip->flatPanel) { + if((chip->Chipset & 0x0ff0) == 0x0110) { + NV_WR32(chip->PRAMDAC, 0x0528, state->dither); + } else + if((chip->Chipset & 0x0ff0) >= 0x0170) { + NV_WR32(chip->PRAMDAC, 0x083C, state->dither); + } + + VGA_WR08(chip->PCIO, 0x03D4, 0x53); + VGA_WR08(chip->PCIO, 0x03D5, 0); + VGA_WR08(chip->PCIO, 0x03D4, 0x54); + VGA_WR08(chip->PCIO, 0x03D5, 0); + VGA_WR08(chip->PCIO, 0x03D4, 0x21); + VGA_WR08(chip->PCIO, 0x03D5, 0xfa); + } + + VGA_WR08(chip->PCIO, 0x03D4, 0x41); + VGA_WR08(chip->PCIO, 0x03D5, state->extra); + } + LOAD_FIXED_STATE(Riva,FIFO); + UpdateFifoState(chip); + /* + * Load HW mode state. + */ + VGA_WR08(chip->PCIO, 0x03D4, 0x19); + VGA_WR08(chip->PCIO, 0x03D5, state->repaint0); + VGA_WR08(chip->PCIO, 0x03D4, 0x1A); + VGA_WR08(chip->PCIO, 0x03D5, state->repaint1); + VGA_WR08(chip->PCIO, 0x03D4, 0x25); + VGA_WR08(chip->PCIO, 0x03D5, state->screen); + VGA_WR08(chip->PCIO, 0x03D4, 0x28); + VGA_WR08(chip->PCIO, 0x03D5, state->pixel); + VGA_WR08(chip->PCIO, 0x03D4, 0x2D); + VGA_WR08(chip->PCIO, 0x03D5, state->horiz); + VGA_WR08(chip->PCIO, 0x03D4, 0x1B); + VGA_WR08(chip->PCIO, 0x03D5, state->arbitration0); + VGA_WR08(chip->PCIO, 0x03D4, 0x20); + VGA_WR08(chip->PCIO, 0x03D5, state->arbitration1); + VGA_WR08(chip->PCIO, 0x03D4, 0x30); + VGA_WR08(chip->PCIO, 0x03D5, state->cursor0); + VGA_WR08(chip->PCIO, 0x03D4, 0x31); + VGA_WR08(chip->PCIO, 0x03D5, state->cursor1); + VGA_WR08(chip->PCIO, 0x03D4, 0x2F); + VGA_WR08(chip->PCIO, 0x03D5, state->cursor2); + VGA_WR08(chip->PCIO, 0x03D4, 0x39); + VGA_WR08(chip->PCIO, 0x03D5, state->interlace); + + if(!chip->flatPanel) { + NV_WR32(chip->PRAMDAC0, 0x00000508, state->vpll); + NV_WR32(chip->PRAMDAC0, 0x0000050C, state->pllsel); + if(chip->twoHeads) + NV_WR32(chip->PRAMDAC0, 0x00000520, state->vpll2); + } else { + NV_WR32(chip->PRAMDAC, 0x00000848 , state->scale); + } + NV_WR32(chip->PRAMDAC, 0x00000600 , state->general); + + /* + * Turn off VBlank enable and reset. + */ + NV_WR32(chip->PCRTC, 0x00000140, 0); + NV_WR32(chip->PCRTC, 0x00000100, chip->VBlankBit); + /* + * Set interrupt enable. + */ + NV_WR32(chip->PMC, 0x00000140, chip->EnableIRQ & 0x01); + /* + * Set current state pointer. + */ + chip->CurrentState = state; + /* + * Reset FIFO free and empty counts. + */ + chip->FifoFreeCount = 0; + /* Free count from first subchannel */ + chip->FifoEmptyCount = NV_RD32(&chip->Rop->FifoFree, 0); +} +static void UnloadStateExt +( + RIVA_HW_INST *chip, + RIVA_HW_STATE *state +) +{ + /* + * Save current HW state. + */ + VGA_WR08(chip->PCIO, 0x03D4, 0x19); + state->repaint0 = VGA_RD08(chip->PCIO, 0x03D5); + VGA_WR08(chip->PCIO, 0x03D4, 0x1A); + state->repaint1 = VGA_RD08(chip->PCIO, 0x03D5); + VGA_WR08(chip->PCIO, 0x03D4, 0x25); + state->screen = VGA_RD08(chip->PCIO, 0x03D5); + VGA_WR08(chip->PCIO, 0x03D4, 0x28); + state->pixel = VGA_RD08(chip->PCIO, 0x03D5); + VGA_WR08(chip->PCIO, 0x03D4, 0x2D); + state->horiz = VGA_RD08(chip->PCIO, 0x03D5); + VGA_WR08(chip->PCIO, 0x03D4, 0x1B); + state->arbitration0 = VGA_RD08(chip->PCIO, 0x03D5); + VGA_WR08(chip->PCIO, 0x03D4, 0x20); + state->arbitration1 = VGA_RD08(chip->PCIO, 0x03D5); + VGA_WR08(chip->PCIO, 0x03D4, 0x30); + state->cursor0 = VGA_RD08(chip->PCIO, 0x03D5); + VGA_WR08(chip->PCIO, 0x03D4, 0x31); + state->cursor1 = VGA_RD08(chip->PCIO, 0x03D5); + VGA_WR08(chip->PCIO, 0x03D4, 0x2F); + state->cursor2 = VGA_RD08(chip->PCIO, 0x03D5); + VGA_WR08(chip->PCIO, 0x03D4, 0x39); + state->interlace = VGA_RD08(chip->PCIO, 0x03D5); + state->vpll = NV_RD32(chip->PRAMDAC0, 0x00000508); + state->vpll2 = NV_RD32(chip->PRAMDAC0, 0x00000520); + state->pllsel = NV_RD32(chip->PRAMDAC0, 0x0000050C); + state->general = NV_RD32(chip->PRAMDAC, 0x00000600); + state->scale = NV_RD32(chip->PRAMDAC, 0x00000848); + state->config = NV_RD32(chip->PFB, 0x00000200); + switch (chip->Architecture) + { + case NV_ARCH_03: + state->offset0 = NV_RD32(chip->PGRAPH, 0x00000630); + state->offset1 = NV_RD32(chip->PGRAPH, 0x00000634); + state->offset2 = NV_RD32(chip->PGRAPH, 0x00000638); + state->offset3 = NV_RD32(chip->PGRAPH, 0x0000063C); + state->pitch0 = NV_RD32(chip->PGRAPH, 0x00000650); + state->pitch1 = NV_RD32(chip->PGRAPH, 0x00000654); + state->pitch2 = NV_RD32(chip->PGRAPH, 0x00000658); + state->pitch3 = NV_RD32(chip->PGRAPH, 0x0000065C); + break; + case NV_ARCH_04: + state->offset0 = NV_RD32(chip->PGRAPH, 0x00000640); + state->offset1 = NV_RD32(chip->PGRAPH, 0x00000644); + state->offset2 = NV_RD32(chip->PGRAPH, 0x00000648); + state->offset3 = NV_RD32(chip->PGRAPH, 0x0000064C); + state->pitch0 = NV_RD32(chip->PGRAPH, 0x00000670); + state->pitch1 = NV_RD32(chip->PGRAPH, 0x00000674); + state->pitch2 = NV_RD32(chip->PGRAPH, 0x00000678); + state->pitch3 = NV_RD32(chip->PGRAPH, 0x0000067C); + break; + case NV_ARCH_10: + case NV_ARCH_20: + case NV_ARCH_30: + state->offset0 = NV_RD32(chip->PGRAPH, 0x00000640); + state->offset1 = NV_RD32(chip->PGRAPH, 0x00000644); + state->offset2 = NV_RD32(chip->PGRAPH, 0x00000648); + state->offset3 = NV_RD32(chip->PGRAPH, 0x0000064C); + state->pitch0 = NV_RD32(chip->PGRAPH, 0x00000670); + state->pitch1 = NV_RD32(chip->PGRAPH, 0x00000674); + state->pitch2 = NV_RD32(chip->PGRAPH, 0x00000678); + state->pitch3 = NV_RD32(chip->PGRAPH, 0x0000067C); + if(chip->twoHeads) { + state->head = NV_RD32(chip->PCRTC0, 0x00000860); + state->head2 = NV_RD32(chip->PCRTC0, 0x00002860); + VGA_WR08(chip->PCIO, 0x03D4, 0x44); + state->crtcOwner = VGA_RD08(chip->PCIO, 0x03D5); + } + VGA_WR08(chip->PCIO, 0x03D4, 0x41); + state->extra = VGA_RD08(chip->PCIO, 0x03D5); + state->cursorConfig = NV_RD32(chip->PCRTC, 0x00000810); + + if((chip->Chipset & 0x0ff0) == 0x0110) { + state->dither = NV_RD32(chip->PRAMDAC, 0x0528); + } else + if((chip->Chipset & 0x0ff0) >= 0x0170) { + state->dither = NV_RD32(chip->PRAMDAC, 0x083C); + } + break; + } +} +static void SetStartAddress +( + RIVA_HW_INST *chip, + unsigned start +) +{ + NV_WR32(chip->PCRTC, 0x800, start); +} + +static void SetStartAddress3 +( + RIVA_HW_INST *chip, + unsigned start +) +{ + int offset = start >> 2; + int pan = (start & 3) << 1; + unsigned char tmp; + + /* + * Unlock extended registers. + */ + chip->LockUnlock(chip, 0); + /* + * Set start address. + */ + VGA_WR08(chip->PCIO, 0x3D4, 0x0D); VGA_WR08(chip->PCIO, 0x3D5, offset); + offset >>= 8; + VGA_WR08(chip->PCIO, 0x3D4, 0x0C); VGA_WR08(chip->PCIO, 0x3D5, offset); + offset >>= 8; + VGA_WR08(chip->PCIO, 0x3D4, 0x19); tmp = VGA_RD08(chip->PCIO, 0x3D5); + VGA_WR08(chip->PCIO, 0x3D5, (offset & 0x01F) | (tmp & ~0x1F)); + VGA_WR08(chip->PCIO, 0x3D4, 0x2D); tmp = VGA_RD08(chip->PCIO, 0x3D5); + VGA_WR08(chip->PCIO, 0x3D5, (offset & 0x60) | (tmp & ~0x60)); + /* + * 4 pixel pan register. + */ + offset = VGA_RD08(chip->PCIO, chip->IO + 0x0A); + VGA_WR08(chip->PCIO, 0x3C0, 0x13); + VGA_WR08(chip->PCIO, 0x3C0, pan); +} +static void nv3SetSurfaces2D +( + RIVA_HW_INST *chip, + unsigned surf0, + unsigned surf1 +) +{ + RivaSurface __iomem *Surface = + (RivaSurface __iomem *)&(chip->FIFO[0x0000E000/4]); + + RIVA_FIFO_FREE(*chip,Tri03,5); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000003); + NV_WR32(&Surface->Offset, 0, surf0); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000004); + NV_WR32(&Surface->Offset, 0, surf1); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000013); +} +static void nv4SetSurfaces2D +( + RIVA_HW_INST *chip, + unsigned surf0, + unsigned surf1 +) +{ + RivaSurface __iomem *Surface = + (RivaSurface __iomem *)&(chip->FIFO[0x0000E000/4]); + + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000003); + NV_WR32(&Surface->Offset, 0, surf0); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000004); + NV_WR32(&Surface->Offset, 0, surf1); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000014); +} +static void nv10SetSurfaces2D +( + RIVA_HW_INST *chip, + unsigned surf0, + unsigned surf1 +) +{ + RivaSurface __iomem *Surface = + (RivaSurface __iomem *)&(chip->FIFO[0x0000E000/4]); + + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000003); + NV_WR32(&Surface->Offset, 0, surf0); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000004); + NV_WR32(&Surface->Offset, 0, surf1); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000014); +} +static void nv3SetSurfaces3D +( + RIVA_HW_INST *chip, + unsigned surf0, + unsigned surf1 +) +{ + RivaSurface __iomem *Surface = + (RivaSurface __iomem *)&(chip->FIFO[0x0000E000/4]); + + RIVA_FIFO_FREE(*chip,Tri03,5); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000005); + NV_WR32(&Surface->Offset, 0, surf0); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000006); + NV_WR32(&Surface->Offset, 0, surf1); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000013); +} +static void nv4SetSurfaces3D +( + RIVA_HW_INST *chip, + unsigned surf0, + unsigned surf1 +) +{ + RivaSurface __iomem *Surface = + (RivaSurface __iomem *)&(chip->FIFO[0x0000E000/4]); + + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000005); + NV_WR32(&Surface->Offset, 0, surf0); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000006); + NV_WR32(&Surface->Offset, 0, surf1); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000014); +} +static void nv10SetSurfaces3D +( + RIVA_HW_INST *chip, + unsigned surf0, + unsigned surf1 +) +{ + RivaSurface3D __iomem *Surfaces3D = + (RivaSurface3D __iomem *)&(chip->FIFO[0x0000E000/4]); + + RIVA_FIFO_FREE(*chip,Tri03,4); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000007); + NV_WR32(&Surfaces3D->RenderBufferOffset, 0, surf0); + NV_WR32(&Surfaces3D->ZBufferOffset, 0, surf1); + NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000014); +} + +/****************************************************************************\ +* * +* Probe RIVA Chip Configuration * +* * +\****************************************************************************/ + +static void nv3GetConfig +( + RIVA_HW_INST *chip +) +{ + /* + * Fill in chip configuration. + */ + if (NV_RD32(&chip->PFB[0x00000000/4], 0) & 0x00000020) + { + if (((NV_RD32(chip->PMC, 0x00000000) & 0xF0) == 0x20) + && ((NV_RD32(chip->PMC, 0x00000000) & 0x0F) >= 0x02)) + { + /* + * SDRAM 128 ZX. + */ + chip->RamBandwidthKBytesPerSec = 800000; + switch (NV_RD32(chip->PFB, 0x00000000) & 0x03) + { + case 2: + chip->RamAmountKBytes = 1024 * 4; + break; + case 1: + chip->RamAmountKBytes = 1024 * 2; + break; + default: + chip->RamAmountKBytes = 1024 * 8; + break; + } + } + else + { + chip->RamBandwidthKBytesPerSec = 1000000; + chip->RamAmountKBytes = 1024 * 8; + } + } + else + { + /* + * SGRAM 128. + */ + chip->RamBandwidthKBytesPerSec = 1000000; + switch (NV_RD32(chip->PFB, 0x00000000) & 0x00000003) + { + case 0: + chip->RamAmountKBytes = 1024 * 8; + break; + case 2: + chip->RamAmountKBytes = 1024 * 4; + break; + default: + chip->RamAmountKBytes = 1024 * 2; + break; + } + } + chip->CrystalFreqKHz = (NV_RD32(chip->PEXTDEV, 0x00000000) & 0x00000040) ? 14318 : 13500; + chip->CURSOR = &(chip->PRAMIN[0x00008000/4 - 0x0800/4]); + chip->VBlankBit = 0x00000100; + chip->MaxVClockFreqKHz = 256000; + /* + * Set chip functions. + */ + chip->Busy = nv3Busy; + chip->ShowHideCursor = ShowHideCursor; + chip->CalcStateExt = CalcStateExt; + chip->LoadStateExt = LoadStateExt; + chip->UnloadStateExt = UnloadStateExt; + chip->SetStartAddress = SetStartAddress3; + chip->SetSurfaces2D = nv3SetSurfaces2D; + chip->SetSurfaces3D = nv3SetSurfaces3D; + chip->LockUnlock = nv3LockUnlock; +} +static void nv4GetConfig +( + RIVA_HW_INST *chip +) +{ + /* + * Fill in chip configuration. + */ + if (NV_RD32(chip->PFB, 0x00000000) & 0x00000100) + { + chip->RamAmountKBytes = ((NV_RD32(chip->PFB, 0x00000000) >> 12) & 0x0F) * 1024 * 2 + + 1024 * 2; + } + else + { + switch (NV_RD32(chip->PFB, 0x00000000) & 0x00000003) + { + case 0: + chip->RamAmountKBytes = 1024 * 32; + break; + case 1: + chip->RamAmountKBytes = 1024 * 4; + break; + case 2: + chip->RamAmountKBytes = 1024 * 8; + break; + case 3: + default: + chip->RamAmountKBytes = 1024 * 16; + break; + } + } + switch ((NV_RD32(chip->PFB, 0x00000000) >> 3) & 0x00000003) + { + case 3: + chip->RamBandwidthKBytesPerSec = 800000; + break; + default: + chip->RamBandwidthKBytesPerSec = 1000000; + break; + } + chip->CrystalFreqKHz = (NV_RD32(chip->PEXTDEV, 0x00000000) & 0x00000040) ? 14318 : 13500; + chip->CURSOR = &(chip->PRAMIN[0x00010000/4 - 0x0800/4]); + chip->VBlankBit = 0x00000001; + chip->MaxVClockFreqKHz = 350000; + /* + * Set chip functions. + */ + chip->Busy = nv4Busy; + chip->ShowHideCursor = ShowHideCursor; + chip->CalcStateExt = CalcStateExt; + chip->LoadStateExt = LoadStateExt; + chip->UnloadStateExt = UnloadStateExt; + chip->SetStartAddress = SetStartAddress; + chip->SetSurfaces2D = nv4SetSurfaces2D; + chip->SetSurfaces3D = nv4SetSurfaces3D; + chip->LockUnlock = nv4LockUnlock; +} +static void nv10GetConfig +( + RIVA_HW_INST *chip, + unsigned int chipset +) +{ + struct pci_dev* dev; + int amt; + +#ifdef __BIG_ENDIAN + /* turn on big endian register access */ + if(!(NV_RD32(chip->PMC, 0x00000004) & 0x01000001)) + NV_WR32(chip->PMC, 0x00000004, 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 ((NV_RD32(chip->PFB, 0x0000020C) >> 20) & 0x000000FF) + { + case 0x02: + chip->RamAmountKBytes = 1024 * 2; + break; + case 0x04: + chip->RamAmountKBytes = 1024 * 4; + break; + case 0x08: + chip->RamAmountKBytes = 1024 * 8; + break; + case 0x10: + chip->RamAmountKBytes = 1024 * 16; + break; + case 0x20: + chip->RamAmountKBytes = 1024 * 32; + break; + case 0x40: + chip->RamAmountKBytes = 1024 * 64; + break; + case 0x80: + chip->RamAmountKBytes = 1024 * 128; + break; + default: + chip->RamAmountKBytes = 1024 * 16; + break; + } + } + switch ((NV_RD32(chip->PFB, 0x00000000) >> 3) & 0x00000003) + { + case 3: + chip->RamBandwidthKBytesPerSec = 800000; + break; + default: + chip->RamBandwidthKBytesPerSec = 1000000; + break; + } + chip->CrystalFreqKHz = (NV_RD32(chip->PEXTDEV, 0x0000) & (1 << 6)) ? + 14318 : 13500; + + switch (chipset & 0x0ff0) { + case 0x0170: + case 0x0180: + case 0x01F0: + case 0x0250: + case 0x0280: + case 0x0300: + case 0x0310: + case 0x0320: + case 0x0330: + case 0x0340: + if(NV_RD32(chip->PEXTDEV, 0x0000) & (1 << 22)) + chip->CrystalFreqKHz = 27000; + break; + default: + break; + } + + chip->CursorStart = (chip->RamAmountKBytes - 128) * 1024; + chip->CURSOR = NULL; /* can't set this here */ + chip->VBlankBit = 0x00000001; + chip->MaxVClockFreqKHz = 350000; + /* + * Set chip functions. + */ + chip->Busy = nv10Busy; + chip->ShowHideCursor = ShowHideCursor; + chip->CalcStateExt = CalcStateExt; + chip->LoadStateExt = LoadStateExt; + chip->UnloadStateExt = UnloadStateExt; + chip->SetStartAddress = SetStartAddress; + chip->SetSurfaces2D = nv10SetSurfaces2D; + chip->SetSurfaces3D = nv10SetSurfaces3D; + chip->LockUnlock = nv4LockUnlock; + + switch(chipset & 0x0ff0) { + case 0x0110: + case 0x0170: + case 0x0180: + case 0x01F0: + case 0x0250: + case 0x0280: + case 0x0300: + case 0x0310: + case 0x0320: + case 0x0330: + case 0x0340: + chip->twoHeads = TRUE; + break; + default: + chip->twoHeads = FALSE; + break; + } +} +int RivaGetConfig +( + RIVA_HW_INST *chip, + unsigned int chipset +) +{ + /* + * Save this so future SW know whats it's dealing with. + */ + chip->Version = RIVA_SW_VERSION; + /* + * Chip specific configuration. + */ + switch (chip->Architecture) + { + case NV_ARCH_03: + nv3GetConfig(chip); + break; + case NV_ARCH_04: + nv4GetConfig(chip); + break; + case NV_ARCH_10: + case NV_ARCH_20: + case NV_ARCH_30: + nv10GetConfig(chip, chipset); + break; + default: + return (-1); + } + chip->Chipset = chipset; + /* + * Fill in FIFO pointers. + */ + chip->Rop = (RivaRop __iomem *)&(chip->FIFO[0x00000000/4]); + chip->Clip = (RivaClip __iomem *)&(chip->FIFO[0x00002000/4]); + chip->Patt = (RivaPattern __iomem *)&(chip->FIFO[0x00004000/4]); + chip->Pixmap = (RivaPixmap __iomem *)&(chip->FIFO[0x00006000/4]); + chip->Blt = (RivaScreenBlt __iomem *)&(chip->FIFO[0x00008000/4]); + chip->Bitmap = (RivaBitmap __iomem *)&(chip->FIFO[0x0000A000/4]); + chip->Line = (RivaLine __iomem *)&(chip->FIFO[0x0000C000/4]); + chip->Tri03 = (RivaTexturedTriangle03 __iomem *)&(chip->FIFO[0x0000E000/4]); + return (0); +} + diff --git a/drivers/video/riva/riva_hw.h b/drivers/video/riva/riva_hw.h new file mode 100644 index 000000000000..a1e71a626df2 --- /dev/null +++ b/drivers/video/riva/riva_hw.h @@ -0,0 +1,548 @@ +/***************************************************************************\ +|* *| +|* Copyright 1993-1999 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 1993-1999 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| +\***************************************************************************/ + +/* + * GPL licensing note -- nVidia is allowing a liberal interpretation of + * the documentation restriction above, to merely say that this nVidia's + * copyright and disclaimer should be included with all code derived + * from this source. -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 + */ + +/* $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. + */ +typedef unsigned char U008; +typedef unsigned short U016; +typedef unsigned int U032; + +/* + * HW access macros. + */ +#include <asm/io.h> + +#define NV_WR08(p,i,d) (__raw_writeb((d), (void __iomem *)(p) + (i))) +#define NV_RD08(p,i) (__raw_readb((void __iomem *)(p) + (i))) +#define NV_WR16(p,i,d) (__raw_writew((d), (void __iomem *)(p) + (i))) +#define NV_RD16(p,i) (__raw_readw((void __iomem *)(p) + (i))) +#define NV_WR32(p,i,d) (__raw_writel((d), (void __iomem *)(p) + (i))) +#define NV_RD32(p,i) (__raw_readl((void __iomem *)(p) + (i))) + +#define VGA_WR08(p,i,d) (writeb((d), (void __iomem *)(p) + (i))) +#define VGA_RD08(p,i) (readb((void __iomem *)(p) + (i))) + +/* + * Define different architectures. + */ +#define NV_ARCH_03 0x03 +#define NV_ARCH_04 0x04 +#define NV_ARCH_10 0x10 +#define NV_ARCH_20 0x20 +#define NV_ARCH_30 0x30 +#define NV_ARCH_40 0x40 + +/***************************************************************************\ +* * +* FIFO registers. * +* * +\***************************************************************************/ + +/* + * Raster OPeration. Windows style ROP3. + */ +typedef volatile struct +{ + U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else + U016 FifoFree; + U016 Nop; +#endif + U032 reserved01[0x0BB]; + U032 Rop3; +} RivaRop; +/* + * 8X8 Monochrome pattern. + */ +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]; + U032 Color0; + U032 Color1; + U032 Monochrome[2]; +} RivaPattern; +/* + * Scissor clip rectangle. + */ +typedef volatile struct +{ + U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else + U016 FifoFree; + U016 Nop; +#endif + U032 reserved01[0x0BB]; + U032 TopLeft; + U032 WidthHeight; +} RivaClip; +/* + * 2D filled rectangle. + */ +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]; + U032 TopLeft; + U032 WidthHeight; +} RivaRectangle; +/* + * 2D screen-screen BLT. + */ +typedef volatile struct +{ + U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else + U016 FifoFree; + U016 Nop; +#endif + U032 reserved01[0x0BB]; + U032 TopLeftSrc; + U032 TopLeftDst; + U032 WidthHeight; +} RivaScreenBlt; +/* + * 2D pixel BLT. + */ +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; + U032 WidthHeightIn; + U032 reserved02[0x03C]; + U032 Pixels; +} RivaPixmap; +/* + * Filled rectangle combined with monochrome expand. Useful for glyphs. + */ +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; + struct + { + U032 TopLeft; + U032 WidthHeight; + } UnclippedRectangle[64]; + U032 reserved04[(0x080)-3]; + struct + { + U032 TopLeft; + U032 BottomRight; + } ClipB; + U032 Color1B; + struct + { + U032 TopLeft; + U032 BottomRight; + } ClippedRectangle[64]; + U032 reserved05[(0x080)-5]; + struct + { + U032 TopLeft; + U032 BottomRight; + } ClipC; + U032 Color1C; + U032 WidthHeightC; + U032 PointC; + U032 MonochromeData1C; + U032 reserved06[(0x080)+121]; + struct + { + U032 TopLeft; + U032 BottomRight; + } ClipD; + U032 Color1D; + U032 WidthHeightInD; + U032 WidthHeightOutD; + U032 PointD; + U032 MonochromeData1D; + U032 reserved07[(0x080)+120]; + struct + { + U032 TopLeft; + U032 BottomRight; + } ClipE; + U032 Color0E; + U032 Color1E; + U032 WidthHeightInE; + U032 WidthHeightOutE; + U032 PointE; + U032 MonochromeData01E; +} RivaBitmap; +/* + * 3D textured, Z buffered triangle. + */ +typedef volatile struct +{ + U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else + U016 FifoFree; + U016 Nop; +#endif + U032 reserved01[0x0BC]; + U032 TextureOffset; + U032 TextureFormat; + U032 TextureFilter; + U032 FogColor; +/* This is a problem on LynxOS */ +#ifdef Control +#undef Control +#endif + U032 Control; + U032 AlphaTest; + U032 reserved02[0x339]; + U032 FogAndIndex; + U032 Color; + float ScreenX; + float ScreenY; + float ScreenZ; + float EyeM; + float TextureS; + float TextureT; +} RivaTexturedTriangle03; +typedef volatile struct +{ + U032 reserved00[4]; +#ifdef __BIG_ENDIAN + U032 FifoFree; +#else + U016 FifoFree; + U016 Nop; +#endif + U032 reserved01[0x0BB]; + U032 ColorKey; + U032 TextureOffset; + U032 TextureFormat; + U032 TextureFilter; + U032 Blend; +/* This is a problem on LynxOS */ +#ifdef Control +#undef Control +#endif + U032 Control; + U032 FogColor; + U032 reserved02[0x39]; + struct + { + float ScreenX; + float ScreenY; + float ScreenZ; + float EyeM; + U032 Color; + U032 Specular; + float TextureS; + float TextureT; + } Vertex[16]; + U032 DrawTriangle3D; +} RivaTexturedTriangle05; +/* + * 2D line. + */ +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]; + struct { /* start aliased methods in array 0400- */ + U032 point0; /* y_x S16_S16 in pixels 0- 3*/ + U032 point1; /* y_x S16_S16 in pixels 4- 7*/ + } Lin[16]; /* end of aliased methods in array -047f*/ + struct { /* start aliased methods in array 0480- */ + U032 point0X; /* in pixels, 0 at left 0- 3*/ + U032 point0Y; /* in pixels, 0 at top 4- 7*/ + U032 point1X; /* in pixels, 0 at left 8- b*/ + U032 point1Y; /* in pixels, 0 at top c- f*/ + } Lin32[8]; /* end of aliased methods in array -04ff*/ + U032 PolyLin[32]; /* y_x S16_S16 in pixels 0500-057f*/ + struct { /* start aliased methods in array 0580- */ + U032 x; /* in pixels, 0 at left 0- 3*/ + U032 y; /* in pixels, 0 at top 4- 7*/ + } PolyLin32[16]; /* end of aliased methods in array -05ff*/ + struct { /* start aliased methods in array 0600- */ + U032 color; /* source color 0- 3*/ + U032 point; /* y_x S16_S16 in pixels 4- 7*/ + } ColorPolyLin[16]; /* end of aliased methods in array -067f*/ +} RivaLine; +/* + * 2D/3D surfaces + */ +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; + U032 ZBufferOffset; +} RivaSurface3D; + +/***************************************************************************\ +* * +* Virtualized RIVA H/W interface. * +* * +\***************************************************************************/ + +#define FP_ENABLE 1 +#define FP_DITHER 2 + +struct _riva_hw_inst; +struct _riva_hw_state; +/* + * Virtialized chip interface. Makes RIVA 128 and TNT look alike. + */ +typedef struct _riva_hw_inst +{ + /* + * Chip specific settings. + */ + U032 Architecture; + U032 Version; + U032 Chipset; + U032 CrystalFreqKHz; + U032 RamAmountKBytes; + U032 MaxVClockFreqKHz; + U032 RamBandwidthKBytesPerSec; + U032 EnableIRQ; + U032 IO; + U032 VBlankBit; + U032 FifoFreeCount; + U032 FifoEmptyCount; + U032 CursorStart; + U032 flatPanel; + Bool twoHeads; + /* + * Non-FIFO registers. + */ + volatile U032 __iomem *PCRTC0; + volatile U032 __iomem *PCRTC; + volatile U032 __iomem *PRAMDAC0; + volatile U032 __iomem *PFB; + volatile U032 __iomem *PFIFO; + volatile U032 __iomem *PGRAPH; + volatile U032 __iomem *PEXTDEV; + volatile U032 __iomem *PTIMER; + volatile U032 __iomem *PMC; + volatile U032 __iomem *PRAMIN; + volatile U032 __iomem *FIFO; + volatile U032 __iomem *CURSOR; + volatile U008 __iomem *PCIO0; + volatile U008 __iomem *PCIO; + volatile U008 __iomem *PVIO; + volatile U008 __iomem *PDIO0; + volatile U008 __iomem *PDIO; + volatile U032 __iomem *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); + 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); + void (*SetSurfaces2D)(struct _riva_hw_inst *,U032,U032); + void (*SetSurfaces3D)(struct _riva_hw_inst *,U032,U032); + int (*ShowHideCursor)(struct _riva_hw_inst *,int); + void (*LockUnlock)(struct _riva_hw_inst *, int); + /* + * Current extended mode settings. + */ + struct _riva_hw_state *CurrentState; + /* + * FIFO registers. + */ + RivaRop __iomem *Rop; + RivaPattern __iomem *Patt; + RivaClip __iomem *Clip; + RivaPixmap __iomem *Pixmap; + RivaScreenBlt __iomem *Blt; + RivaBitmap __iomem *Bitmap; + RivaLine __iomem *Line; + RivaTexturedTriangle03 __iomem *Tri03; + RivaTexturedTriangle05 __iomem *Tri05; +} RIVA_HW_INST; +/* + * Extended mode state information. + */ +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; + U032 offset0; + U032 offset1; + U032 offset2; + U032 offset3; + U032 pitch0; + U032 pitch1; + U032 pitch2; + U032 pitch3; +} RIVA_HW_STATE; +/* + * External routines. + */ +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)) { \ + mb();mb(); \ + (hwinst).FifoFreeCount = NV_RD32(&(hwinst).hwptr->FifoFree, 0) >> 2; \ + } \ + (hwinst).FifoFreeCount -= (cnt); \ +} +#endif /* __RIVA_HW_H__ */ + diff --git a/drivers/video/riva/riva_tbl.h b/drivers/video/riva/riva_tbl.h new file mode 100644 index 000000000000..7ee7d72932d4 --- /dev/null +++ b/drivers/video/riva/riva_tbl.h @@ -0,0 +1,1008 @@ + /***************************************************************************\ +|* *| +|* Copyright 1993-1999 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 1993-1999 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL licensing note -- nVidia is allowing a liberal interpretation of + * the documentation restriction above, to merely say that this nVidia's + * copyright and disclaimer should be included with all code derived + * from this source. -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 + */ + +/* $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. + */ +static unsigned RivaTablePMC[][2] = +{ + {0x00000050, 0x00000000}, + {0x00000080, 0xFFFF00FF}, + {0x00000080, 0xFFFFFFFF} +}; +static unsigned RivaTablePTIMER[][2] = +{ + {0x00000080, 0x00000008}, + {0x00000084, 0x00000003}, + {0x00000050, 0x00000000}, + {0x00000040, 0xFFFFFFFF} +}; +static unsigned RivaTableFIFO[][2] = +{ + {0x00000000, 0x80000000}, + {0x00000800, 0x80000001}, + {0x00001000, 0x80000002}, + {0x00001800, 0x80000010}, + {0x00002000, 0x80000011}, + {0x00002800, 0x80000012}, + {0x00003000, 0x80000016}, + {0x00003800, 0x80000013} +}; +static unsigned nv3TablePFIFO[][2] = +{ + {0x00000140, 0x00000000}, + {0x00000480, 0x00000000}, + {0x00000490, 0x00000000}, + {0x00000494, 0x00000000}, + {0x00000481, 0x00000000}, + {0x00000084, 0x00000000}, + {0x00000086, 0x00002000}, + {0x00000085, 0x00002200}, + {0x00000484, 0x00000000}, + {0x0000049C, 0x00000000}, + {0x00000104, 0x00000000}, + {0x00000108, 0x00000000}, + {0x00000100, 0x00000000}, + {0x000004A0, 0x00000000}, + {0x000004A4, 0x00000000}, + {0x000004A8, 0x00000000}, + {0x000004AC, 0x00000000}, + {0x000004B0, 0x00000000}, + {0x000004B4, 0x00000000}, + {0x000004B8, 0x00000000}, + {0x000004BC, 0x00000000}, + {0x00000050, 0x00000000}, + {0x00000040, 0xFFFFFFFF}, + {0x00000480, 0x00000001}, + {0x00000490, 0x00000001}, + {0x00000140, 0x00000001} +}; +static unsigned nv3TablePGRAPH[][2] = +{ + {0x00000020, 0x1230001F}, + {0x00000021, 0x10113000}, + {0x00000022, 0x1131F101}, + {0x00000023, 0x0100F531}, + {0x00000060, 0x00000000}, + {0x00000065, 0x00000000}, + {0x00000068, 0x00000000}, + {0x00000069, 0x00000000}, + {0x0000006A, 0x00000000}, + {0x0000006B, 0x00000000}, + {0x0000006C, 0x00000000}, + {0x0000006D, 0x00000000}, + {0x0000006E, 0x00000000}, + {0x0000006F, 0x00000000}, + {0x000001A8, 0x00000000}, + {0x00000440, 0xFFFFFFFF}, + {0x00000480, 0x00000001}, + {0x000001A0, 0x00000000}, + {0x000001A2, 0x00000000}, + {0x0000018A, 0xFFFFFFFF}, + {0x00000190, 0x00000000}, + {0x00000142, 0x00000000}, + {0x00000154, 0x00000000}, + {0x00000155, 0xFFFFFFFF}, + {0x00000156, 0x00000000}, + {0x00000157, 0xFFFFFFFF}, + {0x00000064, 0x10010002}, + {0x00000050, 0x00000000}, + {0x00000051, 0x00000000}, + {0x00000040, 0xFFFFFFFF}, + {0x00000041, 0xFFFFFFFF}, + {0x00000440, 0xFFFFFFFF}, + {0x000001A9, 0x00000001} +}; +static unsigned nv3TablePGRAPH_8BPP[][2] = +{ + {0x000001AA, 0x00001111} +}; +static unsigned nv3TablePGRAPH_15BPP[][2] = +{ + {0x000001AA, 0x00002222} +}; +static unsigned nv3TablePGRAPH_32BPP[][2] = +{ + {0x000001AA, 0x00003333} +}; +static unsigned nv3TablePRAMIN[][2] = +{ + {0x00000500, 0x00010000}, + {0x00000501, 0x007FFFFF}, + {0x00000200, 0x80000000}, + {0x00000201, 0x00C20341}, + {0x00000204, 0x80000001}, + {0x00000205, 0x00C50342}, + {0x00000208, 0x80000002}, + {0x00000209, 0x00C60343}, + {0x0000020C, 0x80000003}, + {0x0000020D, 0x00DC0348}, + {0x00000210, 0x80000004}, + {0x00000211, 0x00DC0349}, + {0x00000214, 0x80000005}, + {0x00000215, 0x00DC034A}, + {0x00000218, 0x80000006}, + {0x00000219, 0x00DC034B}, + {0x00000240, 0x80000010}, + {0x00000241, 0x00D10344}, + {0x00000244, 0x80000011}, + {0x00000245, 0x00D00345}, + {0x00000248, 0x80000012}, + {0x00000249, 0x00CC0346}, + {0x0000024C, 0x80000013}, + {0x0000024D, 0x00D70347}, + {0x00000258, 0x80000016}, + {0x00000259, 0x00CA034C}, + {0x00000D05, 0x00000000}, + {0x00000D06, 0x00000000}, + {0x00000D07, 0x00000000}, + {0x00000D09, 0x00000000}, + {0x00000D0A, 0x00000000}, + {0x00000D0B, 0x00000000}, + {0x00000D0D, 0x00000000}, + {0x00000D0E, 0x00000000}, + {0x00000D0F, 0x00000000}, + {0x00000D11, 0x00000000}, + {0x00000D12, 0x00000000}, + {0x00000D13, 0x00000000}, + {0x00000D15, 0x00000000}, + {0x00000D16, 0x00000000}, + {0x00000D17, 0x00000000}, + {0x00000D19, 0x00000000}, + {0x00000D1A, 0x00000000}, + {0x00000D1B, 0x00000000}, + {0x00000D1D, 0x00000140}, + {0x00000D1E, 0x00000000}, + {0x00000D1F, 0x00000000}, + {0x00000D20, 0x10100200}, + {0x00000D21, 0x00000000}, + {0x00000D22, 0x00000000}, + {0x00000D23, 0x00000000}, + {0x00000D24, 0x10210200}, + {0x00000D25, 0x00000000}, + {0x00000D26, 0x00000000}, + {0x00000D27, 0x00000000}, + {0x00000D28, 0x10420200}, + {0x00000D29, 0x00000000}, + {0x00000D2A, 0x00000000}, + {0x00000D2B, 0x00000000}, + {0x00000D2C, 0x10830200}, + {0x00000D2D, 0x00000000}, + {0x00000D2E, 0x00000000}, + {0x00000D2F, 0x00000000}, + {0x00000D31, 0x00000000}, + {0x00000D32, 0x00000000}, + {0x00000D33, 0x00000000} +}; +static unsigned nv3TablePRAMIN_8BPP[][2] = +{ + /* 0xXXXXX3XX For MSB mono format */ + /* 0xXXXXX2XX For LSB mono format */ + {0x00000D04, 0x10110203}, + {0x00000D08, 0x10110203}, + {0x00000D0C, 0x1011020B}, + {0x00000D10, 0x10118203}, + {0x00000D14, 0x10110203}, + {0x00000D18, 0x10110203}, + {0x00000D1C, 0x10419208}, + {0x00000D30, 0x10118203} +}; +static unsigned nv3TablePRAMIN_15BPP[][2] = +{ + /* 0xXXXXX2XX For MSB mono format */ + /* 0xXXXXX3XX For LSB mono format */ + {0x00000D04, 0x10110200}, + {0x00000D08, 0x10110200}, + {0x00000D0C, 0x10110208}, + {0x00000D10, 0x10118200}, + {0x00000D14, 0x10110200}, + {0x00000D18, 0x10110200}, + {0x00000D1C, 0x10419208}, + {0x00000D30, 0x10118200} +}; +static unsigned nv3TablePRAMIN_32BPP[][2] = +{ + /* 0xXXXXX3XX For MSB mono format */ + /* 0xXXXXX2XX For LSB mono format */ + {0x00000D04, 0x10110201}, + {0x00000D08, 0x10110201}, + {0x00000D0C, 0x10110209}, + {0x00000D10, 0x10118201}, + {0x00000D14, 0x10110201}, + {0x00000D18, 0x10110201}, + {0x00000D1C, 0x10419208}, + {0x00000D30, 0x10118201} +}; +static unsigned nv4TableFIFO[][2] = +{ + {0x00003800, 0x80000014} +}; +static unsigned nv4TablePFIFO[][2] = +{ + {0x00000140, 0x00000000}, + {0x00000480, 0x00000000}, + {0x00000494, 0x00000000}, + {0x00000481, 0x00000000}, + {0x0000048B, 0x00000000}, + {0x00000400, 0x00000000}, + {0x00000414, 0x00000000}, + {0x00000084, 0x03000100}, + {0x00000085, 0x00000110}, + {0x00000086, 0x00000112}, + {0x00000143, 0x0000FFFF}, + {0x00000496, 0x0000FFFF}, + {0x00000050, 0x00000000}, + {0x00000040, 0xFFFFFFFF}, + {0x00000415, 0x00000001}, + {0x00000480, 0x00000001}, + {0x00000494, 0x00000001}, + {0x00000495, 0x00000001}, + {0x00000140, 0x00000001} +}; +static unsigned nv4TablePGRAPH[][2] = +{ + {0x00000020, 0x1231C001}, + {0x00000021, 0x72111101}, + {0x00000022, 0x11D5F071}, + {0x00000023, 0x10D4FF31}, + {0x00000060, 0x00000000}, + {0x00000068, 0x00000000}, + {0x00000070, 0x00000000}, + {0x00000078, 0x00000000}, + {0x00000061, 0x00000000}, + {0x00000069, 0x00000000}, + {0x00000071, 0x00000000}, + {0x00000079, 0x00000000}, + {0x00000062, 0x00000000}, + {0x0000006A, 0x00000000}, + {0x00000072, 0x00000000}, + {0x0000007A, 0x00000000}, + {0x00000063, 0x00000000}, + {0x0000006B, 0x00000000}, + {0x00000073, 0x00000000}, + {0x0000007B, 0x00000000}, + {0x00000064, 0x00000000}, + {0x0000006C, 0x00000000}, + {0x00000074, 0x00000000}, + {0x0000007C, 0x00000000}, + {0x00000065, 0x00000000}, + {0x0000006D, 0x00000000}, + {0x00000075, 0x00000000}, + {0x0000007D, 0x00000000}, + {0x00000066, 0x00000000}, + {0x0000006E, 0x00000000}, + {0x00000076, 0x00000000}, + {0x0000007E, 0x00000000}, + {0x00000067, 0x00000000}, + {0x0000006F, 0x00000000}, + {0x00000077, 0x00000000}, + {0x0000007F, 0x00000000}, + {0x00000058, 0x00000000}, + {0x00000059, 0x00000000}, + {0x0000005A, 0x00000000}, + {0x0000005B, 0x00000000}, + {0x00000196, 0x00000000}, + {0x000001A1, 0x01FFFFFF}, + {0x00000197, 0x00000000}, + {0x000001A2, 0x01FFFFFF}, + {0x00000198, 0x00000000}, + {0x000001A3, 0x01FFFFFF}, + {0x00000199, 0x00000000}, + {0x000001A4, 0x01FFFFFF}, + {0x00000050, 0x00000000}, + {0x00000040, 0xFFFFFFFF}, + {0x0000005C, 0x10010100}, + {0x000001C4, 0xFFFFFFFF}, + {0x000001C8, 0x00000001}, + {0x00000204, 0x00000000}, + {0x000001C3, 0x00000001} +}; +static unsigned nv4TablePGRAPH_8BPP[][2] = +{ + {0x000001C9, 0x00111111}, + {0x00000186, 0x00001010}, + {0x0000020C, 0x03020202} +}; +static unsigned nv4TablePGRAPH_15BPP[][2] = +{ + {0x000001C9, 0x00226222}, + {0x00000186, 0x00002071}, + {0x0000020C, 0x09080808} +}; +static unsigned nv4TablePGRAPH_16BPP[][2] = +{ + {0x000001C9, 0x00556555}, + {0x00000186, 0x000050C2}, + {0x0000020C, 0x0C0B0B0B} +}; +static unsigned nv4TablePGRAPH_32BPP[][2] = +{ + {0x000001C9, 0x0077D777}, + {0x00000186, 0x000070E5}, + {0x0000020C, 0x0E0D0D0D} +}; +static unsigned nv4TablePRAMIN[][2] = +{ + {0x00000000, 0x80000010}, + {0x00000001, 0x80011145}, + {0x00000002, 0x80000011}, + {0x00000003, 0x80011146}, + {0x00000004, 0x80000012}, + {0x00000005, 0x80011147}, + {0x00000006, 0x80000013}, + {0x00000007, 0x80011148}, + {0x00000008, 0x80000014}, + {0x00000009, 0x80011149}, + {0x0000000A, 0x80000015}, + {0x0000000B, 0x8001114A}, + {0x0000000C, 0x80000016}, + {0x0000000D, 0x8001114F}, + {0x00000020, 0x80000000}, + {0x00000021, 0x80011142}, + {0x00000022, 0x80000001}, + {0x00000023, 0x80011143}, + {0x00000024, 0x80000002}, + {0x00000025, 0x80011144}, + {0x00000026, 0x80000003}, + {0x00000027, 0x8001114B}, + {0x00000028, 0x80000004}, + {0x00000029, 0x8001114C}, + {0x0000002A, 0x80000005}, + {0x0000002B, 0x8001114D}, + {0x0000002C, 0x80000006}, + {0x0000002D, 0x8001114E}, + {0x00000500, 0x00003000}, + {0x00000501, 0x01FFFFFF}, + {0x00000502, 0x00000002}, + {0x00000503, 0x00000002}, + {0x00000508, 0x01008043}, + {0x0000050A, 0x00000000}, + {0x0000050B, 0x00000000}, + {0x0000050C, 0x01008019}, + {0x0000050E, 0x00000000}, + {0x0000050F, 0x00000000}, +#if 1 + {0x00000510, 0x01008018}, +#else + {0x00000510, 0x01008044}, +#endif + {0x00000512, 0x00000000}, + {0x00000513, 0x00000000}, + {0x00000514, 0x01008021}, + {0x00000516, 0x00000000}, + {0x00000517, 0x00000000}, + {0x00000518, 0x0100805F}, + {0x0000051A, 0x00000000}, + {0x0000051B, 0x00000000}, +#if 1 + {0x0000051C, 0x0100804B}, +#else + {0x0000051C, 0x0100804A}, +#endif + {0x0000051E, 0x00000000}, + {0x0000051F, 0x00000000}, + {0x00000520, 0x0100A048}, + {0x00000521, 0x00000D01}, + {0x00000522, 0x11401140}, + {0x00000523, 0x00000000}, + {0x00000524, 0x0300A054}, + {0x00000525, 0x00000D01}, + {0x00000526, 0x11401140}, + {0x00000527, 0x00000000}, + {0x00000528, 0x0300A055}, + {0x00000529, 0x00000D01}, + {0x0000052A, 0x11401140}, + {0x0000052B, 0x00000000}, + {0x0000052C, 0x00000058}, + {0x0000052E, 0x11401140}, + {0x0000052F, 0x00000000}, + {0x00000530, 0x00000059}, + {0x00000532, 0x11401140}, + {0x00000533, 0x00000000}, + {0x00000534, 0x0000005A}, + {0x00000536, 0x11401140}, + {0x00000537, 0x00000000}, + {0x00000538, 0x0000005B}, + {0x0000053A, 0x11401140}, + {0x0000053B, 0x00000000}, + {0x0000053C, 0x0300A01C}, + {0x0000053E, 0x11401140}, + {0x0000053F, 0x00000000} +}; +static unsigned nv4TablePRAMIN_8BPP[][2] = +{ + /* 0xXXXXXX01 For MSB mono format */ + /* 0xXXXXXX02 For LSB mono format */ + {0x00000509, 0x00000302}, + {0x0000050D, 0x00000302}, + {0x00000511, 0x00000202}, + {0x00000515, 0x00000302}, + {0x00000519, 0x00000302}, + {0x0000051D, 0x00000302}, + {0x0000052D, 0x00000302}, + {0x0000052E, 0x00000302}, + {0x00000535, 0x00000000}, + {0x00000539, 0x00000000}, + {0x0000053D, 0x00000302} +}; +static unsigned nv4TablePRAMIN_15BPP[][2] = +{ + /* 0xXXXXXX01 For MSB mono format */ + /* 0xXXXXXX02 For LSB mono format */ + {0x00000509, 0x00000902}, + {0x0000050D, 0x00000902}, + {0x00000511, 0x00000802}, + {0x00000515, 0x00000902}, + {0x00000519, 0x00000902}, + {0x0000051D, 0x00000902}, + {0x0000052D, 0x00000902}, + {0x0000052E, 0x00000902}, + {0x00000535, 0x00000702}, + {0x00000539, 0x00000702}, + {0x0000053D, 0x00000902} +}; +static unsigned nv4TablePRAMIN_16BPP[][2] = +{ + /* 0xXXXXXX01 For MSB mono format */ + /* 0xXXXXXX02 For LSB mono format */ + {0x00000509, 0x00000C02}, + {0x0000050D, 0x00000C02}, + {0x00000511, 0x00000B02}, + {0x00000515, 0x00000C02}, + {0x00000519, 0x00000C02}, + {0x0000051D, 0x00000C02}, + {0x0000052D, 0x00000C02}, + {0x0000052E, 0x00000C02}, + {0x00000535, 0x00000702}, + {0x00000539, 0x00000702}, + {0x0000053D, 0x00000C02} +}; +static unsigned nv4TablePRAMIN_32BPP[][2] = +{ + /* 0xXXXXXX01 For MSB mono format */ + /* 0xXXXXXX02 For LSB mono format */ + {0x00000509, 0x00000E02}, + {0x0000050D, 0x00000E02}, + {0x00000511, 0x00000D02}, + {0x00000515, 0x00000E02}, + {0x00000519, 0x00000E02}, + {0x0000051D, 0x00000E02}, + {0x0000052D, 0x00000E02}, + {0x0000052E, 0x00000E02}, + {0x00000535, 0x00000E02}, + {0x00000539, 0x00000E02}, + {0x0000053D, 0x00000E02} +}; +static unsigned nv10TableFIFO[][2] = +{ + {0x00003800, 0x80000014} +}; +static unsigned nv10TablePFIFO[][2] = +{ + {0x00000140, 0x00000000}, + {0x00000480, 0x00000000}, + {0x00000494, 0x00000000}, + {0x00000481, 0x00000000}, + {0x0000048B, 0x00000000}, + {0x00000400, 0x00000000}, + {0x00000414, 0x00000000}, + {0x00000084, 0x03000100}, + {0x00000085, 0x00000110}, + {0x00000086, 0x00000112}, + {0x00000143, 0x0000FFFF}, + {0x00000496, 0x0000FFFF}, + {0x00000050, 0x00000000}, + {0x00000040, 0xFFFFFFFF}, + {0x00000415, 0x00000001}, + {0x00000480, 0x00000001}, + {0x00000494, 0x00000001}, + {0x00000495, 0x00000001}, + {0x00000140, 0x00000001} +}; +static unsigned nv10TablePGRAPH[][2] = +{ + {0x00000020, 0x0003FFFF}, + {0x00000021, 0x00118701}, + {0x00000022, 0x24F82AD9}, + {0x00000023, 0x55DE0030}, + {0x00000020, 0x00000000}, + {0x00000024, 0x00000000}, + {0x00000058, 0x00000000}, + {0x00000060, 0x00000000}, + {0x00000068, 0x00000000}, + {0x00000070, 0x00000000}, + {0x00000078, 0x00000000}, + {0x00000059, 0x00000000}, + {0x00000061, 0x00000000}, + {0x00000069, 0x00000000}, + {0x00000071, 0x00000000}, + {0x00000079, 0x00000000}, + {0x0000005A, 0x00000000}, + {0x00000062, 0x00000000}, + {0x0000006A, 0x00000000}, + {0x00000072, 0x00000000}, + {0x0000007A, 0x00000000}, + {0x0000005B, 0x00000000}, + {0x00000063, 0x00000000}, + {0x0000006B, 0x00000000}, + {0x00000073, 0x00000000}, + {0x0000007B, 0x00000000}, + {0x0000005C, 0x00000000}, + {0x00000064, 0x00000000}, + {0x0000006C, 0x00000000}, + {0x00000074, 0x00000000}, + {0x0000007C, 0x00000000}, + {0x0000005D, 0x00000000}, + {0x00000065, 0x00000000}, + {0x0000006D, 0x00000000}, + {0x00000075, 0x00000000}, + {0x0000007D, 0x00000000}, + {0x0000005E, 0x00000000}, + {0x00000066, 0x00000000}, + {0x0000006E, 0x00000000}, + {0x00000076, 0x00000000}, + {0x0000007E, 0x00000000}, + {0x0000005F, 0x00000000}, + {0x00000067, 0x00000000}, + {0x0000006F, 0x00000000}, + {0x00000077, 0x00000000}, + {0x0000007F, 0x00000000}, + {0x00000053, 0x00000000}, + {0x00000054, 0x00000000}, + {0x00000055, 0x00000000}, + {0x00000056, 0x00000000}, + {0x00000057, 0x00000000}, + {0x00000196, 0x00000000}, + {0x000001A1, 0x01FFFFFF}, + {0x00000197, 0x00000000}, + {0x000001A2, 0x01FFFFFF}, + {0x00000198, 0x00000000}, + {0x000001A3, 0x01FFFFFF}, + {0x00000199, 0x00000000}, + {0x000001A4, 0x01FFFFFF}, + {0x0000019A, 0x00000000}, + {0x000001A5, 0x01FFFFFF}, + {0x0000019B, 0x00000000}, + {0x000001A6, 0x01FFFFFF}, + {0x00000050, 0x01111111}, + {0x00000040, 0xFFFFFFFF}, + {0x00000051, 0x10010100}, + {0x000001C5, 0xFFFFFFFF}, + {0x000001C8, 0x00000001}, + {0x00000204, 0x00000000}, + {0x000001C4, 0x00000001} +}; +static unsigned nv10TablePGRAPH_8BPP[][2] = +{ + {0x000001C9, 0x00111111}, + {0x00000186, 0x00001010}, + {0x0000020C, 0x03020202} +}; +static unsigned nv10TablePGRAPH_15BPP[][2] = +{ + {0x000001C9, 0x00226222}, + {0x00000186, 0x00002071}, + {0x0000020C, 0x09080808} +}; +static unsigned nv10TablePGRAPH_16BPP[][2] = +{ + {0x000001C9, 0x00556555}, + {0x00000186, 0x000050C2}, + {0x0000020C, 0x000B0B0C} +}; +static unsigned nv10TablePGRAPH_32BPP[][2] = +{ + {0x000001C9, 0x0077D777}, + {0x00000186, 0x000070E5}, + {0x0000020C, 0x0E0D0D0D} +}; +static unsigned nv10tri05TablePGRAPH[][2] = +{ + {(0x00000E00/4), 0x00000000}, + {(0x00000E04/4), 0x00000000}, + {(0x00000E08/4), 0x00000000}, + {(0x00000E0C/4), 0x00000000}, + {(0x00000E10/4), 0x00001000}, + {(0x00000E14/4), 0x00001000}, + {(0x00000E18/4), 0x4003ff80}, + {(0x00000E1C/4), 0x00000000}, + {(0x00000E20/4), 0x00000000}, + {(0x00000E24/4), 0x00000000}, + {(0x00000E28/4), 0x00000000}, + {(0x00000E2C/4), 0x00000000}, + {(0x00000E30/4), 0x00080008}, + {(0x00000E34/4), 0x00080008}, + {(0x00000E38/4), 0x00000000}, + {(0x00000E3C/4), 0x00000000}, + {(0x00000E40/4), 0x00000000}, + {(0x00000E44/4), 0x00000000}, + {(0x00000E48/4), 0x00000000}, + {(0x00000E4C/4), 0x00000000}, + {(0x00000E50/4), 0x00000000}, + {(0x00000E54/4), 0x00000000}, + {(0x00000E58/4), 0x00000000}, + {(0x00000E5C/4), 0x00000000}, + {(0x00000E60/4), 0x00000000}, + {(0x00000E64/4), 0x10000000}, + {(0x00000E68/4), 0x00000000}, + {(0x00000E6C/4), 0x00000000}, + {(0x00000E70/4), 0x00000000}, + {(0x00000E74/4), 0x00000000}, + {(0x00000E78/4), 0x00000000}, + {(0x00000E7C/4), 0x00000000}, + {(0x00000E80/4), 0x00000000}, + {(0x00000E84/4), 0x00000000}, + {(0x00000E88/4), 0x08000000}, + {(0x00000E8C/4), 0x00000000}, + {(0x00000E90/4), 0x00000000}, + {(0x00000E94/4), 0x00000000}, + {(0x00000E98/4), 0x00000000}, + {(0x00000E9C/4), 0x4B7FFFFF}, + {(0x00000EA0/4), 0x00000000}, + {(0x00000EA4/4), 0x00000000}, + {(0x00000EA8/4), 0x00000000}, + {(0x00000F00/4), 0x07FF0800}, + {(0x00000F04/4), 0x07FF0800}, + {(0x00000F08/4), 0x07FF0800}, + {(0x00000F0C/4), 0x07FF0800}, + {(0x00000F10/4), 0x07FF0800}, + {(0x00000F14/4), 0x07FF0800}, + {(0x00000F18/4), 0x07FF0800}, + {(0x00000F1C/4), 0x07FF0800}, + {(0x00000F20/4), 0x07FF0800}, + {(0x00000F24/4), 0x07FF0800}, + {(0x00000F28/4), 0x07FF0800}, + {(0x00000F2C/4), 0x07FF0800}, + {(0x00000F30/4), 0x07FF0800}, + {(0x00000F34/4), 0x07FF0800}, + {(0x00000F38/4), 0x07FF0800}, + {(0x00000F3C/4), 0x07FF0800}, + {(0x00000F40/4), 0x10000000}, + {(0x00000F44/4), 0x00000000}, + {(0x00000F50/4), 0x00006740}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F50/4), 0x00006750}, + {(0x00000F54/4), 0x40000000}, + {(0x00000F54/4), 0x40000000}, + {(0x00000F54/4), 0x40000000}, + {(0x00000F54/4), 0x40000000}, + {(0x00000F50/4), 0x00006760}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F50/4), 0x00006770}, + {(0x00000F54/4), 0xC5000000}, + {(0x00000F54/4), 0xC5000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F50/4), 0x00006780}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F50/4), 0x000067A0}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F50/4), 0x00006AB0}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F50/4), 0x00006AC0}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F50/4), 0x00006C10}, + {(0x00000F54/4), 0xBF800000}, + {(0x00000F50/4), 0x00007030}, + {(0x00000F54/4), 0x7149F2CA}, + {(0x00000F50/4), 0x00007040}, + {(0x00000F54/4), 0x7149F2CA}, + {(0x00000F50/4), 0x00007050}, + {(0x00000F54/4), 0x7149F2CA}, + {(0x00000F50/4), 0x00007060}, + {(0x00000F54/4), 0x7149F2CA}, + {(0x00000F50/4), 0x00007070}, + {(0x00000F54/4), 0x7149F2CA}, + {(0x00000F50/4), 0x00007080}, + {(0x00000F54/4), 0x7149F2CA}, + {(0x00000F50/4), 0x00007090}, + {(0x00000F54/4), 0x7149F2CA}, + {(0x00000F50/4), 0x000070A0}, + {(0x00000F54/4), 0x7149F2CA}, + {(0x00000F50/4), 0x00006A80}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F50/4), 0x00006AA0}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F50/4), 0x00000040}, + {(0x00000F54/4), 0x00000005}, + {(0x00000F50/4), 0x00006400}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F54/4), 0x4B7FFFFF}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F50/4), 0x00006410}, + {(0x00000F54/4), 0xC5000000}, + {(0x00000F54/4), 0xC5000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F50/4), 0x00006420}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F50/4), 0x00006430}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F50/4), 0x000064C0}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F54/4), 0x477FFFFF}, + {(0x00000F54/4), 0x3F800000}, + {(0x00000F50/4), 0x000064D0}, + {(0x00000F54/4), 0xC5000000}, + {(0x00000F54/4), 0xC5000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F50/4), 0x000064E0}, + {(0x00000F54/4), 0xC4FFF000}, + {(0x00000F54/4), 0xC4FFF000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F50/4), 0x000064F0}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F54/4), 0x00000000}, + {(0x00000F40/4), 0x30000000}, + {(0x00000F44/4), 0x00000004}, + {(0x00000F48/4), 0x10000000}, + {(0x00000F4C/4), 0x00000000} +}; +static unsigned nv10TablePRAMIN[][2] = +{ + {0x00000000, 0x80000010}, + {0x00000001, 0x80011145}, + {0x00000002, 0x80000011}, + {0x00000003, 0x80011146}, + {0x00000004, 0x80000012}, + {0x00000005, 0x80011147}, + {0x00000006, 0x80000013}, + {0x00000007, 0x80011148}, + {0x00000008, 0x80000014}, + {0x00000009, 0x80011149}, + {0x0000000A, 0x80000015}, + {0x0000000B, 0x8001114A}, + {0x0000000C, 0x80000016}, + {0x0000000D, 0x80011150}, + {0x00000020, 0x80000000}, + {0x00000021, 0x80011142}, + {0x00000022, 0x80000001}, + {0x00000023, 0x80011143}, + {0x00000024, 0x80000002}, + {0x00000025, 0x80011144}, + {0x00000026, 0x80000003}, + {0x00000027, 0x8001114B}, + {0x00000028, 0x80000004}, + {0x00000029, 0x8001114C}, + {0x0000002A, 0x80000005}, + {0x0000002B, 0x8001114D}, + {0x0000002C, 0x80000006}, + {0x0000002D, 0x8001114E}, + {0x0000002E, 0x80000007}, + {0x0000002F, 0x8001114F}, + {0x00000500, 0x00003000}, + {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}, +#ifdef __BIG_ENDIAN + {0x00000510, 0x01088018}, +#else + {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}, +#ifdef __BIG_ENDIAN + {0x0000051C, 0x0108804B}, +#else + {0x0000051C, 0x0100804B}, +#endif + {0x0000051E, 0x00000000}, + {0x0000051F, 0x00000000}, + {0x00000520, 0x0100A048}, + {0x00000521, 0x00000D01}, + {0x00000522, 0x11401140}, + {0x00000523, 0x00000000}, + {0x00000524, 0x0300A094}, + {0x00000525, 0x00000D01}, + {0x00000526, 0x11401140}, + {0x00000527, 0x00000000}, + {0x00000528, 0x0300A095}, + {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}, + {0x00000536, 0x11401140}, + {0x00000537, 0x00000000}, + {0x00000538, 0x0000005B}, + {0x0000053A, 0x11401140}, + {0x0000053B, 0x00000000}, + {0x0000053C, 0x00000093}, + {0x0000053E, 0x11401140}, + {0x0000053F, 0x00000000}, +#ifdef __BIG_ENDIAN + {0x00000540, 0x0308A01C}, +#else + {0x00000540, 0x0300A01C}, +#endif + {0x00000542, 0x11401140}, + {0x00000543, 0x00000000} +}; +static unsigned nv10TablePRAMIN_8BPP[][2] = +{ + /* 0xXXXXXX01 For MSB mono format */ + /* 0xXXXXXX02 For LSB mono format */ + {0x00000509, 0x00000302}, + {0x0000050D, 0x00000302}, + {0x00000511, 0x00000202}, + {0x00000515, 0x00000302}, + {0x00000519, 0x00000302}, + {0x0000051D, 0x00000302}, + {0x0000052D, 0x00000302}, + {0x0000052E, 0x00000302}, + {0x00000535, 0x00000000}, + {0x00000539, 0x00000000}, + {0x0000053D, 0x00000000}, + {0x00000541, 0x00000302} +}; +static unsigned nv10TablePRAMIN_15BPP[][2] = +{ + /* 0xXXXXXX01 For MSB mono format */ + /* 0xXXXXXX02 For LSB mono format */ + {0x00000509, 0x00000902}, + {0x0000050D, 0x00000902}, + {0x00000511, 0x00000802}, + {0x00000515, 0x00000902}, + {0x00000519, 0x00000902}, + {0x0000051D, 0x00000902}, + {0x0000052D, 0x00000902}, + {0x0000052E, 0x00000902}, + {0x00000535, 0x00000902}, + {0x00000539, 0x00000902}, + {0x0000053D, 0x00000902}, + {0x00000541, 0x00000902} +}; +static unsigned nv10TablePRAMIN_16BPP[][2] = +{ + /* 0xXXXXXX01 For MSB mono format */ + /* 0xXXXXXX02 For LSB mono format */ + {0x00000509, 0x00000C02}, + {0x0000050D, 0x00000C02}, + {0x00000511, 0x00000B02}, + {0x00000515, 0x00000C02}, + {0x00000519, 0x00000C02}, + {0x0000051D, 0x00000C02}, + {0x0000052D, 0x00000C02}, + {0x0000052E, 0x00000C02}, + {0x00000535, 0x00000C02}, + {0x00000539, 0x00000C02}, + {0x0000053D, 0x00000C02}, + {0x00000541, 0x00000C02} +}; +static unsigned nv10TablePRAMIN_32BPP[][2] = +{ + /* 0xXXXXXX01 For MSB mono format */ + /* 0xXXXXXX02 For LSB mono format */ + {0x00000509, 0x00000E02}, + {0x0000050D, 0x00000E02}, + {0x00000511, 0x00000D02}, + {0x00000515, 0x00000E02}, + {0x00000519, 0x00000E02}, + {0x0000051D, 0x00000E02}, + {0x0000052D, 0x00000E02}, + {0x0000052E, 0x00000E02}, + {0x00000535, 0x00000E02}, + {0x00000539, 0x00000E02}, + {0x0000053D, 0x00000E02}, + {0x00000541, 0x00000E02} +}; + diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c new file mode 100644 index 000000000000..da1334dfd51d --- /dev/null +++ b/drivers/video/riva/rivafb-i2c.c @@ -0,0 +1,214 @@ +/* + * linux/drivers/video/riva/fbdev-i2c.c - nVidia i2c + * + * Maintained by Ani Joshi <ajoshi@shell.unixbox.com> + * + * Copyright 2004 Antonino A. Daplas <adaplas @pol.net> + * + * Based on radeonfb-i2c.c + * + * 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/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/fb.h> +#include <linux/jiffies.h> + +#include <asm/io.h> + +#include "rivafb.h" +#include "../edid.h" + +#define RIVA_DDC 0x50 + +static void riva_gpio_setscl(void* data, int state) +{ + struct riva_i2c_chan *chan = (struct riva_i2c_chan *)data; + struct riva_par *par = chan->par; + u32 val; + + VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base + 1); + val = VGA_RD08(par->riva.PCIO, 0x3d5) & 0xf0; + + if (state) + val |= 0x20; + else + val &= ~0x20; + + VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base + 1); + VGA_WR08(par->riva.PCIO, 0x3d5, val | 0x1); +} + +static void riva_gpio_setsda(void* data, int state) +{ + struct riva_i2c_chan *chan = (struct riva_i2c_chan *)data; + struct riva_par *par = chan->par; + u32 val; + + VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base + 1); + val = VGA_RD08(par->riva.PCIO, 0x3d5) & 0xf0; + + if (state) + val |= 0x10; + else + val &= ~0x10; + + VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base + 1); + VGA_WR08(par->riva.PCIO, 0x3d5, val | 0x1); +} + +static int riva_gpio_getscl(void* data) +{ + struct riva_i2c_chan *chan = (struct riva_i2c_chan *)data; + struct riva_par *par = chan->par; + u32 val = 0; + + VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base); + if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x04) + val = 1; + + val = VGA_RD08(par->riva.PCIO, 0x3d5); + + return val; +} + +static int riva_gpio_getsda(void* data) +{ + struct riva_i2c_chan *chan = (struct riva_i2c_chan *)data; + struct riva_par *par = chan->par; + u32 val = 0; + + VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base); + if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x08) + val = 1; + + return val; +} + +#define I2C_ALGO_RIVA 0x0e0000 +static int riva_setup_i2c_bus(struct riva_i2c_chan *chan, const char *name) +{ + int rc; + + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_ALGO_RIVA; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->par->pdev->dev; + chan->algo.setsda = riva_gpio_setsda; + chan->algo.setscl = riva_gpio_setscl; + chan->algo.getsda = riva_gpio_getsda; + chan->algo.getscl = riva_gpio_getscl; + chan->algo.udelay = 40; + chan->algo.timeout = msecs_to_jiffies(2); + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + /* Raise SCL and SDA */ + riva_gpio_setsda(chan, 1); + riva_gpio_setscl(chan, 1); + udelay(20); + + rc = i2c_bit_add_bus(&chan->adapter); + if (rc == 0) + dev_dbg(&chan->par->pdev->dev, "I2C bus %s registered.\n", name); + else { + dev_warn(&chan->par->pdev->dev, + "Failed to register I2C bus %s.\n", name); + chan->par = NULL; + } + + return rc; +} + +void riva_create_i2c_busses(struct riva_par *par) +{ + par->bus = 3; + + par->chan[0].par = par; + par->chan[1].par = par; + par->chan[2].par = par; + + par->chan[0].ddc_base = 0x3e; + par->chan[1].ddc_base = 0x36; + par->chan[2].ddc_base = 0x50; + riva_setup_i2c_bus(&par->chan[0], "BUS1"); + riva_setup_i2c_bus(&par->chan[1], "BUS2"); + riva_setup_i2c_bus(&par->chan[2], "BUS3"); +} + +void riva_delete_i2c_busses(struct riva_par *par) +{ + if (par->chan[0].par) + i2c_bit_del_bus(&par->chan[0].adapter); + par->chan[0].par = NULL; + + if (par->chan[1].par) + i2c_bit_del_bus(&par->chan[1].adapter); + par->chan[1].par = NULL; + + if (par->chan[2].par) + i2c_bit_del_bus(&par->chan[2].adapter); + par->chan[2].par = NULL; +} + +static u8 *riva_do_probe_i2c_edid(struct riva_i2c_chan *chan) +{ + u8 start = 0x0; + struct i2c_msg msgs[] = { + { + .addr = RIVA_DDC, + .len = 1, + .buf = &start, + }, { + .addr = RIVA_DDC, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + }, + }; + u8 *buf; + + if (!chan->par) + return NULL; + + buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!buf) { + dev_warn(&chan->par->pdev->dev, "Out of memory!\n"); + return NULL; + } + msgs[1].buf = buf; + + if (i2c_transfer(&chan->adapter, msgs, 2) == 2) + return buf; + dev_dbg(&chan->par->pdev->dev, "Unable to read EDID block.\n"); + kfree(buf); + return NULL; +} + +int riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid) +{ + u8 *edid = NULL; + int i; + + for (i = 0; i < 3; i++) { + /* Do the real work */ + edid = riva_do_probe_i2c_edid(&par->chan[conn-1]); + if (edid) + break; + } + if (out_edid) + *out_edid = edid; + if (!edid) + return 1; + + return 0; +} + diff --git a/drivers/video/riva/rivafb.h b/drivers/video/riva/rivafb.h new file mode 100644 index 000000000000..440ff445689b --- /dev/null +++ b/drivers/video/riva/rivafb.h @@ -0,0 +1,79 @@ +#ifndef __RIVAFB_H +#define __RIVAFB_H + +#include <linux/config.h> +#include <linux/fb.h> +#include <video/vga.h> +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/i2c-algo-bit.h> + +#include "riva_hw.h" + +/* GGI compatibility macros */ +#define NUM_SEQ_REGS 0x05 +#define NUM_CRT_REGS 0x41 +#define NUM_GRC_REGS 0x09 +#define NUM_ATC_REGS 0x15 + +/* I2C */ +#define DDC_SCL_READ_MASK (1 << 2) +#define DDC_SCL_WRITE_MASK (1 << 5) +#define DDC_SDA_READ_MASK (1 << 3) +#define DDC_SDA_WRITE_MASK (1 << 4) + +/* holds the state of the VGA core and extended Riva hw state from riva_hw.c. + * From KGI originally. */ +struct riva_regs { + u8 attr[NUM_ATC_REGS]; + u8 crtc[NUM_CRT_REGS]; + u8 gra[NUM_GRC_REGS]; + u8 seq[NUM_SEQ_REGS]; + u8 misc_output; + RIVA_HW_STATE ext; +}; + +struct riva_par; + +struct riva_i2c_chan { + struct riva_par *par; + unsigned long ddc_base; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; +}; + +struct riva_par { + RIVA_HW_INST riva; /* interface to riva_hw.c */ + u32 pseudo_palette[16]; /* default palette */ + u32 palette[16]; /* for Riva128 */ + u8 __iomem *ctrl_base; /* virtual control register base addr */ + unsigned dclk_max; /* max DCLK */ + + struct riva_regs initial_state; /* initial startup video mode */ + struct riva_regs current_state; +#ifdef CONFIG_X86 + struct vgastate state; +#endif + atomic_t ref_count; + unsigned char *EDID; + unsigned int Chipset; + int forceCRTC; + Bool SecondCRTC; + int FlatPanel; + struct pci_dev *pdev; + int bus; + int cursor_reset; +#ifdef CONFIG_MTRR + struct { int vram; int vram_valid; } mtrr; +#endif + struct riva_i2c_chan chan[3]; +}; + +void riva_common_setup(struct riva_par *); +unsigned long riva_get_memlen(struct riva_par *); +unsigned long riva_get_maxdclk(struct riva_par *); +void riva_delete_i2c_busses(struct riva_par *par); +void riva_create_i2c_busses(struct riva_par *par); +int riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid); + +#endif /* __RIVAFB_H */ diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c new file mode 100644 index 000000000000..b637c389e4f4 --- /dev/null +++ b/drivers/video/s1d13xxxfb.c @@ -0,0 +1,772 @@ +/* drivers/video/s1d13xxxfb.c + * + * (c) 2004 Simtec Electronics + * (c) 2005 Thibaut VARENE <varenet@parisc-linux.org> + * + * Driver for Epson S1D13xxx series framebuffer chips + * + * Adapted from + * linux/drivers/video/skeletonfb.c + * linux/drivers/video/epson1355fb.c + * linux/drivers/video/epson/s1d13xxxfb.c (2.4 driver by Epson) + * + * Note, currently only tested on S1D13806 with 16bit CRT. + * As such, this driver might still contain some hardcoded bits relating to + * S1D13806. + * Making it work on other S1D13XXX chips should merely be a matter of adding + * a few switch()s, some missing glue here and there maybe, and split header + * files. + * + * TODO: - handle dual screen display (CRT and LCD at the same time). + * - check_var(), mode change, etc. + * - PM untested. + * - Accelerated interfaces. + * - Probably not SMP safe :) + * + * 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/config.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/delay.h> + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/fb.h> + +#include <asm/io.h> + +#include <video/s1d13xxxfb.h> + +#define PFX "s1d13xxxfb: " + +#if 0 +#define dbg(fmt, args...) do { printk(KERN_INFO fmt, ## args); } while(0) +#else +#define dbg(fmt, args...) do { } while (0) +#endif + +/* + * Here we define the default struct fb_fix_screeninfo + */ +static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = { + .id = S1D_FBID, + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .xpanstep = 0, + .ypanstep = 1, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +static inline u8 +s1d13xxxfb_readreg(struct s1d13xxxfb_par *par, u16 regno) +{ + return readb(par->regs + regno); +} + +static inline void +s1d13xxxfb_writereg(struct s1d13xxxfb_par *par, u16 regno, u8 value) +{ + writeb(value, par->regs + regno); +} + +static inline void +s1d13xxxfb_runinit(struct s1d13xxxfb_par *par, + const struct s1d13xxxfb_regval *initregs, + const unsigned int size) +{ + int i; + + for (i = 0; i < size; i++) { + if ((initregs[i].addr == S1DREG_DELAYOFF) || + (initregs[i].addr == S1DREG_DELAYON)) + mdelay((int)initregs[i].value); + else { + s1d13xxxfb_writereg(par, initregs[i].addr, initregs[i].value); + } + } + + /* make sure the hardware can cope with us */ + mdelay(1); +} + +static inline void +lcd_enable(struct s1d13xxxfb_par *par, int enable) +{ + u8 mode = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE); + + if (enable) + mode |= 0x01; + else + mode &= ~0x01; + + s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode); +} + +static inline void +crt_enable(struct s1d13xxxfb_par *par, int enable) +{ + u8 mode = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE); + + if (enable) + mode |= 0x02; + else + mode &= ~0x02; + + s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode); +} + +/* framebuffer control routines */ + +static inline void +s1d13xxxfb_setup_pseudocolour(struct fb_info *info) +{ + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + + info->var.red.length = 4; + info->var.green.length = 4; + info->var.blue.length = 4; +} + +static inline void +s1d13xxxfb_setup_truecolour(struct fb_info *info) +{ + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->var.bits_per_pixel = 16; + + info->var.red.length = 5; + info->var.red.offset = 11; + + info->var.green.length = 6; + info->var.green.offset = 5; + + info->var.blue.length = 5; + info->var.blue.offset = 0; +} + +/** + * s1d13xxxfb_set_par - Alters the hardware state. + * @info: frame buffer structure + * + * Using the fb_var_screeninfo in fb_info we set the depth of the + * framebuffer. This function alters the par AND the + * fb_fix_screeninfo stored in fb_info. It doesn't not alter var in + * 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. + * + * XXX TODO: write proper s1d13xxxfb_check_var(), without which that + * function is quite useless. + */ +static int +s1d13xxxfb_set_par(struct fb_info *info) +{ + struct s1d13xxxfb_par *s1dfb = info->par; + unsigned int val; + + dbg("s1d13xxxfb_set_par: bpp=%d\n", info->var.bits_per_pixel); + + if ((s1dfb->display & 0x01)) /* LCD */ + val = s1d13xxxfb_readreg(s1dfb, S1DREG_LCD_DISP_MODE); /* read colour control */ + else /* CRT */ + val = s1d13xxxfb_readreg(s1dfb, S1DREG_CRT_DISP_MODE); /* read colour control */ + + val &= ~0x07; + + switch (info->var.bits_per_pixel) { + case 4: + dbg("pseudo colour 4\n"); + s1d13xxxfb_setup_pseudocolour(info); + val |= 2; + break; + case 8: + dbg("pseudo colour 8\n"); + s1d13xxxfb_setup_pseudocolour(info); + val |= 3; + break; + case 16: + dbg("true colour\n"); + s1d13xxxfb_setup_truecolour(info); + val |= 5; + break; + + default: + dbg("bpp not supported!\n"); + return -EINVAL; + } + + dbg("writing %02x to display mode register\n", val); + + if ((s1dfb->display & 0x01)) /* LCD */ + s1d13xxxfb_writereg(s1dfb, S1DREG_LCD_DISP_MODE, val); + else /* CRT */ + s1d13xxxfb_writereg(s1dfb, S1DREG_CRT_DISP_MODE, val); + + info->fix.line_length = info->var.xres * info->var.bits_per_pixel; + info->fix.line_length /= 8; + + dbg("setting line_length to %d\n", info->fix.line_length); + + dbg("done setup\n"); + + return 0; +} + +/** + * s1d13xxxfb_setcolreg - sets a color register. + * @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. + * @info: frame buffer info structure + * + * Returns negative errno on error, or zero on success. + */ +static int +s1d13xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct s1d13xxxfb_par *s1dfb = info->par; + unsigned int pseudo_val; + + if (regno >= S1D_PALETTE_SIZE) + return -EINVAL; + + dbg("s1d13xxxfb_setcolreg: %d: rgb=%d,%d,%d, tr=%d\n", + regno, red, green, blue, transp); + + if (info->var.grayscale) + red = green = blue = (19595*red + 38470*green + 7471*blue) >> 16; + + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + if (regno >= 16) + return -EINVAL; + + /* deal with creating pseudo-palette entries */ + + pseudo_val = (red >> 11) << info->var.red.offset; + pseudo_val |= (green >> 10) << info->var.green.offset; + pseudo_val |= (blue >> 11) << info->var.blue.offset; + + dbg("s1d13xxxfb_setcolreg: pseudo %d, val %08x\n", + regno, pseudo_val); + + ((u32 *)info->pseudo_palette)[regno] = pseudo_val; + + break; + case FB_VISUAL_PSEUDOCOLOR: + s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_ADDR, regno); + s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, red); + s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, green); + s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, blue); + + break; + default: + return -ENOSYS; + } + + dbg("s1d13xxxfb_setcolreg: done\n"); + + return 0; +} + +/** + * s1d13xxxfb_blank - blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + * + * Blank the screen if blank_mode != 0, else unblank. Return 0 if + * blanking succeeded, != 0 if un-/blanking failed due to e.g. a + * video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + * + * Returns negative errno on error, or zero on success. + */ +static int +s1d13xxxfb_blank(int blank_mode, struct fb_info *info) +{ + struct s1d13xxxfb_par *par = info->par; + + dbg("s1d13xxxfb_blank: blank=%d, info=%p\n", blank_mode, info); + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + case FB_BLANK_NORMAL: + if ((par->display & 0x01) != 0) + lcd_enable(par, 1); + if ((par->display & 0x02) != 0) + crt_enable(par, 1); + break; + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + break; + case FB_BLANK_POWERDOWN: + lcd_enable(par, 0); + crt_enable(par, 0); + break; + default: + return -EINVAL; + } + + /* let fbcon do a soft blank for us */ + return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0); +} + +/** + * s1d13xxxfb_pan_display - Pans the display. + * @var: frame buffer variable screen structure + * @info: frame buffer structure that represents a single frame buffer + * + * Pan (or wrap, depending on the `vmode' field) the display using the + * `yoffset' field of the `var' structure (`xoffset' not yet supported). + * If the values don't fit, return -EINVAL. + * + * Returns negative errno on error, or zero on success. + */ +static int +s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct s1d13xxxfb_par *par = info->par; + u32 start; + + if (var->xoffset != 0) /* not yet ... */ + return -EINVAL; + + if (var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + + start = (info->fix.line_length >> 1) * var->yoffset; + + if ((par->display & 0x01)) { + /* LCD */ + s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START0, (start & 0xff)); + s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START1, ((start >> 8) & 0xff)); + s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START2, ((start >> 16) & 0x0f)); + } else { + /* CRT */ + s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START0, (start & 0xff)); + s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START1, ((start >> 8) & 0xff)); + s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START2, ((start >> 16) & 0x0f)); + } + + return 0; +} + + +/* framebuffer information structures */ + +static struct fb_ops s1d13xxxfb_fbops = { + .owner = THIS_MODULE, + .fb_set_par = s1d13xxxfb_set_par, + .fb_setcolreg = s1d13xxxfb_setcolreg, + .fb_blank = s1d13xxxfb_blank, + + .fb_pan_display = s1d13xxxfb_pan_display, + + /* to be replaced by any acceleration we can */ + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor +}; + +static int s1d13xxxfb_width_tab[2][4] __devinitdata = { + {4, 8, 16, -1}, + {9, 12, 18, -1}, +}; + +/** + * s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to + * hardware setup. + * @info: frame buffer structure + * + * We setup the framebuffer structures according to the current + * hardware setup. On some machines, the BIOS will have filled + * the chip registers with such info, on others, these values will + * have been written in some init procedure. In any case, the + * software values needs to match the hardware ones. This is what + * this function ensures. + * + * Note: some of the hardcoded values here might need some love to + * work on various chips, and might need to no longer be hardcoded. + */ +static void __devinit +s1d13xxxfb_fetch_hw_state(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct fb_fix_screeninfo *fix = &info->fix; + struct s1d13xxxfb_par *par = info->par; + u8 panel, display; + u16 offset; + u32 xres, yres; + u32 xres_virtual, yres_virtual; + int bpp, lcd_bpp; + int is_color, is_dual, is_tft; + int lcd_enabled, crt_enabled; + + fix->type = FB_TYPE_PACKED_PIXELS; + + /* general info */ + par->display = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE); + crt_enabled = (par->display & 0x02) != 0; + lcd_enabled = (par->display & 0x01) != 0; + + if (lcd_enabled && crt_enabled) + printk(KERN_WARNING PFX "Warning: LCD and CRT detected, using LCD\n"); + + if (lcd_enabled) + display = s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_MODE); + else /* CRT */ + display = s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_MODE); + + bpp = display & 0x07; + + switch (bpp) { + case 2: /* 4 bpp */ + case 3: /* 8 bpp */ + var->bits_per_pixel = 8; + var->red.offset = var->green.offset = var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = 8; + break; + case 5: /* 16 bpp */ + s1d13xxxfb_setup_truecolour(info); + break; + default: + dbg("bpp: %i\n", bpp); + } + fb_alloc_cmap(&info->cmap, 256, 0); + + /* LCD info */ + panel = s1d13xxxfb_readreg(par, S1DREG_PANEL_TYPE); + is_color = (panel & 0x04) != 0; + is_dual = (panel & 0x02) != 0; + is_tft = (panel & 0x01) != 0; + lcd_bpp = s1d13xxxfb_width_tab[is_tft][(panel >> 4) & 3]; + + if (lcd_enabled) { + xres = (s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_HWIDTH) + 1) * 8; + yres = (s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_VHEIGHT0) + + ((s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_VHEIGHT1) & 0x03) << 8) + 1); + + offset = (s1d13xxxfb_readreg(par, S1DREG_LCD_MEM_OFF0) + + ((s1d13xxxfb_readreg(par, S1DREG_LCD_MEM_OFF1) & 0x7) << 8)); + } else { /* crt */ + xres = (s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_HWIDTH) + 1) * 8; + yres = (s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_VHEIGHT0) + + ((s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_VHEIGHT1) & 0x03) << 8) + 1); + + offset = (s1d13xxxfb_readreg(par, S1DREG_CRT_MEM_OFF0) + + ((s1d13xxxfb_readreg(par, S1DREG_CRT_MEM_OFF1) & 0x7) << 8)); + } + xres_virtual = offset * 16 / var->bits_per_pixel; + yres_virtual = fix->smem_len / (offset * 2); + + var->xres = xres; + var->yres = yres; + var->xres_virtual = xres_virtual; + var->yres_virtual = yres_virtual; + var->xoffset = var->yoffset = 0; + + fix->line_length = offset * 2; + + var->grayscale = !is_color; + + var->activate = FB_ACTIVATE_NOW; + + dbg(PFX "bpp=%d, lcd_bpp=%d, " + "crt_enabled=%d, lcd_enabled=%d\n", + var->bits_per_pixel, lcd_bpp, crt_enabled, lcd_enabled); + dbg(PFX "xres=%d, yres=%d, vxres=%d, vyres=%d " + "is_color=%d, is_dual=%d, is_tft=%d\n", + xres, yres, xres_virtual, yres_virtual, is_color, is_dual, is_tft); +} + + +static int __devexit +s1d13xxxfb_remove(struct device *dev) +{ + struct fb_info *info = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct s1d13xxxfb_par *par = NULL; + + if (info) { + par = info->par; + if (par && par->regs) { + /* disable output & enable powersave */ + s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, 0x00); + s1d13xxxfb_writereg(par, S1DREG_PS_CNF, 0x11); + iounmap(par->regs); + } + + fb_dealloc_cmap(&info->cmap); + + if (info->screen_base) + iounmap(info->screen_base); + + framebuffer_release(info); + } + + release_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start +1); + release_mem_region(pdev->resource[1].start, + pdev->resource[1].end - pdev->resource[1].start +1); + return 0; +} + +static int __devinit +s1d13xxxfb_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct s1d13xxxfb_par *default_par; + struct fb_info *info; + struct s1d13xxxfb_pdata *pdata = NULL; + int ret = 0; + u8 revision; + + dbg("probe called: device is %p\n", dev); + + printk(KERN_INFO "Epson S1D13XXX FB Driver\n"); + + /* enable platform-dependent hardware glue, if any */ + if (dev->platform_data) + pdata = dev->platform_data; + + if (pdata && pdata->platform_init_video) + pdata->platform_init_video(); + + + if (pdev->num_resources != 2) { + dev_err(&pdev->dev, "invalid num_resources: %i\n", + pdev->num_resources); + ret = -ENODEV; + goto bail; + } + + /* resource[0] is VRAM, resource[1] is registers */ + if (pdev->resource[0].flags != IORESOURCE_MEM + || pdev->resource[1].flags != IORESOURCE_MEM) { + dev_err(&pdev->dev, "invalid resource type\n"); + ret = -ENODEV; + goto bail; + } + + if (!request_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start +1, "s1d13xxxfb mem")) { + dev_dbg(dev, "request_mem_region failed\n"); + ret = -EBUSY; + goto bail; + } + + if (!request_mem_region(pdev->resource[1].start, + pdev->resource[1].end - pdev->resource[1].start +1, "s1d13xxxfb regs")) { + dev_dbg(dev, "request_mem_region failed\n"); + ret = -EBUSY; + goto bail; + } + + info = framebuffer_alloc(sizeof(struct s1d13xxxfb_par) + sizeof(u32) * 256, &pdev->dev); + if (!info) { + ret = -ENOMEM; + goto bail; + } + + default_par = info->par; + default_par->regs = ioremap_nocache(pdev->resource[1].start, + pdev->resource[1].end - pdev->resource[1].start +1); + if (!default_par->regs) { + printk(KERN_ERR PFX "unable to map registers\n"); + ret = -ENOMEM; + goto bail; + } + info->pseudo_palette = default_par->pseudo_palette; + + info->screen_base = ioremap_nocache(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start +1); + + if (!info->screen_base) { + printk(KERN_ERR PFX "unable to map framebuffer\n"); + ret = -ENOMEM; + goto bail; + } + + revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE); + if ((revision >> 2) != S1D_CHIP_REV) { + printk(KERN_INFO PFX "chip not found: %i\n", (revision >> 2)); + ret = -ENODEV; + goto bail; + } + + info->fix = s1d13xxxfb_fix; + info->fix.mmio_start = pdev->resource[1].start; + info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start +1; + info->fix.smem_start = pdev->resource[0].start; + info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start +1; + + printk(KERN_INFO PFX "regs mapped at 0x%p, fb %d KiB mapped at 0x%p\n", + default_par->regs, info->fix.smem_len / 1024, info->screen_base); + + info->par = default_par; + info->fbops = &s1d13xxxfb_fbops; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + + /* perform "manual" chip initialization, if needed */ + if (pdata && pdata->initregs) + s1d13xxxfb_runinit(info->par, pdata->initregs, pdata->initregssize); + + s1d13xxxfb_fetch_hw_state(info); + + if (register_framebuffer(info) < 0) { + ret = -EINVAL; + goto bail; + } + + dev_set_drvdata(&pdev->dev, info); + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + info->node, info->fix.id); + + return 0; + +bail: + s1d13xxxfb_remove(dev); + return ret; + +} + +#ifdef CONFIG_PM +static int s1d13xxxfb_suspend(struct device *dev, u32 state, u32 level) +{ + struct fb_info *info = dev_get_drvdata(dev); + struct s1d13xxxfb_par *s1dfb = info->par; + struct s1d13xxxfb_pdata *pdata = NULL; + + /* disable display */ + lcd_enable(s1dfb, 0); + crt_enable(s1dfb, 0); + + if (dev->platform_data) + pdata = dev->platform_data; + +#if 0 + if (!s1dfb->disp_save) + s1dfb->disp_save = kmalloc(info->fix.smem_len, GFP_KERNEL); + + if (!s1dfb->disp_save) { + printk(KERN_ERR PFX "no memory to save screen"); + return -ENOMEM; + } + + memcpy_fromio(s1dfb->disp_save, info->screen_base, info->fix.smem_len); +#else + s1dfb->disp_save = NULL; +#endif + + if (!s1dfb->regs_save) + s1dfb->regs_save = kmalloc(info->fix.mmio_len, GFP_KERNEL); + + if (!s1dfb->regs_save) { + printk(KERN_ERR PFX "no memory to save registers"); + return -ENOMEM; + } + + /* backup all registers */ + memcpy_fromio(s1dfb->regs_save, s1dfb->regs, info->fix.mmio_len); + + /* now activate power save mode */ + s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x11); + + if (pdata && pdata->platform_suspend_video) + return pdata->platform_suspend_video(); + else + return 0; +} + +static int s1d13xxxfb_resume(struct device *dev, u32 level) +{ + struct fb_info *info = dev_get_drvdata(dev); + struct s1d13xxxfb_par *s1dfb = info->par; + struct s1d13xxxfb_pdata *pdata = NULL; + + if (level != RESUME_ENABLE) + return 0; + + /* awaken the chip */ + s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x10); + + /* do not let go until SDRAM "wakes up" */ + while ((s1d13xxxfb_readreg(s1dfb, S1DREG_PS_STATUS) & 0x01)) + udelay(10); + + if (dev->platform_data) + pdata = dev->platform_data; + + if (s1dfb->regs_save) { + /* will write RO regs, *should* get away with it :) */ + memcpy_toio(s1dfb->regs, s1dfb->regs_save, info->fix.mmio_len); + kfree(s1dfb->regs_save); + } + + if (s1dfb->disp_save) { + memcpy_toio(info->screen_base, s1dfb->disp_save, + info->fix.smem_len); + kfree(s1dfb->disp_save); /* XXX kmalloc()'d when? */ + } + + if ((s1dfb->display & 0x01) != 0) + lcd_enable(s1dfb, 1); + if ((s1dfb->display & 0x02) != 0) + crt_enable(s1dfb, 1); + + if (pdata && pdata->platform_resume_video) + return pdata->platform_resume_video(); + else + return 0; +} +#endif /* CONFIG_PM */ + +static struct device_driver s1d13xxxfb_driver = { + .name = S1D_DEVICENAME, + .bus = &platform_bus_type, + .probe = s1d13xxxfb_probe, + .remove = s1d13xxxfb_remove, +#ifdef CONFIG_PM + .suspend = s1d13xxxfb_suspend, + .resume = s1d13xxxfb_resume +#endif +}; + + +static int __init +s1d13xxxfb_init(void) +{ + if (fb_get_options("s1d13xxxfb", NULL)) + return -ENODEV; + + return driver_register(&s1d13xxxfb_driver); +} + + +static void __exit +s1d13xxxfb_exit(void) +{ + driver_unregister(&s1d13xxxfb_driver); +} + +module_init(s1d13xxxfb_init); +module_exit(s1d13xxxfb_exit); + + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Framebuffer driver for S1D13xxx devices"); +MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Thibaut VARENE <varenet@parisc-linux.org>"); diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c new file mode 100644 index 000000000000..4f8043a71f21 --- /dev/null +++ b/drivers/video/sa1100fb.c @@ -0,0 +1,1574 @@ +/* + * linux/drivers/video/sa1100fb.c + * + * Copyright (C) 1999 Eric A. Thomas + * Based on acornfb.c Copyright (C) Russell King. + * + * 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. + * + * StrongARM 1100 LCD Controller Frame Buffer Driver + * + * Please direct your questions and comments on this driver to the following + * email address: + * + * linux-arm-kernel@lists.arm.linux.org.uk + * + * Clean patches should be sent to the ARM Linux Patch System. Please see the + * following web page for more information: + * + * http://www.arm.linux.org.uk/developer/patches/info.shtml + * + * Thank you. + * + * Known problems: + * - With the Neponset plugged into an Assabet, LCD powerdown + * doesn't work (LCD stays powered up). Therefore we shouldn't + * blank the screen. + * - We don't limit the CPU clock rate nor the mode selection + * according to the available SDRAM bandwidth. + * + * Other notes: + * - Linear grayscale palettes and the kernel. + * Such code does not belong in the kernel. The kernel frame buffer + * drivers do not expect a linear colourmap, but a colourmap based on + * the VT100 standard mapping. + * + * If your _userspace_ requires a linear colourmap, then the setup of + * such a colourmap belongs _in userspace_, not in the kernel. Code + * to set the colourmap correctly from user space has been sent to + * David Neuer. It's around 8 lines of C code, plus another 4 to + * detect if we are using grayscale. + * + * - The following must never be specified in a panel definition: + * LCCR0_LtlEnd, LCCR3_PixClkDiv, LCCR3_VrtSnchL, LCCR3_HorSnchL + * + * - The following should be specified: + * either LCCR0_Color or LCCR0_Mono + * either LCCR0_Sngl or LCCR0_Dual + * either LCCR0_Act or LCCR0_Pas + * either LCCR3_OutEnH or LCCD3_OutEnL + * either LCCR3_PixRsEdg or LCCR3_PixFlEdg + * either LCCR3_ACBsDiv or LCCR3_ACBsCntOff + * + * Code Status: + * 1999/04/01: + * - Driver appears to be working for Brutus 320x200x8bpp mode. Other + * resolutions are working, but only the 8bpp mode is supported. + * Changes need to be made to the palette encode and decode routines + * to support 4 and 16 bpp modes. + * Driver is not designed to be a module. The FrameBuffer is statically + * allocated since dynamic allocation of a 300k buffer cannot be + * guaranteed. + * + * 1999/06/17: + * - FrameBuffer memory is now allocated at run-time when the + * driver is initialized. + * + * 2000/04/10: Nicolas Pitre <nico@cam.org> + * - Big cleanup for dynamic selection of machine type at run time. + * + * 2000/07/19: Jamey Hicks <jamey@crl.dec.com> + * - Support for Bitsy aka Compaq iPAQ H3600 added. + * + * 2000/08/07: Tak-Shing Chan <tchan.rd@idthk.com> + * Jeff Sutherland <jsutherland@accelent.com> + * - Resolved an issue caused by a change made to the Assabet's PLD + * earlier this year which broke the framebuffer driver for newer + * Phase 4 Assabets. Some other parameters were changed to optimize + * for the Sharp display. + * + * 2000/08/09: Kunihiko IMAI <imai@vasara.co.jp> + * - XP860 support added + * + * 2000/08/19: Mark Huang <mhuang@livetoy.com> + * - Allows standard options to be passed on the kernel command line + * for most common passive displays. + * + * 2000/08/29: + * - s/save_flags_cli/local_irq_save/ + * - remove unneeded extra save_flags_cli in sa1100fb_enable_lcd_controller + * + * 2000/10/10: Erik Mouw <J.A.K.Mouw@its.tudelft.nl> + * - Updated LART stuff. Fixed some minor bugs. + * + * 2000/10/30: Murphy Chen <murphy@mail.dialogue.com.tw> + * - Pangolin support added + * + * 2000/10/31: Roman Jordan <jor@hoeft-wessel.de> + * - Huw Webpanel support added + * + * 2000/11/23: Eric Peng <ericpeng@coventive.com> + * - Freebird add + * + * 2001/02/07: Jamey Hicks <jamey.hicks@compaq.com> + * Cliff Brake <cbrake@accelent.com> + * - Added PM callback + * + * 2001/05/26: <rmk@arm.linux.org.uk> + * - Fix 16bpp so that (a) we use the right colours rather than some + * totally random colour depending on what was in page 0, and (b) + * we don't de-reference a NULL pointer. + * - remove duplicated implementation of consistent_alloc() + * - convert dma address types to dma_addr_t + * - remove unused 'montype' stuff + * - remove redundant zero inits of init_var after the initial + * memzero. + * - remove allow_modeset (acornfb idea does not belong here) + * + * 2001/05/28: <rmk@arm.linux.org.uk> + * - massive cleanup - move machine dependent data into structures + * - I've left various #warnings in - if you see one, and know + * the hardware concerned, please get in contact with me. + * + * 2001/05/31: <rmk@arm.linux.org.uk> + * - Fix LCCR1 HSW value, fix all machine type specifications to + * keep values in line. (Please check your machine type specs) + * + * 2001/06/10: <rmk@arm.linux.org.uk> + * - Fiddle with the LCD controller from task context only; mainly + * so that we can run with interrupts on, and sleep. + * - Convert #warnings into #errors. No pain, no gain. ;) + * + * 2001/06/14: <rmk@arm.linux.org.uk> + * - Make the palette BPS value for 12bpp come out correctly. + * - Take notice of "greyscale" on any colour depth. + * - Make truecolor visuals use the RGB channel encoding information. + * + * 2001/07/02: <rmk@arm.linux.org.uk> + * - Fix colourmap problems. + * + * 2001/07/13: <abraham@2d3d.co.za> + * - Added support for the ICP LCD-Kit01 on LART. This LCD is + * manufactured by Prime View, model no V16C6448AB + * + * 2001/07/23: <rmk@arm.linux.org.uk> + * - Hand merge version from handhelds.org CVS tree. See patch + * notes for 595/1 for more information. + * - Drop 12bpp (it's 16bpp with different colour register mappings). + * - This hardware can not do direct colour. Therefore we don't + * support it. + * + * 2001/07/27: <rmk@arm.linux.org.uk> + * - Halve YRES on dual scan LCDs. + * + * 2001/08/22: <rmk@arm.linux.org.uk> + * - Add b/w iPAQ pixclock value. + * + * 2001/10/12: <rmk@arm.linux.org.uk> + * - Add patch 681/1 and clean up stork definitions. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/cpufreq.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mach-types.h> +#include <asm/uaccess.h> +#include <asm/arch/assabet.h> +#include <asm/arch/shannon.h> + +/* + * debugging? + */ +#define DEBUG 0 +/* + * Complain if VAR is out of range. + */ +#define DEBUG_VAR 1 + +#undef ASSABET_PAL_VIDEO + +#include "sa1100fb.h" + +extern void (*sa1100fb_backlight_power)(int on); +extern void (*sa1100fb_lcd_power)(int on); + +/* + * IMHO this looks wrong. In 8BPP, length should be 8. + */ +static struct sa1100fb_rgb rgb_8 = { + .red = { .offset = 0, .length = 4, }, + .green = { .offset = 0, .length = 4, }, + .blue = { .offset = 0, .length = 4, }, + .transp = { .offset = 0, .length = 0, }, +}; + +static struct sa1100fb_rgb def_rgb_16 = { + .red = { .offset = 11, .length = 5, }, + .green = { .offset = 5, .length = 6, }, + .blue = { .offset = 0, .length = 5, }, + .transp = { .offset = 0, .length = 0, }, +}; + +#ifdef CONFIG_SA1100_ASSABET +#ifndef ASSABET_PAL_VIDEO +/* + * The assabet uses a sharp LQ039Q2DS54 LCD module. It is actually + * takes an RGB666 signal, but we provide it with an RGB565 signal + * instead (def_rgb_16). + */ +static struct sa1100fb_mach_info lq039q2ds54_info __initdata = { + .pixclock = 171521, .bpp = 16, + .xres = 320, .yres = 240, + + .hsync_len = 5, .vsync_len = 1, + .left_margin = 61, .upper_margin = 3, + .right_margin = 9, .lower_margin = 0, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), +}; +#else +static struct sa1100fb_mach_info pal_info __initdata = { + .pixclock = 67797, .bpp = 16, + .xres = 640, .yres = 512, + + .hsync_len = 64, .vsync_len = 6, + .left_margin = 125, .upper_margin = 70, + .right_margin = 115, .lower_margin = 36, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512), +}; +#endif +#endif + +#ifdef CONFIG_SA1100_H3800 +static struct sa1100fb_mach_info h3800_info __initdata = { + .pixclock = 174757, .bpp = 16, + .xres = 320, .yres = 240, + + .hsync_len = 3, .vsync_len = 3, + .left_margin = 12, .upper_margin = 10, + .right_margin = 17, .lower_margin = 1, + + .cmap_static = 1, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), +}; +#endif + +#ifdef CONFIG_SA1100_H3600 +static struct sa1100fb_mach_info h3600_info __initdata = { + .pixclock = 174757, .bpp = 16, + .xres = 320, .yres = 240, + + .hsync_len = 3, .vsync_len = 3, + .left_margin = 12, .upper_margin = 10, + .right_margin = 17, .lower_margin = 1, + + .cmap_static = 1, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), +}; + +static struct sa1100fb_rgb h3600_rgb_16 = { + .red = { .offset = 12, .length = 4, }, + .green = { .offset = 7, .length = 4, }, + .blue = { .offset = 1, .length = 4, }, + .transp = { .offset = 0, .length = 0, }, +}; +#endif + +#ifdef CONFIG_SA1100_H3100 +static struct sa1100fb_mach_info h3100_info __initdata = { + .pixclock = 406977, .bpp = 4, + .xres = 320, .yres = 240, + + .hsync_len = 26, .vsync_len = 41, + .left_margin = 4, .upper_margin = 0, + .right_margin = 4, .lower_margin = 0, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .cmap_greyscale = 1, + .cmap_inverse = 1, + + .lccr0 = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), +}; +#endif + +#ifdef CONFIG_SA1100_COLLIE +static struct sa1100fb_mach_info collie_info __initdata = { + .pixclock = 171521, .bpp = 16, + .xres = 320, .yres = 240, + + .hsync_len = 5, .vsync_len = 1, + .left_margin = 11, .upper_margin = 2, + .right_margin = 30, .lower_margin = 0, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), +}; +#endif + +#ifdef LART_GREY_LCD +static struct sa1100fb_mach_info lart_grey_info __initdata = { + .pixclock = 150000, .bpp = 4, + .xres = 320, .yres = 240, + + .hsync_len = 1, .vsync_len = 1, + .left_margin = 4, .upper_margin = 0, + .right_margin = 2, .lower_margin = 0, + + .cmap_greyscale = 1, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + .lccr0 = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512), +}; +#endif +#ifdef LART_COLOR_LCD +static struct sa1100fb_mach_info lart_color_info __initdata = { + .pixclock = 150000, .bpp = 16, + .xres = 320, .yres = 240, + + .hsync_len = 2, .vsync_len = 3, + .left_margin = 69, .upper_margin = 14, + .right_margin = 8, .lower_margin = 4, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512), +}; +#endif +#ifdef LART_VIDEO_OUT +static struct sa1100fb_mach_info lart_video_info __initdata = { + .pixclock = 39721, .bpp = 16, + .xres = 640, .yres = 480, + + .hsync_len = 95, .vsync_len = 2, + .left_margin = 40, .upper_margin = 32, + .right_margin = 24, .lower_margin = 11, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512), +}; +#endif + +#ifdef LART_KIT01_LCD +static struct sa1100fb_mach_info lart_kit01_info __initdata = { + .pixclock = 63291, .bpp = 16, + .xres = 640, .yres = 480, + + .hsync_len = 64, .vsync_len = 3, + .left_margin = 122, .upper_margin = 45, + .right_margin = 10, .lower_margin = 10, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg +}; +#endif + +#ifdef CONFIG_SA1100_SHANNON +static struct sa1100fb_mach_info shannon_info __initdata = { + .pixclock = 152500, .bpp = 8, + .xres = 640, .yres = 480, + + .hsync_len = 4, .vsync_len = 3, + .left_margin = 2, .upper_margin = 0, + .right_margin = 1, .lower_margin = 0, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + .lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas, + .lccr3 = LCCR3_ACBsDiv(512), +}; +#endif + + + +static struct sa1100fb_mach_info * __init +sa1100fb_get_machine_info(struct sa1100fb_info *fbi) +{ + struct sa1100fb_mach_info *inf = NULL; + + /* + * R G B T + * default {11,5}, { 5,6}, { 0,5}, { 0,0} + * h3600 {12,4}, { 7,4}, { 1,4}, { 0,0} + * freebird { 8,4}, { 4,4}, { 0,4}, {12,4} + */ +#ifdef CONFIG_SA1100_ASSABET + if (machine_is_assabet()) { +#ifndef ASSABET_PAL_VIDEO + inf = &lq039q2ds54_info; +#else + inf = &pal_info; +#endif + } +#endif +#ifdef CONFIG_SA1100_H3100 + if (machine_is_h3100()) { + inf = &h3100_info; + } +#endif +#ifdef CONFIG_SA1100_H3600 + if (machine_is_h3600()) { + inf = &h3600_info; + fbi->rgb[RGB_16] = &h3600_rgb_16; + } +#endif +#ifdef CONFIG_SA1100_H3800 + if (machine_is_h3800()) { + inf = &h3800_info; + } +#endif +#ifdef CONFIG_SA1100_COLLIE + if (machine_is_collie()) { + inf = &collie_info; + } +#endif +#ifdef CONFIG_SA1100_LART + if (machine_is_lart()) { +#ifdef LART_GREY_LCD + inf = &lart_grey_info; +#endif +#ifdef LART_COLOR_LCD + inf = &lart_color_info; +#endif +#ifdef LART_VIDEO_OUT + inf = &lart_video_info; +#endif +#ifdef LART_KIT01_LCD + inf = &lart_kit01_info; +#endif + } +#endif +#ifdef CONFIG_SA1100_SHANNON + if (machine_is_shannon()) { + inf = &shannon_info; + } +#endif + return inf; +} + +static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *); +static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state); + +static inline void sa1100fb_schedule_work(struct sa1100fb_info *fbi, u_int state) +{ + unsigned long flags; + + local_irq_save(flags); + /* + * We need to handle two requests being made at the same time. + * There are two important cases: + * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE) + * We must perform the unblanking, which will do our REENABLE for us. + * 2. When we are blanking, but immediately unblank before we have + * blanked. We do the "REENABLE" thing here as well, just to be sure. + */ + if (fbi->task_state == C_ENABLE && state == C_REENABLE) + state = (u_int) -1; + if (fbi->task_state == C_DISABLE && state == C_ENABLE) + state = C_REENABLE; + + if (state != (u_int)-1) { + fbi->task_state = state; + schedule_work(&fbi->task); + } + local_irq_restore(flags); +} + +static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +/* + * Convert bits-per-pixel to a hardware palette PBS value. + */ +static inline u_int palette_pbs(struct fb_var_screeninfo *var) +{ + int ret = 0; + switch (var->bits_per_pixel) { + case 4: ret = 0 << 12; break; + case 8: ret = 1 << 12; break; + case 16: ret = 2 << 12; break; + } + return ret; +} + +static int +sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, + u_int trans, struct fb_info *info) +{ + struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; + u_int val, ret = 1; + + if (regno < fbi->palette_size) { + val = ((red >> 4) & 0xf00); + val |= ((green >> 8) & 0x0f0); + val |= ((blue >> 12) & 0x00f); + + if (regno == 0) + val |= palette_pbs(&fbi->fb.var); + + fbi->palette_cpu[regno] = val; + ret = 0; + } + return ret; +} + +static int +sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int trans, struct fb_info *info) +{ + struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; + unsigned int val; + int ret = 1; + + /* + * If inverse mode was selected, invert all the colours + * rather than the register number. The register number + * is what you poke into the framebuffer to produce the + * colour you requested. + */ + if (fbi->cmap_inverse) { + red = 0xffff - red; + green = 0xffff - green; + blue = 0xffff - blue; + } + + /* + * If greyscale is true, then we convert the RGB value + * to greyscale no mater what visual we are using. + */ + if (fbi->fb.var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + + switch (fbi->fb.fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* + * 12 or 16-bit True Colour. We encode the RGB value + * according to the RGB bitfield information. + */ + if (regno < 16) { + u32 *pal = fbi->fb.pseudo_palette; + + val = chan_to_field(red, &fbi->fb.var.red); + val |= chan_to_field(green, &fbi->fb.var.green); + val |= chan_to_field(blue, &fbi->fb.var.blue); + + pal[regno] = val; + ret = 0; + } + break; + + case FB_VISUAL_STATIC_PSEUDOCOLOR: + case FB_VISUAL_PSEUDOCOLOR: + ret = sa1100fb_setpalettereg(regno, red, green, blue, trans, info); + break; + } + + return ret; +} + +/* + * sa1100fb_display_dma_period() + * Calculate the minimum period (in picoseconds) between two DMA + * requests for the LCD controller. If we hit this, it means we're + * doing nothing but LCD DMA. + */ +static unsigned int sa1100fb_display_dma_period(struct fb_var_screeninfo *var) +{ + /* + * Period = pixclock * bits_per_byte * bytes_per_transfer + * / memory_bits_per_pixel; + */ + return var->pixclock * 8 * 16 / var->bits_per_pixel; +} + +/* + * sa1100fb_check_var(): + * Round up in the following order: bits_per_pixel, xres, + * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, + * bitfields, horizontal timing, vertical timing. + */ +static int +sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; + int rgbidx; + + if (var->xres < MIN_XRES) + var->xres = MIN_XRES; + if (var->yres < MIN_YRES) + var->yres = MIN_YRES; + if (var->xres > fbi->max_xres) + var->xres = fbi->max_xres; + if (var->yres > fbi->max_yres) + var->yres = fbi->max_yres; + var->xres_virtual = max(var->xres_virtual, var->xres); + var->yres_virtual = max(var->yres_virtual, var->yres); + + DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel); + switch (var->bits_per_pixel) { + case 4: + rgbidx = RGB_8; + break; + case 8: + rgbidx = RGB_8; + break; + case 16: + rgbidx = RGB_16; + break; + default: + return -EINVAL; + } + + /* + * Copy the RGB parameters for this display + * from the machine specific parameters. + */ + var->red = fbi->rgb[rgbidx]->red; + var->green = fbi->rgb[rgbidx]->green; + var->blue = fbi->rgb[rgbidx]->blue; + var->transp = fbi->rgb[rgbidx]->transp; + + DPRINTK("RGBT length = %d:%d:%d:%d\n", + var->red.length, var->green.length, var->blue.length, + var->transp.length); + + DPRINTK("RGBT offset = %d:%d:%d:%d\n", + var->red.offset, var->green.offset, var->blue.offset, + var->transp.offset); + +#ifdef CONFIG_CPU_FREQ + printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n", + sa1100fb_display_dma_period(var), + cpufreq_get(smp_processor_id())); +#endif + + return 0; +} + +static inline void sa1100fb_set_truecolor(u_int is_true_color) +{ + if (machine_is_assabet()) { +#if 1 // phase 4 or newer Assabet's + if (is_true_color) + ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB); + else + ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB); +#else + // older Assabet's + if (is_true_color) + ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB); + else + ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB); +#endif + } +} + +/* + * sa1100fb_set_par(): + * Set the user defined part of the display for the specified console + */ +static int sa1100fb_set_par(struct fb_info *info) +{ + struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; + struct fb_var_screeninfo *var = &info->var; + unsigned long palette_mem_size; + + DPRINTK("set_par\n"); + + if (var->bits_per_pixel == 16) + fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR; + else if (!fbi->cmap_static) + fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; + else { + /* + * Some people have weird ideas about wanting static + * pseudocolor maps. I suspect their user space + * applications are broken. + */ + fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; + } + + fbi->fb.fix.line_length = var->xres_virtual * + var->bits_per_pixel / 8; + fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16; + + palette_mem_size = fbi->palette_size * sizeof(u16); + + DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size); + + fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); + fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size; + + /* + * Set (any) board control register to handle new color depth + */ + sa1100fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR); + sa1100fb_activate_var(var, fbi); + + return 0; +} + +#if 0 +static int +sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; + + /* + * Make sure the user isn't doing something stupid. + */ + if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->cmap_static)) + return -EINVAL; + + return gen_set_cmap(cmap, kspc, con, info); +} +#endif + +/* + * Formal definition of the VESA spec: + * On + * This refers to the state of the display when it is in full operation + * Stand-By + * This defines an optional operating state of minimal power reduction with + * the shortest recovery time + * Suspend + * This refers to a level of power management in which substantial power + * reduction is achieved by the display. The display can have a longer + * recovery time from this state than from the Stand-by state + * Off + * This indicates that the display is consuming the lowest level of power + * and is non-operational. Recovery from this state may optionally require + * the user to manually power on the monitor + * + * Now, the fbdev driver adds an additional state, (blank), where they + * turn off the video (maybe by colormap tricks), but don't mess with the + * video itself: think of it semantically between on and Stand-By. + * + * So here's what we should do in our fbdev blank routine: + * + * VESA_NO_BLANKING (mode 0) Video on, front/back light on + * VESA_VSYNC_SUSPEND (mode 1) Video on, front/back light off + * VESA_HSYNC_SUSPEND (mode 2) Video on, front/back light off + * VESA_POWERDOWN (mode 3) Video off, front/back light off + * + * This will match the matrox implementation. + */ +/* + * sa1100fb_blank(): + * Blank the display by setting all palette values to zero. Note, the + * 12 and 16 bpp modes don't really use the palette, so this will not + * blank the display in all modes. + */ +static int sa1100fb_blank(int blank, struct fb_info *info) +{ + struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; + int i; + + DPRINTK("sa1100fb_blank: blank=%d\n", blank); + + switch (blank) { + case FB_BLANK_POWERDOWN: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_NORMAL: + if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR || + fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) + for (i = 0; i < fbi->palette_size; i++) + sa1100fb_setpalettereg(i, 0, 0, 0, 0, info); + sa1100fb_schedule_work(fbi, C_DISABLE); + break; + + case FB_BLANK_UNBLANK: + if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR || + fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) + fb_set_cmap(&fbi->fb.cmap, info); + sa1100fb_schedule_work(fbi, C_ENABLE); + } + return 0; +} + +static int sa1100fb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; + unsigned long start, len, off = vma->vm_pgoff << PAGE_SHIFT; + + if (off < info->fix.smem_len) { + vma->vm_pgoff += 1; /* skip over the palette */ + return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu, + fbi->map_dma, fbi->map_size); + } + + start = info->fix.mmio_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); + + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + + off += start & PAGE_MASK; + vma->vm_pgoff = off >> PAGE_SHIFT; + vma->vm_flags |= VM_IO; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +} + +static struct fb_ops sa1100fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = sa1100fb_check_var, + .fb_set_par = sa1100fb_set_par, +// .fb_set_cmap = sa1100fb_set_cmap, + .fb_setcolreg = sa1100fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_blank = sa1100fb_blank, + .fb_cursor = soft_cursor, + .fb_mmap = sa1100fb_mmap, +}; + +/* + * Calculate the PCD value from the clock rate (in picoseconds). + * We take account of the PPCR clock setting. + */ +static inline unsigned int get_pcd(unsigned int pixclock, unsigned int cpuclock) +{ + unsigned int pcd = cpuclock / 100; + + pcd *= pixclock; + pcd /= 10000000; + + return pcd + 1; /* make up for integer math truncations */ +} + +/* + * sa1100fb_activate_var(): + * Configures LCD Controller based on entries in var parameter. Settings are + * only written to the controller if changes were made. + */ +static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi) +{ + struct sa1100fb_lcd_reg new_regs; + u_int half_screen_size, yres, pcd; + u_long flags; + + DPRINTK("Configuring SA1100 LCD\n"); + + DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n", + var->xres, var->hsync_len, + var->left_margin, var->right_margin); + DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n", + var->yres, var->vsync_len, + var->upper_margin, var->lower_margin); + +#if DEBUG_VAR + if (var->xres < 16 || var->xres > 1024) + printk(KERN_ERR "%s: invalid xres %d\n", + fbi->fb.fix.id, var->xres); + if (var->hsync_len < 1 || var->hsync_len > 64) + printk(KERN_ERR "%s: invalid hsync_len %d\n", + fbi->fb.fix.id, var->hsync_len); + if (var->left_margin < 1 || var->left_margin > 255) + printk(KERN_ERR "%s: invalid left_margin %d\n", + fbi->fb.fix.id, var->left_margin); + if (var->right_margin < 1 || var->right_margin > 255) + printk(KERN_ERR "%s: invalid right_margin %d\n", + fbi->fb.fix.id, var->right_margin); + if (var->yres < 1 || var->yres > 1024) + printk(KERN_ERR "%s: invalid yres %d\n", + fbi->fb.fix.id, var->yres); + if (var->vsync_len < 1 || var->vsync_len > 64) + printk(KERN_ERR "%s: invalid vsync_len %d\n", + fbi->fb.fix.id, var->vsync_len); + if (var->upper_margin < 0 || var->upper_margin > 255) + printk(KERN_ERR "%s: invalid upper_margin %d\n", + fbi->fb.fix.id, var->upper_margin); + if (var->lower_margin < 0 || var->lower_margin > 255) + printk(KERN_ERR "%s: invalid lower_margin %d\n", + fbi->fb.fix.id, var->lower_margin); +#endif + + new_regs.lccr0 = fbi->lccr0 | + LCCR0_LEN | LCCR0_LDM | LCCR0_BAM | + LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0); + + new_regs.lccr1 = + LCCR1_DisWdth(var->xres) + + LCCR1_HorSnchWdth(var->hsync_len) + + LCCR1_BegLnDel(var->left_margin) + + LCCR1_EndLnDel(var->right_margin); + + /* + * If we have a dual scan LCD, then we need to halve + * the YRES parameter. + */ + yres = var->yres; + if (fbi->lccr0 & LCCR0_Dual) + yres /= 2; + + new_regs.lccr2 = + LCCR2_DisHght(yres) + + LCCR2_VrtSnchWdth(var->vsync_len) + + LCCR2_BegFrmDel(var->upper_margin) + + LCCR2_EndFrmDel(var->lower_margin); + + pcd = get_pcd(var->pixclock, cpufreq_get(0)); + new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->lccr3 | + (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) | + (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL); + + DPRINTK("nlccr0 = 0x%08lx\n", new_regs.lccr0); + DPRINTK("nlccr1 = 0x%08lx\n", new_regs.lccr1); + DPRINTK("nlccr2 = 0x%08lx\n", new_regs.lccr2); + DPRINTK("nlccr3 = 0x%08lx\n", new_regs.lccr3); + + half_screen_size = var->bits_per_pixel; + half_screen_size = half_screen_size * var->xres * var->yres / 16; + + /* Update shadow copy atomically */ + local_irq_save(flags); + fbi->dbar1 = fbi->palette_dma; + fbi->dbar2 = fbi->screen_dma + half_screen_size; + + fbi->reg_lccr0 = new_regs.lccr0; + fbi->reg_lccr1 = new_regs.lccr1; + fbi->reg_lccr2 = new_regs.lccr2; + fbi->reg_lccr3 = new_regs.lccr3; + local_irq_restore(flags); + + /* + * Only update the registers if the controller is enabled + * and something has changed. + */ + if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) || + (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) || + (DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2)) + sa1100fb_schedule_work(fbi, C_REENABLE); + + return 0; +} + +/* + * NOTE! The following functions are purely helpers for set_ctrlr_state. + * Do not call them directly; set_ctrlr_state does the correct serialisation + * to ensure that things happen in the right way 100% of time time. + * -- rmk + */ +static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on) +{ + DPRINTK("backlight o%s\n", on ? "n" : "ff"); + + if (sa1100fb_backlight_power) + sa1100fb_backlight_power(on); +} + +static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on) +{ + DPRINTK("LCD power o%s\n", on ? "n" : "ff"); + + if (sa1100fb_lcd_power) + sa1100fb_lcd_power(on); +} + +static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi) +{ + u_int mask = 0; + + /* + * Enable GPIO<9:2> for LCD use if: + * 1. Active display, or + * 2. Color Dual Passive display + * + * see table 11.8 on page 11-27 in the SA1100 manual + * -- Erik. + * + * SA1110 spec update nr. 25 says we can and should + * clear LDD15 to 12 for 4 or 8bpp modes with active + * panels. + */ + if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color && + (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) { + mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8; + + if (fbi->fb.var.bits_per_pixel > 8 || + (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual) + mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12; + + } + + if (mask) { + GPDR |= mask; + GAFR |= mask; + } +} + +static void sa1100fb_enable_controller(struct sa1100fb_info *fbi) +{ + DPRINTK("Enabling LCD controller\n"); + + /* + * Make sure the mode bits are present in the first palette entry + */ + fbi->palette_cpu[0] &= 0xcfff; + fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var); + + /* Sequence from 11.7.10 */ + LCCR3 = fbi->reg_lccr3; + LCCR2 = fbi->reg_lccr2; + LCCR1 = fbi->reg_lccr1; + LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN; + DBAR1 = fbi->dbar1; + DBAR2 = fbi->dbar2; + LCCR0 |= LCCR0_LEN; + + if (machine_is_shannon()) { + GPDR |= SHANNON_GPIO_DISP_EN; + GPSR |= SHANNON_GPIO_DISP_EN; + } + + DPRINTK("DBAR1 = 0x%08x\n", DBAR1); + DPRINTK("DBAR2 = 0x%08x\n", DBAR2); + DPRINTK("LCCR0 = 0x%08x\n", LCCR0); + DPRINTK("LCCR1 = 0x%08x\n", LCCR1); + DPRINTK("LCCR2 = 0x%08x\n", LCCR2); + DPRINTK("LCCR3 = 0x%08x\n", LCCR3); +} + +static void sa1100fb_disable_controller(struct sa1100fb_info *fbi) +{ + DECLARE_WAITQUEUE(wait, current); + + DPRINTK("Disabling LCD controller\n"); + + if (machine_is_shannon()) { + GPCR |= SHANNON_GPIO_DISP_EN; + } + + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&fbi->ctrlr_wait, &wait); + + LCSR = 0xffffffff; /* Clear LCD Status Register */ + LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */ + LCCR0 &= ~LCCR0_LEN; /* Disable LCD Controller */ + + schedule_timeout(20 * HZ / 1000); + remove_wait_queue(&fbi->ctrlr_wait, &wait); +} + +/* + * sa1100fb_handle_irq: Handle 'LCD DONE' interrupts. + */ +static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sa1100fb_info *fbi = dev_id; + unsigned int lcsr = LCSR; + + if (lcsr & LCSR_LDD) { + LCCR0 |= LCCR0_LDM; + wake_up(&fbi->ctrlr_wait); + } + + LCSR = lcsr; + return IRQ_HANDLED; +} + +/* + * This function must be called from task context only, since it will + * sleep when disabling the LCD controller, or if we get two contending + * processes trying to alter state. + */ +static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state) +{ + u_int old_state; + + down(&fbi->ctrlr_sem); + + old_state = fbi->state; + + /* + * Hack around fbcon initialisation. + */ + if (old_state == C_STARTUP && state == C_REENABLE) + state = C_ENABLE; + + switch (state) { + case C_DISABLE_CLKCHANGE: + /* + * Disable controller for clock change. If the + * controller is already disabled, then do nothing. + */ + if (old_state != C_DISABLE && old_state != C_DISABLE_PM) { + fbi->state = state; + sa1100fb_disable_controller(fbi); + } + break; + + case C_DISABLE_PM: + case C_DISABLE: + /* + * Disable controller + */ + if (old_state != C_DISABLE) { + fbi->state = state; + + __sa1100fb_backlight_power(fbi, 0); + if (old_state != C_DISABLE_CLKCHANGE) + sa1100fb_disable_controller(fbi); + __sa1100fb_lcd_power(fbi, 0); + } + break; + + case C_ENABLE_CLKCHANGE: + /* + * Enable the controller after clock change. Only + * do this if we were disabled for the clock change. + */ + if (old_state == C_DISABLE_CLKCHANGE) { + fbi->state = C_ENABLE; + sa1100fb_enable_controller(fbi); + } + break; + + case C_REENABLE: + /* + * Re-enable the controller only if it was already + * enabled. This is so we reprogram the control + * registers. + */ + if (old_state == C_ENABLE) { + sa1100fb_disable_controller(fbi); + sa1100fb_setup_gpio(fbi); + sa1100fb_enable_controller(fbi); + } + break; + + case C_ENABLE_PM: + /* + * Re-enable the controller after PM. This is not + * perfect - think about the case where we were doing + * a clock change, and we suspended half-way through. + */ + if (old_state != C_DISABLE_PM) + break; + /* fall through */ + + case C_ENABLE: + /* + * Power up the LCD screen, enable controller, and + * turn on the backlight. + */ + if (old_state != C_ENABLE) { + fbi->state = C_ENABLE; + sa1100fb_setup_gpio(fbi); + __sa1100fb_lcd_power(fbi, 1); + sa1100fb_enable_controller(fbi); + __sa1100fb_backlight_power(fbi, 1); + } + break; + } + up(&fbi->ctrlr_sem); +} + +/* + * Our LCD controller task (which is called when we blank or unblank) + * via keventd. + */ +static void sa1100fb_task(void *dummy) +{ + struct sa1100fb_info *fbi = dummy; + u_int state = xchg(&fbi->task_state, -1); + + set_ctrlr_state(fbi, state); +} + +#ifdef CONFIG_CPU_FREQ +/* + * Calculate the minimum DMA period over all displays that we own. + * This, together with the SDRAM bandwidth defines the slowest CPU + * frequency that can be selected. + */ +static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi) +{ +#if 0 + unsigned int min_period = (unsigned int)-1; + int i; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + struct display *disp = &fb_display[i]; + unsigned int period; + + /* + * Do we own this display? + */ + if (disp->fb_info != &fbi->fb) + continue; + + /* + * Ok, calculate its DMA period + */ + period = sa1100fb_display_dma_period(&disp->var); + if (period < min_period) + min_period = period; + } + + return min_period; +#else + /* + * FIXME: we need to verify _all_ consoles. + */ + return sa1100fb_display_dma_period(&fbi->fb.var); +#endif +} + +/* + * CPU clock speed change handler. We need to adjust the LCD timing + * parameters when the CPU clock is adjusted by the power management + * subsystem. + */ +static int +sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct sa1100fb_info *fbi = TO_INF(nb, freq_transition); + struct cpufreq_freqs *f = data; + u_int pcd; + + switch (val) { + case CPUFREQ_PRECHANGE: + set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE); + break; + + case CPUFREQ_POSTCHANGE: + pcd = get_pcd(fbi->fb.var.pixclock, f->new); + fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); + set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE); + break; + } + return 0; +} + +static int +sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct sa1100fb_info *fbi = TO_INF(nb, freq_policy); + struct cpufreq_policy *policy = data; + + switch (val) { + case CPUFREQ_ADJUST: + case CPUFREQ_INCOMPATIBLE: + printk(KERN_DEBUG "min dma period: %d ps, " + "new clock %d kHz\n", sa1100fb_min_dma_period(fbi), + policy->max); + /* todo: fill in min/max values */ + break; + case CPUFREQ_NOTIFY: + do {} while(0); + /* todo: panic if min/max values aren't fulfilled + * [can't really happen unless there's a bug in the + * CPU policy verififcation process * + */ + break; + } + return 0; +} +#endif + +#ifdef CONFIG_PM +/* + * Power management hooks. Note that we won't be called from IRQ context, + * unlike the blank functions above, so we may sleep. + */ +static int sa1100fb_suspend(struct device *dev, u32 state, u32 level) +{ + struct sa1100fb_info *fbi = dev_get_drvdata(dev); + + if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) + set_ctrlr_state(fbi, C_DISABLE_PM); + return 0; +} + +static int sa1100fb_resume(struct device *dev, u32 level) +{ + struct sa1100fb_info *fbi = dev_get_drvdata(dev); + + if (level == RESUME_ENABLE) + set_ctrlr_state(fbi, C_ENABLE_PM); + return 0; +} +#else +#define sa1100fb_suspend NULL +#define sa1100fb_resume NULL +#endif + +/* + * sa1100fb_map_video_memory(): + * Allocates the DRAM memory for the frame buffer. This buffer is + * remapped into a non-cached, non-buffered, memory region to + * allow palette and pixel writes to occur without flushing the + * cache. Once this area is remapped, all virtual memory + * access to the video memory should occur at the new region. + */ +static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi) +{ + /* + * We reserve one page for the palette, plus the size + * of the framebuffer. + */ + fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); + fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, + &fbi->map_dma, GFP_KERNEL); + + if (fbi->map_cpu) { + fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE; + fbi->screen_dma = fbi->map_dma + PAGE_SIZE; + /* + * FIXME: this is actually the wrong thing to place in + * smem_start. But fbdev suffers from the problem that + * it needs an API which doesn't exist (in this case, + * dma_writecombine_mmap) + */ + fbi->fb.fix.smem_start = fbi->screen_dma; + } + + return fbi->map_cpu ? 0 : -ENOMEM; +} + +/* Fake monspecs to fill in fbinfo structure */ +static struct fb_monspecs monspecs __initdata = { + .hfmin = 30000, + .hfmax = 70000, + .vfmin = 50, + .vfmax = 65, +}; + + +static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev) +{ + struct sa1100fb_mach_info *inf; + struct sa1100fb_info *fbi; + + fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16, + GFP_KERNEL); + if (!fbi) + return NULL; + + memset(fbi, 0, sizeof(struct sa1100fb_info)); + fbi->dev = dev; + + strcpy(fbi->fb.fix.id, SA1100_NAME); + + fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS; + fbi->fb.fix.type_aux = 0; + fbi->fb.fix.xpanstep = 0; + fbi->fb.fix.ypanstep = 0; + fbi->fb.fix.ywrapstep = 0; + fbi->fb.fix.accel = FB_ACCEL_NONE; + + fbi->fb.var.nonstd = 0; + fbi->fb.var.activate = FB_ACTIVATE_NOW; + fbi->fb.var.height = -1; + fbi->fb.var.width = -1; + fbi->fb.var.accel_flags = 0; + fbi->fb.var.vmode = FB_VMODE_NONINTERLACED; + + fbi->fb.fbops = &sa1100fb_ops; + fbi->fb.flags = FBINFO_DEFAULT; + fbi->fb.monspecs = monspecs; + fbi->fb.pseudo_palette = (fbi + 1); + + fbi->rgb[RGB_8] = &rgb_8; + fbi->rgb[RGB_16] = &def_rgb_16; + + inf = sa1100fb_get_machine_info(fbi); + + /* + * People just don't seem to get this. We don't support + * anything but correct entries now, so panic if someone + * does something stupid. + */ + if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) || + inf->pixclock == 0) + panic("sa1100fb error: invalid LCCR3 fields set or zero " + "pixclock."); + + fbi->max_xres = inf->xres; + fbi->fb.var.xres = inf->xres; + fbi->fb.var.xres_virtual = inf->xres; + fbi->max_yres = inf->yres; + fbi->fb.var.yres = inf->yres; + fbi->fb.var.yres_virtual = inf->yres; + fbi->max_bpp = inf->bpp; + fbi->fb.var.bits_per_pixel = inf->bpp; + fbi->fb.var.pixclock = inf->pixclock; + fbi->fb.var.hsync_len = inf->hsync_len; + fbi->fb.var.left_margin = inf->left_margin; + fbi->fb.var.right_margin = inf->right_margin; + fbi->fb.var.vsync_len = inf->vsync_len; + fbi->fb.var.upper_margin = inf->upper_margin; + fbi->fb.var.lower_margin = inf->lower_margin; + fbi->fb.var.sync = inf->sync; + fbi->fb.var.grayscale = inf->cmap_greyscale; + fbi->cmap_inverse = inf->cmap_inverse; + fbi->cmap_static = inf->cmap_static; + fbi->lccr0 = inf->lccr0; + fbi->lccr3 = inf->lccr3; + fbi->state = C_STARTUP; + fbi->task_state = (u_char)-1; + fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres * + fbi->max_bpp / 8; + + init_waitqueue_head(&fbi->ctrlr_wait); + INIT_WORK(&fbi->task, sa1100fb_task, fbi); + init_MUTEX(&fbi->ctrlr_sem); + + return fbi; +} + +static int __init sa1100fb_probe(struct device *dev) +{ + struct sa1100fb_info *fbi; + int ret; + + if (!request_mem_region(0xb0100000, 0x10000, "LCD")) + return -EBUSY; + + fbi = sa1100fb_init_fbinfo(dev); + ret = -ENOMEM; + if (!fbi) + goto failed; + + /* Initialize video memory */ + ret = sa1100fb_map_video_memory(fbi); + if (ret) + goto failed; + + ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT, + "LCD", fbi); + if (ret) { + printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret); + goto failed; + } + +#ifdef ASSABET_PAL_VIDEO + if (machine_is_assabet()) + ASSABET_BCR_clear(ASSABET_BCR_LCD_ON); +#endif + + /* + * This makes sure that our colour bitfield + * descriptors are correctly initialised. + */ + sa1100fb_check_var(&fbi->fb.var, &fbi->fb); + + dev_set_drvdata(dev, fbi); + + ret = register_framebuffer(&fbi->fb); + if (ret < 0) + goto failed; + +#ifdef CONFIG_CPU_FREQ + fbi->freq_transition.notifier_call = sa1100fb_freq_transition; + fbi->freq_policy.notifier_call = sa1100fb_freq_policy; + cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); + cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER); +#endif + + /* This driver cannot be unloaded at the moment */ + return 0; + +failed: + dev_set_drvdata(dev, NULL); + kfree(fbi); + release_mem_region(0xb0100000, 0x10000); + return ret; +} + +static struct device_driver sa1100fb_driver = { + .name = "sa11x0-fb", + .bus = &platform_bus_type, + .probe = sa1100fb_probe, + .suspend = sa1100fb_suspend, + .resume = sa1100fb_resume, +}; + +int __init sa1100fb_init(void) +{ + if (fb_get_options("sa1100fb", NULL)) + return -ENODEV; + + return driver_register(&sa1100fb_driver); +} + +int __init sa1100fb_setup(char *options) +{ +#if 0 + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + + if (!strncmp(this_opt, "bpp:", 4)) + current_par.max_bpp = + simple_strtoul(this_opt + 4, NULL, 0); + + if (!strncmp(this_opt, "lccr0:", 6)) + lcd_shadow.lccr0 = + simple_strtoul(this_opt + 6, NULL, 0); + if (!strncmp(this_opt, "lccr1:", 6)) { + lcd_shadow.lccr1 = + simple_strtoul(this_opt + 6, NULL, 0); + current_par.max_xres = + (lcd_shadow.lccr1 & 0x3ff) + 16; + } + if (!strncmp(this_opt, "lccr2:", 6)) { + lcd_shadow.lccr2 = + simple_strtoul(this_opt + 6, NULL, 0); + current_par.max_yres = + (lcd_shadow. + lccr0 & LCCR0_SDS) ? ((lcd_shadow. + lccr2 & 0x3ff) + + 1) * + 2 : ((lcd_shadow.lccr2 & 0x3ff) + 1); + } + if (!strncmp(this_opt, "lccr3:", 6)) + lcd_shadow.lccr3 = + simple_strtoul(this_opt + 6, NULL, 0); + } +#endif + return 0; +} + +module_init(sa1100fb_init); +MODULE_DESCRIPTION("StrongARM-1100/1110 framebuffer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h new file mode 100644 index 000000000000..0b07f6ae3367 --- /dev/null +++ b/drivers/video/sa1100fb.h @@ -0,0 +1,147 @@ +/* + * linux/drivers/video/sa1100fb.h + * -- StrongARM 1100 LCD Controller Frame Buffer Device + * + * Copyright (C) 1999 Eric A. Thomas + * Based on acornfb.c Copyright (C) Russell King. + * + * 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. + */ + +/* + * These are the bitfields for each + * display depth that we support. + */ +struct sa1100fb_rgb { + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; +}; + +/* + * This structure describes the machine which we are running on. + */ +struct sa1100fb_mach_info { + u_long pixclock; + + u_short xres; + u_short yres; + + u_char bpp; + u_char hsync_len; + u_char left_margin; + u_char right_margin; + + u_char vsync_len; + u_char upper_margin; + u_char lower_margin; + u_char sync; + + u_int cmap_greyscale:1, + cmap_inverse:1, + cmap_static:1, + unused:29; + + u_int lccr0; + u_int lccr3; +}; + +/* Shadows for LCD controller registers */ +struct sa1100fb_lcd_reg { + unsigned long lccr0; + unsigned long lccr1; + unsigned long lccr2; + unsigned long lccr3; +}; + +#define RGB_8 (0) +#define RGB_16 (1) +#define NR_RGB 2 + +struct sa1100fb_info { + struct fb_info fb; + struct device *dev; + struct sa1100fb_rgb *rgb[NR_RGB]; + + u_int max_bpp; + u_int max_xres; + u_int max_yres; + + /* + * These are the addresses we mapped + * the framebuffer memory region to. + */ + dma_addr_t map_dma; + u_char * map_cpu; + u_int map_size; + + u_char * screen_cpu; + dma_addr_t screen_dma; + u16 * palette_cpu; + dma_addr_t palette_dma; + u_int palette_size; + + dma_addr_t dbar1; + dma_addr_t dbar2; + + u_int lccr0; + u_int lccr3; + u_int cmap_inverse:1, + cmap_static:1, + unused:30; + + u_int reg_lccr0; + u_int reg_lccr1; + u_int reg_lccr2; + u_int reg_lccr3; + + volatile u_char state; + volatile u_char task_state; + struct semaphore ctrlr_sem; + wait_queue_head_t ctrlr_wait; + struct work_struct task; + +#ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; + struct notifier_block freq_policy; +#endif +}; + +#define __type_entry(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member))) + +#define TO_INF(ptr,member) __type_entry(ptr,struct sa1100fb_info,member) + +#define SA1100_PALETTE_MODE_VAL(bpp) (((bpp) & 0x018) << 9) + +/* + * These are the actions for set_ctrlr_state + */ +#define C_DISABLE (0) +#define C_ENABLE (1) +#define C_DISABLE_CLKCHANGE (2) +#define C_ENABLE_CLKCHANGE (3) +#define C_REENABLE (4) +#define C_DISABLE_PM (5) +#define C_ENABLE_PM (6) +#define C_STARTUP (7) + +#define SA1100_NAME "SA1100" + +/* + * Debug macros + */ +#if DEBUG +# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + +/* + * Minimum X and Y resolutions + */ +#define MIN_XRES 64 +#define MIN_YRES 64 + diff --git a/drivers/video/savage/Makefile b/drivers/video/savage/Makefile new file mode 100644 index 000000000000..e09770fff8ea --- /dev/null +++ b/drivers/video/savage/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the S3 Savage framebuffer driver +# + +obj-$(CONFIG_FB_SAVAGE) += savagefb.o + +savagefb-y += savagefb_driver.o +savagefb-$(CONFIG_FB_SAVAGE_I2C) += savagefb-i2c.o +savagefb-$(CONFIG_FB_SAVAGE_ACCEL) += savagefb_accel.o diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c new file mode 100644 index 000000000000..024a0cecff15 --- /dev/null +++ b/drivers/video/savage/savagefb-i2c.c @@ -0,0 +1,282 @@ +/* + * linux/drivers/video/savage/savagefb-i2c.c - S3 Savage DDC2 + * + * Copyright 2004 Antonino A. Daplas <adaplas @pol.net> + * + * Based partly on rivafb-i2c.c + * + * 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/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/fb.h> + +#include <asm/io.h> +#include "savagefb.h" + +#define SAVAGE_DDC 0x50 + +#define VGA_CR_IX 0x3d4 +#define VGA_CR_DATA 0x3d5 + +#define CR_SERIAL1 0xa0 /* I2C serial communications interface */ +#define MM_SERIAL1 0xff20 +#define CR_SERIAL2 0xb1 /* DDC2 monitor communications interface */ + +/* based on vt8365 documentation */ +#define PROSAVAGE_I2C_ENAB 0x10 +#define PROSAVAGE_I2C_SCL_OUT 0x01 +#define PROSAVAGE_I2C_SDA_OUT 0x02 +#define PROSAVAGE_I2C_SCL_IN 0x04 +#define PROSAVAGE_I2C_SDA_IN 0x08 + +#define SAVAGE4_I2C_ENAB 0x00000020 +#define SAVAGE4_I2C_SCL_OUT 0x00000001 +#define SAVAGE4_I2C_SDA_OUT 0x00000002 +#define SAVAGE4_I2C_SCL_IN 0x00000008 +#define SAVAGE4_I2C_SDA_IN 0x00000010 + +#define SET_CR_IX(base, val) writeb((val), base + 0x8000 + VGA_CR_IX) +#define SET_CR_DATA(base, val) writeb((val), base + 0x8000 + VGA_CR_DATA) +#define GET_CR_DATA(base) readb(base + 0x8000 + VGA_CR_DATA) + +static void savage4_gpio_setscl(void *data, int val) +{ + struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data; + unsigned int r; + + r = readl(chan->ioaddr + chan->reg); + if(val) + r |= SAVAGE4_I2C_SCL_OUT; + else + r &= ~SAVAGE4_I2C_SCL_OUT; + writel(r, chan->ioaddr + chan->reg); + readl(chan->ioaddr + chan->reg); /* flush posted write */ +} + +static void savage4_gpio_setsda(void *data, int val) +{ + struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data; + + unsigned int r; + r = readl(chan->ioaddr + chan->reg); + if(val) + r |= SAVAGE4_I2C_SDA_OUT; + else + r &= ~SAVAGE4_I2C_SDA_OUT; + writel(r, chan->ioaddr + chan->reg); + readl(chan->ioaddr + chan->reg); /* flush posted write */ +} + +static int savage4_gpio_getscl(void *data) +{ + struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data; + + return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SCL_IN)); +} + +static int savage4_gpio_getsda(void *data) +{ + struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data; + + return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SDA_IN)); +} + +static void prosavage_gpio_setscl(void* data, int val) +{ + struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data; + u32 r; + + SET_CR_IX(chan->ioaddr, chan->reg); + r = GET_CR_DATA(chan->ioaddr); + r |= PROSAVAGE_I2C_ENAB; + if (val) { + r |= PROSAVAGE_I2C_SCL_OUT; + } else { + r &= ~PROSAVAGE_I2C_SCL_OUT; + } + SET_CR_DATA(chan->ioaddr, r); +} + +static void prosavage_gpio_setsda(void* data, int val) +{ + struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data; + unsigned int r; + + SET_CR_IX(chan->ioaddr, chan->reg); + r = GET_CR_DATA(chan->ioaddr); + r |= PROSAVAGE_I2C_ENAB; + if (val) { + r |= PROSAVAGE_I2C_SDA_OUT; + } else { + r &= ~PROSAVAGE_I2C_SDA_OUT; + } + SET_CR_DATA(chan->ioaddr, r); +} + +static int prosavage_gpio_getscl(void* data) +{ + struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data; + + SET_CR_IX(chan->ioaddr, chan->reg); + return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SCL_IN)); +} + +static int prosavage_gpio_getsda(void* data) +{ + struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data; + + SET_CR_IX(chan->ioaddr, chan->reg); + return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SDA_IN)); +} + +#define I2C_ALGO_SAVAGE 0x0f0000 +static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan, + const char *name) +{ + int (*add_bus)(struct i2c_adapter *) = symbol_get(i2c_bit_add_bus); + int rc = 0; + + if (add_bus && chan->par) { + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_ALGO_SAVAGE; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->par->pcidev->dev; + chan->algo.udelay = 40; + chan->algo.mdelay = 5; + chan->algo.timeout = 20; + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + /* Raise SCL and SDA */ + chan->algo.setsda(chan, 1); + chan->algo.setscl(chan, 1); + udelay(20); + + rc = add_bus(&chan->adapter); + + if (rc == 0) + dev_dbg(&chan->par->pcidev->dev, + "I2C bus %s registered.\n", name); + else + dev_warn(&chan->par->pcidev->dev, + "Failed to register I2C bus %s.\n", name); + + symbol_put(i2c_bit_add_bus); + } else + chan->par = NULL; + + return rc; +} + +void savagefb_create_i2c_busses(struct fb_info *info) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + par->chan.par = par; + + switch(info->fix.accel) { + case FB_ACCEL_PROSAVAGE_DDRK: + case FB_ACCEL_PROSAVAGE_PM: + par->chan.reg = CR_SERIAL2; + par->chan.ioaddr = par->mmio.vbase; + par->chan.algo.setsda = prosavage_gpio_setsda; + par->chan.algo.setscl = prosavage_gpio_setscl; + par->chan.algo.getsda = prosavage_gpio_getsda; + par->chan.algo.getscl = prosavage_gpio_getscl; + break; + case FB_ACCEL_SAVAGE4: + par->chan.reg = 0xff20; + par->chan.ioaddr = par->mmio.vbase; + par->chan.algo.setsda = savage4_gpio_setsda; + par->chan.algo.setscl = savage4_gpio_setscl; + par->chan.algo.getsda = savage4_gpio_getsda; + par->chan.algo.getscl = savage4_gpio_getscl; + break; + default: + par->chan.par = NULL; + } + + savage_setup_i2c_bus(&par->chan, "SAVAGE DDC2"); +} + +void savagefb_delete_i2c_busses(struct fb_info *info) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + int (*del_bus)(struct i2c_adapter *) = + symbol_get(i2c_bit_del_bus); + + if (del_bus && par->chan.par) { + del_bus(&par->chan.adapter); + symbol_put(i2c_bit_del_bus); + } + + par->chan.par = NULL; +} + +static u8 *savage_do_probe_i2c_edid(struct savagefb_i2c_chan *chan) +{ + u8 start = 0x0; + int (*transfer)(struct i2c_adapter *, struct i2c_msg *, int) = + symbol_get(i2c_transfer); + struct i2c_msg msgs[] = { + { + .addr = SAVAGE_DDC, + .len = 1, + .buf = &start, + }, { + .addr = SAVAGE_DDC, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + }, + }; + u8 *buf = NULL; + + if (transfer && chan->par) { + buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + + if (buf) { + msgs[1].buf = buf; + + if (transfer(&chan->adapter, msgs, 2) != 2) { + dev_dbg(&chan->par->pcidev->dev, + "Unable to read EDID block.\n"); + kfree(buf); + buf = NULL; + } + } + + symbol_put(i2c_transfer); + } + + return buf; +} + +int savagefb_probe_i2c_connector(struct savagefb_par *par, u8 **out_edid) +{ + u8 *edid = NULL; + int i; + + for (i = 0; i < 3; i++) { + /* Do the real work */ + edid = savage_do_probe_i2c_edid(&par->chan); + if (edid) + break; + } + if (out_edid) + *out_edid = edid; + if (!edid) + return 1; + + return 0; +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h new file mode 100644 index 000000000000..8594b1e42d71 --- /dev/null +++ b/drivers/video/savage/savagefb.h @@ -0,0 +1,354 @@ +/* + * linux/drivers/video/savagefb.h -- S3 Savage Framebuffer Driver + * + * Copyright (c) 2001 Denis Oliver Kropp <dok@convergence.de> + * + * 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 __SAVAGEFB_H__ +#define __SAVAGEFB_H__ + +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/i2c-algo-bit.h> +#include "../edid.h" + +#ifdef SAVAGEFB_DEBUG +# define DBG(x) printk (KERN_DEBUG "savagefb: %s\n", (x)); +#else +# define DBG(x) +# define SavagePrintRegs(...) +#endif + + +#define PCI_CHIP_SAVAGE4 0x8a22 +#define PCI_CHIP_SAVAGE3D 0x8a20 +#define PCI_CHIP_SAVAGE3D_MV 0x8a21 +#define PCI_CHIP_SAVAGE2000 0x9102 +#define PCI_CHIP_SAVAGE_MX_MV 0x8c10 +#define PCI_CHIP_SAVAGE_MX 0x8c11 +#define PCI_CHIP_SAVAGE_IX_MV 0x8c12 +#define PCI_CHIP_SAVAGE_IX 0x8c13 +#define PCI_CHIP_PROSAVAGE_PM 0x8a25 +#define PCI_CHIP_PROSAVAGE_KM 0x8a26 + /* Twister is a code name; hope I get the real name soon. */ +#define PCI_CHIP_S3TWISTER_P 0x8d01 +#define PCI_CHIP_S3TWISTER_K 0x8d02 +#define PCI_CHIP_PROSAVAGE_DDR 0x8d03 +#define PCI_CHIP_PROSAVAGE_DDRK 0x8d04 +#define PCI_CHIP_SUPSAV_MX128 0x8c22 +#define PCI_CHIP_SUPSAV_MX64 0x8c24 +#define PCI_CHIP_SUPSAV_MX64C 0x8c26 +#define PCI_CHIP_SUPSAV_IX128SDR 0x8c2a +#define PCI_CHIP_SUPSAV_IX128DDR 0x8c2b +#define PCI_CHIP_SUPSAV_IX64SDR 0x8c2c +#define PCI_CHIP_SUPSAV_IX64DDR 0x8c2d +#define PCI_CHIP_SUPSAV_IXCSDR 0x8c2e +#define PCI_CHIP_SUPSAV_IXCDDR 0x8c2f + + + +#define S3_SAVAGE3D_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX)) + +#define S3_SAVAGE4_SERIES(chip) ((chip==S3_SAVAGE4) || (chip==S3_PROSAVAGE)) + +#define S3_SAVAGE_MOBILE_SERIES(chip) ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE)) + +#define S3_SAVAGE_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000)) + + +/* Chip tags. These are used to group the adapters into + * related families. + */ + +typedef enum { + S3_UNKNOWN = 0, + S3_SAVAGE3D, + S3_SAVAGE_MX, + S3_SAVAGE4, + S3_PROSAVAGE, + S3_SUPERSAVAGE, + S3_SAVAGE2000, + S3_LAST +} savage_chipset; + +#define BIOS_BSIZE 1024 +#define BIOS_BASE 0xc0000 + +#define SAVAGE_NEWMMIO_REGBASE_S3 0x1000000 /* 16MB */ +#define SAVAGE_NEWMMIO_REGBASE_S4 0x0000000 +#define SAVAGE_NEWMMIO_REGSIZE 0x0080000 /* 512kb */ +#define SAVAGE_NEWMMIO_VGABASE 0x8000 + +#define BASE_FREQ 14318 +#define HALF_BASE_FREQ 7159 + +#define FIFO_CONTROL_REG 0x8200 +#define MIU_CONTROL_REG 0x8204 +#define STREAMS_TIMEOUT_REG 0x8208 +#define MISC_TIMEOUT_REG 0x820c + +#define MONO_PAT_0 0xa4e8 +#define MONO_PAT_1 0xa4ec + +#define MAXFIFO 0x7f00 + +#define BCI_CMD_NOP 0x40000000 +#define BCI_CMD_SETREG 0x96000000 +#define BCI_CMD_RECT 0x48000000 +#define BCI_CMD_RECT_XP 0x01000000 +#define BCI_CMD_RECT_YP 0x02000000 +#define BCI_CMD_SEND_COLOR 0x00008000 +#define BCI_CMD_DEST_GBD 0x00000000 +#define BCI_CMD_SRC_GBD 0x00000020 +#define BCI_CMD_SRC_SOLID 0x00000000 +#define BCI_CMD_SRC_MONO 0x00000060 +#define BCI_CMD_CLIP_NEW 0x00006000 +#define BCI_CMD_CLIP_LR 0x00004000 + +#define BCI_CLIP_LR(l, r) ((((r) << 16) | (l)) & 0x0FFF0FFF) +#define BCI_CLIP_TL(t, l) ((((t) << 16) | (l)) & 0x0FFF0FFF) +#define BCI_CLIP_BR(b, r) ((((b) << 16) | (r)) & 0x0FFF0FFF) +#define BCI_W_H(w, h) (((h) << 16) | ((w) & 0xFFF)) +#define BCI_X_Y(x, y) (((y) << 16) | ((x) & 0xFFF)) + +#define BCI_GBD1 0xE0 +#define BCI_GBD2 0xE1 + +#define BCI_BUFFER_OFFSET 0x10000 +#define BCI_SIZE 0x4000 + +#define BCI_SEND(dw) writel(dw, par->bci_base + par->bci_ptr++) + +#define BCI_CMD_GET_ROP(cmd) (((cmd) >> 16) & 0xFF) +#define BCI_CMD_SET_ROP(cmd, rop) ((cmd) |= ((rop & 0xFF) << 16)) +#define BCI_CMD_SEND_COLOR 0x00008000 + +struct xtimings { + unsigned int Clock; + unsigned int HDisplay; + unsigned int HSyncStart; + unsigned int HSyncEnd; + unsigned int HTotal; + unsigned int HAdjusted; + unsigned int VDisplay; + unsigned int VSyncStart; + unsigned int VSyncEnd; + unsigned int VTotal; + unsigned int sync; + int dblscan; + int interlaced; +}; + + +/* --------------------------------------------------------------------- */ + +#define NR_PALETTE 256 + + +struct savagefb_par; + +struct savagefb_i2c_chan { + struct savagefb_par *par; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; + volatile u8 __iomem *ioaddr; + u32 reg; +}; + +struct savagefb_par { + struct pci_dev *pcidev; + savage_chipset chip; + struct savagefb_i2c_chan chan; + unsigned char *edid; + u32 pseudo_palette[16]; + int dacSpeedBpp; + int maxClock; + int minClock; + int numClocks; + int clock[4]; + struct { + u8 __iomem *vbase; + u32 pbase; + u32 len; +#ifdef CONFIG_MTRR + int mtrr; +#endif + } video; + + struct { + volatile u8 __iomem *vbase; + u32 pbase; + u32 len; + } mmio; + + volatile u32 __iomem *bci_base; + unsigned int bci_ptr; + + u32 cob_offset; + u32 cob_size; + int cob_index; + + void (*SavageWaitIdle) (struct savagefb_par *par); + void (*SavageWaitFifo) (struct savagefb_par *par, int space); + + int MCLK, REFCLK, LCDclk; + int HorizScaleFactor; + + /* Panels size */ + int SavagePanelWidth; + int SavagePanelHeight; + + struct { + u16 red, green, blue, transp; + } palette[NR_PALETTE]; + + int depth; + int vwidth; + + unsigned char MiscOutReg; /* Misc */ + unsigned char CRTC[25]; /* Crtc Controller */ + unsigned char Sequencer[5]; /* Video Sequencer */ + unsigned char Graphics[9]; /* Video Graphics */ + unsigned char Attribute[21]; /* Video Atribute */ + + unsigned int mode, refresh; + unsigned char SR08, SR0E, SR0F; + unsigned char SR10, SR11, SR12, SR13, SR15, SR18, SR29, SR30; + unsigned char SR54[8]; + unsigned char Clock; + unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C; + unsigned char CR40, CR41, CR42, CR43, CR45; + unsigned char CR50, CR51, CR53, CR55, CR58, CR5B, CR5D, CR5E; + unsigned char CR60, CR63, CR65, CR66, CR67, CR68, CR69, CR6D, CR6F; + unsigned char CR86, CR88; + unsigned char CR90, CR91, CRB0; + unsigned int STREAMS[22]; /* yuck, streams regs */ + unsigned int MMPR0, MMPR1, MMPR2, MMPR3; +}; + +#define BCI_BD_BW_DISABLE 0x10000000 +#define BCI_BD_SET_BPP(bd, bpp) ((bd) |= (((bpp) & 0xFF) << 16)) +#define BCI_BD_SET_STRIDE(bd, st) ((bd) |= ((st) & 0xFFFF)) + + +/* IO functions */ + +#define vga_in8(addr) (inb (addr)) +#define vga_in16(addr) (inw (addr)) +#define vga_in32(addr) (inl (addr)) + +#define vga_out8(addr,val) (outb ((val), (addr))) +#define vga_out16(addr,val) (outw ((val), (addr))) +#define vga_out32(addr,val) (outl ((val), (addr))) + +#define savage_in16(addr) readw(par->mmio.vbase + (addr)) +#define savage_in32(addr) readl(par->mmio.vbase + (addr)) + +#define savage_out16(addr,val) writew((val), par->mmio.vbase + (addr)) +#define savage_out32(addr,val) writel((val), par->mmio.vbase + (addr)) + +static inline u8 VGArCR (u8 index) +{ + outb (index, 0x3d4); + return inb (0x3d5); +} + +static inline u8 VGArGR (u8 index) +{ + outb (index, 0x3ce); + return inb (0x3cf); +} + +static inline u8 VGArSEQ (u8 index) +{ + outb (index, 0x3c4); + return inb (0x3c5); +} + +#define VGAwCR(index, val) \ +do { \ + vga_out8 (0x3d4, index); \ + vga_out8 (0x3d5, val); \ +} while (0) + +#define VGAwGR(index, val) \ +do { \ + vga_out8 (0x3ce, index); \ + vga_out8 (0x3cf, val); \ +} while (0) + +#define VGAwSEQ(index, val) \ +do { \ + vga_out8 (0x3c4, index); \ + vga_out8 (0x3c5, val); \ +} while (0) + +#define VGAenablePalette() \ +do { \ + u8 tmp; \ + \ + tmp = vga_in8 (0x3da); \ + vga_out8 (0x3c0, 0x00); \ + paletteEnabled = 1; \ +} while (0) + +#define VGAdisablePalette() \ +do { \ + u8 tmp; \ + \ + tmp = vga_in8 (0x3da); \ + vga_out8 (0x3c0, 0x20); \ + paletteEnabled = 0; \ +} while (0) + +#define VGAwATTR(index, value) \ +do { \ + u8 tmp; \ + \ + if (paletteEnabled) \ + index &= ~0x20; \ + else \ + index |= 0x20; \ + \ + tmp = vga_in8 (0x3da); \ + vga_out8 (0x3c0, index); \ + vga_out8 (0x3c0, value); \ +} while (0) + +#define VGAwMISC(value) \ +do { \ + vga_out8 (0x3c2, value); \ +} while (0) + +#ifndef CONFIG_FB_SAVAGE_ACCEL +#define savagefb_set_clip(x) +#endif + +#define VerticalRetraceWait() \ +{ \ + vga_out8 (0x3d4, 0x17); \ + if (vga_in8 (0x3d5) & 0x80) { \ + while ((vga_in8(0x3da) & 0x08) == 0x08) ; \ + while ((vga_in8(0x3da) & 0x08) == 0x00) ; \ + } \ +} + +extern int savagefb_probe_i2c_connector(struct savagefb_par *par, + u8 **out_edid); +extern void savagefb_create_i2c_busses(struct fb_info *info); +extern void savagefb_delete_i2c_busses(struct fb_info *info); +extern int savagefb_sync(struct fb_info *info); +extern void savagefb_copyarea(struct fb_info *info, + const struct fb_copyarea *region); +extern void savagefb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect); +extern void savagefb_imageblit(struct fb_info *info, + const struct fb_image *image); + + +#endif /* __SAVAGEFB_H__ */ diff --git a/drivers/video/savage/savagefb_accel.c b/drivers/video/savage/savagefb_accel.c new file mode 100644 index 000000000000..bac8ea3a0108 --- /dev/null +++ b/drivers/video/savage/savagefb_accel.c @@ -0,0 +1,136 @@ +/*-*- linux-c -*- + * linux/drivers/video/savage/savage_accel.c -- Hardware Acceleration + * + * Copyright (C) 2004 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/string.h> +#include <linux/fb.h> + +#include "savagefb.h" + +static u32 savagefb_rop[] = { + 0xCC, /* ROP_COPY */ + 0x5A /* ROP_XOR */ +}; + +int savagefb_sync(struct fb_info *info) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + + par->SavageWaitIdle(par); + return 0; +} + +void savagefb_copyarea(struct fb_info *info, const struct fb_copyarea *region) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + int sx = region->sx, dx = region->dx; + int sy = region->sy, dy = region->dy; + int cmd; + + if (!region->width || !region->height) + return; + par->bci_ptr = 0; + cmd = BCI_CMD_RECT | BCI_CMD_DEST_GBD | BCI_CMD_SRC_GBD; + BCI_CMD_SET_ROP(cmd, savagefb_rop[0]); + + if (dx <= sx) { + cmd |= BCI_CMD_RECT_XP; + } else { + sx += region->width - 1; + dx += region->width - 1; + } + + if (dy <= sy) { + cmd |= BCI_CMD_RECT_YP; + } else { + sy += region->height - 1; + dy += region->height - 1; + } + + par->SavageWaitFifo(par,4); + BCI_SEND(cmd); + BCI_SEND(BCI_X_Y(sx, sy)); + BCI_SEND(BCI_X_Y(dx, dy)); + BCI_SEND(BCI_W_H(region->width, region->height)); +} + +void savagefb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + int cmd, color; + + if (!rect->width || !rect->height) + return; + + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) + color = rect->color; + else + color = ((u32 *)info->pseudo_palette)[rect->color]; + + cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | + BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID | + BCI_CMD_SEND_COLOR; + + par->bci_ptr = 0; + BCI_CMD_SET_ROP(cmd, savagefb_rop[rect->rop]); + + par->SavageWaitFifo(par,4); + BCI_SEND(cmd); + BCI_SEND(color); + BCI_SEND( BCI_X_Y(rect->dx, rect->dy) ); + BCI_SEND( BCI_W_H(rect->width, rect->height) ); +} + +void savagefb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + int fg, bg, size, i, width; + int cmd; + u32 *src = (u32 *) image->data; + + if (!image->width || !image->height) + return; + + if (image->depth != 1) { + cfb_imageblit(info, image); + return; + } + + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { + fg = image->fg_color; + bg = image->bg_color; + } else { + fg = ((u32 *)info->pseudo_palette)[image->fg_color]; + bg = ((u32 *)info->pseudo_palette)[image->bg_color]; + } + + cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | + BCI_CMD_CLIP_LR | BCI_CMD_DEST_GBD | BCI_CMD_SRC_MONO | + BCI_CMD_SEND_COLOR; + + par->bci_ptr = 0; + BCI_CMD_SET_ROP(cmd, savagefb_rop[0]); + + width = (image->width + 31) & ~31; + size = (width * image->height)/8; + size >>= 2; + + par->SavageWaitFifo(par, size + 5); + BCI_SEND(cmd); + BCI_SEND(BCI_CLIP_LR(image->dx, image->dx + image->width - 1)); + BCI_SEND(fg); + BCI_SEND(bg); + BCI_SEND(BCI_X_Y(image->dx, image->dy)); + BCI_SEND(BCI_W_H(width, image->height)); + for (i = 0; i < size; i++) + BCI_SEND(src[i]); +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c new file mode 100644 index 000000000000..e1c9c946be2d --- /dev/null +++ b/drivers/video/savage/savagefb_driver.c @@ -0,0 +1,2279 @@ +/* + * linux/drivers/video/savagefb.c -- S3 Savage Framebuffer Driver + * + * Copyright (c) 2001-2002 Denis Oliver Kropp <dok@directfb.org> + * Sven Neumann <neo@directfb.org> + * + * + * Card specific code is based on XFree86's savage driver. + * Framebuffer framework code is based on code of cyber2000fb and tdfxfb. + * + * 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. + * + * 0.4.0 (neo) + * - hardware accelerated clear and move + * + * 0.3.2 (dok) + * - wait for vertical retrace before writing to cr67 + * at the beginning of savagefb_set_par + * - use synchronization registers cr23 and cr26 + * + * 0.3.1 (dok) + * - reset 3D engine + * - don't return alpha bits for 32bit format + * + * 0.3.0 (dok) + * - added WaitIdle functions for all Savage types + * - do WaitIdle before mode switching + * - code cleanup + * + * 0.2.0 (dok) + * - first working version + * + * + * TODO + * - clock validations in decode_var + * + * BUGS + * - white margin on bootup + * + */ + +#include <linux/config.h> +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/console.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include "savagefb.h" + + +#define SAVAGEFB_VERSION "0.4.0_2.6" + +/* --------------------------------------------------------------------- */ + + +static char *mode_option __initdata = NULL; +static int paletteEnabled = 0; + +#ifdef MODULE + +MODULE_AUTHOR("(c) 2001-2002 Denis Oliver Kropp <dok@directfb.org>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips"); + +#endif + + +/* --------------------------------------------------------------------- */ + +static void vgaHWSeqReset (struct savagefb_par *par, int start) +{ + if (start) + VGAwSEQ (0x00, 0x01); /* Synchronous Reset */ + else + VGAwSEQ (0x00, 0x03); /* End Reset */ +} + +static void vgaHWProtect (struct savagefb_par *par, int on) +{ + unsigned char tmp; + + if (on) { + /* + * Turn off screen and disable sequencer. + */ + tmp = VGArSEQ (0x01); + + vgaHWSeqReset (par, 1); /* start synchronous reset */ + VGAwSEQ (0x01, tmp | 0x20); /* disable the display */ + + VGAenablePalette(); + } else { + /* + * Reenable sequencer, then turn on screen. + */ + + tmp = VGArSEQ (0x01); + + VGAwSEQ (0x01, tmp & ~0x20); /* reenable display */ + vgaHWSeqReset (par, 0); /* clear synchronous reset */ + + VGAdisablePalette(); + } +} + +static void vgaHWRestore (struct savagefb_par *par) +{ + int i; + + VGAwMISC (par->MiscOutReg); + + for (i = 1; i < 5; i++) + VGAwSEQ (i, par->Sequencer[i]); + + /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or + CRTC[17] */ + VGAwCR (17, par->CRTC[17] & ~0x80); + + for (i = 0; i < 25; i++) + VGAwCR (i, par->CRTC[i]); + + for (i = 0; i < 9; i++) + VGAwGR (i, par->Graphics[i]); + + VGAenablePalette(); + + for (i = 0; i < 21; i++) + VGAwATTR (i, par->Attribute[i]); + + VGAdisablePalette(); +} + +static void vgaHWInit (struct fb_var_screeninfo *var, + struct savagefb_par *par, + struct xtimings *timings) +{ + par->MiscOutReg = 0x23; + + if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT)) + par->MiscOutReg |= 0x40; + + if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT)) + par->MiscOutReg |= 0x80; + + /* + * Time Sequencer + */ + par->Sequencer[0x00] = 0x00; + par->Sequencer[0x01] = 0x01; + par->Sequencer[0x02] = 0x0F; + par->Sequencer[0x03] = 0x00; /* Font select */ + par->Sequencer[0x04] = 0x0E; /* Misc */ + + /* + * CRTC Controller + */ + par->CRTC[0x00] = (timings->HTotal >> 3) - 5; + par->CRTC[0x01] = (timings->HDisplay >> 3) - 1; + par->CRTC[0x02] = (timings->HSyncStart >> 3) - 1; + par->CRTC[0x03] = (((timings->HSyncEnd >> 3) - 1) & 0x1f) | 0x80; + par->CRTC[0x04] = (timings->HSyncStart >> 3); + par->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) | + (((timings->HSyncEnd >> 3)) & 0x1f); + par->CRTC[0x06] = (timings->VTotal - 2) & 0xFF; + par->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) | + (((timings->VDisplay - 1) & 0x100) >> 7) | + ((timings->VSyncStart & 0x100) >> 6) | + (((timings->VSyncStart - 1) & 0x100) >> 5) | + 0x10 | + (((timings->VTotal - 2) & 0x200) >> 4) | + (((timings->VDisplay - 1) & 0x200) >> 3) | + ((timings->VSyncStart & 0x200) >> 2); + par->CRTC[0x08] = 0x00; + par->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40; + + if (timings->dblscan) + par->CRTC[0x09] |= 0x80; + + par->CRTC[0x0a] = 0x00; + par->CRTC[0x0b] = 0x00; + par->CRTC[0x0c] = 0x00; + par->CRTC[0x0d] = 0x00; + par->CRTC[0x0e] = 0x00; + par->CRTC[0x0f] = 0x00; + par->CRTC[0x10] = timings->VSyncStart & 0xff; + par->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20; + par->CRTC[0x12] = (timings->VDisplay - 1) & 0xff; + par->CRTC[0x13] = var->xres_virtual >> 4; + par->CRTC[0x14] = 0x00; + par->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff; + par->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff; + par->CRTC[0x17] = 0xc3; + par->CRTC[0x18] = 0xff; + + /* + * are these unnecessary? + * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO); + * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO); + */ + + /* + * Graphics Display Controller + */ + par->Graphics[0x00] = 0x00; + par->Graphics[0x01] = 0x00; + par->Graphics[0x02] = 0x00; + par->Graphics[0x03] = 0x00; + par->Graphics[0x04] = 0x00; + par->Graphics[0x05] = 0x40; + par->Graphics[0x06] = 0x05; /* only map 64k VGA memory !!!! */ + par->Graphics[0x07] = 0x0F; + par->Graphics[0x08] = 0xFF; + + + par->Attribute[0x00] = 0x00; /* standard colormap translation */ + par->Attribute[0x01] = 0x01; + par->Attribute[0x02] = 0x02; + par->Attribute[0x03] = 0x03; + par->Attribute[0x04] = 0x04; + par->Attribute[0x05] = 0x05; + par->Attribute[0x06] = 0x06; + par->Attribute[0x07] = 0x07; + par->Attribute[0x08] = 0x08; + par->Attribute[0x09] = 0x09; + par->Attribute[0x0a] = 0x0A; + par->Attribute[0x0b] = 0x0B; + par->Attribute[0x0c] = 0x0C; + par->Attribute[0x0d] = 0x0D; + par->Attribute[0x0e] = 0x0E; + par->Attribute[0x0f] = 0x0F; + par->Attribute[0x10] = 0x41; + par->Attribute[0x11] = 0xFF; + par->Attribute[0x12] = 0x0F; + par->Attribute[0x13] = 0x00; + par->Attribute[0x14] = 0x00; +} + +/* -------------------- Hardware specific routines ------------------------- */ + +/* + * Hardware Acceleration for SavageFB + */ + +/* Wait for fifo space */ +static void +savage3D_waitfifo(struct savagefb_par *par, int space) +{ + int slots = MAXFIFO - space; + + while ((savage_in32(0x48C00) & 0x0000ffff) > slots); +} + +static void +savage4_waitfifo(struct savagefb_par *par, int space) +{ + int slots = MAXFIFO - space; + + while ((savage_in32(0x48C60) & 0x001fffff) > slots); +} + +static void +savage2000_waitfifo(struct savagefb_par *par, int space) +{ + int slots = MAXFIFO - space; + + while ((savage_in32(0x48C60) & 0x0000ffff) > slots); +} + +/* Wait for idle accelerator */ +static void +savage3D_waitidle(struct savagefb_par *par) +{ + while ((savage_in32(0x48C00) & 0x0008ffff) != 0x80000); +} + +static void +savage4_waitidle(struct savagefb_par *par) +{ + while ((savage_in32(0x48C60) & 0x00a00000) != 0x00a00000); +} + +static void +savage2000_waitidle(struct savagefb_par *par) +{ + while ((savage_in32(0x48C60) & 0x009fffff)); +} + + +static void +SavageSetup2DEngine (struct savagefb_par *par) +{ + unsigned long GlobalBitmapDescriptor; + + GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE; + BCI_BD_SET_BPP (GlobalBitmapDescriptor, par->depth); + BCI_BD_SET_STRIDE (GlobalBitmapDescriptor, par->vwidth); + + switch(par->chip) { + case S3_SAVAGE3D: + case S3_SAVAGE_MX: + /* Disable BCI */ + savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0); + /* Setup BCI command overflow buffer */ + savage_out32(0x48C14, (par->cob_offset >> 11) | (par->cob_index << 29)); + /* Program shadow status update. */ + savage_out32(0x48C10, 0x78207220); + savage_out32(0x48C0C, 0); + /* Enable BCI and command overflow buffer */ + savage_out32(0x48C18, savage_in32(0x48C18) | 0x0C); + break; + case S3_SAVAGE4: + case S3_PROSAVAGE: + case S3_SUPERSAVAGE: + /* Disable BCI */ + savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0); + /* Program shadow status update */ + savage_out32(0x48C10, 0x00700040); + savage_out32(0x48C0C, 0); + /* Enable BCI without the COB */ + savage_out32(0x48C18, savage_in32(0x48C18) | 0x08); + break; + case S3_SAVAGE2000: + /* Disable BCI */ + savage_out32(0x48C18, 0); + /* Setup BCI command overflow buffer */ + savage_out32(0x48C18, (par->cob_offset >> 7) | (par->cob_index)); + /* Disable shadow status update */ + savage_out32(0x48A30, 0); + /* Enable BCI and command overflow buffer */ + savage_out32(0x48C18, savage_in32(0x48C18) | 0x00280000 ); + break; + default: + break; + } + /* Turn on 16-bit register access. */ + vga_out8(0x3d4, 0x31); + vga_out8(0x3d5, 0x0c); + + /* Set stride to use GBD. */ + vga_out8 (0x3d4, 0x50); + vga_out8 (0x3d5, vga_in8 (0x3d5 ) | 0xC1); + + /* Enable 2D engine. */ + vga_out8 (0x3d4, 0x40 ); + vga_out8 (0x3d5, 0x01 ); + + savage_out32 (MONO_PAT_0, ~0); + savage_out32 (MONO_PAT_1, ~0); + + /* Setup plane masks */ + savage_out32 (0x8128, ~0 ); /* enable all write planes */ + savage_out32 (0x812C, ~0 ); /* enable all read planes */ + savage_out16 (0x8134, 0x27 ); + savage_out16 (0x8136, 0x07 ); + + /* Now set the GBD */ + par->bci_ptr = 0; + par->SavageWaitFifo (par, 4); + + BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD1 ); + BCI_SEND( 0 ); + BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD2 ); + BCI_SEND( GlobalBitmapDescriptor ); +} + + +static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1, + int min_n2, int max_n2, long freq_min, + long freq_max, unsigned int *mdiv, + unsigned int *ndiv, unsigned int *r) +{ + long diff, best_diff; + unsigned int m; + unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2; + + if (freq < freq_min / (1 << max_n2)) { + printk (KERN_ERR "invalid frequency %ld Khz\n", freq); + freq = freq_min / (1 << max_n2); + } + if (freq > freq_max / (1 << min_n2)) { + printk (KERN_ERR "invalid frequency %ld Khz\n", freq); + freq = freq_max / (1 << min_n2); + } + + /* work out suitable timings */ + best_diff = freq; + + for (n2=min_n2; n2<=max_n2; n2++) { + for (n1=min_n1+2; n1<=max_n1+2; n1++) { + m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) / + BASE_FREQ; + if (m < min_m+2 || m > 127+2) + continue; + if ((m * BASE_FREQ >= freq_min * n1) && + (m * BASE_FREQ <= freq_max * n1)) { + diff = freq * (1 << n2) * n1 - BASE_FREQ * m; + if (diff < 0) + diff = -diff; + if (diff < best_diff) { + best_diff = diff; + best_m = m; + best_n1 = n1; + best_n2 = n2; + } + } + } + } + + *ndiv = best_n1 - 2; + *r = best_n2; + *mdiv = best_m - 2; +} + +static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1, + int min_n2, int max_n2, long freq_min, + long freq_max, unsigned char *mdiv, + unsigned char *ndiv) +{ + long diff, best_diff; + unsigned int m; + unsigned char n1, n2; + unsigned char best_n1 = 16+2, best_n2 = 2, best_m = 125+2; + + best_diff = freq; + + for (n2 = min_n2; n2 <= max_n2; n2++) { + for (n1 = min_n1+2; n1 <= max_n1+2; n1++) { + m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) / + BASE_FREQ; + if (m < min_m + 2 || m > 127+2) + continue; + if((m * BASE_FREQ >= freq_min * n1) && + (m * BASE_FREQ <= freq_max * n1)) { + diff = freq * (1 << n2) * n1 - BASE_FREQ * m; + if(diff < 0) + diff = -diff; + if(diff < best_diff) { + best_diff = diff; + best_m = m; + best_n1 = n1; + best_n2 = n2; + } + } + } + } + + if(max_n1 == 63) + *ndiv = (best_n1 - 2) | (best_n2 << 6); + else + *ndiv = (best_n1 - 2) | (best_n2 << 5); + + *mdiv = best_m - 2; + + return 0; +} + +#ifdef SAVAGEFB_DEBUG +/* This function is used to debug, it prints out the contents of s3 regs */ + +static void SavagePrintRegs(void) +{ + unsigned char i; + int vgaCRIndex = 0x3d4; + int vgaCRReg = 0x3d5; + + printk(KERN_DEBUG "SR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE " + "xF" ); + + for( i = 0; i < 0x70; i++ ) { + if( !(i % 16) ) + printk(KERN_DEBUG "\nSR%xx ", i >> 4 ); + vga_out8( 0x3c4, i ); + printk(KERN_DEBUG " %02x", vga_in8(0x3c5) ); + } + + printk(KERN_DEBUG "\n\nCR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC " + "xD xE xF" ); + + for( i = 0; i < 0xB7; i++ ) { + if( !(i % 16) ) + printk(KERN_DEBUG "\nCR%xx ", i >> 4 ); + vga_out8( vgaCRIndex, i ); + printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg) ); + } + + printk(KERN_DEBUG "\n\n"); +} +#endif + +/* --------------------------------------------------------------------- */ + +static void savage_get_default_par(struct savagefb_par *par) +{ + unsigned char cr3a, cr53, cr66; + + vga_out16 (0x3d4, 0x4838); + vga_out16 (0x3d4, 0xa039); + vga_out16 (0x3c4, 0x0608); + + vga_out8 (0x3d4, 0x66); + cr66 = vga_in8 (0x3d5); + vga_out8 (0x3d5, cr66 | 0x80); + vga_out8 (0x3d4, 0x3a); + cr3a = vga_in8 (0x3d5); + vga_out8 (0x3d5, cr3a | 0x80); + vga_out8 (0x3d4, 0x53); + cr53 = vga_in8 (0x3d5); + vga_out8 (0x3d5, cr53 & 0x7f); + + vga_out8 (0x3d4, 0x66); + vga_out8 (0x3d5, cr66); + vga_out8 (0x3d4, 0x3a); + vga_out8 (0x3d5, cr3a); + + vga_out8 (0x3d4, 0x66); + vga_out8 (0x3d5, cr66); + vga_out8 (0x3d4, 0x3a); + vga_out8 (0x3d5, cr3a); + + /* unlock extended seq regs */ + vga_out8 (0x3c4, 0x08); + par->SR08 = vga_in8 (0x3c5); + vga_out8 (0x3c5, 0x06); + + /* now save all the extended regs we need */ + vga_out8 (0x3d4, 0x31); + par->CR31 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x32); + par->CR32 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x34); + par->CR34 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x36); + par->CR36 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x3a); + par->CR3A = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x40); + par->CR40 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x42); + par->CR42 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x45); + par->CR45 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x50); + par->CR50 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x51); + par->CR51 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x53); + par->CR53 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x58); + par->CR58 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x60); + par->CR60 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x66); + par->CR66 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x67); + par->CR67 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x68); + par->CR68 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x69); + par->CR69 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x6f); + par->CR6F = vga_in8 (0x3d5); + + vga_out8 (0x3d4, 0x33); + par->CR33 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x86); + par->CR86 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x88); + par->CR88 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x90); + par->CR90 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x91); + par->CR91 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0xb0); + par->CRB0 = vga_in8 (0x3d5) | 0x80; + + /* extended mode timing regs */ + vga_out8 (0x3d4, 0x3b); + par->CR3B = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x3c); + par->CR3C = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x43); + par->CR43 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x5d); + par->CR5D = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x5e); + par->CR5E = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x65); + par->CR65 = vga_in8 (0x3d5); + + /* save seq extended regs for DCLK PLL programming */ + vga_out8 (0x3c4, 0x0e); + par->SR0E = vga_in8 (0x3c5); + vga_out8 (0x3c4, 0x0f); + par->SR0F = vga_in8 (0x3c5); + vga_out8 (0x3c4, 0x10); + par->SR10 = vga_in8 (0x3c5); + vga_out8 (0x3c4, 0x11); + par->SR11 = vga_in8 (0x3c5); + vga_out8 (0x3c4, 0x12); + par->SR12 = vga_in8 (0x3c5); + vga_out8 (0x3c4, 0x13); + par->SR13 = vga_in8 (0x3c5); + vga_out8 (0x3c4, 0x29); + par->SR29 = vga_in8 (0x3c5); + + vga_out8 (0x3c4, 0x15); + par->SR15 = vga_in8 (0x3c5); + vga_out8 (0x3c4, 0x30); + par->SR30 = vga_in8 (0x3c5); + vga_out8 (0x3c4, 0x18); + par->SR18 = vga_in8 (0x3c5); + + /* Save flat panel expansion regsters. */ + if (par->chip == S3_SAVAGE_MX) { + int i; + + for (i = 0; i < 8; i++) { + vga_out8 (0x3c4, 0x54+i); + par->SR54[i] = vga_in8 (0x3c5); + } + } + + vga_out8 (0x3d4, 0x66); + cr66 = vga_in8 (0x3d5); + vga_out8 (0x3d5, cr66 | 0x80); + vga_out8 (0x3d4, 0x3a); + cr3a = vga_in8 (0x3d5); + vga_out8 (0x3d5, cr3a | 0x80); + + /* now save MIU regs */ + if (par->chip != S3_SAVAGE_MX) { + par->MMPR0 = savage_in32(FIFO_CONTROL_REG); + par->MMPR1 = savage_in32(MIU_CONTROL_REG); + par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG); + par->MMPR3 = savage_in32(MISC_TIMEOUT_REG); + } + + vga_out8 (0x3d4, 0x3a); + vga_out8 (0x3d5, cr3a); + vga_out8 (0x3d4, 0x66); + vga_out8 (0x3d5, cr66); +} + +static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb) +{ + var->xres = var->xres_virtual = modedb->xres; + var->yres = modedb->yres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + var->xoffset = var->yoffset = 0; + var->pixclock = modedb->pixclock; + var->left_margin = modedb->left_margin; + var->right_margin = modedb->right_margin; + var->upper_margin = modedb->upper_margin; + var->lower_margin = modedb->lower_margin; + var->hsync_len = modedb->hsync_len; + var->vsync_len = modedb->vsync_len; + var->sync = modedb->sync; + var->vmode = modedb->vmode; +} + +static int savagefb_check_var (struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + int memlen, vramlen, mode_valid = 0; + + DBG("savagefb_check_var"); + + var->transp.offset = 0; + var->transp.length = 0; + switch (var->bits_per_pixel) { + case 8: + var->red.offset = var->green.offset = + var->blue.offset = 0; + var->red.length = var->green.length = + var->blue.length = var->bits_per_pixel; + break; + case 16: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + case 32: + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + break; + + default: + return -EINVAL; + } + + if (!info->monspecs.hfmax || !info->monspecs.vfmax || + !info->monspecs.dclkmax || !fb_validate_mode(var, info)) + mode_valid = 1; + + /* calculate modeline if supported by monitor */ + if (!mode_valid && info->monspecs.gtf) { + if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info)) + mode_valid = 1; + } + + if (!mode_valid) { + struct fb_videomode *mode; + + mode = fb_find_best_mode(var, &info->modelist); + if (mode) { + savage_update_var(var, mode); + mode_valid = 1; + } + } + + if (!mode_valid && info->monspecs.modedb_len) + return -EINVAL; + + /* Is the mode larger than the LCD panel? */ + if (par->SavagePanelWidth && + (var->xres > par->SavagePanelWidth || + var->yres > par->SavagePanelHeight)) { + printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel " + "(%dx%d)\n", var->xres, var->yres, + par->SavagePanelWidth, + par->SavagePanelHeight); + return -1; + } + + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + + vramlen = info->fix.smem_len; + + memlen = var->xres_virtual * var->bits_per_pixel * + var->yres_virtual / 8; + if (memlen > vramlen) { + var->yres_virtual = vramlen * 8 / + (var->xres_virtual * var->bits_per_pixel); + memlen = var->xres_virtual * var->bits_per_pixel * + var->yres_virtual / 8; + } + + /* we must round yres/xres down, we already rounded y/xres_virtual up + if it was possible. We should return -EINVAL, but I disagree */ + if (var->yres_virtual < var->yres) + var->yres = var->yres_virtual; + if (var->xres_virtual < var->xres) + var->xres = var->xres_virtual; + if (var->xoffset + var->xres > var->xres_virtual) + var->xoffset = var->xres_virtual - var->xres; + if (var->yoffset + var->yres > var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres; + + return 0; +} + + +static int savagefb_decode_var (struct fb_var_screeninfo *var, + struct savagefb_par *par) +{ + struct xtimings timings; + int width, dclk, i, j; /*, refresh; */ + unsigned int m, n, r; + unsigned char tmp = 0; + unsigned int pixclock = var->pixclock; + + DBG("savagefb_decode_var"); + + memset (&timings, 0, sizeof(timings)); + + if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ + timings.Clock = 1000000000 / pixclock; + if (timings.Clock < 1) timings.Clock = 1; + timings.dblscan = var->vmode & FB_VMODE_DOUBLE; + timings.interlaced = var->vmode & FB_VMODE_INTERLACED; + timings.HDisplay = var->xres; + timings.HSyncStart = timings.HDisplay + var->right_margin; + timings.HSyncEnd = timings.HSyncStart + var->hsync_len; + timings.HTotal = timings.HSyncEnd + var->left_margin; + timings.VDisplay = var->yres; + timings.VSyncStart = timings.VDisplay + var->lower_margin; + timings.VSyncEnd = timings.VSyncStart + var->vsync_len; + timings.VTotal = timings.VSyncEnd + var->upper_margin; + timings.sync = var->sync; + + + par->depth = var->bits_per_pixel; + par->vwidth = var->xres_virtual; + + if (var->bits_per_pixel == 16 && par->chip == S3_SAVAGE3D) { + timings.HDisplay *= 2; + timings.HSyncStart *= 2; + timings.HSyncEnd *= 2; + timings.HTotal *= 2; + } + + /* + * This will allocate the datastructure and initialize all of the + * generic VGA registers. + */ + vgaHWInit (var, par, &timings); + + /* We need to set CR67 whether or not we use the BIOS. */ + + dclk = timings.Clock; + par->CR67 = 0x00; + + switch( var->bits_per_pixel ) { + case 8: + if( (par->chip == S3_SAVAGE2000) && (dclk >= 230000) ) + par->CR67 = 0x10; /* 8bpp, 2 pixels/clock */ + else + par->CR67 = 0x00; /* 8bpp, 1 pixel/clock */ + break; + case 15: + if ( S3_SAVAGE_MOBILE_SERIES(par->chip) || + ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) ) + par->CR67 = 0x30; /* 15bpp, 2 pixel/clock */ + else + par->CR67 = 0x20; /* 15bpp, 1 pixels/clock */ + break; + case 16: + if( S3_SAVAGE_MOBILE_SERIES(par->chip) || + ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) ) + par->CR67 = 0x50; /* 16bpp, 2 pixel/clock */ + else + par->CR67 = 0x40; /* 16bpp, 1 pixels/clock */ + break; + case 24: + par->CR67 = 0x70; + break; + case 32: + par->CR67 = 0xd0; + break; + } + + /* + * Either BIOS use is disabled, or we failed to find a suitable + * match. Fall back to traditional register-crunching. + */ + + vga_out8 (0x3d4, 0x3a); + tmp = vga_in8 (0x3d5); + if (1 /*FIXME:psav->pci_burst*/) + par->CR3A = (tmp & 0x7f) | 0x15; + else + par->CR3A = tmp | 0x95; + + par->CR53 = 0x00; + par->CR31 = 0x8c; + par->CR66 = 0x89; + + vga_out8 (0x3d4, 0x58); + par->CR58 = vga_in8 (0x3d5) & 0x80; + par->CR58 |= 0x13; + + par->SR15 = 0x03 | 0x80; + par->SR18 = 0x00; + par->CR43 = par->CR45 = par->CR65 = 0x00; + + vga_out8 (0x3d4, 0x40); + par->CR40 = vga_in8 (0x3d5) & ~0x01; + + par->MMPR0 = 0x010400; + par->MMPR1 = 0x00; + par->MMPR2 = 0x0808; + par->MMPR3 = 0x08080810; + + SavageCalcClock (dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r); + /* m = 107; n = 4; r = 2; */ + + if (par->MCLK <= 0) { + par->SR10 = 255; + par->SR11 = 255; + } else { + common_calc_clock (par->MCLK, 1, 1, 31, 0, 3, 135000, 270000, + &par->SR11, &par->SR10); + /* par->SR10 = 80; // MCLK == 286000 */ + /* par->SR11 = 125; */ + } + + par->SR12 = (r << 6) | (n & 0x3f); + par->SR13 = m & 0xff; + par->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2; + + if (var->bits_per_pixel < 24) + par->MMPR0 -= 0x8000; + else + par->MMPR0 -= 0x4000; + + if (timings.interlaced) + par->CR42 = 0x20; + else + par->CR42 = 0x00; + + par->CR34 = 0x10; /* display fifo */ + + i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) | + ((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) | + ((((timings.HSyncStart >> 3) - 1) & 0x100) >> 6) | + ((timings.HSyncStart & 0x800) >> 7); + + if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 64) + i |= 0x08; + if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32) + i |= 0x20; + + j = (par->CRTC[0] + ((i & 0x01) << 8) + + par->CRTC[4] + ((i & 0x10) << 4) + 1) / 2; + + if (j - (par->CRTC[4] + ((i & 0x10) << 4)) < 4) { + if (par->CRTC[4] + ((i & 0x10) << 4) + 4 <= + par->CRTC[0] + ((i & 0x01) << 8)) + j = par->CRTC[4] + ((i & 0x10) << 4) + 4; + else + j = par->CRTC[0] + ((i & 0x01) << 8) + 1; + } + + par->CR3B = j & 0xff; + i |= (j & 0x100) >> 2; + par->CR3C = (par->CRTC[0] + ((i & 0x01) << 8)) / 2; + par->CR5D = i; + par->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) | + (((timings.VDisplay - 1) & 0x400) >> 9) | + (((timings.VSyncStart) & 0x400) >> 8) | + (((timings.VSyncStart) & 0x400) >> 6) | 0x40; + width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3; + par->CR91 = par->CRTC[19] = 0xff & width; + par->CR51 = (0x300 & width) >> 4; + par->CR90 = 0x80 | (width >> 8); + par->MiscOutReg |= 0x0c; + + /* Set frame buffer description. */ + + if (var->bits_per_pixel <= 8) + par->CR50 = 0; + else if (var->bits_per_pixel <= 16) + par->CR50 = 0x10; + else + par->CR50 = 0x30; + + if (var->xres_virtual <= 640) + par->CR50 |= 0x40; + else if (var->xres_virtual == 800) + par->CR50 |= 0x80; + else if (var->xres_virtual == 1024) + par->CR50 |= 0x00; + else if (var->xres_virtual == 1152) + par->CR50 |= 0x01; + else if (var->xres_virtual == 1280) + par->CR50 |= 0xc0; + else if (var->xres_virtual == 1600) + par->CR50 |= 0x81; + else + par->CR50 |= 0xc1; /* Use GBD */ + + if( par->chip == S3_SAVAGE2000 ) + par->CR33 = 0x08; + else + par->CR33 = 0x20; + + par->CRTC[0x17] = 0xeb; + + par->CR67 |= 1; + + vga_out8(0x3d4, 0x36); + par->CR36 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x68); + par->CR68 = vga_in8 (0x3d5); + par->CR69 = 0; + vga_out8 (0x3d4, 0x6f); + par->CR6F = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x86); + par->CR86 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x88); + par->CR88 = vga_in8 (0x3d5) | 0x08; + vga_out8 (0x3d4, 0xb0); + par->CRB0 = vga_in8 (0x3d5) | 0x80; + + return 0; +} + +/* --------------------------------------------------------------------- */ + +/* + * Set a single color register. Return != 0 for invalid regno. + */ +static int savagefb_setcolreg(unsigned regno, + unsigned red, + unsigned green, + unsigned blue, + unsigned transp, + struct fb_info *info) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + + if (regno >= NR_PALETTE) + return -EINVAL; + + par->palette[regno].red = red; + par->palette[regno].green = green; + par->palette[regno].blue = blue; + par->palette[regno].transp = transp; + + switch (info->var.bits_per_pixel) { + case 8: + vga_out8 (0x3c8, regno); + + vga_out8 (0x3c9, red >> 10); + vga_out8 (0x3c9, green >> 10); + vga_out8 (0x3c9, blue >> 10); + break; + + case 16: + if (regno < 16) + ((u32 *)info->pseudo_palette)[regno] = + ((red & 0xf800) ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + + case 24: + if (regno < 16) + ((u32 *)info->pseudo_palette)[regno] = + ((red & 0xff00) << 8) | + ((green & 0xff00) ) | + ((blue & 0xff00) >> 8); + break; + case 32: + if (regno < 16) + ((u32 *)info->pseudo_palette)[regno] = + ((transp & 0xff00) << 16) | + ((red & 0xff00) << 8) | + ((green & 0xff00) ) | + ((blue & 0xff00) >> 8); + break; + + default: + return 1; + } + + return 0; +} + +static void savagefb_set_par_int (struct savagefb_par *par) +{ + unsigned char tmp, cr3a, cr66, cr67; + + DBG ("savagefb_set_par_int"); + + par->SavageWaitIdle (par); + + vga_out8 (0x3c2, 0x23); + + vga_out16 (0x3d4, 0x4838); + vga_out16 (0x3d4, 0xa539); + vga_out16 (0x3c4, 0x0608); + + vgaHWProtect (par, 1); + + /* + * Some Savage/MX and /IX systems go nuts when trying to exit the + * server after WindowMaker has displayed a gradient background. I + * haven't been able to find what causes it, but a non-destructive + * switch to mode 3 here seems to eliminate the issue. + */ + + VerticalRetraceWait(); + vga_out8 (0x3d4, 0x67); + cr67 = vga_in8 (0x3d5); + vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c); /* no STREAMS yet */ + + vga_out8 (0x3d4, 0x23); + vga_out8 (0x3d5, 0x00); + vga_out8 (0x3d4, 0x26); + vga_out8 (0x3d5, 0x00); + + /* restore extended regs */ + vga_out8 (0x3d4, 0x66); + vga_out8 (0x3d5, par->CR66); + vga_out8 (0x3d4, 0x3a); + vga_out8 (0x3d5, par->CR3A); + vga_out8 (0x3d4, 0x31); + vga_out8 (0x3d5, par->CR31); + vga_out8 (0x3d4, 0x32); + vga_out8 (0x3d5, par->CR32); + vga_out8 (0x3d4, 0x58); + vga_out8 (0x3d5, par->CR58); + vga_out8 (0x3d4, 0x53); + vga_out8 (0x3d5, par->CR53 & 0x7f); + + vga_out16 (0x3c4, 0x0608); + + /* Restore DCLK registers. */ + + vga_out8 (0x3c4, 0x0e); + vga_out8 (0x3c5, par->SR0E); + vga_out8 (0x3c4, 0x0f); + vga_out8 (0x3c5, par->SR0F); + vga_out8 (0x3c4, 0x29); + vga_out8 (0x3c5, par->SR29); + vga_out8 (0x3c4, 0x15); + vga_out8 (0x3c5, par->SR15); + + /* Restore flat panel expansion regsters. */ + if( par->chip == S3_SAVAGE_MX ) { + int i; + + for( i = 0; i < 8; i++ ) { + vga_out8 (0x3c4, 0x54+i); + vga_out8 (0x3c5, par->SR54[i]); + } + } + + vgaHWRestore (par); + + /* extended mode timing registers */ + vga_out8 (0x3d4, 0x53); + vga_out8 (0x3d5, par->CR53); + vga_out8 (0x3d4, 0x5d); + vga_out8 (0x3d5, par->CR5D); + vga_out8 (0x3d4, 0x5e); + vga_out8 (0x3d5, par->CR5E); + vga_out8 (0x3d4, 0x3b); + vga_out8 (0x3d5, par->CR3B); + vga_out8 (0x3d4, 0x3c); + vga_out8 (0x3d5, par->CR3C); + vga_out8 (0x3d4, 0x43); + vga_out8 (0x3d5, par->CR43); + vga_out8 (0x3d4, 0x65); + vga_out8 (0x3d5, par->CR65); + + /* restore the desired video mode with cr67 */ + vga_out8 (0x3d4, 0x67); + /* following part not present in X11 driver */ + cr67 = vga_in8 (0x3d5) & 0xf; + vga_out8 (0x3d5, 0x50 | cr67); + udelay (10000); + vga_out8 (0x3d4, 0x67); + /* end of part */ + vga_out8 (0x3d5, par->CR67 & ~0x0c); + + /* other mode timing and extended regs */ + vga_out8 (0x3d4, 0x34); + vga_out8 (0x3d5, par->CR34); + vga_out8 (0x3d4, 0x40); + vga_out8 (0x3d5, par->CR40); + vga_out8 (0x3d4, 0x42); + vga_out8 (0x3d5, par->CR42); + vga_out8 (0x3d4, 0x45); + vga_out8 (0x3d5, par->CR45); + vga_out8 (0x3d4, 0x50); + vga_out8 (0x3d5, par->CR50); + vga_out8 (0x3d4, 0x51); + vga_out8 (0x3d5, par->CR51); + + /* memory timings */ + vga_out8 (0x3d4, 0x36); + vga_out8 (0x3d5, par->CR36); + vga_out8 (0x3d4, 0x60); + vga_out8 (0x3d5, par->CR60); + vga_out8 (0x3d4, 0x68); + vga_out8 (0x3d5, par->CR68); + vga_out8 (0x3d4, 0x69); + vga_out8 (0x3d5, par->CR69); + vga_out8 (0x3d4, 0x6f); + vga_out8 (0x3d5, par->CR6F); + + vga_out8 (0x3d4, 0x33); + vga_out8 (0x3d5, par->CR33); + vga_out8 (0x3d4, 0x86); + vga_out8 (0x3d5, par->CR86); + vga_out8 (0x3d4, 0x88); + vga_out8 (0x3d5, par->CR88); + vga_out8 (0x3d4, 0x90); + vga_out8 (0x3d5, par->CR90); + vga_out8 (0x3d4, 0x91); + vga_out8 (0x3d5, par->CR91); + + if (par->chip == S3_SAVAGE4) { + vga_out8 (0x3d4, 0xb0); + vga_out8 (0x3d5, par->CRB0); + } + + vga_out8 (0x3d4, 0x32); + vga_out8 (0x3d5, par->CR32); + + /* unlock extended seq regs */ + vga_out8 (0x3c4, 0x08); + vga_out8 (0x3c5, 0x06); + + /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates + * that we should leave the default SR10 and SR11 values there. + */ + if (par->SR10 != 255) { + vga_out8 (0x3c4, 0x10); + vga_out8 (0x3c5, par->SR10); + vga_out8 (0x3c4, 0x11); + vga_out8 (0x3c5, par->SR11); + } + + /* restore extended seq regs for dclk */ + vga_out8 (0x3c4, 0x0e); + vga_out8 (0x3c5, par->SR0E); + vga_out8 (0x3c4, 0x0f); + vga_out8 (0x3c5, par->SR0F); + vga_out8 (0x3c4, 0x12); + vga_out8 (0x3c5, par->SR12); + vga_out8 (0x3c4, 0x13); + vga_out8 (0x3c5, par->SR13); + vga_out8 (0x3c4, 0x29); + vga_out8 (0x3c5, par->SR29); + + vga_out8 (0x3c4, 0x18); + vga_out8 (0x3c5, par->SR18); + + /* load new m, n pll values for dclk & mclk */ + vga_out8 (0x3c4, 0x15); + tmp = vga_in8 (0x3c5) & ~0x21; + + vga_out8 (0x3c5, tmp | 0x03); + vga_out8 (0x3c5, tmp | 0x23); + vga_out8 (0x3c5, tmp | 0x03); + vga_out8 (0x3c5, par->SR15); + udelay (100); + + vga_out8 (0x3c4, 0x30); + vga_out8 (0x3c5, par->SR30); + vga_out8 (0x3c4, 0x08); + vga_out8 (0x3c5, par->SR08); + + /* now write out cr67 in full, possibly starting STREAMS */ + VerticalRetraceWait(); + vga_out8 (0x3d4, 0x67); + vga_out8 (0x3d5, par->CR67); + + vga_out8 (0x3d4, 0x66); + cr66 = vga_in8 (0x3d5); + vga_out8 (0x3d5, cr66 | 0x80); + vga_out8 (0x3d4, 0x3a); + cr3a = vga_in8 (0x3d5); + vga_out8 (0x3d5, cr3a | 0x80); + + if (par->chip != S3_SAVAGE_MX) { + VerticalRetraceWait(); + savage_out32 (FIFO_CONTROL_REG, par->MMPR0); + par->SavageWaitIdle (par); + savage_out32 (MIU_CONTROL_REG, par->MMPR1); + par->SavageWaitIdle (par); + savage_out32 (STREAMS_TIMEOUT_REG, par->MMPR2); + par->SavageWaitIdle (par); + savage_out32 (MISC_TIMEOUT_REG, par->MMPR3); + } + + vga_out8 (0x3d4, 0x66); + vga_out8 (0x3d5, cr66); + vga_out8 (0x3d4, 0x3a); + vga_out8 (0x3d5, cr3a); + + SavageSetup2DEngine (par); + vgaHWProtect (par, 0); +} + +static void savagefb_update_start (struct savagefb_par *par, + struct fb_var_screeninfo *var) +{ + int base; + + base = ((var->yoffset * var->xres_virtual + (var->xoffset & ~1)) + * ((var->bits_per_pixel+7) / 8)) >> 2; + + /* now program the start address registers */ + vga_out16(0x3d4, (base & 0x00ff00) | 0x0c); + vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d); + vga_out8 (0x3d4, 0x69); + vga_out8 (0x3d5, (base & 0x7f0000) >> 16); +} + + +static void savagefb_set_fix(struct fb_info *info) +{ + info->fix.line_length = info->var.xres_virtual * + info->var.bits_per_pixel / 8; + + if (info->var.bits_per_pixel == 8) + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + else + info->fix.visual = FB_VISUAL_TRUECOLOR; +} + +#if defined(CONFIG_FB_SAVAGE_ACCEL) +static void savagefb_set_clip(struct fb_info *info) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + int cmd; + + cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW; + par->bci_ptr = 0; + par->SavageWaitFifo(par,3); + BCI_SEND(cmd); + BCI_SEND(BCI_CLIP_TL(0, 0)); + BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff)); +} +#endif + +static int savagefb_set_par (struct fb_info *info) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + struct fb_var_screeninfo *var = &info->var; + int err; + + DBG("savagefb_set_par"); + err = savagefb_decode_var (var, par); + if (err) + return err; + + if (par->dacSpeedBpp <= 0) { + if (var->bits_per_pixel > 24) + par->dacSpeedBpp = par->clock[3]; + else if (var->bits_per_pixel >= 24) + par->dacSpeedBpp = par->clock[2]; + else if ((var->bits_per_pixel > 8) && (var->bits_per_pixel < 24)) + par->dacSpeedBpp = par->clock[1]; + else if (var->bits_per_pixel <= 8) + par->dacSpeedBpp = par->clock[0]; + } + + /* Set ramdac limits */ + par->maxClock = par->dacSpeedBpp; + par->minClock = 10000; + + savagefb_set_par_int (par); + savagefb_update_start (par, var); + fb_set_cmap (&info->cmap, info); + savagefb_set_fix(info); + savagefb_set_clip(info); + + SavagePrintRegs(); + return 0; +} + +/* + * Pan or Wrap the Display + */ +static int savagefb_pan_display (struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + u_int y_bottom; + + y_bottom = var->yoffset; + + if (!(var->vmode & FB_VMODE_YWRAP)) + y_bottom += var->yres; + + if (var->xoffset > (var->xres_virtual - var->xres)) + return -EINVAL; + if (y_bottom > info->var.yres_virtual) + return -EINVAL; + + savagefb_update_start (par, var); + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + + return 0; +} + + +static struct fb_ops savagefb_ops = { + .owner = THIS_MODULE, + .fb_check_var = savagefb_check_var, + .fb_set_par = savagefb_set_par, + .fb_setcolreg = savagefb_setcolreg, + .fb_pan_display = savagefb_pan_display, +#if defined(CONFIG_FB_SAVAGE_ACCEL) + .fb_fillrect = savagefb_fillrect, + .fb_copyarea = savagefb_copyarea, + .fb_imageblit = savagefb_imageblit, + .fb_sync = savagefb_sync, +#else + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +#endif + .fb_cursor = soft_cursor, +}; + +/* --------------------------------------------------------------------- */ + +static struct fb_var_screeninfo __devinitdata savagefb_var800x600x8 = { + .accel_flags = FB_ACCELF_TEXT, + .xres = 800, + .yres = 600, + .xres_virtual = 800, + .yres_virtual = 600, + .bits_per_pixel = 8, + .pixclock = 25000, + .left_margin = 88, + .right_margin = 40, + .upper_margin = 23, + .lower_margin = 1, + .hsync_len = 128, + .vsync_len = 4, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED +}; + +static void savage_enable_mmio (struct savagefb_par *par) +{ + unsigned char val; + + DBG ("savage_enable_mmio\n"); + + val = vga_in8 (0x3c3); + vga_out8 (0x3c3, val | 0x01); + val = vga_in8 (0x3cc); + vga_out8 (0x3c2, val | 0x01); + + if (par->chip >= S3_SAVAGE4) { + vga_out8 (0x3d4, 0x40); + val = vga_in8 (0x3d5); + vga_out8 (0x3d5, val | 1); + } +} + + +static void savage_disable_mmio (struct savagefb_par *par) +{ + unsigned char val; + + DBG ("savage_disable_mmio\n"); + + if(par->chip >= S3_SAVAGE4 ) { + vga_out8 (0x3d4, 0x40); + val = vga_in8 (0x3d5); + vga_out8 (0x3d5, val | 1); + } +} + + +static int __devinit savage_map_mmio (struct fb_info *info) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + DBG ("savage_map_mmio"); + + if (S3_SAVAGE3D_SERIES (par->chip)) + par->mmio.pbase = pci_resource_start (par->pcidev, 0) + + SAVAGE_NEWMMIO_REGBASE_S3; + else + par->mmio.pbase = pci_resource_start (par->pcidev, 0) + + SAVAGE_NEWMMIO_REGBASE_S4; + + par->mmio.len = SAVAGE_NEWMMIO_REGSIZE; + + par->mmio.vbase = ioremap (par->mmio.pbase, par->mmio.len); + if (!par->mmio.vbase) { + printk ("savagefb: unable to map memory mapped IO\n"); + return -ENOMEM; + } else + printk (KERN_INFO "savagefb: mapped io at %p\n", + par->mmio.vbase); + + info->fix.mmio_start = par->mmio.pbase; + info->fix.mmio_len = par->mmio.len; + + par->bci_base = (u32*)(par->mmio.vbase + BCI_BUFFER_OFFSET); + par->bci_ptr = 0; + + savage_enable_mmio (par); + + return 0; +} + +static void __devinit savage_unmap_mmio (struct fb_info *info) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + DBG ("savage_unmap_mmio"); + + savage_disable_mmio(par); + + if (par->mmio.vbase) { + iounmap ((void *)par->mmio.vbase); + par->mmio.vbase = NULL; + } +} + +static int __devinit savage_map_video (struct fb_info *info, + int video_len) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + int resource; + + DBG("savage_map_video"); + + if (S3_SAVAGE3D_SERIES (par->chip)) + resource = 0; + else + resource = 1; + + par->video.pbase = pci_resource_start (par->pcidev, resource); + par->video.len = video_len; + par->video.vbase = ioremap (par->video.pbase, par->video.len); + + if (!par->video.vbase) { + printk ("savagefb: unable to map screen memory\n"); + return -ENOMEM; + } else + printk (KERN_INFO "savagefb: mapped framebuffer at %p, " + "pbase == %x\n", par->video.vbase, par->video.pbase); + + info->fix.smem_start = par->video.pbase; + info->fix.smem_len = par->video.len - par->cob_size; + info->screen_base = par->video.vbase; + +#ifdef CONFIG_MTRR + par->video.mtrr = mtrr_add (par->video.pbase, video_len, + MTRR_TYPE_WRCOMB, 1); +#endif + + /* Clear framebuffer, it's all white in memory after boot */ + memset (par->video.vbase, 0, par->video.len); + + return 0; +} + +static void __devinit savage_unmap_video (struct fb_info *info) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + + DBG("savage_unmap_video"); + + if (par->video.vbase) { +#ifdef CONFIG_MTRR + mtrr_del (par->video.mtrr, par->video.pbase, par->video.len); +#endif + + iounmap (par->video.vbase); + par->video.vbase = NULL; + info->screen_base = NULL; + } +} + +static int __devinit savage_init_hw (struct savagefb_par *par) +{ + unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp; + + static unsigned char RamSavage3D[] = { 8, 4, 4, 2 }; + static unsigned char RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 }; + static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 }; + static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 }; + + int videoRam, videoRambytes; + + DBG("savage_init_hw"); + + /* unprotect CRTC[0-7] */ + vga_out8(0x3d4, 0x11); + tmp = vga_in8(0x3d5); + vga_out8(0x3d5, tmp & 0x7f); + + /* unlock extended regs */ + vga_out16(0x3d4, 0x4838); + vga_out16(0x3d4, 0xa039); + vga_out16(0x3c4, 0x0608); + + vga_out8(0x3d4, 0x40); + tmp = vga_in8(0x3d5); + vga_out8(0x3d5, tmp & ~0x01); + + /* unlock sys regs */ + vga_out8(0x3d4, 0x38); + vga_out8(0x3d5, 0x48); + + /* Unlock system registers. */ + vga_out16(0x3d4, 0x4838); + + /* Next go on to detect amount of installed ram */ + + vga_out8(0x3d4, 0x36); /* for register CR36 (CONFG_REG1), */ + config1 = vga_in8(0x3d5); /* get amount of vram installed */ + + /* Compute the amount of video memory and offscreen memory. */ + + switch (par->chip) { + case S3_SAVAGE3D: + videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024; + break; + + case S3_SAVAGE4: + /* + * The Savage4 has one ugly special case to consider. On + * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB + * when it really means 8MB. Why do it the same when you + * can do it different... + */ + vga_out8(0x3d4, 0x68); /* memory control 1 */ + if( (vga_in8(0x3d5) & 0xC0) == (0x01 << 6) ) + RamSavage4[1] = 8; + + /*FALLTHROUGH*/ + + case S3_SAVAGE2000: + videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024; + break; + + case S3_SAVAGE_MX: + case S3_SUPERSAVAGE: + videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024; + break; + + case S3_PROSAVAGE: + videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024; + break; + + default: + /* How did we get here? */ + videoRam = 0; + break; + } + + videoRambytes = videoRam * 1024; + + printk (KERN_INFO "savagefb: probed videoram: %dk\n", videoRam); + + /* reset graphics engine to avoid memory corruption */ + vga_out8 (0x3d4, 0x66); + cr66 = vga_in8 (0x3d5); + vga_out8 (0x3d5, cr66 | 0x02); + udelay (10000); + + vga_out8 (0x3d4, 0x66); + vga_out8 (0x3d5, cr66 & ~0x02); /* clear reset flag */ + udelay (10000); + + + /* + * reset memory interface, 3D engine, AGP master, PCI master, + * master engine unit, motion compensation/LPB + */ + vga_out8 (0x3d4, 0x3f); + cr3f = vga_in8 (0x3d5); + vga_out8 (0x3d5, cr3f | 0x08); + udelay (10000); + + vga_out8 (0x3d4, 0x3f); + vga_out8 (0x3d5, cr3f & ~0x08); /* clear reset flags */ + udelay (10000); + + /* Savage ramdac speeds */ + par->numClocks = 4; + par->clock[0] = 250000; + par->clock[1] = 250000; + par->clock[2] = 220000; + par->clock[3] = 220000; + + /* detect current mclk */ + vga_out8(0x3c4, 0x08); + sr8 = vga_in8(0x3c5); + vga_out8(0x3c5, 0x06); + vga_out8(0x3c4, 0x10); + n = vga_in8(0x3c5); + vga_out8(0x3c4, 0x11); + m = vga_in8(0x3c5); + vga_out8(0x3c4, 0x08); + vga_out8(0x3c5, sr8); + m &= 0x7f; + n1 = n & 0x1f; + n2 = (n >> 5) & 0x03; + par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100; + printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n", + par->MCLK); + + /* Check LCD panel parrmation */ + + if (par->chip == S3_SAVAGE_MX) { + unsigned char cr6b = VGArCR( 0x6b ); + + int panelX = (VGArSEQ (0x61) + + ((VGArSEQ (0x66) & 0x02) << 7) + 1) * 8; + int panelY = (VGArSEQ (0x69) + + ((VGArSEQ (0x6e) & 0x70) << 4) + 1); + + char * sTechnology = "Unknown"; + + /* OK, I admit it. I don't know how to limit the max dot clock + * for LCD panels of various sizes. I thought I copied the + * formula from the BIOS, but many users have parrmed me of + * my folly. + * + * Instead, I'll abandon any attempt to automatically limit the + * clock, and add an LCDClock option to XF86Config. Some day, + * I should come back to this. + */ + + enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */ + ActiveCRT = 0x01, + ActiveLCD = 0x02, + ActiveTV = 0x04, + ActiveCRT2 = 0x20, + ActiveDUO = 0x80 + }; + + if ((VGArSEQ (0x39) & 0x03) == 0) { + sTechnology = "TFT"; + } else if ((VGArSEQ (0x30) & 0x01) == 0) { + sTechnology = "DSTN"; + } else { + sTechnology = "STN"; + } + + printk (KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n", + panelX, panelY, sTechnology, + cr6b & ActiveLCD ? "and active" : "but not active"); + + if( cr6b & ActiveLCD ) { + /* + * If the LCD is active and panel expansion is enabled, + * we probably want to kill the HW cursor. + */ + + printk (KERN_INFO "savagefb: Limiting video mode to " + "%dx%d\n", panelX, panelY ); + + par->SavagePanelWidth = panelX; + par->SavagePanelHeight = panelY; + + } + } + + savage_get_default_par (par); + + if( S3_SAVAGE4_SERIES(par->chip) ) { + /* + * The Savage4 and ProSavage have COB coherency bugs which + * render the buffer useless. We disable it. + */ + par->cob_index = 2; + par->cob_size = 0x8000 << par->cob_index; + par->cob_offset = videoRambytes; + } else { + /* We use 128kB for the COB on all chips. */ + + par->cob_index = 7; + par->cob_size = 0x400 << par->cob_index; + par->cob_offset = videoRambytes - par->cob_size; + } + + return videoRambytes; +} + +static int __devinit savage_init_fb_info (struct fb_info *info, + struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct savagefb_par *par = (struct savagefb_par *)info->par; + int err = 0; + + par->pcidev = dev; + + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + info->fix.xpanstep = 2; + info->fix.ypanstep = 1; + info->fix.ywrapstep = 0; + info->fix.accel = id->driver_data; + + switch (info->fix.accel) { + case FB_ACCEL_SUPERSAVAGE: + par->chip = S3_SUPERSAVAGE; + snprintf (info->fix.id, 16, "SuperSavage"); + break; + case FB_ACCEL_SAVAGE4: + par->chip = S3_SAVAGE4; + snprintf (info->fix.id, 16, "Savage4"); + break; + case FB_ACCEL_SAVAGE3D: + par->chip = S3_SAVAGE3D; + snprintf (info->fix.id, 16, "Savage3D"); + break; + case FB_ACCEL_SAVAGE3D_MV: + par->chip = S3_SAVAGE3D; + snprintf (info->fix.id, 16, "Savage3D-MV"); + break; + case FB_ACCEL_SAVAGE2000: + par->chip = S3_SAVAGE2000; + snprintf (info->fix.id, 16, "Savage2000"); + break; + case FB_ACCEL_SAVAGE_MX_MV: + par->chip = S3_SAVAGE_MX; + snprintf (info->fix.id, 16, "Savage/MX-MV"); + break; + case FB_ACCEL_SAVAGE_MX: + par->chip = S3_SAVAGE_MX; + snprintf (info->fix.id, 16, "Savage/MX"); + break; + case FB_ACCEL_SAVAGE_IX_MV: + par->chip = S3_SAVAGE_MX; + snprintf (info->fix.id, 16, "Savage/IX-MV"); + break; + case FB_ACCEL_SAVAGE_IX: + par->chip = S3_SAVAGE_MX; + snprintf (info->fix.id, 16, "Savage/IX"); + break; + case FB_ACCEL_PROSAVAGE_PM: + par->chip = S3_PROSAVAGE; + snprintf (info->fix.id, 16, "ProSavagePM"); + break; + case FB_ACCEL_PROSAVAGE_KM: + par->chip = S3_PROSAVAGE; + snprintf (info->fix.id, 16, "ProSavageKM"); + break; + case FB_ACCEL_S3TWISTER_P: + par->chip = S3_PROSAVAGE; + snprintf (info->fix.id, 16, "TwisterP"); + break; + case FB_ACCEL_S3TWISTER_K: + par->chip = S3_PROSAVAGE; + snprintf (info->fix.id, 16, "TwisterK"); + break; + case FB_ACCEL_PROSAVAGE_DDR: + par->chip = S3_PROSAVAGE; + snprintf (info->fix.id, 16, "ProSavageDDR"); + break; + case FB_ACCEL_PROSAVAGE_DDRK: + par->chip = S3_PROSAVAGE; + snprintf (info->fix.id, 16, "ProSavage8"); + break; + } + + if (S3_SAVAGE3D_SERIES(par->chip)) { + par->SavageWaitIdle = savage3D_waitidle; + par->SavageWaitFifo = savage3D_waitfifo; + } else if (S3_SAVAGE4_SERIES(par->chip) || + S3_SUPERSAVAGE == par->chip) { + par->SavageWaitIdle = savage4_waitidle; + par->SavageWaitFifo = savage4_waitfifo; + } else { + par->SavageWaitIdle = savage2000_waitidle; + par->SavageWaitFifo = savage2000_waitfifo; + } + + info->var.nonstd = 0; + info->var.activate = FB_ACTIVATE_NOW; + info->var.width = -1; + info->var.height = -1; + info->var.accel_flags = 0; + + info->fbops = &savagefb_ops; + info->flags = FBINFO_DEFAULT | + FBINFO_HWACCEL_YPAN | + FBINFO_HWACCEL_XPAN; + + info->pseudo_palette = par->pseudo_palette; + +#if defined(CONFIG_FB_SAVAGE_ACCEL) + /* FIFO size + padding for commands */ + info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL); + + err = -ENOMEM; + if (info->pixmap.addr) { + memset(info->pixmap.addr, 0, 8*1024); + info->pixmap.size = 8*1024; + info->pixmap.scan_align = 4; + info->pixmap.buf_align = 4; + info->pixmap.access_align = 4; + + fb_alloc_cmap (&info->cmap, NR_PALETTE, 0); + info->flags |= FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_IMAGEBLIT; + + err = 0; + } +#endif + return err; +} + +/* --------------------------------------------------------------------- */ + +static int __devinit savagefb_probe (struct pci_dev* dev, + const struct pci_device_id* id) +{ + struct fb_info *info; + struct savagefb_par *par; + u_int h_sync, v_sync; + int err, lpitch; + int video_len; + + DBG("savagefb_probe"); + SavagePrintRegs(); + + info = framebuffer_alloc(sizeof(struct savagefb_par), &dev->dev); + if (!info) + return -ENOMEM; + par = info->par; + err = pci_enable_device(dev); + if (err) + goto failed_enable; + + if (pci_request_regions(dev, "savagefb")) { + printk(KERN_ERR "cannot request PCI regions\n"); + goto failed_enable; + } + + err = -ENOMEM; + + if (savage_init_fb_info(info, dev, id)) + goto failed_init; + + err = savage_map_mmio(info); + if (err) + goto failed_mmio; + + video_len = savage_init_hw(par); + if (video_len < 0) { + err = video_len; + goto failed_mmio; + } + + err = savage_map_video(info, video_len); + if (err) + goto failed_video; + + INIT_LIST_HEAD(&info->modelist); +#if defined(CONFIG_FB_SAVAGE_I2C) + savagefb_create_i2c_busses(info); + savagefb_probe_i2c_connector(par, &par->edid); + fb_edid_to_monspecs(par->edid, &info->monspecs); + fb_videomode_to_modelist(info->monspecs.modedb, + info->monspecs.modedb_len, + &info->modelist); +#endif + info->var = savagefb_var800x600x8; + + if (mode_option) { + fb_find_mode(&info->var, info, mode_option, + info->monspecs.modedb, info->monspecs.modedb_len, + NULL, 8); + } else if (info->monspecs.modedb != NULL) { + struct fb_monspecs *specs = &info->monspecs; + struct fb_videomode modedb; + + if (info->monspecs.misc & FB_MISC_1ST_DETAIL) { + int i; + + for (i = 0; i < specs->modedb_len; i++) { + if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { + modedb = specs->modedb[i]; + break; + } + } + } else { + /* otherwise, get first mode in database */ + modedb = specs->modedb[0]; + } + + savage_update_var(&info->var, &modedb); + } + + /* maximize virtual vertical length */ + lpitch = info->var.xres_virtual*((info->var.bits_per_pixel + 7) >> 3); + info->var.yres_virtual = info->fix.smem_len/lpitch; + + if (info->var.yres_virtual < info->var.yres) + goto failed; + +#if defined(CONFIG_FB_SAVAGE_ACCEL) + /* + * The clipping coordinates are masked with 0xFFF, so limit our + * virtual resolutions to these sizes. + */ + if (info->var.yres_virtual > 0x1000) + info->var.yres_virtual = 0x1000; + + if (info->var.xres_virtual > 0x1000) + info->var.xres_virtual = 0x1000; +#endif + savagefb_check_var(&info->var, info); + savagefb_set_fix(info); + + /* + * Calculate the hsync and vsync frequencies. Note that + * we split the 1e12 constant up so that we can preserve + * the precision and fit the results into 32-bit registers. + * (1953125000 * 512 = 1e12) + */ + h_sync = 1953125000 / info->var.pixclock; + h_sync = h_sync * 512 / (info->var.xres + info->var.left_margin + + info->var.right_margin + + info->var.hsync_len); + v_sync = h_sync / (info->var.yres + info->var.upper_margin + + info->var.lower_margin + info->var.vsync_len); + + printk(KERN_INFO "savagefb v" SAVAGEFB_VERSION ": " + "%dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", + info->fix.smem_len >> 10, + info->var.xres, info->var.yres, + h_sync / 1000, h_sync % 1000, v_sync); + + + fb_destroy_modedb(info->monspecs.modedb); + info->monspecs.modedb = NULL; + + err = register_framebuffer (info); + if (err < 0) + goto failed; + + printk (KERN_INFO "fb: S3 %s frame buffer device\n", + info->fix.id); + + /* + * Our driver data + */ + pci_set_drvdata(dev, info); + + return 0; + + failed: +#ifdef CONFIG_FB_SAVAGE_I2C + savagefb_delete_i2c_busses(info); +#endif + fb_alloc_cmap (&info->cmap, 0, 0); + savage_unmap_video(info); + failed_video: + savage_unmap_mmio (info); + failed_mmio: + kfree(info->pixmap.addr); + failed_init: + pci_release_regions(dev); + failed_enable: + framebuffer_release(info); + + return err; +} + +static void __devexit savagefb_remove (struct pci_dev *dev) +{ + struct fb_info *info = + (struct fb_info *)pci_get_drvdata(dev); + + DBG("savagefb_remove"); + + if (info) { + /* + * If unregister_framebuffer fails, then + * we will be leaving hooks that could cause + * oopsen laying around. + */ + if (unregister_framebuffer (info)) + printk (KERN_WARNING "savagefb: danger danger! " + "Oopsen imminent!\n"); + +#ifdef CONFIG_FB_SAVAGE_I2C + savagefb_delete_i2c_busses(info); +#endif + fb_alloc_cmap (&info->cmap, 0, 0); + savage_unmap_video (info); + savage_unmap_mmio (info); + kfree(info->pixmap.addr); + pci_release_regions(dev); + framebuffer_release(info); + + /* + * Ensure that the driver data is no longer + * valid. + */ + pci_set_drvdata(dev, NULL); + } +} + +static int savagefb_suspend (struct pci_dev* dev, u32 state) +{ + struct fb_info *info = + (struct fb_info *)pci_get_drvdata(dev); + struct savagefb_par *par = (struct savagefb_par *)info->par; + + DBG("savagefb_suspend"); + printk(KERN_DEBUG "state: %u\n", state); + + acquire_console_sem(); + fb_set_suspend(info, state); + savage_disable_mmio(par); + release_console_sem(); + + pci_disable_device(dev); + pci_set_power_state(dev, state); + + return 0; +} + +static int savagefb_resume (struct pci_dev* dev) +{ + struct fb_info *info = + (struct fb_info *)pci_get_drvdata(dev); + struct savagefb_par *par = (struct savagefb_par *)info->par; + + DBG("savage_resume"); + + pci_set_power_state(dev, 0); + pci_restore_state(dev); + if(pci_enable_device(dev)) + DBG("err"); + + SavagePrintRegs(); + + acquire_console_sem(); + + savage_enable_mmio(par); + savage_init_hw(par); + savagefb_set_par (info); + + fb_set_suspend (info, 0); + release_console_sem(); + + return 0; +} + + +static struct pci_device_id savagefb_devices[] __devinitdata = { + {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX128, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64C, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128SDR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128DDR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64SDR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64DDR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCSDR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCDDR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE4, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE4}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D_MV, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D_MV}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE2000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE2000}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX_MV, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX_MV}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX_MV, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX_MV}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_PM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_PM}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_KM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_KM}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_P, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_P}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_K, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_K}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDR}, + + {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDRK, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDRK}, + + {0, 0, 0, 0, 0, 0, 0} +}; + +MODULE_DEVICE_TABLE(pci, savagefb_devices); + +static struct pci_driver savagefb_driver = { + .name = "savagefb", + .id_table = savagefb_devices, + .probe = savagefb_probe, + .suspend = savagefb_suspend, + .resume = savagefb_resume, + .remove = __devexit_p(savagefb_remove) +}; + +/* **************************** exit-time only **************************** */ + +static void __exit savage_done (void) +{ + DBG("savage_done"); + pci_unregister_driver (&savagefb_driver); +} + + +/* ************************* init in-kernel code ************************** */ + +static int __init savagefb_setup(char *options) +{ +#ifndef MODULE + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + mode_option = this_opt; + } +#endif /* !MODULE */ + return 0; +} + +static int __init savagefb_init(void) +{ + char *option; + + DBG("savagefb_init"); + + if (fb_get_options("savagefb", &option)) + return -ENODEV; + + savagefb_setup(option); + return pci_register_driver (&savagefb_driver); + +} + +module_init(savagefb_init); +module_exit(savage_done); diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c new file mode 100644 index 000000000000..34f72edba820 --- /dev/null +++ b/drivers/video/sbuslib.c @@ -0,0 +1,184 @@ +/* sbuslib.c: Helper library for SBUS framebuffer drivers. + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/mm.h> + +#include <asm/oplib.h> +#include <asm/fbio.h> + +#include "sbuslib.h" + +void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp) +{ + memset(var, 0, sizeof(*var)); + + var->xres = prom_getintdefault(prom_node, "width", 1152); + var->yres = prom_getintdefault(prom_node, "height", 900); + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; + var->bits_per_pixel = bpp; +} + +EXPORT_SYMBOL(sbusfb_fill_var); + +static unsigned long sbusfb_mmapsize(long size, unsigned long fbsize) +{ + if (size == SBUS_MMAP_EMPTY) return 0; + if (size >= 0) return size; + return fbsize * (-size); +} + +int sbusfb_mmap_helper(struct sbus_mmap_map *map, + unsigned long physbase, + unsigned long fbsize, + unsigned long iospace, + struct vm_area_struct *vma) +{ + unsigned int size, page, r, map_size; + unsigned long map_offset = 0; + unsigned long off; + int i; + + size = vma->vm_end - vma->vm_start; + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + + off = vma->vm_pgoff << PAGE_SHIFT; + + /* To stop the swapper from even considering these pages */ + vma->vm_flags |= (VM_IO | VM_RESERVED); + + /* Each page, see which map applies */ + for (page = 0; page < size; ){ + map_size = 0; + for (i = 0; map[i].size; i++) + if (map[i].voff == off+page) { + map_size = sbusfb_mmapsize(map[i].size, fbsize); +#ifdef __sparc_v9__ +#define POFF_MASK (PAGE_MASK|0x1UL) +#else +#define POFF_MASK (PAGE_MASK) +#endif + map_offset = (physbase + map[i].poff) & POFF_MASK; + break; + } + if (!map_size){ + page += PAGE_SIZE; + continue; + } + if (page + map_size > size) + map_size = size - page; + r = io_remap_pfn_range(vma, + vma->vm_start + page, + MK_IOSPACE_PFN(iospace, + map_offset >> PAGE_SHIFT), + map_size, + vma->vm_page_prot); + if (r) + return -EAGAIN; + page += map_size; + } + + return 0; +} +EXPORT_SYMBOL(sbusfb_mmap_helper); + +int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, + struct fb_info *info, + int type, int fb_depth, unsigned long fb_size) +{ + switch(cmd) { + case FBIOGTYPE: { + struct fbtype __user *f = (struct fbtype __user *) arg; + + if (put_user(type, &f->fb_type) || + __put_user(info->var.yres, &f->fb_height) || + __put_user(info->var.xres, &f->fb_width) || + __put_user(fb_depth, &f->fb_depth) || + __put_user(0, &f->fb_cmsize) || + __put_user(fb_size, &f->fb_cmsize)) + return -EFAULT; + return 0; + } + case FBIOPUTCMAP_SPARC: { + struct fbcmap __user *c = (struct fbcmap __user *) arg; + struct fb_cmap cmap; + u16 red, green, blue; + u8 red8, green8, blue8; + unsigned char __user *ured; + unsigned char __user *ugreen; + unsigned char __user *ublue; + int index, count, i; + + if (get_user(index, &c->index) || + __get_user(count, &c->count) || + __get_user(ured, &c->red) || + __get_user(ugreen, &c->green) || + __get_user(ublue, &c->blue)) + return -EFAULT; + + cmap.len = 1; + cmap.red = &red; + cmap.green = &green; + cmap.blue = &blue; + cmap.transp = NULL; + for (i = 0; i < count; i++) { + int err; + + if (get_user(red8, &ured[i]) || + get_user(green8, &ugreen[i]) || + get_user(blue8, &ublue[i])) + return -EFAULT; + + red = red8 << 8; + green = green8 << 8; + blue = blue8 << 8; + + cmap.start = index + i; + err = fb_set_cmap(&cmap, info); + if (err) + return err; + } + return 0; + } + case FBIOGETCMAP_SPARC: { + struct fbcmap __user *c = (struct fbcmap __user *) arg; + unsigned char __user *ured; + unsigned char __user *ugreen; + unsigned char __user *ublue; + struct fb_cmap *cmap = &info->cmap; + int index, count, i; + u8 red, green, blue; + + if (get_user(index, &c->index) || + __get_user(count, &c->count) || + __get_user(ured, &c->red) || + __get_user(ugreen, &c->green) || + __get_user(ublue, &c->blue)) + return -EFAULT; + + if (index + count > cmap->len) + return -EINVAL; + + for (i = 0; i < count; i++) { + red = cmap->red[index + i] >> 8; + green = cmap->green[index + i] >> 8; + blue = cmap->blue[index + i] >> 8; + if (put_user(red, &ured[i]) || + put_user(green, &ugreen[i]) || + put_user(blue, &ublue[i])) + return -EFAULT; + } + return 0; + } + default: + return -EINVAL; + }; +} +EXPORT_SYMBOL(sbusfb_ioctl_helper); diff --git a/drivers/video/sbuslib.h b/drivers/video/sbuslib.h new file mode 100644 index 000000000000..a6aa33ba09d6 --- /dev/null +++ b/drivers/video/sbuslib.h @@ -0,0 +1,24 @@ +/* sbuslib.h: SBUS fb helper library interfaces */ +#ifndef _SBUSLIB_H +#define _SBUSLIB_H + +struct sbus_mmap_map { + unsigned long voff; + unsigned long poff; + unsigned long size; +}; + +#define SBUS_MMAP_FBSIZE(n) (-n) +#define SBUS_MMAP_EMPTY 0x80000000 + +extern void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp); +struct vm_area_struct; +extern int sbusfb_mmap_helper(struct sbus_mmap_map *map, + unsigned long physbase, unsigned long fbsize, + unsigned long iospace, + struct vm_area_struct *vma); +int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, + struct fb_info *info, + int type, int fb_depth, unsigned long fb_size); + +#endif /* _SBUSLIB_H */ diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c new file mode 100644 index 000000000000..8413907b379a --- /dev/null +++ b/drivers/video/sgivwfb.c @@ -0,0 +1,901 @@ +/* + * linux/drivers/video/sgivwfb.c -- SGI DBE frame buffer device + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Jeffrey Newquist, newquist@engr.sgi.som + * + * 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/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/mtrr.h> + +#define INCLUDE_TIMING_TABLE_DATA +#define DBE_REG_BASE par->regs +#include <video/sgivw.h> + +struct sgivw_par { + struct asregs *regs; + u32 cmap_fifo; + u_long timing_num; +}; + +#define FLATPANEL_SGI_1600SW 5 + +/* + * RAM we reserve for the frame buffer. This defines the maximum screen + * size + * + * The default can be overridden if the driver is compiled as a module + */ + +/* set by arch/i386/kernel/setup.c */ +extern unsigned long sgivwfb_mem_phys; +extern unsigned long sgivwfb_mem_size; + +static int ypan = 0; +static int ywrap = 0; + +static int flatpanel_id = -1; + +static struct fb_fix_screeninfo sgivwfb_fix __initdata = { + .id = "SGI Vis WS FB", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .mmio_start = DBE_REG_PHYS, + .mmio_len = DBE_REG_SIZE, + .accel = FB_ACCEL_NONE, + .line_length = 640, +}; + +static struct fb_var_screeninfo sgivwfb_var __initdata = { + /* 640x480, 8 bpp */ + .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, + .pixclock = 20000, + .left_margin = 64, + .right_margin = 64, + .upper_margin = 32, + .lower_margin = 32, + .hsync_len = 64, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED +}; + +static struct fb_var_screeninfo sgivwfb_var1600sw __initdata = { + /* 1600x1024, 8 bpp */ + .xres = 1600, + .yres = 1024, + .xres_virtual = 1600, + .yres_virtual = 1024, + .bits_per_pixel = 8, + .red = { 0, 8, 0 }, + .green = { 0, 8, 0 }, + .blue = { 0, 8, 0 }, + .height = -1, + .width = -1, + .pixclock = 9353, + .left_margin = 20, + .right_margin = 30, + .upper_margin = 37, + .lower_margin = 3, + .hsync_len = 20, + .vsync_len = 3, + .vmode = FB_VMODE_NONINTERLACED +}; + +/* + * Interface used by the world + */ +int sgivwfb_init(void); + +static int sgivwfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); +static int sgivwfb_set_par(struct fb_info *info); +static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info); +static int sgivwfb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma); + +static struct fb_ops sgivwfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = sgivwfb_check_var, + .fb_set_par = sgivwfb_set_par, + .fb_setcolreg = sgivwfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + .fb_mmap = sgivwfb_mmap, +}; + +/* + * Internal routines + */ +static unsigned long bytes_per_pixel(int bpp) +{ + switch (bpp) { + case 8: + return 1; + case 16: + return 2; + case 32: + return 4; + default: + printk(KERN_INFO "sgivwfb: unsupported bpp %d\n", bpp); + return 0; + } +} + +static unsigned long get_line_length(int xres_virtual, int bpp) +{ + return (xres_virtual * bytes_per_pixel(bpp)); +} + +/* + * Function: dbe_TurnOffDma + * Parameters: (None) + * Description: This should turn off the monitor and dbe. This is used + * when switching between the serial console and the graphics + * console. + */ + +static void dbe_TurnOffDma(struct sgivw_par *par) +{ + unsigned int readVal; + int i; + + // Check to see if things are already turned off: + // 1) Check to see if dbe is not using the internal dotclock. + // 2) Check to see if the xy counter in dbe is already off. + + DBE_GETREG(ctrlstat, readVal); + if (GET_DBE_FIELD(CTRLSTAT, PCLKSEL, readVal) < 2) + return; + + DBE_GETREG(vt_xy, readVal); + if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) + return; + + // Otherwise, turn off dbe + + DBE_GETREG(ovr_control, readVal); + SET_DBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, readVal, 0); + DBE_SETREG(ovr_control, readVal); + udelay(1000); + DBE_GETREG(frm_control, readVal); + SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, readVal, 0); + DBE_SETREG(frm_control, readVal); + udelay(1000); + DBE_GETREG(did_control, readVal); + SET_DBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, readVal, 0); + DBE_SETREG(did_control, readVal); + udelay(1000); + + // XXX HACK: + // + // This was necessary for GBE--we had to wait through two + // vertical retrace periods before the pixel DMA was + // turned off for sure. I've left this in for now, in + // case dbe needs it. + + for (i = 0; i < 10000; i++) { + DBE_GETREG(frm_inhwctrl, readVal); + if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) == + 0) + udelay(10); + else { + DBE_GETREG(ovr_inhwctrl, readVal); + if (GET_DBE_FIELD + (OVR_INHWCTRL, OVR_DMA_ENABLE, readVal) == 0) + udelay(10); + else { + DBE_GETREG(did_inhwctrl, readVal); + if (GET_DBE_FIELD + (DID_INHWCTRL, DID_DMA_ENABLE, + readVal) == 0) + udelay(10); + else + break; + } + } + } +} + +/* + * Set the User Defined Part of the Display. Again if par use it to get + * real video mode. + */ +static int sgivwfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct sgivw_par *par = (struct sgivw_par *)info->par; + struct dbe_timing_info *timing; + u_long line_length; + u_long min_mode; + int req_dot; + int test_mode; + + /* + * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! + * as FB_VMODE_SMOOTH_XPAN is only used internally + */ + + if (var->vmode & FB_VMODE_CONUPDATE) { + var->vmode |= FB_VMODE_YWRAP; + var->xoffset = info->var.xoffset; + var->yoffset = info->var.yoffset; + } + + /* XXX FIXME - forcing var's */ + var->xoffset = 0; + var->yoffset = 0; + + /* Limit bpp to 8, 16, and 32 */ + if (var->bits_per_pixel <= 8) + var->bits_per_pixel = 8; + else if (var->bits_per_pixel <= 16) + var->bits_per_pixel = 16; + else if (var->bits_per_pixel <= 32) + var->bits_per_pixel = 32; + else + return -EINVAL; + + var->grayscale = 0; /* No grayscale for now */ + + /* determine valid resolution and timing */ + for (min_mode = 0; min_mode < DBE_VT_SIZE; min_mode++) { + if (dbeVTimings[min_mode].width >= var->xres && + dbeVTimings[min_mode].height >= var->yres) + break; + } + + if (min_mode == DBE_VT_SIZE) + return -EINVAL; /* Resolution to high */ + + /* XXX FIXME - should try to pick best refresh rate */ + /* for now, pick closest dot-clock within 3MHz */ + req_dot = PICOS2KHZ(var->pixclock); + printk(KERN_INFO "sgivwfb: requested pixclock=%d ps (%d KHz)\n", + var->pixclock, req_dot); + test_mode = min_mode; + while (dbeVTimings[min_mode].width == dbeVTimings[test_mode].width) { + if (dbeVTimings[test_mode].cfreq + 3000 > req_dot) + break; + test_mode++; + } + if (dbeVTimings[min_mode].width != dbeVTimings[test_mode].width) + test_mode--; + min_mode = test_mode; + timing = &dbeVTimings[min_mode]; + printk(KERN_INFO "sgivwfb: granted dot-clock=%d KHz\n", timing->cfreq); + + /* Adjust virtual resolution, if necessary */ + if (var->xres > var->xres_virtual || (!ywrap && !ypan)) + var->xres_virtual = var->xres; + if (var->yres > var->yres_virtual || (!ywrap && !ypan)) + var->yres_virtual = var->yres; + + /* + * Memory limit + */ + line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); + if (line_length * var->yres_virtual > sgivwfb_mem_size) + return -ENOMEM; /* Virtual resolution to high */ + + info->fix.line_length = line_length; + + 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: /* RGBA 5551 */ + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 6; + var->green.length = 5; + var->blue.offset = 1; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 32: /* RGB 8888 */ + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + 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; + + /* set video timing information */ + var->pixclock = KHZ2PICOS(timing->cfreq); + var->left_margin = timing->htotal - timing->hsync_end; + var->right_margin = timing->hsync_start - timing->width; + var->upper_margin = timing->vtotal - timing->vsync_end; + var->lower_margin = timing->vsync_start - timing->height; + var->hsync_len = timing->hsync_end - timing->hsync_start; + var->vsync_len = timing->vsync_end - timing->vsync_start; + + /* Ouch. This breaks the rules but timing_num is only important if you + * change a video mode */ + par->timing_num = min_mode; + + printk(KERN_INFO "sgivwfb: new video mode xres=%d yres=%d bpp=%d\n", + var->xres, var->yres, var->bits_per_pixel); + printk(KERN_INFO " vxres=%d vyres=%d\n", var->xres_virtual, + var->yres_virtual); + return 0; +} + +/* + * Setup flatpanel related registers. + */ +static void sgivwfb_setup_flatpanel(struct sgivw_par *par, struct dbe_timing_info *currentTiming) +{ + int fp_wid, fp_hgt, fp_vbs, fp_vbe; + u32 outputVal = 0; + + SET_DBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal, + (currentTiming->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1); + SET_DBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal, + (currentTiming->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1); + DBE_SETREG(vt_flags, outputVal); + + /* Turn on the flat panel */ + switch (flatpanel_id) { + case FLATPANEL_SGI_1600SW: + fp_wid = 1600; + fp_hgt = 1024; + fp_vbs = 0; + fp_vbe = 1600; + currentTiming->pll_m = 4; + currentTiming->pll_n = 1; + currentTiming->pll_p = 0; + break; + default: + fp_wid = fp_hgt = fp_vbs = fp_vbe = 0xfff; + } + + outputVal = 0; + SET_DBE_FIELD(FP_DE, FP_DE_ON, outputVal, fp_vbs); + SET_DBE_FIELD(FP_DE, FP_DE_OFF, outputVal, fp_vbe); + DBE_SETREG(fp_de, outputVal); + outputVal = 0; + SET_DBE_FIELD(FP_HDRV, FP_HDRV_OFF, outputVal, fp_wid); + DBE_SETREG(fp_hdrv, outputVal); + outputVal = 0; + SET_DBE_FIELD(FP_VDRV, FP_VDRV_ON, outputVal, 1); + SET_DBE_FIELD(FP_VDRV, FP_VDRV_OFF, outputVal, fp_hgt + 1); + DBE_SETREG(fp_vdrv, outputVal); +} + +/* + * Set the hardware according to 'par'. + */ +static int sgivwfb_set_par(struct fb_info *info) +{ + struct sgivw_par *par = info->par; + int i, j, htmp, temp; + u32 readVal, outputVal; + int wholeTilesX, maxPixelsPerTileX; + int frmWrite1, frmWrite2, frmWrite3b; + struct dbe_timing_info *currentTiming; /* Current Video Timing */ + int xpmax, ypmax; // Monitor resolution + int bytesPerPixel; // Bytes per pixel + + currentTiming = &dbeVTimings[par->timing_num]; + bytesPerPixel = bytes_per_pixel(info->var.bits_per_pixel); + xpmax = currentTiming->width; + ypmax = currentTiming->height; + + /* dbe_InitGraphicsBase(); */ + /* Turn on dotclock PLL */ + DBE_SETREG(ctrlstat, 0x20000000); + + dbe_TurnOffDma(par); + + /* dbe_CalculateScreenParams(); */ + maxPixelsPerTileX = 512 / bytesPerPixel; + wholeTilesX = xpmax / maxPixelsPerTileX; + if (wholeTilesX * maxPixelsPerTileX < xpmax) + wholeTilesX++; + + printk(KERN_DEBUG "sgivwfb: pixPerTile=%d wholeTilesX=%d\n", + maxPixelsPerTileX, wholeTilesX); + + /* dbe_InitGammaMap(); */ + udelay(10); + + for (i = 0; i < 256; i++) { + DBE_ISETREG(gmap, i, (i << 24) | (i << 16) | (i << 8)); + } + + /* dbe_TurnOn(); */ + DBE_GETREG(vt_xy, readVal); + if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) { + DBE_SETREG(vt_xy, 0x00000000); + udelay(1); + } else + dbe_TurnOffDma(par); + + /* dbe_Initdbe(); */ + for (i = 0; i < 256; i++) { + for (j = 0; j < 100; j++) { + DBE_GETREG(cm_fifo, readVal); + if (readVal != 0x00000000) + break; + else + udelay(10); + } + + // DBE_ISETREG(cmap, i, 0x00000000); + DBE_ISETREG(cmap, i, (i << 8) | (i << 16) | (i << 24)); + } + + /* dbe_InitFramebuffer(); */ + frmWrite1 = 0; + SET_DBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, frmWrite1, + wholeTilesX); + SET_DBE_FIELD(FRM_SIZE_TILE, FRM_RHS, frmWrite1, 0); + + switch (bytesPerPixel) { + case 1: + SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, + DBE_FRM_DEPTH_8); + break; + case 2: + SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, + DBE_FRM_DEPTH_16); + break; + case 4: + SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, + DBE_FRM_DEPTH_32); + break; + } + + frmWrite2 = 0; + SET_DBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, ypmax); + + // Tell dbe about the framebuffer location and type + // XXX What format is the FRM_TILE_PTR?? 64K aligned address? + frmWrite3b = 0; + SET_DBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, frmWrite3b, + sgivwfb_mem_phys >> 9); + SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, frmWrite3b, 1); + SET_DBE_FIELD(FRM_CONTROL, FRM_LINEAR, frmWrite3b, 1); + + /* Initialize DIDs */ + + outputVal = 0; + switch (bytesPerPixel) { + case 1: + SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_I8); + break; + case 2: + SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGBA5); + break; + case 4: + SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGB8); + break; + } + SET_DBE_FIELD(WID, BUF, outputVal, DBE_BMODE_BOTH); + + for (i = 0; i < 32; i++) { + DBE_ISETREG(mode_regs, i, outputVal); + } + + /* dbe_InitTiming(); */ + DBE_SETREG(vt_intr01, 0xffffffff); + DBE_SETREG(vt_intr23, 0xffffffff); + + DBE_GETREG(dotclock, readVal); + DBE_SETREG(dotclock, readVal & 0xffff); + + DBE_SETREG(vt_xymax, 0x00000000); + outputVal = 0; + SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_ON, outputVal, + currentTiming->vsync_start); + SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_OFF, outputVal, + currentTiming->vsync_end); + DBE_SETREG(vt_vsync, outputVal); + outputVal = 0; + SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_ON, outputVal, + currentTiming->hsync_start); + SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_OFF, outputVal, + currentTiming->hsync_end); + DBE_SETREG(vt_hsync, outputVal); + outputVal = 0; + SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_ON, outputVal, + currentTiming->vblank_start); + SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_OFF, outputVal, + currentTiming->vblank_end); + DBE_SETREG(vt_vblank, outputVal); + outputVal = 0; + SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_ON, outputVal, + currentTiming->hblank_start); + SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_OFF, outputVal, + currentTiming->hblank_end - 3); + DBE_SETREG(vt_hblank, outputVal); + outputVal = 0; + SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_ON, outputVal, + currentTiming->vblank_start); + SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_OFF, outputVal, + currentTiming->vblank_end); + DBE_SETREG(vt_vcmap, outputVal); + outputVal = 0; + SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_ON, outputVal, + currentTiming->hblank_start); + SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_OFF, outputVal, + currentTiming->hblank_end - 3); + DBE_SETREG(vt_hcmap, outputVal); + + if (flatpanel_id != -1) + sgivwfb_setup_flatpanel(par, currentTiming); + + outputVal = 0; + temp = currentTiming->vblank_start - currentTiming->vblank_end - 1; + if (temp > 0) + temp = -temp; + + SET_DBE_FIELD(DID_START_XY, DID_STARTY, outputVal, (u32) temp); + if (currentTiming->hblank_end >= 20) + SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal, + currentTiming->hblank_end - 20); + else + SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal, + currentTiming->htotal - (20 - + currentTiming-> + hblank_end)); + DBE_SETREG(did_start_xy, outputVal); + + outputVal = 0; + SET_DBE_FIELD(CRS_START_XY, CRS_STARTY, outputVal, + (u32) (temp + 1)); + if (currentTiming->hblank_end >= DBE_CRS_MAGIC) + SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal, + currentTiming->hblank_end - DBE_CRS_MAGIC); + else + SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal, + currentTiming->htotal - (DBE_CRS_MAGIC - + currentTiming-> + hblank_end)); + DBE_SETREG(crs_start_xy, outputVal); + + outputVal = 0; + SET_DBE_FIELD(VC_START_XY, VC_STARTY, outputVal, (u32) temp); + SET_DBE_FIELD(VC_START_XY, VC_STARTX, outputVal, + currentTiming->hblank_end - 4); + DBE_SETREG(vc_start_xy, outputVal); + + DBE_SETREG(frm_size_tile, frmWrite1); + DBE_SETREG(frm_size_pixel, frmWrite2); + + outputVal = 0; + SET_DBE_FIELD(DOTCLK, M, outputVal, currentTiming->pll_m - 1); + SET_DBE_FIELD(DOTCLK, N, outputVal, currentTiming->pll_n - 1); + SET_DBE_FIELD(DOTCLK, P, outputVal, currentTiming->pll_p); + SET_DBE_FIELD(DOTCLK, RUN, outputVal, 1); + DBE_SETREG(dotclock, outputVal); + + udelay(11 * 1000); + + DBE_SETREG(vt_vpixen, 0xffffff); + DBE_SETREG(vt_hpixen, 0xffffff); + + outputVal = 0; + SET_DBE_FIELD(VT_XYMAX, VT_MAXX, outputVal, currentTiming->htotal); + SET_DBE_FIELD(VT_XYMAX, VT_MAXY, outputVal, currentTiming->vtotal); + DBE_SETREG(vt_xymax, outputVal); + + outputVal = frmWrite1; + SET_DBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, outputVal, 1); + DBE_SETREG(frm_size_tile, outputVal); + DBE_SETREG(frm_size_tile, frmWrite1); + + outputVal = 0; + SET_DBE_FIELD(OVR_WIDTH_TILE, OVR_FIFO_RESET, outputVal, 1); + DBE_SETREG(ovr_width_tile, outputVal); + DBE_SETREG(ovr_width_tile, 0); + + DBE_SETREG(frm_control, frmWrite3b); + DBE_SETREG(did_control, 0); + + // Wait for dbe to take frame settings + for (i = 0; i < 100000; i++) { + DBE_GETREG(frm_inhwctrl, readVal); + if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) != + 0) + break; + else + udelay(1); + } + + if (i == 100000) + printk(KERN_INFO + "sgivwfb: timeout waiting for frame DMA enable.\n"); + + outputVal = 0; + htmp = currentTiming->hblank_end - 19; + if (htmp < 0) + htmp += currentTiming->htotal; /* allow blank to wrap around */ + SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_ON, outputVal, htmp); + SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_OFF, outputVal, + ((htmp + currentTiming->width - + 2) % currentTiming->htotal)); + DBE_SETREG(vt_hpixen, outputVal); + + outputVal = 0; + SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_OFF, outputVal, + currentTiming->vblank_start); + SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_ON, outputVal, + currentTiming->vblank_end); + DBE_SETREG(vt_vpixen, outputVal); + + // Turn off mouse cursor + par->regs->crs_ctl = 0; + + // XXX What's this section for?? + DBE_GETREG(ctrlstat, readVal); + readVal &= 0x02000000; + + if (readVal != 0) { + DBE_SETREG(ctrlstat, 0x30000000); + } + return 0; +} + +/* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info) +{ + struct sgivw_par *par = (struct sgivw_par *) info->par; + + if (regno > 255) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + + /* wait for the color map FIFO to have a free entry */ + while (par->cmap_fifo == 0) + par->cmap_fifo = par->regs->cm_fifo; + + par->regs->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); + par->cmap_fifo--; /* assume FIFO is filling up */ + return 0; +} + +static int sgivwfb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + if (offset + size > sgivwfb_mem_size) + return -EINVAL; + offset += sgivwfb_mem_phys; + pgprot_val(vma->vm_page_prot) = + pgprot_val(vma->vm_page_prot) | _PAGE_PCD; + vma->vm_flags |= VM_IO; + if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, + size, vma->vm_page_prot)) + return -EAGAIN; + vma->vm_file = file; + printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n", + offset, vma->vm_start); + return 0; +} + +int __init sgivwfb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "monitor:", 8)) { + if (!strncmp(this_opt + 8, "crt", 3)) + flatpanel_id = -1; + else if (!strncmp(this_opt + 8, "1600sw", 6)) + flatpanel_id = FLATPANEL_SGI_1600SW; + } + } + return 0; +} + +/* + * Initialisation + */ +static void sgivwfb_release(struct device *device) +{ +} + +static int __init sgivwfb_probe(struct device *device) +{ + struct platform_device *dev = to_platform_device(device); + struct sgivw_par *par; + struct fb_info *info; + char *monitor; + + info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 256, &dev->dev); + if (!info) + return -ENOMEM; + par = info->par; + + if (!request_mem_region(DBE_REG_PHYS, DBE_REG_SIZE, "sgivwfb")) { + printk(KERN_ERR "sgivwfb: couldn't reserve mmio region\n"); + framebuffer_release(info); + return -EBUSY; + } + + par->regs = (struct asregs *) ioremap_nocache(DBE_REG_PHYS, DBE_REG_SIZE); + if (!par->regs) { + printk(KERN_ERR "sgivwfb: couldn't ioremap registers\n"); + goto fail_ioremap_regs; + } + + mtrr_add(sgivwfb_mem_phys, sgivwfb_mem_size, MTRR_TYPE_WRCOMB, 1); + + sgivwfb_fix.smem_start = sgivwfb_mem_phys; + sgivwfb_fix.smem_len = sgivwfb_mem_size; + sgivwfb_fix.ywrapstep = ywrap; + sgivwfb_fix.ypanstep = ypan; + + info->fix = sgivwfb_fix; + + switch (flatpanel_id) { + case FLATPANEL_SGI_1600SW: + info->var = sgivwfb_var1600sw; + monitor = "SGI 1600SW flatpanel"; + break; + default: + info->var = sgivwfb_var; + monitor = "CRT"; + } + + printk(KERN_INFO "sgivwfb: %s monitor selected\n", monitor); + + info->fbops = &sgivwfb_ops; + info->pseudo_palette = (void *) (par + 1); + info->flags = FBINFO_DEFAULT; + + info->screen_base = ioremap_nocache((unsigned long) sgivwfb_mem_phys, sgivwfb_mem_size); + if (!info->screen_base) { + printk(KERN_ERR "sgivwfb: couldn't ioremap screen_base\n"); + goto fail_ioremap_fbmem; + } + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + goto fail_color_map; + + if (register_framebuffer(info) < 0) { + printk(KERN_ERR "sgivwfb: couldn't register framebuffer\n"); + goto fail_register_framebuffer; + } + + dev_set_drvdata(&dev->dev, info); + + printk(KERN_INFO "fb%d: SGI DBE frame buffer device, using %ldK of video memory at %#lx\n", + info->node, sgivwfb_mem_size >> 10, sgivwfb_mem_phys); + return 0; + +fail_register_framebuffer: + fb_dealloc_cmap(&info->cmap); +fail_color_map: + iounmap((char *) info->screen_base); +fail_ioremap_fbmem: + iounmap(par->regs); +fail_ioremap_regs: + release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE); + framebuffer_release(info); + return -ENXIO; +} + +static int sgivwfb_remove(struct device *device) +{ + struct fb_info *info = dev_get_drvdata(device); + + if (info) { + struct sgivw_par *par = info->par; + + unregister_framebuffer(info); + dbe_TurnOffDma(par); + iounmap(par->regs); + iounmap(info->screen_base); + release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE); + } + return 0; +} + +static struct device_driver sgivwfb_driver = { + .name = "sgivwfb", + .bus = &platform_bus_type, + .probe = sgivwfb_probe, + .remove = sgivwfb_remove, +}; + +static struct platform_device sgivwfb_device = { + .name = "sgivwfb", + .id = 0, + .dev = { + .release = sgivwfb_release, + } +}; + +int __init sgivwfb_init(void) +{ + int ret; + +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("sgivwfb", &option)) + return -ENODEV; + sgivwfb_setup(option); +#endif + ret = driver_register(&sgivwfb_driver); + if (!ret) { + ret = platform_device_register(&sgivwfb_device); + if (ret) + driver_unregister(&sgivwfb_driver); + } + return ret; +} + +module_init(sgivwfb_init); + +#ifdef MODULE +MODULE_LICENSE("GPL"); + +static void __exit sgivwfb_exit(void) +{ + platform_device_unregister(&sgivwfb_device); + driver_unregister(&sgivwfb_driver); +} + +module_exit(sgivwfb_exit); + +#endif /* MODULE */ diff --git a/drivers/video/sis/300vtbl.h b/drivers/video/sis/300vtbl.h new file mode 100644 index 000000000000..b6d5c71b2563 --- /dev/null +++ b/drivers/video/sis/300vtbl.h @@ -0,0 +1,1965 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Register settings for SiS 300 series + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +static const SiS_StStruct SiS300_SModeIDTable[] = +{ + {0x01,0x9208,0x01,0x00,0x00,0x00,0x00,0x00, 0}, + {0x01,0x1210,0x14,0x01,0x01,0x00,0x00,0x00, 0}, + {0x01,0x1010,0x17,0x02,0x02,0x00,0x00,0x00, 0}, + {0x03,0x8208,0x03,0x00,0x00,0x00,0x00,0x00, 0}, + {0x03,0x0210,0x16,0x01,0x01,0x00,0x00,0x00, 0}, + {0x03,0x0010,0x18,0x02,0x02,0x00,0x00,0x00, 0}, + {0x05,0x9209,0x05,0x00,0x00,0x00,0x00,0x00, 0}, + {0x06,0x8209,0x06,0x00,0x00,0x00,0x00,0x00, 0}, + {0x07,0x0000,0x07,0x03,0x03,0x00,0x00,0x00, 0}, + {0x07,0x0000,0x19,0x02,0x02,0x00,0x00,0x00, 0}, + {0x0d,0x920a,0x0d,0x00,0x00,0x00,0x00,0x00, 0}, + {0x0e,0x820a,0x0e,0x00,0x00,0x00,0x00,0x00, 0}, + {0x0f,0x0202,0x11,0x01,0x01,0x00,0x00,0x00, 0}, + {0x10,0x0212,0x12,0x01,0x01,0x00,0x00,0x00, 0}, + {0x11,0x0212,0x1a,0x04,0x04,0x00,0x00,0x00, 0}, + {0x12,0x0212,0x1b,0x04,0x04,0x00,0x00,0x00, 0}, + {0x13,0x021b,0x1c,0x00,0x00,0x00,0x00,0x00, 0}, + {0x12,0x0010,0x18,0x02,0x02,0x00,0x00,0x00, 0}, + {0x12,0x0210,0x18,0x01,0x01,0x00,0x00,0x00, 0}, + {0xff, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +static const SiS_ExtStruct SiS300_EModeIDTable[] = +{ + {0x6a,0x2212,0x0102,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00,-1}, /* 800x600x? */ + {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08,-1}, + {0x2f,0x021b,0x0100,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10,-1}, /* 640x400x8 */ + {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00,-1}, + {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x00,0x00,0x11,-1}, /* 720x480x8 */ + {0x32,0x6a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x00,0x00,0x12,-1}, /* 720x576x8 */ + {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x00,0x00,0x11,-1}, /* 720x480x16 */ + {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x00,0x00,0x12,-1}, /* 720x576x16 */ + {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x00,0x00,0x11,-1}, /* 720x480x32 */ + {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x00,0x00,0x12,-1}, /* 720x576x32 */ + {0x37,0x0212,0x0104,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1}, /* 1024x768x? */ + {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1}, /* 1024x768x8 */ + {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1}, /* 1280x1024x8 */ + {0x3c,0x063b,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,-1}, + {0x3d,0x067d,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,-1}, + {0x40,0x921c,0x010d,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23,-1}, /* 320x200x15 */ + {0x41,0x921d,0x010e,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23,-1}, /* 320x200x16 */ + {0x43,0x0a1c,0x0110,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08,-1}, + {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08,-1}, + {0x46,0x2a1c,0x0113,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00,-1}, /* 800x600x15 */ + {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00,-1}, /* 800x600x16 */ + {0x49,0x0a3c,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1}, + {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1}, + {0x4c,0x0e7c,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1}, + {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1}, + {0x50,0x921b,0x0132,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x24,-1}, /* 320x240x8 */ + {0x51,0xb21b,0x0133,SIS_RI_400x300, 0x00,0x00,0x00,0x00,0x25,-1}, /* 400x300x8 */ + {0x52,0x921b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26,-1}, /* 512x384x8 */ + {0x56,0x921d,0x0135,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x24,-1}, /* 320x240x16 */ + {0x57,0xb21d,0x0136,SIS_RI_400x300, 0x00,0x00,0x00,0x00,0x25,-1}, /* 400x300x16 */ + {0x58,0x921d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26,-1}, /* 512x384x16 */ + {0x59,0x921b,0x0138,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23,-1}, /* 320x200x8 */ + {0x5c,0x921f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26,-1}, /* 512x384x32 */ + {0x5d,0x021d,0x0139,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10,-1}, /* 640x400x16 */ + {0x5e,0x021f,0x0000,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10,-1}, /* 640x400x32 */ + {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08,-1}, + {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00,-1}, /* 800x600x32 */ + {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1}, + {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1}, + {0x66,0x06ff,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,-1}, + {0x68,0x067b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1}, + {0x69,0x06fd,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1}, + {0x6b,0x07ff,0x0000,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1}, + {0x6c,0x067b,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28,-1}, /* 2048x1536x8 - not in BIOS! */ + {0x6d,0x06fd,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28,-1}, /* 2048x1536x16 - not in BIOS! */ + {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d,-1}, /* 800x480x8 */ + {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1}, /* 1024x576x8 */ + {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1}, /* 1024x576x16 */ + {0x75,0x0e3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1280x720x16 */ + {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d,-1}, /* 800x480x32 */ + {0x77,0x4a3f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1}, /* 1024x576x32 */ + {0x78,0x0eff,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1280x720x32 */ + {0x79,0x0e3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1280x720x8 */ + {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d,-1}, /* 800x480x16 */ + {0x7c,0x0a3b,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29,-1}, /* 1280x960x8 */ + {0x7d,0x0a7d,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29,-1}, /* 1280x960x16 */ + {0x7e,0x0aff,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29,-1}, /* 1280x960x32 */ + {0x20,0x4a1b,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b,-1}, /* 1024x600 */ + {0x21,0x4a3d,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b,-1}, + {0x22,0x4a7f,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b,-1}, + {0x23,0x4a1b,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c,-1}, /* 1152x768 */ + {0x24,0x4a3d,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c,-1}, + {0x25,0x4a7f,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c,-1}, + {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36,-1}, /* 1152x864 */ + {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36,-1}, + {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36,-1}, + {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x39,-1}, /* 848x480 */ + {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x39,-1}, + {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x39,-1}, + {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x3b,-1}, /* 856x480 */ + {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x3b,-1}, + {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x3b,-1}, + {0x48,0x6a3b,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1360x768 */ + {0x4b,0x6a7d,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3d,-1}, + {0x4e,0x6aff,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3d,-1}, + {0x4f,0x921f,0x0000,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23,-1}, /* 320x200x32 */ + {0x53,0x921f,0x0000,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x24,-1}, /* 320x240x32 */ + {0x54,0xb21f,0x0000,SIS_RI_400x300, 0x00,0x00,0x00,0x00,0x25,-1}, /* 400x300x32 */ + {0x55,0x2e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3e,-1}, /* 1280x768 */ + {0x5a,0x2e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3e,-1}, + {0x5b,0x2eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3e,-1}, + {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x00,0x00,0x3f,-1}, /* 768x576x8 */ + {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x00,0x00,0x3f,-1}, /* 768x576x16 */ + {0x61,0x6a1f,0x0000,SIS_RI_768x576, 0x00,0x00,0x00,0x00,0x3f,-1}, /* 768x576x32 */ + {0x67,0x6e3b,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x40,-1}, /* 1360x1024x8 (BARCO) */ + {0x6f,0x6e7d,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x40,-1}, /* 1360x1024x16 (BARCO) */ + {0x72,0x6eff,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x40,-1}, /* 1360x1024x32 (BARCO) */ + {0xff,0x0000,0xffff,0, 0x00,0x00,0x00,0x00,0x00} +}; + +static const SiS_Ext2Struct SiS300_RefIndex[] = +{ + {0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0}, /* 00 */ + {0x0467,0x0e,0x44,0x05,0x05,0x6a, 800, 600, 0}, /* 01 */ + {0x0067,0x0f,0x07,0x48,0x05,0x6a, 800, 600, 0}, /* 02 - CRT1CRTC was 0x4f */ + {0x0067,0x10,0x06,0x8b,0x05,0x6a, 800, 600, 0}, /* 03 */ + {0x0147,0x11,0x08,0x00,0x05,0x6a, 800, 600, 0}, /* 04 */ + {0x0147,0x12,0x0c,0x00,0x05,0x6a, 800, 600, 0}, /* 05 */ + {0x0047,0x11,0x4e,0x00,0x05,0x6a, 800, 600, 0}, /* 06 - CRT1CRTC was 0x51 */ + {0x0047,0x11,0x13,0x00,0x05,0x6a, 800, 600, 0}, /* 07 */ + {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0}, /* 08 */ + {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0}, /* 09 */ + {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0}, /* 0a */ + {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0}, /* 0b */ + {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0}, /* 0c */ + {0xc047,0x0a,0x08,0x00,0x04,0x2e, 640, 480, 0}, /* 0d */ + {0xc047,0x0b,0x0a,0x00,0x04,0x2e, 640, 480, 0}, /* 0e */ + {0xc047,0x0c,0x10,0x00,0x04,0x2e, 640, 480, 0}, /* 0f */ + {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0}, /* 10 */ + {0xc06f,0x31,0x01,0x06,0x13,0x31, 720, 480, 0}, /* 11 */ + {0x006f,0x32,0x03,0x06,0x14,0x32, 720, 576, 0}, /* 12 */ + {0x0187,0x15,0x05,0x00,0x06,0x37,1024, 768, 0}, /* 13 */ + {0xc877,0x16,0x09,0x06,0x06,0x37,1024, 768, 0}, /* 14 */ + {0xc067,0x17,0x0b,0x49,0x06,0x37,1024, 768, 0}, /* 15 - CRT1CRTC was 0x97 */ + {0x0267,0x18,0x0d,0x00,0x06,0x37,1024, 768, 0}, /* 16 */ + {0x0047,0x19,0x11,0x8c,0x06,0x37,1024, 768, 0}, /* 17 - CRT1CRTC was 0x59 */ + {0x0047,0x1a,0x52,0x00,0x06,0x37,1024, 768, 0}, /* 18 */ + {0x0007,0x1b,0x16,0x00,0x06,0x37,1024, 768, 0}, /* 19 - CRT1CRTC was 0x5b */ + {0x0387,0x1c,0x4d,0x00,0x07,0x3a,1280,1024, 0}, /* 1a - CRT1CRTC was 0x5c */ + {0x0077,0x1d,0x14,0x07,0x07,0x3a,1280,1024, 0}, /* 1b */ + {0x0047,0x1e,0x17,0x00,0x07,0x3a,1280,1024, 0}, /* 1c */ + {0x0007,0x1f,0x98,0x00,0x07,0x3a,1280,1024, 0}, /* 1d */ + {0x0007,0x20,0x59,0x00,0x00,0x3c,1600,1200, 0}, /* 1e - CRT1CRTC was 0x60 */ + {0x0007,0x21,0x5a,0x00,0x00,0x3c,1600,1200, 0}, /* 1f */ + {0x0007,0x22,0x1b,0x00,0x00,0x3c,1600,1200, 0}, /* 20 */ + {0x0007,0x23,0x1d,0x00,0x00,0x3c,1600,1200, 0}, /* 21 - CRT1CRTC was 0x63 */ + {0x0007,0x24,0x1e,0x00,0x00,0x3c,1600,1200, 0}, /* 22 */ + {0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0}, /* 23 */ + {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0}, /* 24 */ + {0x0077,0x02,0x04,0x05,0x05,0x51, 400, 300, 0}, /* 25 */ + {0xc877,0x03,0x09,0x06,0x06,0x52, 512, 384, 0}, /* 26 */ /* was c077 */ + {0x8207,0x25,0x1f,0x00,0x00,0x68,1920,1440, 0}, /* 27 */ + {0x0007,0x26,0x20,0x00,0x00,0x6c,2048,1536, 0}, /* 28 */ + {0x0067,0x27,0x14,0x08,0x0a,0x6e,1280, 960, 0}, /* 29 - 1280x960-60 */ + {0x0027,0x45,0x3c,0x08,0x0a,0x6e,1280, 960, 0}, /* 2a - 1280x960-85 */ + {0xc077,0x33,0x09,0x06,0x00,0x20,1024, 600, 0}, /* 2b */ + {0xc077,0x34,0x0b,0x06,0x00,0x23,1152, 768, 0}, /* 2c */ /* VCLK 0x09 */ + {0x0077,0x35,0x27,0x08,0x18,0x70, 800, 480, 0}, /* 2d */ + {0x0047,0x36,0x37,0x08,0x18,0x70, 800, 480, 0}, /* 2e */ + {0x0047,0x37,0x08,0x08,0x18,0x70, 800, 480, 0}, /* 2f */ + {0x0077,0x38,0x09,0x09,0x19,0x71,1024, 576, 0}, /* 30 */ + {0x0047,0x39,0x38,0x09,0x19,0x71,1024, 576, 0}, /* 31 */ + {0x0047,0x3a,0x11,0x09,0x19,0x71,1024, 576, 0}, /* 32 */ + {0x0077,0x3b,0x39,0x0a,0x0c,0x75,1280, 720, 0}, /* 33 */ + {0x0047,0x3c,0x3a,0x0a,0x0c,0x75,1280, 720, 0}, /* 34 */ + {0x0007,0x3d,0x3b,0x0a,0x0c,0x75,1280, 720, 0}, /* 35 */ + {0x0067,0x49,0x35,0x06,0x1a,0x29,1152, 864, 0}, /* 36 1152x864-60Hz */ + {0x0067,0x3e,0x34,0x06,0x1a,0x29,1152, 864, 0}, /* 37 1152x864-75Hz */ + {0x0047,0x44,0x3a,0x06,0x1a,0x29,1152, 864, 0}, /* 38 1152x864-85Hz */ + {0x00c7,0x3f,0x28,0x00,0x16,0x39, 848, 480, 0}, /* 39 848x480-38Hzi */ + {0xc067,0x40,0x3d,0x0b,0x16,0x39, 848, 480, 0}, /* 3a 848x480-60Hz */ + {0x00c7,0x41,0x28,0x00,0x17,0x3f, 856, 480, 0}, /* 3b 856x480-38Hzi */ + {0xc047,0x42,0x28,0x00,0x17,0x3f, 856, 480, 0}, /* 3c 856x480-60Hz */ + {0x0067,0x43,0x3e,0x0c,0x1b,0x48,1360, 768, 0}, /* 3d 1360x768-60Hz */ + {0x0077,0x46,0x3f,0x08,0x08,0x55,1280, 768, 0}, /* 3e 1280x768-60Hz */ + {0x006f,0x47,0x03,0x06,0x15,0x5f, 768, 576, 0}, /* 3f 768x576 */ + {0x0027,0x48,0x13,0x08,0x00,0x67,1360,1024, 0}, /* 40 1360x1024-59Hz (BARCO1366 only) */ + {0xffff, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +static const SiS_VBModeStruct SiS300_VBModeIDTable[] = +{ + {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, + {0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x02}, + {0x03,0x00,0x00,0x00,0x02,0x00,0x02,0x00}, + {0x03,0x00,0x00,0x00,0x02,0x00,0x02,0x01}, + {0x03,0x00,0x00,0x00,0x03,0x00,0x03,0x02}, + {0x05,0x00,0x00,0x01,0x04,0x00,0x00,0x00}, + {0x06,0x00,0x00,0x01,0x05,0x00,0x02,0x00}, + {0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x01}, + {0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x02}, + {0x0d,0x00,0x00,0x01,0x04,0x00,0x00,0x00}, + {0x0e,0x00,0x00,0x01,0x05,0x00,0x02,0x00}, + {0x0f,0x00,0x00,0x01,0x05,0x00,0x02,0x01}, + {0x10,0x00,0x00,0x01,0x05,0x00,0x02,0x01}, + {0x11,0x00,0x00,0x01,0x05,0x00,0x02,0x03}, + {0x12,0x00,0x00,0x01,0x05,0x00,0x02,0x03}, + {0x13,0x00,0x00,0x01,0x04,0x00,0x04,0x00}, + {0x6a,0x00,0x00,0x01,0x07,0x00,0x08,0x0a}, + {0x2e,0x00,0x00,0x01,0x05,0x00,0x06,0x08}, + {0x2f,0x00,0x00,0x01,0x05,0x00,0x06,0x06}, + {0x30,0x00,0x00,0x01,0x07,0x00,0x08,0x0a}, + {0x31,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x32,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x33,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x34,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x35,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x36,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x37,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c}, + {0x38,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c}, + {0x3a,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}, + {0x40,0x00,0x00,0x01,0x04,0x00,0x05,0x05}, + {0x41,0x00,0x00,0x01,0x04,0x00,0x05,0x05}, + {0x43,0x00,0x00,0x01,0x05,0x00,0x06,0x08}, + {0x44,0x00,0x00,0x01,0x05,0x00,0x06,0x08}, + {0x46,0x00,0x00,0x01,0x07,0x00,0x08,0x0a}, + {0x47,0x00,0x00,0x01,0x07,0x00,0x08,0x0a}, + {0x49,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c}, + {0x4a,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c}, + {0x4c,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}, + {0x4d,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}, + {0x4f,0x00,0x00,0x01,0x04,0x00,0x05,0x05}, + {0x50,0x00,0x00,0x01,0x04,0x00,0x05,0x07}, + {0x51,0x00,0x00,0x01,0x07,0x00,0x07,0x09}, + {0x52,0x00,0x00,0x01,0x00,0x00,0x09,0x0b}, + {0x53,0x00,0x00,0x01,0x04,0x00,0x05,0x07}, + {0x54,0x00,0x00,0x01,0x07,0x00,0x07,0x09}, + {0x56,0x00,0x00,0x01,0x04,0x00,0x05,0x07}, + {0x57,0x00,0x00,0x01,0x07,0x00,0x07,0x09}, + {0x58,0x00,0x00,0x01,0x00,0x00,0x09,0x0b}, + {0x59,0x00,0x00,0x01,0x04,0x00,0x05,0x05}, + {0x5c,0x00,0x00,0x01,0x00,0x00,0x09,0x0b}, + {0x5d,0x00,0x00,0x01,0x05,0x00,0x06,0x06}, + {0x5e,0x00,0x00,0x01,0x05,0x00,0x06,0x06}, + {0x5f,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x60,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x61,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x62,0x00,0x00,0x01,0x05,0x00,0x06,0x08}, + {0x63,0x00,0x00,0x01,0x07,0x00,0x08,0x0a}, + {0x64,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c}, + {0x65,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}, + {0x6c,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}, + {0x6d,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}, + {0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +}; + +static const SiS_CRT1TableStruct SiS300_CRT1Table[] = +{ +#if 1 + {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, /* 0x00 - 320x200 */ + 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, /* HRE [4],[15] is invalid - but correcting it does not work */ + 0x00}}, +#endif +#if 0 + {{0x2d,0x27,0x27,0x91,0x2c,0x92,0xbf,0x1f, /* 0x00 - corrected 320x200-72 - does not work */ + 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x04, + 0x00}}, +#endif + {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, /* 0x01 */ + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, /* HRE [4],[15] is invalid - but correcting it does not work */ + 0x00}}, +#if 0 + {{0x2d,0x27,0x27,0x91,0x2c,0x92,0x0b,0x3e, /* 0x01 - corrected 320x240-60 - does not work */ + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x04, + 0x00}}, +#endif + {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, /* 0x02 */ + 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, + 0x01}}, +#if 0 + {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, /* 0x02 - corrected 400x300-60 */ + 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, + 0x01}}, +#endif + {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, + 0x01}}, + {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, +#if 0 + {{0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e, /* 0x05 */ + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, + 0x00}}, +#endif + {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, /* 0x05 - corrected 640x480-60 */ + 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, + 0x00}}, +#if 0 + {{0x63,0x4f,0x50,0x86,0x56,0x9b,0x06,0x3e, /* 0x06 */ + 0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01, + 0x00}}, +#endif + {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, /* 0x06 - corrected 640x480-72 */ + 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f, + 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01, + 0x00}}, + {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f, + 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, + 0x00}}, +#if 0 + {{0x66,0x4f,0x4f,0x86,0x56,0x9e,0x03,0x3e, /* 0x09 */ + 0xe4,0x87,0xdf,0xdf,0x04,0x00,0x00,0x01, + 0x00}}, +#endif + {{0x67,0x4f,0x4f,0x8b,0x57,0x83,0x10,0x3e, /* 0x09 - corrected 640x480-100 */ + 0xe7,0x8d,0xdf,0xe6,0x11,0x00,0x00,0x05, + 0x00}}, +#if 0 + {{0x6c,0x4f,0x4f,0x83,0x59,0x9e,0x00,0x3e, /* 0x0a */ + 0xe5,0x8d,0xdf,0xdf,0x01,0x00,0x00,0x01, + 0x00}}, +#endif + {{0x67,0x4f,0x4f,0x8b,0x57,0x83,0x10,0x3e, /* 0x0a - corrected 640x480-120 */ + 0xe7,0x8d,0xdf,0xe6,0x11,0x00,0x00,0x05, + 0x00}}, + {{0x63,0x4f,0x4f,0x87,0x56,0x9d,0xfb,0x1f, + 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x01, + 0x00}}, + {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f, + 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, /* Corrected VDE, VBE */ + 0x00}}, + {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0, + 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05, + 0x01}}, + {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0, + 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06, + 0x01}}, + {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0, + 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06, + 0x01}}, + {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0, + 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06, + 0x01}}, + {{0x8c,0x63,0x63,0x87,0x72,0x16,0x7e,0xf0, + 0x59,0x8d,0x57,0x57,0x7f,0x00,0x00,0x06, + 0x01}}, + {{0x7e,0x63,0x63,0x82,0x6c,0x14,0x75,0xe0, + 0x58,0x0b,0x57,0x57,0x76,0x20,0x00,0x06, + 0x01}}, + {{0x7e,0x63,0x63,0x82,0x6c,0x14,0x75,0xe0, /* 0x14 */ + 0x58,0x0b,0x57,0x57,0x76,0x20,0x00,0x06, + 0x01}}, + {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f, + 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02, + 0x00}}, + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, + {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, + {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5, + 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02, + 0x01}}, + {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5, + 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02, + 0x01}}, + {{0x9f,0x7f,0x7f,0x83,0x83,0x93,0x1e,0xf5, /* 0x1a */ + 0x00,0x84,0xff,0xff,0x1f,0x10,0x00,0x02, + 0x01}}, + {{0xa2,0x7f,0x7f,0x86,0x84,0x94,0x37,0xf5, + 0x0b,0x82,0xff,0xff,0x38,0x10,0x00,0x02, + 0x01}}, + {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba, + 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03, + 0x00}}, + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a, + 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, + 0x01}}, + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a, /* 0x1e */ + 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, + 0x01}}, + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a, + 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07, + 0x01}}, + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, /* 36: 1600x1200x85Hz */ + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, + {{0x3f,0xef,0xef,0x83,0xfd,0x1a,0xda,0x1f, /* 37: 1920x1440x60Hz */ + 0xa0,0x84,0x9f,0x9f,0xdb,0x1f,0x01,0x01, + 0x00}}, + {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba, + 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05, + 0x00}}, +#if 0 + {{0xdc,0x9f,0x9f,0x00,0xab,0x19,0xe6,0xef, /* 0x27: 1280x960-70 - invalid! */ + 0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07, + 0x01}}, +#endif + {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff, /* 0x27: 1280x960-60 - correct */ + 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07, + 0x01}}, + {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, /* 0x28 */ + 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, + 0x01}}, + {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, + 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, + 0x01}}, + {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, + 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, + 0x01}}, + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, + 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, + 0x01}}, + {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, + 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, + 0x01}}, + {{0xa7,0x7f,0x7f,0x88,0x89,0x15,0x26,0xf1, + 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, + 0x01}}, + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, + 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, + 0x01}}, + {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e, + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0, /* 0x32 */ + 0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05, + 0x01}}, + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, /* 0x33 - 1024x600 */ + 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, + 0x01}}, + {{0xa3,0x8f,0x8f,0x97,0x96,0x97,0x24,0xf5, /* 0x34 - 1152x768 - corrected */ + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, + {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, /* 0x35 */ + 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, + 0x01}}, /* 0x35 */ + {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, + 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, + 0x01}}, /* 0x36 */ + {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, + 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, + 0x01}}, /* 0x37 */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, + 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, + 0x01}}, /* 0x38 */ + {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, + 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, + 0x01}}, /* 0x39 */ + {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, /* 95 was 15 - illegal HBE! */ + 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, + 0x01}}, /* 0x3a */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x3b */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x3c */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, + 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, + 0x01}}, /* 0x3d */ + {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, /* 1152x864-75 */ + 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07, + 0x01}}, /* 0x3e */ + {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, /* 848x480-38i */ + 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, + 0x00}}, /* 0x3f */ + {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, /* 848x480-60 */ + 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06, + 0x00}}, /* 0x40 */ + {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, /* 856x480-38i */ + 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, + 0x00}}, /* 0x41 */ + {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, /* 856x480-60 */ + 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02, + 0x00}}, /* 0x42 */ + {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, /* 1360x768-60 */ + 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03, + 0x01}}, /* 0x43 */ + {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, /* 1152x864-84 */ + 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03, + 0x01}}, /* 0x44 */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, /* 1280x960-85 */ + 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07, + 0x01}}, /* 0x45 */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5, /* 1280x768-60 */ + 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07, + 0x01}}, /* 0x46 */ + {{0x7b,0x5f,0x63,0x9f,0x6a,0x93,0x6f,0xf0, /* 768x576 */ + 0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05, + 0x01}}, /* 0x47 */ + {{0xce,0xa9,0xa9,0x92,0xb1,0x07,0x28,0x52, /* 1360x1024 (Barco iQ Pro R300) */ + 0x02,0x8e,0xff,0x00,0x29,0x0d,0x00,0x03, + 0x00}}, /* 0x48 */ + {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, /* 1152x864-60 */ + 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07, + 0x41}} /* 0x49 */ +}; + +static const SiS_MCLKDataStruct SiS300_MCLKData_630[] = +{ + { 0x5a,0x64,0x80, 66}, + { 0xb3,0x45,0x80, 83}, + { 0x37,0x61,0x80,100}, + { 0x37,0x22,0x80,133}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100} +}; + +static const SiS_MCLKDataStruct SiS300_MCLKData_300[] = +{ + { 0x68,0x43,0x80,125}, + { 0x68,0x43,0x80,125}, + { 0x68,0x43,0x80,125}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100} +}; + +static SiS_VCLKDataStruct SiS300_VCLKData[] = +{ + { 0x1b,0xe1, 25}, /* 0x00 */ + { 0x4e,0xe4, 28}, /* 0x01 */ + { 0x57,0xe4, 32}, /* 0x02 */ + { 0xc3,0xc8, 36}, /* 0x03 */ + { 0x42,0xc3, 40}, /* 0x04 */ + { 0x5d,0xc4, 45}, /* 0x05 */ + { 0x52,0x65, 50}, /* 0x06 */ + { 0x53,0x65, 50}, /* 0x07 */ + { 0x6d,0x66, 56}, /* 0x08 */ + { 0x5a,0x64, 65}, /* 0x09 */ + { 0x46,0x44, 68}, /* 0x0a */ + { 0x3e,0x43, 75}, /* 0x0b */ + { 0x6d,0x46, 76}, /* 0x0c */ /* 800x600 | LVDS_2(CH), MITAC(CH); - 730, A901(301B): 0xb1,0x46, 76 */ + { 0x41,0x43, 79}, /* 0x0d */ + { 0x31,0x42, 79}, /* 0x0e */ + { 0x46,0x25, 85}, /* 0x0f */ + { 0x78,0x29, 87}, /* 0x10 */ + { 0x62,0x44, 95}, /* 0x11 */ + { 0x2b,0x22,105}, /* 0x12 */ + { 0x49,0x24,106}, /* 0x13 */ + { 0xc3,0x28,108}, /* 0x14 */ + { 0x3c,0x23,109}, /* 0x15 */ + { 0xf7,0x2c,132}, /* 0x16 */ + { 0xd4,0x28,136}, /* 0x17 */ + { 0x41,0x05,158}, /* 0x18 */ + { 0x43,0x05,162}, /* 0x19 */ + { 0xe1,0x0f,175}, /* 0x1a */ + { 0xfc,0x12,189}, /* 0x1b */ + { 0xde,0x26,194}, /* 0x1c */ + { 0x54,0x05,203}, /* 0x1d */ + { 0x3f,0x03,230}, /* 0x1e */ + { 0x30,0x02,234}, /* 0x1f */ + { 0x24,0x01,266}, /* 0x20 */ + { 0x52,0x2a, 54}, /* 0x21 */ /* 301 TV */ + { 0x52,0x6a, 27}, /* 0x22 */ /* 301 TV */ + { 0x62,0x24, 70}, /* 0x23 */ /* 301 TV */ + { 0x62,0x64, 70}, /* 0x24 */ /* 301 TV */ + { 0xa8,0x4c, 30}, /* 0x25 */ /* 301 TV */ + { 0x20,0x26, 33}, /* 0x26 */ /* 301 TV */ + { 0x31,0xc2, 39}, /* 0x27 */ + { 0xbf,0xc8, 35}, /* 0x28 */ /* 856x480 */ + { 0x60,0x36, 30}, /* 0x29 */ /* CH/UNTSC TEXT | LVDS_2(CH) - 730, A901(301B), Mitac(CH): 0xe0, 0xb6, 30 */ + { 0x40,0x4a, 28}, /* 0x2a */ /* CH-TV */ + { 0x9f,0x46, 44}, /* 0x2b */ /* CH-TV */ + { 0x97,0x2c, 26}, /* 0x2c */ /* CH-TV */ + { 0x44,0xe4, 25}, /* 0x2d */ /* CH-TV */ + { 0x7e,0x32, 47}, /* 0x2e */ /* CH-TV */ + { 0x8a,0x24, 31}, /* 0x2f */ /* CH/PAL TEXT | LVDS_2(CH), Mitac(CH) - 730, A901(301B): 0x57, 0xe4, 31 */ + { 0x97,0x2c, 26}, /* 0x30 */ /* CH-TV */ + { 0xce,0x3c, 39}, /* 0x31 */ /* CH-TV */ + { 0x52,0x4a, 36}, /* 0x32 */ /* CH/PAL 800x600 5/6 */ + { 0x34,0x61, 95}, /* 0x33 */ + { 0x78,0x27,108}, /* 0x34 */ /* Replacement for index 0x14 for 630 (?) */ + { 0x70,0x28, 90}, /* 0x35 */ /* 1152x864@60 */ + { 0x45,0x6b, 21}, /* 0x36 */ /* Chrontel SuperOverscan */ + { 0x52,0xe2, 49}, /* 0x37 */ /* 16:9 modes */ + { 0x2b,0x61, 78}, /* 0x38 */ /* 16:9 modes */ + { 0x70,0x44,108}, /* 0x39 */ /* 16:9 modes */ + { 0x54,0x42,135}, /* 0x3a */ /* 16:9 modes */ + { 0x41,0x22,157}, /* 0x3b */ /* 16:9 modes */ + { 0x52,0x07,149}, /* 0x3c */ /* 1280x960-85 */ + { 0x62,0xc6, 34}, /* 0x3d */ /* 848x480-60 */ + { 0x30,0x23, 88}, /* 0x3e */ /* 1360x768-60 */ + { 0x70,0x29, 81}, /* 0x3f */ /* 1280x768-60 */ + { 0x72,0x2a, 76}, /* 0x40 */ /* test for SiS730 --- LIMIT for table (&0x3f) */ + { 0x15,0x21, 79}, /* 0x41 */ /* test for SiS730 */ + { 0xa1,0x42,108}, /* 0x42 */ /* 1280x960 LCD */ + { 0x37,0x61,100}, /* 0x43 */ /* 1280x960 LCD */ + { 0xe3,0x9a,106}, /* 0x44 */ /* 1360x1024 - special for Barco iQ R300 */ + { 0xe2,0x46,135}, /* 0x45 */ /* 1280x1024-75, better clock for VGA2 */ + { 0x70,0x29, 81}, /* 0x46 */ /* unused */ + { 0, 0, 0}, /* 0x47 custom (will be filled out) */ + { 0xce,0x25,189} /* 0x48 */ /* Replacement for index 0x1b for 730 (and 540?) */ +}; + +#ifdef LINUX_KERNEL +static UCHAR SiS300_SR07 = 0x10; +#endif + +static const DRAM4Type SiS300_SR15[8] = +{ + {0x01,0x09,0xa3,0x00}, + {0x43,0x43,0x43,0x00}, + {0x1e,0x1e,0x1e,0x00}, + {0x2a,0x2a,0x2a,0x00}, + {0x06,0x06,0x06,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00} +}; + +#ifdef LINUX_KERNEL +static UCHAR SiS300_SR1F = 0x00; +static UCHAR SiS300_SR21 = 0x16; +static UCHAR SiS300_SR22 = 0xb2; +static UCHAR SiS300_SR23 = 0xf6; +static UCHAR SiS300_SR24 = 0x0d; +static UCHAR SiS300_SR25[] = {0x0,0x0}; +static UCHAR SiS300_SR31 = 0x00; +static UCHAR SiS300_SR32 = 0x11; +static UCHAR SiS300_SR33 = 0x00; +static UCHAR SiS300_CRT2Data_1_2 = 0x40; +static UCHAR SiS300_CRT2Data_4_D = 0x00; +static UCHAR SiS300_CRT2Data_4_E = 0x00; +static UCHAR SiS300_CRT2Data_4_10 = 0x80; + +static const USHORT SiS300_RGBSenseData = 0xd1; +static const USHORT SiS300_VideoSenseData = 0xb3; +static const USHORT SiS300_YCSenseData = 0xb9; +static const USHORT SiS300_RGBSenseData2 = 0x0190; +static const USHORT SiS300_VideoSenseData2 = 0x0174; +static const USHORT SiS300_YCSenseData2 = 0x016b; + +static const DRAM4Type SiS300_CR40[5]; + +static UCHAR SiS300_CR49[2]; +#endif + +static const SiS_PanelDelayTblStruct SiS300_PanelDelayTbl[] = +{ + {{0x05,0xaa}}, + {{0x05,0x14}}, + {{0x05,0x36}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x05,0x90}}, + {{0x05,0x90}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x20,0x80}}, + {{0x05,0x14}}, + {{0x05,0x40}}, + {{0x05,0x60}} +}; + +#if 0 +static const SiS_PanelDelayTblStruct SiS300_PanelDelayTblLVDS[] = +{ + {{0x05,0xaa}}, + {{0x05,0x14}}, + {{0x05,0x36}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x05,0x90}}, + {{0x05,0x90}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x05,0x14}}, /* 2.07a (JVC): 14,96 */ + {{0x05,0x28}}, /* 2.04.5c: 20, 80 - Clevo (2.04.2c): 05, 28 */ + {{0x05,0x14}}, + {{0x05,0x14}}, /* Some BIOSes: 05, 40 */ + {{0x05,0x60}} +}; +#endif + +/**************************************************************/ +/* SIS VIDEO BRIDGE ----------------------------------------- */ +/**************************************************************/ + +static const SiS_LCDDataStruct SiS300_St2LCD1024x768Data[] = +{ + { 62, 25, 800, 546,1344, 806}, + { 32, 15, 930, 546,1344, 806}, + { 32, 15, 930, 546,1344, 806}, + { 104, 45, 945, 496,1344, 806}, + { 62, 25, 800, 546,1344, 806}, + { 31, 18,1008, 624,1344, 806}, + { 1, 1,1344, 806,1344, 806} +}; + +static const SiS_LCDDataStruct SiS300_ExtLCD1024x768Data[] = +{ + { 12, 5, 896, 512,1344, 806}, + { 12, 5, 896, 510,1344, 806}, + { 32, 15,1008, 505,1344, 806}, + { 32, 15,1008, 514,1344, 806}, + { 12, 5, 896, 500,1344, 806}, + { 42, 25,1024, 625,1344, 806}, + { 1, 1,1344, 806,1344, 806}, + { 12, 5, 896, 500,1344, 806}, + { 42, 25,1024, 625,1344, 806}, + { 1, 1,1344, 806,1344, 806}, + { 12, 5, 896, 500,1344, 806}, + { 42, 25,1024, 625,1344, 806}, + { 1, 1,1344, 806,1344, 806} +}; + +static const SiS_LCDDataStruct SiS300_St2LCD1280x1024Data[] = +{ + { 22, 5, 800, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 176, 45, 900, 510,1650,1088}, + { 176, 45, 900, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 13, 5,1024, 675,1560,1152}, + { 16, 9,1266, 804,1688,1072}, + { 1, 1,1688,1066,1688,1066} +}; + +static const SiS_LCDDataStruct SiS300_ExtLCD1280x1024Data[] = +{ + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 211, 60,1024, 500,1688,1066}, + { 211, 75,1024, 625,1688,1066}, + { 211, 120,1280, 798,1688,1066}, + { 1, 1,1688,1066,1688,1066} +}; + +static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_1[] = +{ /* VESA Timing */ + {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, + {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}, + {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}, + {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}} +}; + +static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_2[] = +{ /* Non-VESA */ + {{0x28,0x12,0xa3,0xd0,0xaa,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x28,0x12,0xa3,0xd0,0xaa,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x28,0x13,0xe7,0x0b,0xe8,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x38,0x18,0x16,0x00,0x00,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x36,0x13,0x13,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}} +}; + +static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_3[] = +{ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} +}; + +static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_1[] = +{ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} +}; + +static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_2[] = +{ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} +}; + +static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_3[] = +{ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} +}; + +/**************************************************************/ +/* LVDS/Chrontel -------------------------------------------- */ +/**************************************************************/ + +static const SiS_LVDSDataStruct SiS300_CHTVUPALData[] = +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 750, 840, 750}, + { 936, 836, 936, 836} +}; + +static const SiS_LVDSDataStruct SiS300_CHTVOPALData[] = +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 625, 840, 625}, + { 960, 750, 960, 750} +}; + +static const SiS_LVDSDataStruct SiS300_CHTVSOPALData[] = +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 500, 840, 500}, + { 944, 625, 944, 625} +}; + + +static const SiS_LVDSDesStruct SiS300_PanelType00_1[] = +{ + { 1059, 626 }, /* 2.08 */ + { 1059, 624 }, + { 1059, 626 }, + { 1059, 624 }, + { 1059, 624 }, + { 0, 627 }, + { 0, 627 }, + { 0, 0 }, + { 0, 0 } +#if 0 + {0, 626}, + {0, 624}, + {0, 626}, + {0, 624}, + {0, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +#endif +}; + +static const SiS_LVDSDesStruct SiS300_PanelType01_1[] = +{ + { 0, 0 }, /* 2.08 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 } +#if 0 + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +#endif +}; + +static const SiS_LVDSDesStruct SiS300_PanelType02_1[] = +{ + { 1059, 626 }, /* 2.08 */ + { 1059, 624 }, + { 1059, 626 }, + { 1059, 624 }, + { 1059, 624 }, + { 0, 627 }, + { 0, 627 }, + { 0, 0 }, + { 0, 0 } +#if 0 + {0, 626}, + {0, 624}, + {0, 626}, + {0, 624}, + {0, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +#endif +}; + +static const SiS_LVDSDesStruct SiS300_PanelType03_1[] = +{ + { 8, 436}, + { 8, 440}, + { 8, 436}, + { 8, 440}, + { 8, 512}, + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType04_1[] = /* 1280x1024 */ +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType05_1[] = +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType06_1[] = /* Clevo Trumpion 1024x768 */ +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType07_1[] = +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType08_1[] = +{ + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + { 0, 627}, + { 0, 627}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType09_1[] = +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType0a_1[] = +{ + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + { 0, 627}, + { 0, 627}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType0b_1[] = +{ + {1343, 0}, + {1343, 0}, + {1343, 0}, + {1343, 0}, + {1343, 0}, + {1343, 0}, + { 0, 799}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType0c_1[] = +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType0d_1[] = +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType0e_1[] = +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, /* 640x480 */ + {1343, 0}, /* 800x600 */ + { 0, 805}, /* 1024x768 */ + { 0, 794}, /* 1280x1024 */ + { 0, 0} /* 1280x960 - not applicable */ +}; + +static const SiS_LVDSDesStruct SiS300_PanelType0f_1[] = +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType00_2[] = +{ + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + { 0, 627}, + { 0, 627}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType01_2[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType02_2[] = +{ + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + { 0, 627}, + { 0, 627}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType03_2[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + {1152, 622}, + {1152, 597} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType04_2[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType05_2[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType06_2[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType07_2[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType08_2[] = +{ + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + { 0, 627}, + { 0, 627}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType09_2[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType0a_2[] = +{ + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + { 0, 627}, + { 0, 627}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType0b_2[] = +{ + { 1152, 700}, + { 1152, 675}, + { 1152, 700}, + { 1152, 675}, + { 1152, 740}, + { 1232, 799}, + { 0, 799}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType0c_2[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType0d_2[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType0e_2[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelType0f_2[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelTypeNS_1[]= +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 805}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelTypeNS_2[] = +{ + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0} +}; + +/* Custom data for Barco iQ R200/300/400 (BIOS 2.00.07) */ +static const SiS_LVDSDesStruct SiS300_PanelType04_1a[] = /* 1280x1024 (1366x1024) */ +{ + {1330, 798}, /* 320x200 */ + {1330, 794}, + {1330, 798}, + {1330, 794}, + {1330, 0}, /* 640x480 / 320x240 */ + {1343, 0}, /* 800x600 / 400x300 */ + { 0, 805}, /* 1024x768 / 512x384 */ + {1688,1066}, /* 1280x1024 */ + { 0, 0} /* 1360x1024 */ +}; + +static const SiS_LVDSDesStruct SiS300_PanelType04_2a[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + {1688,1066}, + { 0, 0} +}; + +/* Custom data for Barco iQ G200/300/400 (BIOS 2.00.07) */ +static const SiS_LVDSDesStruct SiS300_PanelType04_1b[] = /* 1024x768 */ +{ + {1330, 798}, /* 320x200 */ + {1330, 794}, + {1330, 798}, + {1330, 794}, + {1330, 0}, /* 640x480 / 320x240 */ + {1343, 0}, /* 800x600 / 400x300 */ + { 0, 805} /* 1024x768 / 512x384 */ +}; + +static const SiS_LVDSDesStruct SiS300_PanelType04_2b[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805} +}; + +/* CRT1 CRTC for slave modes */ + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_1[] = +{ + {{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, + 0x00 }}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00 }}, + {{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, + 0x00 }}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00 }}, + {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e, + 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, + 0x00 }}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_1_H[] = +{ + {{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x04, + 0x00 }}, + {{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x04, + 0x00 }}, + {{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x04, + 0x00 }}, + {{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x04, + 0x00 }}, + {{0x30,0x27,0x94,0x2c,0x92,0x04,0x3e, + 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x04, + 0x00 }}, + {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x05, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_1[] = +{ + {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x88,0x54,0x9f,0x04,0x3e, + 0xe2,0x89,0xdf,0x05,0x00,0x00,0x01, + 0x00}}, + {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0, + 0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26, + 0x01}}, + {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x02, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_1_H[] = +{ + {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, + 0x00 }}, + {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f, + 0x60,0x87,0x5D,0x83,0x10,0x00,0x44, + 0x00}}, + {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, + 0x00}}, + {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f, + 0x60,0x87,0x5D,0x83,0x10,0x00,0x44, + 0x00}}, + {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e, + 0xE2,0x89,0xdf,0x05,0x00,0x00,0x44, + 0x00}}, + {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0, + 0x5A,0x8F,0x57,0x7D,0x20,0x00,0x55, + 0x01}}, + {{0x4f,0x3F,0x93,0x45,0x0D,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x01, + 0x01 }} + +#if 0 + {{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, + 0x00 }}, + {{0x37,0x27,0x9B,0x2b,0x94,0x97,0x1f, + 0x60,0x87,0x5D,0x83,0x01,0x00,0x44, + 0x00}}, + {{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, + 0x00}}, + {{0x37,0x27,0x9B,0x2b,0x94,0x97,0x1f, + 0x60,0x87,0x5D,0x83,0x01,0x00,0x44, + 0x00}}, + {{0x37,0x27,0x9B,0x2b,0x94,0x04,0x3e, + 0xE2,0x89,0xDf,0x05,0x00,0x00,0x44, + 0x00}}, + {{0x41,0x31,0x85,0x35,0x1d,0x7c,0xf0, + 0x5A,0x8F,0x57,0x7D,0x20,0x00,0x55, + 0x01}}, + {{0x4f,0x3F,0x93,0x45,0x0D,0x24,0xf5, + 0x02,0x88,0xFf,0x25,0x10,0x00,0x01, + 0x01 }} +#endif +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_1[] = +{ + {{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, + 0x00 }}, + {{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x01, + 0x00 }}, + {{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, + 0x00 }}, + {{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x01, + 0x00 }}, + {{0x63,0x4f,0x87,0x54,0x9f,0x04,0x3e, + 0xe2,0x89,0xdf,0x05,0x00,0x00,0x01, + 0x00 }}, + {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0, + 0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26, + 0x01 }}, + {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x02, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_1_H[] = +{ + {{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x04, + 0x00 }}, + {{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x04, + 0x00 }}, + {{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x04, + 0x00 }}, + {{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x04, + 0x00 }}, + {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e, + 0xe2,0x89,0xdf,0x05,0x00,0x00,0x04, + 0x00 }}, + {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0, + 0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55, + 0x01 }}, + {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x01, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_2[] = +{ + {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, + 0xf4,0x88,0x8f,0x73,0x20,0x00,0x06, + 0x00 }}, + {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, + 0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06, + 0x00 }}, + {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, + 0xf4,0x88,0x8f,0x73,0x20,0x00,0x06, + 0x00 }}, + {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, + 0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06, + 0x00 }}, + {{0x7f,0x4f,0x83,0x62,0x12,0x72,0xba, + 0x1c,0x80,0xdf,0x73,0x00,0x00,0x06, + 0x00 }}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_2_H[] = +{ + {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e, + 0xf4,0x88,0x8f,0x73,0x20,0x00,0x05, + 0x00 }}, + {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e, + 0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05, + 0x00 }}, + {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e, + 0xf4,0x88,0x8f,0x73,0x20,0x00,0x05, + 0x00 }}, + {{0x3d,0x27,0x81,0x3a,0x1a,0x72,0x3e, + 0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05, + 0x00 }}, + {{0x3d,0x27,0x81,0x32,0x1a,0x72,0xba, + 0x1c,0x80,0xdf,0x73,0x00,0x00,0x05, + 0x00 }}, + {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x05, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_2[] = +{ + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, + 0x00 }}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, + 0x00 }}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, + 0x00 }}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, + 0x00 }}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x72,0x88,0xdf,0x25,0x30,0x00,0x06, + 0x00 }}, + {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1, + 0xae,0x84,0x57,0x25,0x30,0x00,0x02, + 0x01 }}, + {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x02, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_2_H[] = +{ + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, + 0x00 }}, + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, + 0x00 }}, + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, + 0x00 }}, + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, + 0x00 }}, + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x72,0x88,0xdf,0x25,0x30,0x00,0x01, + 0x00 }}, + {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1, + 0xae,0x84,0x57,0x25,0x30,0x00,0x01, + 0x01 }}, + {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x01, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_2[] = +{ + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, + 0x00 }}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, + 0x00 }}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, + 0x00 }}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, + 0x00 }}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x72,0x88,0xdf,0x25,0x30,0x00,0x06, + 0x00 }}, + {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1, + 0xae,0x84,0x57,0x25,0x30,0x00,0x02, + 0x01 }}, + {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x02, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_2_H[] = +{ + {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, + 0x00 }}, + {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, + 0x00 }}, + {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, + 0x00 }}, + {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, + 0x00 }}, + {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb, + 0x72,0x88,0xdf,0x25,0x30,0x00,0x01, + 0x00 }}, + {{0x4f,0x31,0x93,0x3e,0x86,0x24,0xf1, + 0xae,0x84,0x57,0x25,0x30,0x00,0x01, + 0x01 }}, + {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x01, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1XXXxXXX_1[] = +{ + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x02, + 0x01}}, + {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a, + 0x00,0x84,0xff,0x29,0x09,0x00,0x07, + 0x01}}, + {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x07, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1XXXxXXX_1_H[] = +{ + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}}, + {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x01, + 0x01}}, + {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x01, + 0x01}} +}; + + +static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1UNTSC[] = +{ + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xd0,0x82,0x5d,0x57,0x00,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xd0,0x82,0x5d,0x57,0x00,0x00,0x01, + 0x00 }}, + {{0x5d,0x4f,0x81,0x53,0x9c,0x56,0xba, + 0x18,0x84,0xdf,0x57,0x00,0x00,0x01, + 0x00 }}, + {{0x80,0x63,0x84,0x6c,0x17,0xec,0xf0, + 0x90,0x8c,0x57,0xed,0x20,0x00,0x06, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1ONTSC[] = +{ + {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, + 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, + 0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, + 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, + 0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01, + 0x00 }}, + {{0x5d,0x4f,0x81,0x56,0x9c,0x0b,0x3e, + 0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01, + 0x00 }}, + {{0x7d,0x63,0x81,0x6a,0x16,0xba,0xf0, + 0x7f,0x86,0x57,0xbb,0x00,0x00,0x06, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1UPAL[] = +{ + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x64,0x4f,0x88,0x55,0x80,0xec,0xba, + 0x50,0x84,0xdf,0xed,0x00,0x00,0x05, + 0x00 }}, + {{0x70,0x63,0x94,0x68,0x8d,0x42,0xf1, + 0xc8,0x8c,0x57,0xe9,0x20,0x00,0x05, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1OPAL[] = +{ + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x64,0x4f,0x88,0x55,0x80,0x6f,0xba, + 0x20,0x83,0xdf,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x73,0x63,0x97,0x69,0x8e,0xec,0xf0, + 0x90,0x8c,0x57,0xed,0x20,0x00,0x05, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1SOPAL[] = +{ + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x64,0x4f,0x88,0x55,0x80,0x6f,0xba, /* TODO */ + 0x20,0x83,0xdf,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x73,0x63,0x97,0x69,0x8e,0xec,0xf0, /* TODO */ + 0x90,0x8c,0x57,0xed,0x20,0x00,0x05, + 0x01 }} +}; + +static const SiS_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] = +{ + {{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x6a,0x6a,0x00,0x2d,0xfa,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 17: 640x480 NTSC 7/8 */ + {{0x8d,0xc4,0x00,0x3b,0xfb,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 24: 800x600 NTSC 7/10 */ +}; + +static const SiS_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] = +{ + {{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x69,0x6a,0x00,0x1e,0xfd,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 16: 640x480 NTSC 1/1 */ + {{0x8c,0xb4,0x00,0x32,0xf9,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 23: 800x600 NTSC 3/4 */ +}; + +static const SiS_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] = +{ + {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x63,0x94,0x01,0x50,0x30,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 15: 640x480 PAL 5/6 */ + {{0x84,0x64,0x01,0x4e,0x2f,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 21: 800x600 PAL 3/4 */ + +}; + +static const SiS_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] = +{ + {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */ + {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x61,0x94,0x01,0x36,0x30,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 14: 640x480 PAL 1/1 */ + {{0x83,0x76,0x01,0x40,0x31,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 20: 800x600 PAL 5/6 */ + +}; + +static const SiS_CHTVRegDataStruct SiS300_CHTVReg_SOPAL[] = +{ + {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */ + {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x60,0x30,0x00,0x10,0x00,0,0,0,0,0,0,0,0,0,0,0}}, /* TW: Mode 13: 640x480 PAL 5/4 */ + {{0x81,0x50,0x00,0x1b,0x00,0,0,0,0,0,0,0,0,0,0,0}} /* TW: Mode 19: 800x600 PAL 1/1 */ +}; + +static const UCHAR SiS300_CHTVVCLKUNTSC[] = {0x29,0x29,0x29,0x29,0x2a,0x2e}; + +static const UCHAR SiS300_CHTVVCLKONTSC[] = {0x2c,0x2c,0x2c,0x2c,0x2d,0x2b}; + +static const UCHAR SiS300_CHTVVCLKSONTSC[] = {0x2c,0x2c,0x2c,0x2c,0x2d,0x2b}; + +static const UCHAR SiS300_CHTVVCLKUPAL[] = {0x2f,0x2f,0x2f,0x2f,0x2f,0x31}; + +static const UCHAR SiS300_CHTVVCLKOPAL[] = {0x2f,0x2f,0x2f,0x2f,0x30,0x32}; + +static const UCHAR SiS300_CHTVVCLKSOPAL[] = {0x2f,0x2f,0x2f,0x2f,0x36,0x29}; + + diff --git a/drivers/video/sis/310vtbl.h b/drivers/video/sis/310vtbl.h new file mode 100644 index 000000000000..2c71d048f7c4 --- /dev/null +++ b/drivers/video/sis/310vtbl.h @@ -0,0 +1,2754 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Register settings for SiS 315/330 series + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +static const SiS_StStruct SiS310_SModeIDTable[]= +{ + {0x01,0x9208,0x01,0x00,0x00,0x00,0x01,0x00, 0x40}, + {0x01,0x1210,0x14,0x01,0x01,0x00,0x01,0x00, 0x40}, + {0x01,0x1010,0x17,0x02,0x02,0x00,0x01,0x01, 0x40}, + {0x03,0x8208,0x03,0x00,0x00,0x00,0x01,0x02, 0x40}, + {0x03,0x0210,0x16,0x01,0x01,0x00,0x01,0x02, 0x40}, + {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03, 0x40}, + {0x05,0x9209,0x05,0x00,0x00,0x00,0x00,0x04, 0x40}, + {0x06,0x8209,0x06,0x00,0x00,0x00,0x00,0x05, 0x40}, + {0x07,0x0000,0x07,0x03,0x03,0x00,0x01,0x03, 0x40}, + {0x07,0x0000,0x19,0x02,0x02,0x00,0x01,0x03, 0x40}, + {0x0d,0x920a,0x0d,0x00,0x00,0x00,0x00,0x04, 0x40}, + {0x0e,0x820a,0x0e,0x00,0x00,0x00,0x00,0x05, 0x40}, + {0x0f,0x0202,0x11,0x01,0x01,0x00,0x00,0x05, 0x40}, + {0x10,0x0212,0x12,0x01,0x01,0x00,0x00,0x05, 0x40}, + {0x11,0x0212,0x1a,0x04,0x04,0x00,0x00,0x05, 0x40}, + {0x12,0x0212,0x1b,0x04,0x04,0x00,0x00,0x05, 0x40}, + {0x13,0x021b,0x1c,0x00,0x00,0x00,0x00,0x04, 0x40}, + {0x12,0x0010,0x18,0x02,0x02,0x00,0x00,0x05, 0x40}, + {0x12,0x0210,0x18,0x01,0x01,0x00,0x00,0x05, 0x40}, + {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00, 0x40} +}; + +static const SiS_ExtStruct SiS310_EModeIDTable[]= +{ + {0x6a,0x2212,0x0102,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x? */ + {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */ + {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */ + {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */ + {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */ + {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */ + {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */ + {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */ + {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */ + {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */ + {0x37,0x0212,0x0104,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x? */ + {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */ + {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x8 */ + {0x3c,0x0e3b,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,10}, /* 1600x1200x8 */ + {0x3d,0x0e7d,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,10}, /* 1600x1200x16 */ + {0x40,0x9a1c,0x010d,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x15 */ + {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x16 */ + {0x43,0x0a1c,0x0110,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, + {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */ + {0x46,0x2a1c,0x0113,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, + {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */ + {0x49,0x0a3c,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x07,0x13, 4}, + {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */ + {0x4c,0x0e7c,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, + {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x16 */ + {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x8 */ + {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x8 */ + {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x8 */ + {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x16 */ + {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x16 */ + {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x16 */ + {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x8 */ + {0x5a,0x021b,0x0138,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x3f, 2}, /* 320x240x8 fstn */ + {0x5b,0x0a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x3f, 2}, /* 320x240x16 fstn */ + {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x32 */ + {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, + {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */ + {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */ + {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */ + {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */ + {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x32 */ + {0x66,0x0eff,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,10}, /* 1600x1200x32 */ + {0x68,0x067b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29,-1}, /* 1920x1440x8 */ + {0x69,0x06fd,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29,-1}, /* 1920x1440x16 */ + {0x6b,0x07ff,0x0141,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29,-1}, /* 1920x1440x32 */ + {0x6c,0x067b,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f,-1}, /* 2048x1536x8 */ + {0x6d,0x06fd,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f,-1}, /* 2048x1536x16 */ + {0x6e,0x07ff,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f,-1}, /* 2048x1536x32 */ + {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x34,-1}, /* 800x480x8 */ + {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37,-1}, /* 1024x576x8 */ + {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37,-1}, /* 1024x576x16 */ + {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a, 5}, /* 1280x720x16 */ + {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x34,-1}, /* 800x480x32 */ + {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37,-1}, /* 1024x576x32 */ + {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a, 5}, /* 1280x720x32 */ + {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a, 5}, /* 1280x720x8 */ + {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x34,-1}, /* 800x480x16 */ + {0x7c,0x0e3b,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1280x960x8 */ + {0x7d,0x0e7d,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1280x960x16 */ + {0x7e,0x0eff,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1280x960x32 */ + {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x8 */ + {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x16 */ + {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x32 */ + {0x26,0x0e3b,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41, 9}, /* 1400x1050x8 */ + {0x27,0x0e7d,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41, 9}, /* 1400x1050x16 */ + {0x28,0x0eff,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41, 9}, /* 1400x1050x32*/ + {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43,-1}, /* 1152x864 */ + {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43,-1}, + {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43,-1}, + {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x46,-1}, /* 848x480 */ + {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x46,-1}, + {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x46,-1}, + {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x48,-1}, /* 856x480 */ + {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x48,-1}, + {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x48,-1}, + {0x48,0x6a3b,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4a,-1}, /* 1360x768 */ + {0x4b,0x6a7d,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4a,-1}, + {0x4e,0x6aff,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4a,-1}, + {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x32 */ + {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x32 */ + {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x32 */ + {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4b,-1}, /* 768x576 */ + {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4b,-1}, + {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4b,-1}, + {0x14,0x0e3b,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4c, 7}, /* 1280x800 */ + {0x15,0x0e7d,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4c, 7}, + {0x16,0x0eff,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4c, 7}, + {0x17,0x0e3b,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4d, 9}, /* 1680x1050 */ + {0x18,0x0e7d,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4d, 9}, + {0x19,0x0eff,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4d, 9}, + {0x2c,0x267b,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x4e,-1}, /* 1920x1080(i) */ + {0x2d,0x26fd,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x4e,-1}, + {0x73,0x27ff,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x4e,-1}, + {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x4f,-1}, /* 960x540 */ + {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x4f,-1}, + {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x4f,-1}, + {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x50,-1}, /* 960x600 */ + {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x50,-1}, + {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x50,-1}, + {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1} +}; + +static const SiS_Ext2Struct SiS310_RefIndex[]= +{ + {0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0x40}, /* 0x0 */ + {0x0067,0x0e,0x04,0x05,0x05,0x6a, 800, 600, 0x40}, /* 0x1 */ + {0x0067,0x0f,0x08,0x48,0x05,0x6a, 800, 600, 0x40}, /* 0x2 */ + {0x0067,0x10,0x07,0x8b,0x05,0x6a, 800, 600, 0x40}, /* 0x3 */ + {0x0047,0x11,0x0a,0x00,0x05,0x6a, 800, 600, 0x40}, /* 0x4 */ + {0x0047,0x12,0x0d,0x00,0x05,0x6a, 800, 600, 0x40}, /* 0x5 */ + {0x0047,0x13,0x13,0x00,0x05,0x6a, 800, 600, 0x20}, /* 0x6 */ + {0x0107,0x14,0x1c,0x00,0x05,0x6a, 800, 600, 0x20}, /* 0x7 */ + {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40}, /* 0x8 */ + {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40}, /* 0x9 */ + {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40}, /* 0xa */ + {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40}, /* 0xb */ + {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xc */ + {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xd */ + {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xe */ + {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xf */ + {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30}, /* 0x10 */ + {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30}, /* 0x11 */ + {0x006f,0x3d,0x03,0x06,0x14,0x32, 720, 576, 0x30}, /* 0x12 */ + {0x0087,0x15,0x06,0x00,0x06,0x37,1024, 768, 0x30}, /* 0x13 */ + {0xc877,0x16,0x0b,0x06,0x06,0x37,1024, 768, 0x20}, /* 0x14 */ + {0xc067,0x17,0x0f,0x49,0x06,0x37,1024, 768, 0x20}, /* 0x15 */ + {0x0067,0x18,0x11,0x00,0x06,0x37,1024, 768, 0x20}, /* 0x16 */ + {0x0047,0x19,0x16,0x8c,0x06,0x37,1024, 768, 0x20}, /* 0x17 */ + {0x0107,0x1a,0x1b,0x00,0x06,0x37,1024, 768, 0x10}, /* 0x18 */ + {0x0107,0x1b,0x1f,0x00,0x06,0x37,1024, 768, 0x10}, /* 0x19 */ + {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30}, /* 0x1a */ + {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00}, /* 0x1b */ + {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00}, /* 0x1c */ + {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00}, /* 0x1d */ + {0x0227,0x20,0x21,0x09,0x09,0x3c,1600,1200, 0x00}, /* 0x1e */ + {0x0407,0x21,0x22,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x1f */ + {0x0407,0x22,0x23,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x20 */ + {0x0407,0x23,0x25,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x21 */ + {0x0007,0x24,0x26,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x22 */ + {0x0007,0x25,0x2c,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x23 */ + {0x0007,0x26,0x34,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x24 */ + {0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0x30}, /* 0x25 */ + {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30}, /* 0x26 */ + {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30}, /* 0x27 */ + {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30}, /* 0x28 */ + {0x8007,0x27,0x27,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x29 */ + {0x4007,0x28,0x29,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2a */ + {0x4007,0x29,0x2e,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2b */ + {0x4007,0x2a,0x30,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2c */ + {0x4007,0x2b,0x35,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2d */ + {0x4005,0x2c,0x39,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2e */ + {0x4007,0x2d,0x2b,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x2f */ + {0x4007,0x2e,0x31,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x30 */ + {0x4007,0x2f,0x33,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x31 */ + {0x4007,0x30,0x37,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x32 */ + {0x4005,0x31,0x38,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x33 */ + {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30}, /* 0x34 */ + {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30}, /* 0x35 */ + {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30}, /* 0x36 */ + {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30}, /* 0x37 */ + {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30}, /* 0x38 */ + {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30}, /* 0x39 */ + {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3a */ + {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3b */ + {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3c */ + {0x0127,0x3b,0x19,0x08,0x0a,0x7c,1280, 960, 0x30}, /* 0x3d */ + {0x0227,0x4c,0x59,0x08,0x0a,0x7c,1280, 960, 0x20}, /* 0x3e */ + {0xc07f,0x4e,0x00,0x06,0x04,0x5a, 320, 240, 0x30}, /* 0x3f */ /* FSTN 320x240 */ + {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30}, /* 0x40 */ /* 0x5b was 0x12 */ + {0x0127,0x43,0x4d,0x08,0x0b,0x26,1400,1050, 0x30}, /* 0x41 */ + {0x0207,0x4b,0x5a,0x08,0x0b,0x26,1400,1050, 0x30}, /* 0x42 1400x1050-75Hz */ + {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30}, /* 0x43 1152x864-60Hz */ + {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30}, /* 0x44 1152x864-75Hz */ + {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30}, /* 0x45 1152x864-85Hz */ + {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30}, /* 0x46 848x480-38Hzi */ + {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30}, /* 0x47 848x480-60Hz */ + {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30}, /* 0x48 856x480-38Hzi */ + {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30}, /* 0x49 856x480-60Hz */ + {0x0067,0x49,0x58,0x0c,0x1b,0x48,1360, 768, 0x30}, /* 0x4a 1360x768-60Hz */ + {0x006f,0x4d,0x03,0x06,0x15,0x5f, 768, 576, 0x30}, /* 0x4b 768x576-56Hz */ + {0x0067,0x4f,0x5c,0x08,0x0d,0x14,1280, 800, 0x30}, /* 0x4c 1280x800-60Hz */ + {0x0067,0x50,0x5d,0x0c,0x0e,0x17,1680,1050, 0x30}, /* 0x4d 1680x1050-60Hz */ + {0x0087,0x51,0x69,0x00,0x00,0x2c,1920,1080, 0x30}, /* 0x4e 1920x1080 60Hzi */ + {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30}, /* 0x4f 960x540 60Hz */ + {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30}, /* 0x50 960x600 60Hz */ + {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0} +}; + +#ifdef LINUX_XF86 +static const struct { + UCHAR Ext_ModeID; /* ModeID in new ROM */ + UCHAR Ext_MyModeID; /* corresponding ModeID in my tables (0 = identical) */ + USHORT Ext_VESAID; /* corresponding VESA ID in new ROM */ +} SiS_EModeIDTable661[] = { + { 0x6a, 0x00, 0x0102 }, + { 0x1d, 0x20, 0x0000 }, + { 0x1e, 0x21, 0x0000 }, + { 0x1f, 0x22, 0x0000 }, + { 0x20, 0x29, 0x0000 }, + { 0x21, 0x2a, 0x0000 }, + { 0x22, 0x2b, 0x0000 }, + { 0x23, 0x00, 0x011c }, + { 0x24, 0x00, 0x011d }, + { 0x25, 0x00, 0x011e }, + { 0x26, 0x00, 0x011f }, + { 0x27, 0x00, 0x0120 }, + { 0x28, 0x00, 0x0121 }, + { 0x2a, 0x14, 0x013d }, + { 0x2b, 0x15, 0x013e }, + { 0x2c, 0x16, 0x013f }, + { 0x2e, 0x00, 0x0101 }, + { 0x2f, 0x00, 0x0100 }, + { 0x30, 0x00, 0x0103 }, + { 0x37, 0x00, 0x0104 }, + { 0x38, 0x00, 0x0105 }, + { 0x3a, 0x00, 0x0107 }, + { 0x3c, 0x00, 0x0125 }, + { 0x3d, 0x00, 0x0126 }, + { 0x40, 0x00, 0x010d }, + { 0x41, 0x00, 0x010e }, + { 0x43, 0x00, 0x0110 }, + { 0x44, 0x00, 0x0111 }, + { 0x46, 0x00, 0x0113 }, + { 0x47, 0x00, 0x0114 }, + { 0x49, 0x00, 0x0116 }, + { 0x4a, 0x00, 0x0117 }, + { 0x4c, 0x00, 0x0119 }, + { 0x4d, 0x00, 0x011a }, + { 0x50, 0x00, 0x0127 }, + { 0x51, 0x00, 0x0128 }, + { 0x52, 0x00, 0x0129 }, + { 0x56, 0x00, 0x012a }, + { 0x57, 0x00, 0x012b }, + { 0x58, 0x00, 0x012c }, + { 0x59, 0x00, 0x012d }, + { 0x5a, 0x17, 0x012e }, + { 0x5b, 0x18, 0x012f }, + { 0x5c, 0x19, 0x0130 }, + { 0x5d, 0x00, 0x0131 }, + { 0x62, 0x00, 0x0112 }, + { 0x63, 0x00, 0x0115 }, + { 0x64, 0x00, 0x0118 }, + { 0x65, 0x00, 0x011b }, + { 0x66, 0x00, 0x0132 }, + { 0x75, 0x00, 0x013a }, + { 0x78, 0x00, 0x013b }, + { 0x79, 0x00, 0x013c }, + { 0x7b, 0x7c, 0x0136 }, + { 0x7c, 0x7d, 0x0137 }, + { 0x7d, 0x7e, 0x0138 }, + { 0xff, 0xff, 0xffff } +}; +#endif + +static const SiS_CRT1TableStruct SiS310_CRT1Table[]= +{ + {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, /* 0x0 */ + {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, + 0x00}}, /* 0x1 */ + {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, + 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, + 0x01}}, /* 0x2 */ + {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, + 0x01}}, /* 0x3 */ + {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, /* 0x4 */ +#if 0 + {{0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, + 0x00}}, /* 0x5 */ +#endif + {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, /* 0x05 - corrected 640x480-60 */ + 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, + 0x00}}, +#if 0 + {{0x63,0x4f,0x50,0x86,0x56,0x9b,0x06,0x3e, + 0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01, + 0x00}}, /* 0x6 */ +#endif + {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, /* 0x06 - corrected 640x480-72 */ + 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f, + 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01, + 0x00}}, /* 0x7 */ + {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f, + 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, + 0x00}}, /* 0x8 */ + {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f, + 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, /* Corrected VBE */ + 0x61}}, /* 0x9 */ + {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e, + 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05, + 0x61}}, /* 0xa */ + {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e, + 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05, /* Corrected VBE */ + 0x61}}, /* 0xb */ + {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f, + 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, /* Corrected VDE, VBE */ + 0x00}}, /* 0xc */ + {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0, + 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05, + 0x01}}, /* 0xd */ + {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06, + 0x01}}, /* 0xe */ + {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0, + 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06, + 0x01}}, /* 0xf */ + {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0, + 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06, + 0x01}}, /* 0x10 */ + {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0, + 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06, + 0x01}}, /* 0x11 */ + {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0, + 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06, + 0x61}}, /* 0x12 */ + {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0, + 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06, + 0x61}}, /* 0x13 */ + {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0, + 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06, + 0x61}}, /* 0x14 */ + {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f, + 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02, + 0x00}}, /* 0x15 */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, /* 0x16 */ + {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, /* 0x17 */ + {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5, + 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02, + 0x01}}, /* 0x18 */ + {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5, + 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02, + 0x01}}, /* 0x19 */ + {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5, + 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02, + 0x62}}, /* 0x1a */ + {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5, + 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02, + 0x62}}, /* 0x1b */ + {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba, + 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03, + 0x00}}, /* 0x1c */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a, + 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, + 0x01}}, /* 0x1d */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a, + 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, + 0x01}}, /* 0x1e */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a, + 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07, + 0x01}}, /* 0x1f */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x20 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x21 @ 4084 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x22 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x23 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x24 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x25 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x26 */ + {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, + 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, + 0x00}}, /* 0x27 */ + {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f, + 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05, + 0x63}}, /* 0x28 */ + {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f, + 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05, + 0x63}}, /* 0x29 */ + {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, + 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, + 0x00}}, /* 0x2a */ + {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, + 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, + 0x00}}, /* 0x2b */ + {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, + 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, + 0x00}}, /* 0x2c */ + {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba, + 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05, + 0x44}}, /* 0x2d */ + {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba, + 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05, + 0x44}}, /* 0x2e */ + {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba, + 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05, + 0x44}}, /* 0x2f */ + {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba, + 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05, + 0x44}}, /* 0x30 */ + {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba, + 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05, + 0x00}}, /* 0x31 */ + {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, + 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, + 0x01}}, /* 0x32 */ + {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, + 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, + 0x01}}, /* 0x33 */ + {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, + 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, + 0x01}}, /* 0x34 */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, + 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, + 0x01}}, /* 0x35 */ + {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, + 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, + 0x01}}, /* 0x36 */ + {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, /* 95 was 15 - illegal HBE! */ + 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, + 0x01}}, /* 0x37 */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x38 */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x39 */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, + 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, + 0x01}}, /* 0x3a */ +#if 0 + {{0xdc,0x9f,0x9f,0x00,0xab,0x19,0xe6,0xef, /* 1280x960 - invalid */ + 0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07, + 0x01}}, /* 0x3b */ +#endif + {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff, /* 1280x960-60 - corrected */ + 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07, + 0x01}}, /* 0x3b */ + {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e, + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, + 0x00}}, /* 0x3c */ + {{0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0, + 0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05, + 0x01}}, /* 0x3d */ + {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15, + 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02, + 0x00}}, /* 0x3e */ + {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e, + 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02, + 0x00}}, /* 0x3f */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, + 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, + 0x01}}, /* 0x40 */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, /* 0x41 */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5, + 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07, + 0x01}}, /* 0x42 */ + {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10, + 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03, + 0x00}}, /* 0x43 */ + {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, /* 1152x864-75 */ + 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07, + 0x01}}, /* 0x44 */ + {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, /* 848x480-38i */ + 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, + 0x00}}, /* 0x45 */ + {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, /* 848x480-60 */ + 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06, + 0x00}}, /* 0x46 */ + {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, /* 856x480-38i */ + 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, + 0x00}}, /* 0x47 */ + {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, /* 856x480-60 */ + 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02, + 0x00}}, /* 0x48 */ + {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, /* 1360x768-60 */ + 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03, + 0x01}}, /* 0x49 */ + {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, /* 1152x864-84 */ + 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03, + 0x01}}, /* 0x4a */ + {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, /* 1400x1050-75 */ + 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03, + 0x00}}, /* 0x4b */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, /* 1280x960-85 */ + 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07, + 0x01}}, /* 0x4c */ + {{0x7b,0x5f,0x63,0x9f,0x6a,0x93,0x6f,0xf0, /* 768x576 */ + 0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05, + 0x01}}, /* 0x4d */ + {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, /* FSTN 320x480, TEMP - possibly invalid */ + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, + 0x00}}, /* 0x4e */ + {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff, /* 1280x800-60 */ + 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07, + 0x21}}, /* 0x4f */ + {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10, /* 1680x1050-60 */ + 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c, + 0x20}}, /* 0x50 */ + {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0, /* 1920x1080-60i */ + 0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00, + 0x61}}, /* 0x51 */ + {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0, /* 960x540-60 */ + 0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02, + 0x41}}, /* 0x52 */ + {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0, /* 960x600-60 */ + 0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02, + 0x01}}, /* 0x53 */ + {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, /* 1152x864-60 */ + 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07, + 0x41}} /* 0x54 */ +}; + +static const SiS_MCLKDataStruct SiS310_MCLKData_0_315[] = +{ + { 0x3b,0x22,0x01,143}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166} +}; + +static const SiS_MCLKDataStruct SiS310_MCLKData_0_650[] = +{ + { 0x5a,0x64,0x82, 66}, + { 0xb3,0x45,0x82, 83}, + { 0x37,0x61,0x82,100}, + { 0x37,0x22,0x82,133}, + { 0x37,0x61,0x82,100}, + { 0x37,0x22,0x82,133}, + { 0x37,0x22,0x82,133}, + { 0x37,0x22,0x82,133} +}; + +static const SiS_MCLKDataStruct SiS310_MCLKData_0_330[] = +{ + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x7c,0x08,0x01,200}, + { 0x79,0x06,0x01,250}, + { 0x7c,0x08,0x01,200}, + { 0x7c,0x08,0x01,200}, + { 0x7c,0x08,0x01,200}, + { 0x79,0x06,0x01,250} +}; + +static const SiS_MCLKDataStruct SiS310_MCLKData_0_660[] = +{ + { 0x5c,0x23,0x82,166}, + { 0x5c,0x23,0x82,166}, + { 0x37,0x21,0x82,200}, + { 0x37,0x22,0x82,133}, + { 0x29,0x21,0x82,150}, + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x37,0x21,0x82,200} +}; + +static const SiS_MCLKDataStruct SiS310_MCLKData_0_760[] = +{ + { 0x37,0x22,0x82,133}, + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x7c,0x08,0x82,200}, + { 0x29,0x21,0x82,150}, + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x37,0x21,0x82,200} +}; + +static const SiS_MCLKDataStruct SiS310_MCLKData_0_761[] = +{ + { 0x37,0x22,0x82,133}, /* Preliminary */ + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x7c,0x08,0x82,200}, + { 0x29,0x21,0x82,150}, + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x37,0x21,0x82,200} +}; + +static const SiS_MCLKDataStruct SiS310_MCLKData_0_340[] = +{ + { 0x79,0x06,0x01,250}, + { 0x7c,0x08,0x01,200}, + { 0x7c,0x08,0x80,200}, + { 0x79,0x06,0x80,250}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300} +}; + +static const SiS_MCLKDataStruct SiS310_MCLKData_1[] = /* ECLK */ +{ + { 0x29,0x21,0x82,150}, + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x37,0x21,0x82,200}, + { 0x37,0x22,0x82,133}, + { 0x37,0x22,0x82,133}, + { 0x37,0x22,0x82,133}, + { 0x37,0x22,0x82,133} +}; + +static const SiS_MCLKDataStruct SiS310_MCLKData_1_340[] = +{ + { 0x7c,0x08,0x01,200}, + { 0x7c,0x08,0x01,200}, + { 0x7c,0x08,0x80,200}, + { 0x79,0x06,0x80,250}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300} +}; + +static SiS_VCLKDataStruct SiS310_VCLKData[]= +{ + { 0x1b,0xe1, 25}, /* 0x00 */ + { 0x4e,0xe4, 28}, /* 0x01 */ + { 0x57,0xe4, 31}, /* 0x02 */ + { 0xc3,0xc8, 36}, /* 0x03 */ + { 0x42,0xe2, 40}, /* 0x04 */ + { 0xfe,0xcd, 43}, /* 0x05 */ + { 0x5d,0xc4, 44}, /* 0x06 */ + { 0x52,0xe2, 49}, /* 0x07 */ + { 0x53,0xe2, 50}, /* 0x08 */ + { 0x74,0x67, 52}, /* 0x09 */ + { 0x6d,0x66, 56}, /* 0x0a */ + { 0x5a,0x64, 65}, /* 0x0b */ /* was 6c c3 - WRONG */ + { 0x46,0x44, 67}, /* 0x0c */ + { 0xb1,0x46, 68}, /* 0x0d */ + { 0xd3,0x4a, 72}, /* 0x0e */ + { 0x29,0x61, 75}, /* 0x0f */ + { 0x6e,0x46, 76}, /* 0x10 */ + { 0x2b,0x61, 78}, /* 0x11 */ + { 0x31,0x42, 79}, /* 0x12 */ + { 0xab,0x44, 83}, /* 0x13 */ + { 0x46,0x25, 84}, /* 0x14 */ + { 0x78,0x29, 86}, /* 0x15 */ + { 0x62,0x44, 94}, /* 0x16 */ + { 0x2b,0x41,104}, /* 0x17 */ + { 0x3a,0x23,105}, /* 0x18 */ + { 0x70,0x44,108}, /* 0x19 */ + { 0x3c,0x23,109}, /* 0x1a */ + { 0x5e,0x43,113}, /* 0x1b */ + { 0xbc,0x44,116}, /* 0x1c */ + { 0xe0,0x46,132}, /* 0x1d */ + { 0x54,0x42,135}, /* 0x1e */ + { 0xea,0x2a,139}, /* 0x1f */ + { 0x41,0x22,157}, /* 0x20 */ + { 0x70,0x24,162}, /* 0x21 */ + { 0x30,0x21,175}, /* 0x22 */ + { 0x4e,0x22,189}, /* 0x23 */ + { 0xde,0x26,194}, /* 0x24 */ + { 0x62,0x06,202}, /* 0x25 */ + { 0x3f,0x03,229}, /* 0x26 */ + { 0xb8,0x06,234}, /* 0x27 */ + { 0x34,0x02,253}, /* 0x28 */ + { 0x58,0x04,255}, /* 0x29 */ + { 0x24,0x01,265}, /* 0x2a */ + { 0x9b,0x02,267}, /* 0x2b */ + { 0x70,0x05,270}, /* 0x2c */ + { 0x25,0x01,272}, /* 0x2d */ + { 0x9c,0x02,277}, /* 0x2e */ + { 0x27,0x01,286}, /* 0x2f */ + { 0x3c,0x02,291}, /* 0x30 */ + { 0xef,0x0a,292}, /* 0x31 */ + { 0xf6,0x0a,310}, /* 0x32 */ + { 0x95,0x01,315}, /* 0x33 */ + { 0xf0,0x09,324}, /* 0x34 */ + { 0xfe,0x0a,331}, /* 0x35 */ + { 0xf3,0x09,332}, /* 0x36 */ + { 0xea,0x08,340}, /* 0x37 */ + { 0xe8,0x07,376}, /* 0x38 */ + { 0xde,0x06,389}, /* 0x39 */ + { 0x52,0x2a, 54}, /* 0x3a 301 TV */ + { 0x52,0x6a, 27}, /* 0x3b 301 TV */ + { 0x62,0x24, 70}, /* 0x3c 301 TV */ + { 0x62,0x64, 70}, /* 0x3d 301 TV */ + { 0xa8,0x4c, 30}, /* 0x3e 301 TV */ + { 0x20,0x26, 33}, /* 0x3f 301 TV */ + { 0x31,0xc2, 39}, /* 0x40 */ + { 0x60,0x36, 30}, /* 0x41 Chrontel */ + { 0x40,0x4a, 28}, /* 0x42 Chrontel */ + { 0x9f,0x46, 44}, /* 0x43 Chrontel */ + { 0x97,0x2c, 26}, /* 0x44 */ + { 0x44,0xe4, 25}, /* 0x45 Chrontel */ + { 0x7e,0x32, 47}, /* 0x46 Chrontel */ + { 0x8a,0x24, 31}, /* 0x47 Chrontel */ + { 0x97,0x2c, 26}, /* 0x48 Chrontel */ + { 0xce,0x3c, 39}, /* 0x49 */ + { 0x52,0x4a, 36}, /* 0x4a Chrontel */ + { 0x34,0x61, 95}, /* 0x4b */ + { 0x78,0x27,108}, /* 0x4c - was 102 */ + { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ + { 0x41,0x4e, 21}, /* 0x4e */ + { 0xa1,0x4a, 29}, /* 0x4f Chrontel */ + { 0x19,0x42, 42}, /* 0x50 */ + { 0x54,0x46, 58}, /* 0x51 Chrontel */ + { 0x25,0x42, 61}, /* 0x52 */ + { 0x44,0x44, 66}, /* 0x53 Chrontel */ + { 0x3a,0x62, 70}, /* 0x54 Chrontel */ + { 0x62,0xc6, 34}, /* 0x55 848x480-60 */ + { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */ + { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */ + { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ + { 0x52,0x07,149}, /* 0x59 1280x960-85 */ + { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ + { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */ + { 0x45,0x25, 83}, /* 0x5c 1280x800 */ + { 0x70,0x0a,147}, /* 0x5d 1680x1050 */ + { 0x70,0x24,162}, /* 0x5e 1600x1200 */ + { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */ + { 0x63,0x46, 68}, /* 0x60 1280x768_2 */ + { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */ + { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ + { 0x70,0x28, 90}, /* 0x64 1152x864@60 */ + { 0x41,0xc4, 32}, /* 0x65 848x480@60 */ + { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */ + { 0x76,0xe7, 27}, /* 0x67 720x480@60 */ + { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */ + { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ + { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */ + { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */ + { 0x45,0x25, 83}, /* 0x6c 1280x800 */ + { 0x70,0x28, 90} /* 0x6d 1152x864@60 */ +}; + +static SiS_VBVCLKDataStruct SiS310_VBVCLKData[]= +{ + { 0x1b,0xe1, 25}, /* 0x00 */ + { 0x4e,0xe4, 28}, /* 0x01 */ + { 0x57,0xe4, 31}, /* 0x02 */ + { 0xc3,0xc8, 36}, /* 0x03 */ + { 0x42,0x47, 40}, /* 0x04 */ + { 0xfe,0xcd, 43}, /* 0x05 */ + { 0x5d,0xc4, 44}, /* 0x06 */ + { 0x52,0x47, 49}, /* 0x07 */ + { 0x53,0x47, 50}, /* 0x08 */ + { 0x74,0x67, 52}, /* 0x09 */ + { 0x6d,0x66, 56}, /* 0x0a */ + { 0x35,0x62, 65}, /* 0x0b */ /* Was 0x5a,0x64 - 650/LVDS+301: 35,62 */ + { 0x46,0x44, 67}, /* 0x0c */ + { 0xb1,0x46, 68}, /* 0x0d */ + { 0xd3,0x4a, 72}, /* 0x0e */ + { 0x29,0x61, 75}, /* 0x0f */ + { 0x6d,0x46, 75}, /* 0x10 */ + { 0x41,0x43, 78}, /* 0x11 */ + { 0x31,0x42, 79}, /* 0x12 */ + { 0xab,0x44, 83}, /* 0x13 */ + { 0x46,0x25, 84}, /* 0x14 */ + { 0x78,0x29, 86}, /* 0x15 */ + { 0x62,0x44, 94}, /* 0x16 */ + { 0x2b,0x22,104}, /* 0x17 */ + { 0x49,0x24,105}, /* 0x18 */ + { 0xf8,0x2f,108}, /* 0x19 */ /* 1400x1050 LCD */ + { 0x3c,0x23,109}, /* 0x1a */ + { 0x5e,0x43,113}, /* 0x1b */ + { 0xbc,0x44,116}, /* 0x1c */ + { 0xe0,0x46,132}, /* 0x1d */ +#if 0 + { 0xd4,0x28,135}, /* 0x1e */ + { 0xea,0x2a,139}, /* 0x1f */ + { 0x41,0x22,157}, /* 0x20 */ + { 0x70,0x24,162}, /* 0x21 */ +#endif + { 0xe2,0x46,135}, /* 0x1e */ /* 1280x1024-75, better clock for VGA2 */ + { 0xe5,0x46,139}, /* 0x1f */ /* 1024x768-120, better clock for VGA2 */ + { 0x15,0x01,157}, /* 0x20 */ /* 1280x1024-85, better clock for VGA2 */ + { 0x70,0x09,162}, /* 0x21 */ /* 1600x1200-60, better clock for VGA2 */ + { 0x30,0x21,175}, /* 0x22 */ + { 0x4e,0x22,189}, /* 0x23 */ + { 0xde,0x26,194}, /* 0x24 */ + { 0x70,0x07,202}, /* 0x25 */ + { 0x3f,0x03,229}, /* 0x26 */ + { 0xb8,0x06,234}, /* 0x27 */ + { 0x34,0x02,253}, /* 0x28 */ + { 0x58,0x04,255}, /* 0x29 */ + { 0x24,0x01,265}, /* 0x2a */ + { 0x9b,0x02,267}, /* 0x2b */ + { 0x70,0x05,270}, /* 0x2c */ + { 0x25,0x01,272}, /* 0x2d */ + { 0x9c,0x02,277}, /* 0x2e */ + { 0x27,0x01,286}, /* 0x2f */ + { 0x3c,0x02,291}, /* 0x30 */ + { 0xef,0x0a,292}, /* 0x31 */ + { 0xf6,0x0a,310}, /* 0x32 */ + { 0x95,0x01,315}, /* 0x33 */ + { 0xf0,0x09,324}, /* 0x34 */ + { 0xfe,0x0a,331}, /* 0x35 */ + { 0xf3,0x09,332}, /* 0x36 */ + { 0xea,0x08,340}, /* 0x37 */ + { 0xe8,0x07,376}, /* 0x38 */ + { 0xde,0x06,389}, /* 0x39 */ + { 0x52,0x2a, 54}, /* 0x3a 301 TV - start */ + { 0x52,0x6a, 27}, /* 0x3b 301 TV */ + { 0x62,0x24, 70}, /* 0x3c 301 TV */ + { 0x62,0x64, 70}, /* 0x3d 301 TV */ + { 0xa8,0x4c, 30}, /* 0x3e 301 TV */ + { 0x20,0x26, 33}, /* 0x3f 301 TV */ + { 0x31,0xc2, 39}, /* 0x40 */ + { 0x2e,0x48, 25}, /* 0x41 Replacement for LCD on 315 for index 0 */ + { 0x24,0x46, 25}, /* 0x42 Replacement for LCD on 315 for modes 0x01, 0x03, 0x0f, 0x10, 0x12 */ + { 0x26,0x64, 28}, /* 0x43 Replacement for LCD on 315 for index 1 */ + { 0x37,0x64, 40}, /* 0x44 Replacement for LCD on 315 for index 4 */ + { 0xa1,0x42,108}, /* 0x45 1280x960 LCD */ + { 0x37,0x61,100}, /* 0x46 1280x960 LCD */ + { 0x78,0x27,108}, /* 0x47 */ + { 0x97,0x2c, 26}, /* 0x48 UNUSED */ + { 0xce,0x3c, 39}, /* 0x49 UNUSED */ + { 0x52,0x4a, 36}, /* 0x4a UNUSED */ + { 0x34,0x61, 95}, /* 0x4b UNUSED */ + { 0x78,0x27,108}, /* 0x4c UNUSED */ + { 0x66,0x43,123}, /* 0x4d 1400x1050-60 */ + { 0x41,0x4e, 21}, /* 0x4e UNUSED */ + { 0xa1,0x4a, 29}, /* 0x4f UNUSED */ + { 0x19,0x42, 42}, /* 0x50 UNUSED */ + { 0x54,0x46, 58}, /* 0x51 UNUSED */ + { 0x25,0x42, 61}, /* 0x52 UNUSED */ + { 0x44,0x44, 66}, /* 0x53 UNUSED */ + { 0x3a,0x62, 70}, /* 0x54 UNUSED */ + { 0x62,0xc6, 34}, /* 0x55 848x480-60 */ + { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP, UNUSED */ + { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */ + { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) TEMP, UNUSED */ + { 0x52,0x07,149}, /* 0x59 1280x960-85 */ + { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ + { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD (TMDS) */ + { 0xce,0x1e, 73}, /* 0x5c 1280x800_2 LCD (SiS LVDS) - (CRT1: 45 25 83) */ + { 0xbe,0x44,121}, /* 0x5d 1680x1050 LCD */ + { 0x70,0x24,162}, /* 0x5e 1600x1200 LCD */ + { 0x52,0x27, 75}, /* 0x5f 1280x720 (TMDS + HDTV) (correct) */ + { 0xc8,0x48, 77}, /* 0x60 1280x768_2 (SiS LVDS) */ + { 0x31,0x42, 79}, /* 0x61 1280x768_3 (SiS LVDS) - temp */ + { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + { 0x9c,0x62, 69}, /* 0x63 1280x720 (SiS LVDS) */ + { 0x70,0x28, 90}, /* 0x64 1152x864@60 */ + { 0x41,0xc4, 32}, /* 0x65 848x480@60 */ + { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */ + { 0x76,0xe7, 27}, /* 0x67 720x480@60 */ + { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */ + { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced (UNUSED) */ + { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */ + { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */ + { 0x9c,0x62, 69}, /* 0x6c 1280x800 (SiS TMDS) (special) */ + { 0x70,0x28, 90} /* 0x6d 1152x864@60 */ +}; + +static const DRAM4Type SiS310_SR15[8] = { + {0x00,0x04,0x60,0x60}, + {0x0f,0x0f,0x0f,0x0f}, + {0xba,0xba,0xba,0xba}, + {0xa9,0xa9,0xac,0xac}, + {0xa0,0xa0,0xa0,0xa8}, + {0x00,0x00,0x02,0x02}, + {0x30,0x30,0x40,0x40}, + {0x00,0xa5,0xfb,0xf6} +}; + +#ifdef LINUX_KERNEL + +static UCHAR SiS310_SR07 = 0x18; + +static const DRAM4Type SiS310_CR40[5] = { + {0x77,0x77,0x33,0x33}, + {0x77,0x77,0x33,0x33}, + {0x00,0x00,0x00,0x00}, + {0x5b,0x5b,0x03,0x03}, + {0x00,0x00,0xf0,0xf8} +}; + +static UCHAR SiS310_CR49[] = {0xaa,0x88}; +static UCHAR SiS310_SR1F = 0x00; +static UCHAR SiS310_SR21 = 0xa5; +static UCHAR SiS310_SR22 = 0xfb; +static UCHAR SiS310_SR23 = 0xf6; +static UCHAR SiS310_SR24 = 0x0d; +static UCHAR SiS310_SR25[] = {0x33,0x3}; +static UCHAR SiS310_SR31 = 0x00; +static UCHAR SiS310_SR32 = 0x11; +static UCHAR SiS310_SR33 = 0x00; +static UCHAR SiS310_CRT2Data_1_2 = 0x00; +static UCHAR SiS310_CRT2Data_4_D = 0x00; +static UCHAR SiS310_CRT2Data_4_E = 0x00; +static UCHAR SiS310_CRT2Data_4_10 = 0x80; +static const USHORT SiS310_RGBSenseData = 0xd1; +static const USHORT SiS310_VideoSenseData = 0xb9; +static const USHORT SiS310_YCSenseData = 0xb3; +static const USHORT SiS310_RGBSenseData2 = 0x0190; +static const USHORT SiS310_VideoSenseData2 = 0x0174; +static const USHORT SiS310_YCSenseData2 = 0x016b; +#endif + +static const SiS_PanelDelayTblStruct SiS310_PanelDelayTbl[]= +{ + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}} +}; + +static const SiS_PanelDelayTblStruct SiS310_PanelDelayTblLVDS[]= +{ + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}} +}; + +/**************************************************************/ +/* SIS VIDEO BRIDGE ----------------------------------------- */ +/**************************************************************/ + +static const SiS_LCDDataStruct SiS310_St2LCD1024x768Data[] = +{ + { 62, 25, 800, 546,1344, 806}, + { 32, 15, 930, 546,1344, 806}, + { 62, 25, 800, 546,1344, 806}, + { 104, 45, 945, 496,1344, 806}, + { 62, 25, 800, 546,1344, 806}, + { 31, 18,1008, 624,1344, 806}, + { 1, 1,1344, 806,1344, 806} +}; + +static const SiS_LCDDataStruct SiS310_ExtLCD1024x768Data[] = +{ + { 42, 25,1536, 419,1344, 806}, + { 48, 25,1536, 369,1344, 806}, + { 42, 25,1536, 419,1344, 806}, + { 48, 25,1536, 369,1344, 806}, + { 12, 5, 896, 500,1344, 806}, + { 42, 25,1024, 625,1344, 806}, + { 1, 1,1344, 806,1344, 806} +}; + +static const SiS_LCDDataStruct SiS310_St2LCD1280x1024Data[] = +{ + { 22, 5, 800, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 176, 45, 900, 510,1650,1088}, + { 176, 45, 900, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 13, 5,1024, 675,1560,1152}, + { 16, 9,1266, 804,1688,1072}, + { 1, 1,1688,1066,1688,1066} +}; + +static const SiS_LCDDataStruct SiS310_ExtLCD1280x1024Data[] = +{ + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 211, 60,1024, 500,1688,1066}, + { 211, 75,1024, 625,1688,1066}, + { 211, 120,1280, 798,1688,1066}, + { 1, 1,1688,1066,1688,1066} +}; + +static const SiS_Part2PortTblStruct SiS310_CRT2Part2_1024x768_1[] = +{ + {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x38,0x13,0x16,0x0c,0xe6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}} +}; + +/* *** LCDA *** */ + +#if 0 +static const SiS_LVDSDataStruct SiS_LCDA1600x1200Data_1[]= +{ /* Clevo, 651+301C */ + {1200, 450, 2048,1250}, + {1200, 400, 2048,1250}, + {1280, 450, 2048,1250}, + {1280, 400, 2048,1250}, + {1200, 530, 2048,1250}, + {1360, 650, 2048,1250}, + {1584, 818, 2048,1250}, + {1688,1066, 2048,1250}, + {1688,1066, 2048,1250}, +#if 0 + {2048,1250, 2048,1250} /* this should be correct */ +#endif +#if 1 + {2160,1250, 2048,1250} /* ? */ +#endif +}; +#endif + +/**************************************************************/ +/* LVDS, CHRONTEL ------------------------------------------- */ +/**************************************************************/ + +static const SiS_LVDSDataStruct SiS310_CHTVUPALData[]= +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 625, 840, 625}, + { 960, 750, 960, 750}, + {1400,1000,1400,1000} +}; + +static const SiS_LVDSDataStruct SiS310_CHTVOPALData[]= +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 625, 840, 625}, + { 944, 625, 944, 625}, + {1400, 875,1400, 875} +}; + +static const SiS_LVDSDataStruct SiS310_CHTVUPALMData[]= +{ + { 840, 600, 840, 600}, + { 840, 600, 840, 600}, + { 840, 600, 840, 600}, + { 840, 600, 840, 600}, + { 784, 600, 784, 600}, + {1064, 750,1064, 750}, + {1160, 945,1160, 945} +}; + +static const SiS_LVDSDataStruct SiS310_CHTVOPALMData[]= +{ + { 840, 525, 840, 525}, + { 840, 525, 840, 525}, + { 840, 525, 840, 525}, + { 840, 525, 840, 525}, + { 784, 525, 784, 525}, + {1040, 700,1040, 700}, + {1160, 840,1160, 840} +}; + +static const SiS_LVDSDataStruct SiS310_CHTVUPALNData[]= +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 625, 840, 625}, + { 960, 750, 960, 750}, + {1400,1000,1400,1000} +}; + +static const SiS_LVDSDataStruct SiS310_CHTVOPALNData[]= +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 625, 840, 625}, + { 944, 625, 944, 625}, + {1400, 875,1400, 875} +}; + +static const SiS_LVDSDataStruct SiS310_CHTVSOPALData[]= /* (super overscan - no effect on 7019) */ +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 625, 840, 625}, + { 944, 625, 944, 625}, + {1400, 875,1400, 875} +}; + + +static const SiS_LVDSDesStruct SiS310_PanelType00_1[]= /* 800x600 */ +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType01_1[]= /* 1024x768 */ +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 805}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType02_1[]= /* 1280x1024 */ +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 1065}, + { 0, 0}, + { 0, 0} +}; + + +static const SiS_LVDSDesStruct SiS310_PanelType03_1[]= +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType04_1[]= +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType05_1[]= +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType06_1[]= +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType07_1[]= +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType08_1[]= /* 1400x1050 */ +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType09_1[]= /* 1280x768 */ +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType0a_1[]= /* 1600x1200 */ +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType0b_1[]= /* 640x480_2 */ +{ + { 0, 524}, + { 0, 524}, + { 0, 524}, + { 0, 524}, + { 0, 524}, + { 0, 524}, + { 8, 524}, + { 0, 524} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType0c_1[]= /* 640x480_3 */ +{ + { 0, 524}, + { 0, 524}, + { 0, 524}, + { 0, 524}, + { 0, 524}, + { 0, 524}, + { 8, 524}, + { 0, 524} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType0d_1[]= +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType0e_1[]= +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType0f_1[]= +{ + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType00_2[]= +{ + {980, 528}, + {980, 503}, + {980, 528}, + {980, 503}, + {980, 568}, + { 0, 628}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType01_2[]= +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 806}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType02_2[]= +{ + {1368, 754}, + {1368, 729}, + {1368, 754}, + {1368, 729}, + {1368, 794}, + {1448, 854}, + {1560, 938}, + { 0,1066}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType03_2[]= +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType04_2[]= +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType05_2[]= +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType06_2[]= +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType07_2[]= +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType08_2[]= /* 1400x1050 */ +{ + {1308, 741}, + {1308, 716}, + {1308, 741}, + {1308, 716}, + {1308, 781}, + {1388, 841}, + {1500, 925}, + {1628,1053}, + { 0,1065}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType09_2[]= /* 1280x768 */ +{ + {1083, 622}, + {1083, 597}, + {1083, 622}, + {1083, 597}, + {1083, 662}, + {1163, 722}, + {1286, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType0a_2[]= /* 1600x1200 */ +{ + {1568, 920}, + {1568, 895}, + {1568, 920}, + {1568, 895}, + {1568, 960}, + {1648,1020}, + {1760,1104}, + {1888,1232}, + {1948,1245}, + { 0, 0} +#if 0 + {1568, 850}, + {1568, 825}, + {1568, 850}, + {1568, 825}, + {1568, 890}, + {1648, 950}, + {1760,1034}, + {1888,1162}, + {1948,1175}, + { 0, 0} +#endif +}; + +static const SiS_LVDSDesStruct SiS310_PanelType0b_2[]= /* 640x480_2 */ +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType0c_2[]= /* 640x480_3 */ +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType0d_2[]= +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType0e_2[]= +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelType0f_2[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + { 0, 794}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelTypeNS_1[]= +{ + { 8, 0}, + { 8, 0}, + { 8, 0}, + { 8, 0}, + { 8, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 806}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS310_PanelTypeNS_2[] = +{ + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0} +}; + +/* CRT1 CRTC for SlaveModes and LCDA */ + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1[] = +{ + {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, + 0x00 }}, + {{0x6b,0x4f,0x8f,0x55,0x85,0x78,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00 }}, + {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, + 0x00 }}, + {{0x6b,0x4f,0x8f,0x55,0x85,0x78,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00 }}, + {{0x6b,0x4f,0x8f,0x55,0x85,0xfa,0x1f, + 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, + 0x00 }}, + {{0x7f,0x63,0x83,0x69,0x19,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1_H[] = +{ + {{0x43,0x27,0x87,0x2d,0x1d,0xaa,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, + 0x00 }}, + {{0x43,0x27,0x87,0x2d,0x1d,0x78,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00 }}, + {{0x43,0x27,0x87,0x2d,0x1d,0xfa,0x1f, + 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, + 0x00 }}, + {{0x43,0x27,0x87,0x2d,0x1d,0x78,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00 }}, + {{0x43,0x27,0x87,0x2d,0x1d,0xfa,0x1f, + 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, + 0x00 }}, + {{0x4d,0x31,0x91,0x37,0x07,0x72,0xf0, + 0x58,0x8d,0x57,0x73,0x20,0x00,0x01, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2[]= +{ + {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, + 0xff,0x84,0x8f,0x73,0x00,0x00,0x06, + 0x00 }}, + {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, + 0xe6,0x8b,0x5d,0x73,0x00,0x00,0x06, + 0x00 }}, + {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, + 0xff,0x84,0x8f,0x73,0x00,0x00,0x06, + 0x00 }}, + {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, + 0xe6,0x8b,0x5d,0x73,0x00,0x00,0x06, + 0x00 }}, + {{0x7f,0x4f,0x83,0x62,0x12,0x72,0xba, + 0x27,0x8c,0xdf,0x73,0x00,0x00,0x06, + 0x00 }}, + {{0x7f,0x63,0x83,0x69,0x19,0x72,0xf0, + 0x58,0x8d,0x57,0x73,0x20,0x00,0x06, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2_H[] = +{ + {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e, + 0xff,0x84,0x8f,0x73,0x00,0x00,0x01, + 0x00 }}, + {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e, + 0xd6,0x8b,0x5d,0x73,0x00,0x00,0x01, + 0x00 }}, + {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e, + 0xff,0x84,0x8f,0x73,0x00,0x00,0x01, + 0x00 }}, + {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e, + 0xd6,0x8b,0x5d,0x73,0x00,0x00,0x01, + 0x00 }}, + {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0xba, + 0x27,0x8c,0xdf,0x73,0x00,0x00,0x01, + 0x00 }}, + {{0x4d,0x31,0x91,0x3a,0x0a,0x72,0xf0, + 0x63,0x88,0x57,0x73,0x00,0x00,0x01, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1[] = +{ + {{0x73,0x4f,0x97,0x53,0x84,0xb4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x05, + 0x00}}, + {{0x73,0x4f,0x97,0x53,0x84,0x82,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x05, + 0x00}}, + {{0x73,0x4f,0x97,0x53,0x84,0xb4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x05, + 0x00}}, + {{0x73,0x4f,0x97,0x53,0x84,0x82,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x05, + 0x00}}, + {{0x73,0x4f,0x97,0x53,0x84,0x04,0x3e, + 0xE2,0x89,0xDf,0x05,0x00,0x00,0x05, + 0x00}}, + {{0x87,0x63,0x8B,0x67,0x18,0x7c,0xf0, + 0x5A,0x81,0x57,0x7D,0x00,0x00,0x06, + 0x01}}, + {{0xA3,0x7f,0x87,0x83,0x94,0x24,0xf5, + 0x02,0x89,0xFf,0x25,0x10,0x00,0x02, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1_H[] = +{ + {{0x4b,0x27,0x8f,0x2b,0x1c,0xb4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x05, + 0x00 }}, + {{0x4b,0x27,0x8f,0x2b,0x1c,0x82,0x1f, + 0x60,0x87,0x5D,0x83,0x01,0x00,0x05, + 0x00}}, + {{0x4b,0x27,0x8f,0x2b,0x1c,0xb4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x05, + 0x00}}, + {{0x4b,0x27,0x8f,0x2b,0x1c,0x82,0x1f, + 0x60,0x87,0x5D,0x83,0x01,0x00,0x05, + 0x00}}, + {{0x4b,0x27,0x8f,0x2b,0x1c,0x04,0x3e, + 0xE2,0x89,0xDf,0x05,0x00,0x00,0x05, + 0x00}}, + {{0x55,0x31,0x99,0x35,0x06,0x7c,0xf0, + 0x5A,0x81,0x57,0x7D,0x00,0x00,0x01, + 0x01}}, + {{0x63,0x3F,0x87,0x43,0x94,0x24,0xf5, + 0x02,0x89,0xFf,0x25,0x10,0x00,0x01, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2[] = +{ + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x57,0x8e,0x8f,0x25,0x30,0x00,0x06, + 0x00 }}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x3e,0x85,0x5d,0x25,0x10,0x00,0x06, + 0x00 }}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x57,0x8e,0x8f,0x25,0x30,0x00,0x06, + 0x00 }}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x3e,0x85,0x5d,0x25,0x10,0x00,0x06, + 0x01 }}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x7f,0x86,0xdf,0x25,0x10,0x00,0x06, + 0x00 }}, + {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1, + 0xbb,0x82,0x57,0x25,0x10,0x00,0x02, + 0x01 }}, + {{0xa3,0x7f,0x87,0x83,0x94,0x24,0xf5, + 0x02,0x89,0xff,0x25,0x10,0x00,0x02, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2_H[] = +{ + {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb, + 0x57,0x8e,0x8f,0x25,0x30,0x00,0x01, + 0x00 }}, + {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb, + 0x3e,0x85,0x5d,0x25,0x10,0x00,0x01, + 0x00 }}, + {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb, + 0x57,0x8e,0x8f,0x25,0x30,0x00,0x01, + 0x00 }}, + {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb, + 0x3e,0x85,0x5d,0x25,0x10,0x00,0x01, + 0x00 }}, + {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb, + 0x7f,0x86,0xdf,0x25,0x10,0x00,0x01, + 0x00 }}, + {{0x71,0x31,0x95,0x46,0x97,0x24,0xf1, + 0xbb,0x82,0x57,0x25,0x10,0x00,0x01, + 0x01 }}, + {{0x63,0x3f,0x87,0x46,0x97,0x24,0xf5, + 0x0f,0x86,0xff,0x25,0x30,0x00,0x01, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1[] = +{ + {{0x7e,0x4f,0x82,0x58,0x04,0xb8,0x1f, + 0x90,0x84,0x8f,0xb9,0x30,0x00,0x06, + 0x00}}, + {{0x7e,0x4f,0x82,0x58,0x04,0x86,0x1f, + 0x5e,0x82,0x5d,0x87,0x10,0x00,0x06, + 0x00}}, + {{0x7e,0x4f,0x82,0x58,0x04,0xb8,0x1f, + 0x90,0x84,0x8f,0xb9,0x30,0x00,0x06, + 0x00}}, + {{0x7e,0x4f,0x82,0x58,0x04,0x86,0x1f, + 0x5e,0x82,0x5d,0x87,0x10,0x00,0x06, + 0x00}}, + {{0x7e,0x4f,0x82,0x58,0x04,0x08,0x3e, + 0xe0,0x84,0xdf,0x09,0x00,0x00,0x06, + 0x00}}, + {{0x92,0x63,0x96,0x6c,0x18,0x80,0xf0, + 0x58,0x8c,0x57,0x81,0x20,0x00,0x06, + 0x01}}, + {{0xae,0x7f,0x92,0x88,0x94,0x28,0xf5, + 0x00,0x84,0xff,0x29,0x10,0x00,0x02, + 0x01}}, + {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a, + 0x00,0x84,0xff,0x29,0x09,0x00,0x07, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1_H[] = +{ + {{0x56,0x27,0x9a,0x31,0x1c,0xb8,0x1f, + 0x90,0x84,0x8f,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x56,0x27,0x9a,0x31,0x1c,0x86,0x1f, + 0x5e,0x82,0x5d,0x87,0x10,0x00,0x05, + 0x00}}, + {{0x56,0x27,0x9a,0x31,0x1c,0xb8,0x1f, + 0x90,0x84,0x8f,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x56,0x27,0x9a,0x31,0x1c,0x86,0x1f, + 0x5e,0x82,0x5d,0x87,0x10,0x00,0x05, + 0x01}}, + {{0x56,0x27,0x9a,0x31,0x1c,0x08,0x3e, + 0xe0,0x84,0xdf,0x09,0x00,0x00,0x05, + 0x00}}, + {{0x60,0x31,0x84,0x3a,0x86,0x80,0xf0, + 0x58,0x8c,0x57,0x81,0x20,0x00,0x01, + 0x01}}, + {{0x6e,0x3f,0x92,0x48,0x94,0x28,0xf5, + 0x00,0x84,0xff,0x29,0x10,0x00,0x01, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2[] = +{ + {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92, + 0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x02, + 0x01}}, + {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92, + 0xaf,0x83,0x44,0x43,0x21,0x00,0x02, + 0x01}}, + {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92, + 0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x02, + 0x01}}, + {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92, + 0xaf,0x83,0x44,0x43,0x21,0x00,0x02, + 0x01}}, + {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92, + 0xf0,0x84,0x85,0x84,0x11,0x00,0x02, + 0x01}}, + {{0xce,0x63,0x92,0x8b,0x19,0x28,0xd4, + 0x3f,0x83,0x57,0x29,0x01,0x00,0x03, + 0x01}}, + {{0xce,0x7f,0x92,0x99,0x07,0x28,0xd4, + 0x93,0x87,0xff,0x29,0x21,0x00,0x07, + 0x01}}, + {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a, + 0x00,0x84,0xff,0x29,0x09,0x00,0x07, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2_H[] = +{ + {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92, + 0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x06, + 0x01}}, + {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92, + 0xaf,0x83,0x44,0x43,0x21,0x00,0x06, + 0x01}}, + {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92, + 0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x06, + 0x01}}, + {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92, + 0xfa,0x83,0x44,0x43,0x31,0x00,0x06, + 0x01}}, + {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92, + 0xf0,0x84,0x85,0x84,0x11,0x00,0x06, + 0x01}}, + {{0x9c,0x31,0x80,0x59,0x87,0x28,0xd4, + 0x3f,0x83,0x57,0x29,0x01,0x00,0x06, + 0x01}}, + {{0x8e,0x3f,0x92,0x59,0x07,0x28,0xd4, + 0x93,0x87,0xff,0x29,0x21,0x00,0x06, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_1[] = +{ + {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f, + 0x8f,0x81,0x8f,0x9f,0x30,0x00,0x05, + 0x00}}, + {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f, + 0x5e,0x81,0x5d,0x6d,0x10,0x00,0x05, + 0x00}}, + {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f, + 0x90,0x83,0x8f,0x9f,0x30,0x00,0x05, + 0x00}}, + {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f, + 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, + 0x00}}, + {{0x6f,0x4f,0x93,0x54,0x82,0xee,0x1f, + 0xdf,0x82,0xdf,0xef,0x10,0x00,0x05, + 0x00}}, + {{0x83,0x63,0x87,0x68,0x16,0x66,0xf0, + 0x57,0x8e,0x57,0x67,0x20,0x00,0x06, + 0x01}}, + {{0x9f,0x7f,0x83,0x84,0x92,0x0e,0xf1, + 0xff,0x86,0xff,0x0f,0x10,0x00,0x02, + 0x01,}}, + {{0xbf,0x9f,0x83,0xa4,0x12,0x0e,0xde, + 0xff,0x86,0xff,0x0f,0x01,0x00,0x07, + 0x01}}, + {{0xce,0xae,0x92,0xb3,0x01,0x28,0x10, + 0x19,0x80,0x19,0x29,0x0f,0x00,0x03, + 0x00}} +#if 0 + {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f, + 0x93,0x86,0x8f,0x9f,0x30,0x00,0x05, + 0x00}}, + {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f, + 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, + 0x00}}, + {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f, + 0x93,0x86,0x8f,0x9f,0x30,0x00,0x05, + 0x00}}, + {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f, + 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, + 0x00}}, + {{0x6f,0x4f,0x93,0x54,0x82,0xee,0x1f, + 0xe2,0x86,0xdf,0xef,0x10,0x00,0x05, + 0x00}}, + {{0x83,0x63,0x87,0x68,0x16,0x66,0xf0, + 0x5a,0x8e,0x57,0x67,0x20,0x00,0x06, + 0x01}}, + {{0x9f,0x7f,0x83,0x84,0x92,0x0e,0xf5, + 0x02,0x86,0xff,0x0f,0x10,0x00,0x02, + 0x01}}, + {{0xbf,0x9f,0x83,0xa4,0x12,0x0e,0x5a, + 0x02,0x86,0xff,0x0f,0x09,0x00,0x07, + 0x01}}, + {{0xce,0xae,0x92,0xb3,0x01,0x28,0x10, + 0x1a,0x80,0x19,0x29,0x0f,0x00,0x03, + 0x00}} +#endif +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_1_H[] = +{ + {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f, + 0x8f,0x81,0x8f,0x9f,0x30,0x00,0x05, + 0x00}}, + {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, + 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, + 0x00}}, + {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f, + 0x90,0x83,0x8f,0x9f,0x30,0x00,0x05, + 0x00}}, + {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, + 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, + 0x00}}, + {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f, + 0xdf,0x86,0xdf,0xef,0x10,0x00,0x05, + 0x00}}, + {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0, + 0x57,0x8e,0x57,0x67,0x20,0x00,0x01, + 0x01}}, + {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf1, + 0xff,0x86,0xff,0x0f,0x10,0x00,0x01, + 0x01}}, + {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a, + 0x02,0x86,0xff,0x0f,0x09,0x00,0x05, + 0x01}}, + {{0x76,0x56,0x9a,0x5b,0x89,0x28,0x10, + 0x1c,0x80,0x19,0x29,0x0b,0x00,0x05, + 0x00}} +#if 0 + {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f, + 0x93,0x86,0x8f,0x9f,0x30,0x00,0x05, + 0x00}}, + {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, + 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, + 0x00}}, + {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f, + 0x92,0x86,0x8f,0x9f,0x30,0x00,0x05, + 0x00}}, + {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, + 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, + 0x00}}, + {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f, + 0xe2,0x86,0xdf,0xef,0x10,0x00,0x05, + 0x00}}, + {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0, + 0x5a,0x8e,0x57,0x67,0x20,0x00,0x01, + 0x01}}, + {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf5, + 0x02,0x86,0xff,0x0f,0x10,0x00,0x01, + 0x01}}, + {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a, + 0x02,0x86,0xff,0x0f,0x09,0x00,0x05, + 0x01}}, + {{0x76,0x56,0x9a,0x5b,0x89,0x28,0x10, + 0x1c,0x80,0x19,0x29,0x0b,0x00,0x05, + 0x00}} +#endif +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_2[] = +{ + {{0xce,0x72,0x91,0x84,0x92,0x28,0x92, + 0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x02, + 0x01}}, + {{0xce,0x72,0x91,0x84,0x92,0x28,0x92, + 0xbe,0x82,0x44,0x43,0x01,0x00,0x02, + 0x01}}, + {{0xce,0x72,0x91,0x84,0x92,0x28,0x92, + 0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x02, + 0x01}}, + {{0xce,0x72,0x91,0x84,0x92,0x28,0x92, + 0xbe,0x82,0x44,0x43,0x01,0x00,0x02, + 0x01}}, + {{0xce,0x72,0x91,0x84,0x92,0x28,0x92, + 0xff,0x83,0x85,0x84,0x11,0x00,0x02, + 0x01}}, + {{0xce,0x63,0x92,0x8e,0x1c,0x28,0xd4, + 0x3f,0x83,0x57,0x29,0x01,0x00,0x03, + 0x01}}, + {{0xce,0x7f,0x92,0x9c,0x0a,0x28,0xd4, + 0x93,0x87,0xff,0x29,0x21,0x00,0x07, + 0x01}}, + {{0xce,0x9f,0x92,0xac,0x1a,0x28,0x5a, + 0x13,0x87,0xff,0x29,0x29,0x00,0x07, + 0x01}}, + {{0xce,0xae,0x92,0xbc,0x0a,0x28,0x10, + 0x20,0x84,0x19,0x29,0x0f,0x00,0x03, + 0x00}} +#if 0 + {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a, + 0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03, + 0x00}}, + {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a, + 0xc2,0x86,0x5d,0x29,0x01,0x00,0x03, + 0x01}}, + {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a, + 0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03, + 0x00}}, + {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a, + 0xc2,0x86,0x5d,0x29,0x01,0x00,0x03, + 0x00}}, + {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9e, + 0x03,0x87,0xdf,0x29,0x01,0x00,0x03, + 0x00}}, + {{0xce,0x63,0x92,0x96,0x04,0x28,0xd4, + 0x3f,0x83,0x57,0x29,0x01,0x00,0x07, + 0x01}}, + {{0xce,0x7f,0x92,0xa4,0x12,0x28,0xd4, + 0x93,0x87,0xff,0x29,0x21,0x00,0x07, + 0x01}}, + {{0xce,0x9f,0x92,0xb4,0x02,0x28,0x5a, + 0x13,0x87,0xff,0x29,0x29,0x00,0x03, + 0x01}}, + {{0xce,0xae,0x92,0xbc,0x0a,0x28,0x10, + 0x20,0x84,0x19,0x29,0x0f,0x00,0x03, + 0x00}} +#endif +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_2_H[] = +{ + {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92, + 0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x06, + 0x01}}, + {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92, + 0xbe,0x82,0x44,0x43,0x01,0x00,0x06, + 0x01}}, + {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92, + 0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x06, + 0x01}}, + {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92, + 0xbe,0x82,0x44,0x43,0x01,0x00,0x06, + 0x01}}, + {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92, + 0xff,0x83,0x85,0x84,0x11,0x00,0x06, + 0x01}}, + {{0x9c,0x31,0x80,0x5c,0x8a,0x28,0xd4, + 0x3f,0x83,0x57,0x29,0x01,0x00,0x06, + 0x01}}, + {{0x8e,0x3f,0x92,0x5c,0x0a,0x28,0xd4, + 0x93,0x87,0xff,0x29,0x21,0x00,0x06, + 0x01}}, + {{0x7e,0x4f,0x82,0x5c,0x0a,0x28,0x5a, + 0x13,0x87,0xff,0x29,0x29,0x00,0x06, + 0x01}}, + {{0x76,0x56,0x9a,0x64,0x92,0x28,0x10, + 0x20,0x84,0x19,0x29,0x0f,0x00,0x05, + 0x00}} +#if 0 + {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a, + 0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06, + 0x00}}, + {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a, + 0xc2,0x86,0x5d,0x29,0x01,0x00,0x06, + 0x00}}, + {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a, + 0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06, + 0x00}}, + {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a, + 0xc2,0x86,0x5d,0x29,0x01,0x00,0x06, + 0x00}}, + {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9e, + 0x03,0x87,0xdf,0x29,0x01,0x00,0x06, + 0x00}}, + {{0x9c,0x31,0x80,0x64,0x92,0x28,0xd4, + 0x3f,0x83,0x57,0x29,0x01,0x00,0x06, + 0x01}}, + {{0x8e,0x3f,0x92,0x64,0x12,0x28,0xd4, + 0x93,0x87,0xff,0x29,0x21,0x00,0x06, + 0x01}}, + {{0x7e,0x4f,0x82,0x64,0x12,0x28,0x5a, + 0x13,0x87,0xff,0x29,0x29,0x00,0x06, + 0x01}}, + {{0x76,0x56,0x9a,0x64,0x92,0x28,0x10, + 0x20,0x84,0x19,0x29,0x0f,0x00,0x05, + 0x00}} +#endif +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_1[] = +{ + {{0x83,0x4F,0x87,0x5B,0x13,0x06,0x3E, + 0xB3,0x86,0x8F,0x07,0x20,0x00,0x06, + 0x00}}, + {{0x83,0x4F,0x87,0x5B,0x13,0xD4,0x1F, + 0x81,0x84,0x5D,0xD5,0x10,0x00,0x06, + 0x00}}, + {{0x83,0x4F,0x87,0x5B,0x13,0x06,0x3E, + 0xB3,0x86,0x8F,0x07,0x20,0x00,0x06, + 0x00}}, + {{0x83,0x4F,0x87,0x5B,0x13,0xD4,0x1F, + 0x81,0x84,0x5D,0xD5,0x10,0x00,0x06, + 0x00}}, + {{0x83,0x4F,0x87,0x5B,0x13,0x56,0xBA, + 0x03,0x86,0xDF,0x57,0x00,0x00,0x06, + 0x00}}, + {{0x97,0x63,0x9B,0x6F,0x07,0xCE,0xF0, + 0x7B,0x8E,0x57,0xCF,0x20,0x00,0x02, + 0x01}}, + {{0xB3,0x7F,0x97,0x8B,0x83,0x76,0xF5, + 0x23,0x86,0xFF,0x77,0x10,0x00,0x06, + 0x01}}, + {{0xD3,0x9F,0x97,0xAB,0x03,0x76,0x5A, + 0x23,0x86,0xFF,0x77,0x09,0x00,0x03, + 0x01}}, + {{0xE2,0xAE,0x86,0xBA,0x92,0x90,0x10, + 0x3D,0x80,0x19,0x91,0x0F,0x00,0x03, + 0x00}}, + {{0xFB,0xC7,0x9F,0xD3,0x8B,0x26,0x11, + 0xD3,0x86,0xAF,0x27,0x3F,0x00,0x07, + 0x00}} +#if 0 + {{0x83,0x4f,0x87,0x51,0x09,0xc0,0x1f, + 0x90,0x84,0x8f,0xc1,0x30,0x00,0x06, + 0x00}}, + {{0x83,0x4f,0x87,0x51,0x09,0x8e,0x1f, + 0x5e,0x82,0x5d,0x8f,0x10,0x00,0x06, + 0x00}}, + {{0x83,0x4f,0x87,0x51,0x09,0xc0,0x1f, + 0x90,0x84,0x8f,0xc1,0x30,0x00,0x06, + 0x00}}, + {{0x83,0x4f,0x87,0x51,0x09,0x8e,0x1f, + 0x5e,0x82,0x5d,0x8f,0x10,0x00,0x06, + 0x00}}, + {{0x83,0x4f,0x87,0x51,0x09,0x10,0x3e, + 0xe0,0x84,0xdf,0x11,0x00,0x00,0x06, + 0x00}}, + {{0x97,0x63,0x9b,0x65,0x1d,0x88,0xf0, + 0x58,0x8c,0x57,0x89,0x20,0x00,0x06, + 0x01}}, + {{0xb3,0x7f,0x97,0x81,0x99,0x30,0xf5, + 0x00,0x84,0xff,0x31,0x10,0x00,0x02, + 0x01}}, + {{0xd3,0x9f,0x97,0xa1,0x19,0x30,0x5a, + 0x00,0x84,0xff,0x31,0x09,0x00,0x07, + 0x01}}, + {{0xe2,0xae,0x86,0xb0,0x88,0x4a,0x10, + 0x1a,0x8e,0x19,0x4b,0x2f,0x00,0x03, + 0x00}}, + {{0xfb,0xc7,0x9f,0xc9,0x81,0xe0,0x10, + 0xb0,0x84,0xaf,0xe1,0x2f,0x00,0x07, + 0x00}} +#endif +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_1_H[] = +{ + {{0x5B,0x27,0x9F,0x33,0x0B,0x06,0x2E, + 0xB3,0x86,0x8F,0x07,0x20,0x00,0x01, + 0x00}}, + {{0x5B,0x27,0x9F,0x29,0x01,0x8E,0x1F, + 0x81,0x84,0x5D,0xD5,0x10,0x00,0x06, + 0x00}}, + {{0x5B,0x27,0x9F,0x33,0x0B,0x06,0x2E, + 0xB3,0x86,0x8F,0x07,0x20,0x00,0x01, + 0x00}}, + {{0x83,0x4F,0x87,0x5B,0x13,0xD4,0x1F, + 0x81,0x84,0x5D,0xD5,0x10,0x00,0x06, + 0x00}}, + {{0x5B,0x27,0x9F,0x33,0x0B,0x56,0xBA, + 0x03,0x86,0xDF,0x57,0x00,0x00,0x01, + 0x00}}, + {{0x65,0x31,0x89,0x3D,0x95,0xCE,0xF0, + 0x7B,0x8E,0x57,0xCF,0x20,0x00,0x01, + 0x01}}, + {{0x73,0x3F,0x97,0x4B,0x83,0x76,0xF5, + 0x23,0x86,0xFF,0x77,0x10,0x00,0x05, + 0x01}}, + {{0xD3,0x9F,0x97,0xAB,0x03,0x76,0x5A, + 0x23,0x86,0xFF,0x77,0x09,0x00,0x03, + 0x01}}, + {{0xE2,0xAE,0x86,0xBA,0x92,0x90,0x10, + 0x3D,0x80,0x19,0x91,0x0F,0x00,0x03, + 0x00}}, + {{0x97,0x63,0x9B,0x6F,0x07,0xE0,0x10, + 0xB0,0x84,0xAF,0xE1,0x2F,0x00,0x06, + 0x00}} +#if 0 + {{0x5b,0x27,0x9f,0x29,0x01,0xc0,0x1f, + 0x90,0x84,0x8f,0xc1,0x30,0x00,0x01, + 0x00}}, + {{0x5b,0x27,0x9f,0x29,0x01,0x8e,0x1f, + 0x5e,0x82,0x5d,0x8f,0x10,0x00,0x01, + 0x00}}, + {{0x5b,0x27,0x9f,0x29,0x01,0xc0,0x1f, + 0x90,0x84,0x8f,0xc1,0x30,0x00,0x01, + 0x00}}, + {{0x5b,0x27,0x9f,0x29,0x01,0x8e,0x1f, + 0x5e,0x82,0x5d,0x8f,0x10,0x00,0x01, + 0x00}}, + {{0x5b,0x27,0x9f,0x29,0x01,0x10,0x3e, + 0xe0,0x84,0xdf,0x11,0x00,0x00,0x01, + 0x00}}, + {{0x65,0x31,0x89,0x33,0x8b,0x88,0xf0, + 0x58,0x8c,0x57,0x89,0x20,0x00,0x01, + 0x01}}, + {{0x73,0x3f,0x97,0x41,0x99,0x30,0xf5, + 0x00,0x84,0xff,0x31,0x10,0x00,0x01, + 0x01}}, + {{0x83,0x4f,0x87,0x51,0x09,0x30,0x5a, + 0x00,0x84,0xff,0x31,0x09,0x00,0x06, + 0x01}}, + {{0x8a,0x56,0x8e,0x58,0x10,0x4a,0x10, + 0x1a,0x8e,0x19,0x4b,0x2f,0x00,0x06, + 0x00}}, + {{0x97,0x63,0x9b,0x65,0x1d,0xe0,0x10, + 0xb0,0x84,0xaf,0xe1,0x2f,0x00,0x06, + 0x00}} +#endif +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_2[] = +{ + {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97, + 0x43,0x86,0xDB,0xDA,0x11,0x00,0x07, + 0x01}}, + {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97, + 0x2A,0x8D,0xC2,0xC1,0x11,0x00,0x07, + 0x01}}, + {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97, + 0x43,0x86,0xDB,0xDA,0x11,0x00,0x07, + 0x01}}, + {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97, + 0x2A,0x8D,0xC2,0xC1,0x11,0x00,0x07, + 0x01}}, + {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x9F, + 0x6B,0x8E,0x03,0x02,0x01,0x00,0x07, + 0x01}}, + {{0xFB,0x63,0x9F,0xA1,0x99,0x26,0xD5, + 0xA7,0x8A,0xBF,0xBE,0x01,0x00,0x07, + 0x01}}, + {{0xFB,0x7F,0x9F,0xAF,0x87,0x26,0xDD, + 0xFB,0x8E,0x13,0x12,0x31,0x00,0x03, + 0x01}}, + {{0xFB,0x9F,0x9F,0xBF,0x97,0x26,0x5B, + 0x7B,0x8E,0xFF,0x27,0x39,0x00,0x03, + 0x01}}, + {{0xFB,0xAE,0x9F,0xC6,0x9E,0x26,0x11, + 0x88,0x8B,0x19,0x27,0x1F,0x00,0x03, + 0x00}}, + {{0xFB,0xC7,0x9F,0xD3,0x8B,0x26,0x11, + 0xD3,0x86,0xAF,0x27,0x3F,0x00,0x07, + 0x00}} +#if 0 + {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96, + 0x20,0x84,0xb9,0xb8,0x01,0x00,0x07, + 0x01}}, + {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96, + 0x07,0x8b,0xa0,0x9f,0x01,0x00,0x07, + 0x01}}, + {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96, + 0x20,0x84,0xb9,0xb8,0x01,0x00,0x07, + 0x01}}, + {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96, + 0x07,0x8b,0xa0,0x9f,0x01,0x00,0x07, + 0x01}}, + {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96, + 0x48,0x8c,0xe1,0xe0,0x11,0x00,0x07, + 0x01}}, + {{0xfb,0x63,0x9f,0x9a,0x92,0xe0,0xd4, + 0x9b,0x8f,0x9d,0x9c,0x21,0x00,0x07, + 0x01}}, + {{0xfb,0x7f,0x9f,0xa8,0x80,0xe0,0xd4, + 0xef,0x83,0xff,0xe1,0x21,0x00,0x03, + 0x01}}, + {{0xfb,0x9f,0x9f,0xb8,0x90,0xe0,0x5a, + 0x6f,0x83,0xff,0xe1,0x29,0x00,0x03, + 0x01}}, + {{0xfb,0xae,0x9f,0xbf,0x97,0xe0,0x10, + 0x7c,0x80,0x19,0xe1,0x0f,0x00,0x03, + 0x00}}, + {{0xfb,0xc7,0x9f,0xc9,0x84,0xe0,0x10, + 0xc7,0x8b,0xaf,0xe1,0x0f,0x00,0x07, + 0x00}} +#endif +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_2_H[] = +{ + {{0xD3,0x5F,0x9E,0x6F,0x07,0x26,0x97, + 0x43,0x86,0xDB,0xDA,0x11,0x00,0x02, + 0x01}}, + {{0xD3,0x27,0x97,0x6F,0x07,0x26,0x97, + 0x6B,0x8E,0x83,0x82,0x01,0x00,0x03, + 0x01}}, + {{0xD3,0x5F,0x9E,0x6F,0x07,0x26,0x97, + 0x43,0x86,0xDB,0xDA,0x11,0x00,0x02, + 0x01}}, + {{0xD3,0x27,0x97,0x6F,0x07,0x26,0x97, + 0x07,0x8B,0xA0,0x9F,0x01,0x00,0x02, + 0x01}}, + {{0xD3,0x27,0x97,0x6F,0x07,0x26,0x97, + 0x6B,0x8E,0x83,0x82,0x01,0x00,0x03, + 0x01}}, + {{0xC9,0x31,0x8D,0x6F,0x07,0x26,0xD5, + 0xA7,0x8A,0xBF,0xBE,0x01,0x00,0x03, + 0x01}}, + {{0xBB,0x3F,0x9F,0x6F,0x87,0x26,0xDD, + 0xFB,0x8E,0x13,0x12,0x31,0x00,0x02, + 0x01}}, + {{0xAB,0x4F,0x8F,0x68,0x80,0xE0,0x5A, + 0x6F,0x83,0xFF,0xE1,0x29,0x00,0x02, + 0x01}}, + {{0xA3,0x56,0x87,0x67,0x9F,0xE0,0x10, + 0x7C,0x80,0x19,0xE1,0x0F,0x00,0x06, + 0x00}}, + {{0x97,0x63,0x9B,0x68,0x00,0xE0,0x10, + 0xC7,0x8B,0xAF,0xE1,0x0F,0x00,0x02, + 0x00}} +#if 0 + {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96, + 0x20,0x84,0xb9,0xb8,0x01,0x00,0x02, + 0x01}}, + {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96, + 0x07,0x8b,0xa0,0x9f,0x01,0x00,0x02, + 0x01}}, + {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96, + 0x20,0x84,0xb9,0xb8,0x01,0x00,0x02, + 0x01}}, + {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96, + 0x07,0x8b,0xa0,0x9f,0x01,0x00,0x02, + 0x01}}, + {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96, + 0x48,0x8c,0xe1,0xe0,0x11,0x00,0x02, + 0x01}}, + {{0xc9,0x31,0x8d,0x68,0x00,0xe0,0xd4, + 0x9b,0x8f,0x9d,0x9c,0x21,0x00,0x03, + 0x01}}, + {{0xbb,0x3f,0x9f,0x68,0x80,0xe0,0xd4, + 0xef,0x83,0xff,0xe1,0x21,0x00,0x02, + 0x01}}, + {{0xab,0x4f,0x8f,0x68,0x80,0xe0,0x5a, + 0x6f,0x83,0xff,0xe1,0x29,0x00,0x02, + 0x01}}, + {{0xa3,0x56,0x87,0x67,0x9f,0xe0,0x10, + 0x7c,0x80,0x19,0xe1,0x0f,0x00,0x06, + 0x00}}, + {{0x97,0x63,0x9b,0x68,0x00,0xe0,0x10, + 0xc7,0x8b,0xaf,0xe1,0x0f,0x00,0x02, + 0x00}} +#endif +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1XXXxXXX_1[] = +{ + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x02, + 0x01}}, + {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a, + 0x00,0x84,0xff,0x29,0x09,0x00,0x07, + 0x01}}, + {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x07, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1XXXxXXX_1_H[] = +{ + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}}, + {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x01, + 0x01}}, + {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x01, + 0x01}} +}; + + +/* CRT1 CRTC for Chrontel TV slave modes */ + +static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1UNTSC[] = +{ + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xd0,0x82,0x5d,0x57,0x00,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xd0,0x82,0x5d,0x57,0x00,0x00,0x01, + 0x00 }}, + {{0x5d,0x4f,0x81,0x56,0x99,0x56,0xba, + 0x0a,0x84,0xdf,0x57,0x00,0x00,0x01, + 0x00 }}, + {{0x80,0x63,0x84,0x6d,0x0f,0xec,0xf0, + 0x7a,0x8f,0x57,0xed,0x20,0x00,0x06, + 0x01 }}, + {{0x8c,0x7f,0x90,0x86,0x09,0xaf,0xf5, + 0x36,0x88,0xff,0xb0,0x10,0x00,0x02, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1ONTSC[] = +{ + {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e, + 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01, + 0x00 }}, + {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e, + 0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01, + 0x00 }}, + {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e, + 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01, + 0x00 }}, + {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e, + 0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01, + 0x00 }}, + {{0x5d,0x4f,0x81,0x58,0x9d,0x0b,0x3e, + 0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01, + 0x00 }}, + {{0x7d,0x63,0x81,0x68,0x0e,0xba,0xf0, + 0x78,0x8a,0x57,0xbb,0x20,0x00,0x06, + 0x01 }}, + {{0x8c,0x7f,0x90,0x82,0x06,0x46,0xf5, + 0x15,0x88,0xff,0x47,0x70,0x00,0x02, + 0x01 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1UPAL[] = +{ + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x64,0x4f,0x88,0x5a,0x9f,0x6f,0xba, + 0x15,0x83,0xdf,0x70,0x00,0x00,0x01, + 0x00 }}, + {{0x73,0x63,0x97,0x69,0x8b,0xec,0xf0, + 0x90,0x8c,0x57,0xed,0x20,0x00,0x05, + 0x01 }}, + {{0xaa,0x7f,0x8e,0x8e,0x96,0xe6,0xf5, + 0x50,0x88,0xff,0xe7,0x10,0x00,0x02, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1OPAL[] = +{ + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x64,0x4f,0x88,0x58,0x9d,0x6f,0xba, + 0x15,0x83,0xdf,0x70,0x00,0x00,0x01, + 0x00 }}, + {{0x71,0x63,0x95,0x69,0x8c,0x6f,0xf0, + 0x5a,0x8b,0x57,0x70,0x20,0x00,0x05, + 0x01 }}, + {{0xaa,0x7f,0x8e,0x8f,0x96,0x69,0xf5, + 0x28,0x88,0xff,0x6a,0x10,0x00,0x02, + 0x01 }} +}; + + +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = +{ + {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x6a,0x77,0xbb,0x6e,0x84,0x2e,0x02,0x5a,0x04,0x00,0x80,0x20,0x7e,0x80,0x98,0x00}}, + {{0xcf,0x77,0xb7,0xc8,0x84,0x3b,0x02,0x5a,0x04,0x00,0x80,0x19,0x88,0x30,0x7f,0x00}}, + {{0xee,0x77,0xbb,0x66,0x87,0x32,0x01,0x5a,0x04,0x00,0x80,0x1b,0xd3,0xf2,0x36,0x00}} +}; /* WRONG: 0x02: should be 0xfx, because if CIVEnable is clear, this should be set; + 0x07: Blacklevel: NTSC/PAL-M: Should be 131 (0x83), and not 0x50/0x5a + PAL/PAL-N: 110 (0x6e) + NTSC-J: 102 (0x66) + 0x0c-0x0f: CIV is not default as in datasheet + MISSING: 0x21: Should set D1 to ZERO (for NTSC, PAL-M) or ONE (PAL, NTSC-J) + Most of this is wrong in all NTSC and PAL register arrays. But I won't correct + it as long as it works. For NTSC-J, the blacklevel is corrected in init301.c; + for PAL-M and PAL-N all above is corrected. + */ + +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = +{ + {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x69,0x77,0xbb,0x6e,0x84,0x1e,0x00,0x5a,0x04,0x00,0x80,0x25,0x1a,0x43,0x04,0x00}}, + {{0xce,0x77,0xb7,0xb6,0x83,0x2c,0x02,0x5a,0x04,0x00,0x80,0x1c,0x00,0x82,0x97,0x00}}, + {{0xed,0x77,0xbb,0x66,0x8c,0x21,0x02,0x5a,0x04,0x00,0x80,0x1f,0x9f,0xc1,0x0c,0x00}} +}; + +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = +{ + {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x41,0x7f,0xb7,0x12,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x26,0x2a,0x55,0x5d,0x00}}, + {{0xc3,0x7f,0xb7,0x7a,0x84,0x40,0x02,0x5a,0x05,0x00,0x80,0x1f,0x84,0x3d,0x28,0x00}}, + {{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x5a,0x05,0x00,0x80,0x20,0x3e,0xe4,0x22,0x00}} +}; + +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = +{ + {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x26,0x2a,0x55,0x5d,0x00}}, + {{0xc1,0x7f,0xb7,0x4d,0x8c,0x1e,0x31,0x5a,0x05,0x00,0x80,0x26,0x78,0x19,0x34,0x00}}, + {{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x5a,0x05,0x00,0x80,0x25,0x8c,0xb2,0x2a,0x00}} +}; + +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPALM[] = +{ + {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x72,0x77,0xfb,0x6e,0x84,0x2e,0x02,0x83,0x04,0x00,0x80,0x20,0x76,0xdb,0x6e,0x00}}, + {{0xd7,0x77,0xf7,0xc8,0x84,0x3b,0x02,0x83,0x04,0x00,0x80,0x19,0x84,0x0a,0xc7,0x00}}, + {{0xf6,0x77,0xfb,0x66,0x87,0x32,0x01,0x83,0x04,0x00,0x80,0x1b,0xdc,0xb0,0x8d,0x00}} +#if 0 /* Correct blacklevel and CFRB */ + {{0x72,0x77,0xbb,0x6e,0x84,0x2e,0x02,0x5a,0x04,0x00,0x80,0x20,0x76,0xdb,0x6e,0x00}}, + {{0xd7,0x77,0xb7,0xc8,0x84,0x3b,0x02,0x5a,0x04,0x00,0x80,0x19,0x84,0x0a,0xc7,0x00}}, + {{0xf6,0x77,0xbb,0x66,0x87,0x32,0x01,0x5a,0x04,0x00,0x80,0x1b,0xdc,0xb0,0x8d,0x00}} +#endif +}; + +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPALM[] = +{ + {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x71,0x77,0xfb,0x6e,0x84,0x1e,0x00,0x83,0x04,0x00,0x80,0x25,0x1a,0x1f,0x59,0x00}}, + {{0xd6,0x77,0xf7,0xb6,0x83,0x2c,0x02,0x83,0x04,0x00,0x80,0x1b,0xf8,0x1f,0x82,0x00}}, + {{0xf5,0x77,0xfb,0x66,0x8c,0x21,0x02,0x83,0x04,0x00,0x80,0x1f,0x58,0x46,0x9f,0x00}} +#if 0 /* Correct blacklevel and CFRB */ + {{0x71,0x77,0xbb,0x6e,0x84,0x1e,0x00,0x5a,0x04,0x00,0x80,0x25,0x1a,0x1f,0x59,0x00}}, + {{0xd6,0x77,0xb7,0xb6,0x83,0x2c,0x02,0x5a,0x04,0x00,0x80,0x1b,0xf8,0x1f,0x82,0x00}}, + {{0xf5,0x77,0xbb,0x66,0x8c,0x21,0x02,0x5a,0x04,0x00,0x80,0x1f,0x58,0x46,0x9f,0x00}} +#endif +}; + +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPALN[] = +{ + {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x41,0x7f,0xb7,0x12,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0xc3,0x7f,0xb7,0x7a,0x84,0x40,0x02,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}} +#if 0 /* Correct blacklevel, CIV and CFRB */ + {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x1f,0x0d,0x54,0x5e,0x00}}, + {{0xc3,0x7f,0xb7,0x7a,0x84,0x40,0x02,0x5a,0x05,0x00,0x80,0x19,0x78,0xef,0x35,0x00}}, + {{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x5a,0x05,0x00,0x80,0x1a,0x33,0x3f,0x2f,0x00}} +#endif +}; + +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPALN[] = +{ + {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0xc1,0x7f,0xb7,0x4d,0x8c,0x1e,0x31,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}} +#if 0 /* Correct blacklevel, CIV and CFRB */ + {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x1f,0x0d,0x54,0x5e,0x00}}, + {{0xc1,0x7f,0xb7,0x4d,0x8c,0x1e,0x31,0x5a,0x05,0x00,0x80,0x1f,0x15,0xc0,0x1e,0x00}}, + {{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x5a,0x05,0x00,0x80,0x1d,0xf1,0x6c,0xcb,0x00}} +#endif +}; + +static const UCHAR SiS310_CHTVVCLKUNTSC[] = {0x41,0x41,0x41,0x41,0x42,0x46,0x53}; +static const UCHAR SiS310_CHTVVCLKONTSC[] = {0x48,0x48,0x48,0x48,0x45,0x43,0x51}; + +static const UCHAR SiS310_CHTVVCLKUPAL[] = {0x47,0x47,0x47,0x47,0x48,0x4a,0x54}; +static const UCHAR SiS310_CHTVVCLKOPAL[] = {0x47,0x47,0x47,0x47,0x48,0x4f,0x52}; + +static const UCHAR SiS310_CHTVVCLKUPALM[] = {0x41,0x41,0x41,0x41,0x42,0x46,0x53}; +static const UCHAR SiS310_CHTVVCLKOPALM[] = {0x48,0x48,0x48,0x48,0x45,0x43,0x51}; + +static const UCHAR SiS310_CHTVVCLKUPALN[] = {0x47,0x47,0x47,0x47,0x48,0x4a,0x54}; +static const UCHAR SiS310_CHTVVCLKOPALN[] = {0x47,0x47,0x47,0x47,0x48,0x4f,0x52}; + + diff --git a/drivers/video/sis/Makefile b/drivers/video/sis/Makefile new file mode 100644 index 000000000000..aaed8c2b4a64 --- /dev/null +++ b/drivers/video/sis/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the SiS framebuffer device driver +# + +obj-$(CONFIG_FB_SIS) += sisfb.o + +sisfb-objs := sis_main.o sis_accel.o init.o init301.o diff --git a/drivers/video/sis/init.c b/drivers/video/sis/init.c new file mode 100644 index 000000000000..1994054d45ff --- /dev/null +++ b/drivers/video/sis/init.c @@ -0,0 +1,5318 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Mode initializing code (CRT1 section) for + * for SiS 300/305/540/630/730 and + * SiS 315/550/650/M650/651/661FX/M661FX/740/741(GX)/M741/330/660/M660/760/M760 + * (Universal module for Linux kernel framebuffer and XFree86 4.x) + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + * Formerly based on non-functional code-fragements for 300 series by SiS, Inc. + * Used by permission. + * + * TW says: This code looks awful, I know. But please don't do anything about + * this otherwise debugging will be hell. + * The code is extremely fragile as regards the different chipsets, different + * video bridges and combinations thereof. If anything is changed, extreme + * care has to be taken that that change doesn't break it for other chipsets, + * bridges or combinations thereof. + * All comments in this file are by me, regardless if they are marked TW or not. + * + */ + +#include "init.h" + +#ifdef SIS300 +#include "300vtbl.h" +#endif + +#ifdef SIS315H +#include "310vtbl.h" +#endif + +#if defined(ALLOC_PRAGMA) +#pragma alloc_text(PAGE,SiSSetMode) +#endif + +/*********************************************/ +/* POINTER INITIALIZATION */ +/*********************************************/ + +#if defined(SIS300) || defined(SIS315H) +static void +InitCommonPointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + SiS_Pr->SiS_StResInfo = SiS_StResInfo; + SiS_Pr->SiS_ModeResInfo = SiS_ModeResInfo; + SiS_Pr->SiS_StandTable = SiS_StandTable; + + SiS_Pr->SiS_NTSCPhase = SiS_NTSCPhase; + SiS_Pr->SiS_PALPhase = SiS_PALPhase; + SiS_Pr->SiS_NTSCPhase2 = SiS_NTSCPhase2; + SiS_Pr->SiS_PALPhase2 = SiS_PALPhase2; + SiS_Pr->SiS_PALMPhase = SiS_PALMPhase; + SiS_Pr->SiS_PALNPhase = SiS_PALNPhase; + SiS_Pr->SiS_PALMPhase2 = SiS_PALMPhase2; + SiS_Pr->SiS_PALNPhase2 = SiS_PALNPhase2; + SiS_Pr->SiS_SpecialPhase = SiS_SpecialPhase; + SiS_Pr->SiS_SpecialPhaseM = SiS_SpecialPhaseM; + SiS_Pr->SiS_SpecialPhaseJ = SiS_SpecialPhaseJ; + + SiS_Pr->SiS_NTSCTiming = SiS_NTSCTiming; + SiS_Pr->SiS_PALTiming = SiS_PALTiming; + SiS_Pr->SiS_HiTVSt1Timing = SiS_HiTVSt1Timing; + SiS_Pr->SiS_HiTVSt2Timing = SiS_HiTVSt2Timing; + + SiS_Pr->SiS_HiTVExtTiming = SiS_HiTVExtTiming; + SiS_Pr->SiS_HiTVGroup3Data = SiS_HiTVGroup3Data; + SiS_Pr->SiS_HiTVGroup3Simu = SiS_HiTVGroup3Simu; +#if 0 + SiS_Pr->SiS_HiTVTextTiming = SiS_HiTVTextTiming; + SiS_Pr->SiS_HiTVGroup3Text = SiS_HiTVGroup3Text; +#endif + + SiS_Pr->SiS_StPALData = SiS_StPALData; + SiS_Pr->SiS_ExtPALData = SiS_ExtPALData; + SiS_Pr->SiS_StNTSCData = SiS_StNTSCData; + SiS_Pr->SiS_ExtNTSCData = SiS_ExtNTSCData; + SiS_Pr->SiS_St1HiTVData = SiS_StHiTVData; + SiS_Pr->SiS_St2HiTVData = SiS_St2HiTVData; + SiS_Pr->SiS_ExtHiTVData = SiS_ExtHiTVData; + SiS_Pr->SiS_St525iData = SiS_StNTSCData; + SiS_Pr->SiS_St525pData = SiS_St525pData; + SiS_Pr->SiS_St750pData = SiS_St750pData; + SiS_Pr->SiS_Ext525iData = SiS_ExtNTSCData; + SiS_Pr->SiS_Ext525pData = SiS_ExtNTSCData; + SiS_Pr->SiS_Ext750pData = SiS_Ext750pData; + + SiS_Pr->pSiS_OutputSelect = &SiS_OutputSelect; + SiS_Pr->pSiS_SoftSetting = &SiS_SoftSetting; + + SiS_Pr->SiS_LCD1280x720Data = SiS_LCD1280x720Data; + SiS_Pr->SiS_StLCD1280x768_2Data = SiS_StLCD1280x768_2Data; + SiS_Pr->SiS_ExtLCD1280x768_2Data = SiS_ExtLCD1280x768_2Data; + SiS_Pr->SiS_LCD1280x800Data = SiS_LCD1280x800Data; + SiS_Pr->SiS_LCD1280x800_2Data = SiS_LCD1280x800_2Data; + SiS_Pr->SiS_LCD1280x960Data = SiS_LCD1280x960Data; + SiS_Pr->SiS_StLCD1400x1050Data = SiS_StLCD1400x1050Data; + SiS_Pr->SiS_ExtLCD1400x1050Data = SiS_ExtLCD1400x1050Data; + SiS_Pr->SiS_LCD1680x1050Data = SiS_LCD1680x1050Data; + SiS_Pr->SiS_StLCD1600x1200Data = SiS_StLCD1600x1200Data; + SiS_Pr->SiS_ExtLCD1600x1200Data = SiS_ExtLCD1600x1200Data; + SiS_Pr->SiS_NoScaleData = SiS_NoScaleData; + + SiS_Pr->SiS_LVDS320x480Data_1 = SiS_LVDS320x480Data_1; + SiS_Pr->SiS_LVDS800x600Data_1 = SiS_LVDS800x600Data_1; + SiS_Pr->SiS_LVDS800x600Data_2 = SiS_LVDS800x600Data_2; + SiS_Pr->SiS_LVDS1024x768Data_1 = SiS_LVDS1024x768Data_1; + SiS_Pr->SiS_LVDS1024x768Data_2 = SiS_LVDS1024x768Data_2; + SiS_Pr->SiS_LVDS1280x1024Data_1 = SiS_LVDS1280x1024Data_1; + SiS_Pr->SiS_LVDS1280x1024Data_2 = SiS_LVDS1280x1024Data_2; + SiS_Pr->SiS_LVDS1400x1050Data_1 = SiS_LVDS1400x1050Data_1; + SiS_Pr->SiS_LVDS1400x1050Data_2 = SiS_LVDS1400x1050Data_2; + SiS_Pr->SiS_LVDS1600x1200Data_1 = SiS_LVDS1600x1200Data_1; + SiS_Pr->SiS_LVDS1600x1200Data_2 = SiS_LVDS1600x1200Data_2; + SiS_Pr->SiS_LVDS1280x768Data_1 = SiS_LVDS1280x768Data_1; + SiS_Pr->SiS_LVDS1280x768Data_2 = SiS_LVDS1280x768Data_2; + SiS_Pr->SiS_LVDS1024x600Data_1 = SiS_LVDS1024x600Data_1; + SiS_Pr->SiS_LVDS1024x600Data_2 = SiS_LVDS1024x600Data_2; + SiS_Pr->SiS_LVDS1152x768Data_1 = SiS_LVDS1152x768Data_1; + SiS_Pr->SiS_LVDS1152x768Data_2 = SiS_LVDS1152x768Data_2; + SiS_Pr->SiS_LVDSXXXxXXXData_1 = SiS_LVDSXXXxXXXData_1; + SiS_Pr->SiS_LVDS1280x960Data_1 = SiS_LVDS1280x960Data_1; + SiS_Pr->SiS_LVDS1280x960Data_2 = SiS_LVDS1280x960Data_2; + SiS_Pr->SiS_LVDS640x480Data_1 = SiS_LVDS640x480Data_1; + SiS_Pr->SiS_LVDS1280x960Data_1 = SiS_LVDS1280x1024Data_1; + SiS_Pr->SiS_LVDS1280x960Data_2 = SiS_LVDS1280x1024Data_2; + SiS_Pr->SiS_LVDS640x480Data_1 = SiS_LVDS640x480Data_1; + SiS_Pr->SiS_LVDS640x480Data_2 = SiS_LVDS640x480Data_2; + + SiS_Pr->SiS_LVDS848x480Data_1 = SiS_LVDS848x480Data_1; + SiS_Pr->SiS_LVDS848x480Data_2 = SiS_LVDS848x480Data_2; + SiS_Pr->SiS_LVDSBARCO1024Data_1 = SiS_LVDSBARCO1024Data_1; + SiS_Pr->SiS_LVDSBARCO1024Data_2 = SiS_LVDSBARCO1024Data_2; + SiS_Pr->SiS_LVDSBARCO1366Data_1 = SiS_LVDSBARCO1366Data_1; + SiS_Pr->SiS_LVDSBARCO1366Data_2 = SiS_LVDSBARCO1366Data_2; + + SiS_Pr->SiS_LVDSCRT11280x768_1 = SiS_LVDSCRT11280x768_1; + SiS_Pr->SiS_LVDSCRT11024x600_1 = SiS_LVDSCRT11024x600_1; + SiS_Pr->SiS_LVDSCRT11152x768_1 = SiS_LVDSCRT11152x768_1; + SiS_Pr->SiS_LVDSCRT11280x768_1_H = SiS_LVDSCRT11280x768_1_H; + SiS_Pr->SiS_LVDSCRT11024x600_1_H = SiS_LVDSCRT11024x600_1_H; + SiS_Pr->SiS_LVDSCRT11152x768_1_H = SiS_LVDSCRT11152x768_1_H; + SiS_Pr->SiS_LVDSCRT11280x768_2 = SiS_LVDSCRT11280x768_2; + SiS_Pr->SiS_LVDSCRT11024x600_2 = SiS_LVDSCRT11024x600_2; + SiS_Pr->SiS_LVDSCRT11152x768_2 = SiS_LVDSCRT11152x768_2; + SiS_Pr->SiS_LVDSCRT11280x768_2_H = SiS_LVDSCRT11280x768_2_H; + SiS_Pr->SiS_LVDSCRT11024x600_2_H = SiS_LVDSCRT11024x600_2_H; + SiS_Pr->SiS_LVDSCRT11152x768_2_H = SiS_LVDSCRT11152x768_2_H; + SiS_Pr->SiS_LVDSCRT1320x480_1 = SiS_LVDSCRT1320x480_1; + SiS_Pr->SiS_LVDSCRT1640x480_1 = SiS_LVDSCRT1640x480_1; + SiS_Pr->SiS_LVDSCRT1640x480_1_H = SiS_LVDSCRT1640x480_1_H; + SiS_Pr->SiS_LVDSCRT1640x480_2 = SiS_LVDSCRT1640x480_2; + SiS_Pr->SiS_LVDSCRT1640x480_2_H = SiS_LVDSCRT1640x480_2_H; + SiS_Pr->SiS_LVDSCRT1640x480_3 = SiS_LVDSCRT1640x480_3; + SiS_Pr->SiS_LVDSCRT1640x480_3_H = SiS_LVDSCRT1640x480_3_H; + + SiS_Pr->SiS_CHTVUNTSCData = SiS_CHTVUNTSCData; + SiS_Pr->SiS_CHTVONTSCData = SiS_CHTVONTSCData; + + SiS_Pr->SiS_CHTVUNTSCDesData = SiS_CHTVUNTSCDesData; + SiS_Pr->SiS_CHTVONTSCDesData = SiS_CHTVONTSCDesData; + SiS_Pr->SiS_CHTVUPALDesData = SiS_CHTVUPALDesData; + SiS_Pr->SiS_CHTVOPALDesData = SiS_CHTVOPALDesData; + + SiS_Pr->SiS_PanelMinLVDS = Panel_800x600; /* lowest value LVDS/LCDA */ + SiS_Pr->SiS_PanelMin301 = Panel_1024x768; /* lowest value 301 */ +} +#endif + +#ifdef SIS300 +static void +InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + InitCommonPointer(SiS_Pr, HwInfo); + + SiS_Pr->SiS_SModeIDTable = SiS300_SModeIDTable; + SiS_Pr->SiS_VBModeIDTable = SiS300_VBModeIDTable; + SiS_Pr->SiS_EModeIDTable = SiS300_EModeIDTable; + SiS_Pr->SiS_RefIndex = SiS300_RefIndex; + SiS_Pr->SiS_CRT1Table = SiS300_CRT1Table; + if(HwInfo->jChipType == SIS_300) { + SiS_Pr->SiS_MCLKData_0 = SiS300_MCLKData_300; /* 300 */ + } else { + SiS_Pr->SiS_MCLKData_0 = SiS300_MCLKData_630; /* 630, 730 */ + } + SiS_Pr->SiS_VCLKData = SiS300_VCLKData; + SiS_Pr->SiS_VBVCLKData = (SiS_VBVCLKDataStruct *)SiS300_VCLKData; + + SiS_Pr->SiS_SR15 = SiS300_SR15; + +#ifdef LINUX_KERNEL + SiS_Pr->pSiS_SR07 = &SiS300_SR07; + SiS_Pr->SiS_CR40 = SiS300_CR40; + SiS_Pr->SiS_CR49 = SiS300_CR49; + SiS_Pr->pSiS_SR1F = &SiS300_SR1F; + SiS_Pr->pSiS_SR21 = &SiS300_SR21; + SiS_Pr->pSiS_SR22 = &SiS300_SR22; + SiS_Pr->pSiS_SR23 = &SiS300_SR23; + SiS_Pr->pSiS_SR24 = &SiS300_SR24; + SiS_Pr->SiS_SR25 = SiS300_SR25; + SiS_Pr->pSiS_SR31 = &SiS300_SR31; + SiS_Pr->pSiS_SR32 = &SiS300_SR32; + SiS_Pr->pSiS_SR33 = &SiS300_SR33; + SiS_Pr->pSiS_CRT2Data_1_2 = &SiS300_CRT2Data_1_2; + SiS_Pr->pSiS_CRT2Data_4_D = &SiS300_CRT2Data_4_D; + SiS_Pr->pSiS_CRT2Data_4_E = &SiS300_CRT2Data_4_E; + SiS_Pr->pSiS_CRT2Data_4_10 = &SiS300_CRT2Data_4_10; + SiS_Pr->pSiS_RGBSenseData = &SiS300_RGBSenseData; + SiS_Pr->pSiS_VideoSenseData = &SiS300_VideoSenseData; + SiS_Pr->pSiS_YCSenseData = &SiS300_YCSenseData; + SiS_Pr->pSiS_RGBSenseData2 = &SiS300_RGBSenseData2; + SiS_Pr->pSiS_VideoSenseData2 = &SiS300_VideoSenseData2; + SiS_Pr->pSiS_YCSenseData2 = &SiS300_YCSenseData2; +#endif + + SiS_Pr->SiS_PanelDelayTbl = SiS300_PanelDelayTbl; + SiS_Pr->SiS_PanelDelayTblLVDS = SiS300_PanelDelayTbl; + + SiS_Pr->SiS_ExtLCD1024x768Data = SiS300_ExtLCD1024x768Data; + SiS_Pr->SiS_St2LCD1024x768Data = SiS300_St2LCD1024x768Data; + SiS_Pr->SiS_ExtLCD1280x1024Data = SiS300_ExtLCD1280x1024Data; + SiS_Pr->SiS_St2LCD1280x1024Data = SiS300_St2LCD1280x1024Data; + + SiS_Pr->SiS_CRT2Part2_1024x768_1 = SiS300_CRT2Part2_1024x768_1; + SiS_Pr->SiS_CRT2Part2_1280x1024_1 = SiS300_CRT2Part2_1280x1024_1; + SiS_Pr->SiS_CRT2Part2_1024x768_2 = SiS300_CRT2Part2_1024x768_2; + SiS_Pr->SiS_CRT2Part2_1280x1024_2 = SiS300_CRT2Part2_1280x1024_2; + SiS_Pr->SiS_CRT2Part2_1024x768_3 = SiS300_CRT2Part2_1024x768_3; + SiS_Pr->SiS_CRT2Part2_1280x1024_3 = SiS300_CRT2Part2_1280x1024_3; + + SiS_Pr->SiS_CHTVUPALData = SiS300_CHTVUPALData; + SiS_Pr->SiS_CHTVOPALData = SiS300_CHTVOPALData; + SiS_Pr->SiS_CHTVUPALMData = SiS_CHTVUNTSCData; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVOPALMData = SiS_CHTVONTSCData; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVUPALNData = SiS300_CHTVUPALData; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVOPALNData = SiS300_CHTVOPALData; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVSOPALData = SiS300_CHTVSOPALData; + + SiS_Pr->SiS_PanelType00_1 = SiS300_PanelType00_1; + SiS_Pr->SiS_PanelType01_1 = SiS300_PanelType01_1; + SiS_Pr->SiS_PanelType02_1 = SiS300_PanelType02_1; + SiS_Pr->SiS_PanelType03_1 = SiS300_PanelType03_1; + SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1; + SiS_Pr->SiS_PanelType05_1 = SiS300_PanelType05_1; + SiS_Pr->SiS_PanelType06_1 = SiS300_PanelType06_1; + SiS_Pr->SiS_PanelType07_1 = SiS300_PanelType07_1; + SiS_Pr->SiS_PanelType08_1 = SiS300_PanelType08_1; + SiS_Pr->SiS_PanelType09_1 = SiS300_PanelType09_1; + SiS_Pr->SiS_PanelType0a_1 = SiS300_PanelType0a_1; + SiS_Pr->SiS_PanelType0b_1 = SiS300_PanelType0b_1; + SiS_Pr->SiS_PanelType0c_1 = SiS300_PanelType0c_1; + SiS_Pr->SiS_PanelType0d_1 = SiS300_PanelType0d_1; + SiS_Pr->SiS_PanelType0e_1 = SiS300_PanelType0e_1; + SiS_Pr->SiS_PanelType0f_1 = SiS300_PanelType0f_1; + SiS_Pr->SiS_PanelType00_2 = SiS300_PanelType00_2; + SiS_Pr->SiS_PanelType01_2 = SiS300_PanelType01_2; + SiS_Pr->SiS_PanelType02_2 = SiS300_PanelType02_2; + SiS_Pr->SiS_PanelType03_2 = SiS300_PanelType03_2; + SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2; + SiS_Pr->SiS_PanelType05_2 = SiS300_PanelType05_2; + SiS_Pr->SiS_PanelType06_2 = SiS300_PanelType06_2; + SiS_Pr->SiS_PanelType07_2 = SiS300_PanelType07_2; + SiS_Pr->SiS_PanelType08_2 = SiS300_PanelType08_2; + SiS_Pr->SiS_PanelType09_2 = SiS300_PanelType09_2; + SiS_Pr->SiS_PanelType0a_2 = SiS300_PanelType0a_2; + SiS_Pr->SiS_PanelType0b_2 = SiS300_PanelType0b_2; + SiS_Pr->SiS_PanelType0c_2 = SiS300_PanelType0c_2; + SiS_Pr->SiS_PanelType0d_2 = SiS300_PanelType0d_2; + SiS_Pr->SiS_PanelType0e_2 = SiS300_PanelType0e_2; + SiS_Pr->SiS_PanelType0f_2 = SiS300_PanelType0f_2; + SiS_Pr->SiS_PanelTypeNS_1 = SiS300_PanelTypeNS_1; + SiS_Pr->SiS_PanelTypeNS_2 = SiS300_PanelTypeNS_2; + + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { + SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1a; + SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2a; + } + if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { + SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1b; + SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2b; + } + + SiS_Pr->SiS_LVDSCRT1800x600_1 = SiS300_LVDSCRT1800x600_1; + SiS_Pr->SiS_LVDSCRT1800x600_1_H = SiS300_LVDSCRT1800x600_1_H; + SiS_Pr->SiS_LVDSCRT1800x600_2 = SiS300_LVDSCRT1800x600_2; + SiS_Pr->SiS_LVDSCRT1800x600_2_H = SiS300_LVDSCRT1800x600_2_H; + SiS_Pr->SiS_LVDSCRT11024x768_1 = SiS300_LVDSCRT11024x768_1; + SiS_Pr->SiS_LVDSCRT11024x768_1_H = SiS300_LVDSCRT11024x768_1_H; + SiS_Pr->SiS_LVDSCRT11024x768_2 = SiS300_LVDSCRT11024x768_2; + SiS_Pr->SiS_LVDSCRT11024x768_2_H = SiS300_LVDSCRT11024x768_2_H; + SiS_Pr->SiS_LVDSCRT11280x1024_1 = SiS300_LVDSCRT11280x1024_1; + SiS_Pr->SiS_LVDSCRT11280x1024_1_H = SiS300_LVDSCRT11280x1024_1_H; + SiS_Pr->SiS_LVDSCRT11280x1024_2 = SiS300_LVDSCRT11280x1024_2; + SiS_Pr->SiS_LVDSCRT11280x1024_2_H = SiS300_LVDSCRT11280x1024_2_H; + SiS_Pr->SiS_LVDSCRT1XXXxXXX_1 = SiS300_LVDSCRT1XXXxXXX_1; + SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H = SiS300_LVDSCRT1XXXxXXX_1_H; + + SiS_Pr->SiS_CHTVCRT1UNTSC = SiS300_CHTVCRT1UNTSC; + SiS_Pr->SiS_CHTVCRT1ONTSC = SiS300_CHTVCRT1ONTSC; + SiS_Pr->SiS_CHTVCRT1UPAL = SiS300_CHTVCRT1UPAL; + SiS_Pr->SiS_CHTVCRT1OPAL = SiS300_CHTVCRT1OPAL; + SiS_Pr->SiS_CHTVCRT1SOPAL = SiS300_CHTVCRT1SOPAL; + SiS_Pr->SiS_CHTVReg_UNTSC = SiS300_CHTVReg_UNTSC; + SiS_Pr->SiS_CHTVReg_ONTSC = SiS300_CHTVReg_ONTSC; + SiS_Pr->SiS_CHTVReg_UPAL = SiS300_CHTVReg_UPAL; + SiS_Pr->SiS_CHTVReg_OPAL = SiS300_CHTVReg_OPAL; + SiS_Pr->SiS_CHTVReg_UPALM = SiS300_CHTVReg_UNTSC; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVReg_OPALM = SiS300_CHTVReg_ONTSC; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVReg_UPALN = SiS300_CHTVReg_UPAL; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVReg_OPALN = SiS300_CHTVReg_OPAL; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVReg_SOPAL = SiS300_CHTVReg_SOPAL; + SiS_Pr->SiS_CHTVVCLKUNTSC = SiS300_CHTVVCLKUNTSC; + SiS_Pr->SiS_CHTVVCLKONTSC = SiS300_CHTVVCLKONTSC; + SiS_Pr->SiS_CHTVVCLKUPAL = SiS300_CHTVVCLKUPAL; + SiS_Pr->SiS_CHTVVCLKOPAL = SiS300_CHTVVCLKOPAL; + SiS_Pr->SiS_CHTVVCLKUPALM = SiS300_CHTVVCLKUNTSC; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVVCLKOPALM = SiS300_CHTVVCLKONTSC; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVVCLKUPALN = SiS300_CHTVVCLKUPAL; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVVCLKOPALN = SiS300_CHTVVCLKOPAL; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVVCLKSOPAL = SiS300_CHTVVCLKSOPAL; +} +#endif + +#ifdef SIS315H +static void +InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + InitCommonPointer(SiS_Pr, HwInfo); + + SiS_Pr->SiS_SModeIDTable = SiS310_SModeIDTable; + SiS_Pr->SiS_EModeIDTable = SiS310_EModeIDTable; + SiS_Pr->SiS_RefIndex = (SiS_Ext2Struct *)SiS310_RefIndex; + SiS_Pr->SiS_CRT1Table = SiS310_CRT1Table; + if(HwInfo->jChipType >= SIS_340) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_340; /* 340 */ + } else if(HwInfo->jChipType >= SIS_761) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_761; /* 761 - preliminary */ + } else if(HwInfo->jChipType >= SIS_760) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_760; /* 760 */ + } else if(HwInfo->jChipType >= SIS_661) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_660; /* 661/741 */ + } else if(HwInfo->jChipType == SIS_330) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_330; /* 330 */ + } else if(HwInfo->jChipType > SIS_315PRO) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_650; /* 550, 650, 740 */ + } else { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_315; /* 315 */ + } + if(HwInfo->jChipType >= SIS_340) { + SiS_Pr->SiS_MCLKData_1 = SiS310_MCLKData_1_340; + } else { + SiS_Pr->SiS_MCLKData_1 = SiS310_MCLKData_1; + } + SiS_Pr->SiS_VCLKData = SiS310_VCLKData; + SiS_Pr->SiS_VBVCLKData = SiS310_VBVCLKData; + + SiS_Pr->SiS_SR15 = SiS310_SR15; + +#ifdef LINUX_KERNEL + SiS_Pr->pSiS_SR07 = &SiS310_SR07; + SiS_Pr->SiS_CR40 = SiS310_CR40; + SiS_Pr->SiS_CR49 = SiS310_CR49; + SiS_Pr->pSiS_SR1F = &SiS310_SR1F; + SiS_Pr->pSiS_SR21 = &SiS310_SR21; + SiS_Pr->pSiS_SR22 = &SiS310_SR22; + SiS_Pr->pSiS_SR23 = &SiS310_SR23; + SiS_Pr->pSiS_SR24 = &SiS310_SR24; + SiS_Pr->SiS_SR25 = SiS310_SR25; + SiS_Pr->pSiS_SR31 = &SiS310_SR31; + SiS_Pr->pSiS_SR32 = &SiS310_SR32; + SiS_Pr->pSiS_SR33 = &SiS310_SR33; + SiS_Pr->pSiS_CRT2Data_1_2 = &SiS310_CRT2Data_1_2; + SiS_Pr->pSiS_CRT2Data_4_D = &SiS310_CRT2Data_4_D; + SiS_Pr->pSiS_CRT2Data_4_E = &SiS310_CRT2Data_4_E; + SiS_Pr->pSiS_CRT2Data_4_10 = &SiS310_CRT2Data_4_10; + SiS_Pr->pSiS_RGBSenseData = &SiS310_RGBSenseData; + SiS_Pr->pSiS_VideoSenseData = &SiS310_VideoSenseData; + SiS_Pr->pSiS_YCSenseData = &SiS310_YCSenseData; + SiS_Pr->pSiS_RGBSenseData2 = &SiS310_RGBSenseData2; + SiS_Pr->pSiS_VideoSenseData2 = &SiS310_VideoSenseData2; + SiS_Pr->pSiS_YCSenseData2 = &SiS310_YCSenseData2; +#endif + + SiS_Pr->SiS_PanelDelayTbl = SiS310_PanelDelayTbl; + SiS_Pr->SiS_PanelDelayTblLVDS = SiS310_PanelDelayTblLVDS; + + SiS_Pr->SiS_St2LCD1024x768Data = SiS310_St2LCD1024x768Data; + SiS_Pr->SiS_ExtLCD1024x768Data = SiS310_ExtLCD1024x768Data; + SiS_Pr->SiS_St2LCD1280x1024Data = SiS310_St2LCD1280x1024Data; + SiS_Pr->SiS_ExtLCD1280x1024Data = SiS310_ExtLCD1280x1024Data; + + SiS_Pr->SiS_CRT2Part2_1024x768_1 = SiS310_CRT2Part2_1024x768_1; + + SiS_Pr->SiS_PanelType00_1 = SiS310_PanelType00_1; + SiS_Pr->SiS_PanelType01_1 = SiS310_PanelType01_1; + SiS_Pr->SiS_PanelType02_1 = SiS310_PanelType02_1; + SiS_Pr->SiS_PanelType03_1 = SiS310_PanelType03_1; + SiS_Pr->SiS_PanelType04_1 = SiS310_PanelType04_1; + SiS_Pr->SiS_PanelType05_1 = SiS310_PanelType05_1; + SiS_Pr->SiS_PanelType06_1 = SiS310_PanelType06_1; + SiS_Pr->SiS_PanelType07_1 = SiS310_PanelType07_1; + SiS_Pr->SiS_PanelType08_1 = SiS310_PanelType08_1; + SiS_Pr->SiS_PanelType09_1 = SiS310_PanelType09_1; + SiS_Pr->SiS_PanelType0a_1 = SiS310_PanelType0a_1; + SiS_Pr->SiS_PanelType0b_1 = SiS310_PanelType0b_1; + SiS_Pr->SiS_PanelType0c_1 = SiS310_PanelType0c_1; + SiS_Pr->SiS_PanelType0d_1 = SiS310_PanelType0d_1; + SiS_Pr->SiS_PanelType0e_1 = SiS310_PanelType0e_1; + SiS_Pr->SiS_PanelType0f_1 = SiS310_PanelType0f_1; + SiS_Pr->SiS_PanelType00_2 = SiS310_PanelType00_2; + SiS_Pr->SiS_PanelType01_2 = SiS310_PanelType01_2; + SiS_Pr->SiS_PanelType02_2 = SiS310_PanelType02_2; + SiS_Pr->SiS_PanelType03_2 = SiS310_PanelType03_2; + SiS_Pr->SiS_PanelType04_2 = SiS310_PanelType04_2; + SiS_Pr->SiS_PanelType05_2 = SiS310_PanelType05_2; + SiS_Pr->SiS_PanelType06_2 = SiS310_PanelType06_2; + SiS_Pr->SiS_PanelType07_2 = SiS310_PanelType07_2; + SiS_Pr->SiS_PanelType08_2 = SiS310_PanelType08_2; + SiS_Pr->SiS_PanelType09_2 = SiS310_PanelType09_2; + SiS_Pr->SiS_PanelType0a_2 = SiS310_PanelType0a_2; + SiS_Pr->SiS_PanelType0b_2 = SiS310_PanelType0b_2; + SiS_Pr->SiS_PanelType0c_2 = SiS310_PanelType0c_2; + SiS_Pr->SiS_PanelType0d_2 = SiS310_PanelType0d_2; + SiS_Pr->SiS_PanelType0e_2 = SiS310_PanelType0e_2; + SiS_Pr->SiS_PanelType0f_2 = SiS310_PanelType0f_2; + SiS_Pr->SiS_PanelTypeNS_1 = SiS310_PanelTypeNS_1; + SiS_Pr->SiS_PanelTypeNS_2 = SiS310_PanelTypeNS_2; + + SiS_Pr->SiS_CHTVUPALData = SiS310_CHTVUPALData; + SiS_Pr->SiS_CHTVOPALData = SiS310_CHTVOPALData; + SiS_Pr->SiS_CHTVUPALMData = SiS310_CHTVUPALMData; + SiS_Pr->SiS_CHTVOPALMData = SiS310_CHTVOPALMData; + SiS_Pr->SiS_CHTVUPALNData = SiS310_CHTVUPALNData; + SiS_Pr->SiS_CHTVOPALNData = SiS310_CHTVOPALNData; + SiS_Pr->SiS_CHTVSOPALData = SiS310_CHTVSOPALData; + + SiS_Pr->SiS_LVDSCRT1800x600_1 = SiS310_LVDSCRT1800x600_1; + SiS_Pr->SiS_LVDSCRT11024x768_1 = SiS310_LVDSCRT11024x768_1; + SiS_Pr->SiS_LVDSCRT11280x1024_1 = SiS310_LVDSCRT11280x1024_1; + SiS_Pr->SiS_LVDSCRT11400x1050_1 = SiS310_LVDSCRT11400x1050_1; + SiS_Pr->SiS_LVDSCRT11600x1200_1 = SiS310_LVDSCRT11600x1200_1; + SiS_Pr->SiS_LVDSCRT1800x600_1_H = SiS310_LVDSCRT1800x600_1_H; + SiS_Pr->SiS_LVDSCRT11024x768_1_H = SiS310_LVDSCRT11024x768_1_H; + SiS_Pr->SiS_LVDSCRT11280x1024_1_H = SiS310_LVDSCRT11280x1024_1_H; + SiS_Pr->SiS_LVDSCRT11400x1050_1_H = SiS310_LVDSCRT11400x1050_1_H; + SiS_Pr->SiS_LVDSCRT11600x1200_1_H = SiS310_LVDSCRT11600x1200_1_H; + SiS_Pr->SiS_LVDSCRT1800x600_2 = SiS310_LVDSCRT1800x600_2; + SiS_Pr->SiS_LVDSCRT11024x768_2 = SiS310_LVDSCRT11024x768_2; + SiS_Pr->SiS_LVDSCRT11280x1024_2 = SiS310_LVDSCRT11280x1024_2; + SiS_Pr->SiS_LVDSCRT11400x1050_2 = SiS310_LVDSCRT11400x1050_2; + SiS_Pr->SiS_LVDSCRT11600x1200_2 = SiS310_LVDSCRT11600x1200_2; + SiS_Pr->SiS_LVDSCRT1800x600_2_H = SiS310_LVDSCRT1800x600_2_H; + SiS_Pr->SiS_LVDSCRT11024x768_2_H = SiS310_LVDSCRT11024x768_2_H; + SiS_Pr->SiS_LVDSCRT11280x1024_2_H = SiS310_LVDSCRT11280x1024_2_H; + SiS_Pr->SiS_LVDSCRT11400x1050_2_H = SiS310_LVDSCRT11400x1050_2_H; + SiS_Pr->SiS_LVDSCRT11600x1200_2_H = SiS310_LVDSCRT11600x1200_2_H; + SiS_Pr->SiS_LVDSCRT1XXXxXXX_1 = SiS310_LVDSCRT1XXXxXXX_1; + SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H = SiS310_LVDSCRT1XXXxXXX_1_H; + SiS_Pr->SiS_CHTVCRT1UNTSC = SiS310_CHTVCRT1UNTSC; + SiS_Pr->SiS_CHTVCRT1ONTSC = SiS310_CHTVCRT1ONTSC; + SiS_Pr->SiS_CHTVCRT1UPAL = SiS310_CHTVCRT1UPAL; + SiS_Pr->SiS_CHTVCRT1OPAL = SiS310_CHTVCRT1OPAL; + SiS_Pr->SiS_CHTVCRT1SOPAL = SiS310_CHTVCRT1OPAL; + + SiS_Pr->SiS_CHTVReg_UNTSC = SiS310_CHTVReg_UNTSC; + SiS_Pr->SiS_CHTVReg_ONTSC = SiS310_CHTVReg_ONTSC; + SiS_Pr->SiS_CHTVReg_UPAL = SiS310_CHTVReg_UPAL; + SiS_Pr->SiS_CHTVReg_OPAL = SiS310_CHTVReg_OPAL; + SiS_Pr->SiS_CHTVReg_UPALM = SiS310_CHTVReg_UPALM; + SiS_Pr->SiS_CHTVReg_OPALM = SiS310_CHTVReg_OPALM; + SiS_Pr->SiS_CHTVReg_UPALN = SiS310_CHTVReg_UPALN; + SiS_Pr->SiS_CHTVReg_OPALN = SiS310_CHTVReg_OPALN; + SiS_Pr->SiS_CHTVReg_SOPAL = SiS310_CHTVReg_OPAL; + + SiS_Pr->SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC; + SiS_Pr->SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC; + SiS_Pr->SiS_CHTVVCLKUPAL = SiS310_CHTVVCLKUPAL; + SiS_Pr->SiS_CHTVVCLKOPAL = SiS310_CHTVVCLKOPAL; + SiS_Pr->SiS_CHTVVCLKUPALM = SiS310_CHTVVCLKUPALM; + SiS_Pr->SiS_CHTVVCLKOPALM = SiS310_CHTVVCLKOPALM; + SiS_Pr->SiS_CHTVVCLKUPALN = SiS310_CHTVVCLKUPALN; + SiS_Pr->SiS_CHTVVCLKOPALN = SiS310_CHTVVCLKOPALN; + SiS_Pr->SiS_CHTVVCLKSOPAL = SiS310_CHTVVCLKOPAL; +} +#endif + +static void +SiSInitPtr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + switch(HwInfo->jChipType) { +#ifdef SIS315H + case SIS_315H: + case SIS_315: + case SIS_315PRO: + case SIS_550: + case SIS_650: + case SIS_740: + case SIS_330: + case SIS_661: + case SIS_741: + case SIS_660: + case SIS_760: + case SIS_761: + case SIS_340: + InitTo310Pointer(SiS_Pr, HwInfo); + break; +#endif +#ifdef SIS300 + case SIS_300: + case SIS_540: + case SIS_630: + case SIS_730: + InitTo300Pointer(SiS_Pr, HwInfo); + break; +#endif + default: + break; + } +} + +/*********************************************/ +/* HELPER: Get ModeID */ +/*********************************************/ + +#ifdef LINUX_XF86 +USHORT +SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, + int Depth, BOOLEAN FSTN, int LCDwidth, int LCDheight) +{ + USHORT ModeIndex = 0; + + switch(HDisplay) + { + case 320: + if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; + else if(VDisplay == 240) { + if(FSTN) ModeIndex = ModeIndex_320x240_FSTN[Depth]; + else ModeIndex = ModeIndex_320x240[Depth]; + } + break; + case 400: + if((!(VBFlags & CRT1_LCDA)) || ((LCDwidth >= 800) && (LCDwidth >= 600))) { + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + } + break; + case 512: + if((!(VBFlags & CRT1_LCDA)) || ((LCDwidth >= 1024) && (LCDwidth >= 768))) { + if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; + } + break; + case 640: + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; + break; + case 720: + if(VDisplay == 480) ModeIndex = ModeIndex_720x480[Depth]; + else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth]; + break; + case 768: + if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; + break; + case 800: + if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; + else if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth]; + break; + case 848: + if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; + break; + case 856: + if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth]; + break; + case 960: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth]; + else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth]; + } + break; + case 1024: + if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth]; + else if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; + else if(VGAEngine == SIS_300_VGA) { + if(VDisplay == 600) ModeIndex = ModeIndex_1024x600[Depth]; + } + break; + case 1152: + if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth]; + if(VGAEngine == SIS_300_VGA) { + if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth]; + } + break; + case 1280: + switch(VDisplay) { + case 720: + ModeIndex = ModeIndex_1280x720[Depth]; + break; + case 768: + if(VGAEngine == SIS_300_VGA) { + ModeIndex = ModeIndex_300_1280x768[Depth]; + } else { + ModeIndex = ModeIndex_310_1280x768[Depth]; + } + break; + case 800: + if(VGAEngine == SIS_315_VGA) { + ModeIndex = ModeIndex_1280x800[Depth]; + } + break; + case 960: + ModeIndex = ModeIndex_1280x960[Depth]; + break; + case 1024: + ModeIndex = ModeIndex_1280x1024[Depth]; + break; + } + break; + case 1360: + if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; + if(VGAEngine == SIS_300_VGA) { + if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth]; + } + break; + case 1400: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1050) { + ModeIndex = ModeIndex_1400x1050[Depth]; + } + } + break; + case 1600: + if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; + break; + case 1680: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; + } + break; + case 1920: + if(VDisplay == 1440) ModeIndex = ModeIndex_1920x1440[Depth]; + else if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1080) ModeIndex = ModeIndex_1920x1080[Depth]; + } + break; + case 2048: + if(VDisplay == 1536) { + if(VGAEngine == SIS_300_VGA) { + ModeIndex = ModeIndex_300_2048x1536[Depth]; + } else { + ModeIndex = ModeIndex_310_2048x1536[Depth]; + } + } + break; + } + + return(ModeIndex); +} +#endif + +USHORT +SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, + int Depth, BOOLEAN FSTN, USHORT CustomT, int LCDwidth, int LCDheight) +{ + USHORT ModeIndex = 0; + + if(VBFlags & (VB_LVDS | VB_30xBDH)) { + + switch(HDisplay) + { + case 320: + if(CustomT != CUT_PANEL848) { + if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; + else if(VDisplay == 240) { + if(!FSTN) ModeIndex = ModeIndex_320x240[Depth]; + else if(VGAEngine == SIS_315_VGA) { + ModeIndex = ModeIndex_320x240_FSTN[Depth]; + } + } + } + break; + case 400: + if(CustomT != CUT_PANEL848) { + if(!((VGAEngine == SIS_300_VGA) && (VBFlags & VB_TRUMPION))) { + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + } + } + break; + case 512: + if(CustomT != CUT_PANEL848) { + if(!((VGAEngine == SIS_300_VGA) && (VBFlags & VB_TRUMPION))) { + if(LCDwidth >= 1024 && LCDwidth != 1152 && LCDheight >= 768) { + if(VDisplay == 384) { + ModeIndex = ModeIndex_512x384[Depth]; + } + } + } + } + break; + case 640: + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + else if(VDisplay == 400) { + if(CustomT != CUT_PANEL848) ModeIndex = ModeIndex_640x400[Depth]; + } + break; + case 800: + if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; + break; + case 848: + if(CustomT == CUT_PANEL848) { + if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; + } + break; + case 1024: + if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; + else if(VGAEngine == SIS_300_VGA) { + if((VDisplay == 600) && (LCDheight == 600)) { + ModeIndex = ModeIndex_1024x600[Depth]; + } + } + break; + case 1152: + if(VGAEngine == SIS_300_VGA) { + if((VDisplay == 768) && (LCDheight == 768)) { + ModeIndex = ModeIndex_1152x768[Depth]; + } + } + break; + case 1280: + if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth]; + else if(VGAEngine == SIS_315_VGA) { + if((VDisplay == 768) && (LCDheight == 768)) { + ModeIndex = ModeIndex_310_1280x768[Depth]; + } + } + break; + case 1360: + if(VGAEngine == SIS_300_VGA) { + if(CustomT == CUT_BARCO1366) { + if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth]; + } + } + if(CustomT == CUT_PANEL848) { + if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; + } + break; + case 1400: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth]; + } + break; + case 1600: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; + } + break; + } + + } else if(VBFlags & VB_SISBRIDGE) { + + switch(HDisplay) + { + case 320: + if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; + else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth]; + break; + case 400: + if(LCDwidth >= 800 && LCDheight >= 600) { + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + } + break; + case 512: + if(LCDwidth >= 1024 && LCDheight >= 768 && LCDwidth != 1152) { + if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; + } + break; + case 640: + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; + break; + case 720: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 480) ModeIndex = ModeIndex_720x480[Depth]; + else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth]; + } + break; + case 768: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; + } + break; + case 800: + if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth]; + } + break; + case 848: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; + } + break; + case 856: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth]; + } + break; + case 960: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth]; + else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth]; + } + break; + case 1024: + if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth]; + } + break; + case 1152: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth]; + } + break; + case 1280: + switch(VDisplay) { + case 720: + ModeIndex = ModeIndex_1280x720[Depth]; + case 768: + if(VGAEngine == SIS_300_VGA) { + ModeIndex = ModeIndex_300_1280x768[Depth]; + } else { + ModeIndex = ModeIndex_310_1280x768[Depth]; + } + break; + case 800: + if(VGAEngine == SIS_315_VGA) { + ModeIndex = ModeIndex_1280x800[Depth]; + } + break; + case 960: + ModeIndex = ModeIndex_1280x960[Depth]; + break; + case 1024: + ModeIndex = ModeIndex_1280x1024[Depth]; + break; + } + break; + case 1360: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; + } + break; + case 1400: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags & (VB_301C | VB_302LV | VB_302ELV)) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth]; + } + } + break; + case 1600: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags & (VB_301C | VB_302LV | VB_302ELV)) { + if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; + } + } + break; +#ifndef VB_FORBID_CRT2LCD_OVER_1600 + case 1680: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags & (VB_301C | VB_302LV | VB_302ELV)) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; + } + } + break; +#endif + } + } + + return ModeIndex; +} + +USHORT +SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth) +{ + USHORT ModeIndex = 0; + + if(VBFlags & VB_CHRONTEL) { + + switch(HDisplay) + { + case 512: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; + } + break; + case 640: + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; + break; + case 800: + if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; + break; + case 1024: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; + } + break; + } + + } else if(VBFlags & VB_SISTVBRIDGE) { + + switch(HDisplay) + { + case 320: + if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; + else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth]; + break; + case 400: + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + break; + case 512: + if( ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR750P | TV_YPBPR1080I))) || + (VBFlags & TV_HIVISION) || + ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) { + if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; + } + break; + case 640: + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; + break; + case 720: + if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) { + if(VDisplay == 480) { + ModeIndex = ModeIndex_720x480[Depth]; + } else if(VDisplay == 576) { + if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) || + ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) + ModeIndex = ModeIndex_720x576[Depth]; + } + } + break; + case 768: + if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) { + if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) || + ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) { + if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; + } + } + break; + case 800: + if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; + else if(VDisplay == 480) { + if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { + ModeIndex = ModeIndex_800x480[Depth]; + } + } + break; + case 960: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 600) { + if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { + ModeIndex = ModeIndex_960x600[Depth]; + } + } + } + break; + case 1024: + if(VDisplay == 768) { + if(VBFlags & (VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV|VB_302ELV)) { + ModeIndex = ModeIndex_1024x768[Depth]; + } + } else if(VDisplay == 576) { + if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { + ModeIndex = ModeIndex_1024x576[Depth]; + } + } + break; + case 1280: + if(VDisplay == 720) { + if((VBFlags & TV_HIVISION) || + ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)))) { + ModeIndex = ModeIndex_1280x720[Depth]; + } + } else if(VDisplay == 1024) { + if((VBFlags & TV_HIVISION) || + ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { + ModeIndex = ModeIndex_1280x1024[Depth]; + } + } + break; + } + } + return ModeIndex; +} + +USHORT +SiS_GetModeID_VGA2(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth) +{ + USHORT ModeIndex = 0; + + if(!(VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0; + + switch(HDisplay) + { + case 320: + if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; + else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth]; + break; + case 400: + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + break; + case 512: + if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; + break; + case 640: + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; + break; + case 720: + if(VDisplay == 480) ModeIndex = ModeIndex_720x480[Depth]; + else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth]; + break; + case 768: + if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; + break; + case 800: + if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; + else if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth]; + break; + case 848: + if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; + break; + case 856: + if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth]; + break; + case 960: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth]; + else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth]; + } + break; + case 1024: + if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; + else if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth]; + break; + case 1152: + if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth]; + else if(VGAEngine == SIS_300_VGA) { + if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth]; + } + break; + case 1280: + if(VDisplay == 768) { + if(VGAEngine == SIS_300_VGA) { + ModeIndex = ModeIndex_300_1280x768[Depth]; + } else { + ModeIndex = ModeIndex_310_1280x768[Depth]; + } + } else if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth]; + else if(VDisplay == 720) ModeIndex = ModeIndex_1280x720[Depth]; + else if(VDisplay == 800) ModeIndex = ModeIndex_1280x800[Depth]; + else if(VDisplay == 960) ModeIndex = ModeIndex_1280x960[Depth]; + break; + case 1360: + if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; + break; + case 1400: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth]; + } + break; + case 1600: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags & (VB_301B|VB_301C|VB_302B)) { + if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; + } + } + break; + case 1680: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags & (VB_301B|VB_301C|VB_302B)) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; + } + } + break; + } + + return ModeIndex; +} + + +/*********************************************/ +/* HELPER: SetReg, GetReg */ +/*********************************************/ + +void +SiS_SetReg(SISIOADDRESS port, USHORT index, USHORT data) +{ + OutPortByte(port,index); + OutPortByte(port + 1,data); +} + +void +SiS_SetRegByte(SISIOADDRESS port, USHORT data) +{ + OutPortByte(port,data); +} + +void +SiS_SetRegShort(SISIOADDRESS port, USHORT data) +{ + OutPortWord(port,data); +} + +void +SiS_SetRegLong(SISIOADDRESS port, ULONG data) +{ + OutPortLong(port,data); +} + +UCHAR +SiS_GetReg(SISIOADDRESS port, USHORT index) +{ + OutPortByte(port,index); + return(InPortByte(port + 1)); +} + +UCHAR +SiS_GetRegByte(SISIOADDRESS port) +{ + return(InPortByte(port)); +} + +USHORT +SiS_GetRegShort(SISIOADDRESS port) +{ + return(InPortWord(port)); +} + +ULONG +SiS_GetRegLong(SISIOADDRESS port) +{ + return(InPortLong(port)); +} + +void +SiS_SetRegANDOR(SISIOADDRESS Port,USHORT Index,USHORT DataAND,USHORT DataOR) +{ + USHORT temp; + + temp = SiS_GetReg(Port,Index); + temp = (temp & (DataAND)) | DataOR; + SiS_SetReg(Port,Index,temp); +} + +void +SiS_SetRegAND(SISIOADDRESS Port,USHORT Index,USHORT DataAND) +{ + USHORT temp; + + temp = SiS_GetReg(Port,Index); + temp &= DataAND; + SiS_SetReg(Port,Index,temp); +} + +void +SiS_SetRegOR(SISIOADDRESS Port,USHORT Index,USHORT DataOR) +{ + USHORT temp; + + temp = SiS_GetReg(Port,Index); + temp |= DataOR; + SiS_SetReg(Port,Index,temp); +} + +/*********************************************/ +/* HELPER: DisplayOn, DisplayOff */ +/*********************************************/ + +void +SiS_DisplayOn(SiS_Private *SiS_Pr) +{ + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x01,0xDF); +} + +void +SiS_DisplayOff(SiS_Private *SiS_Pr) +{ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20); +} + + +/*********************************************/ +/* HELPER: Init Port Addresses */ +/*********************************************/ + +void +SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr) +{ + SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; + SiS_Pr->SiS_P3d4 = BaseAddr + 0x24; + SiS_Pr->SiS_P3c0 = BaseAddr + 0x10; + SiS_Pr->SiS_P3ce = BaseAddr + 0x1e; + SiS_Pr->SiS_P3c2 = BaseAddr + 0x12; + SiS_Pr->SiS_P3ca = BaseAddr + 0x1a; + SiS_Pr->SiS_P3c6 = BaseAddr + 0x16; + SiS_Pr->SiS_P3c7 = BaseAddr + 0x17; + SiS_Pr->SiS_P3c8 = BaseAddr + 0x18; + SiS_Pr->SiS_P3c9 = BaseAddr + 0x19; + SiS_Pr->SiS_P3cb = BaseAddr + 0x1b; + SiS_Pr->SiS_P3cd = BaseAddr + 0x1d; + SiS_Pr->SiS_P3da = BaseAddr + 0x2a; + SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04; /* Digital video interface registers (LCD) */ + SiS_Pr->SiS_Part2Port = BaseAddr + SIS_CRT2_PORT_10; /* 301 TV Encoder registers */ + SiS_Pr->SiS_Part3Port = BaseAddr + SIS_CRT2_PORT_12; /* 301 Macrovision registers */ + SiS_Pr->SiS_Part4Port = BaseAddr + SIS_CRT2_PORT_14; /* 301 VGA2 (and LCD) registers */ + SiS_Pr->SiS_Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2; /* 301 palette address port registers */ + SiS_Pr->SiS_DDC_Port = BaseAddr + 0x14; /* DDC Port ( = P3C4, SR11/0A) */ + SiS_Pr->SiS_VidCapt = BaseAddr + SIS_VIDEO_CAPTURE; + SiS_Pr->SiS_VidPlay = BaseAddr + SIS_VIDEO_PLAYBACK; +} + +/*********************************************/ +/* HELPER: GetSysFlags */ +/*********************************************/ + +static void +SiS_GetSysFlags(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + unsigned char cr5f, temp1, temp2; + + /* 661 and newer: NEVER write non-zero to SR11[7:4] */ + /* (SR11 is used for DDC and in enable/disablebridge) */ + SiS_Pr->SiS_SensibleSR11 = FALSE; + SiS_Pr->SiS_MyCR63 = 0x63; + if(HwInfo->jChipType >= SIS_330) { + SiS_Pr->SiS_MyCR63 = 0x53; + if(HwInfo->jChipType >= SIS_661) { + SiS_Pr->SiS_SensibleSR11 = TRUE; + } + } + + /* You should use the macros, not these flags directly */ + + SiS_Pr->SiS_SysFlags = 0; + if(HwInfo->jChipType == SIS_650) { + cr5f = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0; + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x5c,0x07); + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8; + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x5c,0xf8); + temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8; + if((!temp1) || (temp2)) { + switch(cr5f) { + case 0x80: + case 0x90: + case 0xc0: + SiS_Pr->SiS_SysFlags |= SF_IsM650; break; + case 0xa0: + case 0xb0: + case 0xe0: + SiS_Pr->SiS_SysFlags |= SF_Is651; break; + } + } else { + switch(cr5f) { + case 0x90: + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8; + switch(temp1) { + case 0x00: SiS_Pr->SiS_SysFlags |= SF_IsM652; break; + case 0x40: SiS_Pr->SiS_SysFlags |= SF_IsM653; break; + default: SiS_Pr->SiS_SysFlags |= SF_IsM650; break; + } + break; + case 0xb0: + SiS_Pr->SiS_SysFlags |= SF_Is652; break; + default: + SiS_Pr->SiS_SysFlags |= SF_IsM650; break; + } + } + } + if(HwInfo->jChipType == SIS_760) { + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78); + if(temp1 & 0x30) SiS_Pr->SiS_SysFlags |= SF_760LFB; + } +} + +/*********************************************/ +/* HELPER: Init PCI & Engines */ +/*********************************************/ + +static void +SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + switch(HwInfo->jChipType) { + case SIS_300: + case SIS_540: + case SIS_630: + case SIS_730: + /* Set - PCI LINEAR ADDRESSING ENABLE (0x80) + * - RELOCATED VGA IO (0x20) + * - MMIO ENABLE (0x1) + */ + SiS_SetReg(SiS_Pr->SiS_P3c4,0x20,0xa1); + /* - Enable 2D (0x40) + * - Enable 3D (0x02) + * - Enable 3D Vertex command fetch (0x10) ? + * - Enable 3D command parser (0x08) ? + */ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x5A); + break; + case SIS_315H: + case SIS_315: + case SIS_315PRO: + case SIS_650: + case SIS_740: + case SIS_330: + case SIS_661: + case SIS_741: + case SIS_660: + case SIS_760: + case SIS_761: + case SIS_340: + SiS_SetReg(SiS_Pr->SiS_P3c4,0x20,0xa1); + /* - Enable 2D (0x40) + * - Enable 3D (0x02) + * - Enable 3D vertex command fetch (0x10) + * - Enable 3D command parser (0x08) + * - Enable 3D G/L transformation engine (0x80) + */ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0xDA); + break; + case SIS_550: + SiS_SetReg(SiS_Pr->SiS_P3c4,0x20,0xa1); + /* No 3D engine ! */ + /* - Enable 2D (0x40) + */ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x40); + } +} + +/*********************************************/ +/* HELPER: SetLVDSetc */ +/*********************************************/ + +void +SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT temp; + + SiS_Pr->SiS_IF_DEF_LVDS = 0; + SiS_Pr->SiS_IF_DEF_TRUMPION = 0; + SiS_Pr->SiS_IF_DEF_CH70xx = 0; + SiS_Pr->SiS_IF_DEF_DSTN = 0; + SiS_Pr->SiS_IF_DEF_FSTN = 0; + SiS_Pr->SiS_IF_DEF_CONEX = 0; + + SiS_Pr->SiS_ChrontelInit = 0; + + /* Check for SiS30x first */ + temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); + if((temp == 1) || (temp == 2)) return; + + switch(HwInfo->jChipType) { +#ifdef SIS300 + case SIS_540: + case SIS_630: + case SIS_730: + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); + temp = (temp & 0x0E) >> 1; + if((temp >= 2) && (temp <= 5)) SiS_Pr->SiS_IF_DEF_LVDS = 1; + if(temp == 3) SiS_Pr->SiS_IF_DEF_TRUMPION = 1; + if((temp == 4) || (temp == 5)) { + /* Save power status (and error check) - UNUSED */ + SiS_Pr->SiS_Backup70xx = SiS_GetCH700x(SiS_Pr, 0x0e); + SiS_Pr->SiS_IF_DEF_CH70xx = 1; + } + break; +#endif +#ifdef SIS315H + case SIS_550: + case SIS_650: + case SIS_740: + case SIS_330: + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); + temp = (temp & 0x0E) >> 1; + if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1; + if(temp == 3) SiS_Pr->SiS_IF_DEF_CH70xx = 2; + break; + case SIS_661: + case SIS_741: + case SIS_660: + case SIS_760: + case SIS_761: + case SIS_340: + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + temp = (temp & 0xe0) >> 5; + if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1; + if(temp == 3) SiS_Pr->SiS_IF_DEF_CH70xx = 2; + if(temp == 4) SiS_Pr->SiS_IF_DEF_CONEX = 1; /* Not yet supported */ + break; +#endif + default: + break; + } +} + +/*********************************************/ +/* HELPER: Enable DSTN/FSTN */ +/*********************************************/ + +void +SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable) +{ + SiS_Pr->SiS_IF_DEF_DSTN = enable ? 1 : 0; +} + +void +SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable) +{ + SiS_Pr->SiS_IF_DEF_FSTN = enable ? 1 : 0; +} + +/*********************************************/ +/* HELPER: Determine ROM usage */ +/*********************************************/ + +BOOLEAN +SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT romversoffs, romvmaj = 1, romvmin = 0; + + if(HwInfo->jChipType >= SIS_761) { + /* I very much assume 761 and 340 will use new layout */ + return TRUE; + } else if(HwInfo->jChipType >= SIS_661) { + if((ROMAddr[0x1a] == 'N') && + (ROMAddr[0x1b] == 'e') && + (ROMAddr[0x1c] == 'w') && + (ROMAddr[0x1d] == 'V')) { + return TRUE; + } + romversoffs = ROMAddr[0x16] | (ROMAddr[0x17] << 8); + if(romversoffs) { + if((ROMAddr[romversoffs+1] == '.') || (ROMAddr[romversoffs+4] == '.')) { + romvmaj = ROMAddr[romversoffs] - '0'; + romvmin = ((ROMAddr[romversoffs+2] -'0') * 10) + (ROMAddr[romversoffs+3] - '0'); + } + } + if((romvmaj != 0) || (romvmin >= 92)) { + return TRUE; + } + } else if(IS_SIS650740) { + if((ROMAddr[0x1a] == 'N') && + (ROMAddr[0x1b] == 'e') && + (ROMAddr[0x1c] == 'w') && + (ROMAddr[0x1d] == 'V')) { + return TRUE; + } + } + return FALSE; +} + +static void +SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT romptr = 0; + + SiS_Pr->SiS_UseROM = FALSE; + SiS_Pr->SiS_ROMNew = FALSE; + + if((ROMAddr) && (HwInfo->UseROM)) { + if(HwInfo->jChipType == SIS_300) { + /* 300: We check if the code starts below 0x220 by + * checking the jmp instruction at the beginning + * of the BIOS image. + */ + if((ROMAddr[3] == 0xe9) && ((ROMAddr[5] << 8) | ROMAddr[4]) > 0x21a) + SiS_Pr->SiS_UseROM = TRUE; + } else if(HwInfo->jChipType < SIS_315H) { + /* Sony's VAIO BIOS 1.09 follows the standard, so perhaps + * the others do as well + */ + SiS_Pr->SiS_UseROM = TRUE; + } else { + /* 315/330 series stick to the standard(s) */ + SiS_Pr->SiS_UseROM = TRUE; + if((SiS_Pr->SiS_ROMNew = SiSDetermineROMLayout661(SiS_Pr, HwInfo))) { + SiS_Pr->SiS_EMIOffset = 14; + SiS_Pr->SiS661LCD2TableSize = 36; + /* Find out about LCD data table entry size */ + if((romptr = SISGETROMW(0x0102))) { + if(ROMAddr[romptr + (32 * 16)] == 0xff) + SiS_Pr->SiS661LCD2TableSize = 32; + else if(ROMAddr[romptr + (34 * 16)] == 0xff) + SiS_Pr->SiS661LCD2TableSize = 34; + else if(ROMAddr[romptr + (36 * 16)] == 0xff) /* 0.94 */ + SiS_Pr->SiS661LCD2TableSize = 36; + else if( (ROMAddr[romptr + (38 * 16)] == 0xff) || /* 2.00.00 - 2.02.00 */ + (ROMAddr[0x6F] & 0x01) ) { /* 2.03.00+ */ + SiS_Pr->SiS661LCD2TableSize = 38; + SiS_Pr->SiS_EMIOffset = 16; + } + } + } + } + } +} + +/*********************************************/ +/* HELPER: SET SEGMENT REGISTERS */ +/*********************************************/ + +static void +SiS_SetSegRegLower(SiS_Private *SiS_Pr, USHORT value) +{ + USHORT temp; + + value &= 0x00ff; + temp = SiS_GetRegByte(SiS_Pr->SiS_P3cb) & 0xf0; + temp |= (value >> 4); + SiS_SetRegByte(SiS_Pr->SiS_P3cb, temp); + temp = SiS_GetRegByte(SiS_Pr->SiS_P3cd) & 0xf0; + temp |= (value & 0x0f); + SiS_SetRegByte(SiS_Pr->SiS_P3cd, temp); +} + +static void +SiS_SetSegRegUpper(SiS_Private *SiS_Pr, USHORT value) +{ + USHORT temp; + + value &= 0x00ff; + temp = SiS_GetRegByte(SiS_Pr->SiS_P3cb) & 0x0f; + temp |= (value & 0xf0); + SiS_SetRegByte(SiS_Pr->SiS_P3cb, temp); + temp = SiS_GetRegByte(SiS_Pr->SiS_P3cd) & 0x0f; + temp |= (value << 4); + SiS_SetRegByte(SiS_Pr->SiS_P3cd, temp); +} + +static void +SiS_SetSegmentReg(SiS_Private *SiS_Pr, USHORT value) +{ + SiS_SetSegRegLower(SiS_Pr, value); + SiS_SetSegRegUpper(SiS_Pr, value); +} + +static void +SiS_ResetSegmentReg(SiS_Private *SiS_Pr) +{ + SiS_SetSegmentReg(SiS_Pr, 0); +} + +static void +SiS_SetSegmentRegOver(SiS_Private *SiS_Pr, USHORT value) +{ + USHORT temp = value >> 8; + + temp &= 0x07; + temp |= (temp << 4); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x1d,temp); + SiS_SetSegmentReg(SiS_Pr, value); +} + +static void +SiS_ResetSegmentRegOver(SiS_Private *SiS_Pr) +{ + SiS_SetSegmentRegOver(SiS_Pr, 0); +} + +static void +SiS_ResetSegmentRegisters(SiS_Private *SiS_Pr,PSIS_HW_INFO HwInfo) +{ + if((IS_SIS65x) || (HwInfo->jChipType >= SIS_661)) { + SiS_ResetSegmentReg(SiS_Pr); + SiS_ResetSegmentRegOver(SiS_Pr); + } +} + +/*********************************************/ +/* HELPER: GetVBType */ +/*********************************************/ + +void +SiS_GetVBType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag=0, rev=0, nolcd=0, p4_0f, p4_25, p4_27; + + SiS_Pr->SiS_VBType = 0; + + if((SiS_Pr->SiS_IF_DEF_LVDS) || (SiS_Pr->SiS_IF_DEF_CONEX)) + return; + + flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); + + if(flag > 3) return; + + rev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); + + if(flag >= 2) { + SiS_Pr->SiS_VBType = VB_SIS302B; + } else if(flag == 1) { + if(rev >= 0xC0) { + SiS_Pr->SiS_VBType = VB_SIS301C; + } else if(rev >= 0xB0) { + SiS_Pr->SiS_VBType = VB_SIS301B; + /* Check if 30xB DH version (no LCD support, use Panel Link instead) */ + nolcd = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x23); + if(!(nolcd & 0x02)) SiS_Pr->SiS_VBType |= VB_NoLCD; + } else { + SiS_Pr->SiS_VBType = VB_SIS301; + } + } + if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS301C | VB_SIS302B)) { + if(rev >= 0xE0) { + flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x39); + if(flag == 0xff) SiS_Pr->SiS_VBType = VB_SIS302LV; + else SiS_Pr->SiS_VBType = VB_SIS301C; /* VB_SIS302ELV; */ + } else if(rev >= 0xD0) { + SiS_Pr->SiS_VBType = VB_SIS301LV; + } + } + if(SiS_Pr->SiS_VBType & (VB_301C | VB_301LV | VB_302LV | VB_302ELV)) { + p4_0f = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0f); + p4_25 = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x25); + p4_27 = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x27); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x0f,0x7f); + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x25,0x08); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,0xfd); + if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x08) { + SiS_Pr->SiS_VBType |= VB_UMC; + } + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x27,p4_27); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x25,p4_25); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0f,p4_0f); + } +} + +/*********************************************/ +/* HELPER: Check RAM size */ +/*********************************************/ + +#ifdef LINUX_KERNEL +static BOOLEAN +SiS_CheckMemorySize(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT AdapterMemSize = HwInfo->ulVideoMemorySize / (1024*1024); + USHORT memorysize,modeflag; + + if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + } else { + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + } + + memorysize = modeflag & MemoryInfoFlag; + memorysize >>= MemorySizeShift; /* Get required memory size */ + memorysize++; + + if(AdapterMemSize < memorysize) return FALSE; + return TRUE; +} +#endif + +/*********************************************/ +/* HELPER: Get DRAM type */ +/*********************************************/ + +#ifdef SIS315H +static UCHAR +SiS_Get310DRAMType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR data, temp; + + if((*SiS_Pr->pSiS_SoftSetting) & SoftDRAMType) { + data = (*SiS_Pr->pSiS_SoftSetting) & 0x03; + } else { + if(HwInfo->jChipType >= SIS_340) { + /* TODO */ + data = 0; + } if(HwInfo->jChipType >= SIS_661) { + data = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x07; + if(SiS_Pr->SiS_ROMNew) { + data = ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0xc0) >> 6); + } + } else if(IS_SIS550650740) { + data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x07; + } else { /* 315, 330 */ + data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3a) & 0x03; + if(HwInfo->jChipType == SIS_330) { + if(data > 1) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0x30; + switch(temp) { + case 0x00: data = 1; break; + case 0x10: data = 3; break; + case 0x20: data = 3; break; + case 0x30: data = 2; break; + } + } else { + data = 0; + } + } + } + } + + return data; +} + +static USHORT +SiS_GetMCLK(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT index; + + index = SiS_Get310DRAMType(SiS_Pr, HwInfo); + if(HwInfo->jChipType >= SIS_661) { + if(SiS_Pr->SiS_ROMNew) { + return((USHORT)(SISGETROMW((0x90 + (index * 5) + 3)))); + } + return(SiS_Pr->SiS_MCLKData_0[index].CLOCK); + } else if(index >= 4) { + index -= 4; + return(SiS_Pr->SiS_MCLKData_1[index].CLOCK); + } else { + return(SiS_Pr->SiS_MCLKData_0[index].CLOCK); + } +} +#endif + +/*********************************************/ +/* HELPER: ClearBuffer */ +/*********************************************/ + +#ifdef LINUX_KERNEL +static void +SiS_ClearBuffer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) +{ + UCHAR SISIOMEMTYPE *VideoMemoryAddress = HwInfo->pjVideoMemoryAddress; + ULONG AdapterMemorySize = HwInfo->ulVideoMemorySize; + USHORT SISIOMEMTYPE *pBuffer; + int i; + + if(SiS_Pr->SiS_ModeType >= ModeEGA) { + if(ModeNo > 0x13) { + SiS_SetMemory(VideoMemoryAddress, AdapterMemorySize, 0); + } else { + pBuffer = (USHORT SISIOMEMTYPE *)VideoMemoryAddress; + for(i=0; i<0x4000; i++) writew(0x0000, &pBuffer[i]); + } + } else { + if(SiS_Pr->SiS_ModeType < ModeCGA) { + pBuffer = (USHORT SISIOMEMTYPE *)VideoMemoryAddress; + for(i=0; i<0x4000; i++) writew(0x0720, &pBuffer[i]); + } else { + SiS_SetMemory(VideoMemoryAddress, 0x8000, 0); + } + } +} +#endif + +/*********************************************/ +/* HELPER: SearchModeID */ +/*********************************************/ + +BOOLEAN +SiS_SearchModeID(SiS_Private *SiS_Pr, USHORT *ModeNo, USHORT *ModeIdIndex) +{ + UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO; + + if(*ModeNo <= 0x13) { + + if((*ModeNo) <= 0x05) (*ModeNo) |= 0x01; + + for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) { + if(SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == (*ModeNo)) break; + if(SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == 0xFF) return FALSE; + } + + if(*ModeNo == 0x07) { + if(VGAINFO & 0x10) (*ModeIdIndex)++; /* 400 lines */ + /* else 350 lines */ + } + if(*ModeNo <= 0x03) { + if(!(VGAINFO & 0x80)) (*ModeIdIndex)++; + if(VGAINFO & 0x10) (*ModeIdIndex)++; /* 400 lines */ + /* else 350 lines */ + } + /* else 200 lines */ + + } else { + + for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) { + if(SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) break; + if(SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF) return FALSE; + } + + } + return TRUE; +} + +/*********************************************/ +/* HELPER: GetModePtr */ +/*********************************************/ + +UCHAR +SiS_GetModePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex) +{ + UCHAR index; + + if(ModeNo <= 0x13) { + index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_StTableIndex; + } else { + if(SiS_Pr->SiS_ModeType <= ModeEGA) index = 0x1B; + else index = 0x0F; + } + return index; +} + +/*********************************************/ +/* HELPER: LowModeTests */ +/*********************************************/ + +static BOOLEAN +SiS_DoLowModeTest(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo) +{ + USHORT temp,temp1,temp2; + + if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12)) + return(TRUE); + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x11); + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x11,0x80); + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,0x55); + temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,temp1); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x11,temp); + if((HwInfo->jChipType >= SIS_315H) || + (HwInfo->jChipType == SIS_300)) { + if(temp2 == 0x55) return(FALSE); + else return(TRUE); + } else { + if(temp2 != 0x55) return(TRUE); + else { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); + return(FALSE); + } + } +} + +static void +SiS_SetLowModeTest(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo) +{ + if(SiS_DoLowModeTest(SiS_Pr, ModeNo, HwInfo)) { + SiS_Pr->SiS_SetFlag |= LowModeTests; + } +} + +/*********************************************/ +/* HELPER: ENABLE CRT1 */ +/*********************************************/ + +static void +SiS_SetupCR5x(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(IS_SIS650) { + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); + if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20); + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); + } + } else if(IS_SIS661741660760) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x61,0xf7); + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); + if(!SiS_Pr->SiS_ROMNew) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef); + } + } +} + +static void +SiS_HandleCRT1(SiS_Private *SiS_Pr) +{ + /* Enable CRT1 gating */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0xbf); +#if 0 + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x01)) { + if((SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x0a) || + (SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x01)) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0x40); + } + } +#endif +} + +/*********************************************/ +/* HELPER: GetColorDepth */ +/*********************************************/ + +USHORT +SiS_GetColorDepth(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT ColorDepth[6] = { 1, 2, 4, 4, 6, 8}; + SHORT index; + USHORT modeflag; + + /* Do NOT check UseCustomMode, will skrew up FIFO */ + if(ModeNo == 0xfe) { + modeflag = SiS_Pr->CModeFlag; + } else { + if(ModeNo <= 0x13) + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + else + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + index = (modeflag & ModeTypeMask) - ModeEGA; + if(index < 0) index = 0; + return(ColorDepth[index]); +} + +/*********************************************/ +/* HELPER: GetOffset */ +/*********************************************/ + +USHORT +SiS_GetOffset(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, + USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo) +{ + USHORT xres, temp, colordepth, infoflag; + + if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + xres = SiS_Pr->CHDisplay; + } else { + infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + xres = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes; + } + + colordepth = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex); + + temp = xres / 16; + if(infoflag & InterlaceMode) temp <<= 1; + temp *= colordepth; + if(xres % 16) { + colordepth >>= 1; + temp += colordepth; + } + + return(temp); +} + +/*********************************************/ +/* SEQ */ +/*********************************************/ + +static void +SiS_SetSeqRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, PSIS_HW_INFO HwInfo) +{ + UCHAR SRdata; + USHORT i; + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x03); /* Set SR0 */ + + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0]; + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SRdata |= 0x01; + } + if(HwInfo->jChipType >= SIS_661) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SRdata |= 0x01; /* 8 dot clock */ + } + } + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_VBType & VB_NoLCD) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SRdata |= 0x01; /* 8 dot clock */ + } + } + } + } + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SRdata |= 0x01; /* 8 dot clock */ + } + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SRdata |= 0x01; /* 8 dot clock */ + } + } + } + + SRdata |= 0x20; /* screen off */ + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x01,SRdata); + + for(i = 2; i <= 4; i++) { + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1]; + SiS_SetReg(SiS_Pr->SiS_P3c4,i,SRdata); + } +} + +/*********************************************/ +/* MISC */ +/*********************************************/ + +static void +SiS_SetMiscRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, PSIS_HW_INFO HwInfo) +{ + UCHAR Miscdata; + + Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC; + + if(HwInfo->jChipType < SIS_661) { + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + Miscdata |= 0x0C; + } + } + } + + SiS_SetRegByte(SiS_Pr->SiS_P3c2,Miscdata); +} + +/*********************************************/ +/* CRTC */ +/*********************************************/ + +static void +SiS_SetCRTCRegs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT StandTableIndex) +{ + UCHAR CRTCdata; + USHORT i; + + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); /* Unlock CRTC */ + + for(i = 0; i <= 0x18; i++) { + CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; + SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata); /* Set CRTC(3d4) */ + } + if(HwInfo->jChipType >= SIS_661) { + SiS_SetupCR5x(SiS_Pr, HwInfo); + for(i = 0x13; i <= 0x14; i++) { + CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; + SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata); + } + } else if( ( (HwInfo->jChipType == SIS_630) || + (HwInfo->jChipType == SIS_730) ) && + (HwInfo->jChipRevision >= 0x30) ) { /* for 630S0 */ + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x18,0xFE); + } + } + } +} + +/*********************************************/ +/* ATT */ +/*********************************************/ + +static void +SiS_SetATTRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, + PSIS_HW_INFO HwInfo) +{ + UCHAR ARdata; + USHORT i; + + for(i = 0; i <= 0x13; i++) { + ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i]; +#if 0 + if((i <= 0x0f) || (i == 0x11)) { + if(ds:489 & 0x08) { + continue; + } + } +#endif + if(i == 0x13) { + /* Pixel shift. If screen on LCD or TV is shifted left or right, + * this might be the cause. + */ + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ARdata=0; + } + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0; + } + } + } + if(HwInfo->jChipType >= SIS_661) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0; + } + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(HwInfo->jChipType >= SIS_315H) { + if(IS_SIS550650740660) { + /* 315, 330 don't do this */ + if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0; + } else { + ARdata = 0; + } + } + } else { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0; + } + } + } + SiS_GetRegByte(SiS_Pr->SiS_P3da); /* reset 3da */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,i); /* set index */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,ARdata); /* set data */ + } + SiS_GetRegByte(SiS_Pr->SiS_P3da); /* reset 3da */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x14); /* set index */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x00); /* set data */ + + SiS_GetRegByte(SiS_Pr->SiS_P3da); + SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x20); /* Enable Attribute */ + SiS_GetRegByte(SiS_Pr->SiS_P3da); +} + +/*********************************************/ +/* GRC */ +/*********************************************/ + +static void +SiS_SetGRCRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex) +{ + UCHAR GRdata; + USHORT i; + + for(i = 0; i <= 0x08; i++) { + GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; + SiS_SetReg(SiS_Pr->SiS_P3ce,i,GRdata); + } + + if(SiS_Pr->SiS_ModeType > ModeVGA) { + /* 256 color disable */ + SiS_SetRegAND(SiS_Pr->SiS_P3ce,0x05,0xBF); + } +} + +/*********************************************/ +/* CLEAR EXTENDED REGISTERS */ +/*********************************************/ + +static void +SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) +{ + USHORT i; + + for(i = 0x0A; i <= 0x0E; i++) { + SiS_SetReg(SiS_Pr->SiS_P3c4,i,0x00); + } + + if(HwInfo->jChipType >= SIS_315H) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x37,0xFE); + if(ModeNo <= 0x13) { + if(ModeNo == 0x06 || ModeNo >= 0x0e) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x0e,0x20); + } + } + } +} + +/*********************************************/ +/* RESET VCLK */ +/*********************************************/ + +static void +SiS_ResetCRT1VCLK(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(HwInfo->jChipType >= SIS_315H) { + if(HwInfo->jChipType < SIS_661) { + if(SiS_Pr->SiS_IF_DEF_LVDS == 0) return; + } + } else { + if((SiS_Pr->SiS_IF_DEF_LVDS == 0) && + (!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) { + return; + } + } + + if(HwInfo->jChipType >= SIS_315H) { + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xCF,0x20); + } else { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x20); + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[1].SR2B); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[1].SR2C); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80); + if(HwInfo->jChipType >= SIS_315H) { + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x10); + } else { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x10); + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[0].SR2B); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[0].SR2C); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80); +} + +/*********************************************/ +/* SYNC */ +/*********************************************/ + +static void +SiS_SetCRT1Sync(SiS_Private *SiS_Pr, USHORT RefreshRateTableIndex) +{ + USHORT sync; + + if(SiS_Pr->UseCustomMode) { + sync = SiS_Pr->CInfoFlag >> 8; + } else { + sync = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag >> 8; + } + + sync &= 0xC0; + sync |= 0x2f; + SiS_SetRegByte(SiS_Pr->SiS_P3c2,sync); +} + +/*********************************************/ +/* CRTC/2 */ +/*********************************************/ + +static void +SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_INFO HwInfo) +{ + UCHAR index; + USHORT temp,i,j,modeflag; + + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); /* unlock cr0-7 */ + + if(SiS_Pr->UseCustomMode) { + + modeflag = SiS_Pr->CModeFlag; + + for(i=0,j=0;i<=7;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); + } + for(j=0x10;i<=10;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); + } + for(j=0x15;i<=12;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); + } + for(j=0x0A;i<=15;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->CCRT1CRTC[i]); + } + + temp = SiS_Pr->CCRT1CRTC[16] & 0xE0; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp); + + temp = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5; + if(modeflag & DoubleScanMode) temp |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp); + + } else { + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + + for(i=0,j=0;i<=7;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); + } + for(j=0x10;i<=10;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); + } + for(j=0x15;i<=12;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); + } + for(j=0x0A;i<=15;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); + } + + temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp); + + temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5; + if(modeflag & DoubleScanMode) temp |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp); + + } + + if(SiS_Pr->SiS_ModeType > ModeVGA) SiS_SetReg(SiS_Pr->SiS_P3d4,0x14,0x4F); +} + +/*********************************************/ +/* OFFSET & PITCH */ +/*********************************************/ +/* (partly overruled by SetPitch() in XF86) */ +/*********************************************/ + +static void +SiS_SetCRT1Offset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_INFO HwInfo) +{ + USHORT temp, DisplayUnit, infoflag; + + if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + } else { + infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + } + + DisplayUnit = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex, + RefreshRateTableIndex,HwInfo); + + temp = (DisplayUnit >> 8) & 0x0f; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,temp); + + temp = DisplayUnit & 0xFF; + SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,temp); + + if(infoflag & InterlaceMode) DisplayUnit >>= 1; + + DisplayUnit <<= 5; + temp = (DisplayUnit & 0xff00) >> 8; + if(DisplayUnit & 0xff) temp++; + temp++; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x10,temp); +} + +/*********************************************/ +/* VCLK */ +/*********************************************/ + +static void +SiS_SetCRT1VCLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex) +{ + USHORT index=0, clka, clkb; + + if(SiS_Pr->UseCustomMode) { + clka = SiS_Pr->CSR2B; + clkb = SiS_Pr->CSR2C; + } else { + index = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + clka = SiS_Pr->SiS_VBVCLKData[index].Part4_A; + clkb = SiS_Pr->SiS_VBVCLKData[index].Part4_B; + } else { + clka = SiS_Pr->SiS_VCLKData[index].SR2B; + clkb = SiS_Pr->SiS_VCLKData[index].SR2C; + } + } + + if(HwInfo->jChipType >= SIS_315H) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF); + } else { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x00); + } + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,clka); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,clkb); + + if(HwInfo->jChipType >= SIS_315H) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x01); + } else { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80); + } +} + +/*********************************************/ +/* FIFO */ +/*********************************************/ + +#ifdef SIS300 +static USHORT +SiS_DoCalcDelay(SiS_Private *SiS_Pr, USHORT MCLK, USHORT VCLK, USHORT colordepth, USHORT key) +{ + const UCHAR ThLowA[] = { 61, 3,52, 5,68, 7,100,11, + 43, 3,42, 5,54, 7, 78,11, + 34, 3,37, 5,47, 7, 67,11 }; + + const UCHAR ThLowB[] = { 81, 4,72, 6,88, 8,120,12, + 55, 4,54, 6,66, 8, 90,12, + 42, 4,45, 6,55, 8, 75,12 }; + + const UCHAR ThTiming[] = { 1, 2, 2, 3, 0, 1, 1, 2 }; + + USHORT tempah, tempal, tempcl, tempbx, temp; + ULONG longtemp; + + tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18); + tempah &= 0x62; + tempah >>= 1; + tempal = tempah; + tempah >>= 3; + tempal |= tempah; + tempal &= 0x07; + tempcl = ThTiming[tempal]; + tempbx = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16); + tempbx >>= 6; + tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); + tempah >>= 4; + tempah &= 0x0c; + tempbx |= tempah; + tempbx <<= 1; + if(key == 0) { + tempal = ThLowA[tempbx + 1]; + tempal *= tempcl; + tempal += ThLowA[tempbx]; + } else { + tempal = ThLowB[tempbx + 1]; + tempal *= tempcl; + tempal += ThLowB[tempbx]; + } + longtemp = tempal * VCLK * colordepth; + temp = longtemp % (MCLK * 16); + longtemp /= (MCLK * 16); + if(temp) longtemp++; + return((USHORT)longtemp); +} + +static USHORT +SiS_CalcDelay(SiS_Private *SiS_Pr, USHORT VCLK, USHORT colordepth, USHORT MCLK) +{ + USHORT tempax, tempbx; + + tempbx = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 0); + tempax = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 1); + if(tempax < 4) tempax = 4; + tempax -= 4; + if(tempbx < tempax) tempbx = tempax; + return(tempbx); +} + +static void +SiS_SetCRT1FIFO_300(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo, + USHORT RefreshRateTableIndex) +{ + USHORT ThresholdLow = 0; + USHORT index, VCLK, MCLK, colorth=0; + USHORT tempah, temp; + + if(ModeNo > 0x13) { + + if(SiS_Pr->UseCustomMode) { + VCLK = SiS_Pr->CSRClock; + } else { + index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + index &= 0x3F; + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; /* Get VCLK */ + } + + switch (SiS_Pr->SiS_ModeType - ModeEGA) { /* Get half colordepth */ + case 0 : colorth = 1; break; + case 1 : colorth = 1; break; + case 2 : colorth = 2; break; + case 3 : colorth = 2; break; + case 4 : colorth = 3; break; + case 5 : colorth = 4; break; + } + + index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3A); + index &= 0x07; + MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK; /* Get MCLK */ + + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + tempah &= 0xc3; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3c,tempah); + + do { + ThresholdLow = SiS_CalcDelay(SiS_Pr, VCLK, colorth, MCLK); + ThresholdLow++; + if(ThresholdLow < 0x13) break; + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x16,0xfc); + ThresholdLow = 0x13; + tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16); + tempah >>= 6; + if(!(tempah)) break; + tempah--; + tempah <<= 6; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3f,tempah); + } while(0); + + } else ThresholdLow = 2; + + /* Write CRT/CPU threshold low, CRT/Engine threshold high */ + temp = (ThresholdLow << 4) | 0x0f; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,temp); + + temp = (ThresholdLow & 0x10) << 1; + if(ModeNo > 0x13) temp |= 0x40; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0f,0x9f,temp); + + /* What is this? */ + SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09); + + /* Write CRT/CPU threshold high */ + temp = ThresholdLow + 3; + if(temp > 0x0f) temp = 0x0f; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x09,temp); +} + +static USHORT +SiS_CalcDelay2(SiS_Private *SiS_Pr, UCHAR key, PSIS_HW_INFO HwInfo) +{ + USHORT data,index; + const UCHAR LatencyFactor[] = { + 97, 88, 86, 79, 77, 00, /*; 64 bit BQ=2 */ + 00, 87, 85, 78, 76, 54, /*; 64 bit BQ=1 */ + 97, 88, 86, 79, 77, 00, /*; 128 bit BQ=2 */ + 00, 79, 77, 70, 68, 48, /*; 128 bit BQ=1 */ + 80, 72, 69, 63, 61, 00, /*; 64 bit BQ=2 */ + 00, 70, 68, 61, 59, 37, /*; 64 bit BQ=1 */ + 86, 77, 75, 68, 66, 00, /*; 128 bit BQ=2 */ + 00, 68, 66, 59, 57, 37 /*; 128 bit BQ=1 */ + }; + const UCHAR LatencyFactor730[] = { + 69, 63, 61, + 86, 79, 77, + 103, 96, 94, + 120,113,111, + 137,130,128, /* --- Table ends with this entry, data below */ + 137,130,128, /* to avoid using illegal values */ + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + }; + + if(HwInfo->jChipType == SIS_730) { + index = ((key & 0x0f) * 3) + ((key & 0xC0) >> 6); + data = LatencyFactor730[index]; + } else { + index = (key & 0xE0) >> 5; + if(key & 0x10) index +=6; + if(!(key & 0x01)) index += 24; + data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); + if(data & 0x0080) index += 12; + data = LatencyFactor[index]; + } + return(data); +} + +static void +SiS_SetCRT1FIFO_630(SiS_Private *SiS_Pr, USHORT ModeNo, + PSIS_HW_INFO HwInfo, + USHORT RefreshRateTableIndex) +{ + USHORT i,index,data,VCLK,MCLK,colorth=0; + ULONG B,eax,bl,data2; + USHORT ThresholdLow=0; + UCHAR FQBQData[]= { + 0x01,0x21,0x41,0x61,0x81, + 0x31,0x51,0x71,0x91,0xb1, + 0x00,0x20,0x40,0x60,0x80, + 0x30,0x50,0x70,0x90,0xb0, + 0xFF + }; + UCHAR FQBQData730[]= { + 0x34,0x74,0xb4, + 0x23,0x63,0xa3, + 0x12,0x52,0x92, + 0x01,0x41,0x81, + 0x00,0x40,0x80, + 0xff + }; + + i=0; + if(ModeNo > 0x13) { + if(SiS_Pr->UseCustomMode) { + VCLK = SiS_Pr->CSRClock; + } else { + index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + index &= 0x3F; + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; /* Get VCLK */ + } + + index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1A); + index &= 0x07; + MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK; /* Get MCLK */ + + data2 = SiS_Pr->SiS_ModeType - ModeEGA; /* Get half colordepth */ + switch (data2) { + case 0 : colorth = 1; break; + case 1 : colorth = 1; break; + case 2 : colorth = 2; break; + case 3 : colorth = 2; break; + case 4 : colorth = 3; break; + case 5 : colorth = 4; break; + } + + if(HwInfo->jChipType == SIS_730) { + + do { + B = SiS_CalcDelay2(SiS_Pr, FQBQData730[i], HwInfo) * VCLK * colorth; + bl = B / (MCLK * 16); + + if(B == bl * 16 * MCLK) { + bl = bl + 1; + } else { + bl = bl + 2; + } + + if(bl > 0x13) { + if(FQBQData730[i+1] == 0xFF) { + ThresholdLow = 0x13; + break; + } + i++; + } else { + ThresholdLow = bl; + break; + } + } while(FQBQData730[i] != 0xFF); + + } else { + + do { + B = SiS_CalcDelay2(SiS_Pr, FQBQData[i], HwInfo) * VCLK * colorth; + bl = B / (MCLK * 16); + + if(B == bl * 16 * MCLK) { + bl = bl + 1; + } else { + bl = bl + 2; + } + + if(bl > 0x13) { + if(FQBQData[i+1] == 0xFF) { + ThresholdLow = 0x13; + break; + } + i++; + } else { + ThresholdLow = bl; + break; + } + } while(FQBQData[i] != 0xFF); + } + } + else { + if(HwInfo->jChipType == SIS_730) { + } else { + i = 9; + } + ThresholdLow = 0x02; + } + + /* Write foreground and background queue */ + if(HwInfo->jChipType == SIS_730) { + + data2 = FQBQData730[i]; + data2 = (data2 & 0xC0) >> 5; + data2 <<= 8; + +#ifdef LINUX_KERNEL + SiS_SetRegLong(0xcf8,0x80000050); + eax = SiS_GetRegLong(0xcfc); + eax &= 0xfffff9ff; + eax |= data2; + SiS_SetRegLong(0xcfc,eax); +#else + /* We use pci functions X offers. We use pcitag 0, because + * we want to read/write to the host bridge (which is always + * 00:00.0 on 630, 730 and 540), not the VGA device. + */ + eax = pciReadLong(0x00000000, 0x50); + eax &= 0xfffff9ff; + eax |= data2; + pciWriteLong(0x00000000, 0x50, eax); +#endif + + /* Write GUI grant timer (PCI config 0xA3) */ + data2 = FQBQData730[i] << 8; + data2 = (data2 & 0x0f00) | ((data2 & 0x3000) >> 8); + data2 <<= 20; + +#ifdef LINUX_KERNEL + SiS_SetRegLong(0xcf8,0x800000A0); + eax = SiS_GetRegLong(0xcfc); + eax &= 0x00ffffff; + eax |= data2; + SiS_SetRegLong(0xcfc,eax); +#else + eax = pciReadLong(0x00000000, 0xA0); + eax &= 0x00ffffff; + eax |= data2; + pciWriteLong(0x00000000, 0xA0, eax); +#endif + + } else { + + data2 = FQBQData[i]; + data2 = (data2 & 0xf0) >> 4; + data2 <<= 24; + +#ifdef LINUX_KERNEL + SiS_SetRegLong(0xcf8,0x80000050); + eax = SiS_GetRegLong(0xcfc); + eax &= 0xf0ffffff; + eax |= data2; + SiS_SetRegLong(0xcfc,eax); +#else + eax = pciReadLong(0x00000000, 0x50); + eax &= 0xf0ffffff; + eax |= data2; + pciWriteLong(0x00000000, 0x50, eax); +#endif + + /* Write GUI grant timer (PCI config 0xA3) */ + data2 = FQBQData[i]; + data2 &= 0x0f; + data2 <<= 24; + +#ifdef LINUX_KERNEL + SiS_SetRegLong(0xcf8,0x800000A0); + eax = SiS_GetRegLong(0xcfc); + eax &= 0xf0ffffff; + eax |= data2; + SiS_SetRegLong(0xcfc,eax); +#else + eax = pciReadLong(0x00000000, 0xA0); + eax &= 0xf0ffffff; + eax |= data2; + pciWriteLong(0x00000000, 0xA0, eax); +#endif + + } + + /* Write CRT/CPU threshold low, CRT/Engine threshold high */ + data = ((ThresholdLow & 0x0f) << 4) | 0x0f; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,data); + + data = (ThresholdLow & 0x10) << 1; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xDF,data); + + /* What is this? */ + SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09); + + /* Write CRT/CPU threshold high (gap = 3) */ + data = ThresholdLow + 3; + if(data > 0x0f) data = 0x0f; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data); +} +#endif + +#ifdef SIS315H +static void +SiS_SetCRT1FIFO_310(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo) +{ + USHORT modeflag; + + /* disable auto-threshold */ + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE); + + if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE); + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0); + if(ModeNo > 0x13) { + if(HwInfo->jChipType >= SIS_661) { + if(!(modeflag & HalfDCLK)) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); + } + } else { + if((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); + } + } + } +} +#endif + +/*********************************************/ +/* MODE REGISTERS */ +/*********************************************/ + +static void +SiS_SetVCLKState(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo, USHORT RefreshRateTableIndex, + USHORT ModeIdIndex) +{ + USHORT data=0, VCLK=0, index=0; + + if(ModeNo > 0x13) { + if(SiS_Pr->UseCustomMode) { + VCLK = SiS_Pr->CSRClock; + } else { + index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex, + RefreshRateTableIndex,HwInfo); + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; + } + } + + if(HwInfo->jChipType < SIS_315H) { + + if(VCLK > 150) data |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data); + + data = 0x00; + if(VCLK >= 150) data |= 0x08; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data); + + } else { + + if(VCLK >= 166) data |= 0x0c; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data); + + if(VCLK >= 166) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1f,0xe7); + } + } + + /* DAC speed */ + if(HwInfo->jChipType >= SIS_661) { + + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xE8,0x10); + + } else { + + data = 0x03; + if((VCLK >= 135) && (VCLK < 160)) data = 0x02; + else if((VCLK >= 160) && (VCLK < 260)) data = 0x01; + else if(VCLK >= 260) data = 0x00; + + if(HwInfo->jChipType == SIS_540) { + if((VCLK == 203) || (VCLK < 234)) data = 0x02; + } + + if(HwInfo->jChipType < SIS_315H) { + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data); + } else { + if(HwInfo->jChipType > SIS_315PRO) { + if(ModeNo > 0x13) data &= 0xfc; + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data); + } + + } +} + +static void +SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex) +{ + USHORT data,infoflag=0,modeflag; + USHORT resindex,xres; +#ifdef SIS315H + USHORT data2,data3; + ULONG longdata; + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; +#endif + + if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + infoflag = SiS_Pr->CInfoFlag; + xres = SiS_Pr->CHDisplay; + } else { + resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex); + if(ModeNo > 0x13) { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal; + } else { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + xres = SiS_Pr->SiS_StResInfo[resindex].HTotal; + } + } + + /* Disable DPMS */ + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1F,0x3F); + + data = 0; + if(ModeNo > 0x13) { + if(SiS_Pr->SiS_ModeType > ModeEGA) { + data |= 0x02; + data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); + } + if(infoflag & InterlaceMode) data |= 0x20; + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0,data); + + if(HwInfo->jChipType != SIS_300) { + data = 0; + if(infoflag & InterlaceMode) { + if(xres <= 800) data = 0x0020; + else if(xres <= 1024) data = 0x0035; + else data = 0x0048; + } + SiS_SetReg(SiS_Pr->SiS_P3d4,0x19,(data & 0xFF)); + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x1a,0xFC,(data >> 8)); + } + + if(modeflag & HalfDCLK) { + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x08); + } + + data = 0; + if(modeflag & LineCompareOff) data = 0x08; + if(HwInfo->jChipType == SIS_300) { + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xF7,data); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,data); + if(SiS_Pr->SiS_ModeType == ModeEGA) { + if(ModeNo > 0x13) { + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x40); + } + } + } + + if(HwInfo->jChipType >= SIS_661) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xfb); + } + +#ifdef SIS315H + if(HwInfo->jChipType == SIS_315PRO) { + + data = SiS_Get310DRAMType(SiS_Pr, HwInfo); + data = SiS_Pr->SiS_SR15[2][data]; + if(SiS_Pr->SiS_ModeType == ModeText) { + data &= 0xc7; + } else { + data2 = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex, + RefreshRateTableIndex,HwInfo); + data2 >>= 1; + if(infoflag & InterlaceMode) data2 >>= 1; + data3 = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex) >> 1; + if(!data3) data3++; + data2 /= data3; + if(data2 >= 0x50) { + data &= 0x0f; + data |= 0x50; + } + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data); + + } else if( (HwInfo->jChipType == SIS_330) || + ((HwInfo->jChipType == SIS_760) && (SiS_Pr->SiS_SysFlags & SF_760LFB))) { + + data = SiS_Get310DRAMType(SiS_Pr, HwInfo); + if(HwInfo->jChipType == SIS_330) { + data = SiS_Pr->SiS_SR15[2][data]; + } else { + if(SiS_Pr->SiS_ROMNew) data = ROMAddr[0xf6]; + else if(SiS_Pr->SiS_UseROM) data = ROMAddr[0x100 + data]; + else data = 0xba; + } + if(SiS_Pr->SiS_ModeType <= ModeEGA) { + data &= 0xc7; + } else { + if(SiS_Pr->UseCustomMode) { + data2 = SiS_Pr->CSRClock; + } else { + data2 = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex, + RefreshRateTableIndex,HwInfo); + data2 = SiS_Pr->SiS_VCLKData[data2].CLOCK; + } + + data3 = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex) >> 1; + if(data3) data2 *= data3; + + longdata = SiS_GetMCLK(SiS_Pr, HwInfo) * 1024; + + data2 = longdata / data2; + + if(HwInfo->jChipType == SIS_330) { + if(SiS_Pr->SiS_ModeType != Mode16Bpp) { + if (data2 >= 0x19c) data = 0xba; + else if(data2 >= 0x140) data = 0x7a; + else if(data2 >= 0x101) data = 0x3a; + else if(data2 >= 0xf5) data = 0x32; + else if(data2 >= 0xe2) data = 0x2a; + else if(data2 >= 0xc4) data = 0x22; + else if(data2 >= 0xac) data = 0x1a; + else if(data2 >= 0x9e) data = 0x12; + else if(data2 >= 0x8e) data = 0x0a; + else data = 0x02; + } else { + if(data2 >= 0x127) data = 0xba; + else data = 0x7a; + } + } else { /* 760+LFB */ + if (data2 >= 0x190) data = 0xba; + else if(data2 >= 0xff) data = 0x7a; + else if(data2 >= 0xd3) data = 0x3a; + else if(data2 >= 0xa9) data = 0x1a; + else if(data2 >= 0x93) data = 0x0a; + else data = 0x02; + } + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data); + } else if(HwInfo->jChipType == SIS_340) { + /* TODO */ + } +#endif + + data = 0x60; + if(SiS_Pr->SiS_ModeType != ModeText) { + data ^= 0x60; + if(SiS_Pr->SiS_ModeType != ModeEGA) { + data ^= 0xA0; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x21,0x1F,data); + + SiS_SetVCLKState(SiS_Pr, HwInfo, ModeNo, RefreshRateTableIndex, ModeIdIndex); + +#ifdef SIS315H + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x2c); + } else { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x6c); + } + } +#endif +} + +/*********************************************/ +/* LOAD DAC */ +/*********************************************/ + +#if 0 +static void +SiS_ClearDAC(SiS_Private *SiS_Pr, ULONG port) +{ + int i; + + OutPortByte(port, 0); + port++; + for (i=0; i < (256 * 3); i++) { + OutPortByte(port, 0); + } +} +#endif + +static void +SiS_WriteDAC(SiS_Private *SiS_Pr, SISIOADDRESS DACData, USHORT shiftflag, + USHORT dl, USHORT ah, USHORT al, USHORT dh) +{ + USHORT temp,bh,bl; + + bh = ah; + bl = al; + if(dl != 0) { + temp = bh; + bh = dh; + dh = temp; + if(dl == 1) { + temp = bl; + bl = dh; + dh = temp; + } else { + temp = bl; + bl = bh; + bh = temp; + } + } + if(shiftflag) { + dh <<= 2; + bh <<= 2; + bl <<= 2; + } + SiS_SetRegByte(DACData,(USHORT)dh); + SiS_SetRegByte(DACData,(USHORT)bh); + SiS_SetRegByte(DACData,(USHORT)bl); +} + +void +SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT data,data2; + USHORT time,i,j,k,m,n,o; + USHORT si,di,bx,dl,al,ah,dh; + USHORT shiftflag; + SISIOADDRESS DACAddr, DACData; + const USHORT *table = NULL; + + if(ModeNo <= 0x13) { + data = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + if(SiS_Pr->UseCustomMode) { + data = SiS_Pr->CModeFlag; + } else { + data = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + } + + data &= DACInfoFlag; + time = 64; + if(data == 0x00) table = SiS_MDA_DAC; + if(data == 0x08) table = SiS_CGA_DAC; + if(data == 0x10) table = SiS_EGA_DAC; + if(data == 0x18) { + time = 256; + table = SiS_VGA_DAC; + } + if(time == 256) j = 16; + else j = time; + + if( ( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && /* 301B-DH LCD */ + (SiS_Pr->SiS_VBType & VB_NoLCD) ) || + (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) || /* LCDA */ + (!(SiS_Pr->SiS_SetFlag & ProgrammingCRT2)) ) { /* Programming CRT1 */ + DACAddr = SiS_Pr->SiS_P3c8; + DACData = SiS_Pr->SiS_P3c9; + shiftflag = 0; + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); + } else { + shiftflag = 1; + DACAddr = SiS_Pr->SiS_Part5Port; + DACData = SiS_Pr->SiS_Part5Port + 1; + } + + SiS_SetRegByte(DACAddr,0x00); + + for(i=0; i<j; i++) { + data = table[i]; + for(k=0; k<3; k++) { + data2 = 0; + if(data & 0x01) data2 = 0x2A; + if(data & 0x02) data2 += 0x15; + if(shiftflag) data2 <<= 2; + SiS_SetRegByte(DACData, data2); + data >>= 2; + } + } + + if(time == 256) { + for(i = 16; i < 32; i++) { + data = table[i]; + if(shiftflag) data <<= 2; + for(k = 0; k < 3; k++) SiS_SetRegByte(DACData, data); + } + si = 32; + for(m = 0; m < 9; m++) { + di = si; + bx = si + 4; + dl = 0; + for(n = 0; n < 3; n++) { + for(o = 0; o < 5; o++) { + dh = table[si]; + ah = table[di]; + al = table[bx]; + si++; + SiS_WriteDAC(SiS_Pr, DACData, shiftflag, dl, ah, al, dh); + } + si -= 2; + for(o = 0; o < 3; o++) { + dh = table[bx]; + ah = table[di]; + al = table[si]; + si--; + SiS_WriteDAC(SiS_Pr, DACData, shiftflag, dl, ah, al, dh); + } + dl++; + } /* for n < 3 */ + si += 5; + } /* for m < 9 */ + } +} + +/*********************************************/ +/* SET CRT1 REGISTER GROUP */ +/*********************************************/ + +static void +SiS_SetCRT1Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT StandTableIndex,RefreshRateTableIndex; + + SiS_Pr->SiS_CRT1Mode = ModeNo; + StandTableIndex = SiS_GetModePtr(SiS_Pr, ModeNo, ModeIdIndex); + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2)) { + SiS_DisableBridge(SiS_Pr, HwInfo); + } + } + + SiS_ResetSegmentRegisters(SiS_Pr, HwInfo); + + SiS_SetSeqRegs(SiS_Pr, StandTableIndex, HwInfo); + SiS_SetMiscRegs(SiS_Pr, StandTableIndex, HwInfo); + SiS_SetCRTCRegs(SiS_Pr, HwInfo, StandTableIndex); + SiS_SetATTRegs(SiS_Pr, StandTableIndex, HwInfo); + SiS_SetGRCRegs(SiS_Pr, StandTableIndex); + SiS_ClearExt1Regs(SiS_Pr, HwInfo, ModeNo); + SiS_ResetCRT1VCLK(SiS_Pr, HwInfo); + + SiS_Pr->SiS_SelectCRT2Rate = 0; + SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); + +#ifdef LINUX_XF86 + xf86DrvMsgVerb(0, X_PROBED, 4, "(init: VBType=0x%04x, VBInfo=0x%04x)\n", + SiS_Pr->SiS_VBType, SiS_Pr->SiS_VBInfo); +#endif + + if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + } + + RefreshRateTableIndex = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_Pr->SiS_SetFlag &= ~ProgrammingCRT2; + } + + if(RefreshRateTableIndex != 0xFFFF) { + SiS_SetCRT1Sync(SiS_Pr, RefreshRateTableIndex); + SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + SiS_SetCRT1VCLK(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + } + +#ifdef SIS300 + if(HwInfo->jChipType == SIS_300) { + SiS_SetCRT1FIFO_300(SiS_Pr, ModeNo,HwInfo,RefreshRateTableIndex); + } else if((HwInfo->jChipType == SIS_630) || + (HwInfo->jChipType == SIS_730) || + (HwInfo->jChipType == SIS_540)) { + SiS_SetCRT1FIFO_630(SiS_Pr, ModeNo, HwInfo, RefreshRateTableIndex); + } +#endif +#ifdef SIS315H + if(HwInfo->jChipType >= SIS_315H) { + SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + } +#endif + + SiS_SetCRT1ModeRegs(SiS_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex); + + SiS_LoadDAC(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); + +#ifdef LINUX_KERNEL + if(SiS_Pr->SiS_flag_clearbuffer) { + SiS_ClearBuffer(SiS_Pr,HwInfo,ModeNo); + } +#endif + + if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA))) { + SiS_WaitRetrace1(SiS_Pr); + SiS_DisplayOn(SiS_Pr); + } +} + +/*********************************************/ +/* HELPER: VIDEO BRIDGE PROG CLK */ +/*********************************************/ + +static void +SiS_ResetVB(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT temp; + + /* VB programming clock */ + if(SiS_Pr->SiS_UseROM) { + if(HwInfo->jChipType < SIS_330) { + temp = ROMAddr[VB310Data_1_2_Offset] | 0x40; + if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); + } else if(HwInfo->jChipType >= SIS_661) { + temp = ROMAddr[0x7e] | 0x40; + if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); + } + } +} + +/*********************************************/ +/* HELPER: SET VIDEO REGISTERS */ +/*********************************************/ + +static void +SiS_StrangeStuff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if((IS_SIS651) || (IS_SISM650)) { + SiS_SetReg(SiS_Pr->SiS_VidCapt, 0x3f, 0x00); /* Fiddle with capture regs */ + SiS_SetReg(SiS_Pr->SiS_VidCapt, 0x00, 0x00); + SiS_SetReg(SiS_Pr->SiS_VidPlay, 0x00, 0x86); /* (BIOS does NOT unlock) */ + SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x30, 0xfe); /* Fiddle with video regs */ + SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x3f, 0xef); + } + /* !!! This does not support modes < 0x13 !!! */ +} + +/*********************************************/ +/* XFree86: SET SCREEN PITCH */ +/*********************************************/ + +#ifdef LINUX_XF86 +static void +SiS_SetPitchCRT1(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) +{ + SISPtr pSiS = SISPTR(pScrn); + UShort HDisplay = pSiS->scrnPitch >> 3; + + SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,(HDisplay & 0xFF)); + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,(HDisplay>>8)); +} + +static void +SiS_SetPitchCRT2(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) +{ + SISPtr pSiS = SISPTR(pScrn); + UShort HDisplay = pSiS->scrnPitch2 >> 3; + + /* Unlock CRT2 */ + if(pSiS->VGAEngine == SIS_315_VGA) + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2F, 0x01); + else + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24, 0x01); + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(HDisplay & 0xFF)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0xF0,(HDisplay >> 8)); +} + +static void +SiS_SetPitch(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) +{ + SISPtr pSiS = SISPTR(pScrn); + BOOLEAN isslavemode = FALSE; + + if( (pSiS->VBFlags & VB_VIDEOBRIDGE) && + ( ((pSiS->VGAEngine == SIS_300_VGA) && + (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) || + ((pSiS->VGAEngine == SIS_315_VGA) && + (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) { + isslavemode = TRUE; + } + + /* We need to set pitch for CRT1 if bridge is in slave mode, too */ + if((pSiS->VBFlags & DISPTYPE_DISP1) || (isslavemode)) { + SiS_SetPitchCRT1(SiS_Pr, pScrn); + } + /* We must not set the pitch for CRT2 if bridge is in slave mode */ + if((pSiS->VBFlags & DISPTYPE_DISP2) && (!isslavemode)) { + SiS_SetPitchCRT2(SiS_Pr, pScrn); + } +} +#endif + +/*********************************************/ +/* SiSSetMode() */ +/*********************************************/ + +#ifdef LINUX_XF86 +/* We need pScrn for setting the pitch correctly */ +BOOLEAN +SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch) +#else +BOOLEAN +SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo) +#endif +{ + USHORT ModeIdIndex; + SISIOADDRESS BaseAddr = HwInfo->ulIOAddress; + unsigned char backupreg=0; +#ifdef LINUX_KERNEL + USHORT KeepLockReg; + ULONG temp; + + SiS_Pr->UseCustomMode = FALSE; + SiS_Pr->CRT1UsesCustomMode = FALSE; +#endif + + if(SiS_Pr->UseCustomMode) { + ModeNo = 0xfe; + } + + SiSInitPtr(SiS_Pr, HwInfo); + SiSRegInit(SiS_Pr, BaseAddr); + SiS_GetSysFlags(SiS_Pr, HwInfo); + +#if defined(LINUX_XF86) && (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__)) + if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff); + else +#endif + SiS_Pr->SiS_VGAINFO = 0x11; + + SiSInitPCIetc(SiS_Pr, HwInfo); + SiSSetLVDSetc(SiS_Pr, HwInfo); + SiSDetermineROMUsage(SiS_Pr, HwInfo); + + SiS_Pr->SiS_flag_clearbuffer = 0; + + if(!SiS_Pr->UseCustomMode) { +#ifdef LINUX_KERNEL + if(!(ModeNo & 0x80)) SiS_Pr->SiS_flag_clearbuffer = 1; +#endif + ModeNo &= 0x7f; + } + +#ifdef LINUX_KERNEL + KeepLockReg = SiS_GetReg(SiS_Pr->SiS_P3c4,0x05); +#endif + SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); + + SiS_UnLockCRT2(SiS_Pr, HwInfo); + + if(!SiS_Pr->UseCustomMode) { + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE; + } else { + ModeIdIndex = 0; + } + + SiS_GetVBType(SiS_Pr, HwInfo); + + /* Init/restore some VB registers */ + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(HwInfo->jChipType >= SIS_315H) { + SiS_ResetVB(SiS_Pr, HwInfo); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10); + SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c); + backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + } else { + backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + } + } + + /* Get VB information (connectors, connected devices) */ + SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, (SiS_Pr->UseCustomMode) ? 0 : 1); + SiS_SetYPbPr(SiS_Pr, HwInfo); + SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo); + +#ifdef LINUX_KERNEL + /* 3. Check memory size (Kernel framebuffer driver only) */ + temp = SiS_CheckMemorySize(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); + if(!temp) return(0); +#endif + + if(HwInfo->jChipType >= SIS_315H) { + SiS_SetupCR5x(SiS_Pr, HwInfo); + } + + if(SiS_Pr->UseCustomMode) { + SiS_Pr->CRT1UsesCustomMode = TRUE; + SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock; + SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag; + } else { + SiS_Pr->CRT1UsesCustomMode = FALSE; + } + + /* Set mode on CRT1 */ + if( (SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) || + (!(SiS_Pr->SiS_VBInfo & SwitchCRT2)) ) { + SiS_SetCRT1Group(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); + } + + /* Set mode on CRT2 */ + if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA)) { + if( (SiS_Pr->SiS_VBType & VB_SISVB) || + (SiS_Pr->SiS_IF_DEF_LVDS == 1) || + (SiS_Pr->SiS_IF_DEF_CH70xx != 0) || + (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) { + SiS_SetCRT2Group(SiS_Pr, HwInfo, ModeNo); + } + } + + SiS_HandleCRT1(SiS_Pr); + + SiS_StrangeStuff(SiS_Pr, HwInfo); + + SiS_DisplayOn(SiS_Pr); + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); + + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); + } + } + } + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(HwInfo->jChipType >= SIS_315H) { + if(!SiS_Pr->SiS_ROMNew) { + if(SiS_IsVAMode(SiS_Pr,HwInfo)) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); + } else { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE); + } + } + + SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg); + + if((IS_SIS650) && (SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & 0xfc)) { + if((ModeNo == 0x03) || (ModeNo == 0x10)) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x80); + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x56,0x08); + } + } + + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc); + } + } else if((HwInfo->jChipType == SIS_630) || + (HwInfo->jChipType == SIS_730)) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg); + } + } + +#ifdef LINUX_XF86 + if(pScrn) { + /* SetPitch: Adapt to virtual size & position */ + if((ModeNo > 0x13) && (dosetpitch)) { + SiS_SetPitch(SiS_Pr, pScrn); + } + + /* Backup/Set ModeNo in BIOS scratch area */ + SiS_GetSetModeID(pScrn, ModeNo); + } +#endif + +#ifdef LINUX_KERNEL /* We never lock registers in XF86 */ + if(KeepLockReg == 0xA1) SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); + else SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x00); +#endif + + return TRUE; +} + +/*********************************************/ +/* XFree86: SiSBIOSSetMode() */ +/* for non-Dual-Head mode */ +/*********************************************/ + +#ifdef LINUX_XF86 +BOOLEAN +SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, + DisplayModePtr mode, BOOLEAN IsCustom) +{ + SISPtr pSiS = SISPTR(pScrn); + UShort ModeNo = 0; + + SiS_Pr->UseCustomMode = FALSE; + + if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) { + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting custom mode %dx%d\n", + SiS_Pr->CHDisplay, + (mode->Flags & V_INTERLACE ? SiS_Pr->CVDisplay * 2 : + (mode->Flags & V_DBLSCAN ? SiS_Pr->CVDisplay / 2 : + SiS_Pr->CVDisplay))); + + } else { + + /* Don't need vbflags here; checks done earlier */ + ModeNo = SiS_GetModeNumber(pScrn, mode, 0); + if(!ModeNo) return FALSE; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x\n", ModeNo); + + } + + return(SiSSetMode(SiS_Pr, HwInfo, pScrn, ModeNo, TRUE)); +} + +/*********************************************/ +/* XFree86: SiSBIOSSetModeCRT2() */ +/* for Dual-Head modes */ +/*********************************************/ +BOOLEAN +SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, + DisplayModePtr mode, BOOLEAN IsCustom) +{ + USHORT ModeIdIndex; + SISIOADDRESS BaseAddr = HwInfo->ulIOAddress; + UShort ModeNo = 0; + unsigned char backupreg=0; + SISPtr pSiS = SISPTR(pScrn); +#ifdef SISDUALHEAD + SISEntPtr pSiSEnt = pSiS->entityPrivate; +#endif + + SiS_Pr->UseCustomMode = FALSE; + + /* Remember: Custom modes for CRT2 are ONLY supported + * -) on the 30x/B/C, and + * -) if CRT2 is LCD or VGA, or CRT1 is LCDA + */ + + if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) { + + ModeNo = 0xfe; + + } else { + + ModeNo = SiS_GetModeNumber(pScrn, mode, 0); + if(!ModeNo) return FALSE; + + } + + SiSRegInit(SiS_Pr, BaseAddr); + SiSInitPtr(SiS_Pr, HwInfo); + SiS_GetSysFlags(SiS_Pr, HwInfo); +#if (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__)) + SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff); +#else + SiS_Pr->SiS_VGAINFO = 0x11; +#endif + SiSInitPCIetc(SiS_Pr, HwInfo); + SiSSetLVDSetc(SiS_Pr, HwInfo); + SiSDetermineROMUsage(SiS_Pr, HwInfo); + + /* Save mode info so we can set it from within SetMode for CRT1 */ +#ifdef SISDUALHEAD + if(pSiS->DualHeadMode) { + pSiSEnt->CRT2ModeNo = ModeNo; + pSiSEnt->CRT2DMode = mode; + pSiSEnt->CRT2IsCustom = IsCustom; + pSiSEnt->CRT2CR30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + pSiSEnt->CRT2CR31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31); + pSiSEnt->CRT2CR35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + pSiSEnt->CRT2CR38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); +#if 0 + /* We can't set CRT2 mode before CRT1 mode is set */ + if(pSiSEnt->CRT1ModeNo == -1) { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "Setting CRT2 mode delayed until after setting CRT1 mode\n"); + return TRUE; + } +#endif + pSiSEnt->CRT2ModeSet = TRUE; + } +#endif + + /* We don't clear the buffer in X */ + SiS_Pr->SiS_flag_clearbuffer=0; + + if(SiS_Pr->UseCustomMode) { + + USHORT temptemp = SiS_Pr->CVDisplay; + + if(SiS_Pr->CModeFlag & DoubleScanMode) temptemp >>= 1; + else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "Setting custom mode %dx%d on CRT2\n", + SiS_Pr->CHDisplay, temptemp); + + } else { + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "Setting standard mode 0x%x on CRT2\n", ModeNo); + + } + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); + + SiS_UnLockCRT2(SiS_Pr, HwInfo); + + if(!SiS_Pr->UseCustomMode) { + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE; + } else { + ModeIdIndex = 0; + } + + SiS_GetVBType(SiS_Pr, HwInfo); + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(HwInfo->jChipType >= SIS_315H) { + SiS_ResetVB(SiS_Pr, HwInfo); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10); + SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c); + backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + } else { + backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + } + } + + /* Get VB information (connectors, connected devices) */ + if(!SiS_Pr->UseCustomMode) { + SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, 1); + } else { + /* If this is a custom mode, we don't check the modeflag for CRT2Mode */ + SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, 0); + } + SiS_SetYPbPr(SiS_Pr, HwInfo); + SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo); + + /* Set mode on CRT2 */ + if( (SiS_Pr->SiS_VBType & VB_SISVB) || + (SiS_Pr->SiS_IF_DEF_LVDS == 1) || + (SiS_Pr->SiS_IF_DEF_CH70xx != 0) || + (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) { + SiS_SetCRT2Group(SiS_Pr, HwInfo, ModeNo); + } + + SiS_StrangeStuff(SiS_Pr, HwInfo); + + SiS_DisplayOn(SiS_Pr); + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); + + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); + } + } + } + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(HwInfo->jChipType >= SIS_315H) { + if(!SiS_Pr->SiS_ROMNew) { + if(SiS_IsVAMode(SiS_Pr,HwInfo)) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); + } else { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE); + } + } + + SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg); + + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc); + } + } else if((HwInfo->jChipType == SIS_630) || + (HwInfo->jChipType == SIS_730)) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg); + } + } + + /* SetPitch: Adapt to virtual size & position */ + SiS_SetPitchCRT2(SiS_Pr, pScrn); + + return TRUE; +} + +/*********************************************/ +/* XFree86: SiSBIOSSetModeCRT1() */ +/* for Dual-Head modes */ +/*********************************************/ + +BOOLEAN +SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, + DisplayModePtr mode, BOOLEAN IsCustom) +{ + SISPtr pSiS = SISPTR(pScrn); + SISIOADDRESS BaseAddr = HwInfo->ulIOAddress; + USHORT ModeIdIndex, ModeNo=0; + UCHAR backupreg=0; +#ifdef SISDUALHEAD + SISEntPtr pSiSEnt = pSiS->entityPrivate; + UCHAR backupcr30, backupcr31, backupcr38, backupcr35, backupp40d=0; + BOOLEAN backupcustom; +#endif + + SiS_Pr->UseCustomMode = FALSE; + + if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) { + + USHORT temptemp = SiS_Pr->CVDisplay; + + if(SiS_Pr->CModeFlag & DoubleScanMode) temptemp >>= 1; + else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "Setting custom mode %dx%d on CRT1\n", + SiS_Pr->CHDisplay, temptemp); + ModeNo = 0xfe; + + } else { + + ModeNo = SiS_GetModeNumber(pScrn, mode, 0); + if(!ModeNo) return FALSE; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "Setting standard mode 0x%x on CRT1\n", ModeNo); + } + + SiSInitPtr(SiS_Pr, HwInfo); + SiSRegInit(SiS_Pr, BaseAddr); + SiS_GetSysFlags(SiS_Pr, HwInfo); +#if (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__)) + SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff); +#else + SiS_Pr->SiS_VGAINFO = 0x11; +#endif + SiSInitPCIetc(SiS_Pr, HwInfo); + SiSSetLVDSetc(SiS_Pr, HwInfo); + SiSDetermineROMUsage(SiS_Pr, HwInfo); + + /* We don't clear the buffer in X */ + SiS_Pr->SiS_flag_clearbuffer = 0; + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); + + SiS_UnLockCRT2(SiS_Pr, HwInfo); + + if(!SiS_Pr->UseCustomMode) { + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE; + } else { + ModeIdIndex = 0; + } + + /* Determine VBType */ + SiS_GetVBType(SiS_Pr, HwInfo); + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(HwInfo->jChipType >= SIS_315H) { + backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + } else { + backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + } + } + + /* Get VB information (connectors, connected devices) */ + /* (We don't care if the current mode is a CRT2 mode) */ + SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, 0); + SiS_SetYPbPr(SiS_Pr, HwInfo); + SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo); + + if(HwInfo->jChipType >= SIS_315H) { + SiS_SetupCR5x(SiS_Pr, HwInfo); + } + + /* Set mode on CRT1 */ + SiS_SetCRT1Group(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetCRT2Group(SiS_Pr, HwInfo, ModeNo); + } + + /* SetPitch: Adapt to virtual size & position */ + SiS_SetPitchCRT1(SiS_Pr, pScrn); + +#ifdef SISDUALHEAD + if(pSiS->DualHeadMode) { + pSiSEnt->CRT1ModeNo = ModeNo; + pSiSEnt->CRT1DMode = mode; + } +#endif + + if(SiS_Pr->UseCustomMode) { + SiS_Pr->CRT1UsesCustomMode = TRUE; + SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock; + SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag; + } else { + SiS_Pr->CRT1UsesCustomMode = FALSE; + } + + /* Reset CRT2 if changing mode on CRT1 */ +#ifdef SISDUALHEAD + if(pSiS->DualHeadMode) { + if(pSiSEnt->CRT2ModeNo != -1) { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "(Re-)Setting mode for CRT2\n"); + backupcustom = SiS_Pr->UseCustomMode; + backupcr30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + backupcr31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31); + backupcr35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + backupcr38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(SiS_Pr->SiS_VBType & VB_SISVB) { + /* Backup LUT-enable */ + if(pSiSEnt->CRT2ModeSet) { + backupp40d = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0d) & 0x08; + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,pSiSEnt->CRT2CR30); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,pSiSEnt->CRT2CR31); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,pSiSEnt->CRT2CR35); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,pSiSEnt->CRT2CR38); + } + SiSBIOSSetModeCRT2(SiS_Pr, HwInfo, pSiSEnt->pScrn_1, + pSiSEnt->CRT2DMode, pSiSEnt->CRT2IsCustom); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,backupcr30); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,backupcr31); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupcr35); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupcr38); + if(SiS_Pr->SiS_VBType & VB_SISVB) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d, ~0x08, backupp40d); + } + SiS_Pr->UseCustomMode = backupcustom; + } + } +#endif + + /* Warning: From here, the custom mode entries in SiS_Pr are + * possibly overwritten + */ + + SiS_HandleCRT1(SiS_Pr); + + SiS_StrangeStuff(SiS_Pr, HwInfo); + + SiS_DisplayOn(SiS_Pr); + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(HwInfo->jChipType >= SIS_315H) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg); + } else if((HwInfo->jChipType == SIS_630) || + (HwInfo->jChipType == SIS_730)) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg); + } + } + + /* Backup/Set ModeNo in BIOS scratch area */ + SiS_GetSetModeID(pScrn,ModeNo); + + return TRUE; +} +#endif /* Linux_XF86 */ + + +#ifdef LINUX_XF86 +BOOLEAN +SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + const USHORT PanelTypeTable300[16] = { + 0xc101, 0xc117, 0x0121, 0xc135, 0xc142, 0xc152, 0xc162, 0xc072, + 0xc181, 0xc192, 0xc1a1, 0xc1b6, 0xc1c2, 0xc0d2, 0xc1e2, 0xc1f2 + }; + const USHORT PanelTypeTable31030x[16] = { + 0xc102, 0xc112, 0x0122, 0xc132, 0xc142, 0xc152, 0xc169, 0xc179, + 0x0189, 0xc192, 0xc1a2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }; + const USHORT PanelTypeTable310LVDS[16] = { + 0xc111, 0xc122, 0xc133, 0xc144, 0xc155, 0xc166, 0xc177, 0xc188, + 0xc199, 0xc0aa, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }; + USHORT tempax,tempbx,temp; + + if(HwInfo->jChipType < SIS_315H) { + + tempax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18); + tempbx = tempax & 0x0F; + if(!(tempax & 0x10)){ + if(SiS_Pr->SiS_IF_DEF_LVDS == 1){ + tempbx = 0; + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x38); + if(temp & 0x40) tempbx |= 0x08; + if(temp & 0x20) tempbx |= 0x02; + if(temp & 0x01) tempbx |= 0x01; + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x39); + if(temp & 0x80) tempbx |= 0x04; + } else { + return 0; + } + } + tempbx = PanelTypeTable300[tempbx]; + tempbx |= LCDSync; + temp = tempbx & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,temp); + temp = (tempbx & 0xFF00) >> 8; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp); + + } else { + + if(HwInfo->jChipType >= SIS_661) return 0; + + tempax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1a); + tempax &= 0x1e; + tempax >>= 1; + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(tempax == 0) { + /* TODO: Include HUGE detection routine + (Probably not worth bothering) + */ + return 0; + } + temp = tempax & 0xff; + tempax--; + tempbx = PanelTypeTable310LVDS[tempax]; + } else { + tempbx = PanelTypeTable31030x[tempax]; + temp = tempbx & 0xff; + } + SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,temp); + tempbx = (tempbx & 0xff00) >> 8; + temp = tempbx & 0xc1; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp); + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = tempbx & 0x04; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x39,0xfb,temp); + } + + } + return 1; +} +#endif + +#ifndef GETBITSTR +#define BITMASK(h,l) (((unsigned)(1U << ((h)-(l)+1))-1)<<(l)) +#define GENMASK(mask) BITMASK(1?mask,0?mask) +#define GETBITS(var,mask) (((var) & GENMASK(mask)) >> (0?mask)) +#define GETBITSTR(val,from,to) ((GETBITS(val,from)) << (0?to)) +#endif + +static void +SiS_CalcCRRegisters(SiS_Private *SiS_Pr, int depth) +{ + SiS_Pr->CCRT1CRTC[0] = ((SiS_Pr->CHTotal >> 3) - 5) & 0xff; /* CR0 */ + SiS_Pr->CCRT1CRTC[1] = (SiS_Pr->CHDisplay >> 3) - 1; /* CR1 */ + SiS_Pr->CCRT1CRTC[2] = (SiS_Pr->CHBlankStart >> 3) - 1; /* CR2 */ + SiS_Pr->CCRT1CRTC[3] = (((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x1F) | 0x80; /* CR3 */ + SiS_Pr->CCRT1CRTC[4] = (SiS_Pr->CHSyncStart >> 3) + 3; /* CR4 */ + SiS_Pr->CCRT1CRTC[5] = ((((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x20) << 2) | /* CR5 */ + (((SiS_Pr->CHSyncEnd >> 3) + 3) & 0x1F); + + SiS_Pr->CCRT1CRTC[6] = (SiS_Pr->CVTotal - 2) & 0xFF; /* CR6 */ + SiS_Pr->CCRT1CRTC[7] = (((SiS_Pr->CVTotal - 2) & 0x100) >> 8) /* CR7 */ + | (((SiS_Pr->CVDisplay - 1) & 0x100) >> 7) + | ((SiS_Pr->CVSyncStart & 0x100) >> 6) + | (((SiS_Pr->CVBlankStart - 1) & 0x100) >> 5) + | 0x10 + | (((SiS_Pr->CVTotal - 2) & 0x200) >> 4) + | (((SiS_Pr->CVDisplay - 1) & 0x200) >> 3) + | ((SiS_Pr->CVSyncStart & 0x200) >> 2); + + SiS_Pr->CCRT1CRTC[16] = ((((SiS_Pr->CVBlankStart - 1) & 0x200) >> 4) >> 5); /* CR9 */ + + if(depth != 8) { + if(SiS_Pr->CHDisplay >= 1600) SiS_Pr->CCRT1CRTC[16] |= 0x60; /* SRE */ + else if(SiS_Pr->CHDisplay >= 640) SiS_Pr->CCRT1CRTC[16] |= 0x40; + } + +#if 0 + if (mode->VScan >= 32) + regp->CRTC[9] |= 0x1F; + else if (mode->VScan > 1) + regp->CRTC[9] |= mode->VScan - 1; +#endif + + SiS_Pr->CCRT1CRTC[8] = (SiS_Pr->CVSyncStart ) & 0xFF; /* CR10 */ + SiS_Pr->CCRT1CRTC[9] = ((SiS_Pr->CVSyncEnd ) & 0x0F) | 0x80; /* CR11 */ + SiS_Pr->CCRT1CRTC[10] = (SiS_Pr->CVDisplay - 1) & 0xFF; /* CR12 */ + SiS_Pr->CCRT1CRTC[11] = (SiS_Pr->CVBlankStart - 1) & 0xFF; /* CR15 */ + SiS_Pr->CCRT1CRTC[12] = (SiS_Pr->CVBlankEnd - 1) & 0xFF; /* CR16 */ + + SiS_Pr->CCRT1CRTC[13] = /* SRA */ + GETBITSTR((SiS_Pr->CVTotal -2), 10:10, 0:0) | + GETBITSTR((SiS_Pr->CVDisplay -1), 10:10, 1:1) | + GETBITSTR((SiS_Pr->CVBlankStart-1), 10:10, 2:2) | + GETBITSTR((SiS_Pr->CVSyncStart ), 10:10, 3:3) | + GETBITSTR((SiS_Pr->CVBlankEnd -1), 8:8, 4:4) | + GETBITSTR((SiS_Pr->CVSyncEnd ), 4:4, 5:5) ; + + SiS_Pr->CCRT1CRTC[14] = /* SRB */ + GETBITSTR((SiS_Pr->CHTotal >> 3) - 5, 9:8, 1:0) | + GETBITSTR((SiS_Pr->CHDisplay >> 3) - 1, 9:8, 3:2) | + GETBITSTR((SiS_Pr->CHBlankStart >> 3) - 1, 9:8, 5:4) | + GETBITSTR((SiS_Pr->CHSyncStart >> 3) + 3, 9:8, 7:6) ; + + + SiS_Pr->CCRT1CRTC[15] = /* SRC */ + GETBITSTR((SiS_Pr->CHBlankEnd >> 3) - 1, 7:6, 1:0) | + GETBITSTR((SiS_Pr->CHSyncEnd >> 3) + 3, 5:5, 2:2) ; +} + +void +SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex) +{ + USHORT modeflag, tempax, tempbx, VGAHDE = SiS_Pr->SiS_VGAHDE; + int i,j; + + /* 1:1 data: use data set by setcrt1crtc() */ + if(SiS_Pr->SiS_LCDInfo & LCDPass11) return; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + if(modeflag & HalfDCLK) VGAHDE >>= 1; + + SiS_Pr->CHDisplay = VGAHDE; + SiS_Pr->CHBlankStart = VGAHDE; + + SiS_Pr->CVDisplay = SiS_Pr->SiS_VGAVDE; + SiS_Pr->CVBlankStart = SiS_Pr->SiS_VGAVDE; + + tempbx = SiS_Pr->PanelHT - SiS_Pr->PanelXRes; + tempax = SiS_Pr->SiS_VGAHDE; /* not /2 ! */ + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax = SiS_Pr->PanelXRes; + } + tempbx += tempax; + if(modeflag & HalfDCLK) tempbx -= VGAHDE; + SiS_Pr->CHTotal = SiS_Pr->CHBlankEnd = tempbx; + + tempax = VGAHDE; + tempbx = SiS_Pr->CHTotal; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempbx = SiS_Pr->PanelXRes; + if(modeflag & HalfDCLK) tempbx >>= 1; + tempax += ((tempbx - tempax) >> 1); + } + + tempax += SiS_Pr->PanelHRS; + SiS_Pr->CHSyncStart = tempax; + tempax += SiS_Pr->PanelHRE; + SiS_Pr->CHSyncEnd = tempax; + + tempbx = SiS_Pr->PanelVT - SiS_Pr->PanelYRes; + tempax = SiS_Pr->SiS_VGAVDE; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax = SiS_Pr->PanelYRes; + } + SiS_Pr->CVTotal = SiS_Pr->CVBlankEnd = tempbx + tempax; + + tempax = SiS_Pr->SiS_VGAVDE; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax += (SiS_Pr->PanelYRes - tempax) >> 1; + } + tempax += SiS_Pr->PanelVRS; + SiS_Pr->CVSyncStart = tempax; + tempax += SiS_Pr->PanelVRE; + SiS_Pr->CVSyncEnd = tempax; + + SiS_CalcCRRegisters(SiS_Pr, 8); + SiS_Pr->CCRT1CRTC[16] &= ~0xE0; + + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); + + for(i=0,j=0;i<=7;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); + } + for(j=0x10;i<=10;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); + } + for(j=0x15;i<=12;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); + } + for(j=0x0A;i<=15;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->CCRT1CRTC[i]); + } + + tempax = SiS_Pr->CCRT1CRTC[16] & 0xE0; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1F,tempax); + + tempax = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5; + if(modeflag & DoubleScanMode) tempax |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,tempax); + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "%d %d %d %d %d %d %d %d (%d %d %d %d)\n", + SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal, + SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal, + SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd); + + xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", + SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1], + SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3], + SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5], + SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]); + xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", + SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9], + SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11], + SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13], + SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]); + xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]); +#endif +} + +#ifdef LINUX_XF86 + +void +SiS_MakeClockRegs(ScrnInfoPtr pScrn, int clock, UCHAR *p2b, UCHAR *p2c) +{ + int out_n, out_dn, out_div, out_sbit, out_scale; + unsigned int vclk[5]; + +#define Midx 0 +#define Nidx 1 +#define VLDidx 2 +#define Pidx 3 +#define PSNidx 4 + + if(SiS_compute_vclk(clock, &out_n, &out_dn, &out_div, &out_sbit, &out_scale)) { + (*p2b) = (out_div == 2) ? 0x80 : 0x00; + (*p2b) |= ((out_n - 1) & 0x7f); + (*p2c) = (out_dn - 1) & 0x1f; + (*p2c) |= (((out_scale - 1) & 3) << 5); + (*p2c) |= ((out_sbit & 0x01) << 7); +#ifdef TWDEBUG + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sb %d sc %d\n", + clock, out_n, out_dn, out_div, out_sbit, out_scale); +#endif + } else { + SiSCalcClock(pScrn, clock, 2, vclk); + (*p2b) = (vclk[VLDidx] == 2) ? 0x80 : 0x00; + (*p2b) |= (vclk[Midx] - 1) & 0x7f; + (*p2c) = (vclk[Nidx] - 1) & 0x1f; + if(vclk[Pidx] <= 4) { + /* postscale 1,2,3,4 */ + (*p2c) |= ((vclk[Pidx] - 1) & 3) << 5; + } else { + /* postscale 6,8 */ + (*p2c) |= (((vclk[Pidx] / 2) - 1) & 3) << 5; + (*p2c) |= 0x80; + } +#ifdef TWDEBUG + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sc %d\n", + clock, vclk[Midx], vclk[Nidx], vclk[VLDidx], vclk[Pidx]); +#endif + } +} + +#endif + +/* ================ XFREE86/X.ORG ================= */ + +/* Helper functions */ + +#ifdef LINUX_XF86 + +USHORT +SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags) +{ + SISPtr pSiS = SISPTR(pScrn); + int depth = pSiS->CurrentLayout.bitsPerPixel; + + pSiS->SiS_Pr->CModeFlag = 0; + + pSiS->SiS_Pr->CDClock = mode->Clock; + + pSiS->SiS_Pr->CHDisplay = mode->HDisplay; + pSiS->SiS_Pr->CHSyncStart = mode->HSyncStart; + pSiS->SiS_Pr->CHSyncEnd = mode->HSyncEnd; + pSiS->SiS_Pr->CHTotal = mode->HTotal; + + pSiS->SiS_Pr->CVDisplay = mode->VDisplay; + pSiS->SiS_Pr->CVSyncStart = mode->VSyncStart; + pSiS->SiS_Pr->CVSyncEnd = mode->VSyncEnd; + pSiS->SiS_Pr->CVTotal = mode->VTotal; + + pSiS->SiS_Pr->CFlags = mode->Flags; + + if(pSiS->SiS_Pr->CFlags & V_INTERLACE) { + pSiS->SiS_Pr->CVDisplay >>= 1; + pSiS->SiS_Pr->CVSyncStart >>= 1; + pSiS->SiS_Pr->CVSyncEnd >>= 1; + pSiS->SiS_Pr->CVTotal >>= 1; + } + if(pSiS->SiS_Pr->CFlags & V_DBLSCAN) { + /* pSiS->SiS_Pr->CDClock <<= 1; */ + pSiS->SiS_Pr->CVDisplay <<= 1; + pSiS->SiS_Pr->CVSyncStart <<= 1; + pSiS->SiS_Pr->CVSyncEnd <<= 1; + pSiS->SiS_Pr->CVTotal <<= 1; + } + + pSiS->SiS_Pr->CHBlankStart = pSiS->SiS_Pr->CHDisplay; + pSiS->SiS_Pr->CHBlankEnd = pSiS->SiS_Pr->CHTotal; + pSiS->SiS_Pr->CVBlankStart = pSiS->SiS_Pr->CVSyncStart - 1; + pSiS->SiS_Pr->CVBlankEnd = pSiS->SiS_Pr->CVTotal; + + SiS_MakeClockRegs(pScrn, pSiS->SiS_Pr->CDClock, &pSiS->SiS_Pr->CSR2B, &pSiS->SiS_Pr->CSR2C); + + pSiS->SiS_Pr->CSRClock = (pSiS->SiS_Pr->CDClock / 1000) + 1; + + SiS_CalcCRRegisters(pSiS->SiS_Pr, depth); + + switch(depth) { + case 8: pSiS->SiS_Pr->CModeFlag |= 0x223b; break; + case 16: pSiS->SiS_Pr->CModeFlag |= 0x227d; break; + case 32: pSiS->SiS_Pr->CModeFlag |= 0x22ff; break; + default: return 0; + } + + if(pSiS->SiS_Pr->CFlags & V_DBLSCAN) + pSiS->SiS_Pr->CModeFlag |= DoubleScanMode; + + if((pSiS->SiS_Pr->CVDisplay >= 1024) || + (pSiS->SiS_Pr->CVTotal >= 1024) || + (pSiS->SiS_Pr->CHDisplay >= 1024)) + pSiS->SiS_Pr->CModeFlag |= LineCompareOff; + + if(pSiS->SiS_Pr->CFlags & V_CLKDIV2) + pSiS->SiS_Pr->CModeFlag |= HalfDCLK; + + pSiS->SiS_Pr->CInfoFlag = 0x0007; + + if(pSiS->SiS_Pr->CFlags & V_NHSYNC) + pSiS->SiS_Pr->CInfoFlag |= 0x4000; + + if(pSiS->SiS_Pr->CFlags & V_NVSYNC) + pSiS->SiS_Pr->CInfoFlag |= 0x8000; + + if(pSiS->SiS_Pr->CFlags & V_INTERLACE) + pSiS->SiS_Pr->CInfoFlag |= InterlaceMode; + + pSiS->SiS_Pr->UseCustomMode = TRUE; +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "Custom mode %dx%d:\n", + pSiS->SiS_Pr->CHDisplay,pSiS->SiS_Pr->CVDisplay); + xf86DrvMsg(0, X_INFO, "Modeflag %04x, Infoflag %04x\n", + pSiS->SiS_Pr->CModeFlag, pSiS->SiS_Pr->CInfoFlag); + xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", + pSiS->SiS_Pr->CCRT1CRTC[0], pSiS->SiS_Pr->CCRT1CRTC[1], + pSiS->SiS_Pr->CCRT1CRTC[2], pSiS->SiS_Pr->CCRT1CRTC[3], + pSiS->SiS_Pr->CCRT1CRTC[4], pSiS->SiS_Pr->CCRT1CRTC[5], + pSiS->SiS_Pr->CCRT1CRTC[6], pSiS->SiS_Pr->CCRT1CRTC[7]); + xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", + pSiS->SiS_Pr->CCRT1CRTC[8], pSiS->SiS_Pr->CCRT1CRTC[9], + pSiS->SiS_Pr->CCRT1CRTC[10], pSiS->SiS_Pr->CCRT1CRTC[11], + pSiS->SiS_Pr->CCRT1CRTC[12], pSiS->SiS_Pr->CCRT1CRTC[13], + pSiS->SiS_Pr->CCRT1CRTC[14], pSiS->SiS_Pr->CCRT1CRTC[15]); + xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", pSiS->SiS_Pr->CCRT1CRTC[16]); + xf86DrvMsg(0, X_INFO, "Clock: 0x%02x, 0x%02x, %d\n", + pSiS->SiS_Pr->CSR2B, pSiS->SiS_Pr->CSR2C, pSiS->SiS_Pr->CSRClock); +#endif + return 1; +} + +int +SiS_FindPanelFromDB(SISPtr pSiS, USHORT panelvendor, USHORT panelproduct, int *maxx, int *maxy, int *prefx, int *prefy) +{ + int i, j; + BOOLEAN done = FALSE; + + i = 0; + while((!done) && (SiS_PlasmaTable[i].vendor) && panelvendor) { + if(SiS_PlasmaTable[i].vendor == panelvendor) { + for(j=0; j<SiS_PlasmaTable[i].productnum; j++) { + if(SiS_PlasmaTable[i].product[j] == panelproduct) { + if(SiS_PlasmaTable[i].maxx && SiS_PlasmaTable[i].maxy) { + (*maxx) = (int)SiS_PlasmaTable[i].maxx; + (*maxy) = (int)SiS_PlasmaTable[i].maxy; + (*prefx) = (int)SiS_PlasmaTable[i].prefx; + (*prefy) = (int)SiS_PlasmaTable[i].prefy; + done = TRUE; + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "Identified %s, correcting max X res %d, max Y res %d\n", + SiS_PlasmaTable[i].plasmaname, + SiS_PlasmaTable[i].maxx, SiS_PlasmaTable[i].maxy); + break; + } + } + } + } + i++; + } + return (done) ? 1 : 0; +} + +/* Build a list of supported modes: + * Built-in modes for which we have all data are M_T_DEFAULT, + * modes derived from DDC or database data are M_T_BUILTIN + */ +DisplayModePtr +SiSBuildBuiltInModeList(ScrnInfoPtr pScrn, BOOLEAN includelcdmodes, BOOLEAN isfordvi) +{ + SISPtr pSiS = SISPTR(pScrn); + unsigned short VRE, VBE, VRS, VBS, VDE, VT; + unsigned short HRE, HBE, HRS, HBS, HDE, HT; + unsigned char sr_data, cr_data, cr_data2, cr_data3; + unsigned char sr2b, sr2c; + float num, denum, postscalar, divider; + int A, B, C, D, E, F, temp, i, j, k, l, index, vclkindex; + DisplayModePtr new = NULL, current = NULL, first = NULL; + BOOLEAN done = FALSE; +#if 0 + DisplayModePtr backup = NULL; +#endif + + pSiS->backupmodelist = NULL; + pSiS->AddedPlasmaModes = FALSE; + + /* Initialize our pointers */ + if(pSiS->VGAEngine == SIS_300_VGA) { +#ifdef SIS300 + InitTo300Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext); +#else + return NULL; +#endif + } else if(pSiS->VGAEngine == SIS_315_VGA) { +#ifdef SIS315H + InitTo310Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext); +#else + return NULL; +#endif + } else return NULL; + + i = 0; + while(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag != 0xFFFF) { + + index = pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRT1CRTC; + + /* 0x5a (320x240) is a pure FTSN mode, not DSTN! */ + if((!pSiS->FSTN) && + (pSiS->SiS_Pr->SiS_RefIndex[i].ModeID == 0x5a)) { + i++; + continue; + } + if((pSiS->FSTN) && + (pSiS->SiS_Pr->SiS_RefIndex[i].XRes == 320) && + (pSiS->SiS_Pr->SiS_RefIndex[i].YRes == 240) && + (pSiS->SiS_Pr->SiS_RefIndex[i].ModeID != 0x5a)) { + i++; + continue; + } + + if(!(new = xalloc(sizeof(DisplayModeRec)))) return first; + memset(new, 0, sizeof(DisplayModeRec)); + if(!(new->name = xalloc(10))) { + xfree(new); + return first; + } + if(!first) first = new; + if(current) { + current->next = new; + new->prev = current; + } + + current = new; + + sprintf(current->name, "%dx%d", pSiS->SiS_Pr->SiS_RefIndex[i].XRes, + pSiS->SiS_Pr->SiS_RefIndex[i].YRes); + + current->status = MODE_OK; + + current->type = M_T_DEFAULT; + + vclkindex = pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRTVCLK; + if(pSiS->VGAEngine == SIS_300_VGA) vclkindex &= 0x3F; + + sr2b = pSiS->SiS_Pr->SiS_VCLKData[vclkindex].SR2B; + sr2c = pSiS->SiS_Pr->SiS_VCLKData[vclkindex].SR2C; + + divider = (sr2b & 0x80) ? 2.0 : 1.0; + postscalar = (sr2c & 0x80) ? + ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0) : (((sr2c >> 5) & 0x03) + 1.0); + num = (sr2b & 0x7f) + 1.0; + denum = (sr2c & 0x1f) + 1.0; + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "------------\n"); + xf86DrvMsg(0, X_INFO, "sr2b: %x sr2c %x div %f ps %f num %f denum %f\n", + sr2b, sr2c, divider, postscalar, num, denum); +#endif + + current->Clock = (int)(14318 * (divider / postscalar) * (num / denum)); + + sr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[14]; + /* inSISIDXREG(SISSR, 0x0b, sr_data); */ + + cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[0]; + /* inSISIDXREG(SISCR, 0x00, cr_data); */ + + /* Horizontal total */ + HT = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0x03) << 8); + A = HT + 5; + + cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[1]; + /* inSISIDXREG(SISCR, 0x01, cr_data); */ + + /* Horizontal display enable end */ + HDE = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0x0C) << 6); + E = HDE + 1; /* 0x80 0x64 */ + + cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[4]; + /* inSISIDXREG(SISCR, 0x04, cr_data); */ + + /* Horizontal retrace (=sync) start */ + HRS = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0xC0) << 2); + F = HRS - E - 3; /* 0x06 0x06 */ + + cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[2]; + /* inSISIDXREG(SISCR, 0x02, cr_data); */ + + /* Horizontal blank start */ + HBS = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0x30) << 4); + + sr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[15]; + /* inSISIDXREG(SISSR, 0x0c, sr_data); */ + + cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[3]; + /* inSISIDXREG(SISCR, 0x03, cr_data); */ + + cr_data2 = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[5]; + /* inSISIDXREG(SISCR, 0x05, cr_data2); */ + + /* Horizontal blank end */ + HBE = (cr_data & 0x1f) | + ((unsigned short) (cr_data2 & 0x80) >> 2) | + ((unsigned short) (sr_data & 0x03) << 6); + + /* Horizontal retrace (=sync) end */ + HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3); + + temp = HBE - ((E - 1) & 255); + B = (temp > 0) ? temp : (temp + 256); + + temp = HRE - ((E + F + 3) & 63); + C = (temp > 0) ? temp : (temp + 64); /* 0x0b 0x0b */ + + D = B - F - C; + + if((pSiS->SiS_Pr->SiS_RefIndex[i].XRes == 320) && + ((pSiS->SiS_Pr->SiS_RefIndex[i].YRes == 200) || + (pSiS->SiS_Pr->SiS_RefIndex[i].YRes == 240))) { + + /* Terrible hack, but correct CRTC data for + * these modes only produces a black screen... + * (HRE is 0, leading into a too large C and + * a negative D. The CRT controller does not + * seem to like correcting HRE to 50 + */ + current->HDisplay = 320; + current->HSyncStart = 328; + current->HSyncEnd = 376; + current->HTotal = 400; + + } else { + + current->HDisplay = (E * 8); + current->HSyncStart = (E * 8) + (F * 8); + current->HSyncEnd = (E * 8) + (F * 8) + (C * 8); + current->HTotal = (E * 8) + (F * 8) + (C * 8) + (D * 8); + + } + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, + "H: A %d B %d C %d D %d E %d F %d HT %d HDE %d HRS %d HBS %d HBE %d HRE %d\n", + A, B, C, D, E, F, HT, HDE, HRS, HBS, HBE, HRE); +#endif + + sr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[13]; + /* inSISIDXREG(SISSR, 0x0A, sr_data); */ + + cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[6]; + /* inSISIDXREG(SISCR, 0x06, cr_data); */ + + cr_data2 = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[7]; + /* inSISIDXREG(SISCR, 0x07, cr_data2); */ + + /* Vertical total */ + VT = (cr_data & 0xFF) | + ((unsigned short) (cr_data2 & 0x01) << 8) | + ((unsigned short)(cr_data2 & 0x20) << 4) | + ((unsigned short) (sr_data & 0x01) << 10); + A = VT + 2; + + cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[10]; + /* inSISIDXREG(SISCR, 0x12, cr_data); */ + + /* Vertical display enable end */ + VDE = (cr_data & 0xff) | + ((unsigned short) (cr_data2 & 0x02) << 7) | + ((unsigned short) (cr_data2 & 0x40) << 3) | + ((unsigned short) (sr_data & 0x02) << 9); + E = VDE + 1; + + cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[8]; + /* inSISIDXREG(SISCR, 0x10, cr_data); */ + + /* Vertical retrace (=sync) start */ + VRS = (cr_data & 0xff) | + ((unsigned short) (cr_data2 & 0x04) << 6) | + ((unsigned short) (cr_data2 & 0x80) << 2) | + ((unsigned short) (sr_data & 0x08) << 7); + F = VRS + 1 - E; + + cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[11]; + /* inSISIDXREG(SISCR, 0x15, cr_data); */ + + cr_data3 = (pSiS->SiS_Pr->SiS_CRT1Table[index].CR[16] & 0x01) << 5; + /* inSISIDXREG(SISCR, 0x09, cr_data3); */ + + /* Vertical blank start */ + VBS = (cr_data & 0xff) | + ((unsigned short) (cr_data2 & 0x08) << 5) | + ((unsigned short) (cr_data3 & 0x20) << 4) | + ((unsigned short) (sr_data & 0x04) << 8); + + cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[12]; + /* inSISIDXREG(SISCR, 0x16, cr_data); */ + + /* Vertical blank end */ + VBE = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0x10) << 4); + temp = VBE - ((E - 1) & 511); + B = (temp > 0) ? temp : (temp + 512); + + cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[9]; + /* inSISIDXREG(SISCR, 0x11, cr_data); */ + + /* Vertical retrace (=sync) end */ + VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1); + temp = VRE - ((E + F - 1) & 31); + C = (temp > 0) ? temp : (temp + 32); + + D = B - F - C; + + current->VDisplay = VDE + 1; + current->VSyncStart = VRS + 1; + current->VSyncEnd = ((VRS & ~0x1f) | VRE) + 1; + if(VRE <= (VRS & 0x1f)) current->VSyncEnd += 32; + current->VTotal = E + D + C + F; + +#if 0 + current->VDisplay = E; + current->VSyncStart = E + D; + current->VSyncEnd = E + D + C; + current->VTotal = E + D + C + F; +#endif + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, + "V: A %d B %d C %d D %d E %d F %d VT %d VDE %d VRS %d VBS %d VBE %d VRE %d\n", + A, B, C, D, E, F, VT, VDE, VRS, VBS, VBE, VRE); +#endif + + if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x4000) + current->Flags |= V_NHSYNC; + else + current->Flags |= V_PHSYNC; + + if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x8000) + current->Flags |= V_NVSYNC; + else + current->Flags |= V_PVSYNC; + + if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x0080) + current->Flags |= V_INTERLACE; + + j = 0; + while(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) { + if(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID == + pSiS->SiS_Pr->SiS_RefIndex[i].ModeID) { + if(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) { + current->Flags |= V_DBLSCAN; + } + break; + } + j++; + } + + if(current->Flags & V_INTERLACE) { + current->VDisplay <<= 1; + current->VSyncStart <<= 1; + current->VSyncEnd <<= 1; + current->VTotal <<= 1; + current->VTotal |= 1; + } + if(current->Flags & V_DBLSCAN) { + current->Clock >>= 1; + current->VDisplay >>= 1; + current->VSyncStart >>= 1; + current->VSyncEnd >>= 1; + current->VTotal >>= 1; + } + +#ifdef TWDEBUG + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Built-in: %s %.2f %d %d %d %d %d %d %d %d\n", + current->name, (float)current->Clock / 1000, + current->HDisplay, current->HSyncStart, current->HSyncEnd, current->HTotal, + current->VDisplay, current->VSyncStart, current->VSyncEnd, current->VTotal); +#else + (void)VBS; (void)HBS; (void)A; +#endif + + i++; + } + + /* Add non-standard LCD modes for panel's detailed timings */ + + if(!includelcdmodes) return first; + + if(pSiS->SiS_Pr->CP_Vendor) { + xf86DrvMsg(0, X_INFO, "Checking database for vendor %x, product %x\n", + pSiS->SiS_Pr->CP_Vendor, pSiS->SiS_Pr->CP_Product); + } + + i = 0; + while((!done) && (SiS_PlasmaTable[i].vendor) && (pSiS->SiS_Pr->CP_Vendor)) { + + if(SiS_PlasmaTable[i].vendor == pSiS->SiS_Pr->CP_Vendor) { + + for(j=0; j<SiS_PlasmaTable[i].productnum; j++) { + + if(SiS_PlasmaTable[i].product[j] == pSiS->SiS_Pr->CP_Product) { + + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "Identified %s panel, adding specific modes\n", + SiS_PlasmaTable[i].plasmaname); + + for(k=0; k<SiS_PlasmaTable[i].modenum; k++) { + + if(isfordvi) { + if(!(SiS_PlasmaTable[i].plasmamodes[k] & 0x80)) continue; + } else { + if(!(SiS_PlasmaTable[i].plasmamodes[k] & 0x40)) continue; + } + + l = SiS_PlasmaTable[i].plasmamodes[k] & 0x3f; + + if(pSiS->VBFlags & (VB_301|VB_301B|VB_302B|VB_301LV)) { + if(isfordvi) { + if(SiS_PlasmaMode[l].VDisplay > 1024) continue; + } + } + + if(!(new = xalloc(sizeof(DisplayModeRec)))) return first; + + memset(new, 0, sizeof(DisplayModeRec)); + if(!(new->name = xalloc(12))) { + xfree(new); + return first; + } + if(!first) first = new; + if(current) { + current->next = new; + new->prev = current; + } + + current = new; + + pSiS->AddedPlasmaModes = TRUE; + + strcpy(current->name, SiS_PlasmaMode[l].name); + /* sprintf(current->name, "%dx%d", SiS_PlasmaMode[l].HDisplay, + SiS_PlasmaMode[l].VDisplay); */ + + current->status = MODE_OK; + + current->type = M_T_BUILTIN; + + current->Clock = SiS_PlasmaMode[l].clock; + current->SynthClock = current->Clock; + + current->HDisplay = SiS_PlasmaMode[l].HDisplay; + current->HSyncStart = current->HDisplay + SiS_PlasmaMode[l].HFrontPorch; + current->HSyncEnd = current->HSyncStart + SiS_PlasmaMode[l].HSyncWidth; + current->HTotal = SiS_PlasmaMode[l].HTotal; + + current->VDisplay = SiS_PlasmaMode[l].VDisplay; + current->VSyncStart = current->VDisplay + SiS_PlasmaMode[l].VFrontPorch; + current->VSyncEnd = current->VSyncStart + SiS_PlasmaMode[l].VSyncWidth; + current->VTotal = SiS_PlasmaMode[l].VTotal; + + current->CrtcHDisplay = current->HDisplay; + current->CrtcHBlankStart = current->HSyncStart; + current->CrtcHSyncStart = current->HSyncStart; + current->CrtcHSyncEnd = current->HSyncEnd; + current->CrtcHBlankEnd = current->HSyncEnd; + current->CrtcHTotal = current->HTotal; + + current->CrtcVDisplay = current->VDisplay; + current->CrtcVBlankStart = current->VSyncStart; + current->CrtcVSyncStart = current->VSyncStart; + current->CrtcVSyncEnd = current->VSyncEnd; + current->CrtcVBlankEnd = current->VSyncEnd; + current->CrtcVTotal = current->VTotal; + + if(SiS_PlasmaMode[l].SyncFlags & SIS_PL_HSYNCP) + current->Flags |= V_PHSYNC; + else + current->Flags |= V_NHSYNC; + + if(SiS_PlasmaMode[l].SyncFlags & SIS_PL_VSYNCP) + current->Flags |= V_PVSYNC; + else + current->Flags |= V_NVSYNC; + + if(current->HDisplay > pSiS->LCDwidth) + pSiS->LCDwidth = pSiS->SiS_Pr->CP_MaxX = current->HDisplay; + if(current->VDisplay > pSiS->LCDheight) + pSiS->LCDheight = pSiS->SiS_Pr->CP_MaxY = current->VDisplay; + + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "\tAdding \"%s\" to list of built-in modes\n", current->name); + + } + done = TRUE; + break; + } + } + } + + i++; + + } + + if(pSiS->SiS_Pr->CP_HaveCustomData) { + + for(i=0; i<7; i++) { + + if(pSiS->SiS_Pr->CP_DataValid[i]) { + + if(!(new = xalloc(sizeof(DisplayModeRec)))) return first; + + memset(new, 0, sizeof(DisplayModeRec)); + if(!(new->name = xalloc(10))) { + xfree(new); + return first; + } + if(!first) first = new; + if(current) { + current->next = new; + new->prev = current; + } + + current = new; + + sprintf(current->name, "%dx%d", pSiS->SiS_Pr->CP_HDisplay[i], + pSiS->SiS_Pr->CP_VDisplay[i]); + + current->status = MODE_OK; + + current->type = M_T_BUILTIN; + + current->Clock = pSiS->SiS_Pr->CP_Clock[i]; + current->SynthClock = current->Clock; + + current->HDisplay = pSiS->SiS_Pr->CP_HDisplay[i]; + current->HSyncStart = pSiS->SiS_Pr->CP_HSyncStart[i]; + current->HSyncEnd = pSiS->SiS_Pr->CP_HSyncEnd[i]; + current->HTotal = pSiS->SiS_Pr->CP_HTotal[i]; + + current->VDisplay = pSiS->SiS_Pr->CP_VDisplay[i]; + current->VSyncStart = pSiS->SiS_Pr->CP_VSyncStart[i]; + current->VSyncEnd = pSiS->SiS_Pr->CP_VSyncEnd[i]; + current->VTotal = pSiS->SiS_Pr->CP_VTotal[i]; + + current->CrtcHDisplay = current->HDisplay; + current->CrtcHBlankStart = pSiS->SiS_Pr->CP_HBlankStart[i]; + current->CrtcHSyncStart = current->HSyncStart; + current->CrtcHSyncEnd = current->HSyncEnd; + current->CrtcHBlankEnd = pSiS->SiS_Pr->CP_HBlankEnd[i]; + current->CrtcHTotal = current->HTotal; + + current->CrtcVDisplay = current->VDisplay; + current->CrtcVBlankStart = pSiS->SiS_Pr->CP_VBlankStart[i]; + current->CrtcVSyncStart = current->VSyncStart; + current->CrtcVSyncEnd = current->VSyncEnd; + current->CrtcVBlankEnd = pSiS->SiS_Pr->CP_VBlankEnd[i]; + current->CrtcVTotal = current->VTotal; + + if(pSiS->SiS_Pr->CP_SyncValid[i]) { + if(pSiS->SiS_Pr->CP_HSync_P[i]) + current->Flags |= V_PHSYNC; + else + current->Flags |= V_NHSYNC; + + if(pSiS->SiS_Pr->CP_VSync_P[i]) + current->Flags |= V_PVSYNC; + else + current->Flags |= V_NVSYNC; + } else { + /* No sync data? Use positive sync... */ + current->Flags |= V_PHSYNC; + current->Flags |= V_PVSYNC; + } + } + } + } + + return first; + +} + +/* Translate a mode number into the VESA pendant */ +int +SiSTranslateToVESA(ScrnInfoPtr pScrn, int modenumber) +{ + SISPtr pSiS = SISPTR(pScrn); + int i = 0; + + /* Initialize our pointers */ + if(pSiS->VGAEngine == SIS_300_VGA) { +#ifdef SIS300 + InitTo300Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext); +#else + return -1; +#endif + } else if(pSiS->VGAEngine == SIS_315_VGA) { +#ifdef SIS315H + InitTo310Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext); +#else + return -1; +#endif + } else return -1; + + if(modenumber <= 0x13) return modenumber; + +#ifdef SIS315H + if(pSiS->ROM661New) { + while(SiS_EModeIDTable661[i].Ext_ModeID != 0xff) { + if(SiS_EModeIDTable661[i].Ext_ModeID == modenumber) { + return (int)SiS_EModeIDTable661[i].Ext_VESAID; + } + i++; + } + } else { +#endif + while(pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID != 0xff) { + if(pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID == modenumber) { + return (int)pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID; + } + i++; + } +#ifdef SIS315H + } +#endif + return -1; +} + +/* Translate a new BIOS mode number into the driver's pendant */ +int +SiSTranslateToOldMode(int modenumber) +{ +#ifdef SIS315H + int i = 0; + + while(SiS_EModeIDTable661[i].Ext_ModeID != 0xff) { + if(SiS_EModeIDTable661[i].Ext_ModeID == modenumber) { + if(SiS_EModeIDTable661[i].Ext_MyModeID) + return (int)SiS_EModeIDTable661[i].Ext_MyModeID; + else + return modenumber; + } + i++; + } +#endif + return modenumber; +} + +#endif /* Xfree86 */ + +#ifdef LINUX_KERNEL +int +sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + unsigned char modeno, unsigned char rateindex) +{ + USHORT ModeNo = modeno; + USHORT ModeIdIndex = 0, ClockIndex = 0; + USHORT RefreshRateTableIndex = 0; + int Clock; + + if(HwInfo->jChipType < SIS_315H) { +#ifdef SIS300 + InitTo300Pointer(SiS_Pr, HwInfo); +#else + return 65 * 1000; +#endif + } else { +#ifdef SIS315H + InitTo310Pointer(SiS_Pr, HwInfo); +#else + return 65 * 1000; +#endif + } + + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {; + printk(KERN_ERR "Could not find mode %x\n", ModeNo); + return 65 * 1000; + } + + RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + RefreshRateTableIndex += (rateindex - 1); + ClockIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + if(HwInfo->jChipType < SIS_315H) { + ClockIndex &= 0x3F; + } + Clock = SiS_Pr->SiS_VCLKData[ClockIndex].CLOCK * 1000; + + return(Clock); +} + +BOOLEAN +sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex) +{ + USHORT ModeNo = modeno; + USHORT ModeIdIndex = 0, CRT1Index = 0; + USHORT RefreshRateTableIndex = 0; + unsigned char sr_data, cr_data, cr_data2; + + if(HwInfo->jChipType < SIS_315H) { +#ifdef SIS300 + InitTo300Pointer(SiS_Pr, HwInfo); +#else + return FALSE; +#endif + } else { +#ifdef SIS315H + InitTo310Pointer(SiS_Pr, HwInfo); +#else + return FALSE; +#endif + } + + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE; + + RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + RefreshRateTableIndex += (rateindex - 1); + CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + + sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14]; + cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[0]; + *htotal = (((cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8)) + 5) * 8; + + sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]; + cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[6]; + cr_data2 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7]; + *vtotal = ((cr_data & 0xFF) | + ((unsigned short)(cr_data2 & 0x01) << 8) | + ((unsigned short)(cr_data2 & 0x20) << 4) | + ((unsigned short)(sr_data & 0x01) << 10)) + 2; + + if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & InterlaceMode) + *vtotal *= 2; + + return TRUE; +} + +int +sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + unsigned char modeno, unsigned char rateindex, + struct fb_var_screeninfo *var) +{ + USHORT ModeNo = modeno; + USHORT ModeIdIndex = 0, index = 0; + USHORT RefreshRateTableIndex = 0; + unsigned short VRE, VBE, VRS, VBS, VDE, VT; + unsigned short HRE, HBE, HRS, HBS, HDE, HT; + unsigned char sr_data, cr_data, cr_data2, cr_data3; + int A, B, C, D, E, F, temp, j; + + if(HwInfo->jChipType < SIS_315H) { +#ifdef SIS300 + InitTo300Pointer(SiS_Pr, HwInfo); +#else + return 0; +#endif + } else { +#ifdef SIS315H + InitTo310Pointer(SiS_Pr, HwInfo); +#else + return 0; +#endif + } + + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return 0; + + RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + RefreshRateTableIndex += (rateindex - 1); + index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + + sr_data = SiS_Pr->SiS_CRT1Table[index].CR[14]; + + cr_data = SiS_Pr->SiS_CRT1Table[index].CR[0]; + + /* Horizontal total */ + HT = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0x03) << 8); + A = HT + 5; + + cr_data = SiS_Pr->SiS_CRT1Table[index].CR[1]; + + /* Horizontal display enable end */ + HDE = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0x0C) << 6); + E = HDE + 1; + + cr_data = SiS_Pr->SiS_CRT1Table[index].CR[4]; + + /* Horizontal retrace (=sync) start */ + HRS = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0xC0) << 2); + F = HRS - E - 3; + + cr_data = SiS_Pr->SiS_CRT1Table[index].CR[2]; + + /* Horizontal blank start */ + HBS = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0x30) << 4); + + sr_data = SiS_Pr->SiS_CRT1Table[index].CR[15]; + + cr_data = SiS_Pr->SiS_CRT1Table[index].CR[3]; + + cr_data2 = SiS_Pr->SiS_CRT1Table[index].CR[5]; + + /* Horizontal blank end */ + HBE = (cr_data & 0x1f) | + ((unsigned short) (cr_data2 & 0x80) >> 2) | + ((unsigned short) (sr_data & 0x03) << 6); + + /* Horizontal retrace (=sync) end */ + HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3); + + temp = HBE - ((E - 1) & 255); + B = (temp > 0) ? temp : (temp + 256); + + temp = HRE - ((E + F + 3) & 63); + C = (temp > 0) ? temp : (temp + 64); + + D = B - F - C; + + if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes == 320) && + ((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].YRes == 200) || + (SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].YRes == 240))) { + + /* Terrible hack, but the correct CRTC data for + * these modes only produces a black screen... + */ + var->left_margin = (400 - 376); + var->right_margin = (328 - 320); + var->hsync_len = (376 - 328); + + } else { + + var->left_margin = D * 8; + var->right_margin = F * 8; + var->hsync_len = C * 8; + + } + + sr_data = SiS_Pr->SiS_CRT1Table[index].CR[13]; + + cr_data = SiS_Pr->SiS_CRT1Table[index].CR[6]; + + cr_data2 = SiS_Pr->SiS_CRT1Table[index].CR[7]; + + /* Vertical total */ + VT = (cr_data & 0xFF) | + ((unsigned short) (cr_data2 & 0x01) << 8) | + ((unsigned short)(cr_data2 & 0x20) << 4) | + ((unsigned short) (sr_data & 0x01) << 10); + A = VT + 2; + + cr_data = SiS_Pr->SiS_CRT1Table[index].CR[10]; + + /* Vertical display enable end */ + VDE = (cr_data & 0xff) | + ((unsigned short) (cr_data2 & 0x02) << 7) | + ((unsigned short) (cr_data2 & 0x40) << 3) | + ((unsigned short) (sr_data & 0x02) << 9); + E = VDE + 1; + + cr_data = SiS_Pr->SiS_CRT1Table[index].CR[8]; + + /* Vertical retrace (=sync) start */ + VRS = (cr_data & 0xff) | + ((unsigned short) (cr_data2 & 0x04) << 6) | + ((unsigned short) (cr_data2 & 0x80) << 2) | + ((unsigned short) (sr_data & 0x08) << 7); + F = VRS + 1 - E; + + cr_data = SiS_Pr->SiS_CRT1Table[index].CR[11]; + + cr_data3 = (SiS_Pr->SiS_CRT1Table[index].CR[16] & 0x01) << 5; + + /* Vertical blank start */ + VBS = (cr_data & 0xff) | + ((unsigned short) (cr_data2 & 0x08) << 5) | + ((unsigned short) (cr_data3 & 0x20) << 4) | + ((unsigned short) (sr_data & 0x04) << 8); + + cr_data = SiS_Pr->SiS_CRT1Table[index].CR[12]; + + /* Vertical blank end */ + VBE = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0x10) << 4); + temp = VBE - ((E - 1) & 511); + B = (temp > 0) ? temp : (temp + 512); + + cr_data = SiS_Pr->SiS_CRT1Table[index].CR[9]; + + /* Vertical retrace (=sync) end */ + VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1); + temp = VRE - ((E + F - 1) & 31); + C = (temp > 0) ? temp : (temp + 32); + + D = B - F - C; + + var->upper_margin = D; + var->lower_margin = F; + var->vsync_len = C; + + if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x8000) + var->sync &= ~FB_SYNC_VERT_HIGH_ACT; + else + var->sync |= FB_SYNC_VERT_HIGH_ACT; + + if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x4000) + var->sync &= ~FB_SYNC_HOR_HIGH_ACT; + else + var->sync |= FB_SYNC_HOR_HIGH_ACT; + + var->vmode = FB_VMODE_NONINTERLACED; + if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x0080) + var->vmode = FB_VMODE_INTERLACED; + else { + j = 0; + while(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) { + if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID == + SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].ModeID) { + if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) { + var->vmode = FB_VMODE_DOUBLE; + } + break; + } + j++; + } + } + + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { +#if 0 /* Do this? */ + var->upper_margin <<= 1; + var->lower_margin <<= 1; + var->vsync_len <<= 1; +#endif + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + var->upper_margin >>= 1; + var->lower_margin >>= 1; + var->vsync_len >>= 1; + } + + return 1; +} + +#endif + diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h new file mode 100644 index 000000000000..35030d300431 --- /dev/null +++ b/drivers/video/sis/init.h @@ -0,0 +1,2472 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Data and prototypes for init.c + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _INIT_ +#define _INIT_ + +#include "osdef.h" +#include "initdef.h" + +#ifdef LINUX_XF86 +#include "sis.h" +#include "sis_regs.h" +#endif + +#ifdef LINUX_KERNEL +#include "vgatypes.h" +#include "vstruct.h" +#ifdef SIS_CP +#undef SIS_CP +#endif +#include <linux/config.h> +#include <linux/version.h> +#include <linux/types.h> +#include <asm/io.h> +#include <linux/fb.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include <linux/sisfb.h> +#else +#include <video/sisfb.h> +#endif +#endif + +/* Mode numbers */ +static const USHORT ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f}; +static const USHORT ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53}; +static const USHORT ModeIndex_320x240_FSTN[] = {0x5a, 0x5b, 0x00, 0x00}; /* FSTN */ +static const USHORT ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54}; +static const USHORT ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c}; +static const USHORT ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e}; +static const USHORT ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62}; +static const USHORT ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35}; +static const USHORT ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36}; +static const USHORT ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61}; +static const USHORT ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76}; +static const USHORT ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63}; +static const USHORT ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e}; +static const USHORT ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45}; +static const USHORT ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f}; /* 315 series only */ +static const USHORT ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22}; /* 315 series only */ +static const USHORT ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64}; +static const USHORT ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77}; +static const USHORT ModeIndex_1024x600[] = {0x20, 0x21, 0x00, 0x22}; /* 300 series only */ +static const USHORT ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65}; +static const USHORT ModeIndex_1280x960[] = {0x7c, 0x7d, 0x00, 0x7e}; +static const USHORT ModeIndex_1152x768[] = {0x23, 0x24, 0x00, 0x25}; /* 300 series only */ +static const USHORT ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b}; +static const USHORT ModeIndex_300_1280x768[] = {0x55, 0x5a, 0x00, 0x5b}; +static const USHORT ModeIndex_310_1280x768[] = {0x23, 0x24, 0x00, 0x25}; +static const USHORT ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78}; +static const USHORT ModeIndex_1280x800[] = {0x14, 0x15, 0x00, 0x16}; +static const USHORT ModeIndex_1360x768[] = {0x48, 0x4b, 0x00, 0x4e}; +static const USHORT ModeIndex_300_1360x1024[]= {0x67, 0x6f, 0x00, 0x72}; /* 300 series, BARCO only */ +static const USHORT ModeIndex_1400x1050[] = {0x26, 0x27, 0x00, 0x28}; /* 315 series only */ +static const USHORT ModeIndex_1680x1050[] = {0x17, 0x18, 0x00, 0x19}; /* 315 series only */ +static const USHORT ModeIndex_1600x1200[] = {0x3c, 0x3d, 0x00, 0x66}; +static const USHORT ModeIndex_1920x1080[] = {0x2c, 0x2d, 0x00, 0x73}; /* 315 series only */ +static const USHORT ModeIndex_1920x1440[] = {0x68, 0x69, 0x00, 0x6b}; +static const USHORT ModeIndex_300_2048x1536[]= {0x6c, 0x6d, 0x00, 0x00}; +static const USHORT ModeIndex_310_2048x1536[]= {0x6c, 0x6d, 0x00, 0x6e}; + +static const USHORT SiS_DRAMType[17][5]={ + {0x0C,0x0A,0x02,0x40,0x39}, + {0x0D,0x0A,0x01,0x40,0x48}, + {0x0C,0x09,0x02,0x20,0x35}, + {0x0D,0x09,0x01,0x20,0x44}, + {0x0C,0x08,0x02,0x10,0x31}, + {0x0D,0x08,0x01,0x10,0x40}, + {0x0C,0x0A,0x01,0x20,0x34}, + {0x0C,0x09,0x01,0x08,0x32}, + {0x0B,0x08,0x02,0x08,0x21}, + {0x0C,0x08,0x01,0x08,0x30}, + {0x0A,0x08,0x02,0x04,0x11}, + {0x0B,0x0A,0x01,0x10,0x28}, + {0x09,0x08,0x02,0x02,0x01}, + {0x0B,0x09,0x01,0x08,0x24}, + {0x0B,0x08,0x01,0x04,0x20}, + {0x0A,0x08,0x01,0x02,0x10}, + {0x09,0x08,0x01,0x01,0x00} +}; + +static const USHORT SiS_SDRDRAM_TYPE[13][5] = +{ + { 2,12, 9,64,0x35}, + { 1,13, 9,64,0x44}, + { 2,12, 8,32,0x31}, + { 2,11, 9,32,0x25}, + { 1,12, 9,32,0x34}, + { 1,13, 8,32,0x40}, + { 2,11, 8,16,0x21}, + { 1,12, 8,16,0x30}, + { 1,11, 9,16,0x24}, + { 1,11, 8, 8,0x20}, + { 2, 9, 8, 4,0x01}, + { 1,10, 8, 4,0x10}, + { 1, 9, 8, 2,0x00} +}; + +static const USHORT SiS_DDRDRAM_TYPE[4][5] = +{ + { 2,12, 9,64,0x35}, + { 2,12, 8,32,0x31}, + { 2,11, 8,16,0x21}, + { 2, 9, 8, 4,0x01} +}; + +static const USHORT SiS_MDA_DAC[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F +}; + +static const USHORT SiS_CGA_DAC[] = +{ + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +}; + +static const USHORT SiS_EGA_DAC[] = +{ + 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, + 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, + 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D, + 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D, + 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17, + 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37, + 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +}; + +static const USHORT SiS_VGA_DAC[] = +{ + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18, + 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F, + 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F, + 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00, + 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18, + 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04, + 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10, + 0x0B,0x0C,0x0D,0x0F,0x10 +}; + +static const SiS_StResInfoStruct SiS_StResInfo[]= +{ + { 640,400}, + { 640,350}, + { 720,400}, + { 720,350}, + { 640,480} +}; + +static const SiS_ModeResInfoStruct SiS_ModeResInfo[] = +{ + { 320, 200, 8, 8}, /* 0x00 */ + { 320, 240, 8, 8}, /* 0x01 */ + { 320, 400, 8, 8}, /* 0x02 */ + { 400, 300, 8, 8}, /* 0x03 */ + { 512, 384, 8, 8}, /* 0x04 */ + { 640, 400, 8,16}, /* 0x05 */ + { 640, 480, 8,16}, /* 0x06 */ + { 800, 600, 8,16}, /* 0x07 */ + { 1024, 768, 8,16}, /* 0x08 */ + { 1280,1024, 8,16}, /* 0x09 */ + { 1600,1200, 8,16}, /* 0x0a */ + { 1920,1440, 8,16}, /* 0x0b */ + { 2048,1536, 8,16}, /* 0x0c */ + { 720, 480, 8,16}, /* 0x0d */ + { 720, 576, 8,16}, /* 0x0e */ + { 1280, 960, 8,16}, /* 0x0f */ + { 800, 480, 8,16}, /* 0x10 */ + { 1024, 576, 8,16}, /* 0x11 */ + { 1280, 720, 8,16}, /* 0x12 */ + { 856, 480, 8,16}, /* 0x13 */ + { 1280, 768, 8,16}, /* 0x14 */ + { 1400,1050, 8,16}, /* 0x15 */ + { 1152, 864, 8,16}, /* 0x16 */ + { 848, 480, 8,16}, /* 0x17 */ + { 1360, 768, 8,16}, /* 0x18 */ + { 1024, 600, 8,16}, /* 0x19 */ + { 1152, 768, 8,16}, /* 0x1a */ + { 768, 576, 8,16}, /* 0x1b */ + { 1360,1024, 8,16}, /* 0x1c */ + { 1680,1050, 8,16}, /* 0x1d */ + { 1280, 800, 8,16}, /* 0x1e */ + { 1920,1080, 8,16}, /* 0x1f */ + { 960, 540, 8,16}, /* 0x20 */ + { 960, 600, 8,16} /* 0x21 */ +}; + +#if defined(SIS300) || defined(SIS315H) +static const SiS_StandTableStruct SiS_StandTable[]= +{ +/* 0x00: MD_0_200 */ + { + 0x28,0x18,0x08,0x0800, + {0x09,0x03,0x00,0x02}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x01: MD_1_200 */ + { + 0x28,0x18,0x08,0x0800, + {0x09,0x03,0x00,0x02}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x02: MD_2_200 */ + { + 0x50,0x18,0x08,0x1000, + {0x01,0x03,0x00,0x02}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x03: MD_3_200 - mode 0x03 - 0 */ + { + 0x50,0x18,0x08,0x1000, + {0x01,0x03,0x00,0x02}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x04: MD_4 */ + { + 0x28,0x18,0x08,0x4000, + {0x09,0x03,0x00,0x02}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, /* 0x2c is 2b for 300 */ + 0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2, + 0xff}, + {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x03,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00, + 0xff} + }, +/* 0x05: MD_5 */ + { + 0x28,0x18,0x08,0x4000, + {0x09,0x03,0x00,0x02}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, /* 0x2c is 2b for 300 */ + 0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2, + 0xff}, + {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x03,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00, + 0xff} + }, +/* 0x06: MD_6 */ + { + 0x50,0x18,0x08,0x4000, + {0x01,0x01,0x00,0x06}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, /* 55,81 is 54,80 for 300 */ + 0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2, + 0xff}, + {0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17, + 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, + 0x01,0x00,0x01,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00, + 0xff} + }, +/* 0x07: MD_7 */ + { + 0x50,0x18,0x0e,0x1000, + {0x00,0x03,0x00,0x03}, + 0xa6, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x28,0x0d,0x63,0xba,0xa3, + 0xff}, + {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0x0e,0x00,0x0f,0x08}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00, + 0xff} + }, +/* 0x08: MDA_DAC */ + { + 0x00,0x00,0x00,0x0000, + {0x00,0x00,0x00,0x15}, + 0x15, + {0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0x00, + 0x00}, + {0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15}, + {0x15,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f} + }, +/* 0x09: CGA_DAC */ + { + 0x00,0x10,0x04,0x0114, + {0x11,0x09,0x15,0x00}, + 0x10, + {0x04,0x14,0x01,0x11,0x09,0x15,0x2a,0x3a, + 0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x2a,0x3a, + 0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x10, + 0x04}, + {0x14,0x01,0x11,0x09,0x15,0x00,0x10,0x04, + 0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,0x2e, + 0x3e,0x2b,0x3b,0x2f}, + {0x3f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f, + 0x3f} + }, +/* 0x0a: EGA_DAC */ + { + 0x00,0x10,0x04,0x0114, + {0x11,0x05,0x15,0x20}, + 0x30, + {0x24,0x34,0x21,0x31,0x25,0x35,0x08,0x18, + 0x0c,0x1c,0x09,0x19,0x0d,0x1d,0x28,0x38, + 0x2c,0x3c,0x29,0x39,0x2d,0x3d,0x02,0x12, + 0x06}, + {0x16,0x03,0x13,0x07,0x17,0x22,0x32,0x26, + 0x36,0x23,0x33,0x27,0x37,0x0a,0x1a,0x0e, + 0x1e,0x0b,0x1b,0x0f}, + {0x1f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f, + 0x3f} + }, +/* 0x0b: VGA_DAC */ + { + 0x00,0x10,0x04,0x0114, + {0x11,0x09,0x15,0x2a}, + 0x3a, + {0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x05, + 0x08,0x0b,0x0e,0x11,0x14,0x18,0x1c,0x20, + 0x24,0x28,0x2d,0x32,0x38,0x3f,0x00,0x10, + 0x1f}, + {0x2f,0x3f,0x1f,0x27,0x2f,0x37,0x3f,0x2d, + 0x31,0x36,0x3a,0x3f,0x00,0x07,0x0e,0x15, + 0x1c,0x0e,0x11,0x15}, + {0x18,0x1c,0x14,0x16,0x18,0x1a,0x1c,0x00, + 0x04} + }, +/* 0x0c */ + { + 0x08,0x0c,0x10,0x0a08, + {0x0c,0x0e,0x10,0x0b}, + 0x0c, + {0x0d,0x0f,0x10,0x10,0x01,0x08,0x00,0x00, + 0x00,0x00,0x01,0x00,0x02,0x02,0x01,0x00, + 0x04,0x04,0x01,0x00,0x05,0x02,0x05,0x00, + 0x06}, + {0x01,0x06,0x05,0x06,0x00,0x08,0x01,0x08, + 0x00,0x07,0x02,0x07,0x06,0x07,0x00,0x00, + 0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00} + }, +/* 0x0d: MD_D */ + { + 0x28,0x18,0x08,0x2000, + {0x09,0x0f,0x00,0x06}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, /* 2c is 2b for 300 */ + 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, + 0xff} + }, +/* 0x0e: MD_E */ + { + 0x50,0x18,0x08,0x4000, + {0x01,0x0f,0x00,0x06}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, /* 55,81 is 54,80 for 300 */ + 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, + 0xff} + }, +/* 0x0f: ExtVGATable - modes > 0x13 */ + { + 0x00,0x00,0x00,0x0000, + {0x01,0x0f,0x00,0x0e}, + 0x23, + {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x01,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, + 0xff} + }, +/* 0x10: ROM_SAVEPTR - totally different for 300 */ + { + 0x9f,0x3b,0x00,0x00c0, + {0x00,0x00,0x00,0x00}, + 0x00, + {0x00,0x00,0x00,0x00,0x00,0x00,0xbb,0x3f, + 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x1a,0x00,0xac,0x3e,0x00,0xc0, + 0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00} + }, +/* 0x11: MD_F */ + { + 0x50,0x18,0x0e,0x8000, + {0x01,0x0f,0x00,0x06}, + 0xa2, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, /* 55,81 is 54,80 on 300 */ + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3, /* 82,84 is 83,85 on 300 */ + 0xff}, + {0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00, + 0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00, + 0x0b,0x00,0x05,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x05, + 0xff} + }, +/* 0x12: MD_10 */ + { + 0x50,0x18,0x0e,0x8000, + {0x01,0x0f,0x00,0x06}, + 0xa3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, /* 55,81 is 54,80 on 300 */ + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3, /* 82,84 is 83,85 on 300 */ + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, + 0xff} + }, +/* 0x13: MD_0_350 */ + { + 0x28,0x18,0x0e,0x0800, + {0x09,0x03,0x00,0x02}, + 0xa3, + {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f, /* b1 is a0 on 300 */ + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x14: MD_1_350 */ + { + 0x28,0x18,0x0e,0x0800, + {0x09,0x03,0x00,0x02}, + 0xa3, + {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x15: MD_2_350 */ + { + 0x50,0x18,0x0e,0x1000, + {0x01,0x03,0x00,0x02}, + 0xa3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x16: MD_3_350 - mode 0x03 - 1 */ + { + 0x50,0x18,0x0e,0x1000, + {0x01,0x03,0x00,0x02}, + 0xa3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x17: MD_0_1_400 */ + { + 0x28,0x18,0x10,0x0800, + {0x08,0x03,0x00,0x02}, + 0x67, + {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f, /* b1 is a0 on 300 */ + 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x0c,0x00,0x0f,0x08}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x18: MD_2_3_400 - mode 0x03 - 2 */ + { + 0x50,0x18,0x10,0x1000, + {0x00,0x03,0x00,0x02}, + 0x67, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x0c,0x00,0x0f,0x08}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x19: MD_7_400 */ + { + 0x50,0x18,0x10,0x1000, + {0x00,0x03,0x00,0x02}, + 0x66, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0x0e,0x00,0x0f,0x08}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00, + 0xff} + }, +/* 0x1a: MD_11 */ + { + 0x50,0x1d,0x10,0xa000, + {0x01,0x0f,0x00,0x06}, + 0xe3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e, /* 55,81 is 54,80 on 300 */ + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xc3, /* e9,8b is ea,8c on 300 */ + 0xff}, + {0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x01, + 0xff} + }, +/* 0x1b: ExtEGATable - Modes <= 0x02 */ + { + 0x50,0x1d,0x10,0xa000, + {0x01,0x0f,0x00,0x06}, + 0xe3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e, /* 55,81 is 54,80 on 300 */ + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3, /* e9,8b is ea,8c on 300 */ + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, + 0xff} + }, +/* 0x1c: MD_13 */ + { + 0x28,0x18,0x08,0x2000, + {0x01,0x0f,0x00,0x0e}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, /* 55,81 is 54,80 on 300 */ + 0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x41,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, + 0xff} + } +}; +#endif + +/**************************************************************/ +/* SIS VIDEO BRIDGE ----------------------------------------- */ +/**************************************************************/ + +static const UCHAR SiS_SoftSetting = 0x30; /* RAM setting */ + +static const UCHAR SiS_OutputSelect = 0x40; + +static const UCHAR SiS_NTSCTiming[] = { + 0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c, + 0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b, + 0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17, + 0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02, + 0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50, + 0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00 +}; + +static const UCHAR SiS_PALTiming[] = { + 0x19,0x52,0x35,0x6e,0x04,0x38,0x3d,0x70, + 0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d, + 0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b, + 0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17, + 0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02, + 0x0d,0x00,0x68,0xb0,0x0b,0x92,0x8f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63, + 0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00 +}; + +static const UCHAR SiS_HiTVExtTiming[] = { + 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64, + 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, + 0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f, + 0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13, + 0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40, + 0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d, + 0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00 +}; + +static const UCHAR SiS_HiTVSt1Timing[] = { + 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65, + 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, + 0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f, + 0x65,0x90,0x7b,0xa8,0x03,0xf0,0x87,0x03, + 0x11,0x15,0x11,0xcf,0x10,0x11,0xcf,0x10, + 0x35,0x35,0x3b,0x69,0x1d,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x86, + 0xaf,0x5d,0x0e,0x00,0xfc,0xff,0x2d,0x00 +}; + +static const UCHAR SiS_HiTVSt2Timing[] = { + 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64, + 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, + 0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f, + 0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13, + 0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40, + 0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d, + 0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00 +}; + +#if 0 +static const UCHAR SiS_HiTVTextTiming[] = { + 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65, + 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, + 0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f, + 0x65,0x90,0xe7,0xbc,0x03,0x0c,0x97,0x03, + 0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20, + 0xc8,0xc8,0x3b,0xd2,0x26,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x96, + 0x72,0x5c,0x11,0x00,0xfc,0xff,0x32,0x00 +}; +#endif + +static const UCHAR SiS_HiTVGroup3Data[] = { + 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x5f, + 0x05,0x21,0xb2,0xb2,0x55,0x77,0x2a,0xa6, + 0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20, + 0x8c,0x6e,0x60,0x2e,0x58,0x48,0x72,0x44, + 0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80, + 0x4f,0x7f,0x03,0xa8,0x7d,0x20,0x1a,0xa9, + 0x14,0x05,0x03,0x7e,0x64,0x31,0x14,0x75, + 0x18,0x05,0x18,0x05,0x4c,0xa8,0x01 +}; + +static const UCHAR SiS_HiTVGroup3Simu[] = { + 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x95, + 0xdb,0x20,0xb8,0xb8,0x55,0x47,0x2a,0xa6, + 0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20, + 0x8c,0x6e,0x60,0x15,0x26,0xd3,0xe4,0x11, + 0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80, + 0x67,0x36,0x01,0x47,0x0e,0x10,0xbe,0xb4, + 0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75, + 0x18,0x05,0x18,0x05,0x4c,0xa8,0x01 +}; + +#if 0 +static const UCHAR SiS_HiTVGroup3Text[] = { + 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0xa7, + 0xf5,0x20,0xce,0xce,0x55,0x47,0x2a,0xa6, + 0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20, + 0x8c,0x6e,0x60,0x18,0x2c,0x0c,0x20,0x22, + 0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80, + 0x93,0x3c,0x01,0x50,0x2f,0x10,0xf4,0xca, + 0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75, + 0x18,0x05,0x18,0x05,0x4c,0xa8,0x01 +}; +#endif + +static const UCHAR SiS_NTSCPhase[] = {0x21,0xed,0xba,0x08}; +static const UCHAR SiS_PALPhase[] = {0x2a,0x05,0xe3,0x00}; +static const UCHAR SiS_PALMPhase[] = {0x21,0xE4,0x2E,0x9B}; +static const UCHAR SiS_PALNPhase[] = {0x21,0xF4,0x3E,0xBA}; +static const UCHAR SiS_NTSCPhase2[] = {0x21,0xF0,0x7B,0xD6}; +static const UCHAR SiS_PALPhase2[] = {0x2a,0x09,0x86,0xe9}; +static const UCHAR SiS_PALMPhase2[] = {0x21,0xE6,0xEF,0xA4}; +static const UCHAR SiS_PALNPhase2[] = {0x21,0xF6,0x94,0x46}; +static const UCHAR SiS_SpecialPhase[] = {0x1e,0x8c,0x5c,0x7a}; +static const UCHAR SiS_SpecialPhaseM[]= {0x1e,0x83,0x0a,0xe0}; +static const UCHAR SiS_SpecialPhaseJ[]= {0x25,0xd4,0xfd,0x5e}; + +static const SiS_TVDataStruct SiS_StPALData[] = +{ + { 1, 1, 864, 525,1270, 400, 100, 0, 760,0xf4,0xff,0x1c,0x22}, + { 1, 1, 864, 525,1270, 350, 100, 0, 760,0xf4,0xff,0x1c,0x22}, + { 1, 1, 864, 525,1270, 400, 0, 0, 720,0xf1,0x04,0x1f,0x18}, + { 1, 1, 864, 525,1270, 350, 0, 0, 720,0xf4,0x0b,0x1c,0x0a}, + { 1, 1, 864, 525,1270, 480, 50, 0, 760,0xf4,0xff,0x1c,0x22}, + { 1, 1, 864, 525,1270, 600, 50, 0, 0,0xf4,0xff,0x1c,0x22} +}; + +static const SiS_TVDataStruct SiS_ExtPALData[] = +{ + { 27, 10, 848, 448,1270, 530, 50, 0, 50,0xf4,0xff,0x1c,0x22}, /* 640x400, 320x200 */ + { 108, 35, 848, 398,1270, 530, 50, 0, 50,0xf4,0xff,0x1c,0x22}, + { 12, 5, 954, 448,1270, 530, 50, 0, 50,0xf1,0x04,0x1f,0x18}, + { 9, 4, 960, 463,1644, 438, 50, 0, 50,0xf4,0x0b,0x1c,0x0a}, + { 9, 4, 848, 528,1270, 530, 0, 0, 50,0xf5,0xfb,0x1b,0x2a}, /* 640x480, 320x240 */ +/*{ 36, 25,1060, 648,1316, 530, 438, 0, 438,0xeb,0x05,0x25,0x16},*//* 800x600, 400x300 */ + { 36, 25,1060, 648,1270, 530, 438, 0, 438,0xeb,0x05,0x25,0x16}, /* 800x600, 400x300 - better */ + { 3, 2,1080, 619,1270, 540, 438, 0, 438,0xf3,0x00,0x1d,0x20}, /* 720x576 */ + { 1, 1,1170, 821,1270, 520, 686, 0, 686,0xF3,0x00,0x1D,0x20}, /* 1024x768 */ + { 1, 1,1170, 821,1270, 520, 686, 0, 686,0xF3,0x00,0x1D,0x20}, /* 1024x768 (for NTSC equ) */ + { 9, 4, 848, 528,1270, 530, 0, 0, 50,0xf5,0xfb,0x1b,0x2a} /* 720x480 test */ +}; + +static const SiS_TVDataStruct SiS_StNTSCData[] = +{ + { 1, 1, 858, 525,1270, 400, 50, 0, 760,0xf1,0x04,0x1f,0x18}, + { 1, 1, 858, 525,1270, 350, 50, 0, 640,0xf1,0x04,0x1f,0x18}, + { 1, 1, 858, 525,1270, 400, 0, 0, 720,0xf1,0x04,0x1f,0x18}, + { 1, 1, 858, 525,1270, 350, 0, 0, 720,0xf4,0x0b,0x1c,0x0a}, + { 1, 1, 858, 525,1270, 480, 0, 0, 760,0xf1,0x04,0x1f,0x18} +}; + +static const SiS_TVDataStruct SiS_ExtNTSCData[] = +{ + { 143, 65, 858, 443,1270, 440, 171, 0, 171,0xf1,0x04,0x1f,0x18}, /* 640x400, 320x200 */ + { 88, 35, 858, 393,1270, 440, 171, 0, 171,0xf1,0x04,0x1f,0x18}, + { 143, 70, 924, 443,1270, 440, 92, 0, 92,0xf1,0x04,0x1f,0x18}, + { 143, 70, 924, 393,1270, 440, 92, 0, 92,0xf4,0x0b,0x1c,0x0a}, + { 143, 76, 836, 523,1270, 440, 224, 0, 0,0xf1,0x05,0x1f,0x16}, /* 640x480, 320x240 */ + { 143, 120,1056, 643,1270, 440, 0, 128, 0,0xf4,0x10,0x1c,0x00}, /* 800x600, 400x300 */ +/*{ 2, 1, 858, 503,1270, 480, 0, 128, 0,0xee,0x0c,0x22,0x08},*/ /* 720x480 (old, from 650) */ + { 143, 76, 836, 523,1270, 440, 0, 128, 0,0xee,0x0c,0x22,0x08}, /* 720x480 - BETTER (from 300 series) */ +/*{ 65, 64,1056, 791,1270, 480, 638, 0, 0,0xEE,0x0C,0x22,0x08} */ /* 1024x768 (525i) */ + { 1, 1,1100, 811,1412, 440, 0, 128, 0,0xee,0x0c,0x22,0x08}, /* 1024x768 (525i) CORRECTED */ + { 65, 64,1056, 791,1270, 480, 455, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +}; + +static const SiS_TVDataStruct SiS_StHiTVData[] = /* Slave + TVSimu */ +{ + { 1, 1, 0x37c,0x233,0x2b2,0x320, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x37c,0x233,0x2b2,0x320, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x37c,0x233,0x2b2,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 8, 5, 0x41a,0x2ab,0x670,0x3c0,0x150,128, 0, 0x00,0x00,0x00,0x00} +}; + +static const SiS_TVDataStruct SiS_St2HiTVData[] = /* Slave */ +{ + { 3, 1, 0x348,0x1e3,0x670,0x3c0,0x032, 0, 0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 3, 1, 0x348,0x1e3,0x670,0x3c0,0x032, 0, 0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 5, 2, 0x348,0x233,0x670,0x3c0,0x08d,128, 0, 0x00,0x00,0x00,0x00}, + { 8, 5, 0x41a,0x2ab,0x670,0x3c0,0x17c,128, 0, 0x00,0x00,0x00,0x00} +}; + +static const SiS_TVDataStruct SiS_ExtHiTVData[] = +{ + { 6, 1, 0x348,0x233,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 3, 1, 0x3c0,0x233,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 6, 1, 0x348,0x233,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 3, 1, 0x3c0,0x233,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 5, 1, 0x348,0x233,0x670,0x3c0,0x166,128, 0, 0x00,0x00,0x00,0x00}, /* 640x480 */ + { 16, 5, 0x41a,0x2ab,0x670,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00}, /* 800x600 */ + { 25, 12, 0x4ec,0x353,0x670,0x3c0,0x032, 0, 0, 0x00,0x00,0x00,0x00}, /* 1024x768 */ + { 5, 4, 0x627,0x464,0x670,0x3c0,0x128, 0, 0, 0x00,0x00,0x00,0x00}, /* 1280x1024 */ + { 4, 1, 0x41a,0x233,0x60c,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00}, /* 800x480 */ + { 5, 2, 0x578,0x293,0x670,0x3c0,0x032, 0, 0, 0x00,0x00,0x00,0x00}, /* 1024x576 */ + { 8, 5, 0x6d6,0x323,0x670,0x3c0,0x128, 0, 0, 0x00,0x00,0x00,0x00}, /* 1280x720 */ + { 137, 32, 0x3d4,0x233,0x663,0x3bf,0x143, 0, 0, 0x00,0x00,0x00,0x00} /* 960x600 */ +}; + +static const SiS_TVDataStruct SiS_St525pData[] = +{ + { 1, 1, 0x6b4,0x20d,0x4f6,0x190, 50, 0, 0x2f8, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x6b4,0x20d,0x4f6,0x15e, 50, 0, 0x280, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x6b4,0x20d,0x4f6,0x190, 50, 0, 0x2f8, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x6b4,0x20d,0x4f6,0x15e, 50, 0, 0x280, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x6b4,0x20d,0x4f6,0x1e0, 0, 0, 0x2f8, 0x00,0x00,0x00,0x00} +}; + +static const SiS_TVDataStruct SiS_St750pData[] = +{ + { 1, 1, 0x672,0x2ee,0x500,0x190, 50, 0, 0x2f8, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x672,0x2ee,0x500,0x15e, 50, 0, 0x280, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x672,0x2ee,0x500,0x190, 0, 0, 0x2d0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x672,0x2ee,0x500,0x15e, 0, 0, 0x2d0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x672,0x2ee,0x500,0x1e0, 0, 0, 0x2f8, 0x00,0x00,0x00,0x00} +}; + +static const SiS_TVDataStruct SiS_Ext750pData[] = +{ + { 143, 65, 0x35a,0x1bb,0x4f6,0x1b8,0x0ab, 0, 0x0ab, 0x00,0x00,0x00,0x00}, + { 88, 35, 0x35a,0x189,0x4f6,0x1b8,0x0ab, 0, 0x0ab, 0x00,0x00,0x00,0x00}, + { 18, 5, 0x339,0x1ae,0x500,0x2d0,0x05c, 0, 0x05c, 0x00,0x00,0x00,0x00}, + { 143, 70, 0x39c,0x189,0x4f6,0x1b8,0x05c, 0, 0x05c, 0x00,0x00,0x00,0x00}, + { 99, 32, 0x320,0x1fe,0x500,0x2d0, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* 640x480 */ + { 5, 4, 0x5d8,0x29e,0x500,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* 800x600 */ + { 99, 32, 0x320,0x1fe,0x500,0x2d0, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* 720x480 test WORKS */ + { 68, 64, 0x55f,0x346,0x500,0x2a8,0x27e, 0, 0, 0x00,0x00,0x00,0x00}, /* 1024x768 */ + { 5, 2, 0x3a7,0x226,0x500,0x2a8, 0,128, 0, 0x00,0x00,0x00,0x00}, /* 720x576 */ + { 25, 24, 0x5d8,0x2f3,0x460,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00} /* 1280x720 WORKS */ +}; + +static const SiS_LCDDataStruct SiS_LCD1280x720Data[] = /* 2.03.00 */ +{ + { 44, 15, 864, 430, 1408, 806 }, /* 640x400 */ + { 128, 35, 792, 385, 1408, 806 }, + { 44, 15, 864, 430, 1408, 806 }, + { 128, 35, 792, 385, 1408, 806 }, + { 22, 9, 864, 516, 1408, 806 }, /* 640x480 */ + { 8, 5, 1056, 655, 1408, 806 }, /* 800x600 */ + { 0, 0, 0, 0, 0, 0 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x1024 */ + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1408, 806, 1408, 806 } /* 1280x720 */ +}; + +/* About 1280x768: For TMDS, Panel_1280x768 will only be set if + * the panel is a Fujitsu 7911 (VL-17WDX8) (with clock 81, 1688x802) + * Other TMDS panels of this resolution will be treated as custom. + * For LVDS, we know another type (_2). + * (Note: 1280x768_3 is now special for SiS301/NetVista + */ + +static const SiS_LCDDataStruct SiS_StLCD1280x768_2Data[] = /* 2.03.00 */ +{ + { 64, 21, 858, 434, 1408, 806 }, /* 640x400 */ + { 32, 9, 858, 372, 1408, 806 }, + { 64, 21, 858, 434, 1408, 806 }, + { 32, 9, 858, 372, 1408, 806 }, + { 143, 68, 1024, 527, 1408, 806 }, /* 640x480 */ + { 64, 51, 1364, 663, 1408, 806 }, /* 800x600 */ + { 88, 81, 1296, 806, 1408, 806 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1408, 806, 1408, 806 }, /* 1280x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 16, 15, 1600, 750, 1600, 806 } /* 1280x720 - from Ext */ +}; + +static const SiS_LCDDataStruct SiS_ExtLCD1280x768_2Data[] = /* 2.03.00 */ +{ + { 16, 5, 960, 410, 1600, 806 }, /* 640x400 */ + { 64, 21, 1152, 364, 1600, 806 }, + { 16, 5, 960, 410, 1600, 806 }, + { 64, 21, 1152, 364, 1600, 806 }, + { 32, 13, 1040, 493, 1600, 806 }, /* 640x480 */ + { 16, 9, 1152, 618, 1600, 806 }, /* 800x600 */ + { 25, 21, 1344, 796, 1600, 806 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1600, 806, 1600, 806 }, /* 1280x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 16, 15, 1600, 750, 1600, 806 } /* 1280x720 */ +}; + +#if 0 /* Not used; _3 now reserved for NetVista (SiS301) */ +static const SiS_LCDDataStruct SiS_LCD1280x768_3Data[] = +{ + { 64, 25, 1056, 422, 1664, 798 }, /* 640x400 */ + { 128, 39, 884, 396, 1408, 806 }, /* ,640 */ + { 64, 25, 1056, 422, 1664, 798 }, /* 640x400 */ + { 128, 39, 884, 396, 1408, 806 }, /* ,640 */ + { 32, 15, 1056, 513, 1408, 806 }, /* ,664 */ /* 640x480 */ + { 176, 125, 1280, 640, 1408, 806 }, /* ,768 */ /* 800x600 */ + { 64, 61, 1342, 806, 1408, 806 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1408, 806, 1408, 806 }, /* 1280x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 16, 15, 1600, 750, 1600, 806 } /* 1280x720 from above */ +}; +#endif + +static const SiS_LCDDataStruct SiS_LCD1280x800Data[] = /* 0.93.12a (TMDS) */ +{ + { 128, 51, 1122, 412, 1408, 816 }, /* 640x400 */ + { 128, 49, 1232, 361, 1408, 816 }, + { 128, 51, 1122, 412, 1408, 816 }, + { 128, 49, 1232, 361, 1408, 816 }, + { 8, 3, 880, 491, 1408, 816 }, /* 640x480 */ + { 11, 6, 1024, 612, 1408, 816 }, /* 800x600 */ + { 22, 21, 1400, 784, 1408, 816 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x1024 */ + { 1, 1, 1408, 816, 1408, 816 }, /* 1280x800 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x768 (patch index) */ + { 0, 0, 0, 0, 0, 0 } /* 1280x720 */ +}; + +static const SiS_LCDDataStruct SiS_LCD1280x800_2Data[] = /* 2.03.00 (LVDS) */ +{ + { 97, 42, 1344, 409, 1552, 812 }, /* 640x400 */ + { 97, 35, 1280, 358, 1552, 812 }, + { 97, 42, 1344, 409, 1552, 812 }, + { 97, 35, 1280, 358, 1552, 812 }, + { 97, 39, 1040, 488, 1552, 812 }, /* 640x480 */ + { 194, 105, 1120, 608, 1552, 812 }, /* 800x600 */ + { 97, 84, 1400, 780, 1552, 812 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x1024 */ + { 1, 1, 1552, 812, 1552, 812 }, /* 1280x800 */ + { 97, 96, 1600, 780, 1552, 812 }, /* 1280x768 - patch index */ + { 97, 90, 1600, 730, 1552, 812 } /* 1280x720 */ +}; + +static const SiS_LCDDataStruct SiS_LCD1280x960Data[] = +{ + { 9, 2, 800, 500, 1800, 1000 }, + { 9, 2, 800, 500, 1800, 1000 }, + { 4, 1, 900, 500, 1800, 1000 }, + { 4, 1, 900, 500, 1800, 1000 }, + { 9, 2, 800, 500, 1800, 1000 }, + { 30, 11, 1056, 625, 1800, 1000 }, + { 5, 3, 1350, 800, 1800, 1000 }, + { 1, 1, 1576, 1050, 1576, 1050 }, + { 1, 1, 1800, 1000, 1800, 1000 } +}; + +static const SiS_LCDDataStruct SiS_StLCD1400x1050Data[] = +{ + { 211, 100, 2100, 408, 1688, 1066 }, + { 211, 64, 1536, 358, 1688, 1066 }, + { 211, 100, 2100, 408, 1688, 1066 }, + { 211, 64, 1536, 358, 1688, 1066 }, + { 211, 48, 840, 488, 1688, 1066 }, + { 211, 72, 1008, 609, 1688, 1066 }, + { 211, 128, 1400, 776, 1688, 1066 }, + { 211, 205, 1680, 1041, 1688, 1066 }, + { 1, 1, 1688, 1066, 1688, 1066 } +}; + +static const SiS_LCDDataStruct SiS_ExtLCD1400x1050Data[] = +{ +/* { 211, 60, 1260, 410, 1688, 1066 }, 640x400 (6330) */ + { 211, 100, 2100, 408, 1688, 1066 }, /* 640x400 (6325) WORKS */ + { 211, 64, 1536, 358, 1688, 1066 }, + { 211, 100, 2100, 408, 1688, 1066 }, + { 211, 64, 1536, 358, 1688, 1066 }, +/* { 211, 80, 1400, 490, 1688, 1066 }, 640x480 (6330) */ + { 211, 48, 840, 488, 1688, 1066 }, /* 640x480 (6325) WORKS */ +/* { 211, 117, 1638, 613, 1688, 1066 }, 800x600 (6330) */ + { 211, 72, 1008, 609, 1688, 1066 }, /* 800x600 (6325) WORKS */ + { 211, 128, 1400, 776, 1688, 1066 }, /* 1024x768 */ + { 211, 205, 1680, 1041, 1688, 1066 }, /* 1280x1024 - not used (always unscaled) */ + { 1, 1, 1688, 1066, 1688, 1066 }, /* 1400x1050 */ + { 0, 0, 0, 0, 0, 0 }, /* kludge */ + { 211, 120, 1400, 730, 1688, 1066 } /* 1280x720 */ +}; + +static const SiS_LCDDataStruct SiS_LCD1680x1050Data[] = +{ + { 95, 24, 1260, 410, 1900, 1066 }, /* 0 640x400 */ + { 10, 3, 1710, 362, 1900, 1066 }, + { 95, 24, 1260, 410, 1900, 1066 }, + { 10, 3, 1710, 362, 1900, 1066 }, + { 95, 32, 1400, 490, 1900, 1066 }, /* 4 640x480 */ + { 95, 42, 1470, 610, 1900, 1066 }, /* 5 800x600 */ + { 95, 64, 1750, 784, 1900, 1066 }, /* 6 1024x768 */ + { 95, 94, 1900, 1055, 1900, 1066 }, /* 7 1280x1024 */ + { 41, 31, 1900, 806, 1900, 1066 }, /* 8 1280x768 */ + { 95, 69, 1800, 817, 1900, 1066 }, /* 9 1280x800 patch index */ + { 13, 9, 1900, 739, 1900, 1066 }, /* 10 1280x720 */ + { 95, 94, 1880, 1066, 1900, 1066 }, /* 11 1400x1050 patch index */ + { 1, 1, 1900, 1066, 1900, 1066 } /* 12 1680x1050 */ +}; + +static const SiS_LCDDataStruct SiS_StLCD1600x1200Data[] = +{ + {27, 4, 800, 500, 2160, 1250 }, + {27, 4, 800, 500, 2160, 1250 }, + { 6, 1, 900, 500, 2160, 1250 }, + { 6, 1, 900, 500, 2160, 1250 }, + {27, 1, 800, 500, 2160, 1250 }, + { 4, 1,1080, 625, 2160, 1250 }, + { 5, 2,1350, 800, 2160, 1250 }, + {135,88,1600,1100, 2160, 1250 }, + {72, 49,1680,1092, 2160, 1250 }, + { 1, 1,2160,1250, 2160, 1250 } +}; + +static const SiS_LCDDataStruct SiS_ExtLCD1600x1200Data[] = +{ + {72,11, 990, 422, 2160, 1250 }, /* 640x400 (6330) WORKS */ +/* {27, 4, 800, 500, 2160, 1250 }, 640x400 (6235) */ + {27, 4, 800, 500, 2160, 1250 }, + { 6, 1, 900, 500, 2160, 1250 }, + { 6, 1, 900, 500, 2160, 1250 }, + {45, 8, 960, 505, 2160, 1250 }, /* 640x480 (6330) WORKS */ +/* {27, 1, 800, 500, 2160, 1250 }, 640x480 (6325) */ + { 4, 1,1080, 625, 2160, 1250 }, + { 5, 2,1350, 800, 2160, 1250 }, + {27,16,1500,1064, 2160, 1250 }, /* 1280x1024 */ + {72,49,1680,1092, 2160, 1250 }, /* 1400x1050 (6330, was not supported on 6325) */ + { 1, 1,2160,1250, 2160, 1250 } +}; + +static const SiS_LCDDataStruct SiS_NoScaleData[] = +{ + { 1, 1, 800, 449, 800, 449 }, /* 0x00: 320x200, 640x400 */ + { 1, 1, 800, 449, 800, 449 }, + { 1, 1, 900, 449, 900, 449 }, + { 1, 1, 900, 449, 900, 449 }, + { 1, 1, 800, 525, 800, 525 }, /* 0x04: 320x240, 640x480 */ + { 1, 1,1056, 628,1056, 628 }, /* 0x05: 400x300, 800x600 */ + { 1, 1,1344, 806,1344, 806 }, /* 0x06: 512x384, 1024x768 */ + { 1, 1,1688,1066,1688,1066 }, /* 0x07: 1280x1024 */ + { 1, 1,1688, 802,1688, 802 }, /* 0x08: 1280x768: Fujitsu, TMDS only */ + { 1, 1,2160,1250,2160,1250 }, /* 0x09: 1600x1200 */ + { 1, 1,1800,1000,1800,1000 }, /* 0x0a: 1280x960 */ + { 1, 1,1688,1066,1688,1066 }, /* 0x0b: 1400x1050 */ + { 1, 1,1650, 750,1650, 750 }, /* 0x0c: 1280x720 (TMDS, projector) */ + { 1, 1,1552, 812,1552, 812 }, /* 0x0d: 1280x800_2 (LVDS) (was: 1408,816/ 1656,841) */ + { 1, 1,1900,1066,1900,1066 }, /* 0x0e: 1680x1050 (LVDS) */ + { 1, 1,1660, 806,1660, 806 }, /* 0x0f: 1280x768_2 (LVDS) */ + { 1, 1,1664, 798,1664, 798 }, /* 0x10: 1280x768_3 (NetVista SiS 301) - TODO */ + { 1, 1,1688, 802,1688, 802 }, /* 0x11: 1280x768 (TMDS Fujitsu) */ + { 1, 1,1408, 806,1408, 806 }, /* 0x12: 1280x720 (LVDS) */ + { 1, 1, 896, 497, 896, 497 }, /* 0x13: 720x480 */ + { 1, 1, 912, 597, 912, 597 }, /* 0x14: 720x576 */ + { 1, 1, 912, 597, 912, 597 }, /* 0x15: 768x576 */ + { 1, 1,1056, 497,1056, 497 }, /* 0x16: 848x480 */ + { 1, 1,1064, 497,1064, 497 }, /* 0x17: 856x480 */ + { 1, 1,1056, 497,1056, 497 }, /* 0x18: 800x480 */ + { 1, 1,1328, 739,1328, 739 }, /* 0x19: 1024x576 */ + { 1, 1,1680, 892,1680, 892 }, /* 0x1a: 1152x864 */ + { 1, 1,1808, 808,1808, 808 }, /* 0x1b: 1360x768 */ + { 1, 1,1104, 563,1104, 563 }, /* 0x1c: 960x540 */ + { 1, 1,1120, 618,1120, 618 }, /* 0x1d: 960x600 */ + { 1, 1,1408, 816,1408, 816 } /* 0x1f: 1280x800 (TMDS special) */ +}; + +/**************************************************************/ +/* LVDS ----------------------------------------------------- */ +/**************************************************************/ + +static const SiS_LVDSDataStruct SiS_LVDS320x480Data_1[]= +{ + { 848, 433, 400, 525}, + { 848, 389, 400, 525}, + { 848, 433, 400, 525}, + { 848, 389, 400, 525}, + { 848, 518, 400, 525}, + {1056, 628, 400, 525}, + { 400, 525, 400, 525}, + { 800, 449,1000, 644}, + { 800, 525,1000, 635} +}; + +static const SiS_LVDSDataStruct SiS_LVDS640x480Data_1[]= +{ + { 800, 445, 800, 525}, /* 800, 449, 800, 449 */ + { 800, 395, 800, 525}, + { 800, 445, 800, 525}, + { 800, 395, 800, 525}, + { 800, 525, 800, 525}, + { 800, 525, 800, 525}, /* pseudo */ + { 800, 525, 800, 525} /* pseudo */ +}; + +/* FSTN 320x240 */ +static const SiS_LVDSDataStruct SiS_LVDS640x480Data_2[]= +{ + { 800, 445, 800, 525}, + { 800, 395, 800, 525}, + { 800, 445, 800, 525}, + { 800, 395, 800, 525}, + { 800, 525, 800, 525}, + { 800, 525, 800, 525}, /* pseudo */ + { 800, 525, 800, 525} /* pseudo */ +}; + +static const SiS_LVDSDataStruct SiS_LVDS800x600Data_1[]= +{ + { 848, 433,1060, 629}, + { 848, 389,1060, 629}, + { 848, 433,1060, 629}, + { 848, 389,1060, 629}, + { 848, 518,1060, 629}, + {1056, 628,1056, 628}, + {1056, 628,1056, 628} +}; + +static const SiS_LVDSDataStruct SiS_LVDS800x600Data_2[]= +{ + {1056, 628,1056, 628} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1024x768Data_1[]= +{ + { 840, 438,1344, 806}, + { 840, 409,1344, 806}, + { 840, 438,1344, 806}, + { 840, 409,1344, 806}, + { 840, 518,1344, 806}, /* 640x480 */ + {1050, 638,1344, 806}, /* 800x600 */ + {1344, 806,1344, 806}, /* 1024x768 */ +}; + +static const SiS_LVDSDataStruct SiS_LVDS1024x768Data_2[]= +{ + {1344, 806,1344, 806} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1280x1024Data_1[]= +{ + {1048, 442,1688,1066}, + {1048, 392,1688,1066}, + {1048, 442,1688,1066}, + {1048, 392,1688,1066}, + {1048, 522,1688,1066}, + {1208, 642,1688,1066}, + {1432, 810,1688,1066}, + {1688,1066,1688,1066} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1280x1024Data_2[]= +{ + {1688,1066,1688,1066} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1400x1050Data_1[]= +{ + { 928, 416, 1688,1066}, + { 928, 366, 1688,1066}, + { 928, 416, 1688,1066}, + { 928, 366, 1688,1066}, + { 928, 496, 1688,1066}, + {1088, 616, 1688,1066}, + {1312, 784, 1688,1066}, + {1568,1040, 1688,1066}, + {1688,1066, 1688,1066} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1400x1050Data_2[]= +{ + {1688,1066, 1688,1066} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1600x1200Data_1[]= +{ + {1088, 520, 2048,1320}, + {1088, 470, 2048,1320}, + {1088, 520, 2048,1320}, + {1088, 470, 2048,1320}, + {1088, 600, 2048,1320}, + {1248, 720, 2048,1320}, + {1472, 888, 2048,1320}, + {1728,1144, 2048,1320}, + {1848,1170, 2048,1320}, + {2048,1320, 2048,1320} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1600x1200Data_2[]= +{ + {2048,1320, 2048,1320} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1280x960Data_1[]= +{ + { 840, 438,1344, 806}, + { 840, 409,1344, 806}, + { 840, 438,1344, 806}, + { 840, 409,1344, 806}, + { 840, 518,1344, 806}, + {1050, 638,1344, 806}, + {1344, 806,1344, 806}, + { 800, 449,1280, 801}, + { 800, 525,1280, 813} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1280x960Data_2[]= +{ + {1344, 806,1344, 806} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1280x768Data_1[]= +{ + { 768, 438, 1408, 806}, + { 768, 388, 1408, 806}, + { 768, 438, 1408, 806}, + { 768, 388, 1408, 806}, + { 768, 518, 1408, 806}, + { 928, 638, 1408, 806}, + {1152, 806, 1408, 806}, + {1408, 806, 1408, 806}, + {1408, 806, 1408, 806} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1280x768Data_2[]= +{ + {1408, 806, 1408, 806} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1024x600Data_1[] = +{ + { 840, 604,1344, 800}, + { 840, 560,1344, 800}, + { 840, 604,1344, 800}, + { 840, 560,1344, 800}, + { 840, 689,1344, 800}, + {1050, 800,1344, 800}, + {1344, 800,1344, 800} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1024x600Data_2[] = +{ + {1344, 800,1344, 800} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1152x768Data_1[] = +{ + { 840, 438,1344, 806}, + { 840, 409,1344, 806}, + { 840, 438,1344, 806}, + { 840, 409,1344, 806}, + { 840, 518,1344, 806}, + {1050, 638,1344, 806}, + {1344, 806,1344, 806} +}; + +static const SiS_LVDSDataStruct SiS_LVDS1152x768Data_2[] = +{ + {1344, 806,1344, 806} +}; + +/* Pass 1:1 data */ +static const SiS_LVDSDataStruct SiS_LVDSXXXxXXXData_1[]= +{ + { 800, 449, 800, 449}, + { 800, 449, 800, 449}, + { 900, 449, 900, 449}, + { 900, 449, 900, 449}, + { 800, 525, 800, 525}, /* 640x480 */ + {1056, 628, 1056, 628}, /* 800x600 */ + {1344, 806, 1344, 806}, /* 1024x768 */ + {1688,1066, 1688,1066}, /* 1280x1024 */ /* INSERTED */ + {1688, 806, 1688, 806}, /* 1280x768 */ +}; + +/* Custom data for Barco iQ R series */ +static const SiS_LVDSDataStruct SiS_LVDSBARCO1366Data_1[]= +{ + { 832, 438,1331, 806}, + { 832, 388,1331, 806}, + { 832, 438,1331, 806}, + { 832, 388,1331, 806}, + { 832, 518,1331, 806}, + {1050, 638,1344, 806}, + {1344, 806,1344, 806}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066} /* 1360x1024 */ +}; + +/* Custom data for Barco iQ R series */ +static const SiS_LVDSDataStruct SiS_LVDSBARCO1366Data_2[]= +{ + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066} /* 1360x1024 */ +}; + +/* Custom data for Barco iQ G series */ +static const SiS_LVDSDataStruct SiS_LVDSBARCO1024Data_1[]= +{ + { 832, 438,1331, 806}, + { 832, 409,1331, 806}, + { 832, 438,1331, 806}, + { 832, 409,1331, 806}, + { 832, 518,1331, 806}, /* 640x480 */ + {1050, 638,1344, 806}, /* 800x600 */ + {1344, 806,1344, 806}, /* 1024x768 */ +}; + +/* Custom data for Barco iQ G series */ +static const SiS_LVDSDataStruct SiS_LVDSBARCO1024Data_2[]= +{ + {1344, 806,1344, 806} +}; + +/* Custom data for 848x480 parallel panel */ +static const SiS_LVDSDataStruct SiS_LVDS848x480Data_1[]= +{ + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + {1088, 525,1088, 525}, /* 640x480 TODO */ + {1088, 525,1088, 525}, /* 800x600 TODO */ + {1088, 525,1088, 525}, /* 1024x768 TODO */ + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + {1088, 525,1088, 525}, /* 848x480 */ + {1088, 525,1088, 525} /* 1360x768 TODO */ +}; + +/* Custom data for 848x480 parallel panel */ +static const SiS_LVDSDataStruct SiS_LVDS848x480Data_2[]= +{ + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + {1088, 525,1088, 525}, /* 640x480 */ + {1088, 525,1088, 525}, /* 800x600 */ + {1088, 525,1088, 525}, /* 1024x768 */ + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + {1088, 525,1088, 525}, /* 848x480 */ + {1088, 525,1088, 525} /* 1360x768 TODO */ +}; + +static const SiS_LVDSDataStruct SiS_CHTVUNTSCData[]= +{ + { 840, 600, 840, 600}, + { 840, 600, 840, 600}, + { 840, 600, 840, 600}, + { 840, 600, 840, 600}, + { 784, 600, 784, 600}, + {1064, 750,1064, 750}, + {1160, 945,1160, 945} +}; + +static const SiS_LVDSDataStruct SiS_CHTVONTSCData[]= +{ + { 840, 525, 840, 525}, + { 840, 525, 840, 525}, + { 840, 525, 840, 525}, + { 840, 525, 840, 525}, + { 784, 525, 784, 525}, + {1040, 700,1040, 700}, + {1160, 840,1160, 840} +}; + +/* Chrontel TV Skew */ + +static const SiS_LVDSDesStruct SiS_CHTVUNTSCDesData[]= +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS_CHTVONTSCDesData[]= +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS_CHTVUPALDesData[]= +{ + {256, 0}, + {256, 0}, + {256, 0}, + {256, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS_CHTVOPALDesData[]= +{ + {256, 0}, + {256, 0}, + {256, 0}, + {256, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +/* CRT1 CRTC data for slave modes */ + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1320x480_1[] = +{ + {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, + 0x00 }}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00 }}, + {{0x65,0x4f,0x89,0x54,0x9f,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, + 0x00 }}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00 }}, + {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e, + 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, + 0x00 }}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01 }}, + {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00 }} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_1[] = +{ + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_1_H[] = +{ + {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x00,0x00,0x00, + 0x00}}, + {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x83,0x85,0x63,0xba,0x00,0x00,0x00, + 0x00}}, + {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x00,0x00,0x00, + 0x00}}, + {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x83,0x85,0x63,0xba,0x00,0x00,0x00, + 0x00}}, + {{0x2d,0x28,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_2[] = +{ + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_2_H[] = +{ + {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, + 0x00}}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00}}, + {{0x65,0x4f,0x89,0x54,0x9f,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, + 0x00}}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00}}, + {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e, + 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_3[] = +{ + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_3_H[] = +{ + {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, + 0x00}}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00}}, + {{0x65,0x4f,0x89,0x54,0x9f,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, + 0x00}}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00}}, + {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e, + 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11024x600_1[] = +{ + {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e, + 0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e, + 0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e, + 0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e, + 0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x88,0x54,0x9f,0xaf,0xba, + 0x3b,0x82,0xdf,0xb0,0x00,0x00,0x01, + 0x00}}, + {{0x7e,0x63,0x82,0x68,0x15,0x1e,0xf1, + 0xae,0x85,0x57,0x1f,0x30,0x00,0x26, + 0x01}}, + {{0xa3,0x7f,0x87,0x86,0x97,0x1e,0xf1, + 0xae,0x85,0x57,0x1f,0x30,0x00,0x02, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11024x600_1_H[] = +{ + {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, + 0x00}}, + {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x44, + 0x00}}, + {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, + 0x00}}, + {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x44, + 0x00}}, + {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e, + 0xe2,0x89,0xdf,0x05,0x00,0x00,0x44, + 0x00}}, + {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0, + 0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55, + 0x01}}, + {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x01, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11024x600_2[] = +{ + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, + 0x00}}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, + 0x00}}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, + 0x00}}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, + 0x00}}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x72,0x88,0xdf,0x25,0x30,0x00,0x06, + 0x00}}, + {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1, + 0xae,0x84,0x57,0x25,0x30,0x00,0x02, + 0x01}}, + {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x02, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11024x600_2_H[] = +{ + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, + 0x00}}, + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, + 0x00}}, + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, + 0x00}}, + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, + 0x00}}, + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x72,0x88,0xdf,0x25,0x30,0x00,0x01, + 0x00}}, + {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1, + 0xae,0x84,0x57,0x25,0x30,0x00,0x01, + 0x01}}, + {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x01, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11152x768_1[] = +{ + {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x88,0x54,0x9f,0x04,0x3e, + 0xe2,0x89,0xdf,0x05,0x00,0x00,0x01, + 0x00}}, + {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0, + 0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26, + 0x01}}, + {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x02, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11152x768_1_H[] = +{ + {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, + 0x00}}, + {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x44, + 0x00}}, + {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, + 0x00}}, + {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f, + 0x60,0x87,0x5d,0x83,0x10,0x00,0x44, + 0x00}}, + {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e, + 0xe2,0x89,0xdf,0x05,0x00,0x00,0x44, + 0x00}}, + {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0, + 0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55, + 0x01}}, + {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x01, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11152x768_2[] = +{ + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, + 0x00}}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, + 0x00}}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, + 0x00}}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, + 0x00}}, + {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, + 0x72,0x88,0xdf,0x25,0x30,0x00,0x06, + 0x00}}, + {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1, + 0xae,0x84,0x57,0x25,0x30,0x00,0x02, + 0x01}}, + {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x02, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11152x768_2_H[] = +{ + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, + 0x00}}, + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, + 0x00}}, + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, + 0x00}}, + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, + 0x00}}, + {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, + 0x72,0x88,0xdf,0x25,0x30,0x00,0x01, + 0x00}}, + {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1, + 0xae,0x84,0x57,0x25,0x30,0x00,0x01, + 0x01}}, + {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x01, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11280x768_1[] = +{ + {{0x5b,0x4f,0x9f,0x55,0x19,0xb4,0x1f, + 0x9c,0x8e,0x8f,0xb5,0x10,0x00,0x01, + 0x00}}, + {{0x5b,0x4f,0x9f,0x55,0x19,0x82,0x1f, + 0x6a,0x8c,0x5d,0x83,0x30,0x00,0x01, + 0x00}}, + {{0x5b,0x4f,0x9f,0x55,0x19,0xb4,0x1f, + 0x9c,0x8e,0x8f,0xb5,0x10,0x00,0x01, + 0x00}}, + {{0x5b,0x4f,0x9f,0x55,0x19,0x82,0x1f, + 0x6a,0x8c,0x5d,0x83,0x30,0x00,0x01, + 0x00}}, + {{0x5b,0x4f,0x9f,0x55,0x19,0x04,0x3e, + 0xec,0x8e,0xdf,0x05,0x20,0x00,0x01, + 0x00}}, + {{0x6f,0x63,0x93,0x69,0x8d,0x7c,0xf0, + 0x64,0x86,0x57,0x7d,0x20,0x00,0x05, + 0x01}}, + {{0x8b,0x7f,0x8f,0x85,0x09,0x24,0xf5, + 0x0c,0x8e,0xff,0x25,0x30,0x00,0x02, + 0x01}}, + {{0xab,0x9f,0x8f,0xa5,0x89,0x24,0xf5, + 0x0c,0x8e,0xff,0x25,0x30,0x00,0x06, + 0x01}}, + {{0xab,0x9f,0x8f,0xa5,0x89,0x24,0xf5, + 0x0c,0x8e,0xff,0x25,0x30,0x00,0x06, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11280x768_1_H[] = +{ + {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f, + 0x93,0x86,0x8f,0x9f,0x30,0x00,0x05, + 0x00}}, + {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, + 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, + 0x00}}, + {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f, + 0x92,0x86,0x8f,0x9f,0x30,0x00,0x05, + 0x00}}, + {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, + 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, + 0x00}}, + {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f, + 0xe2,0x86,0xdf,0xef,0x10,0x00,0x05, + 0x00}}, + {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0, + 0x5a,0x8e,0x57,0x67,0x20,0x00,0x01, + 0x01}}, + {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf5, + 0x02,0x86,0xff,0x0f,0x10,0x00,0x01, + 0x01}}, + {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a, + 0x02,0x86,0xff,0x0f,0x09,0x00,0x05, + 0x01}}, + {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a, + 0x02,0x86,0xff,0x0f,0x09,0x00,0x05, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11280x768_2[] = +{ + {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb, + 0x54,0x86,0xdb,0xda,0x00,0x00,0x02, + 0x00}}, + {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb, + 0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x02, + 0x00}}, + {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb, + 0x54,0x86,0xdb,0xda,0x00,0x00,0x02, + 0x00}}, + {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb, + 0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x02, + 0x00}}, + {{0xab,0x60,0x9f,0x80,0x04,0x24,0xb3, + 0x7c,0x8e,0x03,0x02,0x10,0x00,0x02, + 0x01}}, + {{0xab,0x63,0x8f,0x8a,0x8e,0x24,0xf1, + 0xb6,0x88,0x57,0x25,0x10,0x00,0x02, + 0x01}}, + {{0xab,0x7f,0x8f,0x98,0x9c,0x24,0xf5, + 0x0a,0x8c,0xff,0x25,0x30,0x00,0x02, + 0x01}}, + {{0xab,0x9f,0x8f,0xa8,0x8c,0x24,0xf5, + 0x0a,0x8c,0xff,0x25,0x30,0x00,0x06, + 0x01}}, + {{0xab,0x9f,0x8f,0xa8,0x8c,0x24,0xf5, + 0x0a,0x8c,0xff,0x25,0x30,0x00,0x06, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11280x768_2_H[] = +{ + {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb, + 0x54,0x86,0xdb,0xda,0x00,0x00,0x01, + 0x00}}, + {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb, + 0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x01, + 0x00}}, + {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb, + 0x54,0x86,0xdb,0xda,0x00,0x00,0x01, + 0x00}}, + {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb, + 0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x01, + 0x00}}, + {{0x83,0x38,0x97,0x58,0x9c,0x24,0xb3, + 0x7c,0x8e,0x03,0x02,0x10,0x00,0x01, + 0x01}}, + {{0x79,0x31,0x9d,0x58,0x9c,0x24,0xf1, + 0xb6,0x88,0x57,0x25,0x10,0x00,0x01, + 0x01}}, + {{0x6b,0x3f,0x8f,0x58,0x9c,0x24,0xf5, + 0x0a,0x8c,0xff,0x25,0x30,0x00,0x01, + 0x01}}, + {{0xab,0x9f,0x8f,0xa8,0x8c,0x24,0xf5, + 0x0a,0x8c,0xff,0x25,0x30,0x00,0x06, + 0x01}}, + {{0xab,0x9f,0x8f,0xa8,0x8c,0x24,0xf5, + 0x0a,0x8c,0xff,0x25,0x30,0x00,0x06, + 0x01}} +}; + +/**************************************************************/ +/* COMMON --------------------------------------------------- */ +/**************************************************************/ + +#ifdef LINUX_XF86 + +#define SIS_PL_HSYNCP 0x01 +#define SIS_PL_HSYNCN 0x02 +#define SIS_PL_VSYNCP 0x04 +#define SIS_PL_VSYNCN 0x08 +#define SIS_PL_DVI 0x80 + +typedef struct _SiS_PlasmaModes +{ + const char *name; + ULONG clock; + USHORT HDisplay, HTotal, HFrontPorch, HSyncWidth; + USHORT VDisplay, VTotal, VFrontPorch, VSyncWidth; + UCHAR SyncFlags; +} SiS_PlasmaModes; + +typedef struct _SiS_PlasmaTables +{ + USHORT vendor; + UCHAR productnum; + USHORT product[5]; + const char *DDCnames[5]; + const char *plasmaname; + USHORT maxx,maxy; + USHORT prefx, prefy; + UCHAR modenum; + UCHAR plasmamodes[20]; /* | 0x80 = DVI-capable, | 0x40 = analog */ +} SiS_PlasmaTables; + +static const SiS_PlasmaModes SiS_PlasmaMode[] = { + { "640x400", /* 00: IBM 400@70 */ + 25175, + 640, 800, 17, 64, + 400, 449, 13, 2, + SIS_PL_HSYNCN | SIS_PL_VSYNCN }, + { "640x480", /* 01: VESA 480@72 */ + 31500, + 640, 832, 24, 40, + 480, 520, 9, 3, + SIS_PL_HSYNCN | SIS_PL_VSYNCN }, + { "800x600", /* 02: VESA 600@72 */ + 50000, + 800, 1040, 56, 120, + 600, 666, 37, 6, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "864x480", /* 03: Cereb wide 1 */ + 42526, + 864, 1134, 22, 86, + 480, 500, 1, 3, + SIS_PL_HSYNCP | SIS_PL_VSYNCN }, + { "848x480", /* 04: VESA wide (NEC1) */ + 33750, + 848, 1088, 16, 112, + 480, 517, 6, 8, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1024x576", /* 05: VESA wide (NEC2) */ + 47250, + 1024, 1320, 16, 144, + 576, 596, 2, 4, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1280x720", /* 06: VESA wide (NEC3) */ + 76500, + 1280, 1696, 48, 176, + 720, 750, 4, 8, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1360x765", /* 07: VESA wide (NEC4) */ + 85500, + 1360, 1792, 64, 176, + 765, 795, 4, 8, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1024x600", /* 08: CEREB wide 2 */ + 51200, + 1024, 1352, 51, 164, + 600, 628, 1, 4, + SIS_PL_HSYNCN | SIS_PL_VSYNCP }, + { "1024x768", /* 09: VESA 768@75 */ + 78750, + 1024, 1312, 16, 96, + 768, 800, 1, 3, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1152x864", /* 10: VESA 1152x864@75 */ + 108000, + 1152, 1600, 64, 128, + 864, 900, 1, 3, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1280x1024", /* 11: VESA 1024@60 */ + 108000, + 1280, 1688, 48, 112, + 1024, 1066, 1, 3, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1280x768", /* 12: W_XGA */ + 81000, + 1280, 1688, 48, 112, + 768, 802, 3, 6, + SIS_PL_HSYNCP | SIS_PL_VSYNCN }, + { "1280x768", /* 13: I/O Data W_XGA@56Hz */ + 76064, + 1280, 1688, 48, 112, + 768, 802, 2, 3, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1376x768", /* 14: I/O Wide XGA */ + 87340, + 1376, 1808, 32, 128, + 768, 806, 3, 6, + SIS_PL_HSYNCN | SIS_PL_VSYNCP }, + { "1280x960", /* 15: VESA 960@60 */ + 108000, + 1280, 1800, 96, 112, + 960, 1000, 1, 3, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1400x1050", /* 16: VESA 1050@60Hz */ + 108000, + 1400, 1688, 48, 112, + 1050, 1066, 1, 3, + SIS_PL_HSYNCN | SIS_PL_VSYNCN }, + { "1360x768", /* 17: VESA wide (NEC4/2) */ + 85500, + 1360, 1792, 64, 112, + 765, 795, 3, 6, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "800x600", /* 18: VESA 600@56 */ + 36000, + 800, 1024, 24, 2, + 600, 625, 1, 2, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1072x600", /* 19: Panasonic 1072x600 (sync?) */ + 54100, + 1072, 1424, 48, 176, + 600, 628, 16, 1, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "848x480", /* 20: Panasonic 848x480 (sync?) */ + 33070, /* is 852x480, but we can't use 852 */ + 848, 1068, 20, 40, /* differs from DDC data, better centered */ + 480, 516, 3, 5, /* won't work assumingly, because data is % 8 */ + SIS_PL_HSYNCN | SIS_PL_VSYNCN }, + { "1280x720", /* 21: WIDE720(60) (aka "750p") (Panasonic) */ + 74300, + 1280, 1650,110, 40, + 720, 750, 5, 5, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1280x768", /* 22: 1280x768@56.5 (Panasonic) */ + 76200, /* (According to manual not supported for HDMI; but works) */ + 1280, 1680, 16, 24, + 768, 802, 2, 5, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1280x720@50", /* 23: WIDE720(50) (aka "750p") (Panasonic) */ + 74300, /* Panasonic states 45.0kHz. Not possible. This one works (with some overscan) */ + 1280, 1980,400, 80, + 720, 750, 1, 2, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "720x480", /* 24: 720x480 (aka "525p" and "480p") (Panasonic) */ + 27000, + 720, 856, 40, 32, + 480, 525, 1, 3, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "720x576", /* 25: 720x576 (aka "625p"and "576p") (Panasonic) */ + 27500, + 720, 864, 16, 64, + 576, 625, 5, 6, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + { "1280x720@50", /* 26: WIDE720(50) (aka "750p") (Generic) */ + 74300, + 1280, 1980,400, 80, + 720, 750, 5, 5, + SIS_PL_HSYNCP | SIS_PL_VSYNCP }, +}; + +/* +27.00 720 755 791 858 480 480 484 525 +27.50 720 732 795 864 576 581 587 625 +*/ + +static const SiS_PlasmaTables SiS_PlasmaTable[] = { +#if 0 /* Product IDs missing */ + { 0x38a3, 4, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "", "", "", "", "" }, + "NEC PlasmaSync 42VP4/42VP4D/42VP4G/42VP4DG", + 0, 0, + 0, 0, + 11, /* All DVI, except 0, 7, 13 */ + { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,13|0x40,14|0xc0, + 17|0xc0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, +#endif +#if 0 /* Product IDs missing */ + { 0x38a3, 3, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "", "", "", "", "" }, + "NEC PlasmaSync 42PD1/50PD1/50PD2", + 0, 0, + 0, 0, + 5, /* DVI entirely unknown */ + { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 9|0xc0, 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x38a3, 1, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "", "", "", "", "" }, + "NEC PlasmaSync 42PD3", + 0, 0, + 0, 0, + 10, /* DVI entirely unknown */ + { 0|0x40, 1|0xc0, 2|0xc0, 3|0xc0, 4|0xc0, 5|0xc0, 6|0xc0, 7|0x40, 8|0xc0, 9|0xc0, + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x38a3, 2, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "", "", "", "", "" }, + "NEC PlasmaSync 42VM3/61XM1", + 0, 0, + 0, 0, + 11, /* DVI entirely unknown */ + { 0|0x40, 1|0xc0, 2|0xc0, 3|0xc0, 4|0xc0, 5|0xc0, 6|0xc0, 8|0xc0, 9|0xc0,11|0xc0, + 17|0xc0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x38a3, 2, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "", "", "", "", "" }, + "NEC PlasmaSync 42MP1/42MP2", + 0, 0, + 0, 0, + 6, /* DVI entirely unknown */ + { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 9|0xc0,11|0xc0, 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x38a3, 1, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "", "", "", "", "" }, + "NEC PlasmaSync 50MP1", + 0, 0, + 0, 0, + 10, /* DVI entirely unknown */ + { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,13|0x40,14|0xc0, + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, +#endif + { 0x38a3, 4, + { 0xa482, 0xa483, 0x0000, 0x0000, 0x0000 }, + { "PX-42VM", "", "", "", "" }, + "NEC PlasmaSync 42MP3/42MP4/50MP2/61MP1", + 0, 0, + 0, 0, + 11, /* All DVI except 0, 7, 13, 17 */ + { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,13|0x40,14|0xc0, + 17|0x40, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, +#if 0 /* Product IDs missing */ + { 0x38a3, 1, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "", "", "", "", "" }, + "NEC PlasmaSync 3300W", + 0, 0, + 0, 0, + 3, + { 0|0x40, 1|0xc0,18|0xc0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x38a3, 1, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "", "", "", "", "" }, + "NEC PlasmaSync 4200W", + 4, /* DVI entirely unknown */ + { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x38a3, 1, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "", "", "", "", "" }, + "NEC PlasmaSync 4210W", + 0, 0, + 0, 0, + 6, /* DVI entirely unknown */ + { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 9|0xc0,11|0xc0, 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x38a3, 1, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "", "", "", "", "" }, + "NEC PlasmaSync 5000W", + 0, 0, + 0, 0, + 7, /* DVI entirely unknown */ + { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,11|0xc0, 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, +#endif + { 0x412f, 2, + { 0x000c, 0x000b, 0x0000, 0x0000, 0x0000 }, + { "", "", "", "", "" }, + "Pioneer 503CMX/PDA-5002", + 0, 0, + 0, 0, + 6, /* DVI unknown */ + { 1|0xc0, 2|0xc0, 9|0xc0,11|0xc0,12|0xc0,15|0xc0, 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x34a9, 1, + { 0xa00e, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "", "", "", "", "" }, + "Panasonic TH-42", + 0, 0, + 0, 0, + 5, /* No DVI output */ + { 1|0x40, 2|0x40, 4|0x40, 9|0x40,15|0x40, 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x34a9, 1, + { 0xa005, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "TH-42PW*4", "", "", "", "" }, + "Panasonic TH-42PW5", + 0, 0, + 0, 0, + 1, /* No special modes otherwise; no DVI. */ + {20|0x40,19|0x40, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x4c2e, 1, + { 0x9b05, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "PLV-Z2", "", "", "", "" }, + "Sanyo PLV-Z2 (non HDCP-mode)", /* HDCP mode would be id 9b06, but not needed */ + 1280, 768, /* as it then advertises correct size */ + 1280, 720, + 1, /* 1280x720, no special modes otherwise */ + {21|0xc0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x34a9, 1, + { 0xd034, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "AE500U (DVI-D)", "", "", "", "" }, + "Panasonic AE500U", + 1280, 768, + 1280, 720, + 1, /* 1280x720, no special modes otherwise */ + {21|0xc0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x34a9, 1, + { 0xd043, 0x0000, 0x0000, 0x0000, 0x0000 }, + { "AE700U (HDMI)", "", "", "", "" }, + "Panasonic AE700U", + 1360, 768, + 1280, 720, + 6, /* 1280x720/60, 1280x720/50, 1280x768@56(digital/analog), 720x480, 720x576 */ + {21|0xc0,23|0xc0,22|0x80,13|0x40,24|0x80,25|0x80, 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } + }, + { 0x0000 } +}; +#endif + +#ifdef LINUX_XF86 +USHORT SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, + int Depth, BOOLEAN FSTN, int LCDwith, int LCDheight); +#endif +USHORT SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, BOOLEAN FSTN, + USHORT CustomT, int LCDwith, int LCDheight); +USHORT SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth); +USHORT SiS_GetModeID_VGA2(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth); + +void SiS_SetReg(SISIOADDRESS port, USHORT index, USHORT data); +void SiS_SetRegByte(SISIOADDRESS port, USHORT data); +void SiS_SetRegShort(SISIOADDRESS port, USHORT data); +void SiS_SetRegLong(SISIOADDRESS port, ULONG data); +UCHAR SiS_GetReg(SISIOADDRESS port, USHORT index); +UCHAR SiS_GetRegByte(SISIOADDRESS port); +USHORT SiS_GetRegShort(SISIOADDRESS port); +ULONG SiS_GetRegLong(SISIOADDRESS port); +void SiS_SetRegANDOR(SISIOADDRESS Port, USHORT Index, USHORT DataAND, USHORT DataOR); +void SiS_SetRegAND(SISIOADDRESS Port,USHORT Index, USHORT DataAND); +void SiS_SetRegOR(SISIOADDRESS Port,USHORT Index, USHORT DataOR); +void SiS_DisplayOn(SiS_Private *SiS_Pr); +void SiS_DisplayOff(SiS_Private *SiS_Pr); +void SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr); +void SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +BOOLEAN SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +void SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable); +void SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable); +void SiS_GetVBType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +BOOLEAN SiS_SearchModeID(SiS_Private *SiS_Pr, USHORT *ModeNo, USHORT *ModeIdIndex); +UCHAR SiS_GetModePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); +USHORT SiS_GetColorDepth(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); +USHORT SiS_GetOffset(SiS_Private *SiS_Pr,USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo); +void SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT ModeIdIndex); +void SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); + +#ifdef LINUX_XF86 +BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch); +BOOLEAN SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, + DisplayModePtr mode, BOOLEAN IsCustom); +BOOLEAN SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, + DisplayModePtr mode, BOOLEAN IsCustom); +BOOLEAN SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, + DisplayModePtr mode, BOOLEAN IsCustom); +int SiSTranslateToVESA(ScrnInfoPtr pScrn, int modenumber); +int SiSTranslateToOldMode(int modenumber); +BOOLEAN SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_INFO); +USHORT SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags); +DisplayModePtr SiSBuildBuiltInModeList(ScrnInfoPtr pScrn, BOOLEAN includelcdmodes, BOOLEAN isfordvi); +int SiS_FindPanelFromDB(SISPtr pSiS, USHORT panelvendor, USHORT panelproduct, int *maxx, int *maxy, int *prefx, int *prefy); +void SiS_MakeClockRegs(ScrnInfoPtr pScrn, int clock, UCHAR *p2b, UCHAR *p2c); +#else +BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo); +#endif + +#ifdef LINUX_KERNEL +int sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + UCHAR modeno, UCHAR rateindex); +int sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + UCHAR modeno, UCHAR rateindex, + struct fb_var_screeninfo *var); +BOOLEAN sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + UCHAR modeno, int *htotal, int *vtotal, UCHAR rateindex); +#endif + +/* init301.c: */ +extern void SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo, int chkcrt2mode); +extern void SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo); +extern void SiS_SetYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +extern void SiS_SetTVMode(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo); +extern void SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +extern void SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +extern void SiS_DisableBridge(SiS_Private *, PSIS_HW_INFO); +extern BOOLEAN SiS_SetCRT2Group(SiS_Private *, PSIS_HW_INFO, USHORT); +extern USHORT SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo); +extern void SiS_WaitRetrace1(SiS_Private *SiS_Pr); +extern USHORT SiS_GetResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); +extern USHORT SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempax); +extern USHORT SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo); +extern BOOLEAN SiS_IsVAMode(SiS_Private *, PSIS_HW_INFO); +extern BOOLEAN SiS_IsDualEdge(SiS_Private *, PSIS_HW_INFO); + +#ifdef LINUX_XF86 +/* From other sis driver modules: */ +extern int SiS_compute_vclk(int Clock, int *out_n, int *out_dn, int *out_div, + int *out_sbit, int *out_scale); +extern void SiSCalcClock(ScrnInfoPtr pScrn, int clock, int max_VLD, unsigned int *vclk); + +extern UCHAR SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, USHORT offset, UCHAR value); +extern UCHAR SiS_GetSetModeID(ScrnInfoPtr pScrn, UCHAR id); +extern USHORT SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, ULONG VBFlags); +#endif + +#endif + diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c new file mode 100644 index 000000000000..2bc5b8097910 --- /dev/null +++ b/drivers/video/sis/init301.c @@ -0,0 +1,12239 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Mode initializing code (CRT2 section) + * for SiS 300/305/540/630/730 and + * SiS 315/550/650/M650/651/661FX/M661xX/740/741(GX)/M741/330/660/M660/760/M760 + * (Universal module for Linux kernel framebuffer and XFree86/X.org 4.x) + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + * Formerly based on non-functional code-fragements for 300 series by SiS, Inc. + * Used by permission. + * + * TW says: This code looks awful, I know. But please don't do anything about + * this otherwise debugging will be hell. + * The code is extremely fragile as regards the different chipsets, different + * video bridges and combinations thereof. If anything is changed, extreme + * care has to be taken that that change doesn't break it for other chipsets, + * bridges or combinations thereof. + * All comments in this file are by me, regardless if marked TW or not. + * + */ + +#if 1 +#define SET_EMI /* 302LV/ELV: Set EMI values */ +#endif + +#define COMPAL_HACK /* Needed for Compal 1400x1050 (EMI) */ +#define COMPAQ_HACK /* Needed for Inventec/Compaq 1280x1024 (EMI) */ +#define ASUS_HACK /* Needed for Asus A2H 1024x768 (EMI) */ + +#include "init301.h" + +#ifdef SIS300 +#include "oem300.h" +#endif + +#ifdef SIS315H +#include "oem310.h" +#endif + +#define SiS_I2CDELAY 1000 +#define SiS_I2CDELAYSHORT 150 + +static USHORT SiS_GetBIOSLCDResInfo(SiS_Private *SiS_Pr); + +/*********************************************/ +/* HELPER: Lock/Unlock CRT2 */ +/*********************************************/ + +void +SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(HwInfo->jChipType >= SIS_315H) + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2f,0x01); + else + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01); +} + +void +SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(HwInfo->jChipType >= SIS_315H) + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE); + else + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE); +} + +/*********************************************/ +/* HELPER: Write SR11 */ +/*********************************************/ + +static void +SiS_SetRegSR11ANDOR(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DataAND, USHORT DataOR) +{ + if(HwInfo->jChipType >= SIS_661) { + DataAND &= 0x0f; + DataOR &= 0x0f; + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,DataAND,DataOR); +} + +/*********************************************/ +/* HELPER: Get Pointer to LCD structure */ +/*********************************************/ + +#ifdef SIS315H +static UCHAR * +GetLCDStructPtr661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + UCHAR *myptr = NULL; + USHORT romindex = 0, reg = 0, idx = 0; + + /* Use the BIOS tables only for LVDS panels; TMDS is unreliable + * due to the variaty of panels the BIOS doesn't know about. + * Exception: If the BIOS has better knowledge (such as in case + * of machines with a 301C and a panel that does not support DDC) + * use the BIOS data as well. + */ + + if((SiS_Pr->SiS_ROMNew) && + ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) || (!SiS_Pr->PanelSelfDetected))) { + + if(HwInfo->jChipType < SIS_661) reg = 0x3c; + else reg = 0x7d; + + idx = (SiS_GetReg(SiS_Pr->SiS_P3d4,reg) & 0x1f) * 26; + + if(idx < (8*26)) { + myptr = (UCHAR *)&SiS_LCDStruct661[idx]; + } + romindex = SISGETROMW(0x100); + if(romindex) { + romindex += idx; + myptr = &ROMAddr[romindex]; + } + } + return myptr; +} + +static USHORT +GetLCDStructPtr661_2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT romptr = 0; + + /* Use the BIOS tables only for LVDS panels; TMDS is unreliable + * due to the variaty of panels the BIOS doesn't know about. + * Exception: If the BIOS has better knowledge (such as in case + * of machines with a 301C and a panel that does not support DDC) + * use the BIOS data as well. + */ + + if((SiS_Pr->SiS_ROMNew) && + ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) || (!SiS_Pr->PanelSelfDetected))) { + romptr = SISGETROMW(0x102); + romptr += ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) * SiS_Pr->SiS661LCD2TableSize); + } + + return(romptr); +} +#endif + +/*********************************************/ +/* Adjust Rate for CRT2 */ +/*********************************************/ + +static BOOLEAN +SiS_AdjustCRT2Rate(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RRTI, USHORT *i, PSIS_HW_INFO HwInfo) +{ + USHORT checkmask=0,modeid,infoflag; + + modeid = SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID; + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + + checkmask |= SupportRAMDAC2; + if(HwInfo->jChipType >= SIS_315H) { + checkmask |= SupportRAMDAC2_135; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + checkmask |= SupportRAMDAC2_162; + if(SiS_Pr->SiS_VBType & VB_SIS301C) { + checkmask |= SupportRAMDAC2_202; + } + } + } + + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + + checkmask |= SupportLCD; + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(modeid == 0x2e) checkmask |= Support64048060Hz; + } + } + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + + checkmask |= SupportHiVision; + + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750|SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) { + + checkmask |= SupportTV; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + checkmask |= SupportTV1024; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + checkmask |= SupportYPbPr750p; + } + } + } + + } + + } else { /* LVDS */ + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + checkmask |= SupportCHTV; + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + checkmask |= SupportLCD; + } + + } + + /* Look backwards in table for matching CRT2 mode */ + for(; SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID == modeid; (*i)--) { + infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag; + if(infoflag & checkmask) return TRUE; + if((*i) == 0) break; + } + + /* Look through the whole mode-section of the table from the beginning + * for a matching CRT2 mode if no mode was found yet. + */ + for((*i) = 0; ; (*i)++) { + if(SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID != modeid) break; + infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag; + if(infoflag & checkmask) return TRUE; + } + return FALSE; +} + +/*********************************************/ +/* Get rate index */ +/*********************************************/ + +USHORT +SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo) +{ + SHORT LCDRefreshIndex[] = { 0x00, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00 }; + USHORT RRTI,i,backup_i; + USHORT modeflag,index,temp,backupindex; + + /* Do NOT check for UseCustomMode here, will skrew up FIFO */ + if(ModeNo == 0xfe) return 0; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(modeflag & HalfDCLK) return 0; + } + } + + if(ModeNo < 0x14) return 0xFFFF; + + index = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x33) >> SiS_Pr->SiS_SelectCRT2Rate) & 0x0F; + backupindex = index; + + if(index > 0) index--; + + if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_VBType & VB_NoLCD) index = 0; + else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index = backupindex = 0; + } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_VBType & VB_NoLCD)) { + temp = LCDRefreshIndex[SiS_GetBIOSLCDResInfo(SiS_Pr)]; + if(index > temp) index = temp; + } + } + } else { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) index = 0; + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) index = 0; + } + } + } + + RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + ModeNo = SiS_Pr->SiS_RefIndex[RRTI].ModeID; + + if(HwInfo->jChipType >= SIS_315H) { + if(!(SiS_Pr->SiS_VBInfo & DriverMode)) { + if( (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x105) || + (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x107) ) { + if(backupindex <= 1) RRTI++; + } + } + } + + i = 0; + do { + if(SiS_Pr->SiS_RefIndex[RRTI + i].ModeID != ModeNo) break; + temp = SiS_Pr->SiS_RefIndex[RRTI + i].Ext_InfoFlag; + temp &= ModeTypeMask; + if(temp < SiS_Pr->SiS_ModeType) break; + i++; + index--; + } while(index != 0xFFFF); + + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + temp = SiS_Pr->SiS_RefIndex[RRTI + i - 1].Ext_InfoFlag; + if(temp & InterlaceMode) i++; + } + } + + i--; + + if((SiS_Pr->SiS_SetFlag & ProgrammingCRT2) && (!(SiS_Pr->SiS_VBInfo & DisableCRT2Display))) { + backup_i = i; + if(!(SiS_AdjustCRT2Rate(SiS_Pr, ModeNo, ModeIdIndex, RRTI, &i, HwInfo))) { + i = backup_i; + } + } + + return(RRTI + i); +} + +/*********************************************/ +/* STORE CRT2 INFO in CR34 */ +/*********************************************/ + +static void +SiS_SaveCRT2Info(SiS_Private *SiS_Pr, USHORT ModeNo) +{ + USHORT temp1,temp2; + + /* Store CRT1 ModeNo in CR34 */ + SiS_SetReg(SiS_Pr->SiS_P3d4,0x34,ModeNo); + temp1 = (SiS_Pr->SiS_VBInfo & SetInSlaveMode) >> 8; + temp2 = ~(SetInSlaveMode >> 8); + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x31,temp2,temp1); +} + +/*********************************************/ +/* HELPER: GET SOME DATA FROM BIOS ROM */ +/*********************************************/ + +#ifdef SIS300 +static BOOLEAN +SiS_CR36BIOSWord23b(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT temp,temp1; + + if(SiS_Pr->SiS_UseROM) { + if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { + temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f); + temp1 = SISGETROMW(0x23b); + if(temp1 & temp) return TRUE; + } + } + return FALSE; +} + +static BOOLEAN +SiS_CR36BIOSWord23d(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT temp,temp1; + + if(SiS_Pr->SiS_UseROM) { + if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { + temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f); + temp1 = SISGETROMW(0x23d); + if(temp1 & temp) return TRUE; + } + } + return FALSE; +} +#endif + +/*********************************************/ +/* HELPER: DELAY FUNCTIONS */ +/*********************************************/ + +void +SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime) +{ + USHORT i, j; + + for(i=0; i<delaytime; i++) { + j += SiS_GetReg(SiS_Pr->SiS_P3c4,0x05); + } +} + +#if defined(SIS300) || defined(SIS315H) +static void +SiS_GenericDelay(SiS_Private *SiS_Pr, USHORT delay) +{ + USHORT temp,flag; + + flag = SiS_GetRegByte(0x61) & 0x10; + + while(delay) { + temp = SiS_GetRegByte(0x61) & 0x10; + if(temp == flag) continue; + flag = temp; + delay--; + } +} +#endif + +#ifdef SIS315H +static void +SiS_LongDelay(SiS_Private *SiS_Pr, USHORT delay) +{ + while(delay--) { + SiS_GenericDelay(SiS_Pr,0x19df); + } +} +#endif + +#if defined(SIS300) || defined(SIS315H) +static void +SiS_ShortDelay(SiS_Private *SiS_Pr, USHORT delay) +{ + while(delay--) { + SiS_GenericDelay(SiS_Pr,0x42); + } +} +#endif + +static void +SiS_PanelDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DelayTime) +{ +#if defined(SIS300) || defined(SIS315H) + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT PanelID, DelayIndex, Delay=0; +#endif + + if(HwInfo->jChipType < SIS_315H) { + +#ifdef SIS300 + + PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBType & VB_SIS301) PanelID &= 0xf7; + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x18) & 0x10)) PanelID = 0x12; + } + DelayIndex = PanelID >> 4; + if((DelayTime >= 2) && ((PanelID & 0x0f) == 1)) { + Delay = 3; + } else { + if(DelayTime >= 2) DelayTime -= 2; + if(!(DelayTime & 0x01)) { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0]; + } else { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1]; + } + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x40) { + if(!(DelayTime & 0x01)) Delay = (USHORT)ROMAddr[0x225]; + else Delay = (USHORT)ROMAddr[0x226]; + } + } + } + SiS_ShortDelay(SiS_Pr, Delay); + +#endif /* SIS300 */ + + } else { + +#ifdef SIS315H + + if((HwInfo->jChipType >= SIS_661) || + (HwInfo->jChipType <= SIS_315PRO) || + (HwInfo->jChipType == SIS_330) || + (SiS_Pr->SiS_ROMNew)) { + + if(!(DelayTime & 0x01)) { + SiS_DDC2Delay(SiS_Pr, 0x1000); + } else { + SiS_DDC2Delay(SiS_Pr, 0x4000); + } + + } else if((SiS_Pr->SiS_IF_DEF_LVDS == 1) /* || + (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || + (SiS_Pr->SiS_CustomT == CUT_CLEVO1400) */ ) { /* 315 series, LVDS; Special */ + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); + if(SiS_Pr->SiS_CustomT == CUT_CLEVO1400) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x1b) & 0x10)) PanelID = 0x12; + } + if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { + DelayIndex = PanelID & 0x0f; + } else { + DelayIndex = PanelID >> 4; + } + if((DelayTime >= 2) && ((PanelID & 0x0f) == 1)) { + Delay = 3; + } else { + if(DelayTime >= 2) DelayTime -= 2; + if(!(DelayTime & 0x01)) { + Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[0]; + } else { + Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[1]; + } + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + if(ROMAddr[0x13c] & 0x40) { + if(!(DelayTime & 0x01)) { + Delay = (USHORT)ROMAddr[0x17e]; + } else { + Delay = (USHORT)ROMAddr[0x17f]; + } + } + } + } + SiS_ShortDelay(SiS_Pr, Delay); + } + + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { /* 315 series, all bridges */ + + DelayIndex = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4; + if(!(DelayTime & 0x01)) { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0]; + } else { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1]; + } + Delay <<= 8; + SiS_DDC2Delay(SiS_Pr, Delay); + + } + +#endif /* SIS315H */ + + } +} + +#ifdef SIS315H +static void +SiS_PanelDelayLoop(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT DelayTime, USHORT DelayLoop) +{ + int i; + for(i=0; i<DelayLoop; i++) { + SiS_PanelDelay(SiS_Pr, HwInfo, DelayTime); + } +} +#endif + +/*********************************************/ +/* HELPER: WAIT-FOR-RETRACE FUNCTIONS */ +/*********************************************/ + +void +SiS_WaitRetrace1(SiS_Private *SiS_Pr) +{ + USHORT watchdog; + + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return; + if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x17) & 0x80)) return; + + watchdog = 65535; + while((SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08) && --watchdog); + watchdog = 65535; + while((!(SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog); +} + +#if defined(SIS300) || defined(SIS315H) +static void +SiS_WaitRetrace2(SiS_Private *SiS_Pr, USHORT reg) +{ + USHORT watchdog; + + watchdog = 65535; + while((SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02) && --watchdog); + watchdog = 65535; + while((!(SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02)) && --watchdog); +} +#endif + +static void +SiS_WaitVBRetrace(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(HwInfo->jChipType < SIS_315H) { +#ifdef SIS300 + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x20)) return; + } + if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x80)) { + SiS_WaitRetrace1(SiS_Pr); + } else { + SiS_WaitRetrace2(SiS_Pr, 0x25); + } +#endif + } else { +#ifdef SIS315H + if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x40)) { + SiS_WaitRetrace1(SiS_Pr); + } else { + SiS_WaitRetrace2(SiS_Pr, 0x30); + } +#endif + } +} + +static void +SiS_VBWait(SiS_Private *SiS_Pr) +{ + USHORT tempal,temp,i,j; + + temp = 0; + for(i=0; i<3; i++) { + for(j=0; j<100; j++) { + tempal = SiS_GetRegByte(SiS_Pr->SiS_P3da); + if(temp & 0x01) { + if((tempal & 0x08)) continue; + else break; + } else { + if(!(tempal & 0x08)) continue; + else break; + } + } + temp ^= 0x01; + } +} + +static void +SiS_VBLongWait(SiS_Private *SiS_Pr) +{ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SiS_VBWait(SiS_Pr); + } else { + SiS_WaitRetrace1(SiS_Pr); + } +} + +/*********************************************/ +/* HELPER: MISC */ +/*********************************************/ + +#ifdef SIS300 +static BOOLEAN +SiS_Is301B(SiS_Private *SiS_Pr) +{ + if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01) >= 0xb0) return TRUE; + return FALSE; +} +#endif + +static BOOLEAN +SiS_CRT2IsLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(HwInfo->jChipType == SIS_730) { + flag = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13); + if(flag & 0x20) return TRUE; + } + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & 0x20) return TRUE; + return FALSE; +} + +BOOLEAN +SiS_IsDualEdge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ +#ifdef SIS315H + USHORT flag; + + if(HwInfo->jChipType >= SIS_315H) { + if((HwInfo->jChipType != SIS_650) || (SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0)) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & EnableDualEdge) return TRUE; + } + } +#endif + return FALSE; +} + +BOOLEAN +SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ +#ifdef SIS315H + USHORT flag; + + if(HwInfo->jChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if((flag & EnableDualEdge) && (flag & SetToLCDA)) return TRUE; + } +#endif + return FALSE; +} + +#ifdef SIS315H +static BOOLEAN +SiS_IsVAorLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(SiS_IsVAMode(SiS_Pr,HwInfo)) return TRUE; + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) return TRUE; + return FALSE; +} +#endif + +static BOOLEAN +SiS_IsDualLink(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ +#ifdef SIS315H + if(HwInfo->jChipType >= SIS_315H) { + if((SiS_CRT2IsLCD(SiS_Pr, HwInfo)) || + (SiS_IsVAMode(SiS_Pr, HwInfo))) { + if(SiS_Pr->SiS_LCDInfo & LCDDualLink) return TRUE; + } + } +#endif + return FALSE; +} + +#ifdef SIS315H +static BOOLEAN +SiS_TVEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if((SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) != 0x0c) return TRUE; + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS301LV302LV)) { + if(SiS_GetReg(SiS_Pr->SiS_Part2Port,0x4d) & 0x10) return TRUE; + } + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_LCDAEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) return TRUE; + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_WeHaveBacklightCtrl(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x79) & 0x10) return TRUE; + } + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_IsNotM650orLater(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(HwInfo->jChipType == SIS_650) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f); + flag &= 0xF0; + /* Check for revision != A0 only */ + if((flag == 0xe0) || (flag == 0xc0) || + (flag == 0xb0) || (flag == 0x90)) return FALSE; + } else if(HwInfo->jChipType >= SIS_661) return FALSE; + return TRUE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_IsYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(HwInfo->jChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & EnableCHYPbPr) return TRUE; /* = YPrPb = 0x08 */ + } + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_IsChScart(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(HwInfo->jChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & EnableCHScart) return TRUE; /* = Scart = 0x04 */ + } + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_IsTVOrYPbPrOrScart(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(HwInfo->jChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToTV) return TRUE; + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & EnableCHYPbPr) return TRUE; /* = YPrPb = 0x08 */ + if(flag & EnableCHScart) return TRUE; /* = Scart = 0x04 - TW */ + } else { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToTV) return TRUE; + } + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_IsLCDOrLCDA(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(HwInfo->jChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToLCD) return TRUE; + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & SetToLCDA) return TRUE; + } else { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToLCD) return TRUE; + } + return FALSE; +} +#endif + +static BOOLEAN +SiS_BridgeIsOn(SiS_Private *SiS_Pr) +{ + USHORT flag; + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + return TRUE; + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); + if((flag == 1) || (flag == 2)) return TRUE; + } + return FALSE; +} + +static BOOLEAN +SiS_BridgeIsEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(SiS_BridgeIsOn(SiS_Pr)) { + flag = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); + if(HwInfo->jChipType < SIS_315H) { + flag &= 0xa0; + if((flag == 0x80) || (flag == 0x20)) return TRUE; + } else { + flag &= 0x50; + if((flag == 0x40) || (flag == 0x10)) return TRUE; + } + } + return FALSE; +} + +static BOOLEAN +SiS_BridgeInSlavemode(SiS_Private *SiS_Pr) +{ + USHORT flag1; + + flag1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31); + if(flag1 & (SetInSlaveMode >> 8)) return TRUE; + return FALSE; +} + +/*********************************************/ +/* GET VIDEO BRIDGE CONFIG INFO */ +/*********************************************/ + +/* Setup general purpose IO for Chrontel communication */ +void +SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo) +{ + unsigned long acpibase; + unsigned short temp; + + if(!(SiS_Pr->SiS_ChSW)) return; + +#ifdef LINUX_KERNEL + SiS_SetRegLong(0xcf8,0x80000874); /* get ACPI base */ + acpibase = SiS_GetRegLong(0xcfc); +#else + acpibase = pciReadLong(0x00000800, 0x74); +#endif + acpibase &= 0xFFFF; + temp = SiS_GetRegShort((USHORT)(acpibase + 0x3c)); /* ACPI register 0x3c: GP Event 1 I/O mode select */ + temp &= 0xFEFF; + SiS_SetRegShort((USHORT)(acpibase + 0x3c), temp); + temp = SiS_GetRegShort((USHORT)(acpibase + 0x3c)); + temp = SiS_GetRegShort((USHORT)(acpibase + 0x3a)); /* ACPI register 0x3a: GP Pin Level (low/high) */ + temp &= 0xFEFF; + if(!(myvbinfo & SetCRT2ToTV)) temp |= 0x0100; + SiS_SetRegShort((USHORT)(acpibase + 0x3a), temp); + temp = SiS_GetRegShort((USHORT)(acpibase + 0x3a)); +} + +void +SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo, int checkcrt2mode) +{ + USHORT tempax,tempbx,temp; + USHORT modeflag, resinfo=0; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + SiS_Pr->SiS_SetFlag = 0; + + SiS_Pr->SiS_ModeType = modeflag & ModeTypeMask; + + tempbx = 0; + if(SiS_BridgeIsOn(SiS_Pr)) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); +#if 0 + if(HwInfo->jChipType < SIS_661) { + /* NO - YPbPr not set yet ! */ + if(SiS_Pr->SiS_YPbPr & <all ypbpr except 525i>) { + temp &= (SetCRT2ToHiVision | SwitchCRT2 | SetSimuScanMode); /* 0x83 */ + temp |= SetCRT2ToHiVision; /* 0x80 */ + } + if(SiS_Pr->SiS_YPbPr & <ypbpr525i>) { + temp &= (SetCRT2ToHiVision | SwitchCRT2 | SetSimuScanMode); /* 0x83 */ + temp |= SetCRT2ToSVIDEO; /* 0x08 */ + } + } +#endif + tempbx |= temp; + tempax = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) << 8; + tempax &= (DriverMode | LoadDACFlag | SetNotSimuMode | SetPALTV); + tempbx |= tempax; + +#ifdef SIS315H + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISLCDA) { + if(ModeNo == 0x03) { + /* Mode 0x03 is never in driver mode */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x31,0xbf); + } + if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & (DriverMode >> 8))) { + /* Reset LCDA setting if not driver mode */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc); + } + if(IS_SIS650) { + if(SiS_Pr->SiS_UseLCDA) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xF0) { + if((ModeNo <= 0x13) || (!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & (DriverMode >> 8)))) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x38,(EnableDualEdge | SetToLCDA)); + } + } + } + } + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if((temp & (EnableDualEdge | SetToLCDA)) == (EnableDualEdge | SetToLCDA)) { + tempbx |= SetCRT2ToLCDA; + } + } + + if(SiS_Pr->SiS_VBType & (VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)) { + tempbx &= ~(SetCRT2ToRAMDAC); + } + + if(HwInfo->jChipType >= SIS_661) { + tempbx &= ~(SetCRT2ToYPbPr525750 | SetCRT2ToHiVision); + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(SiS_Pr->SiS_VBType & VB_SISYPBPR) { + if(temp & 0x04) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0; + if(temp == 0x60) tempbx |= SetCRT2ToHiVision; + else tempbx |= SetCRT2ToYPbPr525750; + } + } else if(SiS_Pr->SiS_VBType & VB_SISHIVISION) { + if(temp & 0x04) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0; + if(temp == 0x60) tempbx |= SetCRT2ToHiVision; + } + } + } + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(temp & SetToLCDA) { + tempbx |= SetCRT2ToLCDA; + } + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(temp & EnableCHYPbPr) { + tempbx |= SetCRT2ToCHYPbPr; + } + } + } + } + +#endif /* SIS315H */ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = SetCRT2ToSVIDEO | + SetCRT2ToAVIDEO | + SetCRT2ToSCART | + SetCRT2ToLCDA | + SetCRT2ToLCD | + SetCRT2ToRAMDAC | + SetCRT2ToHiVision | + SetCRT2ToYPbPr525750; + } else { + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + temp = SetCRT2ToAVIDEO | + SetCRT2ToSVIDEO | + SetCRT2ToSCART | + SetCRT2ToLCDA | + SetCRT2ToLCD | + SetCRT2ToCHYPbPr; + } else { + temp = SetCRT2ToLCDA | + SetCRT2ToLCD; + } + } else { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + temp = SetCRT2ToTV | SetCRT2ToLCD; + } else { + temp = SetCRT2ToLCD; + } + } + } + + if(!(tempbx & temp)) { + tempax = DisableCRT2Display; + tempbx = 0; + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + USHORT clearmask = ( DriverMode | + DisableCRT2Display | + LoadDACFlag | + SetNotSimuMode | + SetInSlaveMode | + SetPALTV | + SwitchCRT2 | + SetSimuScanMode ); + if(tempbx & SetCRT2ToLCDA) tempbx &= (clearmask | SetCRT2ToLCDA); + if(tempbx & SetCRT2ToRAMDAC) tempbx &= (clearmask | SetCRT2ToRAMDAC); + if(tempbx & SetCRT2ToLCD) tempbx &= (clearmask | SetCRT2ToLCD); + if(tempbx & SetCRT2ToSCART) tempbx &= (clearmask | SetCRT2ToSCART); + if(tempbx & SetCRT2ToHiVision) tempbx &= (clearmask | SetCRT2ToHiVision); + if(tempbx & SetCRT2ToYPbPr525750) tempbx &= (clearmask | SetCRT2ToYPbPr525750); + } else { + if(HwInfo->jChipType >= SIS_315H) { + if(tempbx & SetCRT2ToLCDA) { + tempbx &= (0xFF00|SwitchCRT2|SetSimuScanMode); + } + } + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(tempbx & SetCRT2ToTV) { + tempbx &= (0xFF00|SetCRT2ToTV|SwitchCRT2|SetSimuScanMode); + } + } + if(tempbx & SetCRT2ToLCD) { + tempbx &= (0xFF00|SetCRT2ToLCD|SwitchCRT2|SetSimuScanMode); + } + if(HwInfo->jChipType >= SIS_315H) { + if(tempbx & SetCRT2ToLCDA) { + tempbx |= SetCRT2ToLCD; + } + } + } + + if(tempax & DisableCRT2Display) { + if(!(tempbx & (SwitchCRT2 | SetSimuScanMode))) { + tempbx = SetSimuScanMode | DisableCRT2Display; + } + } + + if(!(tempbx & DriverMode)) tempbx |= SetSimuScanMode; + + /* LVDS/CHRONTEL (LCD/TV) and 301BDH (LCD) can only be slave in 8bpp modes */ + if(SiS_Pr->SiS_ModeType <= ModeVGA) { + if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) || + ((SiS_Pr->SiS_VBType & VB_NoLCD) && (tempbx & SetCRT2ToLCD)) ) { + modeflag &= (~CRT2Mode); + } + } + + if(!(tempbx & SetSimuScanMode)) { + if(tempbx & SwitchCRT2) { + if((!(modeflag & CRT2Mode)) && (checkcrt2mode)) { + if( (HwInfo->jChipType >= SIS_315H) && + (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) ) { + if(resinfo != SIS_RI_1600x1200) { + tempbx |= SetSimuScanMode; + } + } else { + tempbx |= SetSimuScanMode; + } + } + } else { + if(SiS_BridgeIsEnabled(SiS_Pr,HwInfo)) { + if(!(tempbx & DriverMode)) { + if(SiS_BridgeInSlavemode(SiS_Pr)) { + tempbx |= SetSimuScanMode; + } + } + } + } + } + + if(!(tempbx & DisableCRT2Display)) { + if(tempbx & DriverMode) { + if(tempbx & SetSimuScanMode) { + if((!(modeflag & CRT2Mode)) && (checkcrt2mode)) { + if( (HwInfo->jChipType >= SIS_315H) && + (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) ) { + if(resinfo != SIS_RI_1600x1200) { + tempbx |= SetInSlaveMode; + } + } else { + tempbx |= SetInSlaveMode; + } + } + } + } else { + tempbx |= SetInSlaveMode; + } + } + + } + + SiS_Pr->SiS_VBInfo = tempbx; + + if(HwInfo->jChipType == SIS_630) { + SiS_SetChrontelGPIO(SiS_Pr, SiS_Pr->SiS_VBInfo); + } + +#ifdef TWDEBUG +#ifdef LINUX_KERNEL + printk(KERN_DEBUG "sisfb: (VBInfo= 0x%04x, SetFlag=0x%04x)\n", + SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag); +#endif +#ifdef LINUX_XF86 + xf86DrvMsgVerb(0, X_PROBED, 3, "(init301: VBInfo=0x%04x, SetFlag=0x%04x)\n", + SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag); +#endif +#endif +} + +/*********************************************/ +/* DETERMINE YPbPr MODE */ +/*********************************************/ + +void +SiS_SetYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + + UCHAR temp; + + /* Note: This variable is only used on 30xLV systems. + * CR38 has a different meaning on LVDS/CH7019 systems. + * On 661 and later, these bits moved to CR35. + * + * On 301, 301B, only HiVision 1080i is supported. + * On 30xLV, 301C, only YPbPr 1080i is supported. + */ + + SiS_Pr->SiS_YPbPr = 0; + if(HwInfo->jChipType >= SIS_661) return; + + if(SiS_Pr->SiS_VBType) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + SiS_Pr->SiS_YPbPr = YPbPrHiVision; + } + } + + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & (VB_SIS301LV302LV | VB_SIS301C)) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(temp & 0x08) { + switch((temp >> 4)) { + case 0x00: SiS_Pr->SiS_YPbPr = YPbPr525i; break; + case 0x01: SiS_Pr->SiS_YPbPr = YPbPr525p; break; + case 0x02: SiS_Pr->SiS_YPbPr = YPbPr750p; break; + case 0x03: SiS_Pr->SiS_YPbPr = YPbPrHiVision; break; + } + } + } + } + +} + +/*********************************************/ +/* DETERMINE TVMode flag */ +/*********************************************/ + +void +SiS_SetTVMode(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT temp, temp1, resinfo = 0, romindex = 0; + UCHAR OutputSelect = *SiS_Pr->pSiS_OutputSelect; + + SiS_Pr->SiS_TVMode = 0; + + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return; + if(SiS_Pr->UseCustomMode) return; + + if(ModeNo > 0x13) { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + if(HwInfo->jChipType < SIS_661) { + + if(SiS_Pr->SiS_VBInfo & SetPALTV) SiS_Pr->SiS_TVMode |= TVSetPAL; + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = 0; + if((HwInfo->jChipType == SIS_630) || + (HwInfo->jChipType == SIS_730)) { + temp = 0x35; + romindex = 0xfe; + } else if(HwInfo->jChipType >= SIS_315H) { + temp = 0x38; + romindex = 0xf3; + if(HwInfo->jChipType >= SIS_330) romindex = 0x11b; + } + if(temp) { + if(romindex && SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { + OutputSelect = ROMAddr[romindex]; + if(!(OutputSelect & EnablePALMN)) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,temp,0x3F); + } + } + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,temp); + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + if(temp1 & EnablePALM) { /* 0x40 */ + SiS_Pr->SiS_TVMode |= TVSetPALM; + SiS_Pr->SiS_TVMode &= ~TVSetPAL; + } else if(temp1 & EnablePALN) { /* 0x80 */ + SiS_Pr->SiS_TVMode |= TVSetPALN; + } + } else { + if(temp1 & EnableNTSCJ) { /* 0x40 */ + SiS_Pr->SiS_TVMode |= TVSetNTSCJ; + } + } + } + /* Translate HiVision/YPbPr to our new flags */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(SiS_Pr->SiS_YPbPr == YPbPr750p) SiS_Pr->SiS_TVMode |= TVSetYPbPr750p; + else if(SiS_Pr->SiS_YPbPr == YPbPr525p) SiS_Pr->SiS_TVMode |= TVSetYPbPr525p; + else if(SiS_Pr->SiS_YPbPr == YPbPrHiVision) SiS_Pr->SiS_TVMode |= TVSetHiVision; + else SiS_Pr->SiS_TVMode |= TVSetYPbPr525i; + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetYPbPr525p | TVSetYPbPr525i)) { + SiS_Pr->SiS_VBInfo &= ~SetCRT2ToHiVision; + SiS_Pr->SiS_VBInfo |= SetCRT2ToYPbPr525750; + } else if(SiS_Pr->SiS_TVMode & TVSetHiVision) { + SiS_Pr->SiS_TVMode |= TVSetPAL; + } + } + } else if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_CHOverScan) { + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + if((temp & TVOverScan) || (SiS_Pr->SiS_CHOverScan == 1)) { + SiS_Pr->SiS_TVMode |= TVSetCHOverScan; + } + } else if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x79); + if((temp & 0x80) || (SiS_Pr->SiS_CHOverScan == 1)) { + SiS_Pr->SiS_TVMode |= TVSetCHOverScan; + } + } + if(SiS_Pr->SiS_CHSOverScan) { + SiS_Pr->SiS_TVMode |= TVSetCHOverScan; + } + } + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + if(temp & EnablePALM) SiS_Pr->SiS_TVMode |= TVSetPALM; + else if(temp & EnablePALN) SiS_Pr->SiS_TVMode |= TVSetPALN; + } else { + if(temp & EnableNTSCJ) { + SiS_Pr->SiS_TVMode |= TVSetNTSCJ; + } + } + } + } + + } else { /* 661 and later */ + + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + if(temp1 & 0x01) { + SiS_Pr->SiS_TVMode |= TVSetPAL; + if(temp1 & 0x08) { + SiS_Pr->SiS_TVMode |= TVSetPALN; + } else if(temp1 & 0x04) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + SiS_Pr->SiS_TVMode &= ~TVSetPAL; + } + SiS_Pr->SiS_TVMode |= TVSetPALM; + } + } else { + if(temp1 & 0x02) { + SiS_Pr->SiS_TVMode |= TVSetNTSCJ; + } + } + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_Pr->SiS_CHOverScan) { + if((temp1 & 0x10) || (SiS_Pr->SiS_CHOverScan == 1)) { + SiS_Pr->SiS_TVMode |= TVSetCHOverScan; + } + } + } + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + temp1 &= 0xe0; + if(temp1 == 0x00) SiS_Pr->SiS_TVMode |= TVSetYPbPr525i; + else if(temp1 == 0x20) SiS_Pr->SiS_TVMode |= TVSetYPbPr525p; + else if(temp1 == 0x40) SiS_Pr->SiS_TVMode |= TVSetYPbPr750p; + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + SiS_Pr->SiS_TVMode |= (TVSetHiVision | TVSetPAL); + } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750 | SetCRT2ToHiVision)) { + if(resinfo == SIS_RI_800x480 || resinfo == SIS_RI_1024x576 || resinfo == SIS_RI_1280x720) { + SiS_Pr->SiS_TVMode |= TVAspect169; + } else { + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x39); + if(temp1 & 0x02) { + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetHiVision)) { + SiS_Pr->SiS_TVMode |= TVAspect169; + } else { + SiS_Pr->SiS_TVMode |= TVAspect43LB; + } + } else { + SiS_Pr->SiS_TVMode |= TVAspect43; + } + } + } + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART) SiS_Pr->SiS_TVMode |= TVSetPAL; + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + SiS_Pr->SiS_TVMode |= TVSetPAL; + SiS_Pr->SiS_TVMode &= ~(TVSetPALM | TVSetPALN | TVSetNTSCJ); + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525i | TVSetYPbPr525p | TVSetYPbPr750p)) { + SiS_Pr->SiS_TVMode &= ~(TVSetPAL | TVSetNTSCJ | TVSetPALM | TVSetPALN); + } + } + + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { + SiS_Pr->SiS_TVMode |= TVSetTVSimuMode; + } + } + + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + /* BIOS sets TVNTSC1024 without checking 525p here. Wrong? */ + if(!(SiS_Pr->SiS_TVMode & (TVSetHiVision | TVSetYPbPr525p | TVSetYPbPr750p))) { + if(resinfo == SIS_RI_1024x768) { + SiS_Pr->SiS_TVMode |= TVSetNTSC1024; + } + } + } + + SiS_Pr->SiS_TVMode |= TVRPLLDIV2XO; + if((SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) && + (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO; + } else if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) { + SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO; + } else if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) { + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO; + } + } + + } + + SiS_Pr->SiS_VBInfo &= ~SetPALTV; + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "(init301: TVMode %x, VBInfo %x)\n", SiS_Pr->SiS_TVMode, SiS_Pr->SiS_VBInfo); +#endif +} + +/*********************************************/ +/* GET LCD INFO */ +/*********************************************/ + +static USHORT +SiS_GetBIOSLCDResInfo(SiS_Private *SiS_Pr) +{ + USHORT temp = SiS_Pr->SiS_LCDResInfo; + /* Translate my LCDResInfo to BIOS value */ + if(temp == Panel_1280x768_2) temp = Panel_1280x768; + if(temp == Panel_1280x800_2) temp = Panel_1280x800; + return temp; +} + +static void +SiS_GetLCDInfoBIOS(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ +#ifdef SIS315H + UCHAR *ROMAddr; + USHORT temp; + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "Paneldata driver: [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n", + SiS_Pr->PanelHT, SiS_Pr->PanelVT, + SiS_Pr->PanelHRS, SiS_Pr->PanelHRE, + SiS_Pr->PanelVRS, SiS_Pr->PanelVRE, + SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK, + SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A, + SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B); +#endif + + if((ROMAddr = GetLCDStructPtr661(SiS_Pr, HwInfo))) { + if((temp = SISGETROMW(6)) != SiS_Pr->PanelHT) { + SiS_Pr->SiS_NeedRomModeData = TRUE; + SiS_Pr->PanelHT = temp; + } + if((temp = SISGETROMW(8)) != SiS_Pr->PanelVT) { + SiS_Pr->SiS_NeedRomModeData = TRUE; + SiS_Pr->PanelVT = temp; + } + SiS_Pr->PanelHRS = SISGETROMW(10); + SiS_Pr->PanelHRE = SISGETROMW(12); + SiS_Pr->PanelVRS = SISGETROMW(14); + SiS_Pr->PanelVRE = SISGETROMW(16); + SiS_Pr->PanelVCLKIdx315 = VCLK_CUSTOM_315; + SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].CLOCK = + SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].CLOCK = (USHORT)((UCHAR)ROMAddr[18]); + SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2B = + SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_A = ROMAddr[19]; + SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2C = + SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_B = ROMAddr[20]; + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "Paneldata BIOS: [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n", + SiS_Pr->PanelHT, SiS_Pr->PanelVT, + SiS_Pr->PanelHRS, SiS_Pr->PanelHRE, + SiS_Pr->PanelVRS, SiS_Pr->PanelVRE, + SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK, + SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A, + SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B); +#endif + + } +#endif +} + +static void +SiS_CheckScaling(SiS_Private *SiS_Pr, USHORT resinfo, const UCHAR *nonscalingmodes) +{ + int i = 0; + while(nonscalingmodes[i] != 0xff) { + if(nonscalingmodes[i++] == resinfo) { + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) || + (SiS_Pr->UsePanelScaler == -1)) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + } + } +} + +void +SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo) +{ +#ifdef SIS300 + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + const unsigned char SiS300SeriesLCDRes[] = + { 0, 1, 2, 3, 7, 4, 5, 8, + 0, 0, 10, 0, 0, 0, 0, 15 }; +#endif +#ifdef SIS315H + UCHAR *myptr = NULL; +#endif + USHORT temp,modeflag,resinfo=0,modexres=0,modeyres=0; + BOOLEAN panelcanscale = FALSE; + + SiS_Pr->SiS_LCDResInfo = 0; + SiS_Pr->SiS_LCDTypeInfo = 0; + SiS_Pr->SiS_LCDInfo = 0; + SiS_Pr->PanelHRS = 999; /* HSync start */ + SiS_Pr->PanelHRE = 999; /* HSync end */ + SiS_Pr->PanelVRS = 999; /* VSync start */ + SiS_Pr->PanelVRE = 999; /* VSync end */ + SiS_Pr->SiS_NeedRomModeData = FALSE; + + if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))) return; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + modexres = SiS_Pr->SiS_ModeResInfo[resinfo].HTotal; + modeyres = SiS_Pr->SiS_ModeResInfo[resinfo].VTotal; + } + + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); + + /* For broken BIOSes: Assume 1024x768 */ + if(temp == 0) temp = 0x02; + + if((HwInfo->jChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { + SiS_Pr->SiS_LCDTypeInfo = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x7c) >> 2; + } else if((HwInfo->jChipType < SIS_315H) || (HwInfo->jChipType >= SIS_661)) { + SiS_Pr->SiS_LCDTypeInfo = temp >> 4; + } else { + SiS_Pr->SiS_LCDTypeInfo = (temp & 0x0F) - 1; + } + temp &= 0x0f; +#ifdef SIS300 + if(HwInfo->jChipType < SIS_315H) { + /* Very old BIOSes only know 7 sizes (NetVista 2179, 1.01g) */ + if(SiS_Pr->SiS_VBType & VB_SIS301) { + if(temp < 0x0f) temp &= 0x07; + } + /* Translate 300 series LCDRes to 315 series for unified usage */ + temp = SiS300SeriesLCDRes[temp]; + } +#endif + + /* Translate to our internal types */ + if(HwInfo->jChipType == SIS_550) { + if(temp == Panel310_640x480_2) temp = Panel_640x480_2; + if(temp == Panel310_640x480_3) temp = Panel_640x480_3; + } + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { /* SiS LVDS */ + if(temp == Panel310_1280x768) { + temp = Panel_1280x768_2; + } + if(SiS_Pr->SiS_ROMNew) { + if(temp == Panel661_1280x800) { + temp = Panel_1280x800_2; + } + } + } + + SiS_Pr->SiS_LCDResInfo = temp; + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { + SiS_Pr->SiS_LCDResInfo = Panel_Barco1366; + } else if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { + SiS_Pr->SiS_LCDResInfo = Panel_848x480; + } + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMin301) + SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMin301; + } else { + if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMinLVDS) + SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMinLVDS; + } + + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); + SiS_Pr->SiS_LCDInfo = temp & ~0x000e; + /* Need temp below! */ + + /* These can't scale no matter what */ + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_1280x960: + SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD; + } + + panelcanscale = (SiS_Pr->SiS_LCDInfo & DontExpandLCD) ? TRUE : FALSE; + + if(!SiS_Pr->UsePanelScaler) SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD; + else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + + /* Dual link, Pass 1:1 BIOS default, etc. */ +#ifdef SIS315H + if(HwInfo->jChipType >= SIS_661) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(temp & 0x08) SiS_Pr->SiS_LCDInfo |= LCDPass11; + } + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + if(SiS_Pr->SiS_ROMNew) { + if(temp & 0x02) SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } else if((myptr = GetLCDStructPtr661(SiS_Pr, HwInfo))) { + if(myptr[2] & 0x01) SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } + } + } else if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x01) SiS_Pr->SiS_LCDInfo |= LCDPass11; + } + if((SiS_Pr->SiS_ROMNew) && (!(SiS_Pr->PanelSelfDetected))) { + SiS_Pr->SiS_LCDInfo &= ~(LCDRGB18Bit); + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + if(temp & 0x01) SiS_Pr->SiS_LCDInfo |= LCDRGB18Bit; + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + if(temp & 0x02) SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } + } else if(!(SiS_Pr->SiS_ROMNew)) { + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + if((SiS_Pr->SiS_CustomT == CUT_CLEVO1024) && + (SiS_Pr->SiS_LCDResInfo == Panel_1024x768)) { + SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } + if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || + (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) || + (SiS_Pr->SiS_LCDResInfo == Panel_1680x1050)) { + SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } + } + } + } +#endif + + /* Pass 1:1 */ + if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_NoLCD)) { + /* Always center screen on LVDS (if scaling is disabled) */ + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + /* Always center screen on SiS LVDS (if scaling is disabled) */ + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } else { + /* By default, pass 1:1 on SiS TMDS (if scaling is supported) */ + if(panelcanscale) SiS_Pr->SiS_LCDInfo |= LCDPass11; + if(SiS_Pr->CenterScreen == 1) SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } + } + + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315; + + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_320x480: SiS_Pr->PanelXRes = 320; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelHT = 400; SiS_Pr->PanelVT = 525; + SiS_Pr->PanelVCLKIdx300 = VCLK28; + SiS_Pr->PanelVCLKIdx315 = VCLK28; + break; + case Panel_640x480_2: + case Panel_640x480_3: SiS_Pr->PanelXRes = 640; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelVRS = 24; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx300 = VCLK28; + SiS_Pr->PanelVCLKIdx315 = VCLK28; + break; + case Panel_640x480: SiS_Pr->PanelXRes = 640; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx300 = VCLK28; + SiS_Pr->PanelVCLKIdx315 = VCLK28; + break; + case Panel_800x600: SiS_Pr->PanelXRes = 800; SiS_Pr->PanelYRes = 600; + SiS_Pr->PanelHT = 1056; SiS_Pr->PanelVT = 628; + SiS_Pr->PanelHRS = 40; SiS_Pr->PanelHRE = 128; + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 4; + SiS_Pr->PanelVCLKIdx300 = VCLK40; + SiS_Pr->PanelVCLKIdx315 = VCLK40; + break; + case Panel_1024x600: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 600; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 800; + SiS_Pr->PanelHRS = 24; SiS_Pr->PanelHRE = 136; + SiS_Pr->PanelVRS = 2 /* 88 */ ; SiS_Pr->PanelVRE = 6; + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx315 = VCLK65_315; + break; + case Panel_1024x768: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHRS = 24; SiS_Pr->PanelHRE = 136; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + if(HwInfo->jChipType < SIS_315H) { + SiS_Pr->PanelHRS = 23; + SiS_Pr->PanelVRE = 5; + } + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx315 = VCLK65_315; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1152x768: SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHRS = 24; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + if(HwInfo->jChipType < SIS_315H) { + SiS_Pr->PanelHRS = 23; + SiS_Pr->PanelVRE = 5; + } + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx315 = VCLK65_315; + break; + case Panel_1152x864: SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes = 864; + break; + case Panel_1280x720: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 720; + SiS_Pr->PanelHT = 1650; SiS_Pr->PanelVT = 750; + SiS_Pr->PanelHRS = 110; SiS_Pr->PanelHRE = 40; + SiS_Pr->PanelVRS = 5; SiS_Pr->PanelVRE = 5; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x720; + /* Data above for TMDS (projector); get from BIOS for LVDS */ + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1280x768: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 768; + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + SiS_Pr->PanelHT = 1408; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelVCLKIdx300 = VCLK81_300; /* ? */ + SiS_Pr->PanelVCLKIdx315 = VCLK81_315; /* ? */ + } else { + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 802; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRS = 112; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + SiS_Pr->PanelVCLKIdx300 = VCLK81_300; + SiS_Pr->PanelVCLKIdx315 = VCLK81_315; + } + break; + case Panel_1280x768_2: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1660; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x768_2; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1280x800: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 800; + SiS_Pr->PanelHT = 1408; SiS_Pr->PanelVT = 816; + SiS_Pr->PanelHRS = 21; SiS_Pr->PanelHRE = 24; + SiS_Pr->PanelVRS = 4; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x800_315; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1280x800_2: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 800; + SiS_Pr->PanelHT = 1552; SiS_Pr->PanelVT = 812; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; + SiS_Pr->PanelVRS = 4; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x800_315_2; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1280x960: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 960; + SiS_Pr->PanelHT = 1800; SiS_Pr->PanelVT = 1000; + SiS_Pr->PanelVCLKIdx300 = VCLK108_3_300; + SiS_Pr->PanelVCLKIdx315 = VCLK108_3_315; + if(resinfo == SIS_RI_1280x1024) { + SiS_Pr->PanelVCLKIdx300 = VCLK100_300; + SiS_Pr->PanelVCLKIdx315 = VCLK100_315; + } + break; + case Panel_1280x1024: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 1024; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx300 = VCLK108_3_300; + SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1400x1050: SiS_Pr->PanelXRes = 1400; SiS_Pr->PanelYRes = 1050; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; /* HRE OK for LVDS, not for LCDA */ + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1600x1200: SiS_Pr->PanelXRes = 1600; SiS_Pr->PanelYRes = 1200; + SiS_Pr->PanelHT = 2160; SiS_Pr->PanelVT = 1250; + SiS_Pr->PanelHRS = 64; SiS_Pr->PanelHRE = 192; + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK162_315; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1680x1050: SiS_Pr->PanelXRes = 1680; SiS_Pr->PanelYRes = 1050; + SiS_Pr->PanelHT = 1900; SiS_Pr->PanelVT = 1066; + SiS_Pr->PanelHRS = 26; SiS_Pr->PanelHRE = 76; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + SiS_Pr->PanelVCLKIdx315 = VCLK121_315; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_Barco1366: SiS_Pr->PanelXRes = 1360; SiS_Pr->PanelYRes = 1024; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; + break; + case Panel_848x480: SiS_Pr->PanelXRes = 848; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelHT = 1088; SiS_Pr->PanelVT = 525; + break; + case Panel_Custom: SiS_Pr->PanelXRes = SiS_Pr->CP_MaxX; + SiS_Pr->PanelYRes = SiS_Pr->CP_MaxY; + SiS_Pr->PanelHT = SiS_Pr->CHTotal; + SiS_Pr->PanelVT = SiS_Pr->CVTotal; + if(SiS_Pr->CP_PreferredIndex != -1) { + SiS_Pr->PanelXRes = SiS_Pr->CP_HDisplay[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelYRes = SiS_Pr->CP_VDisplay[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelHT = SiS_Pr->CP_HTotal[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelVT = SiS_Pr->CP_VTotal[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelHRS = SiS_Pr->CP_HSyncStart[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelHRE = SiS_Pr->CP_HSyncEnd[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelVRS = SiS_Pr->CP_VSyncStart[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelVRE = SiS_Pr->CP_VSyncEnd[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelHRS -= SiS_Pr->PanelXRes; + SiS_Pr->PanelHRE -= SiS_Pr->PanelHRS; + SiS_Pr->PanelVRS -= SiS_Pr->PanelYRes; + SiS_Pr->PanelVRE -= SiS_Pr->PanelVRS; + if(SiS_Pr->CP_PrefClock) { + int idx; + SiS_Pr->PanelVCLKIdx315 = VCLK_CUSTOM_315; + SiS_Pr->PanelVCLKIdx300 = VCLK_CUSTOM_300; + if(HwInfo->jChipType < SIS_315H) idx = VCLK_CUSTOM_300; + else idx = VCLK_CUSTOM_315; + SiS_Pr->SiS_VCLKData[idx].CLOCK = + SiS_Pr->SiS_VBVCLKData[idx].CLOCK = SiS_Pr->CP_PrefClock; + SiS_Pr->SiS_VCLKData[idx].SR2B = + SiS_Pr->SiS_VBVCLKData[idx].Part4_A = SiS_Pr->CP_PrefSR2B; + SiS_Pr->SiS_VCLKData[idx].SR2C = + SiS_Pr->SiS_VBVCLKData[idx].Part4_B = SiS_Pr->CP_PrefSR2C; + } + } + break; + default: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; + break; + } + + /* Special cases */ + if( (SiS_Pr->SiS_IF_DEF_FSTN) || + (SiS_Pr->SiS_IF_DEF_DSTN) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) { + SiS_Pr->PanelHRS = 999; + SiS_Pr->PanelHRE = 999; + } + + if( (SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) { + SiS_Pr->PanelVRS = 999; + SiS_Pr->PanelVRE = 999; + } + + /* DontExpand overrule */ + if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (modeflag & NoSupportLCDScale)) { + /* No scaling for this mode on any panel (LCD=CRT2)*/ + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + + switch(SiS_Pr->SiS_LCDResInfo) { + + case Panel_Custom: + case Panel_1152x864: + case Panel_1280x768: /* TMDS only */ + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + break; + + case Panel_800x600: { + static const UCHAR nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, 0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1024x768: { + static const UCHAR nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + 0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1280x720: { + static const UCHAR nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + 0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + if(SiS_Pr->PanelHT == 1650) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + } + case Panel_1280x768_2: { /* LVDS only */ + static const UCHAR nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + switch(resinfo) { + case SIS_RI_1280x720: if(SiS_Pr->UsePanelScaler == -1) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + } + break; + } + case Panel_1280x800: { /* SiS TMDS special (Averatec 6200 series) */ + static const UCHAR nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1280x720,SIS_RI_1280x768,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1280x800_2: { /* SiS LVDS */ + static const UCHAR nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + switch(resinfo) { + case SIS_RI_1280x720: + case SIS_RI_1280x768: if(SiS_Pr->UsePanelScaler == -1) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + } + break; + } + case Panel_1280x960: { + static const UCHAR nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800, + 0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1280x1024: { + static const UCHAR nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800, + SIS_RI_1280x960,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1400x1050: { + static const UCHAR nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x768,SIS_RI_1280x800,SIS_RI_1280x960, + 0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + switch(resinfo) { + case SIS_RI_1280x720: if(SiS_Pr->UsePanelScaler == -1) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + case SIS_RI_1280x1024: SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + break; + } + break; + } + case Panel_1600x1200: { + static const UCHAR nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800, + SIS_RI_1280x960,SIS_RI_1360x768,SIS_RI_1360x1024,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1680x1050: { + static const UCHAR nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x960,SIS_RI_1360x768,SIS_RI_1360x1024, + 0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + } + } + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { + SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20; /* neg h/v sync, RGB24(D0 = 0) */ + } + } + +#ifdef SIS300 + if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(SiS_Pr->SiS_UseROM) { + if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { + if(!(ROMAddr[0x235] & 0x02)) { + SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD); + } + } + } + } else if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10))) { + SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD); + } + } + } +#endif + + /* Special cases */ + + if(modexres == SiS_Pr->PanelXRes && modeyres == SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } + + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + SiS_Pr->SiS_LCDInfo |= (DontExpandLCD | LCDPass11); + } + + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: + SiS_Pr->SiS_LCDInfo |= LCDPass11; + break; + case Panel_1280x800: + /* Don't pass 1:1 by default (TMDS special) */ + if(SiS_Pr->CenterScreen == -1) SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + break; + case Panel_1280x960: + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + break; + case Panel_Custom: + if((!SiS_Pr->CP_PrefClock) || + (modexres > SiS_Pr->PanelXRes) || (modeyres > SiS_Pr->PanelYRes)) { + SiS_Pr->SiS_LCDInfo |= LCDPass11; + } + break; + } + + if(SiS_Pr->UseCustomMode) { + SiS_Pr->SiS_LCDInfo |= (DontExpandLCD | LCDPass11); + } + + /* (In)validate LCDPass11 flag */ + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } + + /* LVDS DDA */ + if(!((HwInfo->jChipType < SIS_315H) && (SiS_Pr->SiS_SetFlag & SetDOSMode))) { + + if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_NoLCD)) { + if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) { + if(ModeNo == 0x12) { + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } + } else if(ModeNo > 0x13) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x600) { + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + if((resinfo == SIS_RI_800x600) || (resinfo == SIS_RI_400x300)) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } + } + } + } + } + } + + if(modeflag & HalfDCLK) { + if(SiS_Pr->SiS_IF_DEF_TRUMPION == 1) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(ModeNo > 0x13) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(resinfo == SIS_RI_512x384) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(SiS_Pr->SiS_LCDResInfo == Panel_800x600) { + if(resinfo == SIS_RI_400x300) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } + } + } + + } + + /* VESA timing */ + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_VBInfo & SetNotSimuMode) { + SiS_Pr->SiS_SetFlag |= LCDVESATiming; + } + } else { + SiS_Pr->SiS_SetFlag |= LCDVESATiming; + } + +#ifdef LINUX_KERNEL +#ifdef TWDEBUG + printk(KERN_DEBUG "sisfb: (LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x)\n", + SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo); +#endif +#endif +#ifdef LINUX_XF86 + xf86DrvMsgVerb(0, X_PROBED, 4, + "(init301: LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x SetFlag=0x%04x)\n", + SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo, SiS_Pr->SiS_SetFlag); +#endif +} + +/*********************************************/ +/* GET VCLK */ +/*********************************************/ + +USHORT +SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +{ + USHORT CRT2Index,VCLKIndex=0,VCLKIndexGEN=0; + USHORT modeflag,resinfo,tempbx; + const UCHAR *CHTVVCLKPtr = NULL; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + VCLKIndexGEN = (SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)) >> 2) & 0x03; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + CRT2Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + VCLKIndexGEN = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + if(HwInfo->jChipType < SIS_315H) VCLKIndexGEN &= 0x3f; + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { /* 30x/B/LV */ + + if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { + + CRT2Index >>= 6; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /* LCD */ + + if(HwInfo->jChipType < SIS_315H) { + VCLKIndex = SiS_Pr->PanelVCLKIdx300; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { + VCLKIndex = VCLKIndexGEN; + } + } else { + VCLKIndex = SiS_Pr->PanelVCLKIdx315; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { + switch(resinfo) { + /* Only those whose IndexGEN doesn't match VBVCLK array */ + case SIS_RI_1280x720: VCLKIndex = VCLK_1280x720; break; + case SIS_RI_720x480: VCLKIndex = VCLK_720x480; break; + case SIS_RI_720x576: VCLKIndex = VCLK_720x576; break; + case SIS_RI_768x576: VCLKIndex = VCLK_768x576; break; + case SIS_RI_848x480: VCLKIndex = VCLK_848x480; break; + case SIS_RI_856x480: VCLKIndex = VCLK_856x480; break; + case SIS_RI_800x480: VCLKIndex = VCLK_800x480; break; + case SIS_RI_1024x576: VCLKIndex = VCLK_1024x576; break; + case SIS_RI_1152x864: VCLKIndex = VCLK_1152x864; break; + case SIS_RI_1360x768: VCLKIndex = VCLK_1360x768; break; + default: VCLKIndex = VCLKIndexGEN; + } + + if(ModeNo <= 0x13) { + if(HwInfo->jChipType <= SIS_315PRO) { + if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x42; + } else { + if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x00; + } + } + if(HwInfo->jChipType <= SIS_315PRO) { + if(VCLKIndex == 0) VCLKIndex = 0x41; + if(VCLKIndex == 1) VCLKIndex = 0x43; + if(VCLKIndex == 4) VCLKIndex = 0x44; + } + } + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* TV */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = HiTVVCLKDIV2; + else VCLKIndex = HiTVVCLK; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + if(modeflag & Charx8Dot) VCLKIndex = HiTVSimuVCLK; + else VCLKIndex = HiTVTextVCLK; + } + } else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) VCLKIndex = YPbPr750pVCLK; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) VCLKIndex = TVVCLKDIV2; + else if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = TVVCLKDIV2; + else VCLKIndex = TVVCLK; + + if(HwInfo->jChipType < SIS_315H) VCLKIndex += TVCLKBASE_300; + else VCLKIndex += TVCLKBASE_315; + + } else { /* VGA2 */ + + VCLKIndex = VCLKIndexGEN; + if(HwInfo->jChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (HwInfo->jChipType == SIS_630) && + (HwInfo->jChipRevision >= 0x30)) { + if(VCLKIndex == 0x14) VCLKIndex = 0x34; + } + /* Better VGA2 clock for 1280x1024@75 */ + if(VCLKIndex == 0x17) VCLKIndex = 0x45; + } + } + } + + } else { /* If not programming CRT2 */ + + VCLKIndex = VCLKIndexGEN; + if(HwInfo->jChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (HwInfo->jChipType != SIS_630) && + (HwInfo->jChipType != SIS_300) ) { + if(VCLKIndex == 0x1b) VCLKIndex = 0x48; + } + } + } + } + + } else { /* LVDS */ + + VCLKIndex = CRT2Index; + + if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { + + if( (SiS_Pr->SiS_IF_DEF_CH70xx != 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) ) { + + VCLKIndex &= 0x1f; + tempbx = 0; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + tempbx += 2; + if(SiS_Pr->SiS_ModeType > ModeVGA) { + if(SiS_Pr->SiS_CHSOverScan) tempbx = 8; + } + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + tempbx = 4; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { + tempbx = 6; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + } + } + switch(tempbx) { + case 0: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUNTSC; break; + case 1: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKONTSC; break; + case 2: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPAL; break; + case 3: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPAL; break; + case 4: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPALM; break; + case 5: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPALM; break; + case 6: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPALN; break; + case 7: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPALN; break; + case 8: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKSOPAL; break; + default: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPAL; break; + } + VCLKIndex = CHTVVCLKPtr[VCLKIndex]; + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + + if(HwInfo->jChipType < SIS_315H) { + VCLKIndex = SiS_Pr->PanelVCLKIdx300; + } else { + VCLKIndex = SiS_Pr->PanelVCLKIdx315; + } + + /* Special Timing: Barco iQ Pro R series */ + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) VCLKIndex = 0x44; + + /* Special Timing: 848x480 parallel lvds */ + if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { + if(HwInfo->jChipType < SIS_315H) { + VCLKIndex = VCLK34_300; + /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */ + } else { + VCLKIndex = VCLK34_315; + /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */ + } + } + + } else { + + VCLKIndex = VCLKIndexGEN; + if(HwInfo->jChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (HwInfo->jChipType == SIS_630) && + (HwInfo->jChipRevision >= 0x30) ) { + if(VCLKIndex == 0x14) VCLKIndex = 0x2e; + } + } + } + } + + } else { /* if not programming CRT2 */ + + VCLKIndex = VCLKIndexGEN; + if(HwInfo->jChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (HwInfo->jChipType != SIS_630) && + (HwInfo->jChipType != SIS_300) ) { + if(VCLKIndex == 0x1b) VCLKIndex = 0x48; + } +#if 0 + if(HwInfo->jChipType == SIS_730) { + if(VCLKIndex == 0x0b) VCLKIndex = 0x40; /* 1024x768-70 */ + if(VCLKIndex == 0x0d) VCLKIndex = 0x41; /* 1024x768-75 */ + } +#endif + } + } + + } + + } + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "VCLKIndex %d (0x%x)\n", VCLKIndex, VCLKIndex); +#endif + + return(VCLKIndex); +} + +/*********************************************/ +/* SET CRT2 MODE TYPE REGISTERS */ +/*********************************************/ + +static void +SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo) +{ + USHORT i,j,modeflag; + USHORT tempcl,tempah=0; +#if defined(SIS300) || defined(SIS315H) + USHORT tempbl; +#endif +#ifdef SIS315H + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT tempah2, tempbl2; +#endif + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xAF,0x40); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2E,0xF7); + + } else { + + for(i=0,j=4; i<3; i++,j++) SiS_SetReg(SiS_Pr->SiS_Part1Port,j,0); + if(HwInfo->jChipType >= SIS_315H) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0x7F); + } + + tempcl = SiS_Pr->SiS_ModeType; + + if(HwInfo->jChipType < SIS_315H) { + +#ifdef SIS300 /* ---- 300 series ---- */ + + /* For 301BDH: (with LCD via LVDS) */ + if(SiS_Pr->SiS_VBType & VB_NoLCD) { + tempbl = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32); + tempbl &= 0xef; + tempbl |= 0x02; + if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) || (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + tempbl |= 0x10; + tempbl &= 0xfd; + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,tempbl); + } + + if(ModeNo > 0x13) { + tempcl -= ModeVGA; + if((tempcl > 0) || (tempcl == 0)) { /* tempcl is USHORT -> always true! */ + tempah = ((0x10 >> tempcl) | 0x80); + } + } else tempah = 0x80; + + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0xA0; + +#endif /* SIS300 */ + + } else { + +#ifdef SIS315H /* ------- 315/330 series ------ */ + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x08); + } + } + + if(ModeNo > 0x13) { + tempcl -= ModeVGA; + if((tempcl > 0) || (tempcl == 0)) { /* tempcl is USHORT -> always true! */ + tempah = (0x08 >> tempcl); + if (tempah == 0) tempah = 1; + tempah |= 0x40; + } + } else tempah = 0x40; + + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0x50; + +#endif /* SIS315H */ + + } + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0; + + if(HwInfo->jChipType < SIS_315H) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,tempah); + } else { + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah); + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(IS_SIS740) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,tempah); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah); + } + } + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + tempah = 0x01; + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + tempah |= 0x02; + } + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + tempah ^= 0x05; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + tempah ^= 0x01; + } + } + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0; + + if(HwInfo->jChipType < SIS_315H) { + + tempah = (tempah << 5) & 0xFF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,tempah); + tempah = (tempah >> 5) & 0xFF; + + } else { + + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2E,0xF8,tempah); + + } + + if((SiS_Pr->SiS_ModeType == ModeVGA) && (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) { + tempah |= 0x10; + } + + tempah |= 0x80; + if(SiS_Pr->SiS_VBType & VB_SIS301) { + if(SiS_Pr->PanelXRes < 1280 && SiS_Pr->PanelYRes < 960) tempah &= ~0x80; + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(!(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetYPbPr525p))) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + tempah |= 0x20; + } + } + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0D,0x40,tempah); + + tempah = 0x80; + if(SiS_Pr->SiS_VBType & VB_SIS301) { + if(SiS_Pr->PanelXRes < 1280 && SiS_Pr->PanelYRes < 960) tempah = 0; + } + + if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempah |= 0x40; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) { + tempah |= 0x40; + } + } + + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0C,tempah); + + } else { /* LVDS */ + + if(HwInfo->jChipType >= SIS_315H) { + +#ifdef SIS315H + /* LVDS can only be slave in 8bpp modes */ + tempah = 0x80; + if((modeflag & CRT2Mode) && (SiS_Pr->SiS_ModeType > ModeVGA)) { + if(SiS_Pr->SiS_VBInfo & DriverMode) { + tempah |= 0x02; + } + } + + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + tempah |= 0x02; + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + tempah ^= 0x01; + } + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) { + tempah = 1; + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2e,0xF0,tempah); +#endif + + } else { + +#ifdef SIS300 + tempah = 0; + if( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) && (SiS_Pr->SiS_ModeType > ModeVGA) ) { + tempah |= 0x02; + } + tempah <<= 5; + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0; + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,tempah); +#endif + + } + + } + + } /* LCDA */ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(HwInfo->jChipType >= SIS_315H) { + +#ifdef SIS315H + unsigned char bridgerev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); + + /* The following is nearly unpreditable and varies from machine + * to machine. Especially the 301DH seems to be a real trouble + * maker. Some BIOSes simply set the registers (like in the + * NoLCD-if-statements here), some set them according to the + * LCDA stuff. It is very likely that some machines are not + * treated correctly in the following, very case-orientated + * code. What do I do then...? + */ + + /* 740 variants match for 30xB, 301B-DH, 30xLV */ + + if(!(IS_SIS740)) { + tempah = 0x04; /* For all bridges */ + tempbl = 0xfb; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + tempah = 0x00; + if(SiS_IsDualEdge(SiS_Pr, HwInfo)) { + tempbl = 0xff; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah); + } + + /* The following two are responsible for eventually wrong colors + * in TV output. The DH (VB_NoLCD) conditions are unknown; the + * b0 was found in some 651 machine (Pim; P4_23=0xe5); the b1 version + * in a 650 box (Jake). What is the criteria? + */ + + if((IS_SIS740) || (HwInfo->jChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { + tempah = 0x30; + tempbl = 0xc0; + if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) || + ((SiS_Pr->SiS_ROMNew) && (!(ROMAddr[0x5b] & 0x04)))) { + tempah = 0x00; + tempbl = 0x00; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xcf,tempah); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0x3f,tempbl); + } else if(SiS_Pr->SiS_VBType & VB_SIS301) { + /* Fixes "TV-blue-bug" on 315+301 */ + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2c,0xcf); /* For 301 */ + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f); + } else if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30); /* For 30xLV */ + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x21,0xc0); + } else if((SiS_Pr->SiS_VBType & VB_NoLCD) && (bridgerev == 0xb0)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30); /* For 30xB-DH rev b0 (or "DH on 651"?) */ + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x21,0xc0); + } else { + tempah = 0x30; tempah2 = 0xc0; /* For 30xB (and 301BDH rev b1) */ + tempbl = 0xcf; tempbl2 = 0x3f; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + tempah = tempah2 = 0x00; + if(SiS_IsDualEdge(SiS_Pr, HwInfo)) { + tempbl = tempbl2 = 0xff; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,tempbl,tempah); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,tempbl2,tempah2); + } + + if(IS_SIS740) { + tempah = 0x80; + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0x00; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,0x7f,tempah); + } else { + tempah = 0x00; + tempbl = 0x7f; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + tempbl = 0xff; + if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) tempah = 0x80; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah); + } + +#endif /* SIS315H */ + + } else if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + +#ifdef SIS300 + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f); + + if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) || + ((SiS_Pr->SiS_VBType & VB_NoLCD) && + (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD))) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x23,0x7F); + } else { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x23,0x80); + } +#endif + + } + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x0D,0x80); + if(SiS_Pr->SiS_VBType & VB_SIS301C) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3A,0xC0); + } + } + + } else { /* LVDS */ + +#ifdef SIS315H + if(HwInfo->jChipType >= SIS_315H) { + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + + tempah = 0x04; + tempbl = 0xfb; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + tempah = 0x00; + if(SiS_IsDualEdge(SiS_Pr, HwInfo)) tempbl = 0xff; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah); + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); + } + + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30); + + } else if(HwInfo->jChipType == SIS_550) { + + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30); + + } + + } +#endif + + } + +} + +/*********************************************/ +/* GET RESOLUTION DATA */ +/*********************************************/ + +USHORT +SiS_GetResInfo(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex) +{ + if(ModeNo <= 0x13) return((USHORT)SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo); + else return((USHORT)SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO); +} + +static void +SiS_GetCRT2ResInfo(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo) +{ + USHORT xres,yres,modeflag=0,resindex; + + if(SiS_Pr->UseCustomMode) { + xres = SiS_Pr->CHDisplay; + if(SiS_Pr->CModeFlag & HalfDCLK) xres *= 2; + SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres; + yres = SiS_Pr->CVDisplay; + if(SiS_Pr->CModeFlag & DoubleScanMode) yres *= 2; + SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres; + return; + } + + resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex); + + if(ModeNo <= 0x13) { + xres = SiS_Pr->SiS_StResInfo[resindex].HTotal; + yres = SiS_Pr->SiS_StResInfo[resindex].VTotal; + } else { + xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal; + yres = SiS_Pr->SiS_ModeResInfo[resindex].VTotal; + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + if(!SiS_Pr->SiS_IF_DEF_DSTN && !SiS_Pr->SiS_IF_DEF_FSTN) { + + if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 1)) { + if((ModeNo != 0x03) && (SiS_Pr->SiS_SetFlag & SetDOSMode)) { + if(yres == 350) yres = 400; + } + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x3a) & 0x01) { + if(ModeNo == 0x12) yres = 400; + } + } + + if(modeflag & HalfDCLK) xres *= 2; + if(modeflag & DoubleScanMode) yres *= 2; + + } + + if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + +#if 0 + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCDA | SetCRT2ToLCD | SetCRT2ToHiVision)) { + if(xres == 720) xres = 640; + } +#endif + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_1024x768: + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + if(yres == 350) yres = 357; + if(yres == 400) yres = 420; + if(yres == 480) yres = 525; + } + } + break; + case Panel_1280x1024: + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + /* BIOS bug - does this regardless of scaling */ + if(yres == 400) yres = 405; + } + if(yres == 350) yres = 360; + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + if(yres == 360) yres = 375; + } + break; + case Panel_1600x1200: + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + if(yres == 1024) yres = 1056; + } + break; + } + } + + } else { + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVision)) { + if(xres == 720) xres = 640; + } + } else if(xres == 720) xres = 640; + + if(SiS_Pr->SiS_SetFlag & SetDOSMode) { + yres = 400; + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480; + } else { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480; + } + if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) yres = 480; + } + + } + SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres; + SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres; +} + +/*********************************************/ +/* GET CRT2 TIMING DATA */ +/*********************************************/ + +static BOOLEAN +SiS_GetLVDSCRT1Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT *ResIndex, + USHORT *DisplayType) + { + USHORT modeflag=0; + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return FALSE; + } + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return FALSE; + } else + return FALSE; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + (*ResIndex) &= 0x3F; + + if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + (*DisplayType) = 18; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + (*DisplayType) += 2; + if(SiS_Pr->SiS_ModeType > ModeVGA) { + if(SiS_Pr->SiS_CHSOverScan) (*DisplayType) = 99; + } + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + (*DisplayType) = 18; /* PALM uses NTSC data */ + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++; + } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { + (*DisplayType) = 20; /* PALN uses PAL data */ + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++; + } + } + } else { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: (*DisplayType) = 50; break; + case Panel_640x480_2: (*DisplayType) = 52; break; + case Panel_640x480_3: (*DisplayType) = 54; break; + case Panel_800x600: (*DisplayType) = 0; break; + case Panel_1024x600: (*DisplayType) = 23; break; + case Panel_1024x768: (*DisplayType) = 4; break; + case Panel_1152x768: (*DisplayType) = 27; break; + case Panel_1280x768: (*DisplayType) = 40; break; + case Panel_1280x1024: (*DisplayType) = 8; break; + case Panel_1400x1050: (*DisplayType) = 14; break; + case Panel_1600x1200: (*DisplayType) = 36; break; + default: return FALSE; + } + + if(modeflag & HalfDCLK) (*DisplayType)++; + + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: + case Panel_640x480_2: + case Panel_640x480_3: + break; + default: + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) (*DisplayType) += 2; + } + + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + (*DisplayType) = 12; + if(modeflag & HalfDCLK) (*DisplayType)++; + } + } + +#if 0 + if(SiS_Pr->SiS_IF_DEF_FSTN) { + if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480){ + (*DisplayType) = 22; + } + } +#endif + + return TRUE; +} + +static void +SiS_GetCRT2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, + USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex, + PSIS_HW_INFO HwInfo) +{ + USHORT tempbx=0,tempal=0,resinfo=0; + + if(ModeNo <= 0x13) { + tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) { + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { /* LCD */ + + tempbx = SiS_Pr->SiS_LCDResInfo; + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx += 32; + + if(SiS_Pr->SiS_LCDResInfo == Panel_1680x1050) { + if (resinfo == SIS_RI_1280x800) tempal = 9; + else if(resinfo == SIS_RI_1400x1050) tempal = 11; + } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x800) || + (SiS_Pr->SiS_LCDResInfo == Panel_1280x800_2)) { + if (resinfo == SIS_RI_1280x768) tempal = 9; + } + + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + /* Pass 1:1 only (center-screen handled outside) */ + /* This is never called for the panel's native resolution */ + /* since Pass1:1 will not be set in this case */ + tempbx = 100; + if(ModeNo >= 0x13) { + tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC_NS; + } + } + +#ifdef SIS315H + if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + tempbx = 200; + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx++; + } + } + } +#endif + + } else { /* TV */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + /* if(SiS_Pr->SiS_VGAVDE > 480) SiS_Pr->SiS_TVMode &= (~TVSetTVSimuMode); */ + tempbx = 2; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + tempbx = 13; + if(!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) tempbx = 14; + } + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempbx = 7; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) tempbx = 6; + else tempbx = 5; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) tempbx += 5; + } else { + if(SiS_Pr->SiS_TVMode & TVSetPAL) tempbx = 3; + else tempbx = 4; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) tempbx += 5; + } + + } + + tempal &= 0x3F; + + if(ModeNo > 0x13) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision) { + if(tempal == 6) tempal = 7; + if((resinfo == SIS_RI_720x480) || + (resinfo == SIS_RI_720x576) || + (resinfo == SIS_RI_768x576)) { + tempal = 6; + if(SiS_Pr->SiS_TVMode & (TVSetPAL | TVSetPALN)) { + if(resinfo == SIS_RI_720x480) tempal = 9; + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { + if(resinfo == SIS_RI_1024x768) tempal = 8; + } + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + if((resinfo == SIS_RI_720x576) || + (resinfo == SIS_RI_768x576)) { + tempal = 8; + } + if(resinfo == SIS_RI_1280x720) tempal = 9; + } + } + } + } + + *CRT2Index = tempbx; + *ResIndex = tempal; + + } else { /* LVDS, 301B-DH (if running on LCD) */ + + tempbx = 0; + if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + + tempbx = 10; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + tempbx += 2; + if(SiS_Pr->SiS_ModeType > ModeVGA) { + if(SiS_Pr->SiS_CHSOverScan) tempbx = 99; + } + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + tempbx = 90; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { + tempbx = 92; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + } + } + + } else { + + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: tempbx = 6; break; + case Panel_640x480_2: + case Panel_640x480_3: tempbx = 30; break; + case Panel_800x600: tempbx = 0; break; + case Panel_1024x600: tempbx = 15; break; + case Panel_1024x768: tempbx = 2; break; + case Panel_1152x768: tempbx = 17; break; + case Panel_1280x768: tempbx = 18; break; + case Panel_1280x1024: tempbx = 4; break; + case Panel_1400x1050: tempbx = 8; break; + case Panel_1600x1200: tempbx = 21; break; + case Panel_Barco1366: tempbx = 80; break; + } + + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: + case Panel_640x480_2: + case Panel_640x480_3: + break; + default: + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + } + + if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempbx = 7; + + if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { + tempbx = 82; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + } else if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { + tempbx = 84; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + } + + if((SiS_Pr->SiS_CustomT != CUT_BARCO1366) && + (SiS_Pr->SiS_CustomT != CUT_PANEL848)) { + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && + (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + tempal = 0; + } + } + + } + + (*CRT2Index) = tempbx; + (*ResIndex) = tempal & 0x1F; + } +} + +static void +SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, + USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo) +{ + USHORT tempax=0,tempbx=0; + USHORT temp1=0,modeflag=0,tempcx=0; + USHORT index; + + SiS_Pr->SiS_RVBHCMAX = 1; + SiS_Pr->SiS_RVBHCFACT = 1; + + if(ModeNo <= 0x13) { + + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + index = SiS_GetModePtr(SiS_Pr,ModeNo,ModeIdIndex); + + tempax = SiS_Pr->SiS_StandTable[index].CRTC[0]; + tempbx = SiS_Pr->SiS_StandTable[index].CRTC[6]; + temp1 = SiS_Pr->SiS_StandTable[index].CRTC[7]; + + } else { + + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + + tempax = SiS_Pr->SiS_CRT1Table[index].CR[0]; + tempax |= (SiS_Pr->SiS_CRT1Table[index].CR[14] << 8); + tempax &= 0x03FF; + tempbx = SiS_Pr->SiS_CRT1Table[index].CR[6]; + tempcx = SiS_Pr->SiS_CRT1Table[index].CR[13] << 8; + tempcx &= 0x0100; + tempcx <<= 2; + tempbx |= tempcx; + temp1 = SiS_Pr->SiS_CRT1Table[index].CR[7]; + + } + + if(temp1 & 0x01) tempbx |= 0x0100; + if(temp1 & 0x20) tempbx |= 0x0200; + + tempax += 5; + + /* Charx8Dot is no more used (and assumed), so we set it */ + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + modeflag |= Charx8Dot; + } + + if(modeflag & Charx8Dot) tempax *= 8; + else tempax *= 9; + + if(modeflag & HalfDCLK) tempax <<= 1; + + tempbx++; + + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = tempax; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = tempbx; +} + +static void +SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +{ + USHORT CRT2Index, ResIndex; + const SiS_LVDSDataStruct *LVDSData = NULL; + + SiS_GetCRT2ResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + SiS_Pr->SiS_RVBHCMAX = 1; + SiS_Pr->SiS_RVBHCFACT = 1; + SiS_Pr->SiS_NewFlickerMode = 0; + SiS_Pr->SiS_RVBHRS = 50; + SiS_Pr->SiS_RY1COE = 0; + SiS_Pr->SiS_RY2COE = 0; + SiS_Pr->SiS_RY3COE = 0; + SiS_Pr->SiS_RY4COE = 0; + } + + if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + +#ifdef SIS315H + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + if(SiS_Pr->UseCustomMode) { + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = SiS_Pr->CHTotal; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->CVTotal; + } else { + if(ModeNo < 0x13) { + ResIndex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + ResIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC_NS; + } + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAVT; + SiS_Pr->SiS_HT = SiS_Pr->SiS_NoScaleData[ResIndex].LCDHT; + SiS_Pr->SiS_VT = SiS_Pr->SiS_NoScaleData[ResIndex].LCDVT; + } + } else { + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + } + } else { + /* This handles custom modes and custom panels */ + SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; + SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; + SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT - (SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE); + SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT - (SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE); + } + + SiS_CalcLCDACRT1Timing(SiS_Pr,ModeNo,ModeIdIndex); + +#endif + + } else { + + /* 301BDH needs LVDS Data */ + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + SiS_Pr->SiS_IF_DEF_LVDS = 1; + } + + SiS_GetCRT2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, + &CRT2Index, &ResIndex, HwInfo); + + /* 301BDH needs LVDS Data */ + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + SiS_Pr->SiS_IF_DEF_LVDS = 0; + } + + switch (CRT2Index) { + case 0: LVDSData = SiS_Pr->SiS_LVDS800x600Data_1; break; + case 1: LVDSData = SiS_Pr->SiS_LVDS800x600Data_2; break; + case 2: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break; + case 3: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_2; break; + case 4: LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_1; break; + case 5: LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_2; break; + case 6: LVDSData = SiS_Pr->SiS_LVDS640x480Data_1; break; + case 7: LVDSData = SiS_Pr->SiS_LVDSXXXxXXXData_1; break; + case 8: LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_1; break; + case 9: LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_2; break; + case 10: LVDSData = SiS_Pr->SiS_CHTVUNTSCData; break; + case 11: LVDSData = SiS_Pr->SiS_CHTVONTSCData; break; + case 12: LVDSData = SiS_Pr->SiS_CHTVUPALData; break; + case 13: LVDSData = SiS_Pr->SiS_CHTVOPALData; break; + case 14: LVDSData = SiS_Pr->SiS_LVDS320x480Data_1; break; + case 15: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1; break; + case 16: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_2; break; + case 17: LVDSData = SiS_Pr->SiS_LVDS1152x768Data_1; break; + case 18: LVDSData = SiS_Pr->SiS_LVDS1152x768Data_2; break; + case 19: LVDSData = SiS_Pr->SiS_LVDS1280x768Data_1; break; + case 20: LVDSData = SiS_Pr->SiS_LVDS1280x768Data_2; break; + case 21: LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_1; break; + case 22: LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_2; break; + case 30: LVDSData = SiS_Pr->SiS_LVDS640x480Data_2; break; + case 80: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_1; break; + case 81: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_2; break; + case 82: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_1; break; + case 83: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_2; break; + case 84: LVDSData = SiS_Pr->SiS_LVDS848x480Data_1; break; + case 85: LVDSData = SiS_Pr->SiS_LVDS848x480Data_2; break; + case 90: LVDSData = SiS_Pr->SiS_CHTVUPALMData; break; + case 91: LVDSData = SiS_Pr->SiS_CHTVOPALMData; break; + case 92: LVDSData = SiS_Pr->SiS_CHTVUPALNData; break; + case 93: LVDSData = SiS_Pr->SiS_CHTVOPALNData; break; + case 99: LVDSData = SiS_Pr->SiS_CHTVSOPALData; break; /* Super Overscan */ + default: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break; + } + + SiS_Pr->SiS_VGAHT = (LVDSData+ResIndex)->VGAHT; + SiS_Pr->SiS_VGAVT = (LVDSData+ResIndex)->VGAVT; + SiS_Pr->SiS_HT = (LVDSData+ResIndex)->LCDHT; + SiS_Pr->SiS_VT = (LVDSData+ResIndex)->LCDVT; + + if(!(SiS_Pr->SiS_VBType & VB_SISVB)) { + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (SiS_Pr->SiS_SetFlag & SetDOSMode)) { + SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; + SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { + if(ResIndex < 0x08) { + SiS_Pr->SiS_HDE = 1280; + SiS_Pr->SiS_VDE = 1024; + } + } + } + } + } + } +} + +static void +SiS_GetCRT2Data301(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = NULL; + USHORT tempax,tempbx,modeflag,romptr=0; + USHORT resinfo,CRT2Index,ResIndex; + const SiS_LCDDataStruct *LCDPtr = NULL; + const SiS_TVDataStruct *TVPtr = NULL; +#ifdef SIS315H + SHORT resinfo661; +#endif + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + resinfo = 0; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; +#ifdef SIS315H + resinfo661 = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].ROMMODEIDX661; + if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && + (SiS_Pr->SiS_SetFlag & LCDVESATiming) && + (resinfo661 >= 0) && + (SiS_Pr->SiS_NeedRomModeData) ) { + if((ROMAddr = GetLCDStructPtr661(SiS_Pr, HwInfo))) { + if((romptr = (SISGETROMW(21)))) { + romptr += (resinfo661 * 10); + ROMAddr = HwInfo->pjVirtualRomBase; + } + } + } +#endif + } + + SiS_Pr->SiS_NewFlickerMode = 0; + SiS_Pr->SiS_RVBHRS = 50; + SiS_Pr->SiS_RY1COE = 0; + SiS_Pr->SiS_RY2COE = 0; + SiS_Pr->SiS_RY3COE = 0; + SiS_Pr->SiS_RY4COE = 0; + + SiS_GetCRT2ResInfo(SiS_Pr,ModeNo,ModeIdIndex,HwInfo); + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){ + + if(SiS_Pr->UseCustomMode) { + + SiS_Pr->SiS_RVBHCMAX = 1; + SiS_Pr->SiS_RVBHCFACT = 1; + SiS_Pr->SiS_VGAHT = SiS_Pr->CHTotal; + SiS_Pr->SiS_VGAVT = SiS_Pr->CVTotal; + SiS_Pr->SiS_HT = SiS_Pr->CHTotal; + SiS_Pr->SiS_VT = SiS_Pr->CVTotal; + SiS_Pr->SiS_HDE = SiS_Pr->SiS_VGAHDE; + SiS_Pr->SiS_VDE = SiS_Pr->SiS_VGAVDE; + + } else { + + SiS_GetRAMDAC2DATA(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + + SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex, + &CRT2Index,&ResIndex,HwInfo); + + switch(CRT2Index) { + case 2: TVPtr = SiS_Pr->SiS_ExtHiTVData; break; + case 3: TVPtr = SiS_Pr->SiS_ExtPALData; break; + case 4: TVPtr = SiS_Pr->SiS_ExtNTSCData; break; + case 5: TVPtr = SiS_Pr->SiS_Ext525iData; break; + case 6: TVPtr = SiS_Pr->SiS_Ext525pData; break; + case 7: TVPtr = SiS_Pr->SiS_Ext750pData; break; + case 8: TVPtr = SiS_Pr->SiS_StPALData; break; + case 9: TVPtr = SiS_Pr->SiS_StNTSCData; break; + case 10: TVPtr = SiS_Pr->SiS_St525iData; break; + case 11: TVPtr = SiS_Pr->SiS_St525pData; break; + case 12: TVPtr = SiS_Pr->SiS_St750pData; break; + case 13: TVPtr = SiS_Pr->SiS_St1HiTVData; break; + case 14: TVPtr = SiS_Pr->SiS_St2HiTVData; break; + default: TVPtr = SiS_Pr->SiS_StPALData; break; + } + + SiS_Pr->SiS_RVBHCMAX = (TVPtr+ResIndex)->RVBHCMAX; + SiS_Pr->SiS_RVBHCFACT = (TVPtr+ResIndex)->RVBHCFACT; + SiS_Pr->SiS_VGAHT = (TVPtr+ResIndex)->VGAHT; + SiS_Pr->SiS_VGAVT = (TVPtr+ResIndex)->VGAVT; + SiS_Pr->SiS_HDE = (TVPtr+ResIndex)->TVHDE; + SiS_Pr->SiS_VDE = (TVPtr+ResIndex)->TVVDE; + SiS_Pr->SiS_RVBHRS = (TVPtr+ResIndex)->RVBHRS; + SiS_Pr->SiS_NewFlickerMode = (TVPtr+ResIndex)->FlickerMode; + if(modeflag & HalfDCLK) { + SiS_Pr->SiS_RVBHRS = (TVPtr+ResIndex)->HALFRVBHRS; + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + + if((resinfo == SIS_RI_1024x768) || + (resinfo == SIS_RI_1280x1024) || + (resinfo == SIS_RI_1280x720)) { + SiS_Pr->SiS_NewFlickerMode = 0x40; + } + + if(SiS_Pr->SiS_VGAVDE == 350) SiS_Pr->SiS_TVMode |= TVSetTVSimuMode; + + SiS_Pr->SiS_HT = ExtHiTVHT; + SiS_Pr->SiS_VT = ExtHiTVVT; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + SiS_Pr->SiS_HT = StHiTVHT; + SiS_Pr->SiS_VT = StHiTVVT; +#if 0 + if(!(modeflag & Charx8Dot)) { + SiS_Pr->SiS_HT = StHiTextTVHT; + SiS_Pr->SiS_VT = StHiTextTVVT; + } +#endif + } + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + SiS_Pr->SiS_HT = 1650; + SiS_Pr->SiS_VT = 750; + } else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { + SiS_Pr->SiS_HT = NTSCHT; + SiS_Pr->SiS_VT = NTSCVT; + } else { + SiS_Pr->SiS_HT = NTSCHT; + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) SiS_Pr->SiS_HT = NTSC2HT; + SiS_Pr->SiS_VT = NTSCVT; + } + + } else { + + SiS_Pr->SiS_RY1COE = (TVPtr+ResIndex)->RY1COE; + SiS_Pr->SiS_RY2COE = (TVPtr+ResIndex)->RY2COE; + SiS_Pr->SiS_RY3COE = (TVPtr+ResIndex)->RY3COE; + SiS_Pr->SiS_RY4COE = (TVPtr+ResIndex)->RY4COE; + + if(modeflag & HalfDCLK) { + SiS_Pr->SiS_RY1COE = 0x00; + SiS_Pr->SiS_RY2COE = 0xf4; + SiS_Pr->SiS_RY3COE = 0x10; + SiS_Pr->SiS_RY4COE = 0x38; + } + + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + SiS_Pr->SiS_HT = NTSCHT; + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) SiS_Pr->SiS_HT = NTSC2HT; + SiS_Pr->SiS_VT = NTSCVT; + } else { + SiS_Pr->SiS_HT = PALHT; + SiS_Pr->SiS_VT = PALVT; + } + + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + + SiS_Pr->SiS_RVBHCMAX = 1; + SiS_Pr->SiS_RVBHCFACT = 1; + + if(SiS_Pr->UseCustomMode) { + + SiS_Pr->SiS_VGAHT = SiS_Pr->CHTotal; + SiS_Pr->SiS_VGAVT = SiS_Pr->CVTotal; + SiS_Pr->SiS_HT = SiS_Pr->CHTotal; + SiS_Pr->SiS_VT = SiS_Pr->CVTotal; + SiS_Pr->SiS_HDE = SiS_Pr->SiS_VGAHDE; + SiS_Pr->SiS_VDE = SiS_Pr->SiS_VGAVDE; + + } else { + + BOOLEAN gotit = FALSE; + + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + + SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT; + SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + gotit = TRUE; + + } else if( (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) && (romptr) && (ROMAddr) ) { + +#ifdef SIS315H + SiS_Pr->SiS_RVBHCMAX = ROMAddr[romptr]; + SiS_Pr->SiS_RVBHCFACT = ROMAddr[romptr+1]; + SiS_Pr->SiS_VGAHT = ROMAddr[romptr+2] | ((ROMAddr[romptr+3] & 0x0f) << 8); + SiS_Pr->SiS_VGAVT = ROMAddr[romptr+4] | ((ROMAddr[romptr+3] & 0xf0) << 4); + SiS_Pr->SiS_HT = ROMAddr[romptr+5] | ((ROMAddr[romptr+6] & 0x0f) << 8); + SiS_Pr->SiS_VT = ROMAddr[romptr+7] | ((ROMAddr[romptr+6] & 0xf0) << 4); + if(SiS_Pr->SiS_VGAHT) gotit = TRUE; + else { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT; + SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + gotit = TRUE; + } +#endif + + } + + if(!gotit) { + + SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex, + &CRT2Index,&ResIndex,HwInfo); + + switch(CRT2Index) { + case Panel_1024x768 : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break; + case Panel_1024x768 + 32: LCDPtr = SiS_Pr->SiS_St2LCD1024x768Data; break; + case Panel_1280x720 : + case Panel_1280x720 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x720Data; break; + case Panel_1280x768_2 : LCDPtr = SiS_Pr->SiS_ExtLCD1280x768_2Data; break; + case Panel_1280x768_2+ 32: LCDPtr = SiS_Pr->SiS_StLCD1280x768_2Data; break; + case Panel_1280x800 : + case Panel_1280x800 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x800Data; break; + case Panel_1280x800_2 : + case Panel_1280x800_2+ 32: LCDPtr = SiS_Pr->SiS_LCD1280x800_2Data; break; + case Panel_1280x960 : + case Panel_1280x960 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x960Data; break; + case Panel_1280x1024 : LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data; break; + case Panel_1280x1024 + 32: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break; + case Panel_1400x1050 : LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data; break; + case Panel_1400x1050 + 32: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data; break; + case Panel_1600x1200 : LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data; break; + case Panel_1600x1200 + 32: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data; break; + case Panel_1680x1050 : + case Panel_1680x1050 + 32: LCDPtr = SiS_Pr->SiS_LCD1680x1050Data; break; + case 100 : LCDPtr = SiS_Pr->SiS_NoScaleData; break; +#ifdef SIS315H + case 200 : LCDPtr = SiS310_ExtCompaq1280x1024Data; break; + case 201 : LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break; +#endif + default : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break; + } + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex); +#endif + + SiS_Pr->SiS_RVBHCMAX = (LCDPtr+ResIndex)->RVBHCMAX; + SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT; + SiS_Pr->SiS_VGAHT = (LCDPtr+ResIndex)->VGAHT; + SiS_Pr->SiS_VGAVT = (LCDPtr+ResIndex)->VGAVT; + SiS_Pr->SiS_HT = (LCDPtr+ResIndex)->LCDHT; + SiS_Pr->SiS_VT = (LCDPtr+ResIndex)->LCDVT; + + } + + tempax = SiS_Pr->PanelXRes; + tempbx = SiS_Pr->PanelYRes; + + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + if(HwInfo->jChipType < SIS_315H) { + if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 560; + else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640; + } + } else { + if (SiS_Pr->SiS_VGAVDE == 357) tempbx = 527; + else if(SiS_Pr->SiS_VGAVDE == 420) tempbx = 620; + else if(SiS_Pr->SiS_VGAVDE == 525) tempbx = 775; + else if(SiS_Pr->SiS_VGAVDE == 600) tempbx = 775; + else if(SiS_Pr->SiS_VGAVDE == 350) tempbx = 560; + else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640; + } + } else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x960) { + if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 700; + else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 800; + else if(SiS_Pr->SiS_VGAVDE == 1024) tempbx = 960; + } else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if (SiS_Pr->SiS_VGAVDE == 360) tempbx = 768; + else if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 800; + else if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 864; + } else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) { + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 875; + else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 1000; + } + } + + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax = SiS_Pr->SiS_VGAHDE; + tempbx = SiS_Pr->SiS_VGAVDE; + } + + SiS_Pr->SiS_HDE = tempax; + SiS_Pr->SiS_VDE = tempbx; + } + } +} + +static void +SiS_GetCRT2Data(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +{ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + } else { + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + /* Need LVDS Data for LCD on 301B-DH */ + SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + } else { + SiS_GetCRT2Data301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + } + } + + } else { + + SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + + } +} + +/*********************************************/ +/* GET LVDS DES (SKEW) DATA */ +/*********************************************/ + +static void +SiS_GetLVDSDesPtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT *PanelIndex, + USHORT *ResIndex, PSIS_HW_INFO HwInfo) +{ + USHORT modeflag; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + (*ResIndex) &= 0x1F; + (*PanelIndex) = 0; + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + (*PanelIndex) = 50; + if((SiS_Pr->SiS_TVMode & TVSetPAL) && (!(SiS_Pr->SiS_TVMode & TVSetPALM))) (*PanelIndex) += 2; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*PanelIndex) += 1; + /* Nothing special needed for SOverscan */ + /* PALM uses NTSC data, PALN uses PAL data */ + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + *PanelIndex = SiS_Pr->SiS_LCDTypeInfo; + if(HwInfo->jChipType >= SIS_661) { + /* As long as we don's use the BIOS tables, we + * need to convert the TypeInfo as for 315 series + */ + (*PanelIndex) = SiS_Pr->SiS_LCDResInfo - 1; + } + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + (*PanelIndex) += 16; + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + (*PanelIndex) = 32; + if(modeflag & HalfDCLK) (*PanelIndex)++; + } + } + } + + if(SiS_Pr->SiS_SetFlag & SetDOSMode) { + if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) { + (*ResIndex) = 7; + if(HwInfo->jChipType < SIS_315H) { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) (*ResIndex)++; + } + } + } +} + +static void +SiS_GetLVDSDesData(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +{ + USHORT modeflag; + USHORT PanelIndex,ResIndex; + const SiS_LVDSDesStruct *PanelDesPtr = NULL; + + SiS_Pr->SiS_LCDHDES = 0; + SiS_Pr->SiS_LCDVDES = 0; + + if( (SiS_Pr->UseCustomMode) || + (SiS_Pr->SiS_LCDResInfo == Panel_Custom) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) || + ((SiS_Pr->SiS_VBType & VB_SISVB) && + (SiS_Pr->SiS_LCDInfo & DontExpandLCD) && + (SiS_Pr->SiS_LCDInfo & LCDPass11)) ) { + return; + } + + if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + +#ifdef SIS315H + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + /* non-pass 1:1 only, see above */ + if(SiS_Pr->SiS_VGAHDE != SiS_Pr->PanelXRes) { + SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE) / 2); + } + if(SiS_Pr->SiS_VGAVDE != SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE) / 2); + } + } + if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { + switch(SiS_Pr->SiS_CustomT) { + case CUT_UNIWILL1024: + case CUT_UNIWILL10242: + case CUT_CLEVO1400: + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } + break; + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } + } + } +#endif + + } else { + + SiS_GetLVDSDesPtr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, + &PanelIndex, &ResIndex, HwInfo); + + switch(PanelIndex) { + case 0: PanelDesPtr = SiS_Pr->SiS_PanelType00_1; break; /* --- */ + case 1: PanelDesPtr = SiS_Pr->SiS_PanelType01_1; break; + case 2: PanelDesPtr = SiS_Pr->SiS_PanelType02_1; break; + case 3: PanelDesPtr = SiS_Pr->SiS_PanelType03_1; break; + case 4: PanelDesPtr = SiS_Pr->SiS_PanelType04_1; break; + case 5: PanelDesPtr = SiS_Pr->SiS_PanelType05_1; break; + case 6: PanelDesPtr = SiS_Pr->SiS_PanelType06_1; break; + case 7: PanelDesPtr = SiS_Pr->SiS_PanelType07_1; break; + case 8: PanelDesPtr = SiS_Pr->SiS_PanelType08_1; break; + case 9: PanelDesPtr = SiS_Pr->SiS_PanelType09_1; break; + case 10: PanelDesPtr = SiS_Pr->SiS_PanelType0a_1; break; + case 11: PanelDesPtr = SiS_Pr->SiS_PanelType0b_1; break; + case 12: PanelDesPtr = SiS_Pr->SiS_PanelType0c_1; break; + case 13: PanelDesPtr = SiS_Pr->SiS_PanelType0d_1; break; + case 14: PanelDesPtr = SiS_Pr->SiS_PanelType0e_1; break; + case 15: PanelDesPtr = SiS_Pr->SiS_PanelType0f_1; break; + case 16: PanelDesPtr = SiS_Pr->SiS_PanelType00_2; break; /* --- */ + case 17: PanelDesPtr = SiS_Pr->SiS_PanelType01_2; break; + case 18: PanelDesPtr = SiS_Pr->SiS_PanelType02_2; break; + case 19: PanelDesPtr = SiS_Pr->SiS_PanelType03_2; break; + case 20: PanelDesPtr = SiS_Pr->SiS_PanelType04_2; break; + case 21: PanelDesPtr = SiS_Pr->SiS_PanelType05_2; break; + case 22: PanelDesPtr = SiS_Pr->SiS_PanelType06_2; break; + case 23: PanelDesPtr = SiS_Pr->SiS_PanelType07_2; break; + case 24: PanelDesPtr = SiS_Pr->SiS_PanelType08_2; break; + case 25: PanelDesPtr = SiS_Pr->SiS_PanelType09_2; break; + case 26: PanelDesPtr = SiS_Pr->SiS_PanelType0a_2; break; + case 27: PanelDesPtr = SiS_Pr->SiS_PanelType0b_2; break; + case 28: PanelDesPtr = SiS_Pr->SiS_PanelType0c_2; break; + case 29: PanelDesPtr = SiS_Pr->SiS_PanelType0d_2; break; + case 30: PanelDesPtr = SiS_Pr->SiS_PanelType0e_2; break; + case 31: PanelDesPtr = SiS_Pr->SiS_PanelType0f_2; break; + case 32: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_1; break; /* pass 1:1 */ + case 33: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_2; break; + case 50: PanelDesPtr = SiS_Pr->SiS_CHTVUNTSCDesData; break; /* TV */ + case 51: PanelDesPtr = SiS_Pr->SiS_CHTVONTSCDesData; break; + case 52: PanelDesPtr = SiS_Pr->SiS_CHTVUPALDesData; break; + case 53: PanelDesPtr = SiS_Pr->SiS_CHTVOPALDesData; break; + default: return; + } + + SiS_Pr->SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES; + SiS_Pr->SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES; + + if((ModeNo <= 0x13) && (SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 632; + } else if(!(SiS_Pr->SiS_SetFlag & SetDOSMode)) { + if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) { + if(SiS_Pr->SiS_LCDResInfo >= Panel_1024x768) { + if(HwInfo->jChipType < SIS_315H) { + if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 320; + } else { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) SiS_Pr->SiS_LCDHDES = 480; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 804; + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 704; + if(!(modeflag & HalfDCLK)) { + SiS_Pr->SiS_LCDHDES = 320; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 632; + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 542; + } + } + } + } + } + } + } +} + +/*********************************************/ +/* DISABLE VIDEO BRIDGE */ +/*********************************************/ + +/* NEVER use any variables (VBInfo), this will be called + * from outside the context of modeswitch! + * MUST call getVBType before calling this + */ +void +SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ +#ifdef SIS315H + USHORT tempah,pushax=0,modenum; +#endif + USHORT temp=0; + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { /* ===== For 30xB/LV ===== */ + + if(HwInfo->jChipType < SIS_315H) { + +#ifdef SIS300 /* 300 series */ + + if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE); + } else { + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); + } + SiS_PanelDelay(SiS_Pr, HwInfo, 3); + } + if(SiS_Is301B(SiS_Pr)) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0x3f); + SiS_ShortDelay(SiS_Pr,1); + } + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF); + SiS_DisplayOff(SiS_Pr); + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); + SiS_UnLockCRT2(SiS_Pr,HwInfo); + if(!(SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); + } + if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) || + (!(SiS_CR36BIOSWord23d(SiS_Pr, HwInfo))) ) { + SiS_PanelDelay(SiS_Pr, HwInfo, 2); + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); + } else { + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04); + } + } + +#endif /* SIS300 */ + + } else { + +#ifdef SIS315H /* 315 series */ + + BOOLEAN custom1 = ((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || + (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) ? TRUE : FALSE; + + modenum = SiS_GetReg(SiS_Pr->SiS_P3d4,0x34) & 0x7f; + + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + +#ifdef SET_EMI + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); + } + } +#endif + if( (modenum <= 0x13) || + (SiS_IsVAMode(SiS_Pr,HwInfo)) || + (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE); + if(custom1) SiS_PanelDelay(SiS_Pr, HwInfo, 3); + } + + if(!custom1) { + SiS_DDC2Delay(SiS_Pr,0xff00); + SiS_DDC2Delay(SiS_Pr,0xe000); + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00); + pushax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x06); + if(IS_SIS740) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3); + } + SiS_PanelDelay(SiS_Pr, HwInfo, 3); + } + + } + + if(!(SiS_IsNotM650orLater(SiS_Pr, HwInfo))) { + if(HwInfo->jChipType < SIS_340) { + tempah = 0xef; + if(SiS_IsVAMode(SiS_Pr,HwInfo)) tempah = 0xf7; + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah); + } + } + + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,~0x10); + } + + tempah = 0x3f; + if(SiS_IsDualEdge(SiS_Pr,HwInfo)) { + tempah = 0x7f; + if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) tempah = 0xbf; + } + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah); + + if((SiS_IsVAMode(SiS_Pr,HwInfo)) || + ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (modenum <= 0x13))) { + + SiS_DisplayOff(SiS_Pr); + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + SiS_PanelDelay(SiS_Pr, HwInfo, 2); + } + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1E,0xDF); + + } + + if((!(SiS_IsVAMode(SiS_Pr,HwInfo))) || + ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (modenum <= 0x13))) { + + if(!(SiS_IsDualEdge(SiS_Pr,HwInfo))) { + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf); + SiS_DisplayOff(SiS_Pr); + } + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80); + + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + SiS_PanelDelay(SiS_Pr, HwInfo, 2); + } + + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10); + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp); + + } + + if(SiS_IsNotM650orLater(SiS_Pr,HwInfo)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); + } + + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + + if(!custom1) { + + if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) { + if(!(SiS_CRT2IsLCD(SiS_Pr,HwInfo))) { + if(!(SiS_IsDualEdge(SiS_Pr,HwInfo))) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); + } + } + } + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x06,pushax); + + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + if(SiS_IsVAorLCD(SiS_Pr, HwInfo)) { + SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 20); + } + } + + } else { + + if((SiS_IsVAMode(SiS_Pr,HwInfo)) || + (!(SiS_IsDualEdge(SiS_Pr,HwInfo)))) { + if((!(SiS_WeHaveBacklightCtrl(SiS_Pr, HwInfo))) || + (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo)))) { + SiS_PanelDelay(SiS_Pr, HwInfo, 2); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); + SiS_PanelDelay(SiS_Pr, HwInfo, 4); + } + } + + } + } + +#endif /* SIS315H */ + + } + + } else { /* ============ For 301 ================ */ + + if(HwInfo->jChipType < SIS_315H) { +#ifdef SIS300 + if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); + SiS_PanelDelay(SiS_Pr, HwInfo, 3); + } +#endif + } + + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF); /* disable VB */ + SiS_DisplayOff(SiS_Pr); + + if(HwInfo->jChipType >= SIS_315H) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80); + } + + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); /* disable lock mode */ + + if(HwInfo->jChipType >= SIS_315H) { + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp); + } else { +#ifdef SIS300 + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); /* disable CRT2 */ + if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) || + (!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) ) { + SiS_PanelDelay(SiS_Pr, HwInfo, 2); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04); + } +#endif + } + + } + + } else { /* ============ For LVDS =============*/ + + if(HwInfo->jChipType < SIS_315H) { + +#ifdef SIS300 /* 300 series */ + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { + SiS_SetCH700x(SiS_Pr,0x090E); + } + + if(HwInfo->jChipType == SIS_730) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x08)) { + SiS_WaitVBRetrace(SiS_Pr,HwInfo); + } + if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); + SiS_PanelDelay(SiS_Pr, HwInfo, 3); + } + } else { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x08)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) { + if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { + SiS_WaitVBRetrace(SiS_Pr,HwInfo); + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x1c)) { + SiS_DisplayOff(SiS_Pr); + } + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); + SiS_PanelDelay(SiS_Pr, HwInfo, 3); + } + } + } + } + + SiS_DisplayOff(SiS_Pr); + + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); + + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); + SiS_UnLockCRT2(SiS_Pr,HwInfo); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); + + if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) || + (!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) ) { + SiS_PanelDelay(SiS_Pr, HwInfo, 2); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04); + } + +#endif /* SIS300 */ + + } else { + +#ifdef SIS315H /* 315 series */ + + if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) { + if(HwInfo->jChipType < SIS_340) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,~0x18); + } + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + + if(HwInfo->jChipType == SIS_740) { + temp = SiS_GetCH701x(SiS_Pr,0x61); + if(temp < 1) { + SiS_SetCH701x(SiS_Pr,0xac76); + SiS_SetCH701x(SiS_Pr,0x0066); + } + + if( (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || + (SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwInfo)) ) { + SiS_SetCH701x(SiS_Pr,0x3e49); + } + } + + if( (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || + (SiS_IsVAMode(SiS_Pr,HwInfo)) ) { + SiS_Chrontel701xBLOff(SiS_Pr); + SiS_Chrontel701xOff(SiS_Pr,HwInfo); + } + + if(HwInfo->jChipType != SIS_740) { + if( (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || + (SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwInfo)) ) { + SiS_SetCH701x(SiS_Pr,0x0149); + } + } + + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); + SiS_PanelDelay(SiS_Pr, HwInfo, 3); + } + + if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0) || + (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || + (!(SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwInfo))) ) { + SiS_DisplayOff(SiS_Pr); + } + + if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0) || + (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || + (!(SiS_IsVAMode(SiS_Pr,HwInfo))) ) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80); + } + + if(HwInfo->jChipType == SIS_740) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); + } + + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); + + if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0) || + (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || + (!(SiS_IsVAMode(SiS_Pr,HwInfo))) ) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf); + if(HwInfo->jChipType == SIS_550) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xbf); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xef); + } + } + } else { + if(HwInfo->jChipType == SIS_740) { + if(SiS_IsLCDOrLCDA(SiS_Pr,HwInfo)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf); + } + } else if(SiS_IsVAMode(SiS_Pr,HwInfo)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf); + } + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_IsDualEdge(SiS_Pr,HwInfo)) { + /* SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xff); */ + } else { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); + } + } + + SiS_UnLockCRT2(SiS_Pr,HwInfo); + + if(HwInfo->jChipType == SIS_550) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80); /* DirectDVD PAL?*/ + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); /* VB clock / 4 ? */ + } else if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0) || + (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || + (!(SiS_IsVAMode(SiS_Pr,HwInfo))) ) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7); + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { + SiS_PanelDelay(SiS_Pr, HwInfo, 2); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04); + } + } + } + +#endif /* SIS315H */ + + } /* 315 series */ + + } /* LVDS */ + +} + +/*********************************************/ +/* ENABLE VIDEO BRIDGE */ +/*********************************************/ + +/* NEVER use any variables (VBInfo), this will be called + * from outside the context of a mode switch! + * MUST call getVBType before calling this + */ +void +SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT temp=0,tempah; +#ifdef SIS315H + USHORT temp1,pushax=0; + BOOLEAN delaylong = FALSE; +#endif + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { /* ====== For 301B et al ====== */ + + if(HwInfo->jChipType < SIS_315H) { + +#ifdef SIS300 /* 300 series */ + + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02); + } else if(SiS_Pr->SiS_VBType & VB_NoLCD) { + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00); + } + if(SiS_Pr->SiS_VBType & (VB_SIS301LV302LV | VB_NoLCD)) { + if(!(SiS_CR36BIOSWord23d(SiS_Pr, HwInfo))) { + SiS_PanelDelay(SiS_Pr, HwInfo, 0); + } + } + } + + if((SiS_Pr->SiS_VBType & VB_NoLCD) && + (SiS_CRT2IsLCD(SiS_Pr, HwInfo))) { + + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); /* Enable CRT2 */ + SiS_DisplayOn(SiS_Pr); + SiS_UnLockCRT2(SiS_Pr,HwInfo); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF); + if(SiS_BridgeInSlavemode(SiS_Pr)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40); + } + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) { + if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { + SiS_PanelDelay(SiS_Pr, HwInfo, 1); + } + SiS_WaitVBRetrace(SiS_Pr,HwInfo); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00); + } + } + + } else { + + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF; /* lock mode */ + if(SiS_BridgeInSlavemode(SiS_Pr)) { + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(!(tempah & SetCRT2ToRAMDAC)) temp |= 0x20; + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20); /* enable VB processor */ + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0); + SiS_DisplayOn(SiS_Pr); + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) { + if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { + SiS_PanelDelay(SiS_Pr, HwInfo, 1); + } + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01); + } + } + } + + } + + +#endif /* SIS300 */ + + } else { + +#ifdef SIS315H /* 315 series */ + +#ifdef SET_EMI + UCHAR r30=0, r31=0, r32=0, r33=0, cr36=0; + /* USHORT emidelay=0; */ +#endif + + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0xef); +#ifdef SET_EMI + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); + } +#endif + } + + if(!(SiS_IsNotM650orLater(SiS_Pr, HwInfo))) { + if(HwInfo->jChipType < SIS_340) { + tempah = 0x10; + if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) { + if(SiS_TVEnabled(SiS_Pr, HwInfo)) tempah = 0x18; + else tempah = 0x08; + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4c,tempah); + } + } + + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00); + SiS_DisplayOff(SiS_Pr); + pushax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x06); + if(IS_SIS740) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3); + } + + if(SiS_IsVAorLCD(SiS_Pr, HwInfo)) { + if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) { + SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 2); + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02); + SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 2); + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + SiS_GenericDelay(SiS_Pr, 0x4500); + } + } + } + + if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40)) { + SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10); + delaylong = TRUE; + } + + } + + if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) { + + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF; + if(SiS_BridgeInSlavemode(SiS_Pr)) { + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(!(tempah & SetCRT2ToRAMDAC)) { + if(!(SiS_LCDAEnabled(SiS_Pr, HwInfo))) temp |= 0x20; + } + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp); + + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); /* enable CRT2 */ + + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80); + + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + SiS_PanelDelay(SiS_Pr, HwInfo, 2); + } + + } else { + + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x20); + + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80); + + tempah = 0xc0; + if(SiS_IsDualEdge(SiS_Pr, HwInfo)) { + tempah = 0x80; + if(!(SiS_IsVAMode(SiS_Pr, HwInfo))) tempah = 0x40; + } + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah); + + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + + SiS_PanelDelay(SiS_Pr, HwInfo, 2); + + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1f,0x10); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80); + + if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) { +#ifdef SET_EMI + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); + SiS_GenericDelay(SiS_Pr, 0x500); + } +#endif + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c); + + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { +#ifdef SET_EMI + cr36 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); + + if(SiS_Pr->SiS_ROMNew) { + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo); + if(romptr) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20); /* Reset */ + SiS_Pr->EMI_30 = 0; + SiS_Pr->EMI_31 = ROMAddr[romptr + SiS_Pr->SiS_EMIOffset + 0]; + SiS_Pr->EMI_32 = ROMAddr[romptr + SiS_Pr->SiS_EMIOffset + 1]; + SiS_Pr->EMI_33 = ROMAddr[romptr + SiS_Pr->SiS_EMIOffset + 2]; + if(ROMAddr[romptr + 1] & 0x10) SiS_Pr->EMI_30 = 0x40; + /* emidelay = SISGETROMW((romptr + 0x22)); */ + SiS_Pr->HaveEMI = SiS_Pr->HaveEMILCD = SiS_Pr->OverruleEMI = TRUE; + } + } + + /* (P4_30|0x40) */ + /* Compal 1400x1050: 0x05, 0x60, 0x00 YES (1.10.7w; CR36=69) */ + /* Compal 1400x1050: 0x0d, 0x70, 0x40 YES (1.10.7x; CR36=69) */ + /* Acer 1280x1024: 0x12, 0xd0, 0x6b NO (1.10.9k; CR36=73) */ + /* Compaq 1280x1024: 0x0d, 0x70, 0x6b YES (1.12.04b; CR36=03) */ + /* Clevo 1024x768: 0x05, 0x60, 0x33 NO (1.10.8e; CR36=12, DL!) */ + /* Clevo 1024x768: 0x0d, 0x70, 0x40 (if type == 3) YES (1.10.8y; CR36=?2) */ + /* Clevo 1024x768: 0x05, 0x60, 0x33 (if type != 3) YES (1.10.8y; CR36=?2) */ + /* Asus 1024x768: ? ? (1.10.8o; CR36=?2) */ + /* Asus 1024x768: 0x08, 0x10, 0x3c (problematic) YES (1.10.8q; CR36=22) */ + + if(SiS_Pr->HaveEMI) { + r30 = SiS_Pr->EMI_30; r31 = SiS_Pr->EMI_31; + r32 = SiS_Pr->EMI_32; r33 = SiS_Pr->EMI_33; + } else { + r30 = 0; + } + + /* EMI_30 is read at driver start; however, the BIOS sets this + * (if it is used) only if the LCD is in use. In case we caught + * the machine while on TV output, this bit is not set and we + * don't know if it should be set - hence our detection is wrong. + * Work-around this here: + */ + + if((!SiS_Pr->HaveEMI) || (!SiS_Pr->HaveEMILCD)) { + switch((cr36 & 0x0f)) { + case 2: + r30 |= 0x40; + if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) r30 &= ~0x40; + if(!SiS_Pr->HaveEMI) { + r31 = 0x05; r32 = 0x60; r33 = 0x33; + if((cr36 & 0xf0) == 0x30) { + r31 = 0x0d; r32 = 0x70; r33 = 0x40; + } + } + break; + case 3: /* 1280x1024 */ + if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) r30 |= 0x40; + if(!SiS_Pr->HaveEMI) { + r31 = 0x12; r32 = 0xd0; r33 = 0x6b; + if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { + r31 = 0x0d; r32 = 0x70; r33 = 0x6b; + } + } + break; + case 9: /* 1400x1050 */ + r30 |= 0x40; + if(!SiS_Pr->HaveEMI) { + r31 = 0x05; r32 = 0x60; r33 = 0x00; + if(SiS_Pr->SiS_CustomT == CUT_COMPAL1400_2) { + r31 = 0x0d; r32 = 0x70; r33 = 0x40; /* BIOS values */ + } + } + break; + case 11: /* 1600x1200 - unknown */ + r30 |= 0x40; + if(!SiS_Pr->HaveEMI) { + r31 = 0x05; r32 = 0x60; r33 = 0x00; + } + } + } + + /* BIOS values don't work so well sometimes */ + if(!SiS_Pr->OverruleEMI) { +#ifdef COMPAL_HACK + if(SiS_Pr->SiS_CustomT == CUT_COMPAL1400_2) { + if((cr36 & 0x0f) == 0x09) { + r30 = 0x60; r31 = 0x05; r32 = 0x60; r33 = 0x00; + } + } +#endif +#ifdef COMPAQ_HACK + if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { + if((cr36 & 0x0f) == 0x03) { + r30 = 0x20; r31 = 0x12; r32 = 0xd0; r33 = 0x6b; + } + } +#endif +#ifdef ASUS_HACK + if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) { + if((cr36 & 0x0f) == 0x02) { + /* r30 = 0x60; r31 = 0x05; r32 = 0x60; r33 = 0x33; */ /* rev 2 */ + /* r30 = 0x20; r31 = 0x05; r32 = 0x60; r33 = 0x33; */ /* rev 3 */ + /* r30 = 0x60; r31 = 0x0d; r32 = 0x70; r33 = 0x40; */ /* rev 4 */ + /* r30 = 0x20; r31 = 0x0d; r32 = 0x70; r33 = 0x40; */ /* rev 5 */ + } + } +#endif + } + + if(!(SiS_Pr->OverruleEMI && (!r30) && (!r31) && (!r32) && (!r33))) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20); /* Reset */ + SiS_GenericDelay(SiS_Pr, 0x500); + } + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x31,r31); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x32,r32); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x33,r33); +#endif /* SET_EMI */ + + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); + +#ifdef SET_EMI + if( (SiS_LCDAEnabled(SiS_Pr, HwInfo)) || + (SiS_CRT2IsLCD(SiS_Pr, HwInfo)) ) { + if(r30 & 0x40) { + SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 5); + if(delaylong) { + SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 5); + delaylong = FALSE; + } + SiS_WaitVBRetrace(SiS_Pr,HwInfo); + if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) { + SiS_GenericDelay(SiS_Pr, 0x500); + } + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40); /* Enable */ + } + } +#endif + } + } + + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { + if(SiS_IsVAorLCD(SiS_Pr, HwInfo)) { + SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10); + if(delaylong) { + SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10); + } + SiS_WaitVBRetrace(SiS_Pr,HwInfo); + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + SiS_GenericDelay(SiS_Pr, 0x500); + } + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01); + } + } + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x06,pushax); + SiS_DisplayOn(SiS_Pr); + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xff); + + } + + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f); + } + +#endif /* SIS315H */ + + } + + } else { /* ============ For 301 ================ */ + + if(HwInfo->jChipType < SIS_315H) { + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00); + SiS_PanelDelay(SiS_Pr, HwInfo, 0); + } + } + + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF; /* lock mode */ + if(SiS_BridgeInSlavemode(SiS_Pr)) { + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(!(tempah & SetCRT2ToRAMDAC)) temp |= 0x20; + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp); + + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); /* enable CRT2 */ + + if(HwInfo->jChipType >= SIS_315H) { + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2E); + if(!(temp & 0x80)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80); /* BVBDOENABLE=1 */ + } + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20); /* enable VB processor */ + + SiS_VBLongWait(SiS_Pr); + SiS_DisplayOn(SiS_Pr); + if(HwInfo->jChipType >= SIS_315H) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f); + } + SiS_VBLongWait(SiS_Pr); + + if(HwInfo->jChipType < SIS_315H) { + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + SiS_PanelDelay(SiS_Pr, HwInfo, 1); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00); + } + } + + } + + } else { /* =================== For LVDS ================== */ + + if(HwInfo->jChipType < SIS_315H) { + +#ifdef SIS300 /* 300 series */ + + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + if(HwInfo->jChipType == SIS_730) { + SiS_PanelDelay(SiS_Pr, HwInfo, 1); + SiS_PanelDelay(SiS_Pr, HwInfo, 1); + SiS_PanelDelay(SiS_Pr, HwInfo, 1); + } + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00); + if(!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) { + SiS_PanelDelay(SiS_Pr, HwInfo, 0); + } + } + + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); + SiS_DisplayOn(SiS_Pr); + SiS_UnLockCRT2(SiS_Pr,HwInfo); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF); + if(SiS_BridgeInSlavemode(SiS_Pr)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40); + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { + if(!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) { + SiS_WaitVBRetrace(SiS_Pr, HwInfo); + SiS_SetCH700x(SiS_Pr,0x0B0E); + } + } + + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) { + if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { + SiS_PanelDelay(SiS_Pr, HwInfo, 1); + SiS_PanelDelay(SiS_Pr, HwInfo, 1); + } + SiS_WaitVBRetrace(SiS_Pr, HwInfo); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00); + } + } + } + +#endif /* SIS300 */ + + } else { + +#ifdef SIS315H /* 315 series */ + + if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) { + if(HwInfo->jChipType < SIS_340) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,0x18); + } + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00); + SiS_PanelDelay(SiS_Pr, HwInfo, 0); + } + } + + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); + SiS_UnLockCRT2(SiS_Pr,HwInfo); + + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7); + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp &= 0x20; + SiS_Chrontel701xBLOff(SiS_Pr); + } + + if(HwInfo->jChipType != SIS_550) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); + } + + if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_IsLCDOrLCDA(SiS_Pr, HwInfo)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20); + } + } + } + + temp1 = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2E); + if(!(temp1 & 0x80)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80); + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(temp) { + SiS_Chrontel701xBLOn(SiS_Pr, HwInfo); + } + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20); + if(HwInfo->jChipType == SIS_550) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x40); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x10); + } + } + } else if(SiS_IsVAMode(SiS_Pr,HwInfo)) { + if(HwInfo->jChipType != SIS_740) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20); + } + } + + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f); + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwInfo)) { + SiS_Chrontel701xOn(SiS_Pr,HwInfo); + } + if( (SiS_IsVAMode(SiS_Pr,HwInfo)) || + (SiS_IsLCDOrLCDA(SiS_Pr,HwInfo)) ) { + SiS_ChrontelDoSomething1(SiS_Pr,HwInfo); + } + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { + if( (SiS_IsVAMode(SiS_Pr,HwInfo)) || + (SiS_IsLCDOrLCDA(SiS_Pr,HwInfo)) ) { + SiS_Chrontel701xBLOn(SiS_Pr, HwInfo); + SiS_ChrontelInitTVVSync(SiS_Pr,HwInfo); + } + } + } else if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + SiS_PanelDelay(SiS_Pr, HwInfo, 1); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00); + } + } + } + +#endif /* SIS315H */ + + } /* 310 series */ + + } /* LVDS */ + +} + +/*********************************************/ +/* SET PART 1 REGISTER GROUP */ +/*********************************************/ + +/* Set CRT2 OFFSET / PITCH */ +static void +SiS_SetCRT2Offset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RRTI, PSIS_HW_INFO HwInfo) +{ + USHORT offset; + UCHAR temp; + + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) return; + + offset = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex,RRTI,HwInfo); + + if((SiS_Pr->SiS_LCDResInfo == Panel_640x480_2) || + (SiS_Pr->SiS_LCDResInfo == Panel_640x480_3)) { + offset >>= 1; + } + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(offset & 0xFF)); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x09,(offset >> 8)); + temp = (UCHAR)(((offset >> 3) & 0xFF) + 1); + if(offset % 8) temp++; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,temp); +} + +/* Set CRT2 sync and PanelLink mode */ +static void +SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT RefreshRateTableIndex, + PSIS_HW_INFO HwInfo) +{ + USHORT tempah=0,tempbl,infoflag; + + tempbl = 0xC0; + + if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + } else { + infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + } + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { /* LVDS */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + tempah = 0; + } else if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_LCDInfo & LCDSync)) { + tempah = SiS_Pr->SiS_LCDInfo; + } else tempah = infoflag >> 8; + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { + tempah |= 0xf0; + } + if( (SiS_Pr->SiS_IF_DEF_FSTN) || + (SiS_Pr->SiS_IF_DEF_DSTN) || + (SiS_Pr->SiS_IF_DEF_TRUMPION) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) { + tempah |= 0x30; + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(HwInfo->jChipType >= SIS_315H) { + tempah >>= 3; + tempah &= 0x18; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xE7,tempah); + /* Don't care about 12/18/24 bit mode - TV is via VGA, not PL */ + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,0xe0); + } + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + } + + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(HwInfo->jChipType < SIS_315H) { + +#ifdef SIS300 /* ---- 300 series --- */ + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { /* 630 - 301B(-DH) */ + + tempah = infoflag >> 8; + tempbl = 0; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_LCDInfo & LCDSync) { + tempah = SiS_Pr->SiS_LCDInfo; + tempbl = (tempah >> 6) & 0x03; + } + } + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + tempah |= 0xc0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); + } + + } else { /* 630 - 301 */ + + tempah = infoflag >> 8; + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + + } + +#endif /* SIS300 */ + + } else { + +#ifdef SIS315H /* ------- 315 series ------ */ + + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { /* 315 - LVDS */ + + tempbl = 0; + if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) && + (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { + tempah = infoflag >> 8; + if(SiS_Pr->SiS_LCDInfo & LCDSync) { + tempbl = ((SiS_Pr->SiS_LCDInfo & 0xc0) >> 6); + } + } else if((SiS_Pr->SiS_CustomT == CUT_CLEVO1400) && + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050)) { + tempah = infoflag >> 8; + tempbl = 0x03; + } else { + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); + tempbl = (tempah >> 6) & 0x03; + tempbl |= 0x08; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempbl |= 0x04; + } + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) tempah |= 0xc0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); + } + } + + } else { /* 315 - TMDS */ + + tempah = tempbl = infoflag >> 8; + if(!SiS_Pr->UseCustomMode) { + tempbl = 0; + if((SiS_Pr->SiS_VBType & VB_SIS301C) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + if(ModeNo <= 0x13) { + tempah = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)); + } + } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(SiS_Pr->SiS_LCDInfo & LCDSync) { + tempah = SiS_Pr->SiS_LCDInfo; + tempbl = (tempah >> 6) & 0x03; + } + } + } + } + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + if(SiS_Pr->SiS_VBType & VB_NoLCD) { + /* Imitate BIOS bug */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) tempah |= 0xc0; + } + if((SiS_Pr->SiS_VBType & VB_SIS301C) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + tempah >>= 3; + tempah &= 0x18; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xe7,tempah); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); + } + } + } + + } +#endif /* SIS315H */ + } + } +} + +/* Set CRT2 FIFO on 300/630/730 */ +#ifdef SIS300 +static void +SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,USHORT ModeNo, + PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT temp,index; + USHORT modeidindex,refreshratetableindex; + USHORT VCLK=0,MCLK,colorth=0,data2=0; + USHORT tempal, tempah, tempbx, tempcl, tempax; + USHORT CRT1ModeNo,CRT2ModeNo; + USHORT SelectRate_backup; + ULONG data,eax; + const UCHAR LatencyFactor[] = { + 97, 88, 86, 79, 77, 00, /*; 64 bit BQ=2 */ + 00, 87, 85, 78, 76, 54, /*; 64 bit BQ=1 */ + 97, 88, 86, 79, 77, 00, /*; 128 bit BQ=2 */ + 00, 79, 77, 70, 68, 48, /*; 128 bit BQ=1 */ + 80, 72, 69, 63, 61, 00, /*; 64 bit BQ=2 */ + 00, 70, 68, 61, 59, 37, /*; 64 bit BQ=1 */ + 86, 77, 75, 68, 66, 00, /*; 128 bit BQ=2 */ + 00, 68, 66, 59, 57, 37 /*; 128 bit BQ=1 */ + }; + const UCHAR LatencyFactor730[] = { + 69, 63, 61, + 86, 79, 77, + 103, 96, 94, + 120,113,111, + 137,130,128, /* <-- last entry, data below */ + 137,130,128, /* to avoid using illegal values */ + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + 137,130,128, + }; + const UCHAR ThLowB[] = { + 81, 4, 72, 6, 88, 8,120,12, + 55, 4, 54, 6, 66, 8, 90,12, + 42, 4, 45, 6, 55, 8, 75,12 + }; + const UCHAR ThTiming[] = { + 1, 2, 2, 3, 0, 1, 1, 2 + }; + + SelectRate_backup = SiS_Pr->SiS_SelectCRT2Rate; + + if(!SiS_Pr->CRT1UsesCustomMode) { + + CRT1ModeNo = SiS_Pr->SiS_CRT1Mode; /* get CRT1 ModeNo */ + SiS_SearchModeID(SiS_Pr, &CRT1ModeNo, &modeidindex); + SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); + SiS_Pr->SiS_SelectCRT2Rate = 0; + refreshratetableindex = SiS_GetRatePtr(SiS_Pr, CRT1ModeNo, modeidindex, HwInfo); + + if(CRT1ModeNo >= 0x13) { + index = SiS_Pr->SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK; + index &= 0x3F; + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; /* Get VCLK */ + + colorth = SiS_GetColorDepth(SiS_Pr,CRT1ModeNo,modeidindex); /* Get colordepth */ + colorth >>= 1; + if(!colorth) colorth++; + } + + } else { + + CRT1ModeNo = 0xfe; + VCLK = SiS_Pr->CSRClock_CRT1; /* Get VCLK */ + data2 = (SiS_Pr->CModeFlag_CRT1 & ModeTypeMask) - 2; + switch(data2) { /* Get color depth */ + case 0 : colorth = 1; break; + case 1 : colorth = 1; break; + case 2 : colorth = 2; break; + case 3 : colorth = 2; break; + case 4 : colorth = 3; break; + case 5 : colorth = 4; break; + default: colorth = 2; + } + + } + + if(CRT1ModeNo >= 0x13) { + if(HwInfo->jChipType == SIS_300) { + index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3A); + } else { + index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1A); + } + index &= 0x07; + MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK; /* Get MCLK */ + + data2 = (colorth * VCLK) / MCLK; + + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); + temp = ((temp & 0x00FF) >> 6) << 1; + if(temp == 0) temp = 1; + temp <<= 2; + temp &= 0xff; + + data2 = temp - data2; + + if((28 * 16) % data2) { + data2 = (28 * 16) / data2; + data2++; + } else { + data2 = (28 * 16) / data2; + } + + if(HwInfo->jChipType == SIS_300) { + + tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18); + tempah &= 0x62; + tempah >>= 1; + tempal = tempah; + tempah >>= 3; + tempal |= tempah; + tempal &= 0x07; + tempcl = ThTiming[tempal]; + tempbx = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16); + tempbx >>= 6; + tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); + tempah >>= 4; + tempah &= 0x0c; + tempbx |= tempah; + tempbx <<= 1; + tempal = ThLowB[tempbx + 1]; + tempal *= tempcl; + tempal += ThLowB[tempbx]; + data = tempal; + + } else if(HwInfo->jChipType == SIS_730) { + +#ifdef LINUX_KERNEL + SiS_SetRegLong(0xcf8,0x80000050); + eax = SiS_GetRegLong(0xcfc); +#else + eax = pciReadLong(0x00000000, 0x50); +#endif + tempal = (USHORT)(eax >> 8); + tempal &= 0x06; + tempal <<= 5; + +#ifdef LINUX_KERNEL + SiS_SetRegLong(0xcf8,0x800000A0); + eax = SiS_GetRegLong(0xcfc); +#else + eax = pciReadLong(0x00000000, 0xA0); +#endif + temp = (USHORT)(eax >> 28); + temp &= 0x0F; + tempal |= temp; + + tempbx = tempal; /* BIOS BUG (2.04.5d, 2.04.6a use ah here, which is unset!) */ + tempbx = 0; /* -- do it like the BIOS anyway... */ + tempax = tempbx; + tempbx &= 0xc0; + tempbx >>= 6; + tempax &= 0x0f; + tempax *= 3; + tempbx += tempax; + + data = LatencyFactor730[tempbx]; + data += 15; + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); + if(!(temp & 0x80)) data += 5; + + } else { + + index = 0; + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); + if(temp & 0x0080) index += 12; + +#ifdef LINUX_KERNEL + SiS_SetRegLong(0xcf8,0x800000A0); + eax = SiS_GetRegLong(0xcfc); +#else + /* We use pci functions X offers. We use tag 0, because + * we want to read/write to the host bridge (which is always + * 00:00.0 on 630, 730 and 540), not the VGA device. + */ + eax = pciReadLong(0x00000000, 0xA0); +#endif + temp = (USHORT)(eax >> 24); + if(!(temp&0x01)) index += 24; + +#ifdef LINUX_KERNEL + SiS_SetRegLong(0xcf8,0x80000050); + eax = SiS_GetRegLong(0xcfc); +#else + eax = pciReadLong(0x00000000, 0x50); +#endif + temp=(USHORT)(eax >> 24); + if(temp & 0x01) index += 6; + + temp = (temp & 0x0F) >> 1; + index += temp; + + data = LatencyFactor[index]; + data += 15; + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); + if(!(temp & 0x80)) data += 5; + } + + data += data2; /* CRT1 Request Period */ + + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup; + + if(!SiS_Pr->UseCustomMode) { + + CRT2ModeNo = ModeNo; + SiS_SearchModeID(SiS_Pr, &CRT2ModeNo, &modeidindex); + + refreshratetableindex = SiS_GetRatePtr(SiS_Pr, CRT2ModeNo, modeidindex, HwInfo); + + index = SiS_GetVCLK2Ptr(SiS_Pr,CRT2ModeNo,modeidindex, + refreshratetableindex,HwInfo); + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; /* Get VCLK */ + + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x01) { + VCLK = ROMAddr[0x229] | (ROMAddr[0x22a] << 8); + } + } + } + + } else { + + CRT2ModeNo = 0xfe; + VCLK = SiS_Pr->CSRClock; /* Get VCLK */ + + } + + colorth = SiS_GetColorDepth(SiS_Pr,CRT2ModeNo,modeidindex); /* Get colordepth */ + colorth >>= 1; + if(!colorth) colorth++; + + data = data * VCLK * colorth; + if(data % (MCLK << 4)) { + data = data / (MCLK << 4); + data++; + } else { + data = data / (MCLK << 4); + } + + if(data <= 6) data = 6; + if(data > 0x14) data = 0x14; + + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x01); + if(HwInfo->jChipType == SIS_300) { + if(data <= 0x0f) temp = (temp & (~0x1F)) | 0x13; + else temp = (temp & (~0x1F)) | 0x16; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + temp = (temp & (~0x1F)) | 0x13; + } + } else { + if( ( (HwInfo->jChipType == SIS_630) || + (HwInfo->jChipType == SIS_730) ) && + (HwInfo->jChipRevision >= 0x30) ) /* 630s or 730(s?) */ + { + temp = (temp & (~0x1F)) | 0x1b; + } else { + temp = (temp & (~0x1F)) | 0x16; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0xe0,temp); + + if( (HwInfo->jChipType == SIS_630) && + (HwInfo->jChipRevision >= 0x30) ) /* 630s, NOT 730 */ + { + if(data > 0x13) data = 0x13; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,0xe0,data); + + } else { /* If mode <= 0x13, we just restore everything */ + + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup; + + } +} +#endif + +/* Set CRT2 FIFO on 315/330 series */ +#ifdef SIS315H +static void +SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,0x3B); + if( (HwInfo->jChipType == SIS_760) && + (SiS_Pr->SiS_SysFlags & SF_760LFB) && + (SiS_Pr->SiS_ModeType == Mode32Bpp) && + (SiS_Pr->SiS_VGAHDE >= 1280) && + (SiS_Pr->SiS_VGAVDE >= 1024) ) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2f,0x03); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,0x3b); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4d,0xc0); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2f,0x01); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4d,0xc0); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,0x6e); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x3f,0x04); + } + +} +#endif + +static USHORT +SiS_GetVGAHT2(SiS_Private *SiS_Pr) +{ + ULONG tempax,tempbx; + + tempbx = (SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) * SiS_Pr->SiS_RVBHCMAX; + tempax = (SiS_Pr->SiS_VT - SiS_Pr->SiS_VDE) * SiS_Pr->SiS_RVBHCFACT; + tempax = (tempax * SiS_Pr->SiS_HT) / tempbx; + return((USHORT)tempax); +} + +/* Set Part 1 / SiS bridge slave mode */ +static void +SiS_SetGroup1_301(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo,USHORT RefreshRateTableIndex) +{ + USHORT push1,push2; + USHORT tempax,tempbx,tempcx,temp; + USHORT resinfo,modeflag,xres=0; + unsigned char p1_7, p1_8; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + resinfo = 0; + xres = SiS_Pr->CHDisplay; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + xres = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes; + } + + /* The following is only done if bridge is in slave mode: */ + + if((HwInfo->jChipType >= SIS_661) && (ModeNo > 0x13)) { + if(xres >= 1600) { + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x31,0x04); + } + } + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,0xff); /* set MAX HT */ + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) modeflag |= Charx8Dot; + + if(modeflag & Charx8Dot) tempcx = 0x08; + else tempcx = 0x09; + + tempax = SiS_Pr->SiS_VGAHDE; /* 0x04 Horizontal Display End */ + if(modeflag & HalfDCLK) tempax >>= 1; + tempax = ((tempax / tempcx) - 1) & 0xff; + tempbx = tempax; + + temp = tempax; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x04,temp); + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) { + temp += 2; + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(resinfo == SIS_RI_800x600) temp -= 2; + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x05,temp); /* 0x05 Horizontal Display Start */ + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x06,0x03); /* 0x06 Horizontal Blank end */ + + tempax = 0xFFFF; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempax = SiS_GetVGAHT2(SiS_Pr); + if(tempax >= SiS_Pr->SiS_VGAHT) tempax = SiS_Pr->SiS_VGAHT; + if(modeflag & HalfDCLK) tempax >>= 1; + tempax = (tempax / tempcx) - 5; + tempcx = tempax; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + temp = tempcx - 1; + if(!(modeflag & HalfDCLK)) { + temp -= 6; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + temp -= 2; + if(ModeNo > 0x13) temp -= 10; + } + } + } else { + tempcx = (tempcx + tempbx) >> 1; + temp = (tempcx & 0x00FF) + 2; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + temp--; + if(!(modeflag & HalfDCLK)) { + if((modeflag & Charx8Dot)) { + temp += 4; + if(SiS_Pr->SiS_VGAHDE >= 800) temp -= 6; + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VGAHDE == 800) temp += 2; + } + } + } + } else { + if(!(modeflag & HalfDCLK)) { + temp -= 4; + if((SiS_Pr->SiS_LCDResInfo != Panel_1280x960) && + (SiS_Pr->SiS_LCDResInfo != Panel_1600x1200)) { + if(SiS_Pr->SiS_VGAHDE >= 800) { + temp -= 7; + if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->SiS_ModeType == ModeEGA) { + if(SiS_Pr->SiS_VGAVDE == 1024) { + temp += 15; + if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) + temp += 7; + } + } + } + if(SiS_Pr->SiS_LCDResInfo != Panel_1400x1050) { + if(SiS_Pr->SiS_VGAHDE >= 1280) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) temp += 28; + } + } + } + } + } + } + } + + p1_7 = temp; + p1_8 = 0x00; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + if(ModeNo <= 0x01) { + p1_7 = 0x2a; + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) p1_8 = 0x61; + else p1_8 = 0x41; + } else if(SiS_Pr->SiS_ModeType == ModeText) { + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) p1_7 = 0x54; + else p1_7 = 0x55; + p1_8 = 0x00; + } else if(ModeNo <= 0x13) { + if(modeflag & HalfDCLK) { + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + p1_7 = 0x30; + p1_8 = 0x03; + } else { + p1_7 = 0x2f; + p1_8 = 0x02; + } + } else { + p1_7 = 0x5b; + p1_8 = 0x03; + } + } else if( ((HwInfo->jChipType >= SIS_315H) && + ((ModeNo == 0x50) || (ModeNo == 0x56) || (ModeNo == 0x53))) || + ((HwInfo->jChipType < SIS_315H) && + (resinfo == SIS_RI_320x200 || resinfo == SIS_RI_320x240)) ) { + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + p1_7 = 0x30, + p1_8 = 0x03; + } else { + p1_7 = 0x2f; + p1_8 = 0x03; + } + } + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p|TVSetYPbPr750p)) { + p1_7 = 0x63; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) p1_7 = 0x55; + } + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + if(!(modeflag & HalfDCLK)) { + p1_7 = 0xb2; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + p1_7 = 0xab; + } + } + } else { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { + if(modeflag & HalfDCLK) p1_7 = 0x30; + } + } + } + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,p1_7); /* 0x07 Horizontal Retrace Start */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,p1_8); /* 0x08 Horizontal Retrace End */ + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x03); /* 0x18 SR08 (FIFO Threshold?) */ + + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x19,0xF0); + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x09,0xFF); /* 0x09 Set Max VT */ + + tempcx = 0x121; + tempbx = SiS_Pr->SiS_VGAVDE; /* 0x0E Vertical Display End */ + if (tempbx == 357) tempbx = 350; + else if(tempbx == 360) tempbx = 350; + else if(tempbx == 375) tempbx = 350; + else if(tempbx == 405) tempbx = 400; + else if(tempbx == 420) tempbx = 400; + else if(tempbx == 525) tempbx = 480; + push2 = tempbx; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + if (tempbx == 350) tempbx += 5; + else if(tempbx == 480) tempbx += 5; + } + } + } + tempbx -= 2; + temp = tempbx & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,temp); /* 0x10 vertical Blank Start */ + + tempbx = push2; + tempbx--; + temp = tempbx & 0x00FF; +#if 0 + /* Missing code from 630/301B 2.04.5a and 650/302LV 1.10.6s (calles int 2f) */ + if(xxx()) { + if(temp == 0xdf) temp = 0xda; + } +#endif + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0E,temp); + + temp = 0; + if(modeflag & DoubleScanMode) temp |= 0x80; + if(HwInfo->jChipType >= SIS_661) { + if(tempbx & 0x0200) temp |= 0x20; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x0B,0x5F,temp); + if(tempbx & 0x0100) tempcx |= 0x000a; + if(tempbx & 0x0400) tempcx |= 0x1200; + } else { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,temp); + if(tempbx & 0x0100) tempcx |= 0x0002; + if(tempbx & 0x0400) tempcx |= 0x0600; + } + + if(tempbx & 0x0200) tempcx |= 0x0040; + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x11,0x00); /* 0x11 Vertical Blank End */ + + tempax = (SiS_Pr->SiS_VGAVT - tempbx) >> 2; + + if((ModeNo > 0x13) || (HwInfo->jChipType < SIS_315H)) { + if(resinfo != SIS_RI_1280x1024) { + tempbx += (tempax << 1); + } + } else if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_LCDResInfo != Panel_1400x1050) { + tempbx += (tempax << 1); + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + tempbx -= 10; + } else { + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + tempbx += 40; + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VGAHDE == 800) tempbx += 10; + } + } + } + } + tempax >>= 2; + tempax++; + tempax += tempbx; + push1 = tempax; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + if(tempbx <= 513) { + if(tempax >= 513) tempbx = 513; + } + } + temp = tempbx & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0C,temp); /* 0x0C Vertical Retrace Start */ + + tempbx--; + temp = tempbx & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,temp); + + if(tempbx & 0x0100) tempcx |= 0x0008; + + if(tempbx & 0x0200) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x0B,0x20); + } + tempbx++; + + if(tempbx & 0x0100) tempcx |= 0x0004; + if(tempbx & 0x0200) tempcx |= 0x0080; + if(tempbx & 0x0400) { + if(HwInfo->jChipType >= SIS_661) tempcx |= 0x0800; + else if(SiS_Pr->SiS_VBType & VB_SIS301) tempcx |= 0x0800; + else tempcx |= 0x0C00; + } + + tempbx = push1; + temp = tempbx & 0x000F; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0D,temp); /* 0x0D vertical Retrace End */ + + if(tempbx & 0x0010) tempcx |= 0x2000; + + temp = tempcx & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp); /* 0x0A CR07 */ + + temp = (tempcx & 0xFF00) >> 8; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,temp); /* 0x17 SR0A */ + + tempax = modeflag; + temp = (tempax & 0xFF00) >> 8; + temp = (temp >> 1) & 0x09; + if(!(SiS_Pr->SiS_VBType & VB_SIS301)) temp |= 0x01; /* Always 8 dotclock */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp); /* 0x16 SR01 */ + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0F,0x00); /* 0x0F CR14 */ + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,0x00); /* 0x12 CR17 */ + + temp = 0x00; + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) { + temp = 0x80; + } + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp); /* 0x1A SR0E */ + + temp = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp); +} + +/* Setup panel link + * This is used for LVDS, LCDA and Chrontel TV output + * 300/LVDS+TV, 300/301B-DH, 315/LVDS+TV, 315/LCDA + */ +static void +SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex) +{ + USHORT modeflag,resinfo; + USHORT push2,tempax,tempbx,tempcx,temp; + ULONG tempeax=0,tempebx,tempecx,tempvcfact=0; + BOOLEAN islvds = FALSE, issis = FALSE, chkdclkfirst = FALSE; +#ifdef SIS300 + USHORT crt2crtc; +#endif +#ifdef SIS315H + USHORT pushcx; +#endif + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; +#ifdef SIS300 + crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; +#endif + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + resinfo = 0; +#ifdef SIS300 + crt2crtc = 0; +#endif + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; +#ifdef SIS300 + crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; +#endif + } + + /* is lvds if really LVDS, or 301B-DH with external LVDS transmitter */ + if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_NoLCD)) { + islvds = TRUE; + } + + /* is really sis if sis bridge, but not 301B-DH */ + if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + issis = TRUE; + } + + if((HwInfo->jChipType >= SIS_315H) && (islvds) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA))) { + if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) { + chkdclkfirst = TRUE; + } + } + +#ifdef SIS315H + if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if(IS_SIS330) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10); + } else if(IS_SIS740) { + if(islvds) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x03); + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10); + } + } else { + if(islvds) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x00); + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2D,0x0f); + if(SiS_Pr->SiS_VBType & VB_SIS301C) { + if((SiS_Pr->SiS_LCDResInfo == Panel_1024x768) || + (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x20); + } + } + } + } + } +#endif + + /* Horizontal */ + + tempax = SiS_Pr->SiS_LCDHDES; + if(islvds) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) { + if((SiS_Pr->SiS_LCDResInfo == Panel_640x480) && + (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) { + tempax -= 8; + } + } + } + } + + temp = (tempax & 0x0007); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp); /* BPLHDESKEW[2:0] */ + temp = (tempax >> 3) & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp); /* BPLHDESKEW[10:3] */ + + tempbx = SiS_Pr->SiS_HDE; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if((SiS_Pr->SiS_LCDResInfo == Panel_640x480_2) || + (SiS_Pr->SiS_LCDResInfo == Panel_640x480_3)) { + tempbx >>= 1; + } + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + tempbx = SiS_Pr->PanelXRes; + } + } + + tempax += tempbx; + if(tempax >= SiS_Pr->SiS_HT) tempax -= SiS_Pr->SiS_HT; + + temp = tempax; + if(temp & 0x07) temp += 8; + temp >>= 3; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,temp); /* BPLHDEE */ + + tempcx = (SiS_Pr->SiS_HT - tempbx) >> 2; + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(SiS_Pr->PanelHRS != 999) tempcx = SiS_Pr->PanelHRS; + } + } + + tempcx += tempax; + if(tempcx >= SiS_Pr->SiS_HT) tempcx -= SiS_Pr->SiS_HT; + + temp = (tempcx >> 3) & 0x00FF; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + switch(ModeNo) { + case 0x04: + case 0x05: + case 0x0d: temp = 0x56; break; + case 0x10: temp = 0x60; break; + case 0x13: temp = 0x5f; break; + case 0x40: + case 0x41: + case 0x4f: + case 0x43: + case 0x44: + case 0x62: + case 0x56: + case 0x53: + case 0x5d: + case 0x5e: temp = 0x54; break; + } + } + } + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,temp); /* BPLHRS */ + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + temp += 2; + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + temp += 8; + if(SiS_Pr->PanelHRE != 999) { + temp = tempcx + SiS_Pr->PanelHRE; + if(temp >= SiS_Pr->SiS_HT) temp -= SiS_Pr->SiS_HT; + temp >>= 3; + } + } + } else { + temp += 10; + } + + temp &= 0x1F; + temp |= ((tempcx & 0x07) << 5); +#if 0 + if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0x20; /* WRONG? BIOS loads cl, not ah */ +#endif + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,temp); /* BPLHRE */ + + /* Vertical */ + + tempax = SiS_Pr->SiS_VGAVDE; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + tempax = SiS_Pr->PanelYRes; + } + } + + tempbx = SiS_Pr->SiS_LCDVDES + tempax; + if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT; + + push2 = tempbx; + + tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE; + if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->PanelYRes; + } + } + } + if(islvds) tempcx >>= 1; + else tempcx >>= 2; + + if( (SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) && + (!(SiS_Pr->SiS_LCDInfo & LCDPass11)) && + (SiS_Pr->PanelVRS != 999) ) { + tempcx = SiS_Pr->PanelVRS; + tempbx += tempcx; + if(issis) tempbx++; + } else { + tempbx += tempcx; + if(HwInfo->jChipType < SIS_315H) tempbx++; + else if(issis) tempbx++; + } + + if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT; /* BPLVRS */ + + temp = tempbx & 0x00FF; + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(ModeNo == 0x10) temp = 0xa9; + } + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp); + + tempcx >>= 3; + tempcx++; + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(SiS_Pr->PanelVRE != 999) tempcx = SiS_Pr->PanelVRE; + } + } + + tempcx += tempbx; + temp = tempcx & 0x000F; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp); /* BPLVRE */ + + temp = ((tempbx >> 8) & 0x07) << 3; + if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) { + if(SiS_Pr->SiS_HDE != 640) { + if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40; + } + } else if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40; + if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) temp |= 0x40; + tempbx = 0x87; + if((HwInfo->jChipType >= SIS_315H) || + (HwInfo->jChipRevision >= 0x30)) { + tempbx = 0x07; + if((SiS_Pr->SiS_IF_DEF_CH70xx == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x03) temp |= 0x80; + } + /* Chrontel 701x operates in 24bit mode (8-8-8, 2x12bit mutliplexed) via VGA2 */ + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x10) temp |= 0x80; + } else { + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) temp |= 0x80; + } + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,tempbx,temp); + + tempbx = push2; /* BPLVDEE */ + + tempcx = SiS_Pr->SiS_LCDVDES; /* BPLVDES */ + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: + tempbx = SiS_Pr->SiS_VGAVDE - 1; + tempcx = SiS_Pr->SiS_VGAVDE; + break; + case Panel_800x600: + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + if(resinfo == SIS_RI_800x600) tempcx++; + } + break; + case Panel_1024x600: + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + if(resinfo == SIS_RI_1024x600) tempcx++; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(resinfo == SIS_RI_800x600) tempcx++; + } + } + break; + case Panel_1024x768: + if(HwInfo->jChipType < SIS_315H) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + if(resinfo == SIS_RI_1024x768) tempcx++; + } + } + break; + } + } + + temp = ((tempbx >> 8) & 0x07) << 3; + temp = temp | ((tempcx >> 8) & 0x07); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1D,temp); + /* if(SiS_Pr->SiS_IF_DEF_FSTN) tempbx++; */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1C,tempbx); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1B,tempcx); + + /* Vertical scaling */ + + if(HwInfo->jChipType < SIS_315H) { + +#ifdef SIS300 /* 300 series */ + tempeax = SiS_Pr->SiS_VGAVDE << 6; + temp = (tempeax % (ULONG)SiS_Pr->SiS_VDE); + tempeax = tempeax / (ULONG)SiS_Pr->SiS_VDE; + if(temp) tempeax++; + + if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) tempeax = 0x3F; + + temp = (USHORT)(tempeax & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,temp); /* BPLVCFACT */ + tempvcfact = temp; +#endif /* SIS300 */ + + } else { + +#ifdef SIS315H /* 315 series */ + tempeax = SiS_Pr->SiS_VGAVDE << 18; + tempebx = SiS_Pr->SiS_VDE; + temp = (tempeax % tempebx); + tempeax = tempeax / tempebx; + if(temp) tempeax++; + tempvcfact = tempeax; + + temp = (USHORT)(tempeax & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,temp); + temp = (USHORT)((tempeax & 0x00FF00) >> 8); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,temp); + temp = (USHORT)((tempeax & 0x00030000) >> 16); + if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,temp); + + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) { + temp = (USHORT)(tempeax & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3c,temp); + temp = (USHORT)((tempeax & 0x00FF00) >> 8); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3b,temp); + temp = (USHORT)(((tempeax & 0x00030000) >> 16) << 6); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0x3f,temp); + temp = 0; + if(SiS_Pr->SiS_VDE != SiS_Pr->SiS_VGAVDE) temp |= 0x08; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x30,0xf3,temp); + } +#endif + + } + + /* Horizontal scaling */ + + tempeax = SiS_Pr->SiS_VGAHDE; /* 1f = ( (VGAHDE * 65536) / ( (VGAHDE * 65536) / HDE ) ) - 1*/ + if(chkdclkfirst) { + if(modeflag & HalfDCLK) tempeax >>= 1; + } + tempebx = tempeax << 16; + if(SiS_Pr->SiS_HDE == tempeax) { + tempecx = 0xFFFF; + } else { + tempecx = tempebx / SiS_Pr->SiS_HDE; + if(HwInfo->jChipType >= SIS_315H) { + if(tempebx % SiS_Pr->SiS_HDE) tempecx++; + } + } + + if(HwInfo->jChipType >= SIS_315H) { + tempeax = (tempebx / tempecx) - 1; + } else { + tempeax = ((SiS_Pr->SiS_VGAHT << 16) / tempecx) - 1; + } + tempecx = (tempecx << 16) | (tempeax & 0xFFFF); + temp = (USHORT)(tempecx & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1F,temp); + + if(HwInfo->jChipType >= SIS_315H) { + tempeax = (SiS_Pr->SiS_VGAVDE << 18) / tempvcfact; + tempbx = (USHORT)(tempeax & 0xFFFF); + } else { + tempeax = SiS_Pr->SiS_VGAVDE << 6; + tempbx = tempvcfact & 0x3f; + if(tempbx == 0) tempbx = 64; + tempeax /= tempbx; + tempbx = (USHORT)(tempeax & 0xFFFF); + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tempbx--; + if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) { + if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) tempbx = 1; + else if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) tempbx = 1; + } + + temp = ((tempbx >> 8) & 0x07) << 3; + temp = temp | ((tempecx >> 8) & 0x07); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x20,temp); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x21,tempbx); + + tempecx >>= 16; /* BPLHCFACT */ + if(!chkdclkfirst) { + if(modeflag & HalfDCLK) tempecx >>= 1; + } + temp = (USHORT)((tempecx & 0xFF00) >> 8); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x22,temp); + temp = (USHORT)(tempecx & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp); + +#ifdef SIS315H + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + if((islvds) || (SiS_Pr->SiS_VBInfo & VB_SIS301LV302LV)) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x20); + } + } else { + if(islvds) { + if(HwInfo->jChipType == SIS_740) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x03); + } else { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x23); + } + } + } + } +#endif + +#ifdef SIS300 + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + int i; + UCHAR TrumpMode13[4] = { 0x01, 0x10, 0x2c, 0x00 }; + UCHAR TrumpMode10_1[4] = { 0x01, 0x10, 0x27, 0x00 }; + UCHAR TrumpMode10_2[4] = { 0x01, 0x16, 0x10, 0x00 }; + + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xbf); + for(i=0; i<5; i++) { + SiS_SetTrumpionBlock(SiS_Pr, &SiS300_TrumpionData[crt2crtc][0]); + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(ModeNo == 0x13) { + for(i=0; i<4; i++) { + SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode13[0]); + } + } else if(ModeNo == 0x10) { + for(i=0; i<4; i++) { + SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode10_1[0]); + SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode10_2[0]); + } + } + } + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); + } +#endif + +#ifdef SIS315H + if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x25,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x26,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x27,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x28,0x87); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x29,0x5A); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2A,0x4B); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x07,0x03); + tempax = SiS_Pr->SiS_HDE; /* Blps = lcdhdee(lcdhdes+HDE) + 64 */ + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || + SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1; + tempax += 64; + temp = tempax & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x38,temp); + temp = ((tempax & 0xFF00) >> 8) << 3; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,~0x078,temp); + tempax += 32; /* Blpe=lBlps+32 */ + temp = tempax & 0x00FF; + if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x39,temp); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3A,0x00); /* Bflml=0 */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x007,0x00); + + tempax = SiS_Pr->SiS_VDE; + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || + SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1; + tempax >>= 1; + temp = tempax & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3B,temp); + temp = ((tempax & 0xFF00) >> 8) << 3; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x038,temp); + + tempeax = SiS_Pr->SiS_HDE; + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || + SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempeax >>= 1; + tempeax <<= 2; /* BDxFIFOSTOP = (HDE*4)/128 */ + tempebx = 128; + temp = (USHORT)(tempeax % tempebx); + tempeax = tempeax / tempebx; + if(temp) tempeax++; + temp = (USHORT)(tempeax & 0x003F); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x45,~0x0FF,temp); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3F,0x00); /* BDxWadrst0 */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3E,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3D,0x10); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x040,0x00); + + tempax = SiS_Pr->SiS_HDE; + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || + SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1; + tempax >>= 4; /* BDxWadroff = HDE*4/8/8 */ + pushcx = tempax; + temp = tempax & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x43,temp); + temp = ((tempax & 0xFF00) >> 8) << 3; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x0F8,temp); + + tempax = SiS_Pr->SiS_VDE; /* BDxWadrst1 = BDxWadrst0 + BDxWadroff * VDE */ + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || + SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1; + tempeax = (tempax * pushcx); + tempebx = 0x00100000 + tempeax; + temp = (USHORT)tempebx & 0x000000FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x42,temp); + temp = (USHORT)((tempebx & 0x0000FF00) >> 8); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x41,temp); + temp = (USHORT)((tempebx & 0x00FF0000) >> 16); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x40,temp); + temp = (USHORT)(((tempebx & 0x01000000) >> 24) << 7); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x080,temp); + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2F,0x03); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,0x50); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x04,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2F,0x01); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,0x38); + + if(SiS_Pr->SiS_IF_DEF_FSTN) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2b,0x02); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2c,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,0x0c); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x38,0x80); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x39,0xA0); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3a,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3b,0xf0); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3c,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3d,0x10); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3e,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3f,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x40,0x10); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x41,0x25); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x42,0x80); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x43,0x14); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x44,0x03); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x45,0x0a); + } + } +#endif /* SIS315H */ +} + +/* Set Part 1 */ +static void +SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex) +{ +#if defined(SIS300) || defined(SIS315H) + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; +#endif + USHORT temp=0, tempax=0, tempbx=0, tempcx=0, bridgeadd=0; + USHORT pushbx=0, CRT1Index=0, modeflag, resinfo=0; +#ifdef SIS315H + USHORT tempbl=0; +#endif + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + return; + } + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + } else { + CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + SiS_SetCRT2Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + + if( ! ((HwInfo->jChipType >= SIS_315H) && + (SiS_Pr->SiS_IF_DEF_LVDS == 1) && + (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ) { + + if(HwInfo->jChipType < SIS_315H ) { +#ifdef SIS300 + SiS_SetCRT2FIFO_300(SiS_Pr, ModeNo, HwInfo); +#endif + } else { +#ifdef SIS315H + SiS_SetCRT2FIFO_310(SiS_Pr, HwInfo); +#endif + } + + /* 1. Horizontal setup */ + + if(HwInfo->jChipType < SIS_315H ) { + +#ifdef SIS300 /* ------------- 300 series --------------*/ + + temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp); /* CRT2 Horizontal Total */ + + temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8) << 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0f,temp); /* CRT2 Horizontal Total Overflow [7:4] */ + + temp = (SiS_Pr->SiS_VGAHDE + 12) & 0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp); /* CRT2 Horizontal Display Enable End */ + + pushbx = SiS_Pr->SiS_VGAHDE + 12; /* bx BTVGA2HRS 0x0B,0x0C */ + tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2; + tempbx = pushbx + tempcx; + tempcx <<= 1; + tempcx += tempbx; + + bridgeadd = 12; + +#endif /* SIS300 */ + + } else { + +#ifdef SIS315H /* ------------------- 315/330 series --------------- */ + + tempcx = SiS_Pr->SiS_VGAHT; /* BTVGA2HT 0x08,0x09 */ + if(modeflag & HalfDCLK) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + tempcx >>= 1; + } else { + tempax = SiS_Pr->SiS_VGAHDE >> 1; + tempcx = SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE + tempax; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempcx = SiS_Pr->SiS_HT - tempax; + } + } + } + tempcx--; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,tempcx); /* CRT2 Horizontal Total */ + temp = (tempcx >> 4) & 0xF0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp); /* CRT2 Horizontal Total Overflow [7:4] */ + + tempcx = SiS_Pr->SiS_VGAHT; /* BTVGA2HDEE 0x0A,0x0C */ + tempbx = SiS_Pr->SiS_VGAHDE; + tempcx -= tempbx; + tempcx >>= 2; + if(modeflag & HalfDCLK) { + tempbx >>= 1; + tempcx >>= 1; + } + tempbx += 16; + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,tempbx); /* CRT2 Horizontal Display Enable End */ + + pushbx = tempbx; + tempcx >>= 1; + tempbx += tempcx; + tempcx += tempbx; + + bridgeadd = 16; + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(HwInfo->jChipType >= SIS_661) { + if((SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) || + (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { + if(resinfo == SIS_RI_1280x1024) { + tempcx = (tempcx & 0xff00) | 0x30; + } else if(resinfo == SIS_RI_1600x1200) { + tempcx = (tempcx & 0xff00) | 0xff; + } + } + } + } + +#endif /* SIS315H */ + + } /* 315/330 series */ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CHSyncStart + bridgeadd; + tempcx = SiS_Pr->CHSyncEnd + bridgeadd; + tempax = SiS_Pr->SiS_VGAHT; + if(modeflag & HalfDCLK) tempax >>= 1; + tempax--; + if(tempcx > tempax) tempcx = tempax; + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + unsigned char cr4, cr14, cr5, cr15; + if(SiS_Pr->UseCustomMode) { + cr4 = SiS_Pr->CCRT1CRTC[4]; + cr14 = SiS_Pr->CCRT1CRTC[14]; + cr5 = SiS_Pr->CCRT1CRTC[5]; + cr15 = SiS_Pr->CCRT1CRTC[15]; + } else { + cr4 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4]; + cr14 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14]; + cr5 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5]; + cr15 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15]; + } + tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 3) << 3; /* (VGAHRS-3)*8 */ + tempcx = (((cr5 & 0x1f) | ((cr15 & 0x04) << (5-2))) - 3) << 3; /* (VGAHRE-3)*8 */ + tempcx &= 0x00FF; + tempcx |= (tempbx & 0xFF00); + tempbx += bridgeadd; + tempcx += bridgeadd; + tempax = SiS_Pr->SiS_VGAHT; + if(modeflag & HalfDCLK) tempax >>= 1; + tempax--; + if(tempcx > tempax) tempcx = tempax; + } + + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { + tempbx = 1040; + tempcx = 1044; /* HWCursor bug! */ + } + + } + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,tempbx); /* CRT2 Horizontal Retrace Start */ + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0D,tempcx); /* CRT2 Horizontal Retrace End */ + + temp = ((tempbx >> 8) & 0x0F) | ((pushbx >> 4) & 0xF0); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0C,temp); /* Overflow */ + + /* 2. Vertical setup */ + + tempcx = SiS_Pr->SiS_VGAVT - 1; + temp = tempcx & 0x00FF; + + if(HwInfo->jChipType < SIS_661) { + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) { + temp--; + } + } + } else { + temp--; + } + } else if(HwInfo->jChipType >= SIS_315H) { + temp--; + } + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0E,temp); /* CRT2 Vertical Total */ + + tempbx = SiS_Pr->SiS_VGAVDE - 1; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0F,tempbx); /* CRT2 Vertical Display Enable End */ + + temp = ((tempbx >> 5) & 0x38) | ((tempcx >> 8) & 0x07); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,temp); /* Overflow */ + + if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) { + tempbx++; + tempax = tempbx; + tempcx++; + tempcx -= tempax; + tempcx >>= 2; + tempbx += tempcx; + if(tempcx < 4) tempcx = 4; + tempcx >>= 2; + tempcx += tempbx; + tempcx++; + } else { + tempbx = (SiS_Pr->SiS_VGAVT + SiS_Pr->SiS_VGAVDE) >> 1; /* BTVGA2VRS 0x10,0x11 */ + tempcx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 4) + tempbx + 1; /* BTVGA2VRE 0x11 */ + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CVSyncStart; + tempcx = SiS_Pr->CVSyncEnd; + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + unsigned char cr8, cr7, cr13; + if(SiS_Pr->UseCustomMode) { + cr8 = SiS_Pr->CCRT1CRTC[8]; + cr7 = SiS_Pr->CCRT1CRTC[7]; + cr13 = SiS_Pr->CCRT1CRTC[13]; + tempcx = SiS_Pr->CCRT1CRTC[9]; + } else { + cr8 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[8]; + cr7 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7]; + cr13 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]; + tempcx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[9]; + } + tempbx = cr8; + if(cr7 & 0x04) tempbx |= 0x0100; + if(cr7 & 0x80) tempbx |= 0x0200; + if(cr13 & 0x08) tempbx |= 0x0400; + } + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,tempbx); /* CRT2 Vertical Retrace Start */ + + temp = ((tempbx >> 4) & 0x70) | (tempcx & 0x0F); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x11,temp); /* CRT2 Vert. Retrace End; Overflow */ + + /* 3. Panel delay compensation */ + + if(HwInfo->jChipType < SIS_315H) { + +#ifdef SIS300 /* ---------- 300 series -------------- */ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = 0x20; + if(HwInfo->jChipType == SIS_300) { + temp = 0x10; + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) temp = 0x2c; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) temp = 0x20; + } + if(SiS_Pr->SiS_VBType & VB_SIS301) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) temp = 0x20; + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x960) temp = 0x24; + if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) temp = 0x2c; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x08; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) temp = 0x2c; + else temp = 0x20; + } + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x80) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) + temp = ROMAddr[0x221]; + else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) + temp = ROMAddr[0x222]; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) + temp = ROMAddr[0x223]; + else + temp = ROMAddr[0x224]; + temp &= 0x3c; + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->PDC != -1) temp = SiS_Pr->PDC & 0x3c; + } + + } else { + temp = 0x20; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) temp = 0x04; + } + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x80) { + temp = ROMAddr[0x220] & 0x3c; + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->PDC != -1) temp = SiS_Pr->PDC & 0x3c; + } + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */ + +#endif /* SIS300 */ + + } else { + +#ifdef SIS315H /* --------------- 315/330 series ---------------*/ + + if(HwInfo->jChipType < SIS_661) { + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + + if(HwInfo->jChipType == SIS_740) temp = 0x03; + else temp = 0x00; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x0a; + tempbl = 0xF0; + if(HwInfo->jChipType == SIS_650) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempbl = 0x0F; + } + } + + if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) { + temp = 0x08; + tempbl = 0; + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + if(ROMAddr[0x13c] & 0x80) tempbl = 0xf0; + } + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,tempbl,temp); /* Panel Link Delay Compensation */ + } + + } /* < 661 */ + + tempax = 0; + if(modeflag & DoubleScanMode) tempax |= 0x80; + if(modeflag & HalfDCLK) tempax |= 0x40; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax); + +#endif /* SIS315H */ + + } + + } /* Slavemode */ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + /* For 301BDH with LCD, we set up the Panel Link */ + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SiS_SetGroup1_301(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + } + } else { + if(HwInfo->jChipType < SIS_315H) { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + } else { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex, HwInfo,RefreshRateTableIndex); + } + } else { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex, HwInfo,RefreshRateTableIndex); + } + } + } +} + +/*********************************************/ +/* SET PART 2 REGISTER GROUP */ +/*********************************************/ + +#ifdef SIS315H +static UCHAR * +SiS_GetGroup2CLVXPtr(SiS_Private *SiS_Pr, int tabletype, PSIS_HW_INFO HwInfo) +{ + const UCHAR *tableptr = NULL; + USHORT a, b, p = 0; + + a = SiS_Pr->SiS_VGAHDE; + b = SiS_Pr->SiS_HDE; + if(tabletype) { + a = SiS_Pr->SiS_VGAVDE; + b = SiS_Pr->SiS_VDE; + } + + if(a < b) { + tableptr = SiS_Part2CLVX_1; + } else if(a == b) { + tableptr = SiS_Part2CLVX_2; + } else { + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + tableptr = SiS_Part2CLVX_4; + } else { + tableptr = SiS_Part2CLVX_3; + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) tableptr = SiS_Part2CLVX_3; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) tableptr = SiS_Part2CLVX_3; + else tableptr = SiS_Part2CLVX_5; + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + tableptr = SiS_Part2CLVX_6; + } + do { + if((tableptr[p] | tableptr[p+1] << 8) == a) break; + p += 0x42; + } while((tableptr[p] | tableptr[p+1] << 8) != 0xffff); + if((tableptr[p] | tableptr[p+1] << 8) == 0xffff) p -= 0x42; + } + p += 2; + return((UCHAR *)&tableptr[p]); +} + +static void +SiS_SetGroup2_C_ELV(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +{ + UCHAR *tableptr; + int i, j; + UCHAR temp; + + if(!(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV))) return; + + tableptr = SiS_GetGroup2CLVXPtr(SiS_Pr, 0, HwInfo); + for(i = 0x80, j = 0; i <= 0xbf; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port, i, tableptr[j]); + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + tableptr = SiS_GetGroup2CLVXPtr(SiS_Pr, 1, HwInfo); + for(i = 0xc0, j = 0; i <= 0xff; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port, i, tableptr[j]); + } + } + temp = 0x10; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp |= 0x04; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4e,0xeb,temp); +} + +static BOOLEAN +SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, + USHORT RefreshRateTableIndex,USHORT *CRT2Index, + USHORT *ResIndex,PSIS_HW_INFO HwInfo) +{ + + if(HwInfo->jChipType < SIS_315H) return FALSE; + + if(ModeNo <= 0x13) + (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + else + (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + + (*ResIndex) &= 0x3f; + (*CRT2Index) = 0; + + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + (*CRT2Index) = 200; + } + } + + if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) (*CRT2Index) = 206; + } + } + return(((*CRT2Index) != 0)); +} +#endif + +#ifdef SIS300 +static void +SiS_Group2LCDSpecial(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT crt2crtc) +{ + USHORT tempcx; + const UCHAR atable[] = { + 0xc3,0x9e,0xc3,0x9e,0x02,0x02,0x02, + 0xab,0x87,0xab,0x9e,0xe7,0x02,0x02 + }; + + if(!SiS_Pr->UseCustomMode) { + if( ( ( (HwInfo->jChipType == SIS_630) || + (HwInfo->jChipType == SIS_730) ) && + (HwInfo->jChipRevision > 2) ) && + (SiS_Pr->SiS_LCDResInfo == Panel_1024x768) && + (!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) && + (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) { + if(ModeNo == 0x13) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xB9); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0xCC); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xA6); + } else { + if((crt2crtc & 0x3F) == 4) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x2B); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x13); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xE5); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0x08); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xE2); + } + } + } + + if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->SiS_LCDTypeInfo == 0x0c) { + crt2crtc &= 0x1f; + tempcx = 0; + if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + tempcx += 7; + } + } + tempcx += crt2crtc; + if(crt2crtc >= 4) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xff); + } + + if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(crt2crtc == 4) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x28); + } + } + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x18); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]); + } + } + } +} + +/* For ECS A907. Highly preliminary. */ +static void +SiS_Set300Part2Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + USHORT ModeNo) +{ + USHORT crt2crtc, resindex; + int i,j; + const SiS_Part2PortTblStruct *CRT2Part2Ptr = NULL; + + if(HwInfo->jChipType != SIS_300) return; + if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) return; + if(SiS_Pr->UseCustomMode) return; + + if(ModeNo <= 0x13) { + crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + resindex = crt2crtc & 0x3F; + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1; + else CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_2; + + /* The BIOS code (1.16.51,56) is obviously a fragment! */ + if(ModeNo > 0x13) { + CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1; + resindex = 4; + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,(CRT2Part2Ptr+resindex)->CR[0]); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x02,0x80,(CRT2Part2Ptr+resindex)->CR[1]); + for(i = 2, j = 0x04; j <= 0x06; i++, j++ ) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + } + for(j = 0x1c; j <= 0x1d; i++, j++ ) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + } + for(j = 0x1f; j <= 0x21; i++, j++ ) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,(CRT2Part2Ptr+resindex)->CR[10]); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0f,(CRT2Part2Ptr+resindex)->CR[11]); +} +#endif + +static void +SiS_SetTVSpecial(SiS_Private *SiS_Pr, USHORT ModeNo) +{ + if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) return; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision)) return; + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) return; + + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { + const UCHAR specialtv[] = { + 0xa7,0x07,0xf2,0x6e,0x17,0x8b,0x73,0x53, + 0x13,0x40,0x34,0xf4,0x63,0xbb,0xcc,0x7a, + 0x58,0xe4,0x73,0xda,0x13 + }; + int i, j; + for(i = 0x1c, j = 0; i <= 0x30; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,specialtv[j]); + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,0x72); + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750)) { + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x14); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1b); + } else { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x14); /* 15 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1a); /* 1b */ + } + } + } + } else { + if((ModeNo == 0x38) || (ModeNo == 0x4a) || (ModeNo == 0x64) || + (ModeNo == 0x52) || (ModeNo == 0x58) || (ModeNo == 0x5c)) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1b); /* 21 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x54); /* 5a */ + } else { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1a); /* 21 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x53); /* 5a */ + } + } +} + +static void +SiS_SetGroup2_Tail(SiS_Private *SiS_Pr, USHORT ModeNo) +{ + USHORT temp; + + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + if(SiS_Pr->SiS_VGAVDE == 525) { + temp = 0xc3; + if(SiS_Pr->SiS_ModeType <= ModeVGA) { + temp++; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp += 2; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,0xb3); + } else if(SiS_Pr->SiS_VGAVDE == 420) { + temp = 0x4d; + if(SiS_Pr->SiS_ModeType <= ModeVGA) { + temp++; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp++; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) { + if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { + SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x1a,0x03); + /* Not always for LV, see SetGrp2 */ + } + temp = 1; + if(ModeNo <= 0x13) temp = 3; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0b,temp); + } +#if 0 + /* 651+301C, for 1280x768 - do I really need that? */ + if((SiS_Pr->SiS_PanelXRes == 1280) && (SiS_Pr->SiS_PanelYRes == 768)) { + if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) { + if(((SiS_Pr->SiS_HDE == 640) && (SiS_Pr->SiS_VDE == 480)) || + ((SiS_Pr->SiS_HDE == 320) && (SiS_Pr->SiS_VDE == 240))) { + SiS_SetReg(SiS_Part2Port,0x01,0x2b); + SiS_SetReg(SiS_Part2Port,0x02,0x13); + SiS_SetReg(SiS_Part2Port,0x04,0xe5); + SiS_SetReg(SiS_Part2Port,0x05,0x08); + SiS_SetReg(SiS_Part2Port,0x06,0xe2); + SiS_SetReg(SiS_Part2Port,0x1c,0x21); + SiS_SetReg(SiS_Part2Port,0x1d,0x45); + SiS_SetReg(SiS_Part2Port,0x1f,0x0b); + SiS_SetReg(SiS_Part2Port,0x20,0x00); + SiS_SetReg(SiS_Part2Port,0x21,0xa9); + SiS_SetReg(SiS_Part2Port,0x23,0x0b); + SiS_SetReg(SiS_Part2Port,0x25,0x04); + } + } + } +#endif + } +} + +static void +SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT RefreshRateTableIndex, + PSIS_HW_INFO HwInfo) +{ + USHORT i, j, tempax, tempbx, tempcx, tempch, tempcl, temp; + USHORT push2, modeflag, crt2crtc, bridgeoffset; + ULONG longtemp; + const UCHAR *PhasePoint; + const UCHAR *TimingPoint; +#ifdef SIS315H + USHORT resindex, CRT2Index; + const SiS_Part2PortTblStruct *CRT2Part2Ptr = NULL; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return; +#endif + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + crt2crtc = 0; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + temp = 0; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToAVIDEO)) temp |= 0x08; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSVIDEO)) temp |= 0x04; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART) temp |= 0x02; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) temp |= 0x01; + + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) temp |= 0x10; + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x00,temp); + + PhasePoint = SiS_Pr->SiS_PALPhase; + TimingPoint = SiS_Pr->SiS_PALTiming; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + + TimingPoint = SiS_Pr->SiS_HiTVExtTiming; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + TimingPoint = SiS_Pr->SiS_HiTVSt2Timing; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + TimingPoint = SiS_Pr->SiS_HiTVSt1Timing; +#if 0 + if(!(modeflag & Charx8Dot)) TimingPoint = SiS_Pr->SiS_HiTVTextTiming; +#endif + } + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) TimingPoint = &SiS_YPbPrTable[2][0]; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) TimingPoint = &SiS_YPbPrTable[1][0]; + else TimingPoint = &SiS_YPbPrTable[0][0]; + + PhasePoint = SiS_Pr->SiS_NTSCPhase; + + } else if(SiS_Pr->SiS_TVMode & TVSetPAL) { + + if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && + ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || + (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { + PhasePoint = SiS_Pr->SiS_PALPhase2; + } + + } else { + + TimingPoint = SiS_Pr->SiS_NTSCTiming; + PhasePoint = SiS_Pr->SiS_NTSCPhase; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { + PhasePoint = SiS_Pr->SiS_PALPhase; + } + + if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && + ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || + (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { + PhasePoint = SiS_Pr->SiS_NTSCPhase2; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { + PhasePoint = SiS_Pr->SiS_PALPhase2; + } + } + + } + + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + PhasePoint = SiS_Pr->SiS_PALMPhase; + if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && + ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || + (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { + PhasePoint = SiS_Pr->SiS_PALMPhase2; + } + } + + if(SiS_Pr->SiS_TVMode & TVSetPALN) { + PhasePoint = SiS_Pr->SiS_PALNPhase; + if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && + ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || + (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { + PhasePoint = SiS_Pr->SiS_PALNPhase2; + } + } + + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { + PhasePoint = SiS_Pr->SiS_SpecialPhase; + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + PhasePoint = SiS_Pr->SiS_SpecialPhaseM; + } else if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { + PhasePoint = SiS_Pr->SiS_SpecialPhaseJ; + } + } + + for(i=0x31, j=0; i<=0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,PhasePoint[j]); + } + + for(i=0x01, j=0; i<=0x2D; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]); + } + for(i=0x39; i<=0x45; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]); + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_ModeType != ModeText) { + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x3A,0x1F); + } + } + + SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x0A,SiS_Pr->SiS_NewFlickerMode); + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x35,SiS_Pr->SiS_RY1COE); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x36,SiS_Pr->SiS_RY2COE); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x37,SiS_Pr->SiS_RY3COE); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x38,SiS_Pr->SiS_RY4COE); + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempax = 950; + else if(SiS_Pr->SiS_TVMode & TVSetPAL) tempax = 520; + else tempax = 440; /* NTSC, YPbPr 525, 750 */ + + if( ( (!(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision)) && (SiS_Pr->SiS_VDE <= tempax) ) || + ( (SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision) && + ((SiS_Pr->SiS_VGAHDE == 1024) || (SiS_Pr->SiS_VDE <= tempax)) ) ) { + + tempax -= SiS_Pr->SiS_VDE; + tempax >>= 2; + tempax &= 0x00ff; + + temp = tempax + (USHORT)TimingPoint[0]; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp); + + temp = tempax + (USHORT)TimingPoint[1]; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp); + + if((SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) && (SiS_Pr->SiS_VGAHDE >= 1024)) { + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1b); /* 19 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x54); /* 52 */ + } else { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x17); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1d); + } + } + + } + + tempcx = SiS_Pr->SiS_HT; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1; + tempcx--; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) tempcx--; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1B,tempcx); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0xF0,((tempcx >> 8) & 0x0f)); + + tempcx = SiS_Pr->SiS_HT >> 1; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1; + tempcx += 7; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempcx -= 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x22,0x0F,((tempcx << 4) & 0xf0)); + + tempbx = TimingPoint[j] | (TimingPoint[j+1] << 8); + tempbx += tempcx; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x24,tempbx); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0F,((tempbx >> 4) & 0xf0)); + + tempbx += 8; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + tempbx -= 4; + tempcx = tempbx; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x29,0x0F,((tempbx << 4) & 0xf0)); + + j += 2; + tempcx += (TimingPoint[j] | (TimingPoint[j+1] << 8)); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x27,tempcx); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x28,0x0F,((tempcx >> 4) & 0xf0)); + + tempcx += 8; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempcx -= 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2A,0x0F,((tempcx << 4) & 0xf0)); + + tempcx = SiS_Pr->SiS_HT >> 1; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1; + j += 2; + tempcx -= (TimingPoint[j] | ((TimingPoint[j+1]) << 8)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2D,0x0F,((tempcx << 4) & 0xf0)); + + tempcx -= 11; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + tempcx = SiS_GetVGAHT2(SiS_Pr) - 1; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2E,tempcx); + + tempbx = SiS_Pr->SiS_VDE; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_VGAVDE == 360) tempbx = 746; + if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 746; + if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 853; + } else if( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && + (!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p|TVSetYPbPr750p))) ) { + tempbx >>= 1; + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + if((ModeNo <= 0x13) && (crt2crtc == 1)) tempbx++; + } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_ModeType <= ModeVGA) { + if(crt2crtc == 4) tempbx++; + } + } + } + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if((ModeNo == 0x2f) || (ModeNo == 0x5d) || (ModeNo == 0x5e)) tempbx++; + } + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + if(ModeNo == 0x03) tempbx++; /* From 1.10.7w - doesn't make sense */ + } + } + } + tempbx -= 2; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2F,tempbx); + + temp = (tempcx >> 8) & 0x0F; + temp |= ((tempbx >> 2) & 0xC0); + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) { + temp |= 0x10; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToAVIDEO) temp |= 0x20; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,temp); + + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,0xdf,((tempbx & 0x0400) >> 5)); + } + +#if 0 + /* TEST qqqq */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + for(i=0x01, j=0; i<=0x2D; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]); + } + for(i=0x39; i<=0x45; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]); + } + } +#endif + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + tempbx = SiS_Pr->SiS_VDE; + if( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && + (!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p))) ) { + tempbx >>= 1; + } + tempbx -= 3; + temp = ((tempbx >> 3) & 0x60) | 0x18; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x46,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x47,tempbx); + + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,0xbf,((tempbx & 0x0400) >> 4)); + } + } + + tempbx = 0; + if(!(modeflag & HalfDCLK)) { + if(SiS_Pr->SiS_VGAHDE >= SiS_Pr->SiS_HDE) { + tempax = 0; + tempbx |= 0x20; + } + } + + tempch = tempcl = 0x01; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_VGAHDE >= 1024) { + if((!(modeflag & HalfDCLK)) || (HwInfo->jChipType < SIS_315H)) { + tempch = 0x19; + tempcl = 0x20; + if(SiS_Pr->SiS_VGAHDE >= 1280) { + tempch = 0x14; + tempbx &= ~0x20; + } + } + } + } + + if(!(tempbx & 0x20)) { + if(modeflag & HalfDCLK) tempcl <<= 1; + longtemp = ((SiS_Pr->SiS_VGAHDE * tempch) / tempcl) << 13; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) longtemp <<= 3; + tempax = longtemp / SiS_Pr->SiS_HDE; + if(longtemp % SiS_Pr->SiS_HDE) tempax++; + tempbx |= ((tempax >> 8) & 0x1F); + tempcx = tempax >> 13; + } + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x44,tempax); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x45,0xC0,tempbx); + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + + tempcx &= 0x07; + if(tempbx & 0x20) tempcx = 0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x46,0xF8,tempcx); + + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + tempbx = 0x0382; + tempcx = 0x007e; + } else { + tempbx = 0x0369; + tempcx = 0x0061; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4B,tempbx); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4C,tempcx); + temp = (tempcx & 0x0300) >> 6; + temp |= ((tempbx >> 8) & 0x03); + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + temp |= 0x10; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) temp |= 0x20; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) temp |= 0x40; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4D,temp); + + temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x43); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,(temp - 3)); + + SiS_SetTVSpecial(SiS_Pr, ModeNo); + + if(SiS_Pr->SiS_VBType & VB_SIS301C) { + temp = 0; + if(SiS_Pr->SiS_TVMode & TVSetPALM) temp = 8; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4e,0xf7,temp); + } + + } + + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + if(!(SiS_Pr->SiS_TVMode & TVSetNTSC1024)) { + temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x01); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,(temp - 1)); + } + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xEF); + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0B,0x00); + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) return; + + /* From here: Part2 LCD setup */ + + tempbx = SiS_Pr->SiS_HDE; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; + tempbx--; /* RHACTE = HDE - 1 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2C,tempbx); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2B,0x0F,((tempbx >> 4) & 0xf0)); + + temp = 0x01; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if(SiS_Pr->SiS_ModeType == ModeEGA) { + if(SiS_Pr->SiS_VGAHDE >= 1024) { + temp = 0x02; + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + temp = 0x01; + } + } + } + } + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0B,temp); + + tempbx = SiS_Pr->SiS_VDE - 1; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x03,tempbx); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0C,0xF8,((tempbx >> 8) & 0x07)); + + tempcx = SiS_Pr->SiS_VT - 1; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x19,tempcx); + temp = (tempcx >> 3) & 0xE0; + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { + /* Enable dithering; only do this for 32bpp mode */ + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) { + temp |= 0x10; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1A,0x0f,temp); + + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x09,0xF0); + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x0A,0xF0); + + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x17,0xFB); + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x18,0xDF); + +#ifdef SIS315H + if(SiS_GetCRT2Part2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, + &CRT2Index, &resindex, HwInfo)) { + switch(CRT2Index) { + case 200: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1; break; + case 206: CRT2Part2Ptr = SiS310_CRT2Part2_Asus1024x768_3; break; + default: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3; break; + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,(CRT2Part2Ptr+resindex)->CR[0]); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x02,0x80,(CRT2Part2Ptr+resindex)->CR[1]); + for(i = 2, j = 0x04; j <= 0x06; i++, j++ ) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + } + for(j = 0x1c; j <= 0x1d; i++, j++ ) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + } + for(j = 0x1f; j <= 0x21; i++, j++ ) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,(CRT2Part2Ptr+resindex)->CR[10]); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0f,(CRT2Part2Ptr+resindex)->CR[11]); + + SiS_SetGroup2_Tail(SiS_Pr, ModeNo); + + + } else { +#endif + + /* Checked for 1024x768, 1280x1024, 1400x1050, 1600x1200 */ + /* Clevo dual-link 1024x768 */ + /* Compaq 1280x1024 has HT 1696 sometimes (calculation OK, if given HT is correct) */ + /* Acer: OK, but uses different setting for VESA timing at 640/800/1024 and 640x400 */ + + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if((SiS_Pr->SiS_LCDInfo & LCDPass11) || (SiS_Pr->PanelYRes == SiS_Pr->SiS_VDE)) { + tempbx = SiS_Pr->SiS_VDE - 1; + tempcx = SiS_Pr->SiS_VT - 1; + } else { + tempbx = SiS_Pr->SiS_VDE + ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VDE) / 2); + tempcx = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VDE) / 2); + } + } else { + tempbx = SiS_Pr->PanelYRes; + tempcx = SiS_Pr->SiS_VT; + tempax = 1; + if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) { + tempax = SiS_Pr->PanelYRes; + /* if(SiS_Pr->SiS_VGAVDE == 525) tempax += 0x3c; */ /* 651+301C */ + if(SiS_Pr->PanelYRes < SiS_Pr->SiS_VDE) { + tempax = tempcx = 0; + } else { + tempax -= SiS_Pr->SiS_VDE; + } + tempax >>= 1; + } + tempcx -= tempax; /* lcdvdes */ + tempbx -= tempax; /* lcdvdee */ + } + + /* Non-expanding: lcdvdes = tempcx = VT-1; lcdvdee = tempbx = VDE-1 */ + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "lcdvdes 0x%x lcdvdee 0x%x\n", tempcx, tempbx); +#endif + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,tempcx); /* lcdvdes */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,tempbx); /* lcdvdee */ + + temp = (tempbx >> 5) & 0x38; + temp |= ((tempcx >> 8) & 0x07); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp); + + tempax = SiS_Pr->SiS_VDE; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + tempax = SiS_Pr->PanelYRes; + } + tempcx = (SiS_Pr->SiS_VT - tempax) >> 4; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) { + tempcx = (SiS_Pr->SiS_VT - tempax) / 10; + } + } + + tempbx = ((SiS_Pr->SiS_VT + SiS_Pr->SiS_VDE) >> 1) - 1; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { /* ? */ + tempax = SiS_Pr->SiS_VT - SiS_Pr->PanelYRes; + if(tempax % 4) { tempax >>= 2; tempax++; } + else { tempax >>= 2; } + tempbx -= (tempax - 1); + } else { + tempbx -= 10; + if(tempbx <= SiS_Pr->SiS_VDE) tempbx = SiS_Pr->SiS_VDE + 1; + } + } + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + tempbx++; + if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (crt2crtc == 6)) { + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + tempbx = 770; + tempcx = 3; + } + } + } + + /* non-expanding: lcdvrs = ((VT + VDE) / 2) - 10 */ + + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CVSyncStart; + } + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "lcdvrs 0x%x\n", tempbx); +#endif + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,tempbx); /* lcdvrs */ + + temp = (tempbx >> 4) & 0xF0; + tempbx += (tempcx + 1); + temp |= (tempbx & 0x0F); + + if(SiS_Pr->UseCustomMode) { + temp &= 0xf0; + temp |= (SiS_Pr->CVSyncEnd & 0x0f); + } + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "lcdvre[3:0] 0x%x\n", (temp & 0x0f)); +#endif + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp); + +#ifdef SIS300 + SiS_Group2LCDSpecial(SiS_Pr, HwInfo, ModeNo, crt2crtc); +#endif + + bridgeoffset = 7; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) bridgeoffset += 2; + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) bridgeoffset++; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) bridgeoffset++; + + temp = 0; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) { + temp = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2); + if(SiS_IsDualLink(SiS_Pr, HwInfo)) temp >>= 1; + } + } + temp += bridgeoffset; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1F,temp); /* lcdhdes */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x20,0x0F,((temp >> 4) & 0xf0)); + + tempcx = SiS_Pr->SiS_HT; + tempax = tempbx = SiS_Pr->SiS_HDE; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) { + tempax = SiS_Pr->PanelXRes; + tempbx = SiS_Pr->PanelXRes - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2); + } + } + if(SiS_IsDualLink(SiS_Pr, HwInfo)) { + tempcx >>= 1; + tempbx >>= 1; + tempax >>= 1; + } + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "lcdhdee 0x%x\n", tempbx); +#endif + + tempbx += bridgeoffset; + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,tempbx); /* lcdhdee */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0xF0,((tempbx >> 8) & 0x0f)); + + tempcx = (tempcx - tempax) >> 2; + + tempbx += tempcx; + push2 = tempbx; + + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + if(SiS_Pr->SiS_HDE == 1280) tempbx = (tempbx & 0xff00) | 0x47; + } + } + } + + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CHSyncStart; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; + tempbx += bridgeoffset; + } + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "lcdhrs 0x%x\n", tempbx); +#endif + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1C,tempbx); /* lcdhrs */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0x0F,((tempbx >> 4) & 0xf0)); + + tempbx = push2; + + tempcx <<= 1; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) tempcx >>= 2; + } + tempbx += tempcx; + + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CHSyncEnd; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; + tempbx += bridgeoffset; + } + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "lcdhre 0x%x\n", tempbx); +#endif + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,tempbx); /* lcdhre */ + + SiS_SetGroup2_Tail(SiS_Pr, ModeNo); + +#ifdef SIS300 + SiS_Set300Part2Regs(SiS_Pr, HwInfo, ModeIdIndex, RefreshRateTableIndex, ModeNo); +#endif +#ifdef SIS315H + } /* CRT2-LCD from table */ +#endif +} + +/*********************************************/ +/* SET PART 3 REGISTER GROUP */ +/*********************************************/ + +static void +SiS_SetGroup3(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo) +{ + USHORT i; + const UCHAR *tempdi; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return; + +#ifndef SIS_CP + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x00,0x00); +#else + SIS_CP_INIT301_CP +#endif + + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x13,0xFA); + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x14,0xC8); + } else { + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x13,0xF5); + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x14,0xB7); + } + + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x13,0xFA); + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x14,0xC8); + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x3D,0xA8); + } + + tempdi = NULL; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + tempdi = SiS_Pr->SiS_HiTVGroup3Data; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + tempdi = SiS_Pr->SiS_HiTVGroup3Simu; + } + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(!(SiS_Pr->SiS_TVMode & TVSetYPbPr525i)) { + tempdi = SiS_HiTVGroup3_1; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempdi = SiS_HiTVGroup3_2; + } + } + if(tempdi) { + for(i=0; i<=0x3E; i++) { + SiS_SetReg(SiS_Pr->SiS_Part3Port,i,tempdi[i]); + } + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x28,0x3f); + } + } + } + +#ifdef SIS_CP + SIS_CP_INIT301_CP2 +#endif +} + +/*********************************************/ +/* SET PART 4 REGISTER GROUP */ +/*********************************************/ + +#ifdef SIS315H +static void +SiS_ShiftXPos(SiS_Private *SiS_Pr, int shift) +{ + USHORT temp, temp1, temp2; + + temp1 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x1f); + temp2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x20); + temp = (USHORT)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1f,temp); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x20,0x0f,((temp >> 4) & 0xf0)); + temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x2b) & 0x0f; + temp = (USHORT)((int)(temp) + shift); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2b,0xf0,(temp & 0x0f)); + temp1 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x43); + temp2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x42); + temp = (USHORT)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,temp); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x42,0x0f,((temp >> 4) & 0xf0)); +} + +static void +SiS_SetGroup4_C_ELV(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT temp, temp1, resinfo = 0; + + if(!(SiS_Pr->SiS_VBType & VB_SIS301C)) return; + if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToHiVision | SetCRT2ToYPbPr525750))) return; + + if(ModeNo > 0x13) { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3a,0x08); + temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x3a); + if(!(temp & 0x01)) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x3a,0xdf); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x25,0xfc); + if((HwInfo->jChipType < SIS_661) && (!(SiS_Pr->SiS_ROMNew))) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x25,0xf8); + } + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x0f,0xfb); + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) temp = 0x0000; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) temp = 0x0002; + else if(SiS_Pr->SiS_TVMode & TVSetHiVision) temp = 0x0400; + else temp = 0x0402; + if((HwInfo->jChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { + temp1 = 0; + if(SiS_Pr->SiS_TVMode & TVAspect43) temp1 = 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0f,0xfb,temp1); + if(SiS_Pr->SiS_TVMode & TVAspect43LB) temp |= 0x01; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0x7c,(temp & 0xff)); + } else { + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x3b) & 0x03; + if(temp1 == 0x01) temp |= 0x01; + if(temp1 == 0x03) temp |= 0x04; /* ? why not 0x10? */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xf8,(temp & 0xff)); + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0xfb,(temp >> 8)); + if(ModeNo > 0x13) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x3b,0xfd); + } + + if(HwInfo->jChipType >= SIS_661) { /* ? */ + if(SiS_Pr->SiS_TVMode & TVAspect43) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + if(resinfo == SIS_RI_1024x768) { + SiS_ShiftXPos(SiS_Pr, 97); + } else { + SiS_ShiftXPos(SiS_Pr, 111); + } + } else if(SiS_Pr->SiS_TVMode & TVSetHiVision) { + SiS_ShiftXPos(SiS_Pr, 136); + } + } + } + } +} +#endif + +static void +SiS_SetCRT2VCLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +{ + USHORT vclkindex; + USHORT temp, reg1, reg2; + + if(SiS_Pr->UseCustomMode) { + reg1 = SiS_Pr->CSR2B; + reg2 = SiS_Pr->CSR2C; + } else { + vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, + HwInfo); + reg1 = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_A; + reg2 = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_B; + } + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,0x57); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0b,0x46); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1f,0xf6); + } else { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,reg1); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0b,reg2); + } + } else { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,0x01); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0b,reg2); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,reg1); + } + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x12,0x00); + temp = 0x08; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) temp |= 0x20; + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x12,temp); +} + +static void +SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +{ + USHORT tempax,tempcx,tempbx,modeflag,temp,resinfo; + ULONG tempebx,tempeax,templong; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + resinfo = 0; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x24,0x0e); + } + } + } + + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV)) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x10,0x9f); + } + } + + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_IsDualLink(SiS_Pr, HwInfo)) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c); + } else { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,~0x20); + } + + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00); +#ifdef SET_EMI + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); +#endif + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); + } + } + return; + } + } + + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x13,SiS_Pr->SiS_RVBHCFACT); + + tempbx = SiS_Pr->SiS_RVBHCMAX; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x14,tempbx); + + temp = (tempbx >> 1) & 0x80; + + tempcx = SiS_Pr->SiS_VGAHT - 1; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x16,tempcx); + + temp |= ((tempcx >> 5) & 0x78); + + tempcx = SiS_Pr->SiS_VGAVT - 1; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempcx -= 5; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x17,tempcx); + + temp |= ((tempcx >> 8) & 0x07); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x15,temp); + + tempbx = SiS_Pr->SiS_VGAHDE; + if(modeflag & HalfDCLK) tempbx >>= 1; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + temp = 0; + if(tempbx > 800) temp = 0x60; + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + temp = 0; + if(tempbx == 1024) temp = 0xA0; + else if(tempbx > 1024) temp = 0xC0; + } else if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) { + temp = 0; + if(tempbx >= 1280) temp = 0x40; + else if(tempbx >= 1024) temp = 0x20; + } else { + temp = 0x80; + if(tempbx >= 1024) temp = 0xA0; + } + + if(SiS_Pr->SiS_VBType & VB_SIS301) { + if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) temp |= 0x0A; + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0E,0x10,temp); + + tempeax = SiS_Pr->SiS_VGAVDE; + tempebx = SiS_Pr->SiS_VDE; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(!(temp & 0xE0)) tempebx >>=1; + } + + tempcx = SiS_Pr->SiS_RVBHRS; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x18,tempcx); + tempcx >>= 8; + tempcx |= 0x40; + + if(tempeax <= tempebx) { + tempcx ^= 0x40; + } else { + tempeax -= tempebx; + } + + tempeax *= (256 * 1024); + templong = tempeax % tempebx; + tempeax /= tempebx; + if(templong) tempeax++; + + temp = (USHORT)(tempeax & 0x000000FF); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1B,temp); + temp = (USHORT)((tempeax & 0x0000FF00) >> 8); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1A,temp); + temp = (USHORT)((tempeax >> 12) & 0x70); /* sic! */ + temp |= (tempcx & 0x4F); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x19,temp); + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1C,0x28); + + /* Calc Linebuffer max address and set/clear decimode */ + tempbx = 0; + if(SiS_Pr->SiS_TVMode & (TVSetHiVision | TVSetYPbPr750p)) tempbx = 0x08; + tempax = SiS_Pr->SiS_VGAHDE; + if(modeflag & HalfDCLK) tempax >>= 1; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempax >>= 1; + if(tempax > 800) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + tempax -= 800; + } else { /* 651+301C: Only if TVNoHiviNoYPbPr */ + tempbx = 0x08; + if(tempax == 1024) tempax *= 25; + else tempax *= 20; + temp = tempax % 32; + tempax /= 32; + if(temp) tempax++; + tempax++; + if((SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) || + (SiS_Pr->SiS_TVMode & TVSetYPbPr525i)) { + if(resinfo == SIS_RI_1024x768) { + /* Otherwise white line at right edge */ + tempax = (tempax & 0xff00) | 0x20; + } + } + } + } + tempax--; + temp = ((tempax >> 4) & 0x30) | tempbx; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1D,tempax); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1E,temp); + + temp = 0x0036; tempbx = 0xD0; + if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { + temp = 0x0026; tempbx = 0xC0; /* See En/DisableBridge() */ + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(!(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSetHiVision | TVSetYPbPr750p | TVSetYPbPr525p))) { + temp |= 0x01; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) { + temp &= ~0x01; + } + } + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x1F,tempbx,temp); + + tempbx = SiS_Pr->SiS_HT >> 1; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; + tempbx -= 2; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x22,tempbx); + temp = (tempbx >> 5) & 0x38; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0xC0,temp); + + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x24,0x0e); + /* LCD-too-dark-error-source, see FinalizeLCD() */ + } + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_IsDualLink(SiS_Pr, HwInfo)) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c); + } else { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,~0x20); + } + } + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00); +#ifdef SET_EMI + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); +#endif + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); + } + } + + } /* 301B */ + + SiS_SetCRT2VCLK(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); +} + +/*********************************************/ +/* SET PART 5 REGISTER GROUP */ +/*********************************************/ + +static void +SiS_SetGroup5(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo) +{ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return; + + if(SiS_Pr->SiS_ModeType == ModeVGA) { + if(!(SiS_Pr->SiS_VBInfo & (SetInSlaveMode | LoadDACFlag))) { + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); + SiS_LoadDAC(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); + } + } +} + +/*********************************************/ +/* MODIFY CRT1 GROUP FOR SLAVE MODE */ +/*********************************************/ + +static void +SiS_ModCRT1CRTC(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +{ + USHORT tempah,i,modeflag,j; + USHORT ResIndex,DisplayType; + const SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL; + + if(ModeNo <= 0x13) modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + else modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848)) + return; + + if(!(SiS_GetLVDSCRT1Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, + &ResIndex, &DisplayType))) { + return; + } + + if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->SiS_SetFlag & SetDOSMode) return; + } + + switch(DisplayType) { + case 0 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1; break; + case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H; break; + case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2; break; + case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H; break; + case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1; break; + case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H; break; + case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2; break; + case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H; break; + case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1; break; + case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H; break; + case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2; break; + case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2_H; break; + case 12: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1; break; + case 13: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H; break; + case 14: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1; break; + case 15: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1_H; break; + case 16: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2; break; + case 17: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2_H; break; + case 18: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UNTSC; break; + case 19: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1ONTSC; break; + case 20: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UPAL; break; + case 21: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1OPAL; break; + case 22: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x480_1; break; /* FSTN */ + case 23: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1; break; + case 24: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1_H; break; + case 25: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2; break; + case 26: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2_H; break; + case 27: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1; break; + case 28: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1_H; break; + case 29: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2; break; + case 30: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2_H; break; + case 36: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1; break; + case 37: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1_H; break; + case 38: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2; break; + case 39: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2_H; break; + case 40: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x768_1; break; + case 41: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x768_1_H; break; + case 42: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x768_2; break; + case 43: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x768_2_H; break; + case 50: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_1; break; + case 51: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_1_H; break; + case 52: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_2; break; + case 53: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_2_H; break; + case 54: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_3; break; + case 55: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_3_H; break; + case 99: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1SOPAL; break; + default: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1; break; + } + + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); + + tempah = (LVDSCRT1Ptr + ResIndex)->CR[0]; + SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,tempah); + + for(i=0x02,j=1;i<=0x05;i++,j++){ + tempah = (LVDSCRT1Ptr + ResIndex)->CR[j]; + SiS_SetReg(SiS_Pr->SiS_P3d4,i,tempah); + } + for(i=0x06,j=5;i<=0x07;i++,j++){ + tempah = (LVDSCRT1Ptr + ResIndex)->CR[j]; + SiS_SetReg(SiS_Pr->SiS_P3d4,i,tempah); + } + for(i=0x10,j=7;i<=0x11;i++,j++){ + tempah = (LVDSCRT1Ptr + ResIndex)->CR[j]; + SiS_SetReg(SiS_Pr->SiS_P3d4,i,tempah); + } + for(i=0x15,j=9;i<=0x16;i++,j++){ + tempah = (LVDSCRT1Ptr + ResIndex)->CR[j]; + SiS_SetReg(SiS_Pr->SiS_P3d4,i,tempah); + } + for(i=0x0A,j=11;i<=0x0C;i++,j++){ + tempah = (LVDSCRT1Ptr + ResIndex)->CR[j]; + SiS_SetReg(SiS_Pr->SiS_P3c4,i,tempah); + } + + tempah = (LVDSCRT1Ptr + ResIndex)->CR[14]; + tempah &= 0xE0; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1f,tempah); + + tempah = (LVDSCRT1Ptr + ResIndex)->CR[14]; + tempah &= 0x01; + tempah <<= 5; + if(modeflag & DoubleScanMode) tempah |= 0x080; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah); +} + +/*********************************************/ +/* SET CRT2 ECLK */ +/*********************************************/ + +static void +SiS_SetCRT2ECLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT clkbase, vclkindex=0; + UCHAR sr2b, sr2c; + + if((SiS_Pr->SiS_LCDResInfo == Panel_640x480) || (SiS_Pr->SiS_LCDInfo & LCDPass11)) { + SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); + if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK & 0x3f) == 2) { + RefreshRateTableIndex--; + } + vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwInfo); + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + } else { + vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwInfo); + } + + sr2b = SiS_Pr->SiS_VCLKData[vclkindex].SR2B; + sr2c = SiS_Pr->SiS_VCLKData[vclkindex].SR2C; + + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x01) { + sr2b = ROMAddr[0x227]; + sr2c = ROMAddr[0x228]; + } + } + } + + clkbase = 0x02B; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + clkbase += 3; + } + } + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x20); + SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase,sr2b); + SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase+1,sr2c); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x10); + SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase,sr2b); + SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase+1,sr2c); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x00); + SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase,sr2b); + SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase+1,sr2c); +} + +/*********************************************/ +/* SET UP CHRONTEL CHIPS */ +/*********************************************/ + +static void +SiS_SetCHTVReg(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ +#if defined(SIS300) || defined(SIS315H) + USHORT temp, tempbx; +#endif + USHORT tempcl; + USHORT TVType, resindex; + const SiS_CHTVRegDataStruct *CHTVRegData = NULL; + + if(ModeNo <= 0x13) + tempcl = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + else + tempcl = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + + TVType = 0; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + TVType += 2; + if(SiS_Pr->SiS_ModeType > ModeVGA) { + if(SiS_Pr->SiS_CHSOverScan) TVType = 8; + } + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + TVType = 4; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; + } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { + TVType = 6; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; + } + } + switch(TVType) { + case 0: CHTVRegData = SiS_Pr->SiS_CHTVReg_UNTSC; break; + case 1: CHTVRegData = SiS_Pr->SiS_CHTVReg_ONTSC; break; + case 2: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPAL; break; + case 3: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL; break; + case 4: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALM; break; + case 5: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALM; break; + case 6: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALN; break; + case 7: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALN; break; + case 8: CHTVRegData = SiS_Pr->SiS_CHTVReg_SOPAL; break; + default: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL; break; + } + resindex = tempcl & 0x3F; + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { + +#ifdef SIS300 + + /* Chrontel 7005 - I assume that it does not come with a 315 series chip */ + + /* We don't support modes >800x600 */ + if (resindex > 5) return; + + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + SiS_SetCH700x(SiS_Pr,0x4304); /* 0x40=76uA (PAL); 0x03=15bit non-multi RGB*/ + SiS_SetCH700x(SiS_Pr,0x6909); /* Black level for PAL (105)*/ + } else { + SiS_SetCH700x(SiS_Pr,0x0304); /* upper nibble=71uA (NTSC), 0x03=15bit non-multi RGB*/ + SiS_SetCH700x(SiS_Pr,0x7109); /* Black level for NTSC (113)*/ + } + + temp = CHTVRegData[resindex].Reg[0]; + tempbx=((temp&0x00FF)<<8)|0x00; /* Mode register */ + SiS_SetCH700x(SiS_Pr,tempbx); + temp = CHTVRegData[resindex].Reg[1]; + tempbx=((temp&0x00FF)<<8)|0x07; /* Start active video register */ + SiS_SetCH700x(SiS_Pr,tempbx); + temp = CHTVRegData[resindex].Reg[2]; + tempbx=((temp&0x00FF)<<8)|0x08; /* Position overflow register */ + SiS_SetCH700x(SiS_Pr,tempbx); + temp = CHTVRegData[resindex].Reg[3]; + tempbx=((temp&0x00FF)<<8)|0x0A; /* Horiz Position register */ + SiS_SetCH700x(SiS_Pr,tempbx); + temp = CHTVRegData[resindex].Reg[4]; + tempbx=((temp&0x00FF)<<8)|0x0B; /* Vertical Position register */ + SiS_SetCH700x(SiS_Pr,tempbx); + + /* Set minimum flicker filter for Luma channel (SR1-0=00), + minimum text enhancement (S3-2=10), + maximum flicker filter for Chroma channel (S5-4=10) + =00101000=0x28 (When reading, S1-0->S3-2, and S3-2->S1-0!) + */ + SiS_SetCH700x(SiS_Pr,0x2801); + + /* Set video bandwidth + High bandwith Luma composite video filter(S0=1) + low bandwith Luma S-video filter (S2-1=00) + disable peak filter in S-video channel (S3=0) + high bandwidth Chroma Filter (S5-4=11) + =00110001=0x31 + */ + SiS_SetCH700x(SiS_Pr,0xb103); /* old: 3103 */ + + /* Register 0x3D does not exist in non-macrovision register map + (Maybe this is a macrovision register?) + */ +#ifndef SIS_CP + SiS_SetCH70xx(SiS_Pr,0x003D); +#endif + + /* Register 0x10 only contains 1 writable bit (S0) for sensing, + all other bits a read-only. Macrovision? + */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0010,0x1F); + + /* Register 0x11 only contains 3 writable bits (S0-S2) for + contrast enhancement (set to 010 -> gain 1 Yout = 17/16*(Yin-30) ) + */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0211,0xF8); + + /* Clear DSEN + */ + SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xEF); + + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { /* ---- NTSC ---- */ + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) { + if(resindex == 0x04) { /* 640x480 overscan: Mode 16 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE); /* ACIV on, no need to set FSCI */ + } else if(resindex == 0x05) { /* 800x600 overscan: Mode 23 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0); /* 0x18-0x1f: FSCI 469,762,048 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0C19,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x001A,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x001B,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x001D,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x001E,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x001F,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x0120,0xEF); /* Loop filter on for mode 23 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE); /* ACIV off, need to set FSCI */ + } + } else { + if(resindex == 0x04) { /* ----- 640x480 underscan; Mode 17 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE); + } else if(resindex == 0x05) { /* ----- 800x600 underscan: Mode 24 */ +#if 0 + SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0); /* (FSCI was 0x1f1c71c7 - this is for mode 22) */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0919,0xF0); /* FSCI for mode 24 is 428,554,851 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x081A,0xF0); /* 198b3a63 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0b1B,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x041C,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x011D,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x061E,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x051F,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); /* loop filter off for mode 24 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE); /* ACIV off, need to set FSCI */ +#endif /* All alternatives wrong (datasheet wrong?), don't use FSCI */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE); + } + } + } else { /* ---- PAL ---- */ + /* We don't play around with FSCI in PAL mode */ + if(resindex == 0x04) { + SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE); /* ACIV on */ + } else { + SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE); /* ACIV on */ + } + } + +#endif /* 300 */ + + } else { + + /* Chrontel 7019 - assumed that it does not come with a 300 series chip */ + +#ifdef SIS315H + + /* We don't support modes >1024x768 */ + if (resindex > 6) return; + + temp = CHTVRegData[resindex].Reg[0]; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { + temp |= 0x10; + } + tempbx=((temp & 0x00FF) << 8) | 0x00; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[1]; + tempbx=((temp & 0x00FF) << 8) | 0x01; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[2]; + tempbx=((temp & 0x00FF) << 8) | 0x02; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[3]; + tempbx=((temp & 0x00FF) << 8) | 0x04; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[4]; + tempbx=((temp & 0x00FF) << 8) | 0x03; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[5]; + tempbx=((temp & 0x00FF) << 8) | 0x05; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[6]; + tempbx=((temp & 0x00FF) << 8) | 0x06; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[7]; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { + temp = 0x66; + } + tempbx=((temp & 0x00FF) << 8) | 0x07; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[8]; + tempbx=((temp & 0x00FF) << 8) | 0x08; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[9]; + tempbx=((temp & 0x00FF) << 8) | 0x15; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[10]; + tempbx=((temp & 0x00FF) << 8) | 0x1f; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[11]; + tempbx=((temp & 0x00FF) << 8) | 0x0c; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[12]; + tempbx=((temp & 0x00FF) << 8) | 0x0d; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[13]; + tempbx=((temp & 0x00FF) << 8) | 0x0e; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[14]; + tempbx=((temp & 0x00FF) << 8) | 0x0f; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = CHTVRegData[resindex].Reg[15]; + tempbx=((temp & 0x00FF) << 8) | 0x10; + SiS_SetCH701x(SiS_Pr,tempbx); + + temp = SiS_GetCH701x(SiS_Pr,0x21) & ~0x02; + /* D1 should be set for PAL, PAL-N and NTSC-J, + but I won't do that for PAL unless somebody + tells me to do so. Since the BIOS uses + non-default CIV values and blacklevels, + this might be compensated anyway. + */ + if(SiS_Pr->SiS_TVMode & (TVSetPALN | TVSetNTSCJ)) temp |= 0x02; + SiS_SetCH701x(SiS_Pr,((temp << 8) | 0x21)); + +#endif /* 315 */ + + } + +#ifdef SIS_CP + SIS_CP_INIT301_CP3 +#endif + +} + +void +SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT temp; + + /* Enable Chrontel 7019 LCD panel backlight */ + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(HwInfo->jChipType == SIS_740) { + SiS_SetCH701x(SiS_Pr,0x6566); + } else { + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp |= 0x20; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66); + } + } +} + +void +SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr) +{ + USHORT temp; + + /* Disable Chrontel 7019 LCD panel backlight */ + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp &= 0xDF; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66); + } +} + +#ifdef SIS315H /* ----------- 315 series only ---------- */ + +static void +SiS_ChrontelPowerSequencing(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR regtable[] = { 0x67, 0x68, 0x69, 0x6a, 0x6b }; + UCHAR table1024_740[] = { 0x01, 0x02, 0x01, 0x01, 0x01 }; + UCHAR table1400_740[] = { 0x01, 0x6e, 0x01, 0x01, 0x01 }; + UCHAR asus1024_740[] = { 0x19, 0x6e, 0x01, 0x19, 0x09 }; + UCHAR asus1400_740[] = { 0x19, 0x6e, 0x01, 0x19, 0x09 }; + UCHAR table1024_650[] = { 0x01, 0x02, 0x01, 0x01, 0x02 }; + UCHAR table1400_650[] = { 0x01, 0x02, 0x01, 0x01, 0x02 }; + UCHAR *tableptr = NULL; + int i; + + /* Set up Power up/down timing */ + + if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1024_740; + else tableptr = table1024_740; + } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || + (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200)) { + if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1400_740; + else tableptr = table1400_740; + } else return; + } else { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + tableptr = table1024_650; + } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || + (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200)) { + tableptr = table1400_650; + } else return; + } + + for(i=0; i<5; i++) { + SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]); + } +} + +static void +SiS_SetCH701xForLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR regtable[] = { 0x1c, 0x5f, 0x64, 0x6f, 0x70, 0x71, + 0x72, 0x73, 0x74, 0x76, 0x78, 0x7d, 0x66 }; + UCHAR table1024_740[] = { 0x60, 0x02, 0x00, 0x07, 0x40, 0xed, + 0xa3, 0xc8, 0xc7, 0xac, 0xe0, 0x02, 0x44 }; + UCHAR table1280_740[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02, 0x44 }; + UCHAR table1400_740[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02, 0x44 }; + UCHAR table1600_740[] = { 0x60, 0x04, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xde, 0xf6, 0xac, 0x60, 0x1a, 0x44 }; + UCHAR table1024_650[] = { 0x60, 0x02, 0x00, 0x07, 0x40, 0xed, + 0xa3, 0xc8, 0xc7, 0xac, 0x60, 0x02 }; + UCHAR table1280_650[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02 }; + UCHAR table1400_650[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xef, + 0xad, 0xdb, 0xf6, 0xac, 0x60, 0x02 }; + UCHAR table1600_650[] = { 0x60, 0x04, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xde, 0xf6, 0xac, 0x60, 0x1a }; + UCHAR *tableptr = NULL; + USHORT tempbh; + int i; + + if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tableptr = table1024_740; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) tableptr = table1280_740; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) tableptr = table1400_740; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) tableptr = table1600_740; + else return; + } else { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tableptr = table1024_650; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) tableptr = table1280_650; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) tableptr = table1400_650; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) tableptr = table1600_650; + else return; + } + + tempbh = SiS_GetCH701x(SiS_Pr,0x74); + if((tempbh == 0xf6) || (tempbh == 0xc7)) { + tempbh = SiS_GetCH701x(SiS_Pr,0x73); + if(tempbh == 0xc8) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) return; + } else if(tempbh == 0xdb) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) return; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) return; + } else if(tempbh == 0xde) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) return; + } + } + + if(HwInfo->jChipType == SIS_740) tempbh = 0x0d; + else tempbh = 0x0c; + + for(i = 0; i < tempbh; i++) { + SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]); + } + SiS_ChrontelPowerSequencing(SiS_Pr,HwInfo); + tempbh = SiS_GetCH701x(SiS_Pr,0x1e); + tempbh |= 0xc0; + SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x1e); + + if(HwInfo->jChipType == SIS_740) { + tempbh = SiS_GetCH701x(SiS_Pr,0x1c); + tempbh &= 0xfb; + SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x1c); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,0x03); + tempbh = SiS_GetCH701x(SiS_Pr,0x64); + tempbh |= 0x40; + SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x64); + tempbh = SiS_GetCH701x(SiS_Pr,0x03); + tempbh &= 0x3f; + SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x03); + } +} + +static void +SiS_ChrontelResetVSync(SiS_Private *SiS_Pr) +{ + unsigned char temp, temp1; + + temp1 = SiS_GetCH701x(SiS_Pr,0x49); + SiS_SetCH701x(SiS_Pr,0x3e49); + temp = SiS_GetCH701x(SiS_Pr,0x47); + temp &= 0x7f; /* Use external VSYNC */ + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47); + SiS_LongDelay(SiS_Pr,3); + temp = SiS_GetCH701x(SiS_Pr,0x47); + temp |= 0x80; /* Use internal VSYNC */ + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47); + SiS_SetCH701x(SiS_Pr,(temp1 << 8) | 0x49); +} + +static void +SiS_Chrontel701xOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT temp; + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(HwInfo->jChipType == SIS_740) { + temp = SiS_GetCH701x(SiS_Pr,0x1c); + temp |= 0x04; /* Invert XCLK phase */ + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x1c); + } + if(SiS_IsYPbPr(SiS_Pr, HwInfo)) { + temp = SiS_GetCH701x(SiS_Pr,0x01); + temp &= 0x3f; + temp |= 0x80; /* Enable YPrPb (HDTV) */ + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x01); + } + if(SiS_IsChScart(SiS_Pr, HwInfo)) { + temp = SiS_GetCH701x(SiS_Pr,0x01); + temp &= 0x3f; + temp |= 0xc0; /* Enable SCART + CVBS */ + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x01); + } + if(HwInfo->jChipType == SIS_740) { + SiS_ChrontelResetVSync(SiS_Pr); + SiS_SetCH701x(SiS_Pr,0x2049); /* Enable TV path */ + } else { + SiS_SetCH701x(SiS_Pr,0x2049); /* Enable TV path */ + temp = SiS_GetCH701x(SiS_Pr,0x49); + if(SiS_IsYPbPr(SiS_Pr,HwInfo)) { + temp = SiS_GetCH701x(SiS_Pr,0x73); + temp |= 0x60; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x73); + } + temp = SiS_GetCH701x(SiS_Pr,0x47); + temp &= 0x7f; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47); + SiS_LongDelay(SiS_Pr,2); + temp = SiS_GetCH701x(SiS_Pr,0x47); + temp |= 0x80; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47); + } + } +} + +static void +SiS_Chrontel701xOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT temp; + + /* Complete power down of LVDS */ + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(HwInfo->jChipType == SIS_740) { + SiS_LongDelay(SiS_Pr,1); + SiS_GenericDelay(SiS_Pr,0x16ff); + SiS_SetCH701x(SiS_Pr,0xac76); + SiS_SetCH701x(SiS_Pr,0x0066); + } else { + SiS_LongDelay(SiS_Pr,2); + temp = SiS_GetCH701x(SiS_Pr,0x76); + temp &= 0xfc; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76); + SiS_SetCH701x(SiS_Pr,0x0066); + } + } +} + +static void +SiS_ChrontelResetDB(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT temp; + + if(HwInfo->jChipType == SIS_740) { + + temp = SiS_GetCH701x(SiS_Pr,0x4a); /* Version ID */ + temp &= 0x01; + if(!temp) { + + if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo)) { + temp = SiS_GetCH701x(SiS_Pr,0x49); + SiS_SetCH701x(SiS_Pr,0x3e49); + } + /* Reset Chrontel 7019 datapath */ + SiS_SetCH701x(SiS_Pr,0x1048); + SiS_LongDelay(SiS_Pr,1); + SiS_SetCH701x(SiS_Pr,0x1848); + + if(SiS_WeHaveBacklightCtrl(SiS_Pr, HwInfo)) { + SiS_ChrontelResetVSync(SiS_Pr); + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x49); + } + + } else { + + /* Clear/set/clear GPIO */ + temp = SiS_GetCH701x(SiS_Pr,0x5c); + temp &= 0xef; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c); + temp = SiS_GetCH701x(SiS_Pr,0x5c); + temp |= 0x10; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c); + temp = SiS_GetCH701x(SiS_Pr,0x5c); + temp &= 0xef; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c); + temp = SiS_GetCH701x(SiS_Pr,0x61); + if(!temp) { + SiS_SetCH701xForLCD(SiS_Pr, HwInfo); + } + } + + } else { /* 650 */ + /* Reset Chrontel 7019 datapath */ + SiS_SetCH701x(SiS_Pr,0x1048); + SiS_LongDelay(SiS_Pr,1); + SiS_SetCH701x(SiS_Pr,0x1848); + } +} + +static void +SiS_ChrontelInitTVVSync(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT temp; + + if(HwInfo->jChipType == SIS_740) { + + if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo)) { + SiS_ChrontelResetVSync(SiS_Pr); + } + + } else { + + SiS_SetCH701x(SiS_Pr,0xaf76); /* Power up LVDS block */ + temp = SiS_GetCH701x(SiS_Pr,0x49); + temp &= 1; + if(temp != 1) { /* TV block powered? (0 = yes, 1 = no) */ + temp = SiS_GetCH701x(SiS_Pr,0x47); + temp &= 0x70; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47); /* enable VSYNC */ + SiS_LongDelay(SiS_Pr,3); + temp = SiS_GetCH701x(SiS_Pr,0x47); + temp |= 0x80; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47); /* disable VSYNC */ + } + + } +} + +static void +SiS_ChrontelDoSomething3(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo) +{ + USHORT temp,temp1; + + if(HwInfo->jChipType == SIS_740) { + + temp = SiS_GetCH701x(SiS_Pr,0x61); + if(temp < 1) { + temp++; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x61); + } + SiS_SetCH701x(SiS_Pr,0x4566); /* Panel power on */ + SiS_SetCH701x(SiS_Pr,0xaf76); /* All power on */ + SiS_LongDelay(SiS_Pr,1); + SiS_GenericDelay(SiS_Pr,0x16ff); + + } else { /* 650 */ + + temp1 = 0; + temp = SiS_GetCH701x(SiS_Pr,0x61); + if(temp < 2) { + temp++; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x61); + temp1 = 1; + } + SiS_SetCH701x(SiS_Pr,0xac76); + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp |= 0x5f; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66); + if(ModeNo > 0x13) { + if(SiS_WeHaveBacklightCtrl(SiS_Pr, HwInfo)) { + SiS_GenericDelay(SiS_Pr,0x3ff); + } else { + SiS_GenericDelay(SiS_Pr,0x2ff); + } + } else { + if(!temp1) + SiS_GenericDelay(SiS_Pr,0x2ff); + } + temp = SiS_GetCH701x(SiS_Pr,0x76); + temp |= 0x03; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76); + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp &= 0x7f; + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66); + SiS_LongDelay(SiS_Pr,1); + + } +} + +static void +SiS_ChrontelDoSomething2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT temp,tempcl,tempch; + + SiS_LongDelay(SiS_Pr, 1); + tempcl = 3; + tempch = 0; + + do { + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp &= 0x04; /* PLL stable? -> bail out */ + if(temp == 0x04) break; + + if(HwInfo->jChipType == SIS_740) { + /* Power down LVDS output, PLL normal operation */ + SiS_SetCH701x(SiS_Pr,0xac76); + } + + SiS_SetCH701xForLCD(SiS_Pr,HwInfo); + + if(tempcl == 0) { + if(tempch == 3) break; + SiS_ChrontelResetDB(SiS_Pr,HwInfo); + tempcl = 3; + tempch++; + } + tempcl--; + temp = SiS_GetCH701x(SiS_Pr,0x76); + temp &= 0xfb; /* Reset PLL */ + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76); + SiS_LongDelay(SiS_Pr,2); + temp = SiS_GetCH701x(SiS_Pr,0x76); + temp |= 0x04; /* PLL normal operation */ + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76); + if(HwInfo->jChipType == SIS_740) { + SiS_SetCH701x(SiS_Pr,0xe078); /* PLL loop filter */ + } else { + SiS_SetCH701x(SiS_Pr,0x6078); + } + SiS_LongDelay(SiS_Pr,2); + } while(0); + + SiS_SetCH701x(SiS_Pr,0x0077); /* MV? */ +} + +static void +SiS_ChrontelDoSomething1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT temp; + + temp = SiS_GetCH701x(SiS_Pr,0x03); + temp |= 0x80; /* Set datapath 1 to TV */ + temp &= 0xbf; /* Set datapath 2 to LVDS */ + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x03); + + if(HwInfo->jChipType == SIS_740) { + + temp = SiS_GetCH701x(SiS_Pr,0x1c); + temp &= 0xfb; /* Normal XCLK phase */ + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x1c); + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,0x03); + + temp = SiS_GetCH701x(SiS_Pr,0x64); + temp |= 0x40; /* ? Bit not defined */ + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x64); + + temp = SiS_GetCH701x(SiS_Pr,0x03); + temp &= 0x3f; /* D1 input to both LVDS and TV */ + SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x03); + + if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) { + SiS_SetCH701x(SiS_Pr,0x4063); /* LVDS off */ + SiS_LongDelay(SiS_Pr, 1); + SiS_SetCH701x(SiS_Pr,0x0063); /* LVDS on */ + SiS_ChrontelResetDB(SiS_Pr, HwInfo); + SiS_ChrontelDoSomething2(SiS_Pr, HwInfo); + SiS_ChrontelDoSomething3(SiS_Pr, 0, HwInfo); + } else { + temp = SiS_GetCH701x(SiS_Pr,0x66); + if(temp != 0x45) { + SiS_ChrontelResetDB(SiS_Pr, HwInfo); + SiS_ChrontelDoSomething2(SiS_Pr, HwInfo); + SiS_ChrontelDoSomething3(SiS_Pr, 0, HwInfo); + } + } + + } else { /* 650 */ + + SiS_ChrontelResetDB(SiS_Pr,HwInfo); + SiS_ChrontelDoSomething2(SiS_Pr,HwInfo); + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x34); + SiS_ChrontelDoSomething3(SiS_Pr,temp,HwInfo); + SiS_SetCH701x(SiS_Pr,0xaf76); /* All power on, LVDS normal operation */ + + } + +} +#endif /* 315 series */ + +/*********************************************/ +/* MAIN: SET CRT2 REGISTER GROUP */ +/*********************************************/ + +BOOLEAN +SiS_SetCRT2Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) +{ +#ifdef SIS300 + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; +#endif + USHORT ModeIdIndex, RefreshRateTableIndex; +#if 0 + USHORT temp; +#endif + + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + + if(!SiS_Pr->UseCustomMode) { + SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex); + } else { + ModeIdIndex = 0; + } + + /* Used for shifting CR33 */ + SiS_Pr->SiS_SelectCRT2Rate = 4; + + SiS_UnLockCRT2(SiS_Pr, HwInfo); + + RefreshRateTableIndex = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + + SiS_SaveCRT2Info(SiS_Pr,ModeNo); + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + SiS_DisableBridge(SiS_Pr,HwInfo); + if((SiS_Pr->SiS_IF_DEF_LVDS == 1) && (HwInfo->jChipType == SIS_730)) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,0x80); + } + SiS_SetCRT2ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + } + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) { + SiS_LockCRT2(SiS_Pr, HwInfo); + SiS_DisplayOn(SiS_Pr); + return TRUE; + } + + SiS_GetCRT2Data(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + + /* Set up Panel Link for LVDS and LCDA */ + SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0; + if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) || + ((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) || + ((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) { + SiS_GetLVDSDesData(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + } + +#ifdef LINUX_XF86 +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "(init301: LCDHDES 0x%03x LCDVDES 0x%03x)\n", SiS_Pr->SiS_LCDHDES, SiS_Pr->SiS_LCDVDES); + xf86DrvMsg(0, X_INFO, "(init301: HDE 0x%03x VDE 0x%03x)\n", SiS_Pr->SiS_HDE, SiS_Pr->SiS_VDE); + xf86DrvMsg(0, X_INFO, "(init301: VGAHDE 0x%03x VGAVDE 0x%03x)\n", SiS_Pr->SiS_VGAHDE, SiS_Pr->SiS_VGAVDE); + xf86DrvMsg(0, X_INFO, "(init301: HT 0x%03x VT 0x%03x)\n", SiS_Pr->SiS_HT, SiS_Pr->SiS_VT); + xf86DrvMsg(0, X_INFO, "(init301: VGAHT 0x%03x VGAVT 0x%03x)\n", SiS_Pr->SiS_VGAHT, SiS_Pr->SiS_VGAVT); +#endif +#endif + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + SiS_SetGroup1(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + + SiS_SetGroup2(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); +#ifdef SIS315H + SiS_SetGroup2_C_ELV(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); +#endif + SiS_SetGroup3(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + SiS_SetGroup4(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); +#ifdef SIS315H + SiS_SetGroup4_C_ELV(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); +#endif + SiS_SetGroup5(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + + SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo); + + /* For 301BDH (Panel link initialization): */ + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) { + if(!((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10)))) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex, + RefreshRateTableIndex,HwInfo); + } + } + } + SiS_SetCRT2ECLK(SiS_Pr,ModeNo,ModeIdIndex, + RefreshRateTableIndex,HwInfo); + } + } + + } else { + + SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo); + + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwInfo); + } + + SiS_SetCRT2ECLK(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwInfo); + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { +#ifdef SIS315H + SiS_SetCH701xForLCD(SiS_Pr,HwInfo); +#endif + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SiS_SetCHTVReg(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex); + } + } + } + + } + +#ifdef SIS300 + if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + if(SiS_Pr->SiS_UseOEM) { + if((SiS_Pr->SiS_UseROM) && (SiS_Pr->SiS_UseOEM == -1)) { + if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { + SiS_OEM300Setting(SiS_Pr,HwInfo,ModeNo,ModeIdIndex, + RefreshRateTableIndex); + } + } else { + SiS_OEM300Setting(SiS_Pr,HwInfo,ModeNo,ModeIdIndex, + RefreshRateTableIndex); + } + } + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { + SetOEMLCDData2(SiS_Pr, HwInfo, ModeNo, ModeIdIndex,RefreshRateTableIndex); + } + SiS_DisplayOn(SiS_Pr); + } + } + } +#endif + +#ifdef SIS315H + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + if(HwInfo->jChipType < SIS_661) { + SiS_FinalizeLCD(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + SiS_OEM310Setting(SiS_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } else { + SiS_OEM661Setting(SiS_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x40); + } + } +#endif + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + SiS_EnableBridge(SiS_Pr, HwInfo); + } + + SiS_DisplayOn(SiS_Pr); + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + /* Disable LCD panel when using TV */ + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFF,0x0C); + } else { + /* Disable TV when using LCD */ + SiS_SetCH70xxANDOR(SiS_Pr,0x010E,0xF8); + } + } + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + SiS_LockCRT2(SiS_Pr,HwInfo); + } + + return TRUE; +} + + +/*********************************************/ +/* ENABLE/DISABLE LCD BACKLIGHT (SIS) */ +/*********************************************/ + +void +SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + /* Switch on LCD backlight on SiS30xLV */ + SiS_DDC2Delay(SiS_Pr,0xff00); + if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02); + SiS_WaitVBRetrace(SiS_Pr,HwInfo); + } + if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x01)) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01); + } +} + +void +SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + /* Switch off LCD backlight on SiS30xLV */ + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); + SiS_DDC2Delay(SiS_Pr,0xe000); +} + +/*********************************************/ +/* DDC RELATED FUNCTIONS */ +/*********************************************/ + +static void +SiS_SetupDDCN(SiS_Private *SiS_Pr) +{ + SiS_Pr->SiS_DDC_NData = ~SiS_Pr->SiS_DDC_Data; + SiS_Pr->SiS_DDC_NClk = ~SiS_Pr->SiS_DDC_Clk; + if((SiS_Pr->SiS_DDC_Index == 0x11) && (SiS_Pr->SiS_SensibleSR11)) { + SiS_Pr->SiS_DDC_NData &= 0x0f; + SiS_Pr->SiS_DDC_NClk &= 0x0f; + } +} + +#ifdef SIS300 +static UCHAR * +SiS_SetTrumpBlockLoop(SiS_Private *SiS_Pr, UCHAR *dataptr) +{ + int i, j, num; + USHORT tempah,temp; + UCHAR *mydataptr; + + for(i=0; i<20; i++) { /* Do 20 attempts to write */ + mydataptr = dataptr; + num = *mydataptr++; + if(!num) return mydataptr; + if(i) { + SiS_SetStop(SiS_Pr); + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT*2); + } + if(SiS_SetStart(SiS_Pr)) continue; /* Set start condition */ + tempah = SiS_Pr->SiS_DDC_DeviceAddr; + temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* Write DAB (S0=0=write) */ + if(temp) continue; /* (ERROR: no ack) */ + tempah = *mydataptr++; + temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* Write register number */ + if(temp) continue; /* (ERROR: no ack) */ + for(j=0; j<num; j++) { + tempah = *mydataptr++; + temp = SiS_WriteDDC2Data(SiS_Pr,tempah);/* Write DAB (S0=0=write) */ + if(temp) break; + } + if(temp) continue; + if(SiS_SetStop(SiS_Pr)) continue; + return mydataptr; + } + return NULL; +} + +static BOOLEAN +SiS_SetTrumpionBlock(SiS_Private *SiS_Pr, UCHAR *dataptr) +{ + SiS_Pr->SiS_DDC_DeviceAddr = 0xF0; /* DAB (Device Address Byte) */ + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + + SiS_SetSwitchDDC2(SiS_Pr); + + while(*dataptr) { + dataptr = SiS_SetTrumpBlockLoop(SiS_Pr, dataptr); + if(!dataptr) return FALSE; + } +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "Trumpion block success\n"); +#endif + return TRUE; +} +#endif + +/* The Chrontel 700x is connected to the 630/730 via + * the 630/730's DDC/I2C port. + * + * On 630(S)T chipset, the index changed from 0x11 to + * 0x0a, possibly for working around the DDC problems + */ + +static BOOLEAN +SiS_SetChReg(SiS_Private *SiS_Pr, USHORT tempbx, USHORT myor) +{ + USHORT tempah,temp,i; + + for(i=0; i<20; i++) { /* Do 20 attempts to write */ + if(i) { + SiS_SetStop(SiS_Pr); + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); + } + if(SiS_SetStart(SiS_Pr)) continue; /* Set start condition */ + tempah = SiS_Pr->SiS_DDC_DeviceAddr; + temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* Write DAB (S0=0=write) */ + if(temp) continue; /* (ERROR: no ack) */ + tempah = tempbx & 0x00FF; /* Write RAB */ + tempah |= myor; /* (700x: set bit 7, see datasheet) */ + temp = SiS_WriteDDC2Data(SiS_Pr,tempah); + if(temp) continue; /* (ERROR: no ack) */ + tempah = (tempbx & 0xFF00) >> 8; + temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* Write data */ + if(temp) continue; /* (ERROR: no ack) */ + if(SiS_SetStop(SiS_Pr)) continue; /* Set stop condition */ + SiS_Pr->SiS_ChrontelInit = 1; + return TRUE; + } + return FALSE; +} + +#if 0 +#ifdef SIS300 +/* Write Trumpion register */ +static void +SiS_SetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx) +{ + SiS_Pr->SiS_DDC_DeviceAddr = 0xF0; /* DAB (Device Address Byte) */ + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + SiS_SetChReg(SiS_Pr, tempbx, 0); +} +#endif +#endif + +/* Write to Chrontel 700x */ +/* Parameter is [Data (S15-S8) | Register no (S7-S0)] */ +void +SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx) +{ + SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB (Device Address Byte) */ + + if(!(SiS_Pr->SiS_ChrontelInit)) { + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + } + + if( (!(SiS_SetChReg(SiS_Pr, tempbx, 0x80))) && + (!(SiS_Pr->SiS_ChrontelInit)) ) { + SiS_Pr->SiS_DDC_Index = 0x0a; /* Bit 7 = SC; Bit 6 = SD */ + SiS_Pr->SiS_DDC_Data = 0x80; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x40; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + + SiS_SetChReg(SiS_Pr, tempbx, 0x80); + } +} + +/* Write to Chrontel 701x */ +/* Parameter is [Data (S15-S8) | Register no (S7-S0)] */ +void +SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempbx) +{ + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x08; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x04; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB (Device Address Byte) */ + SiS_SetChReg(SiS_Pr, tempbx, 0); +} + +void +SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx) +{ + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) + SiS_SetCH700x(SiS_Pr,tempbx); + else + SiS_SetCH701x(SiS_Pr,tempbx); +} + +static USHORT +SiS_GetChReg(SiS_Private *SiS_Pr, USHORT myor) +{ + USHORT tempah,temp,i; + + for(i=0; i<20; i++) { /* Do 20 attempts to read */ + if(i) { + SiS_SetStop(SiS_Pr); + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); + } + if(SiS_SetStart(SiS_Pr)) continue; /* Set start condition */ + tempah = SiS_Pr->SiS_DDC_DeviceAddr; + temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* Write DAB (S0=0=write) */ + if(temp) continue; /* (ERROR: no ack) */ + tempah = SiS_Pr->SiS_DDC_ReadAddr | myor; /* Write RAB (700x: | 0x80) */ + temp = SiS_WriteDDC2Data(SiS_Pr,tempah); + if(temp) continue; /* (ERROR: no ack) */ + if (SiS_SetStart(SiS_Pr)) continue; /* Re-start */ + tempah = SiS_Pr->SiS_DDC_DeviceAddr | 0x01;/* DAB | 0x01 = Read */ + temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* DAB (S0=1=read) */ + if(temp) continue; /* (ERROR: no ack) */ + tempah = SiS_ReadDDC2Data(SiS_Pr,tempah); /* Read byte */ + if(SiS_SetStop(SiS_Pr)) continue; /* Stop condition */ + SiS_Pr->SiS_ChrontelInit = 1; + return(tempah); + } + return 0xFFFF; +} + +#if 0 +#ifdef SIS300 +/* Read from Trumpion */ +static USHORT +SiS_GetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx) +{ + SiS_Pr->SiS_DDC_DeviceAddr = 0xF0; /* DAB */ + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + SiS_Pr->SiS_DDC_ReadAddr = tempbx; + return(SiS_GetChReg(SiS_Pr,0)); +} +#endif +#endif + +/* Read from Chrontel 700x */ +/* Parameter is [Register no (S7-S0)] */ +USHORT +SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx) +{ + USHORT result; + + SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB */ + + if(!(SiS_Pr->SiS_ChrontelInit)) { + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + } + + SiS_Pr->SiS_DDC_ReadAddr = tempbx; + + if( ((result = SiS_GetChReg(SiS_Pr,0x80)) == 0xFFFF) && + (!SiS_Pr->SiS_ChrontelInit) ) { + + SiS_Pr->SiS_DDC_Index = 0x0a; + SiS_Pr->SiS_DDC_Data = 0x80; + SiS_Pr->SiS_DDC_Clk = 0x40; + SiS_SetupDDCN(SiS_Pr); + + result = SiS_GetChReg(SiS_Pr,0x80); + } + return(result); +} + +/* Read from Chrontel 701x */ +/* Parameter is [Register no (S7-S0)] */ +USHORT +SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempbx) +{ + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x08; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x04; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB */ + + SiS_Pr->SiS_DDC_ReadAddr = tempbx; + + return(SiS_GetChReg(SiS_Pr,0)); +} + +/* Read from Chrontel 70xx */ +/* Parameter is [Register no (S7-S0)] */ +USHORT +SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx) +{ + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) + return(SiS_GetCH700x(SiS_Pr, tempbx)); + else + return(SiS_GetCH701x(SiS_Pr, tempbx)); +} + +/* Our own DDC functions */ +static USHORT +SiS_InitDDCRegs(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine, + USHORT adaptnum, USHORT DDCdatatype, BOOLEAN checkcr32) +{ + unsigned char ddcdtype[] = { 0xa0, 0xa0, 0xa0, 0xa2, 0xa6 }; + unsigned char flag, cr32; + USHORT temp = 0, myadaptnum = adaptnum; + + if(adaptnum != 0) { + if(!(VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0xFFFF; + if((VBFlags & VB_30xBDH) && (adaptnum == 1)) return 0xFFFF; + } + + /* adapternum for SiS bridges: 0 = CRT1, 1 = LCD, 2 = VGA2 */ + + SiS_Pr->SiS_ChrontelInit = 0; /* force re-detection! */ + + SiS_Pr->SiS_DDC_SecAddr = 0; + SiS_Pr->SiS_DDC_DeviceAddr = ddcdtype[DDCdatatype]; + SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_P3c4; + SiS_Pr->SiS_DDC_Index = 0x11; + flag = 0xff; + + cr32 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x32); + +#if 0 + if(VBFlags & VB_SISBRIDGE) { + if(myadaptnum == 0) { + if(!(cr32 & 0x20)) { + myadaptnum = 2; + if(!(cr32 & 0x10)) { + myadaptnum = 1; + if(!(cr32 & 0x08)) { + myadaptnum = 0; + } + } + } + } + } +#endif + + if(VGAEngine == SIS_300_VGA) { /* 300 series */ + + if(myadaptnum != 0) { + flag = 0; + if(VBFlags & VB_SISBRIDGE) { + SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port; + SiS_Pr->SiS_DDC_Index = 0x0f; + } + } + + if(!(VBFlags & VB_301)) { + if((cr32 & 0x80) && (checkcr32)) { + if(myadaptnum >= 1) { + if(!(cr32 & 0x08)) { + myadaptnum = 1; + if(!(cr32 & 0x10)) return 0xFFFF; + } + } + } + } + + temp = 4 - (myadaptnum * 2); + if(flag) temp = 0; + + } else { /* 315/330 series */ + + /* here we simplify: 0 = CRT1, 1 = CRT2 (VGA, LCD) */ + + if(VBFlags & VB_SISBRIDGE) { + if(myadaptnum == 2) { + myadaptnum = 1; + } + } + + if(myadaptnum == 1) { + flag = 0; + if(VBFlags & VB_SISBRIDGE) { + SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port; + SiS_Pr->SiS_DDC_Index = 0x0f; + } + } + + if((cr32 & 0x80) && (checkcr32)) { + if(myadaptnum >= 1) { + if(!(cr32 & 0x08)) { + myadaptnum = 1; + if(!(cr32 & 0x10)) return 0xFFFF; + } + } + } + + temp = myadaptnum; + if(myadaptnum == 1) { + temp = 0; + if(VBFlags & VB_LVDS) flag = 0xff; + } + + if(flag) temp = 0; + } + + SiS_Pr->SiS_DDC_Data = 0x02 << temp; + SiS_Pr->SiS_DDC_Clk = 0x01 << temp; + + SiS_SetupDDCN(SiS_Pr); + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "DDC Port %x Index %x Shift %d\n", + SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index, temp); +#endif + + return 0; +} + +static USHORT +SiS_WriteDABDDC(SiS_Private *SiS_Pr) +{ + if(SiS_SetStart(SiS_Pr)) return 0xFFFF; + if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_DeviceAddr)) { + return 0xFFFF; + } + if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_SecAddr)) { + return 0xFFFF; + } + return(0); +} + +static USHORT +SiS_PrepareReadDDC(SiS_Private *SiS_Pr) +{ + if(SiS_SetStart(SiS_Pr)) return 0xFFFF; + if(SiS_WriteDDC2Data(SiS_Pr, (SiS_Pr->SiS_DDC_DeviceAddr | 0x01))) { + return 0xFFFF; + } + return(0); +} + +static USHORT +SiS_PrepareDDC(SiS_Private *SiS_Pr) +{ + if(SiS_WriteDABDDC(SiS_Pr)) SiS_WriteDABDDC(SiS_Pr); + if(SiS_PrepareReadDDC(SiS_Pr)) return(SiS_PrepareReadDDC(SiS_Pr)); + return(0); +} + +static void +SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno) +{ + SiS_SetSCLKLow(SiS_Pr); + if(yesno) { + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0); + } + SiS_SetSCLKHigh(SiS_Pr); +} + +static USHORT +SiS_DoProbeDDC(SiS_Private *SiS_Pr) +{ + unsigned char mask, value; + USHORT temp, ret=0; + BOOLEAN failed = FALSE; + + SiS_SetSwitchDDC2(SiS_Pr); + if(SiS_PrepareDDC(SiS_Pr)) { + SiS_SetStop(SiS_Pr); +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "Probe: Prepare failed\n"); +#endif + return(0xFFFF); + } + mask = 0xf0; + value = 0x20; + if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) { + temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0); + SiS_SendACK(SiS_Pr, 0); + if(temp == 0) { + mask = 0xff; + value = 0xff; + } else { + failed = TRUE; + ret = 0xFFFF; +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "Probe: Read 1 failed\n"); +#endif + } + } + if(failed == FALSE) { + temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0); + SiS_SendACK(SiS_Pr, 1); + temp &= mask; + if(temp == value) ret = 0; + else { + ret = 0xFFFF; +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "Probe: Read 2 failed\n"); +#endif + if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) { + if(temp == 0x30) ret = 0; + } + } + } + SiS_SetStop(SiS_Pr); + return(ret); +} + +static USHORT +SiS_ProbeDDC(SiS_Private *SiS_Pr) +{ + USHORT flag; + + flag = 0x180; + SiS_Pr->SiS_DDC_DeviceAddr = 0xa0; + if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x02; + SiS_Pr->SiS_DDC_DeviceAddr = 0xa2; + if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x08; + SiS_Pr->SiS_DDC_DeviceAddr = 0xa6; + if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x10; + if(!(flag & 0x1a)) flag = 0; + return(flag); +} + +static USHORT +SiS_ReadDDC(SiS_Private *SiS_Pr, USHORT DDCdatatype, unsigned char *buffer) +{ + USHORT flag, length, i; + unsigned char chksum,gotcha; + + if(DDCdatatype > 4) return 0xFFFF; + + flag = 0; + SiS_SetSwitchDDC2(SiS_Pr); + if(!(SiS_PrepareDDC(SiS_Pr))) { + length = 127; + if(DDCdatatype != 1) length = 255; + chksum = 0; + gotcha = 0; + for(i=0; i<length; i++) { + buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0); + chksum += buffer[i]; + gotcha |= buffer[i]; + SiS_SendACK(SiS_Pr, 0); + } + buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0); + chksum += buffer[i]; + SiS_SendACK(SiS_Pr, 1); + if(gotcha) flag = (USHORT)chksum; + else flag = 0xFFFF; + } else { + flag = 0xFFFF; + } + SiS_SetStop(SiS_Pr); + return(flag); +} + +/* Our private DDC functions + + It complies somewhat with the corresponding VESA function + in arguments and return values. + + Since this is probably called before the mode is changed, + we use our pre-detected pSiS-values instead of SiS_Pr as + regards chipset and video bridge type. + + Arguments: + adaptnum: 0=CRT1(analog), 1=CRT2/LCD(digital), 2=CRT2/VGA2(analog) + CRT2 DDC is only supported on SiS301, 301B, 301C, 302B. + LCDA is CRT1, but DDC is read from CRT2 port. + DDCdatatype: 0=Probe, 1=EDID, 2=EDID+VDIF, 3=EDID V2 (P&D), 4=EDID V2 (FPDI-2) + buffer: ptr to 256 data bytes which will be filled with read data. + + Returns 0xFFFF if error, otherwise + if DDCdatatype > 0: Returns 0 if reading OK (included a correct checksum) + if DDCdatatype = 0: Returns supported DDC modes + + */ +USHORT +SiS_HandleDDC(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine, + USHORT adaptnum, USHORT DDCdatatype, unsigned char *buffer) +{ + unsigned char sr1f,cr17=1; + USHORT result; + + if(adaptnum > 2) return 0xFFFF; + if(DDCdatatype > 4) return 0xFFFF; + if((!(VBFlags & VB_VIDEOBRIDGE)) && (adaptnum > 0)) return 0xFFFF; + if(SiS_InitDDCRegs(SiS_Pr, VBFlags, VGAEngine, adaptnum, DDCdatatype, FALSE) == 0xFFFF) return 0xFFFF; + + sr1f = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f); + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1f,0x3f,0x04); + if(VGAEngine == SIS_300_VGA) { + cr17 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x17) & 0x80; + if(!cr17) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x17,0x80); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x01); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x03); + } + } + if((sr1f) || (!cr17)) { + SiS_WaitRetrace1(SiS_Pr); + SiS_WaitRetrace1(SiS_Pr); + SiS_WaitRetrace1(SiS_Pr); + SiS_WaitRetrace1(SiS_Pr); + } + + if(DDCdatatype == 0) { + result = SiS_ProbeDDC(SiS_Pr); + } else { + result = SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer); + if((!result) && (DDCdatatype == 1)) { + if((buffer[0] == 0x00) && (buffer[1] == 0xff) && + (buffer[2] == 0xff) && (buffer[3] == 0xff) && + (buffer[4] == 0xff) && (buffer[5] == 0xff) && + (buffer[6] == 0xff) && (buffer[7] == 0x00) && + (buffer[0x12] == 1)) { + if(adaptnum == 1) { + if(!(buffer[0x14] & 0x80)) result = 0xFFFE; + } else { + if(buffer[0x14] & 0x80) result = 0xFFFE; + } + } + } + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x1f,sr1f); + if(VGAEngine == SIS_300_VGA) { + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x17,0x7f,cr17); + } + return result; +} + +#ifdef LINUX_XF86 + +static BOOLEAN +checkedid1(unsigned char *buffer) +{ + /* Check header */ + if((buffer[0] != 0x00) || + (buffer[1] != 0xff) || + (buffer[2] != 0xff) || + (buffer[3] != 0xff) || + (buffer[4] != 0xff) || + (buffer[5] != 0xff) || + (buffer[6] != 0xff) || + (buffer[7] != 0x00)) + return FALSE; + + /* Check EDID version and revision */ + if((buffer[0x12] != 1) || (buffer[0x13] > 4)) return FALSE; + + /* Check week of manufacture for sanity */ + if(buffer[0x10] > 53) return FALSE; + + /* Check year of manufacture for sanity */ + if(buffer[0x11] > 40) return FALSE; + + return TRUE; +} + +static BOOLEAN +checkedid2(unsigned char *buffer) +{ + USHORT year = buffer[6] | (buffer[7] << 8); + + /* Check EDID version */ + if((buffer[0] & 0xf0) != 0x20) return FALSE; + + /* Check week of manufacture for sanity */ + if(buffer[5] > 53) return FALSE; + + /* Check year of manufacture for sanity */ + if((year != 0) && ((year < 1990) || (year > 2030))) return FALSE; + + return TRUE; +} + +/* Sense the LCD parameters (CR36, CR37) via DDC */ +/* SiS30x(B) only */ +USHORT +SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SISPtr pSiS) +{ + USHORT DDCdatatype, paneltype, flag, xres=0, yres=0; + USHORT index, myindex, lumsize, numcodes, panelvendor, panelproduct; + int maxx=0, maxy=0, prefx=0, prefy=0; + unsigned char cr37=0, seekcode; + BOOLEAN checkexpand = FALSE; + BOOLEAN havesync = FALSE; + BOOLEAN indb = FALSE; + int retry, i; + unsigned char buffer[256]; + + for(i=0; i<7; i++) SiS_Pr->CP_DataValid[i] = FALSE; + SiS_Pr->CP_HaveCustomData = FALSE; + SiS_Pr->CP_MaxX = SiS_Pr->CP_MaxY = SiS_Pr->CP_MaxClock = 0; + SiS_Pr->CP_PreferredX = SiS_Pr->CP_PreferredY = 0; + SiS_Pr->CP_PreferredIndex = -1; + SiS_Pr->CP_PrefClock = 0; + SiS_Pr->PanelSelfDetected = FALSE; + + if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0; + if(pSiS->VBFlags & VB_30xBDH) return 0; + + if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 1, 0, FALSE) == 0xFFFF) return 0; + + SiS_Pr->SiS_DDC_SecAddr = 0x00; + + /* Probe supported DA's */ + flag = SiS_ProbeDDC(SiS_Pr); +#ifdef TWDEBUG + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO, + "CRT2 DDC capabilities 0x%x\n", flag); +#endif + if(flag & 0x10) { + SiS_Pr->SiS_DDC_DeviceAddr = 0xa6; /* EDID V2 (FP) */ + DDCdatatype = 4; + } else if(flag & 0x08) { + SiS_Pr->SiS_DDC_DeviceAddr = 0xa2; /* EDID V2 (P&D-D Monitor) */ + DDCdatatype = 3; + } else if(flag & 0x02) { + SiS_Pr->SiS_DDC_DeviceAddr = 0xa0; /* EDID V1 */ + DDCdatatype = 1; + } else return 0; /* no DDC support (or no device attached) */ + + /* Read the entire EDID */ + retry = 2; + do { + if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "CRT2: DDC read failed (attempt %d), %s\n", + (3-retry), (retry == 1) ? "giving up" : "retrying"); + retry--; + if(retry == 0) return 0xFFFF; + } else break; + } while(1); + +#ifdef TWDEBUG + for(i=0; i<256; i+=16) { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + buffer[i], buffer[i+1], buffer[i+2], buffer[i+3], + buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7], + buffer[i+8], buffer[i+9], buffer[i+10], buffer[i+11], + buffer[i+12], buffer[i+13], buffer[i+14], buffer[i+15]); + } +#endif + + /* Analyze EDID and retrieve LCD panel information */ + paneltype = 0; + switch(DDCdatatype) { + case 1: /* Analyze EDID V1 */ + /* Catch a few clear cases: */ + if(!(checkedid1(buffer))) { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "LCD sense: EDID corrupt\n"); + return 0; + } + + if(!(buffer[0x14] & 0x80)) { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "LCD sense: Attached display expects analog input (0x%02x)\n", + buffer[0x14]); + return 0; + } + + if((buffer[0x18] & 0x18) != 0x08) { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "LCD sense: Warning: Attached display is not of RGB but of %s type (0x%02x)\n", + ((buffer[0x18] & 0x18) == 0x00) ? "monochrome/greyscale" : + ( ((buffer[0x18] & 0x18) == 0x10) ? "non-RGB multicolor" : + "undefined"), + buffer[0x18]); + } + + /* Now analyze the first Detailed Timing Block and see + * if the preferred timing mode is stored there. If so, + * check if this is a standard panel for which we already + * know the timing. + */ + + paneltype = Panel_Custom; + checkexpand = FALSE; + + panelvendor = buffer[9] | (buffer[8] << 8); + panelproduct = buffer[10] | (buffer[11] << 8); + + /* Overrule bogus preferred modes from database */ + if((indb = SiS_FindPanelFromDB(pSiS, panelvendor, panelproduct, &maxx, &maxy, &prefx, &prefy))) { + if(prefx) SiS_Pr->CP_PreferredX = xres = prefx; + if(prefy) SiS_Pr->CP_PreferredY = yres = prefy; + } + + if(buffer[0x18] & 0x02) { + + USHORT pclk = (buffer[0x36] | (buffer[0x37] << 8)); + USHORT phb = (buffer[0x39] | ((buffer[0x3a] & 0x0f) << 8)); + USHORT pvb = (buffer[0x3c] | ((buffer[0x3d] & 0x0f) << 8)); + + if(!xres) SiS_Pr->CP_PreferredX = xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4); + if(!yres) SiS_Pr->CP_PreferredY = yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4); + + switch(xres) { +#if 0 /* Treat as custom */ + case 800: + if(yres == 600) { + paneltype = Panel_800x600; + checkexpand = TRUE; + } + break; +#endif + case 1024: + if(yres == 768) { + paneltype = Panel_1024x768; + checkexpand = TRUE; + } + break; + case 1280: + if(yres == 1024) { + paneltype = Panel_1280x1024; + checkexpand = TRUE; + } else if(yres == 960) { + if(pSiS->VGAEngine == SIS_300_VGA) { + paneltype = Panel300_1280x960; + } else { + paneltype = Panel310_1280x960; + } + } else if(yres == 768) { + if( (pclk == 8100) && + (phb == (1688 - 1280)) && + (pvb == (802 - 768)) ) { + paneltype = Panel_1280x768; + checkexpand = FALSE; + cr37 |= 0x10; + } + } else if(yres == 800) { + if( (pclk == 6900) && + (phb == (1408 - 1280)) && + (pvb == (816 - 800)) ) { + paneltype = Panel_1280x800; + } + } + break; + case 1400: + if(pSiS->VGAEngine == SIS_315_VGA) { + if(yres == 1050) { + paneltype = Panel310_1400x1050; + checkexpand = TRUE; + } + } + break; + case 1600: + if(pSiS->VGAEngine == SIS_315_VGA) { + if(pSiS->VBFlags & VB_301C) { + if(yres == 1200) { + paneltype = Panel310_1600x1200; + checkexpand = TRUE; + } + } + } + break; + } + + /* Save sync: This is used if "Pass 1:1" is off; in this case + * we always use the panel's native mode = this "preferred mode" + * we just have been analysing. Hence, we also need its sync. + */ + if((buffer[0x47] & 0x18) == 0x18) { + cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20); + havesync = TRUE; + } else { + /* What now? There is no digital separate output timing... */ + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING, + "LCD sense: Unable to retrieve Sync polarity information\n"); + cr37 |= 0xc0; /* Default */ + } + + } + + /* Check against our database; eg. Sanyo Z2 projector reports + * 1024x768 as preferred mode, although it supports 1280x720 + * natively in non-HDCP mode. Treat such wrongly reporting + * panels as custom and fixup actual maximum resolutions. + */ + if(paneltype != Panel_Custom) { + if(indb) { + paneltype = Panel_Custom; + SiS_Pr->CP_MaxX = maxx; + SiS_Pr->CP_MaxY = maxy; + /* Leave preferred unchanged (MUST contain a valid mode!) */ + } + } + + /* If we still don't know what panel this is, we take it + * as a custom panel and derive the timing data from the + * detailed timing blocks + */ + if(paneltype == Panel_Custom) { + + int i, temp, base = 0x36; + unsigned long estpack; + const unsigned short estx[] = { + 720, 720, 640, 640, 640, 640, 800, 800, + 800, 800, 832,1024,1024,1024,1024,1280, + 1152 + }; + const unsigned short esty[] = { + 400, 400, 480, 480, 480, 480, 600, 600, + 600, 600, 624, 768, 768, 768, 768,1024, + 870 + }; + const int estclk[] = { + 0, 0, 25100, 0, 31500, 31500, 36100, 40000, + 50100, 49500, 0, 0, 65100, 75200, 78700,135200, + 0 + }; + + paneltype = 0; + SiS_Pr->CP_Supports64048075 = TRUE; + + /* Find the maximum resolution */ + + /* 1. From Established timings */ + estpack = (buffer[0x23] << 9) | (buffer[0x24] << 1) | ((buffer[0x25] >> 7) & 0x01); + for(i=16; i>=0; i--) { + if(estpack & (1 << i)) { + if(estx[16 - i] > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = estx[16 - i]; + if(esty[16 - i] > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = esty[16 - i]; + if(estclk[16 - i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = estclk[16 - i]; + } + } + + /* By default we drive the LCD at 75Hz in 640x480 mode; if + * the panel does not provide this mode, use 60hz + */ + if(!(buffer[0x23] & 0x04)) SiS_Pr->CP_Supports64048075 = FALSE; + + /* 2. From Standard Timings */ + for(i=0x26; i < 0x36; i+=2) { + if((buffer[i] != 0x01) && (buffer[i+1] != 0x01)) { + temp = (buffer[i] + 31) * 8; + if(temp > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = temp; + switch((buffer[i+1] & 0xc0) >> 6) { + case 0x03: temp = temp * 9 / 16; break; + case 0x02: temp = temp * 4 / 5; break; + case 0x01: temp = temp * 3 / 4; break; + } + if(temp > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = temp; + } + } + + /* Now extract the Detailed Timings and convert them into modes */ + + for(i = 0; i < 4; i++, base += 18) { + + /* Is this a detailed timing block or a monitor descriptor? */ + if(buffer[base] || buffer[base+1] || buffer[base+2]) { + + xres = buffer[base+2] | ((buffer[base+4] & 0xf0) << 4); + yres = buffer[base+5] | ((buffer[base+7] & 0xf0) << 4); + + SiS_Pr->CP_HDisplay[i] = xres; + SiS_Pr->CP_HSyncStart[i] = xres + (buffer[base+8] | ((buffer[base+11] & 0xc0) << 2)); + SiS_Pr->CP_HSyncEnd[i] = SiS_Pr->CP_HSyncStart[i] + (buffer[base+9] | ((buffer[base+11] & 0x30) << 4)); + SiS_Pr->CP_HTotal[i] = xres + (buffer[base+3] | ((buffer[base+4] & 0x0f) << 8)); + SiS_Pr->CP_HBlankStart[i] = xres + 1; + SiS_Pr->CP_HBlankEnd[i] = SiS_Pr->CP_HTotal[i]; + + SiS_Pr->CP_VDisplay[i] = yres; + SiS_Pr->CP_VSyncStart[i] = yres + (((buffer[base+10] & 0xf0) >> 4) | ((buffer[base+11] & 0x0c) << 2)); + SiS_Pr->CP_VSyncEnd[i] = SiS_Pr->CP_VSyncStart[i] + ((buffer[base+10] & 0x0f) | ((buffer[base+11] & 0x03) << 4)); + SiS_Pr->CP_VTotal[i] = yres + (buffer[base+6] | ((buffer[base+7] & 0x0f) << 8)); + SiS_Pr->CP_VBlankStart[i] = yres + 1; + SiS_Pr->CP_VBlankEnd[i] = SiS_Pr->CP_VTotal[i]; + + SiS_Pr->CP_Clock[i] = (buffer[base] | (buffer[base+1] << 8)) * 10; + + SiS_Pr->CP_DataValid[i] = TRUE; + + /* Sort out invalid timings, interlace and too high clocks */ + if((SiS_Pr->CP_HDisplay[i] & 7) || + (SiS_Pr->CP_HDisplay[i] > SiS_Pr->CP_HSyncStart[i]) || + (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HSyncEnd[i]) || + (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HTotal[i]) || + (SiS_Pr->CP_HSyncStart[i] >= SiS_Pr->CP_HSyncEnd[i]) || + (SiS_Pr->CP_HSyncStart[i] > SiS_Pr->CP_HTotal[i]) || + (SiS_Pr->CP_HSyncEnd[i] > SiS_Pr->CP_HTotal[i]) || + (SiS_Pr->CP_VDisplay[i] > SiS_Pr->CP_VSyncStart[i]) || + (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VSyncEnd[i]) || + (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VTotal[i]) || + (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i]) || + (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i]) || + (SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i]) || + (((pSiS->VBFlags & VB_301C) && (SiS_Pr->CP_Clock[i] > 162500)) || + ((!(pSiS->VBFlags & VB_301C)) && + ((SiS_Pr->CP_Clock[i] > 108200) || (SiS_Pr->CP_VDisplay[i] > 1024) || + (SiS_Pr->CP_HDisplay[i] > 1600)))) || + (buffer[base+17] & 0x80)) { + + SiS_Pr->CP_DataValid[i] = FALSE; + + } else { + + SiS_Pr->CP_HaveCustomData = TRUE; + + if(xres > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = xres; + if(yres > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = yres; + if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i]; + + if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) { + SiS_Pr->CP_PreferredIndex = i; + SiS_MakeClockRegs(pSiS->pScrn, SiS_Pr->CP_Clock[i], &SiS_Pr->CP_PrefSR2B, &SiS_Pr->CP_PrefSR2C); + SiS_Pr->CP_PrefClock = (SiS_Pr->CP_Clock[i] / 1000) + 1; + } + + /* Extract the sync polarisation information. This only works + * if the Flags indicate a digital separate output. + */ + if((buffer[base+17] & 0x18) == 0x18) { + SiS_Pr->CP_HSync_P[i] = (buffer[base+17] & 0x02) ? TRUE : FALSE; + SiS_Pr->CP_VSync_P[i] = (buffer[base+17] & 0x04) ? TRUE : FALSE; + SiS_Pr->CP_SyncValid[i] = TRUE; + if((i == SiS_Pr->CP_PreferredIndex) && (!havesync)) { + cr37 |= ((((buffer[base+17] & 0x06) ^ 0x06) << 5) | 0x20); + havesync = TRUE; + } + } else { + SiS_Pr->CP_SyncValid[i] = FALSE; + } + + } + + } else if((!buffer[base]) && (!buffer[base+1]) && (!buffer[base+2]) && (!buffer[base+4])) { + + /* Maximum pixclock from Monitor Range Limits */ + if((buffer[base+3] == 0xfd) && (buffer[base+9] != 0xff)) { + int maxclk = buffer[base+9] * 10; + /* More than 170 is not supported anyway */ + if(maxclk <= 170) SiS_Pr->CP_MaxClock = maxclk * 1000; + } + + } + + } + + if(SiS_Pr->CP_MaxX && SiS_Pr->CP_MaxY) { + paneltype = Panel_Custom; + checkexpand = FALSE; + cr37 |= 0x10; + SiS_Pr->CP_Vendor = panelvendor; + SiS_Pr->CP_Product = panelproduct; + } + + } + + if(paneltype && checkexpand) { + /* If any of the Established low-res modes is supported, the + * panel can scale automatically. For 800x600 panels, we only + * check the even lower ones. + */ + if(paneltype == Panel_800x600) { + if(buffer[0x23] & 0xfc) cr37 |= 0x10; + } else { + if(buffer[0x23]) cr37 |= 0x10; + } + } + + break; + + case 3: /* Analyze EDID V2 */ + case 4: + index = 0; + + if(!(checkedid2(buffer))) { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "LCD sense: EDID corrupt\n"); + return 0; + } + + if((buffer[0x41] & 0x0f) == 0x03) { + index = 0x42 + 3; + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "LCD sense: Display supports TMDS input on primary interface\n"); + } else if((buffer[0x41] & 0xf0) == 0x30) { + index = 0x46 + 3; + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "LCD sense: Display supports TMDS input on secondary interface\n"); + } else { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "LCD sense: Display does not support TMDS video interface (0x%02x)\n", + buffer[0x41]); + return 0; + } + + SiS_Pr->CP_Vendor = panelvendor = buffer[2] | (buffer[1] << 8); + SiS_Pr->CP_Product = panelproduct = buffer[3] | (buffer[4] << 8); + + paneltype = Panel_Custom; + SiS_Pr->CP_MaxX = SiS_Pr->CP_PreferredX = xres = buffer[0x76] | (buffer[0x77] << 8); + SiS_Pr->CP_MaxY = SiS_Pr->CP_PreferredY = yres = buffer[0x78] | (buffer[0x79] << 8); + + switch(xres) { +#if 0 + case 800: + if(yres == 600) { + paneltype = Panel_800x600; + checkexpand = TRUE; + } + break; +#endif + case 1024: + if(yres == 768) { + paneltype = Panel_1024x768; + checkexpand = TRUE; + } + break; + case 1280: + if(yres == 960) { + if(pSiS->VGAEngine == SIS_315_VGA) { + paneltype = Panel310_1280x960; + } else { + paneltype = Panel300_1280x960; + } + } else if(yres == 1024) { + paneltype = Panel_1280x1024; + checkexpand = TRUE; + } + /* 1280x768 treated as custom here */ + break; + case 1400: + if(pSiS->VGAEngine == SIS_315_VGA) { + if(yres == 1050) { + paneltype = Panel310_1400x1050; + checkexpand = TRUE; + } + } + break; + case 1600: + if(pSiS->VGAEngine == SIS_315_VGA) { + if(pSiS->VBFlags & VB_301C) { + if(yres == 1200) { + paneltype = Panel310_1600x1200; + checkexpand = TRUE; + } + } + } + break; + } + + /* Determine if RGB18 or RGB24 */ + if(index) { + if((buffer[index] == 0x20) || (buffer[index] == 0x34)) { + cr37 |= 0x01; + } + } + + if(checkexpand) { + /* TODO - for now, we let the panel scale */ + cr37 |= 0x10; + } + + /* Now seek 4-Byte Timing codes and extract sync pol info */ + index = 0x80; + if(buffer[0x7e] & 0x20) { /* skip Luminance Table (if provided) */ + lumsize = buffer[0x80] & 0x1f; + if(buffer[0x80] & 0x80) lumsize *= 3; + lumsize++; /* luminance header byte */ + index += lumsize; + } +#if 0 /* "pixel rate" = pixel clock? */ + if(buffer[0x7e] & 0x1c) { + for(i=0; i<((buffer[0x7e] & 0x1c) >> 2); i++) { + if(buffer[index + (i*8) + 6] && (buffer[index + (i*8) + 7] & 0x0f)) { + int clk = (buffer[index + (i*8) + 6] | ((buffer[index + (i*8) + 7] & 0x0f) << 4)) * 1000; + if(clk > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = clk; + } + } + } +#endif + index += (((buffer[0x7e] & 0x1c) >> 2) * 8); /* skip Frequency Ranges */ + if(buffer[0x7e] & 0x03) { + for(i=0; i<(buffer[0x7e] & 0x03); i++) { + if((buffer[index + (i*27) + 9]) || (buffer[index + (i*27) + 10])) { + int clk = ((buffer[index + (i*27) + 9]) | ((buffer[index + (i*27) + 9]) << 8)) * 10; + if(clk > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = clk; + } + } + } + index += ((buffer[0x7e] & 0x03) * 27); /* skip Detailed Range Limits */ + numcodes = (buffer[0x7f] & 0xf8) >> 3; + if(numcodes) { + myindex = index; + seekcode = (xres - 256) / 16; + for(i=0; i<numcodes; i++) { + if(buffer[myindex] == seekcode) break; + myindex += 4; + } + if(buffer[myindex] == seekcode) { + cr37 |= ((((buffer[myindex + 1] & 0x0c) ^ 0x0c) << 4) | 0x20); + havesync = TRUE; + } else { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING, + "LCD sense: Unable to retrieve Sync polarity information\n"); + } + } else { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING, + "LCD sense: Unable to retrieve Sync polarity information\n"); + } + + /* Check against our database; Eg. Sanyo projector reports + * 1024x768 in non-HDPC mode, although it supports 1280x720. + * Treat such wrongly reporting panels as custom. + */ + if(paneltype != Panel_Custom) { + int maxx, maxy, prefx, prefy; + if((SiS_FindPanelFromDB(pSiS, panelvendor, panelproduct, &maxx, &maxy, &prefx, &prefy))) { + paneltype = Panel_Custom; + SiS_Pr->CP_MaxX = maxx; + SiS_Pr->CP_MaxY = maxy; + cr37 |= 0x10; + /* Leave preferred unchanged (MUST be a valid mode!) */ + } + } + + /* Now seek the detailed timing descriptions for custom panels */ + if(paneltype == Panel_Custom) { + + SiS_Pr->CP_Supports64048075 = TRUE; + + index += (numcodes * 4); + numcodes = buffer[0x7f] & 0x07; + for(i=0; i<numcodes; i++, index += 18) { + xres = buffer[index+2] | ((buffer[index+4] & 0xf0) << 4); + yres = buffer[index+5] | ((buffer[index+7] & 0xf0) << 4); + + SiS_Pr->CP_HDisplay[i] = xres; + SiS_Pr->CP_HSyncStart[i] = xres + (buffer[index+8] | ((buffer[index+11] & 0xc0) << 2)); + SiS_Pr->CP_HSyncEnd[i] = SiS_Pr->CP_HSyncStart[i] + (buffer[index+9] | ((buffer[index+11] & 0x30) << 4)); + SiS_Pr->CP_HTotal[i] = xres + (buffer[index+3] | ((buffer[index+4] & 0x0f) << 8)); + SiS_Pr->CP_HBlankStart[i] = xres + 1; + SiS_Pr->CP_HBlankEnd[i] = SiS_Pr->CP_HTotal[i]; + + SiS_Pr->CP_VDisplay[i] = yres; + SiS_Pr->CP_VSyncStart[i] = yres + (((buffer[index+10] & 0xf0) >> 4) | ((buffer[index+11] & 0x0c) << 2)); + SiS_Pr->CP_VSyncEnd[i] = SiS_Pr->CP_VSyncStart[i] + ((buffer[index+10] & 0x0f) | ((buffer[index+11] & 0x03) << 4)); + SiS_Pr->CP_VTotal[i] = yres + (buffer[index+6] | ((buffer[index+7] & 0x0f) << 8)); + SiS_Pr->CP_VBlankStart[i] = yres + 1; + SiS_Pr->CP_VBlankEnd[i] = SiS_Pr->CP_VTotal[i]; + + SiS_Pr->CP_Clock[i] = (buffer[index] | (buffer[index+1] << 8)) * 10; + + SiS_Pr->CP_DataValid[i] = TRUE; + + if((SiS_Pr->CP_HDisplay[i] & 7) || + (SiS_Pr->CP_HDisplay[i] > SiS_Pr->CP_HSyncStart[i]) || + (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HSyncEnd[i]) || + (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HTotal[i]) || + (SiS_Pr->CP_HSyncStart[i] >= SiS_Pr->CP_HSyncEnd[i]) || + (SiS_Pr->CP_HSyncStart[i] > SiS_Pr->CP_HTotal[i]) || + (SiS_Pr->CP_HSyncEnd[i] > SiS_Pr->CP_HTotal[i]) || + (SiS_Pr->CP_VDisplay[i] > SiS_Pr->CP_VSyncStart[i]) || + (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VSyncEnd[i]) || + (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VTotal[i]) || + (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i]) || + (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i]) || + (SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i]) || + (((pSiS->VBFlags & VB_301C) && (SiS_Pr->CP_Clock[i] > 162500)) || + ((!(pSiS->VBFlags & VB_301C)) && + ((SiS_Pr->CP_Clock[i] > 108200) || (SiS_Pr->CP_VDisplay[i] > 1024)))) || + (buffer[index + 17] & 0x80)) { + + SiS_Pr->CP_DataValid[i] = FALSE; + + } else { + + SiS_Pr->CP_HaveCustomData = TRUE; + + if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i]; + + if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) { + SiS_Pr->CP_PreferredIndex = i; + SiS_MakeClockRegs(pSiS->pScrn, SiS_Pr->CP_Clock[i], &SiS_Pr->CP_PrefSR2B, &SiS_Pr->CP_PrefSR2C); + SiS_Pr->CP_PrefClock = (SiS_Pr->CP_Clock[i] / 1000) + 1; + if(!havesync) { + cr37 |= ((((buffer[index + 17] & 0x06) ^ 0x06) << 5) | 0x20); + havesync = TRUE; + } + } + + SiS_Pr->CP_HSync_P[i] = (buffer[index + 17] & 0x02) ? TRUE : FALSE; + SiS_Pr->CP_VSync_P[i] = (buffer[index + 17] & 0x04) ? TRUE : FALSE; + SiS_Pr->CP_SyncValid[i] = TRUE; + + } + } + + cr37 |= 0x10; + + } + + break; + + } + + /* 1280x960 panels are always RGB24, unable to scale and use + * high active sync polarity + */ + if(pSiS->VGAEngine == SIS_315_VGA) { + if(paneltype == Panel310_1280x960) cr37 &= 0x0e; + } else { + if(paneltype == Panel300_1280x960) cr37 &= 0x0e; + } + + for(i = 0; i < 7; i++) { + if(SiS_Pr->CP_DataValid[i]) { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "Non-standard LCD/DVI-D timing data no. %d:\n", i); + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + " HDisplay %d HSync %d HSyncEnd %d HTotal %d\n", + SiS_Pr->CP_HDisplay[i], SiS_Pr->CP_HSyncStart[i], + SiS_Pr->CP_HSyncEnd[i], SiS_Pr->CP_HTotal[i]); + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + " VDisplay %d VSync %d VSyncEnd %d VTotal %d\n", + SiS_Pr->CP_VDisplay[i], SiS_Pr->CP_VSyncStart[i], + SiS_Pr->CP_VSyncEnd[i], SiS_Pr->CP_VTotal[i]); + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + " Pixel clock: %3.3fMhz\n", (float)SiS_Pr->CP_Clock[i] / 1000); + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO, + " To use this, add \"%dx%d\" to the list of Modes in the Screen section\n", + SiS_Pr->CP_HDisplay[i], + SiS_Pr->CP_VDisplay[i]); + } + } + + if(paneltype) { + if(!SiS_Pr->CP_PreferredX) SiS_Pr->CP_PreferredX = SiS_Pr->CP_MaxX; + if(!SiS_Pr->CP_PreferredY) SiS_Pr->CP_PreferredY = SiS_Pr->CP_MaxY; + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x08); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,paneltype); + cr37 &= 0xf1; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0x0c,cr37); + SiS_Pr->PanelSelfDetected = TRUE; +#ifdef TWDEBUG + xf86DrvMsgVerb(pSiS->pScrn->scrnIndex, X_PROBED, 3, + "LCD sense: [DDC LCD results: 0x%02x, 0x%02x]\n", paneltype, cr37); +#endif + } else { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x32,~0x08); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,0x00); + } + return 0; +} + +USHORT +SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SISPtr pSiS) +{ + USHORT DDCdatatype,flag; + BOOLEAN foundcrt = FALSE; + int retry; + unsigned char buffer[256]; + + if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0; + + if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 2, 0, FALSE) == 0xFFFF) return 0; + + SiS_Pr->SiS_DDC_SecAddr = 0x00; + + /* Probe supported DA's */ + flag = SiS_ProbeDDC(SiS_Pr); + if(flag & 0x10) { + SiS_Pr->SiS_DDC_DeviceAddr = 0xa6; /* EDID V2 (FP) */ + DDCdatatype = 4; + } else if(flag & 0x08) { + SiS_Pr->SiS_DDC_DeviceAddr = 0xa2; /* EDID V2 (P&D-D Monitor) */ + DDCdatatype = 3; + } else if(flag & 0x02) { + SiS_Pr->SiS_DDC_DeviceAddr = 0xa0; /* EDID V1 */ + DDCdatatype = 1; + } else { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "VGA2 sense: Do DDC answer\n"); + return 0; /* no DDC support (or no device attached) */ + } + + /* Read the entire EDID */ + retry = 2; + do { + if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, + "VGA2 sense: DDC read failed (attempt %d), %s\n", + (3-retry), (retry == 1) ? "giving up" : "retrying"); + retry--; + if(retry == 0) return 0xFFFF; + } else break; + } while(1); + + /* Analyze EDID. We don't have many chances to + * distinguish a flat panel from a CRT... + */ + switch(DDCdatatype) { + case 1: + if(!(checkedid1(buffer))) { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR, + "VGA2 sense: EDID corrupt\n"); + return 0; + } + if(buffer[0x14] & 0x80) { /* Display uses digital input */ + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR, + "VGA2 sense: Attached display expects digital input\n"); + return 0; + } + SiS_Pr->CP_Vendor = buffer[9] | (buffer[8] << 8); + SiS_Pr->CP_Product = buffer[10] | (buffer[11] << 8); + foundcrt = TRUE; + break; + case 3: + case 4: + if(!(checkedid2(buffer))) { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR, + "VGA2 sense: EDID corrupt\n"); + return 0; + } + if( ((buffer[0x41] & 0x0f) != 0x01) && /* Display does not support analog input */ + ((buffer[0x41] & 0x0f) != 0x02) && + ((buffer[0x41] & 0xf0) != 0x10) && + ((buffer[0x41] & 0xf0) != 0x20) ) { + xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR, + "VGA2 sense: Attached display does not support analog input (0x%02x)\n", + buffer[0x41]); + return 0; + } + SiS_Pr->CP_Vendor = buffer[2] | (buffer[1] << 8); + SiS_Pr->CP_Product = buffer[3] | (buffer[4] << 8); + foundcrt = TRUE; + break; + } + + if(foundcrt) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x10); + } + return(0); +} + +#endif + +void +SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh) +{ + USHORT tempbl; + + tempbl = SiS_GetCH70xx(SiS_Pr,(tempax & 0x00FF)); + tempbl = (((tempbl & tempbh) << 8) | tempax); + SiS_SetCH70xx(SiS_Pr,tempbl); +} + +/* Generic I2C functions for Chrontel & DDC --------- */ + +static void +SiS_SetSwitchDDC2(SiS_Private *SiS_Pr) +{ + SiS_SetSCLKHigh(SiS_Pr); + SiS_WaitRetrace1(SiS_Pr); + + SiS_SetSCLKLow(SiS_Pr); + SiS_WaitRetrace1(SiS_Pr); +} + +USHORT +SiS_ReadDDC1Bit(SiS_Private *SiS_Pr) +{ + SiS_WaitRetrace1(SiS_Pr); + return((SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x02) >> 1); +} + +/* Set I2C start condition */ +/* This is done by a SD high-to-low transition while SC is high */ +static USHORT +SiS_SetStart(SiS_Private *SiS_Pr) +{ + if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF; /* (SC->low) */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* SD->high */ + if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* SC->high */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0x00); /* SD->low = start condition */ + if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* (SC->low) */ + return 0; +} + +/* Set I2C stop condition */ +/* This is done by a SD low-to-high transition while SC is high */ +static USHORT +SiS_SetStop(SiS_Private *SiS_Pr) +{ + if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF; /* (SC->low) */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0x00); /* SD->low */ + if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* SC->high */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* SD->high = stop condition */ + if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* (SC->high) */ + return 0; +} + +/* Write 8 bits of data */ +static USHORT +SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax) +{ + USHORT i,flag,temp; + + flag = 0x80; + for(i=0; i<8; i++) { + SiS_SetSCLKLow(SiS_Pr); /* SC->low */ + if(tempax & flag) { + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* Write bit (1) to SD */ + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0x00); /* Write bit (0) to SD */ + } + SiS_SetSCLKHigh(SiS_Pr); /* SC->high */ + flag >>= 1; + } + temp = SiS_CheckACK(SiS_Pr); /* Check acknowledge */ + return(temp); +} + +static USHORT +SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax) +{ + USHORT i,temp,getdata; + + getdata=0; + for(i=0; i<8; i++) { + getdata <<= 1; + SiS_SetSCLKLow(SiS_Pr); + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); + SiS_SetSCLKHigh(SiS_Pr); + temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); + if(temp & SiS_Pr->SiS_DDC_Data) getdata |= 0x01; + } + return(getdata); +} + +static USHORT +SiS_SetSCLKLow(SiS_Private *SiS_Pr) +{ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NClk, + 0x00); /* SetSCLKLow() */ + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); + return 0; +} + +static USHORT +SiS_SetSCLKHigh(SiS_Private *SiS_Pr) +{ + USHORT temp, watchdog=1000; + + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NClk, + SiS_Pr->SiS_DDC_Clk); /* SetSCLKHigh() */ + do { + temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); + } while((!(temp & SiS_Pr->SiS_DDC_Clk)) && --watchdog); + if (!watchdog) { +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "SetClkHigh failed\n"); +#endif + return 0xFFFF; + } + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); + return 0; +} + +/* Check I2C acknowledge */ +/* Returns 0 if ack ok, non-0 if ack not ok */ +static USHORT +SiS_CheckACK(SiS_Private *SiS_Pr) +{ + USHORT tempah; + + SiS_SetSCLKLow(SiS_Pr); /* (SC->low) */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* (SD->high) */ + SiS_SetSCLKHigh(SiS_Pr); /* SC->high = clock impulse for ack */ + tempah = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); /* Read SD */ + SiS_SetSCLKLow(SiS_Pr); /* SC->low = end of clock impulse */ + if(tempah & SiS_Pr->SiS_DDC_Data) return(1); /* Ack OK if bit = 0 */ + else return(0); +} + +/* End of I2C functions ----------------------- */ + + +/* =============== SiS 315/330 O.E.M. ================= */ + +#ifdef SIS315H + +static USHORT +GetRAMDACromptr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT romptr; + + if(HwInfo->jChipType < SIS_330) { + romptr = SISGETROMW(0x128); + if(SiS_Pr->SiS_VBType & VB_SIS301B302B) + romptr = SISGETROMW(0x12a); + } else { + romptr = SISGETROMW(0x1a8); + if(SiS_Pr->SiS_VBType & VB_SIS301B302B) + romptr = SISGETROMW(0x1aa); + } + return(romptr); +} + +static USHORT +GetLCDromptr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT romptr; + + if(HwInfo->jChipType < SIS_330) { + romptr = SISGETROMW(0x120); + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) + romptr = SISGETROMW(0x122); + } else { + romptr = SISGETROMW(0x1a0); + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) + romptr = SISGETROMW(0x1a2); + } + return(romptr); +} + +static USHORT +GetTVromptr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT romptr; + + if(HwInfo->jChipType < SIS_330) { + romptr = SISGETROMW(0x114); + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) + romptr = SISGETROMW(0x11a); + } else { + romptr = SISGETROMW(0x194); + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) + romptr = SISGETROMW(0x19a); + } + return(romptr); +} + +static USHORT +GetLCDPtrIndexBIOS(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT index; + + if((IS_SIS650) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { + if(!(SiS_IsNotM650orLater(SiS_Pr, HwInfo))) { + if((index = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0xf0)) { + index >>= 4; + index *= 3; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2; + else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++; + return index; + } + } + } + + index = SiS_GetBIOSLCDResInfo(SiS_Pr) & 0x0F; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) index -= 5; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) index -= 6; + index--; + index *= 3; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2; + else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++; + return index; +} + +static USHORT +GetLCDPtrIndex(SiS_Private *SiS_Pr) +{ + USHORT index; + + index = ((SiS_GetBIOSLCDResInfo(SiS_Pr) & 0x0F) - 1) * 3; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2; + else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++; + return index; +} + +static USHORT +GetTVPtrIndex(SiS_Private *SiS_Pr) +{ + USHORT index; + + index = 0; + if(SiS_Pr->SiS_TVMode & TVSetPAL) index = 1; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) index = 2; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) index = 0; + + index <<= 1; + + if((SiS_Pr->SiS_VBInfo & SetInSlaveMode) && + (SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) { + index++; + } + + return index; +} + +static ULONG +GetOEMTVPtr661_2_GEN(SiS_Private *SiS_Pr, int addme) +{ + USHORT index = 0, temp = 0; + + if(SiS_Pr->SiS_TVMode & TVSetPAL) index = 1; + if(SiS_Pr->SiS_TVMode & TVSetPALM) index = 2; + if(SiS_Pr->SiS_TVMode & TVSetPALN) index = 3; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) index = 6; + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { + index = 4; + if(SiS_Pr->SiS_TVMode & TVSetPALM) index++; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) index = 7; + } + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if((!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || + (SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) { + index += addme; + temp++; + } + temp += 0x0100; + } + return(ULONG)(index | (temp << 16)); +} + +static ULONG +GetOEMTVPtr661_2_OLD(SiS_Private *SiS_Pr) +{ + return(GetOEMTVPtr661_2_GEN(SiS_Pr, 8)); +} + +#if 0 +static ULONG +GetOEMTVPtr661_2_NEW(SiS_Private *SiS_Pr) +{ + return(GetOEMTVPtr661_2_GEN(SiS_Pr, 6)); +} +#endif + +static int +GetOEMTVPtr661(SiS_Private *SiS_Pr) +{ + int index = 0; + + if(SiS_Pr->SiS_TVMode & TVSetPAL) index = 2; + if(SiS_Pr->SiS_ROMNew) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) index = 4; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) index = 6; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) index = 8; + if(SiS_Pr->SiS_TVMode & TVSetHiVision) index = 10; + } else { + if(SiS_Pr->SiS_TVMode & TVSetHiVision) index = 4; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) index = 6; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) index = 8; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) index = 10; + } + + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) index++; + + return index; +} + +static void +SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT delay=0,index,myindex,temp,romptr=0; + BOOLEAN dochiptest = TRUE; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x20,0xbf); + } else { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x35,0x7f); + } + + /* Find delay (from ROM, internal tables, PCI subsystem) */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { /* ------------ VGA */ + + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + romptr = GetRAMDACromptr(SiS_Pr, HwInfo); + } + if(romptr) delay = ROMAddr[romptr]; + else { + delay = 0x04; + if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { + if(IS_SIS650) { + delay = 0x0a; + } else if(IS_SIS740) { + delay = 0x00; + } else if(HwInfo->jChipType < SIS_330) { + delay = 0x0c; + } else { + delay = 0x0c; + } + } else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + delay = 0x00; + } + } + + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD|SetCRT2ToLCDA)) { /* ---------- LCD/LCDA */ + + BOOLEAN gotitfrompci = FALSE; + + /* Could we detect a PDC for LCD or did we get a user-defined? If yes, use it */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->PDC != -1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((SiS_Pr->PDC >> 1) & 0x0f)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((SiS_Pr->PDC & 0x01) << 7)); + return; + } + } else { + if(SiS_Pr->PDCA != -1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((SiS_Pr->PDCA << 3) & 0xf0)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((SiS_Pr->PDCA & 0x01) << 6)); + return; + } + } + + /* Custom Panel? */ + + if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + delay = 0x00; + if((SiS_Pr->PanelXRes <= 1280) && (SiS_Pr->PanelYRes <= 1024)) { + delay = 0x20; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,delay); + } else { + delay = 0x0c; + if(SiS_Pr->SiS_VBType & VB_SIS301C) delay = 0x03; + else if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(IS_SIS740) delay = 0x01; + else delay = 0x03; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,delay); + } + return; + } + + /* This is a piece of typical SiS crap: They code the OEM LCD + * delay into the code, at no defined place in the BIOS. + * We now have to start doing a PCI subsystem check here. + */ + + switch(SiS_Pr->SiS_CustomT) { + case CUT_COMPAQ1280: + case CUT_COMPAQ12802: + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + gotitfrompci = TRUE; + dochiptest = FALSE; + delay = 0x03; + } + break; + case CUT_CLEVO1400: + case CUT_CLEVO14002: + gotitfrompci = TRUE; + dochiptest = FALSE; + delay = 0x02; + break; + case CUT_CLEVO1024: + case CUT_CLEVO10242: + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + gotitfrompci = TRUE; + dochiptest = FALSE; + delay = 0x33; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2D,delay); + delay &= 0x0f; + } + break; + } + + /* Could we find it through the PCI ID? If no, use ROM or table */ + + if(!gotitfrompci) { + + index = GetLCDPtrIndexBIOS(SiS_Pr, HwInfo); + myindex = GetLCDPtrIndex(SiS_Pr); + + if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { + + if(SiS_IsNotM650orLater(SiS_Pr, HwInfo)) { + + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + /* Always use the second pointer on 650; some BIOSes */ + /* still carry old 301 data at the first location */ + /* romptr = SISGETROMW(0x120); */ + /* if(SiS_Pr->SiS_VBType & VB_SIS302LV) */ + romptr = SISGETROMW(0x122); + if(!romptr) return; + delay = ROMAddr[(romptr + index)]; + } else { + delay = SiS310_LCDDelayCompensation_650301LV[myindex]; + } + + } else { + + delay = SiS310_LCDDelayCompensation_651301LV[myindex]; + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) + delay = SiS310_LCDDelayCompensation_651302LV[myindex]; + + } + + } else if(SiS_Pr->SiS_UseROM && + (!(SiS_Pr->SiS_ROMNew)) && + (SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) && + (SiS_Pr->SiS_LCDResInfo != Panel_1280x768) && + (SiS_Pr->SiS_LCDResInfo != Panel_1280x960)) { + + /* Data for 1280x1024 wrong in 301B BIOS */ + romptr = GetLCDromptr(SiS_Pr, HwInfo); + if(!romptr) return; + delay = ROMAddr[(romptr + index)]; + + } else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + + if(IS_SIS740) delay = 0x03; + else delay = 0x00; + + } else { + + delay = SiS310_LCDDelayCompensation_301[myindex]; + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(IS_SIS740) delay = 0x01; + else if(HwInfo->jChipType <= SIS_315PRO) delay = SiS310_LCDDelayCompensation_3xx301LV[myindex]; + else delay = SiS310_LCDDelayCompensation_650301LV[myindex]; + } else if(SiS_Pr->SiS_VBType & VB_SIS301C) { + if(IS_SIS740) delay = 0x01; /* ? */ + else delay = 0x03; + } else if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { + if(IS_SIS740) delay = 0x01; + else delay = SiS310_LCDDelayCompensation_3xx301B[myindex]; + } + + } + + } /* got it from PCI */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0x0F,((delay << 4) & 0xf0)); + dochiptest = FALSE; + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* ------------ TV */ + + index = GetTVPtrIndex(SiS_Pr); + + if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { + + if(SiS_IsNotM650orLater(SiS_Pr,HwInfo)) { + + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + /* Always use the second pointer on 650; some BIOSes */ + /* still carry old 301 data at the first location */ + /* romptr = SISGETROMW(0x114); */ + /* if(SiS_Pr->SiS_VBType & VB_SIS302LV) */ + romptr = SISGETROMW(0x11a); + if(!romptr) return; + delay = ROMAddr[romptr + index]; + + } else { + + delay = SiS310_TVDelayCompensation_301B[index]; + + } + + } else { + + switch(SiS_Pr->SiS_CustomT) { + case CUT_COMPAQ1280: + case CUT_COMPAQ12802: + case CUT_CLEVO1400: + case CUT_CLEVO14002: + delay = 0x02; + dochiptest = FALSE; + break; + case CUT_CLEVO1024: + case CUT_CLEVO10242: + delay = 0x03; + dochiptest = FALSE; + break; + default: + delay = SiS310_TVDelayCompensation_651301LV[index]; + if(SiS_Pr->SiS_VBType & VB_SIS302LV) { + delay = SiS310_TVDelayCompensation_651302LV[index]; + } + } + } + + } else if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + + romptr = GetTVromptr(SiS_Pr, HwInfo); + if(!romptr) return; + delay = ROMAddr[romptr + index]; + + } else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + + delay = SiS310_TVDelayCompensation_LVDS[index]; + + } else { + + delay = SiS310_TVDelayCompensation_301[index]; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(IS_SIS740) { + delay = SiS310_TVDelayCompensation_740301B[index]; + /* LV: use 301 data? BIOS bug? */ + } else { + delay = SiS310_TVDelayCompensation_301B[index]; + if(SiS_Pr->SiS_VBType & VB_SIS301C) delay = 0x02; + } + } + + } + + if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) { + delay &= 0x0f; + dochiptest = FALSE; + } + + } else return; + + /* Write delay */ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && dochiptest) { + + temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0xf0) >> 4; + if(temp == 8) { /* 1400x1050 BIOS (COMPAL) */ + delay &= 0x0f; + delay |= 0xb0; + } else if(temp == 6) { + delay &= 0x0f; + delay |= 0xc0; + } else if(temp > 7) { /* 1280x1024 BIOS (which one?) */ + delay = 0x35; + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2D,delay); + + } else { + + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0xF0,delay); + + } + + } else { /* LVDS */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0xF0,delay); + } else { + if(IS_SIS650 && (SiS_Pr->SiS_IF_DEF_CH70xx != 0)) { + delay <<= 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0x0F,delay); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0xF0,delay); + } + } + + } + +} + +static void +SetAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT index,temp,temp1,romptr=0; + + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p|TVSetYPbPr525p)) return; + + if(ModeNo<=0x13) + index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex; + else + index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex; + + temp = GetTVPtrIndex(SiS_Pr); + temp >>= 1; /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */ + temp1 = temp; + + if(SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { + if(HwInfo->jChipType >= SIS_661) { + temp1 = GetOEMTVPtr661(SiS_Pr); + temp1 >>= 1; + romptr = SISGETROMW(0x260); + if(HwInfo->jChipType >= SIS_760) { + romptr = SISGETROMW(0x360); + } + } else if(HwInfo->jChipType >= SIS_330) { + romptr = SISGETROMW(0x192); + } else { + romptr = SISGETROMW(0x112); + } + } + + if(romptr) { + temp1 <<= 1; + temp = ROMAddr[romptr + temp1 + index]; + } else { + temp = SiS310_TVAntiFlick1[temp][index]; + } + temp <<= 4; + + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8f,temp); /* index 0A D[6:4] */ +} + +static void +SetEdgeEnhance(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT index,temp,temp1,romptr=0; + + temp = temp1 = GetTVPtrIndex(SiS_Pr) >> 1; /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */ + + if(ModeNo <= 0x13) + index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex; + else + index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex; + + if(SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { + if(HwInfo->jChipType >= SIS_661) { + romptr = SISGETROMW(0x26c); + if(HwInfo->jChipType >= SIS_760) { + romptr = SISGETROMW(0x36c); + } + temp1 = GetOEMTVPtr661(SiS_Pr); + temp1 >>= 1; + } else if(HwInfo->jChipType >= SIS_330) { + romptr = SISGETROMW(0x1a4); + } else { + romptr = SISGETROMW(0x124); + } + } + + if(romptr) { + temp1 <<= 1; + temp = ROMAddr[romptr + temp1 + index]; + } else { + temp = SiS310_TVEdge1[temp][index]; + } + temp <<= 5; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x3A,0x1F,temp); /* index 0A D[7:5] */ +} + +static void +SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex) +{ + USHORT index, temp, i, j; + + if(ModeNo <= 0x13) { + index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex; + } else { + index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex; + } + + temp = GetTVPtrIndex(SiS_Pr) >> 1; /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */ + + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) temp = 1; /* NTSC-J uses PAL */ + else if(SiS_Pr->SiS_TVMode & TVSetPALM) temp = 3; /* PAL-M */ + else if(SiS_Pr->SiS_TVMode & TVSetPALN) temp = 4; /* PAL-N */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) temp = 1; /* HiVision uses PAL */ + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + for(i=0x35, j=0; i<=0x38; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter2[temp][index][j]); + } + for(i=0x48; i<=0x4A; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter2[temp][index][j]); + } + } else { + for(i=0x35, j=0; i<=0x38; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter1[temp][index][j]); + } + } +} + +static void +SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT index,temp,i,j,resinfo,romptr=0; + ULONG lindex; + + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return; + + /* NTSC-J data not in BIOS, and already set in SetGroup2 */ + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) return; + + if((HwInfo->jChipType >= SIS_661) || SiS_Pr->SiS_ROMNew) { + lindex = GetOEMTVPtr661_2_OLD(SiS_Pr) & 0xffff; + lindex <<= 2; + for(j=0, i=0x31; i<=0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS661_TVPhase[lindex + j]); + } + return; + } + + /* PAL-M, PAL-N not in BIOS, and already set in SetGroup2 */ + if(SiS_Pr->SiS_TVMode & (TVSetPALM | TVSetPALN)) return; + + if(ModeNo<=0x13) { + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + temp = GetTVPtrIndex(SiS_Pr); + /* 0: NTSC Graphics, 1: NTSC Text, 2: PAL Graphics, + * 3: PAL Text, 4: HiTV Graphics 5: HiTV Text + */ + if(SiS_Pr->SiS_UseROM) { + romptr = SISGETROMW(0x116); + if(HwInfo->jChipType >= SIS_330) { + romptr = SISGETROMW(0x196); + } + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + romptr = SISGETROMW(0x11c); + if(HwInfo->jChipType >= SIS_330) { + romptr = SISGETROMW(0x19c); + } + if((SiS_Pr->SiS_VBInfo & SetInSlaveMode) && (!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode))) { + romptr = SISGETROMW(0x116); + if(HwInfo->jChipType >= SIS_330) { + romptr = SISGETROMW(0x196); + } + } + } + } + if(romptr) { + romptr += (temp << 2); + for(j=0, i=0x31; i<=0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]); + } + } else { + index = temp % 2; + temp >>= 1; /* 0:NTSC, 1:PAL, 2:HiTV */ + for(j=0, i=0x31; i<=0x34; i++, j++) { + if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr1[temp][index][j]); + else if((!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || (SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr2[temp][index][j]); + else + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr1[temp][index][j]); + } + } + + if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision))) { + if((!(SiS_Pr->SiS_TVMode & (TVSetPAL | TVSetYPbPr525p | TVSetYPbPr750p))) && (ModeNo > 0x13)) { + if((resinfo == SIS_RI_640x480) || + (resinfo == SIS_RI_800x600)) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x31,0x21); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x32,0xf0); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x33,0xf5); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x34,0x7f); + } else if(resinfo == SIS_RI_1024x768) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x31,0x1e); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x32,0x8b); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x33,0xfb); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x34,0x7b); + } + } + } +} + +static void +SetDelayComp661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RTI) +{ + USHORT delay = 0, romptr = 0, index, lcdpdcindex; + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + + if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA | SetCRT2ToRAMDAC))) + return; + + /* 1. New ROM: VGA2 and LCD/LCDA-Pass1:1 */ + /* (If a custom mode is used, Pass1:1 is always set; hence we do this:) */ + + if(SiS_Pr->SiS_ROMNew) { + if((SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) || + ((SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) && + (SiS_Pr->SiS_LCDInfo & LCDPass11))) { + index = 25; + if(SiS_Pr->UseCustomMode) { + index = SiS_Pr->CSRClock; + } else if(ModeNo > 0x13) { + index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RTI,HwInfo); + index = SiS_Pr->SiS_VCLKData[index].CLOCK; + } + if(index < 25) index = 25; + index = ((index / 25) - 1) << 1; + if((ROMAddr[0x5b] & 0x80) || (SiS_Pr->SiS_VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToLCD))) { + index++; + } + romptr = SISGETROMW(0x104); + delay = ROMAddr[romptr + index]; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToLCD)) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((delay >> 1) & 0x0f)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((delay & 0x01) << 7)); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((delay << 3) & 0xf0)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((delay & 0x01) << 6)); + } + return; + } + } + + /* 2. Old ROM: VGA2 and LCD/LCDA-Pass 1:1 */ + + if(SiS_Pr->UseCustomMode) delay = 0x04; + else if(ModeNo <= 0x13) delay = 0x04; + else delay = (SiS_Pr->SiS_RefIndex[RTI].Ext_PDC >> 4); + delay |= (delay << 8); + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + + /* 3. TV */ + + index = GetOEMTVPtr661(SiS_Pr); + if(SiS_Pr->SiS_ROMNew) { + romptr = SISGETROMW(0x106); + if(SiS_Pr->SiS_VBType & VB_UMC) romptr += 12; + delay = ROMAddr[romptr + index]; + } else { + delay = 0x04; + if(index > 3) delay = 0; + } + + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + + /* 4. LCD, LCDA (for new ROM only LV and non-Pass 1:1) */ + + if( (SiS_Pr->SiS_LCDResInfo != Panel_Custom) && + ((romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo))) ) { + + lcdpdcindex = (SiS_Pr->SiS_VBType & VB_UMC) ? 14 : 12; + + /* For LVDS (and sometimes TMDS), the BIOS must know about the correct value */ + delay = ROMAddr[romptr + lcdpdcindex + 1]; /* LCD */ + delay |= (ROMAddr[romptr + lcdpdcindex] << 8); /* LCDA */ + + } else { + + /* TMDS: Set our own, since BIOS has no idea */ + /* (This is done on >=661 only, since <661 is calling this only for LVDS) */ + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_1024x768: delay = 0x0008; break; + case Panel_1280x720: delay = 0x0004; break; + case Panel_1280x768: + case Panel_1280x768_2:delay = 0x0004; break; + case Panel_1280x800: + case Panel_1280x800_2:delay = 0x0004; break; /* Verified for 1280x800 */ + case Panel_1280x1024: delay = 0x1e04; break; + case Panel_1400x1050: delay = 0x0004; break; + case Panel_1600x1200: delay = 0x0400; break; + case Panel_1680x1050: delay = 0x0e04; break; + default: + if((SiS_Pr->PanelXRes <= 1024) && (SiS_Pr->PanelYRes <= 768)) { + delay = 0x0008; + } else if((SiS_Pr->PanelXRes == 1280) && (SiS_Pr->PanelYRes == 1024)) { + delay = 0x1e04; + } else if((SiS_Pr->PanelXRes <= 1400) && (SiS_Pr->PanelYRes <= 1050)) { + delay = 0x0004; + } else if((SiS_Pr->PanelXRes <= 1600) && (SiS_Pr->PanelYRes <= 1200)) { + delay = 0x0400; + } else + delay = 0x0e04; + break; + } + } + + /* Override by detected or user-set values */ + /* (but only if, for some reason, we can't read value from BIOS) */ + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->PDC != -1)) { + delay = SiS_Pr->PDC & 0x1f; + } + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) && (SiS_Pr->PDCA != -1)) { + delay = (SiS_Pr->PDCA & 0x1f) << 8; + } + + } + + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + delay >>= 8; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((delay << 3) & 0xf0)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((delay & 0x01) << 6)); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((delay >> 1) & 0x0f)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((delay & 0x01) << 7)); + } +} + +static void +SetCRT2SyncDither661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT RTI) +{ + USHORT infoflag; + UCHAR temp; + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + + if(ModeNo <= 0x13) { + infoflag = SiS_GetRegByte(SiS_Pr->SiS_P3ca+2); + } else if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + } else { + infoflag = SiS_Pr->SiS_RefIndex[RTI].Ext_InfoFlag; + } + + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + infoflag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); /* No longer check D5 */ + } + + infoflag &= 0xc0; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + temp = (infoflag >> 6) | 0x0c; + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { + temp ^= 0x04; + if(SiS_Pr->SiS_ModeType >= Mode24Bpp) temp |= 0x10; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xe0,temp); + } else { + temp = 0x30; + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) temp = 0x20; + temp |= infoflag; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0f,temp); + temp = 0; + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { + if(SiS_Pr->SiS_ModeType >= Mode24Bpp) temp |= 0x80; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1a,0x7f,temp); + } + + } +} + +static void +SetPanelParms661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT romptr, temp1, temp2; + + if(SiS_Pr->SiS_VBType & (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) { + if(SiS_Pr->LVDSHL != -1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,SiS_Pr->LVDSHL); + } + } + + if(SiS_Pr->SiS_ROMNew) { + + if((romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo))) { + if(SiS_Pr->SiS_VBType & (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) { + temp1 = (ROMAddr[romptr] & 0x03) | 0x0c; + temp2 = 0xfc; + if(SiS_Pr->LVDSHL != -1) { + temp1 &= 0xfc; + temp2 = 0xf3; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,temp2,temp1); + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + temp1 = (ROMAddr[romptr + 1] & 0x80) >> 1; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d,0xbf,temp1); + } + } + + } +} + +static void +SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex,USHORT RRTI) +{ + if((SiS_Pr->SiS_ROMNew) && (SiS_Pr->SiS_VBType & VB_SISLVDS)) { + SetDelayComp661(SiS_Pr,HwInfo,ModeNo,ModeIdIndex,RRTI); + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + SetCRT2SyncDither661(SiS_Pr,HwInfo,ModeNo,RRTI); + SetPanelParms661(SiS_Pr,HwInfo); + } + } else { + SetDelayComp(SiS_Pr,HwInfo,ModeNo); + } + + if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + SetAntiFlicker(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + SetPhaseIncr(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + SetYFilter(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + if(SiS_Pr->SiS_VBType & VB_SIS301) { + SetEdgeEnhance(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + } + } +} + +static void +SiS_OEM661Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex, USHORT RRTI) +{ + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + SetDelayComp661(SiS_Pr,HwInfo,ModeNo,ModeIdIndex,RRTI); + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + SetCRT2SyncDither661(SiS_Pr,HwInfo,ModeNo,RRTI); + SetPanelParms661(SiS_Pr,HwInfo); + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SetPhaseIncr(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + SetYFilter(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + SetAntiFlicker(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + if(SiS_Pr->SiS_VBType & VB_SIS301) { + SetEdgeEnhance(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + } + } + } +} + +/* FinalizeLCD + * This finalizes some CRT2 registers for the very panel used. + * If we have a backup if these registers, we use it; otherwise + * we set the register according to most BIOSes. However, this + * function looks quite different in every BIOS, so you better + * pray that we have a backup... + */ +static void +SiS_FinalizeLCD(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo) +{ + USHORT tempcl,tempch,tempbl,tempbh,tempbx,tempax,temp; + USHORT resinfo,modeflag; + + if(!(SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) return; + if(SiS_Pr->SiS_ROMNew) return; + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(SiS_Pr->LVDSHL != -1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,SiS_Pr->LVDSHL); + } + } + + if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) return; + if(SiS_Pr->UseCustomMode) return; + + switch(SiS_Pr->SiS_CustomT) { + case CUT_COMPAQ1280: + case CUT_COMPAQ12802: + case CUT_CLEVO1400: + case CUT_CLEVO14002: + return; + } + + if(ModeNo <= 0x13) { + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + if(IS_SIS650) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3d4, 0x5f) & 0xf0)) { + if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x02); + } else { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x03); + } + } + } + + if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + /* Maybe all panels? */ + if(SiS_Pr->LVDSHL == -1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01); + } + return; + } + } + + if(SiS_Pr->SiS_CustomT == CUT_CLEVO10242) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->LVDSHL == -1) { + /* Maybe all panels? */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01); + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + tempch = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4; + if(tempch == 3) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x25); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x1b); + } + } + return; + } + } + } + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00); +#ifdef SET_EMI + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); +#endif + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); + } + } else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if(SiS_Pr->LVDSHL == -1) { + /* Maybe ACER only? */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01); + } + } + tempch = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1f,0x76); + } else if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(tempch == 0x03) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x25); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x1b); + } + if((SiS_Pr->Backup == TRUE) && (SiS_Pr->Backup_Mode == ModeNo)) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,SiS_Pr->Backup_14); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,SiS_Pr->Backup_15); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,SiS_Pr->Backup_16); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,SiS_Pr->Backup_17); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,SiS_Pr->Backup_18); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,SiS_Pr->Backup_19); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1a,SiS_Pr->Backup_1a); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,SiS_Pr->Backup_1b); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,SiS_Pr->Backup_1c); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,SiS_Pr->Backup_1d); + } else if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { /* 1.10.8w */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,0x90); + if(ModeNo <= 0x13) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x11); + if((resinfo == 0) || (resinfo == 2)) return; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x18); + if((resinfo == 1) || (resinfo == 3)) return; + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02); + if((ModeNo > 0x13) && (resinfo == SIS_RI_1024x768)) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02); /* 1.10.7u */ +#if 0 + tempbx = 806; /* 0x326 */ /* other older BIOSes */ + tempbx--; + temp = tempbx & 0xff; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp); + temp = (tempbx >> 8) & 0x03; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1d,0xf8,temp); +#endif + } + } else if(ModeNo <= 0x13) { + if(ModeNo <= 1) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x70); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,0xff); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x48); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x12); + } + if(!(modeflag & HalfDCLK)) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,0x20); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,0x1a); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,0x28); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x4c); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,0xdc); + if(ModeNo == 0x12) { + switch(tempch) { + case 0: + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x95); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,0xdc); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1a,0x10); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x95); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,0x48); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x12); + break; + case 2: + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x95); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x48); + break; + case 3: + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x95); + break; + } + } + } + } + } + } else { + tempcl = tempbh = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x01); + tempcl &= 0x0f; + tempbh &= 0x70; + tempbh >>= 4; + tempbl = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x04); + tempbx = (tempbh << 8) | tempbl; + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if((resinfo == SIS_RI_1024x768) || (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD))) { + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + tempbx = 770; + } else { + if(tempbx > 770) tempbx = 770; + if(SiS_Pr->SiS_VGAVDE < 600) { + tempax = 768 - SiS_Pr->SiS_VGAVDE; + tempax >>= 4; /* 1.10.7w; 1.10.6s: 3; */ + if(SiS_Pr->SiS_VGAVDE <= 480) tempax >>= 4; /* 1.10.7w; 1.10.6s: < 480; >>=1; */ + tempbx -= tempax; + } + } + } else return; + } + temp = tempbx & 0xff; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,temp); + temp = ((tempbx & 0xff00) >> 4) | tempcl; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,temp); + } + } +} + +#endif + +/* ================= SiS 300 O.E.M. ================== */ + +#ifdef SIS300 + +static void +SetOEMLCDData2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex, USHORT RefTabIndex) +{ + USHORT crt2crtc=0, modeflag, myindex=0; + UCHAR temp; + int i; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + crt2crtc = SiS_Pr->SiS_RefIndex[RefTabIndex].Ext_CRT2CRTC; + } + + crt2crtc &= 0x3f; + + if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xdf); + } + + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { + if(modeflag & HalfDCLK) myindex = 1; + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + for(i=0; i<7; i++) { + if(barco_p1[myindex][crt2crtc][i][0]) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port, + barco_p1[myindex][crt2crtc][i][0], + barco_p1[myindex][crt2crtc][i][2], + barco_p1[myindex][crt2crtc][i][1]); + } + } + } + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); + if(temp & 0x80) { + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x18); + temp++; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp); + } + } +} + +static USHORT +GetOEMLCDPtr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, int Flag) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT tempbx=0,romptr=0; + UCHAR customtable300[] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff + }; + UCHAR customtable630[] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff + }; + + if(HwInfo->jChipType == SIS_300) { + + tempbx = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0x0f; + if(SiS_Pr->SiS_VBType & VB_SIS301) tempbx &= 0x07; + tempbx -= 2; + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx += 4; + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 3; + } + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x235] & 0x80) { + tempbx = SiS_Pr->SiS_LCDTypeInfo; + if(Flag) { + romptr = SISGETROMW(0x255); + if(romptr) tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo]; + else tempbx = customtable300[SiS_Pr->SiS_LCDTypeInfo]; + if(tempbx == 0xFF) return 0xFFFF; + } + tempbx <<= 1; + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx++; + } + } + + } else { + + if(Flag) { + if(SiS_Pr->SiS_UseROM) { + romptr = SISGETROMW(0x255); + if(romptr) tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo]; + else tempbx = 0xff; + } else { + tempbx = customtable630[SiS_Pr->SiS_LCDTypeInfo]; + } + if(tempbx == 0xFF) return 0xFFFF; + tempbx <<= 2; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempbx += 2; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + return tempbx; + } + tempbx = SiS_Pr->SiS_LCDTypeInfo << 2; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempbx += 2; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + + } + + return tempbx; +} + +static void +SetOEMLCDDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT index,temp,romptr=0; + + if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) return; + + if(SiS_Pr->SiS_UseROM) { + if(!(ROMAddr[0x237] & 0x01)) return; + if(!(ROMAddr[0x237] & 0x02)) return; + romptr = SISGETROMW(0x24b); + } + + /* The Panel Compensation Delay should be set according to tables + * here. Unfortunately, various BIOS versions don't case about + * a uniform way using eg. ROM byte 0x220, but use different + * hard coded delays (0x04, 0x20, 0x18) in SetGroup1(). + * Thus we don't set this if the user select a custom pdc or if + * we otherwise detected a valid pdc. + */ + if(SiS_Pr->PDC != -1) return; + + temp = GetOEMLCDPtr(SiS_Pr,HwInfo, 0); + + if(SiS_Pr->UseCustomMode) + index = 0; + else + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex; + + if(HwInfo->jChipType != SIS_300) { + if(romptr) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += index; + temp = ROMAddr[romptr]; + } else { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = SiS300_OEMLCDDelay2[temp][index]; + } else { + temp = SiS300_OEMLCDDelay3[temp][index]; + } + } + } else { + if(SiS_Pr->SiS_UseROM && (ROMAddr[0x235] & 0x80)) { + if(romptr) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += index; + temp = ROMAddr[romptr]; + } else { + temp = SiS300_OEMLCDDelay5[temp][index]; + } + } else { + if(SiS_Pr->SiS_UseROM) { + romptr = ROMAddr[0x249] | (ROMAddr[0x24a] << 8); + if(romptr) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += index; + temp = ROMAddr[romptr]; + } else { + temp = SiS300_OEMLCDDelay4[temp][index]; + } + } else { + temp = SiS300_OEMLCDDelay4[temp][index]; + } + } + } + temp &= 0x3c; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); /* index 0A D[6:4] */ +} + +static void +SetOEMLCDData(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex) +{ +#if 0 /* Unfinished; Data table missing */ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT index,temp; + + if((SiS_Pr->SiS_UseROM) { + if(!(ROMAddr[0x237] & 0x01)) return; + if(!(ROMAddr[0x237] & 0x04)) return; + /* No rom pointer in BIOS header! */ + } + + temp = GetOEMLCDPtr(SiS_Pr,HwInfo, 1); + if(temp = 0xFFFF) return; + + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex]._VB_LCDHIndex; + for(i=0x14, j=0; i<=0x17; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,i,SiS300_LCDHData[temp][index][j]); + } + SiS_SetRegANDOR(SiS_SiS_Part1Port,0x1a, 0xf8, (SiS300_LCDHData[temp][index][j] & 0x07)); + + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex]._VB_LCDVIndex; + SiS_SetReg(SiS_SiS_Part1Port,0x18, SiS300_LCDVData[temp][index][0]); + SiS_SetRegANDOR(SiS_SiS_Part1Port,0x19, 0xF0, SiS300_LCDVData[temp][index][1]); + SiS_SetRegANDOR(SiS_SiS_Part1Port,0x1A, 0xC7, (SiS300_LCDVData[temp][index][2] & 0x38)); + for(i=0x1b, j=3; i<=0x1d; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,i,SiS300_LCDVData[temp][index][j]); + } +#endif +} + +static USHORT +GetOEMTVPtr(SiS_Private *SiS_Pr) +{ + USHORT index; + + index = 0; + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) index += 4; + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART) index += 2; + else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) index += 3; + else if(SiS_Pr->SiS_TVMode & TVSetPAL) index += 1; + } else { + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) index += 2; + if(SiS_Pr->SiS_TVMode & TVSetPAL) index += 1; + } + return index; +} + +static void +SetOEMTVDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT index,temp,romptr=0; + + if(SiS_Pr->SiS_UseROM) { + if(!(ROMAddr[0x238] & 0x01)) return; + if(!(ROMAddr[0x238] & 0x02)) return; + romptr = SISGETROMW(0x241); + } + + temp = GetOEMTVPtr(SiS_Pr); + + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVDelayIndex; + + if(romptr) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += index; + temp = ROMAddr[romptr]; + } else { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = SiS300_OEMTVDelay301[temp][index]; + } else { + temp = SiS300_OEMTVDelayLVDS[temp][index]; + } + } + temp &= 0x3c; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); +} + +static void +SetOEMAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo, USHORT ModeIdIndex) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT index,temp,romptr=0; + + if(SiS_Pr->SiS_UseROM) { + if(!(ROMAddr[0x238] & 0x01)) return; + if(!(ROMAddr[0x238] & 0x04)) return; + romptr = SISGETROMW(0x243); + } + + temp = GetOEMTVPtr(SiS_Pr); + + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVFlickerIndex; + + if(romptr) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += index; + temp = ROMAddr[romptr]; + } else { + temp = SiS300_OEMTVFlicker[temp][index]; + } + temp &= 0x70; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8F,temp); +} + +static void +SetOEMPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT index,i,j,temp,romptr=0; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) return; + + if(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSetNTSCJ | TVSetPALM | TVSetPALN)) return; + + if(SiS_Pr->SiS_UseROM) { + if(!(ROMAddr[0x238] & 0x01)) return; + if(!(ROMAddr[0x238] & 0x08)) return; + romptr = SISGETROMW(0x245); + } + + temp = GetOEMTVPtr(SiS_Pr); + + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVPhaseIndex; + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + for(i=0x31, j=0; i<=0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Phase2[temp][index][j]); + } + } else { + if(romptr) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += (index * 4); + for(i=0x31, j=0; i<=0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]); + } + } else { + for(i=0x31, j=0; i<=0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Phase1[temp][index][j]); + } + } + } +} + +static void +SetOEMYFilter(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT index,temp,i,j,romptr=0; + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSCART | SetCRT2ToHiVision | SetCRT2ToYPbPr525750)) return; + + if(SiS_Pr->SiS_UseROM) { + if(!(ROMAddr[0x238] & 0x01)) return; + if(!(ROMAddr[0x238] & 0x10)) return; + romptr = SISGETROMW(0x247); + } + + temp = GetOEMTVPtr(SiS_Pr); + + if(SiS_Pr->SiS_TVMode & TVSetPALM) temp = 8; + else if(SiS_Pr->SiS_TVMode & TVSetPALN) temp = 9; + /* NTSCJ uses NTSC filters */ + + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVYFilterIndex; + + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + for(i=0x35, j=0; i<=0x38; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Filter2[temp][index][j]); + } + for(i=0x48; i<=0x4A; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Filter2[temp][index][j]); + } + } else { + if((romptr) && (!(SiS_Pr->SiS_TVMode & (TVSetPALM|TVSetPALN)))) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += (index * 4); + for(i=0x35, j=0; i<=0x38; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]); + } + } else { + for(i=0x35, j=0; i<=0x38; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Filter1[temp][index][j]); + } + } + } +} + +static USHORT +SiS_SearchVBModeID(SiS_Private *SiS_Pr, USHORT *ModeNo) +{ + USHORT ModeIdIndex; + UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO; + + if(*ModeNo <= 5) *ModeNo |= 1; + + for(ModeIdIndex=0; ; ModeIdIndex++) { + if(SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].ModeID == *ModeNo) break; + if(SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].ModeID == 0xFF) return 0; + } + + if(*ModeNo != 0x07) { + if(*ModeNo > 0x03) return ModeIdIndex; + if(VGAINFO & 0x80) return ModeIdIndex; + ModeIdIndex++; + } + + if(VGAINFO & 0x10) ModeIdIndex++; /* 400 lines */ + /* else 350 lines */ + return ModeIdIndex; +} + +static void +SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo, USHORT ModeIdIndex, USHORT RefTableIndex) +{ + USHORT OEMModeIdIndex=0; + + if(!SiS_Pr->UseCustomMode) { + OEMModeIdIndex = SiS_SearchVBModeID(SiS_Pr,&ModeNo); + if(!(OEMModeIdIndex)) return; + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SetOEMLCDDelay(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex); + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + SetOEMLCDData(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex); + } + } + if(SiS_Pr->UseCustomMode) return; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SetOEMTVDelay(SiS_Pr, HwInfo, ModeNo,OEMModeIdIndex); + if(SiS_Pr->SiS_VBType & VB_SISVB) { + SetOEMAntiFlicker(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex); + SetOEMPhaseIncr(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex); + SetOEMYFilter(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex); + } + } +} +#endif + diff --git a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h new file mode 100644 index 000000000000..f05aebc994b4 --- /dev/null +++ b/drivers/video/sis/init301.h @@ -0,0 +1,410 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Data and prototypes for init301.c + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _INIT301_ +#define _INIT301_ + +#include "osdef.h" +#include "initdef.h" + +#ifdef LINUX_XF86 +#include "sis.h" +#include "sis_regs.h" +#endif + +#ifdef LINUX_KERNEL +#include "vgatypes.h" +#include "vstruct.h" +#ifdef SIS_CP +#undef SIS_CP +#endif +#include <linux/config.h> +#include <linux/version.h> +#include <asm/io.h> +#include <linux/types.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include <linux/sisfb.h> +#else +#include <video/sisfb.h> +#endif +#endif + +static const UCHAR SiS_YPbPrTable[3][64] = { + { + 0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c, + 0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b, + 0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17, + 0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02, + 0x03,0x0a,0x65,0x9d /*0x8d*/,0x08,0x92,0x8f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x53 /*0x50*/, + 0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00 + }, + { + 0x1d,0x11,0x06,0x09,0x0b,0x0c,0x0c,0x0c, + 0x98,0x0a,0x01,0x0d,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, + 0x0c,0x50,0xb2,0x9f,0x16,0x59,0x4c /*0x4f*/,0x13, + 0xad,0x11,0xad,0x1d,0x40,0x8a,0x3d,0xb8, + 0x51,0x5e,0x60,0x57 /*0x49*/,0x7b /*0x7d*/,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x4b, + 0x43,0x41,0x11,0x00,0xfc,0xff,0x32,0x00 + }, + { +#if 1 + 0x13,0x1d,0xe8,0x09,0x09,0xed,0x0c,0x0c, + 0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, + 0xed,0x50,0x70,0x9f,0x16,0x59,0x21 /*0x2b*/,0x13, + 0x27,0x0b,0x27,0xfc,0x30,0x27,0x1c,0xb0, + 0x4b,0x4b,0x65 /*0x6f*/,0x2f,0x63,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x27, + 0x00,0x40,0x11,0x00,0xfc,0xff,0x32,0x00 +#endif +#if 0 + 0x2a,0x14,0xe8,0x09,0x09,0xed,0x0c,0x0c, /* TEST (0.93) - BAD */ + 0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, + 0xed,0x50,0x70,0x9e,0x16,0x57,0x6c,0x13, + 0x27,0x0b,0x27,0xfb,0x30,0x27,0x15,0xb0, + 0x3b,0xdb,0x61,0x24,0x78,0x92,0x0f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x14,0x6f, + 0x00,0x52,0xbb,0x00,0xd5,0xf7,0xa2,0x00 +#endif + } +}; + +static const UCHAR SiS_HiTVGroup3_1[] = { + 0x00, 0x14, 0x15, 0x25, 0x55, 0x15, 0x0b, 0x13, + 0xb1, 0x41, 0x62, 0x62, 0xff, 0xf4, 0x45, 0xa6, + 0x25, 0x2f, 0x67, 0xf6, 0xbf, 0xff, 0x8e, 0x20, + 0xac, 0xda, 0x60, 0xfe, 0x6a, 0x9a, 0x06, 0x10, + 0xd1, 0x04, 0x18, 0x0a, 0xff, 0x80, 0x00, 0x80, + 0x3b, 0x77, 0x00, 0xef, 0xe0, 0x10, 0xb0, 0xe0, + 0x10, 0x4f, 0x0f, 0x0f, 0x05, 0x0f, 0x08, 0x6e, + 0x1a, 0x1f, 0x25, 0x2a, 0x4c, 0xaa, 0x01 +}; + +static const UCHAR SiS_HiTVGroup3_2[] = { + 0x00, 0x14, 0x15, 0x25, 0x55, 0x15, 0x0b, 0x7a, + 0x54, 0x41, 0xe7, 0xe7, 0xff, 0xf4, 0x45, 0xa6, + 0x25, 0x2f, 0x67, 0xf6, 0xbf, 0xff, 0x8e, 0x20, + 0xac, 0x6a, 0x60, 0x2b, 0x52, 0xcd, 0x61, 0x10, + 0x51, 0x04, 0x18, 0x0a, 0x1f, 0x80, 0x00, 0x80, + 0xff, 0xa4, 0x04, 0x2b, 0x94, 0x21, 0x72, 0x94, + 0x26, 0x05, 0x01, 0x0f, 0xed, 0x0f, 0x0a, 0x64, + 0x18, 0x1d, 0x23, 0x28, 0x4c, 0xaa, 0x01 +}; + +/* 301C / 302ELV extended Part2 TV registers (4 tap scaler) */ + +static const UCHAR SiS_Part2CLVX_1[] = { + 0x00,0x00, + 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F,0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, + 0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E,0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C, + 0x7C,0x14,0x14,0x7C,0x7C,0x11,0x17,0x7C,0x7D,0x0E,0x19,0x7C,0x7E,0x0B,0x1B,0x7C, + 0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C,0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E +}; + +static const UCHAR SiS_Part2CLVX_2[] = { + 0x00,0x00, + 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F,0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, + 0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E,0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C, + 0x7C,0x14,0x14,0x7C,0x7C,0x11,0x17,0x7C,0x7D,0x0E,0x19,0x7C,0x7E,0x0B,0x1B,0x7C, + 0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C,0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E +}; + +static const UCHAR SiS_Part2CLVX_3[] = { /* NTSC, 525i, 525p */ + 0xE0,0x01, + 0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D,0x01,0x1A,0x08,0x7D,0x00,0x19,0x0A,0x7D, + 0x7F,0x19,0x0C,0x7C,0x7E,0x18,0x0E,0x7C,0x7E,0x17,0x10,0x7B,0x7D,0x15,0x12,0x7C, + 0x7D,0x13,0x13,0x7D,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x7D,0x7C,0x0E,0x18,0x7E, + 0x7D,0x0C,0x19,0x7E,0x7D,0x0A,0x19,0x00,0x7D,0x08,0x1A,0x01,0x7E,0x06,0x1A,0x02, + 0x58,0x02, + 0x07,0x14,0x07,0x7E,0x06,0x14,0x09,0x7D,0x05,0x14,0x0A,0x7D,0x04,0x13,0x0B,0x7E, + 0x03,0x13,0x0C,0x7E,0x02,0x12,0x0D,0x7F,0x01,0x12,0x0E,0x7F,0x01,0x11,0x0F,0x7F, + 0x00,0x10,0x10,0x00,0x7F,0x0F,0x11,0x01,0x7F,0x0E,0x12,0x01,0x7E,0x0D,0x12,0x03, + 0x7E,0x0C,0x13,0x03,0x7E,0x0B,0x13,0x04,0x7E,0x0A,0x14,0x04,0x7D,0x09,0x14,0x06, + 0x00,0x03, + 0x09,0x0F,0x09,0x7F,0x08,0x0F,0x09,0x00,0x07,0x0F,0x0A,0x00,0x06,0x0F,0x0A,0x01, + 0x06,0x0E,0x0B,0x01,0x05,0x0E,0x0B,0x02,0x04,0x0E,0x0C,0x02,0x04,0x0D,0x0C,0x03, + 0x03,0x0D,0x0D,0x03,0x02,0x0C,0x0D,0x05,0x02,0x0C,0x0E,0x04,0x01,0x0B,0x0E,0x06, + 0x01,0x0B,0x0E,0x06,0x00,0x0A,0x0F,0x07,0x00,0x0A,0x0F,0x07,0x00,0x09,0x0F,0x08, + 0xFF,0xFF +}; + +static const UCHAR SiS_Part2CLVX_4[] = { /* PAL */ + 0x58,0x02, + 0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E,0x02,0x19,0x08,0x7D,0x01,0x18,0x0A,0x7D, + 0x00,0x18,0x0C,0x7C,0x7F,0x17,0x0E,0x7C,0x7E,0x16,0x0F,0x7D,0x7E,0x14,0x11,0x7D, + 0x7D,0x13,0x13,0x7D,0x7D,0x11,0x14,0x7E,0x7D,0x0F,0x16,0x7E,0x7D,0x0E,0x17,0x7E, + 0x7D,0x0C,0x18,0x7F,0x7D,0x0A,0x18,0x01,0x7D,0x08,0x19,0x02,0x7D,0x06,0x19,0x04, + 0x00,0x03, + 0x08,0x12,0x08,0x7E,0x07,0x12,0x09,0x7E,0x06,0x12,0x0A,0x7E,0x05,0x11,0x0B,0x7F, + 0x04,0x11,0x0C,0x7F,0x03,0x11,0x0C,0x00,0x03,0x10,0x0D,0x00,0x02,0x0F,0x0E,0x01, + 0x01,0x0F,0x0F,0x01,0x01,0x0E,0x0F,0x02,0x00,0x0D,0x10,0x03,0x7F,0x0C,0x11,0x04, + 0x7F,0x0C,0x11,0x04,0x7F,0x0B,0x11,0x05,0x7E,0x0A,0x12,0x06,0x7E,0x09,0x12,0x07, + 0x40,0x02, + 0x04,0x1A,0x04,0x7E,0x02,0x1B,0x05,0x7E,0x01,0x1A,0x07,0x7E,0x00,0x1A,0x09,0x7D, + 0x7F,0x19,0x0B,0x7D,0x7E,0x18,0x0D,0x7D,0x7D,0x17,0x10,0x7C,0x7D,0x15,0x12,0x7C, + 0x7C,0x14,0x14,0x7C,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x7D,0x7C,0x0D,0x18,0x7F, + 0x7D,0x0B,0x19,0x7F,0x7D,0x09,0x1A,0x00,0x7D,0x07,0x1A,0x02,0x7E,0x05,0x1B,0x02, + 0xFF,0xFF +}; + +static const UCHAR SiS_Part2CLVX_5[] = { /* 750p */ + 0x00,0x03, + 0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E,0x02,0x19,0x08,0x7D,0x01,0x18,0x0A,0x7D, + 0x00,0x18,0x0C,0x7C,0x7F,0x17,0x0E,0x7C,0x7E,0x16,0x0F,0x7D,0x7E,0x14,0x11,0x7D, + 0x7D,0x13,0x13,0x7D,0x7D,0x11,0x14,0x7E,0x7D,0x0F,0x16,0x7E,0x7D,0x0E,0x17,0x7E, + 0x7D,0x0C,0x18,0x7F,0x7D,0x0A,0x18,0x01,0x7D,0x08,0x19,0x02,0x7D,0x06,0x19,0x04, + 0xFF,0xFF +}; + +static const UCHAR SiS_Part2CLVX_6[] = { /* 1080i */ + 0x00,0x04, + 0x04,0x1A,0x04,0x7E,0x02,0x1B,0x05,0x7E,0x01,0x1A,0x07,0x7E,0x00,0x1A,0x09,0x7D, + 0x7F,0x19,0x0B,0x7D,0x7E,0x18,0x0D,0x7D,0x7D,0x17,0x10,0x7C,0x7D,0x15,0x12,0x7C, + 0x7C,0x14,0x14,0x7C,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x7D,0x7C,0x0D,0x18,0x7F, + 0x7D,0x0B,0x19,0x7F,0x7D,0x09,0x1A,0x00,0x7D,0x07,0x1A,0x02,0x7E,0x05,0x1B,0x02, + 0xFF,0xFF, +}; + +#ifdef SIS315H +/* 661 et al LCD data structure (2.03.00) */ +static const UCHAR SiS_LCDStruct661[] = { + /* 1024x768 */ +/* type|CR37| HDE | VDE | HT | VT | hss | hse */ + 0x02,0xC0,0x00,0x04,0x00,0x03,0x40,0x05,0x26,0x03,0x10,0x00,0x88, + 0x00,0x02,0x00,0x06,0x00,0x41,0x5A,0x64,0x00,0x00,0x00,0x00,0x04, + /* | vss | vse |clck| clock |CRT2DataP|CRT2DataP|idx */ + /* VESA non-VESA noscale */ + /* 1280x1024 */ + 0x03,0xC0,0x00,0x05,0x00,0x04,0x98,0x06,0x2A,0x04,0x30,0x00,0x70, + 0x00,0x01,0x00,0x03,0x00,0x6C,0xF8,0x2F,0x00,0x00,0x00,0x00,0x08, + /* 1400x1050 */ + 0x09,0x20,0x78,0x05,0x1A,0x04,0x98,0x06,0x2A,0x04,0x18,0x00,0x38, + 0x00,0x01,0x00,0x03,0x00,0x6C,0xF8,0x2F,0x00,0x00,0x00,0x00,0x09, + /* 1600x1200 */ + 0x0B,0xE0,0x40,0x06,0xB0,0x04,0x70,0x08,0xE2,0x04,0x40,0x00,0xC0, + 0x00,0x01,0x00,0x03,0x00,0xA2,0x70,0x24,0x00,0x00,0x00,0x00,0x0A, + /* 1280x768 (_2) */ + 0x0A,0xE0,0x00,0x05,0x00,0x03,0x7C,0x06,0x26,0x03,0x30,0x00,0x70, + 0x00,0x03,0x00,0x06,0x00,0x4D,0xC8,0x48,0x00,0x00,0x00,0x00,0x06, + /* 1280x720 */ + 0x0E,0xE0,0x00,0x05,0xD0,0x02,0x80,0x05,0x26,0x03,0x10,0x00,0x20, + 0x00,0x01,0x00,0x06,0x00,0x45,0x9C,0x62,0x00,0x00,0x00,0x00,0x05, + /* 1280x800 (_2) */ + 0x0C,0xE0,0x00,0x05,0x20,0x03,0x10,0x06,0x2C,0x03,0x30,0x00,0x70, + 0x00,0x04,0x00,0x03,0x00,0x49,0xCE,0x1E,0x00,0x00,0x00,0x00,0x09, + /* 1680x1050 */ + 0x0D,0xE0,0x90,0x06,0x1A,0x04,0x6C,0x07,0x2A,0x04,0x1A,0x00,0x4C, + 0x00,0x03,0x00,0x06,0x00,0x79,0xBE,0x44,0x00,0x00,0x00,0x00,0x06, +}; +#endif + +#ifdef SIS300 +static UCHAR SiS300_TrumpionData[7][80] = { + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, + 0x20,0x03,0x0B,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x10,0x00,0x00,0x04,0x23, + 0x00,0x00,0x03,0x28,0x03,0x10,0x05,0x08,0x40,0x10,0x00,0x10,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xBC,0x01,0xFF,0x03,0xFF,0x19,0x01,0x00,0x05,0x09,0x04,0x04,0x05, + 0x04,0x0C,0x09,0x05,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5A,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x27,0x00,0x80,0x02, + 0x20,0x03,0x07,0x00,0x5E,0x01,0x0D,0x02,0x60,0x0C,0x30,0x11,0x00,0x00,0x04,0x23, + 0x00,0x00,0x03,0x80,0x03,0x28,0x06,0x08,0x40,0x11,0x00,0x11,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0x90,0x01,0xFF,0x0F,0xF4,0x19,0x01,0x00,0x05,0x01,0x00,0x04,0x05, + 0x04,0x0C,0x02,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xEC,0x57,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x8A,0x00,0xD8,0x02, + 0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23, + 0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xD9,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05, + 0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x59,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x72,0x00,0xD8,0x02, + 0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23, + 0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xDA,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05, + 0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x02,0x00,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, + 0x20,0x03,0x16,0x00,0xE0,0x01,0x0D,0x02,0x60,0x0C,0x30,0x98,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x45,0x03,0x48,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xF4,0x01,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x05,0x01,0x00,0x05,0x05, + 0x04,0x0C,0x08,0x05,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x02,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0xBF,0x00,0x20,0x03, + 0x20,0x04,0x0D,0x00,0x58,0x02,0x71,0x02,0x80,0x0C,0x30,0x9A,0x00,0xFA,0x03,0x1D, + 0x00,0x01,0x03,0x22,0x03,0x28,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x1D,0x00,0x1D, + 0x03,0x11,0x60,0x39,0x03,0x40,0x05,0xF4,0x18,0x07,0x02,0x06,0x04,0x01,0x06,0x0B, + 0x02,0x0A,0x20,0x19,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0xEF,0x00,0x00,0x04, + 0x40,0x05,0x13,0x00,0x00,0x03,0x26,0x03,0x88,0x0C,0x30,0x90,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x24,0x03,0x28,0x06,0x08,0x40,0x90,0x00,0x90,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0x40,0x05,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x08,0x01,0x00,0x08,0x01, + 0x00,0x08,0x01,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 } +}; +#endif + +void SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +void SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +void SiS_EnableCRT2(SiS_Private *SiS_Pr); +USHORT SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo); +void SiS_WaitRetrace1(SiS_Private *SiS_Pr); +BOOLEAN SiS_IsDualEdge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +BOOLEAN SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +void SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo); +void SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_INFO HwInfo, + int checkcrt2mode); +void SiS_SetYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +void SiS_SetTVMode(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo); +void SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo); +USHORT SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo); +USHORT SiS_GetResInfo(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex); +void SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +void SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +BOOLEAN SiS_SetCRT2Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo); +void SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +void SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); + +void SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempax); +USHORT SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempax); +void SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempax); +USHORT SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempax); +void SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempax); +USHORT SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempax); +void SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh); +#ifdef SIS315H +static void SiS_Chrontel701xOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +static void SiS_Chrontel701xOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +static void SiS_ChrontelInitTVVSync(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +static void SiS_ChrontelDoSomething1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +void SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +void SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr); +#endif /* 315 */ + +#ifdef SIS300 +#if 0 +static void SiS_SetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx); +static USHORT SiS_GetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx); +#endif +static BOOLEAN SiS_SetTrumpionBlock(SiS_Private *SiS_Pr, UCHAR *dataptr); +#endif + +void SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime); +USHORT SiS_ReadDDC1Bit(SiS_Private *SiS_Pr); +USHORT SiS_HandleDDC(SiS_Private *SiS_Pr, ULONG VBFlags, int VGAEngine, + USHORT adaptnum, USHORT DDCdatatype, UCHAR *buffer); +#ifdef LINUX_XF86 +USHORT SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SISPtr pSiS); +USHORT SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SISPtr pSiS); +#endif + +static void SiS_SetSwitchDDC2(SiS_Private *SiS_Pr); +static USHORT SiS_SetStart(SiS_Private *SiS_Pr); +static USHORT SiS_SetStop(SiS_Private *SiS_Pr); +static USHORT SiS_SetSCLKLow(SiS_Private *SiS_Pr); +static USHORT SiS_SetSCLKHigh(SiS_Private *SiS_Pr); +static USHORT SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax); +static USHORT SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax); +static USHORT SiS_CheckACK(SiS_Private *SiS_Pr); +static USHORT SiS_InitDDCRegs(SiS_Private *SiS_Pr, ULONG VBFlags, int VGAEngine, + USHORT adaptnum, USHORT DDCdatatype, BOOLEAN checkcr32); +static USHORT SiS_WriteDABDDC(SiS_Private *SiS_Pr); +static USHORT SiS_PrepareReadDDC(SiS_Private *SiS_Pr); +static USHORT SiS_PrepareDDC(SiS_Private *SiS_Pr); +static void SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno); +static USHORT SiS_DoProbeDDC(SiS_Private *SiS_Pr); +static USHORT SiS_ProbeDDC(SiS_Private *SiS_Pr); +static USHORT SiS_ReadDDC(SiS_Private *SiS_Pr, USHORT DDCdatatype, UCHAR *buffer); + +#ifdef SIS315H +static void SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex, USHORT RRTI); +static void SiS_OEM661Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo,USHORT ModeIdIndex, USHORT RRTI); +static void SiS_FinalizeLCD(SiS_Private *, USHORT, USHORT, PSIS_HW_INFO); +#endif +#ifdef SIS300 +static void SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo, USHORT ModeIdIndex, USHORT RefTabindex); +static void SetOEMLCDData2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo, USHORT ModeIdIndex,USHORT RefTableIndex); +#endif + +extern void SiS_SetReg(SISIOADDRESS, USHORT, USHORT); +extern void SiS_SetRegByte(SISIOADDRESS, USHORT); +extern void SiS_SetRegShort(SISIOADDRESS, USHORT); +extern void SiS_SetRegLong(SISIOADDRESS, ULONG); +extern UCHAR SiS_GetReg(SISIOADDRESS, USHORT); +extern UCHAR SiS_GetRegByte(SISIOADDRESS); +extern USHORT SiS_GetRegShort(SISIOADDRESS); +extern ULONG SiS_GetRegLong(SISIOADDRESS); +extern void SiS_SetRegANDOR(SISIOADDRESS, USHORT, USHORT, USHORT); +extern void SiS_SetRegOR(SISIOADDRESS, USHORT, USHORT); +extern void SiS_SetRegAND(SISIOADDRESS, USHORT, USHORT); +extern void SiS_DisplayOff(SiS_Private *SiS_Pr); +extern void SiS_DisplayOn(SiS_Private *SiS_Pr); +extern BOOLEAN SiS_SearchModeID(SiS_Private *, USHORT *, USHORT *); +extern UCHAR SiS_GetModePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); +extern USHORT SiS_GetColorDepth(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); +extern USHORT SiS_GetOffset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo); +extern void SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO, USHORT ModeNo, + USHORT ModeIdIndex); +extern void SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); +#ifdef LINUX_XF86 +extern void SiS_MakeClockRegs(ScrnInfoPtr pScrn, int clock, UCHAR *p2b, UCHAR *p2c); +extern int SiS_FindPanelFromDB(SISPtr pSiS, USHORT panelvendor, USHORT panelproduct, + int *maxx, int *maxy, int *prefx, int *prefy); +#endif + +#endif diff --git a/drivers/video/sis/initdef.h b/drivers/video/sis/initdef.h new file mode 100644 index 000000000000..55a82d6dc4cf --- /dev/null +++ b/drivers/video/sis/initdef.h @@ -0,0 +1,671 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Global definitions for init.c and init301.c + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _INITDEF_ +#define _INITDEF_ + +#define IS_SIS330 (HwInfo->jChipType == SIS_330) +#define IS_SIS550 (HwInfo->jChipType == SIS_550) +#define IS_SIS650 (HwInfo->jChipType == SIS_650) /* All versions, incl 651, M65x */ +#define IS_SIS740 (HwInfo->jChipType == SIS_740) +#define IS_SIS651 (SiS_Pr->SiS_SysFlags & (SF_Is651 | SF_Is652)) +#define IS_SISM650 (SiS_Pr->SiS_SysFlags & (SF_IsM650 | SF_IsM652 | SF_IsM653)) +#define IS_SIS65x (IS_SIS651 || IS_SISM650) /* Only special versions of 65x */ +#define IS_SIS661 (HwInfo->jChipType == SIS_661) +#define IS_SIS741 (HwInfo->jChipType == SIS_741) +#define IS_SIS660 (HwInfo->jChipType == SIS_660) +#define IS_SIS760 (HwInfo->jChipType == SIS_760) +#define IS_SIS661741660760 (IS_SIS661 || IS_SIS741 || IS_SIS660 || IS_SIS760) +#define IS_SIS650740 ((HwInfo->jChipType >= SIS_650) && (HwInfo->jChipType < SIS_330)) +#define IS_SIS550650740 (IS_SIS550 || IS_SIS650740) +#define IS_SIS650740660 (IS_SIS650 || IS_SIS740 || IS_SIS661741660760) +#define IS_SIS550650740660 (IS_SIS550 || IS_SIS650740660) + +#define SISGETROMW(x) (ROMAddr[(x)] | (ROMAddr[(x)+1] << 8)) + +/* SiS_VBType */ +#define VB_SIS301 0x0001 +#define VB_SIS301B 0x0002 +#define VB_SIS302B 0x0004 +#define VB_SIS301LV 0x0008 +#define VB_SIS302LV 0x0010 +#define VB_SIS302ELV 0x0020 +#define VB_SIS301C 0x0040 +#define VB_UMC 0x4000 +#define VB_NoLCD 0x8000 +#define VB_SIS301BLV302BLV (VB_SIS301B|VB_SIS301C|VB_SIS302B|VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV) +#define VB_SIS301B302B (VB_SIS301B|VB_SIS301C|VB_SIS302B) +#define VB_SIS301LV302LV (VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV) +#define VB_SISVB (VB_SIS301 | VB_SIS301BLV302BLV) +#define VB_SISTMDS (VB_SIS301 | VB_SIS301B302B) +#define VB_SISLVDS VB_SIS301LV302LV +#define VB_SISLCDA (VB_SIS302B|VB_SIS301C|VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV) +#define VB_SISYPBPR (VB_SIS301C|VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV) +#define VB_SISHIVISION (VB_SIS301|VB_SIS301B|VB_SIS302B) + +/* VBInfo */ +#define SetSimuScanMode 0x0001 /* CR 30 */ +#define SwitchCRT2 0x0002 +#define SetCRT2ToAVIDEO 0x0004 +#define SetCRT2ToSVIDEO 0x0008 +#define SetCRT2ToSCART 0x0010 +#define SetCRT2ToLCD 0x0020 +#define SetCRT2ToRAMDAC 0x0040 +#define SetCRT2ToHiVision 0x0080 /* for SiS bridge */ +#define SetCRT2ToCHYPbPr SetCRT2ToHiVision /* for Chrontel */ +#define SetNTSCTV 0x0000 /* CR 31 */ +#define SetPALTV 0x0100 /* Deprecated here, now in TVMode */ +#define SetInSlaveMode 0x0200 +#define SetNotSimuMode 0x0400 +#define SetNotSimuTVMode SetNotSimuMode +#define SetDispDevSwitch 0x0800 +#define SetCRT2ToYPbPr525750 0x0800 +#define LoadDACFlag 0x1000 +#define DisableCRT2Display 0x2000 +#define DriverMode 0x4000 +#define HotKeySwitch 0x8000 +#define SetCRT2ToLCDA 0x8000 + +/* v-- Needs change in sis_vga.c if changed (GPIO) --v */ +#define SetCRT2ToTV (SetCRT2ToYPbPr525750|SetCRT2ToHiVision|SetCRT2ToSCART|SetCRT2ToSVIDEO|SetCRT2ToAVIDEO) +#define SetCRT2ToTVNoYPbPrHiVision (SetCRT2ToSCART | SetCRT2ToSVIDEO | SetCRT2ToAVIDEO) +#define SetCRT2ToTVNoHiVision (SetCRT2ToYPbPr525750 | SetCRT2ToSCART | SetCRT2ToSVIDEO | SetCRT2ToAVIDEO) + +/* SiS_ModeType */ +#define ModeText 0x00 +#define ModeCGA 0x01 +#define ModeEGA 0x02 +#define ModeVGA 0x03 +#define Mode15Bpp 0x04 +#define Mode16Bpp 0x05 +#define Mode24Bpp 0x06 +#define Mode32Bpp 0x07 + +#define ModeTypeMask 0x07 +#define IsTextMode 0x07 + +#define DACInfoFlag 0x0018 +#define MemoryInfoFlag 0x01E0 +#define MemorySizeShift 5 + +/* modeflag */ +#define Charx8Dot 0x0200 +#define LineCompareOff 0x0400 +#define CRT2Mode 0x0800 +#define HalfDCLK 0x1000 +#define NoSupportSimuTV 0x2000 +#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ +#define DoubleScanMode 0x8000 + +/* Infoflag */ +#define SupportTV 0x0008 +#define SupportTV1024 0x0800 +#define SupportCHTV 0x0800 +#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ +#define SupportHiVision 0x0010 +#define SupportYPbPr750p 0x1000 +#define SupportLCD 0x0020 +#define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */ +#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ +#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ +#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ +#define InterlaceMode 0x0080 +#define SyncPP 0x0000 +#define SyncPN 0x4000 +#define SyncNP 0x8000 +#define SyncNN 0xc000 + +/* SetFlag */ +#define ProgrammingCRT2 0x0001 +#define LowModeTests 0x0002 +/* #define TVSimuMode 0x0002 - deprecated */ +/* #define RPLLDIV2XO 0x0004 - deprecated */ +#define LCDVESATiming 0x0008 +#define EnableLVDSDDA 0x0010 +#define SetDispDevSwitchFlag 0x0020 +#define CheckWinDos 0x0040 +#define SetDOSMode 0x0080 + +/* TVMode flag */ +#define TVSetPAL 0x0001 +#define TVSetNTSCJ 0x0002 +#define TVSetPALM 0x0004 +#define TVSetPALN 0x0008 +#define TVSetCHOverScan 0x0010 +#define TVSetYPbPr525i 0x0020 /* new 0x10 */ +#define TVSetYPbPr525p 0x0040 /* new 0x20 */ +#define TVSetYPbPr750p 0x0080 /* new 0x40 */ +#define TVSetHiVision 0x0100 /* new 0x80; = 1080i, software-wise identical */ +#define TVSetTVSimuMode 0x0200 /* new 0x200, prev. 0x800 */ +#define TVRPLLDIV2XO 0x0400 /* prev 0x1000 */ +#define TVSetNTSC1024 0x0800 /* new 0x100, prev. 0x2000 */ +#define TVAspect43 0x2000 +#define TVAspect169 0x4000 +#define TVAspect43LB 0x8000 + +/* YPbPr flag (>=315, <661; converted to TVMode) */ +#define YPbPr525p 0x0001 +#define YPbPr750p 0x0002 +#define YPbPr525i 0x0004 +#define YPbPrHiVision 0x0008 +#define YPbPrModeMask (YPbPr750p | YPbPr525p | YPbPr525i | YPbPrHiVision) + +/* SysFlags (to identify special versions) */ +#define SF_Is651 0x0001 +#define SF_IsM650 0x0002 +#define SF_Is652 0x0004 +#define SF_IsM652 0x0008 +#define SF_IsM653 0x0010 +#define SF_IsM661 0x0020 +#define SF_IsM741 0x0040 +#define SF_IsM760 0x0080 +#define SF_760LFB 0x8000 /* 760: We have LFB */ + +/* CR32 (Newer 630, and 315 series) + + [0] VB connected with CVBS + [1] VB connected with SVHS + [2] VB connected with SCART + [3] VB connected with LCD + [4] VB connected with CRT2 (secondary VGA) + [5] CRT1 monitor is connected + [6] VB connected with Hi-Vision TV + [7] <= 330: VB connected with DVI combo connector + >= 661: VB connected to YPbPr +*/ + +/* CR35 (300 series only) */ +#define TVOverScan 0x10 +#define TVOverScanShift 4 + +/* CR35 (661 series only) + + [0] 1 = PAL, 0 = NTSC + [1] 1 = NTSC-J (if D0 = 0) + [2] 1 = PALM (if D0 = 1) + [3] 1 = PALN (if D0 = 1) + [4] 1 = Overscan (Chrontel only) + [7:5] (only if D2 in CR38 is set) + 000 525i + 001 525p + 010 750p + 011 1080i (or HiVision on 301, 301B) + + These bits are being translated to TVMode flag. + +*/ + +/* + CR37 + + [0] Set 24/18 bit (0/1) RGB to LVDS/TMDS transmitter (set by BIOS) + [3:1] External chip + 300 series: + 001 SiS301 (never seen) + 010 LVDS + 011 LVDS + Tumpion Zurac + 100 LVDS + Chrontel 7005 + 110 Chrontel 7005 + 315/330 series + 001 SiS30x (never seen) + 010 LVDS + 011 LVDS + Chrontel 7019 + 660 series [2:1] only: + reserved (now in CR38) + All other combinations reserved + [3] 661 only: Pass 1:1 data + [4] LVDS: 0: Panel Link expands / 1: Panel Link does not expand + 30x: 0: Bridge scales / 1: Bridge does not scale = Panel scales (if possible) + [5] LCD polarity select + 0: VESA DMT Standard + 1: EDID 2.x defined + [6] LCD horizontal polarity select + 0: High active + 1: Low active + [7] LCD vertical polarity select + 0: High active + 1: Low active +*/ + +/* CR37: LCDInfo */ +#define LCDRGB18Bit 0x0001 +#define LCDNonExpanding 0x0010 +#define LCDSync 0x0020 +#define LCDPass11 0x0100 /* 0: center screen, 1: Pass 1:1 data */ +#define LCDDualLink 0x0200 + +#define DontExpandLCD LCDNonExpanding +#define LCDNonExpandingShift 4 +#define DontExpandLCDShift LCDNonExpandingShift +#define LCDSyncBit 0x00e0 +#define LCDSyncShift 6 + +/* CR38 (315 series) */ +#define EnableDualEdge 0x01 +#define SetToLCDA 0x02 /* LCD channel A (301C/302B/30x(E)LV and 650+LVDS only) */ +#define EnableCHScart 0x04 /* Scart on Ch7019 (unofficial definition - TW) */ +#define EnableCHYPbPr 0x08 /* YPbPr on Ch7019 (480i HDTV); only on 650/Ch7019 systems */ +#define EnableSiSYPbPr 0x08 /* Enable YPbPr mode (30xLV/301C only) */ +#define EnableYPbPr525i 0x00 /* Enable 525i YPbPr mode (30xLV/301C only) (mask 0x30) */ +#define EnableYPbPr525p 0x10 /* Enable 525p YPbPr mode (30xLV/301C only) (mask 0x30) */ +#define EnableYPbPr750p 0x20 /* Enable 750p YPbPr mode (30xLV/301C only) (mask 0x30) */ +#define EnableYPbPr1080i 0x30 /* Enable 1080i YPbPr mode (30xLV/301C only) (mask 0x30) */ +#define EnablePALM 0x40 /* 1 = Set PALM */ +#define EnablePALN 0x80 /* 1 = Set PALN */ +#define EnableNTSCJ EnablePALM /* Not BIOS */ + +/* CR38 (661 and later) + D[7:5] 000 No VB + 001 301 series VB + 010 LVDS + 011 Chrontel 7019 + 100 Conexant + D2 Enable YPbPr output (see CR35) + D[1:0] LCDA (like before) +*/ + +#define EnablePALMN 0x40 /* Romflag: 1 = Allow PALM/PALN */ + +/* CR39 (650 only) */ +#define LCDPass1_1 0x01 /* 0: center screen, 1: pass 1:1 data output */ +#define Enable302LV_DualLink 0x04 /* 302LV only; enable dual link */ + +/* CR39 (661 and later) + D[1:0] YPbPr Aspect Ratio + 00 4:3 letterbox + 01 4:3 + 10 16:9 + 11 4:3 +*/ + +/* CR3B (651+301C) + D[1:0] YPbPr Aspect Ratio + ? +*/ + +/* CR79 (315/330 series only; not 661 and later) + [3-0] Notify driver + 0001 Mode Switch event (set by BIOS) + 0010 Epansion On/Off event + 0011 TV UnderScan/OverScan event + 0100 Set Brightness event + 0101 Set Contrast event + 0110 Set Mute event + 0111 Set Volume Up/Down event + [4] Enable Backlight Control by BIOS/driver + (set by driver; set means that the BIOS should + not touch the backlight registers because eg. + the driver already switched off the backlight) + [5] PAL/NTSC (set by BIOS) + [6] Expansion On/Off (set by BIOS; copied to CR32[4]) + [7] TV UnderScan/OverScan (set by BIOS) +*/ + +/* LCDResInfo */ +#define Panel300_800x600 0x01 /* CR36 */ +#define Panel300_1024x768 0x02 +#define Panel300_1280x1024 0x03 +#define Panel300_1280x960 0x04 +#define Panel300_640x480 0x05 +#define Panel300_1024x600 0x06 +#define Panel300_1152x768 0x07 +#define Panel300_1280x768 0x0a +#define Panel300_320x480 0x0e /* fstn - This is fake, can be any */ +#define Panel300_Custom 0x0f +#define Panel300_Barco1366 0x10 + +#define Panel310_800x600 0x01 +#define Panel310_1024x768 0x02 +#define Panel310_1280x1024 0x03 +#define Panel310_640x480 0x04 +#define Panel310_1024x600 0x05 +#define Panel310_1152x864 0x06 +#define Panel310_1280x960 0x07 +#define Panel310_1152x768 0x08 /* LVDS only */ +#define Panel310_1400x1050 0x09 +#define Panel310_1280x768 0x0a +#define Panel310_1600x1200 0x0b +#define Panel310_640x480_2 0x0c +#define Panel310_640x480_3 0x0d +#define Panel310_320x480 0x0e /* fstn - TW: This is fake, can be any */ +#define Panel310_Custom 0x0f + +#define Panel661_800x600 0x01 +#define Panel661_1024x768 0x02 +#define Panel661_1280x1024 0x03 +#define Panel661_640x480 0x04 +#define Panel661_1024x600 0x05 +#define Panel661_1152x864 0x06 +#define Panel661_1280x960 0x07 +#define Panel661_1152x768 0x08 +#define Panel661_1400x1050 0x09 +#define Panel661_1280x768 0x0a +#define Panel661_1600x1200 0x0b +#define Panel661_1280x800 0x0c +#define Panel661_1680x1050 0x0d +#define Panel661_1280x720 0x0e +#define Panel661_Custom 0x0f + +#define Panel_800x600 0x01 /* Unified values */ +#define Panel_1024x768 0x02 /* MUST match BIOS values from 0-e */ +#define Panel_1280x1024 0x03 +#define Panel_640x480 0x04 +#define Panel_1024x600 0x05 +#define Panel_1152x864 0x06 +#define Panel_1280x960 0x07 +#define Panel_1152x768 0x08 /* LVDS only */ +#define Panel_1400x1050 0x09 +#define Panel_1280x768 0x0a /* 30xB/C and LVDS only (BIOS: all) */ +#define Panel_1600x1200 0x0b +#define Panel_1280x800 0x0c /* 661etc (TMDS) */ +#define Panel_1680x1050 0x0d /* 661etc */ +#define Panel_1280x720 0x0e /* 661etc */ +#define Panel_Custom 0x0f /* MUST BE 0x0f (for DVI DDC detection) */ +#define Panel_320x480 0x10 /* SiS 550 fstn - TW: This is fake, can be any */ +#define Panel_Barco1366 0x11 +#define Panel_848x480 0x12 +#define Panel_640x480_2 0x13 /* SiS 550 */ +#define Panel_640x480_3 0x14 /* SiS 550 */ +#define Panel_1280x768_2 0x15 /* 30xLV */ +#define Panel_1280x768_3 0x16 /* (unused) */ +#define Panel_1280x800_2 0x17 /* 30xLV */ + +/* Index in ModeResInfo table */ +#define SIS_RI_320x200 0 +#define SIS_RI_320x240 1 +#define SIS_RI_320x400 2 +#define SIS_RI_400x300 3 +#define SIS_RI_512x384 4 +#define SIS_RI_640x400 5 +#define SIS_RI_640x480 6 +#define SIS_RI_800x600 7 +#define SIS_RI_1024x768 8 +#define SIS_RI_1280x1024 9 +#define SIS_RI_1600x1200 10 +#define SIS_RI_1920x1440 11 +#define SIS_RI_2048x1536 12 +#define SIS_RI_720x480 13 +#define SIS_RI_720x576 14 +#define SIS_RI_1280x960 15 +#define SIS_RI_800x480 16 +#define SIS_RI_1024x576 17 +#define SIS_RI_1280x720 18 +#define SIS_RI_856x480 19 +#define SIS_RI_1280x768 20 +#define SIS_RI_1400x1050 21 +#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ +#define SIS_RI_848x480 23 +#define SIS_RI_1360x768 24 +#define SIS_RI_1024x600 25 +#define SIS_RI_1152x768 26 +#define SIS_RI_768x576 27 +#define SIS_RI_1360x1024 28 +#define SIS_RI_1680x1050 29 +#define SIS_RI_1280x800 30 +#define SIS_RI_1920x1080 31 +#define SIS_RI_960x540 32 +#define SIS_RI_960x600 33 + +/* CR5F */ +#define IsM650 0x80 + +/* Timing data */ +#define NTSCHT 1716 +#define NTSC2HT 1920 +#define NTSCVT 525 +#define PALHT 1728 +#define PALVT 625 +#define StHiTVHT 892 +#define StHiTVVT 1126 +#define StHiTextTVHT 1000 +#define StHiTextTVVT 1126 +#define ExtHiTVHT 2100 +#define ExtHiTVVT 1125 + +/* Indices in (VB)VCLKData tables */ + +#define VCLK28 0x00 /* Index in VCLKData table (300 and 315) */ +#define VCLK40 0x04 /* Index in VCLKData table (300 and 315) */ +#define VCLK65_300 0x09 /* Index in VCLKData table (300) */ +#define VCLK108_2_300 0x14 /* Index in VCLKData table (300) */ +#define VCLK81_300 0x3f /* Index in VCLKData table (300) */ +#define VCLK108_3_300 0x42 /* Index in VCLKData table (300) */ +#define VCLK100_300 0x43 /* Index in VCLKData table (300) */ +#define VCLK34_300 0x3d /* Index in VCLKData table (300) */ +#define VCLK_CUSTOM_300 0x47 +#define VCLK65_315 0x0b /* Index in (VB)VCLKData table (315) */ +#define VCLK108_2_315 0x19 /* Index in (VB)VCLKData table (315) */ +#define VCLK81_315 0x5b /* Index in (VB)VCLKData table (315) */ +#define VCLK162_315 0x5e /* Index in (VB)VCLKData table (315) */ +#define VCLK108_3_315 0x45 /* Index in VBVCLKData table (315) */ +#define VCLK100_315 0x46 /* Index in VBVCLKData table (315) */ +#define VCLK34_315 0x55 +#define VCLK68_315 0x0d +#define VCLK_1280x800_315_2 0x5c /* Index in VBVCLKData table (315) */ +#define VCLK121_315 0x5d /* Index in VBVCLKData table (315) */ +#define VCLK_1280x720 0x5f +#define VCLK_1280x768_2 0x60 +#define VCLK_1280x768_3 0x61 /* (unused?) */ +#define VCLK_CUSTOM_315 0x62 +#define VCLK_1280x720_2 0x63 +#define VCLK_720x480 0x67 +#define VCLK_720x576 0x68 +#define VCLK_768x576 0x68 +#define VCLK_848x480 0x65 +#define VCLK_856x480 0x66 +#define VCLK_800x480 0x65 +#define VCLK_1024x576 0x51 +#define VCLK_1152x864 0x64 +#define VCLK_1360x768 0x58 +#define VCLK_1280x800_315 0x6c + +#define TVCLKBASE_300 0x21 /* Indices on TV clocks in VCLKData table (300) */ +#define TVCLKBASE_315 0x3a /* Indices on TV clocks in (VB)VCLKData table (315) */ +#define TVVCLKDIV2 0x00 /* Index relative to TVCLKBASE */ +#define TVVCLK 0x01 /* Index relative to TVCLKBASE */ +#define HiTVVCLKDIV2 0x02 /* Index relative to TVCLKBASE */ +#define HiTVVCLK 0x03 /* Index relative to TVCLKBASE */ +#define HiTVSimuVCLK 0x04 /* Index relative to TVCLKBASE */ +#define HiTVTextVCLK 0x05 /* Index relative to TVCLKBASE */ +#define YPbPr750pVCLK 0x25 /* Index relative to TVCLKBASE; was 0x0f NOT relative */ + +/* ------------------------------ */ + +#define SetSCARTOutput 0x01 + +#define HotPlugFunction 0x08 + +#define StStructSize 0x06 + +#define SIS_VIDEO_CAPTURE 0x00 - 0x30 +#define SIS_VIDEO_PLAYBACK 0x02 - 0x30 +#define SIS_CRT2_PORT_04 0x04 - 0x30 +#define SIS_CRT2_PORT_10 0x10 - 0x30 +#define SIS_CRT2_PORT_12 0x12 - 0x30 +#define SIS_CRT2_PORT_14 0x14 - 0x30 + +#define ADR_CRT2PtrData 0x20E +#define offset_Zurac 0x210 /* TW: Trumpion Zurac data pointer */ +#define ADR_LVDSDesPtrData 0x212 +#define ADR_LVDSCRT1DataPtr 0x214 +#define ADR_CHTVVCLKPtr 0x216 +#define ADR_CHTVRegDataPtr 0x218 + +#define LCDDataLen 8 +#define HiTVDataLen 12 +#define TVDataLen 16 + +#define LVDSDataLen 6 +#define LVDSDesDataLen 3 +#define ActiveNonExpanding 0x40 +#define ActiveNonExpandingShift 6 +#define ActivePAL 0x20 +#define ActivePALShift 5 +#define ModeSwitchStatus 0x0F +#define SoftTVType 0x40 +#define SoftSettingAddr 0x52 +#define ModeSettingAddr 0x53 + +#define _PanelType00 0x00 +#define _PanelType01 0x08 +#define _PanelType02 0x10 +#define _PanelType03 0x18 +#define _PanelType04 0x20 +#define _PanelType05 0x28 +#define _PanelType06 0x30 +#define _PanelType07 0x38 +#define _PanelType08 0x40 +#define _PanelType09 0x48 +#define _PanelType0A 0x50 +#define _PanelType0B 0x58 +#define _PanelType0C 0x60 +#define _PanelType0D 0x68 +#define _PanelType0E 0x70 +#define _PanelType0F 0x78 + +#define PRIMARY_VGA 0 /* 1: SiS is primary vga 0:SiS is secondary vga */ + +#define BIOSIDCodeAddr 0x235 /* Offsets to ptrs in BIOS image */ +#define OEMUtilIDCodeAddr 0x237 +#define VBModeIDTableAddr 0x239 +#define OEMTVPtrAddr 0x241 +#define PhaseTableAddr 0x243 +#define NTSCFilterTableAddr 0x245 +#define PALFilterTableAddr 0x247 +#define OEMLCDPtr_1Addr 0x249 +#define OEMLCDPtr_2Addr 0x24B +#define LCDHPosTable_1Addr 0x24D +#define LCDHPosTable_2Addr 0x24F +#define LCDVPosTable_1Addr 0x251 +#define LCDVPosTable_2Addr 0x253 +#define OEMLCDPIDTableAddr 0x255 + +#define VBModeStructSize 5 +#define PhaseTableSize 4 +#define FilterTableSize 4 +#define LCDHPosTableSize 7 +#define LCDVPosTableSize 5 +#define OEMLVDSPIDTableSize 4 +#define LVDSHPosTableSize 4 +#define LVDSVPosTableSize 6 + +#define VB_ModeID 0 +#define VB_TVTableIndex 1 +#define VB_LCDTableIndex 2 +#define VB_LCDHIndex 3 +#define VB_LCDVIndex 4 + +#define OEMLCDEnable 0x0001 +#define OEMLCDDelayEnable 0x0002 +#define OEMLCDPOSEnable 0x0004 +#define OEMTVEnable 0x0100 +#define OEMTVDelayEnable 0x0200 +#define OEMTVFlickerEnable 0x0400 +#define OEMTVPhaseEnable 0x0800 +#define OEMTVFilterEnable 0x1000 + +#define OEMLCDPanelIDSupport 0x0080 + +/* + ============================================================= + for 315 series (old data layout) + ============================================================= +*/ +#define SoftDRAMType 0x80 +#define SoftSetting_OFFSET 0x52 +#define SR07_OFFSET 0x7C +#define SR15_OFFSET 0x7D +#define SR16_OFFSET 0x81 +#define SR17_OFFSET 0x85 +#define SR19_OFFSET 0x8D +#define SR1F_OFFSET 0x99 +#define SR21_OFFSET 0x9A +#define SR22_OFFSET 0x9B +#define SR23_OFFSET 0x9C +#define SR24_OFFSET 0x9D +#define SR25_OFFSET 0x9E +#define SR31_OFFSET 0x9F +#define SR32_OFFSET 0xA0 +#define SR33_OFFSET 0xA1 + +#define CR40_OFFSET 0xA2 +#define SR25_1_OFFSET 0xF6 +#define CR49_OFFSET 0xF7 + +#define VB310Data_1_2_Offset 0xB6 +#define VB310Data_4_D_Offset 0xB7 +#define VB310Data_4_E_Offset 0xB8 +#define VB310Data_4_10_Offset 0xBB + +#define RGBSenseDataOffset 0xBD +#define YCSenseDataOffset 0xBF +#define VideoSenseDataOffset 0xC1 +#define OutputSelectOffset 0xF3 + +#define ECLK_MCLK_DISTANCE 0x14 +#define VBIOSTablePointerStart 0x100 +#define StandTablePtrOffset VBIOSTablePointerStart+0x02 +#define EModeIDTablePtrOffset VBIOSTablePointerStart+0x04 +#define CRT1TablePtrOffset VBIOSTablePointerStart+0x06 +#define ScreenOffsetPtrOffset VBIOSTablePointerStart+0x08 +#define VCLKDataPtrOffset VBIOSTablePointerStart+0x0A +#define MCLKDataPtrOffset VBIOSTablePointerStart+0x0E +#define CRT2PtrDataPtrOffset VBIOSTablePointerStart+0x10 +#define TVAntiFlickPtrOffset VBIOSTablePointerStart+0x12 +#define TVDelayPtr1Offset VBIOSTablePointerStart+0x14 +#define TVPhaseIncrPtr1Offset VBIOSTablePointerStart+0x16 +#define TVYFilterPtr1Offset VBIOSTablePointerStart+0x18 +#define LCDDelayPtr1Offset VBIOSTablePointerStart+0x20 +#define TVEdgePtr1Offset VBIOSTablePointerStart+0x24 +#define CRT2Delay1Offset VBIOSTablePointerStart+0x28 + +#endif diff --git a/drivers/video/sis/oem300.h b/drivers/video/sis/oem300.h new file mode 100644 index 000000000000..b1358b750f53 --- /dev/null +++ b/drivers/video/sis/oem300.h @@ -0,0 +1,859 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * OEM Data for 300 series + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +static const UCHAR SiS300_OEMTVDelay301[8][4] = +{ + {0x08,0x08,0x08,0x08}, + {0x08,0x08,0x08,0x08}, + {0x08,0x08,0x08,0x08}, + {0x2c,0x2c,0x2c,0x2c}, + {0x08,0x08,0x08,0x08}, + {0x08,0x08,0x08,0x08}, + {0x08,0x08,0x08,0x08}, + {0x20,0x20,0x20,0x20} +}; + +static const UCHAR SiS300_OEMTVDelayLVDS[8][4] = +{ + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20} +}; + +static const UCHAR SiS300_OEMTVFlicker[8][4] = +{ + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00} +}; + +#if 0 /* TW: Not used */ +static const UCHAR SiS300_OEMLCDDelay1[12][4]={ + {0x2c,0x2c,0x2c,0x2c}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x2c,0x2c,0x2c,0x2c}, + {0x2c,0x2c,0x2c,0x2c}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x24,0x24,0x24,0x24}, + {0x24,0x24,0x24,0x24}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x24,0x24,0x24,0x24} +}; +#endif + +/* From 630/301B BIOS */ +static const UCHAR SiS300_OEMLCDDelay2[64][4] = /* for 301/301b/302b/301LV/302LV */ +{ + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20} +}; + +/* From 300/301LV BIOS */ +static const UCHAR SiS300_OEMLCDDelay4[12][4] = +{ + {0x2c,0x2c,0x2c,0x2c}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x2c,0x2c,0x2c,0x2c}, + {0x2c,0x2c,0x2c,0x2c}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x24,0x24,0x24,0x24}, + {0x24,0x24,0x24,0x24}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x24,0x24,0x24,0x24} +}; + +/* From 300/301LV BIOS */ +static const UCHAR SiS300_OEMLCDDelay5[32][4] = +{ + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, +}; + +/* Added for LVDS */ +static const UCHAR SiS300_OEMLCDDelay3[64][4] = { /* For LVDS */ + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20} +}; + +static const UCHAR SiS300_Phase1[8][5][4] = +{ + { + {0x21,0xed,0x00,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x21,0xed,0x00,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + } +}; + + +static const UCHAR SiS300_Phase2[8][5][4] = +{ + { + {0x21,0xed,0x00,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x21,0xed,0x00,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + } +}; + +static const UCHAR SiS300_Filter1[10][16][4] = +{ + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x10,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x15,0x25,0xf6}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x10,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xfc,0xfb,0x14,0x2a}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x10,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xfc,0xfb,0x14,0x2a}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x10,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xfc,0xfb,0x14,0x2a}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x10,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x15,0x25,0xf6}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x10,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xfc,0xfb,0x14,0x2a}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x10,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xfc,0xfb,0x14,0x2a}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x10,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xfc,0xfb,0x14,0x2a}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x10,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x15,0x25,0xf6}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x10,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x15,0x25,0xf6}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18} + }, +}; + +static const UCHAR SiS300_Filter2[10][9][7] = +{ + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + } +}; + +/* Custom data for Barco iQ Pro R300 */ +static const UCHAR barco_p1[2][9][7][3] = { + { + { { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x19, 0x00 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x1e, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x16, 0x00 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x19, 0x00 }, + { 0, 0, 0 } + }, + { + { 0, 0, 0 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x1e, 0x00 }, + { 0, 0, 0 } + }, + { + { 0x16, 0xd1, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x11, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x26, 0x00 } + }, + { + { 0x16, 0xd1, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x30, 0x00 }, + { 0, 0, 0 } + }, + { + { 0x16, 0x00, 0x00 }, + { 0x17, 0xa0, 0x00 }, + { 0x1a, 0xa0, 0x00 }, + { 0x1b, 0x2a, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0, 0, 0 } + }, + { + { 0x16, 0x00, 0x00 }, + { 0x17, 0xaa, 0x00 }, + { 0x1a, 0xa0, 0x00 }, + { 0x1b, 0x2a, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0, 0, 0 } + } + }, + { + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x19, 0x00 } + }, + { + { 0, 0, 0 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x19, 0x00 }, + }, + { + { 0, 0, 0 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x1e, 0x00 } + }, + { + { 0x16, 0xd1, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe6, 0x00 }, + { 0x1b, 0x11, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x26, 0x00 } + }, + { + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe0, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x30, 0x00 }, + { 0, 0, 0 } + }, + { + { 0, 0, 0 } + }, + { + { 0, 0, 0 } + } + } +}; + + + + + + diff --git a/drivers/video/sis/oem310.h b/drivers/video/sis/oem310.h new file mode 100644 index 000000000000..2b7db916b7e7 --- /dev/null +++ b/drivers/video/sis/oem310.h @@ -0,0 +1,449 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * OEM Data for 315/330 series + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +static const UCHAR SiS310_LCDDelayCompensation_301[] = /* 301 */ +{ + 0x00,0x00,0x00, /* 800x600 */ + 0x0b,0x0b,0x0b, /* 1024x768 */ + 0x08,0x08,0x08, /* 1280x1024 */ + 0x00,0x00,0x00, /* 640x480 (unknown) */ + 0x00,0x00,0x00, /* 1024x600 (unknown) */ + 0x00,0x00,0x00, /* 1152x864 (unknown) */ + 0x08,0x08,0x08, /* 1280x960 (guessed) */ + 0x00,0x00,0x00, /* 1152x768 (unknown) */ + 0x08,0x08,0x08, /* 1400x1050 */ + 0x08,0x08,0x08, /* 1280x768 (guessed) */ + 0x00,0x00,0x00, /* 1600x1200 */ + 0x00,0x00,0x00, /* 320x480 (unknown) */ + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00 +}; + +/* This is contained in 650+301B BIOSes, but it is wrong - so we don't use it */ +static const UCHAR SiS310_LCDDelayCompensation_650301LV[] = /* 650 + 30xLV */ +{ + 0x01,0x01,0x01, /* 800x600 */ + 0x01,0x01,0x01, /* 1024x768 */ + 0x01,0x01,0x01, /* 1280x1024 */ + 0x01,0x01,0x01, /* 640x480 (unknown) */ + 0x01,0x01,0x01, /* 1024x600 (unknown) */ + 0x01,0x01,0x01, /* 1152x864 (unknown) */ + 0x01,0x01,0x01, /* 1280x960 (guessed) */ + 0x01,0x01,0x01, /* 1152x768 (unknown) */ + 0x01,0x01,0x01, /* 1400x1050 */ + 0x01,0x01,0x01, /* 1280x768 (guessed) */ + 0x01,0x01,0x01, /* 1600x1200 */ + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02 +}; + +static const UCHAR SiS310_LCDDelayCompensation_651301LV[] = /* M650/651 301LV */ +{ + 0x33,0x33,0x33, /* 800x600 (guessed) - new: PanelType, not PanelRes ! */ + 0x33,0x33,0x33, /* 1024x768 */ + 0x33,0x33,0x33, /* 1280x1024 */ + 0x33,0x33,0x33, /* 640x480 (unknown) */ + 0x33,0x33,0x33, /* 1024x600 (unknown) */ + 0x33,0x33,0x33, /* 1152x864 (unknown) */ + 0x33,0x33,0x33, /* 1280x960 (guessed) */ + 0x33,0x33,0x33, /* 1152x768 (unknown) */ + 0x33,0x33,0x33, /* 1400x1050 */ + 0x33,0x33,0x33, /* 1280x768 (guessed) */ + 0x33,0x33,0x33, /* 1600x1200 */ + 0x33,0x33,0x33, + 0x33,0x33,0x33, + 0x33,0x33,0x33, + 0x33,0x33,0x33 +}; + +static const UCHAR SiS310_LCDDelayCompensation_651302LV[] = /* M650/651 302LV */ +{ + 0x33,0x33,0x33, /* 800x600 (guessed) */ + 0x33,0x33,0x33, /* 1024x768 */ + 0x33,0x33,0x33, /* 1280x1024 */ + 0x33,0x33,0x33, /* 640x480 (unknown) */ + 0x33,0x33,0x33, /* 1024x600 (unknown) */ + 0x33,0x33,0x33, /* 1152x864 (unknown) */ + 0x33,0x33,0x33, /* 1280x960 (guessed) */ + 0x33,0x33,0x33, /* 1152x768 (unknown) */ + 0x33,0x33,0x33, /* 1400x1050 */ + 0x33,0x33,0x33, /* 1280x768 (guessed) */ + 0x33,0x33,0x33, /* 1600x1200 */ + 0x33,0x33,0x33, + 0x33,0x33,0x33, + 0x33,0x33,0x33, + 0x33,0x33,0x33 +}; + +static const UCHAR SiS310_LCDDelayCompensation_3xx301B[] = /* 30xB */ +{ + 0x01,0x01,0x01, /* 800x600 */ + 0x0C,0x0C,0x0C, /* 1024x768 */ + 0x0C,0x0C,0x0C, /* 1280x1024 */ + 0x08,0x08,0x08, /* 640x480 */ + 0x0C,0x0C,0x0C, /* 1024x600 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x864 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x960 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1400x1050 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1600x1200 (guessed) */ + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02 +}; + +static const UCHAR SiS310_LCDDelayCompensation_3xx301LV[] = /* 315+30xLV */ +{ + 0x01,0x01,0x01, /* 800x600 */ + 0x04,0x04,0x04, /* 1024x768 (A531/BIOS 1.14.05f: 4 - works with 6 */ + 0x0C,0x0C,0x0C, /* 1280x1024 */ + 0x08,0x08,0x08, /* 640x480 */ + 0x0C,0x0C,0x0C, /* 1024x600 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x864 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x960 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1400x1050 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1600x1200 (guessed) */ + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02 +}; + +static const UCHAR SiS310_TVDelayCompensation_301[] = /* 301 */ +{ + 0x02,0x02, /* NTSC Enhanced, Standard */ + 0x02,0x02, /* PAL */ + 0x08,0x0b /* HiVision */ +}; + +static const UCHAR SiS310_TVDelayCompensation_301B[] = /* 30xB, 30xLV */ +{ + 0x03,0x03, + 0x03,0x03, + 0x03,0x03 +}; + +static const UCHAR SiS310_TVDelayCompensation_740301B[] = /* 740 + 30xB (30xLV?) */ +{ + 0x05,0x05, + 0x05,0x05, + 0x05,0x05 +}; + +static const UCHAR SiS310_TVDelayCompensation_651301LV[] = /* M650, 651, 301LV */ +{ + 0x33,0x33, + 0x33,0x33, + 0x33,0x33 +}; + +static const UCHAR SiS310_TVDelayCompensation_651302LV[] = /* M650, 651, 302LV */ +{ + 0x33,0x33, + 0x33,0x33, + 0x33,0x33 +}; + +static const UCHAR SiS_TVDelay661_301[] = /* 661, 301 */ +{ + 0x44,0x44, + 0x44,0x44, + 0x00,0x00, + 0x44,0x44, + 0x44,0x44, + 0x44,0x44 +}; + +static const UCHAR SiS_TVDelay661_301B[] = /* 661, 301B et al */ +{ + 0x44,0x44, + 0x44,0x44, + 0x00,0x00, + 0x44,0x44, + 0x44,0x44, + 0x44,0x44 +}; + +static const UCHAR SiS310_TVDelayCompensation_LVDS[] = /* LVDS */ +{ + 0x0a,0x0a, + 0x0a,0x0a, + 0x0a,0x0a +}; + +static const UCHAR SiS310_TVAntiFlick1[6][2] = +{ + {0x4,0x0}, + {0x4,0x8}, + {0x0,0x0}, + {0x0,0x0}, + {0x0,0x0}, + {0x0,0x0} +}; + +static const UCHAR SiS310_TVEdge1[6][2] = +{ + {0x0,0x4}, + {0x0,0x4}, + {0x0,0x0}, + {0x0,0x0}, + {0x0,0x0}, + {0x0,0x0} +}; + +static const UCHAR SiS310_TVYFilter1[5][8][4] = +{ + { + {0x00,0xf4,0x10,0x38}, /* NTSC */ + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xf1,0x04,0x1f,0x18}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xee,0x0c,0x22,0x08}, + {0xeb,0x15,0x25,0xf6} + }, + { + {0x00,0xf4,0x10,0x38}, /* PAL */ + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0xfc,0xfb,0x14,0x2a} + }, + { + {0x00,0x00,0x00,0x00}, /* HiVision */ + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xee,0x0c,0x22,0x08} + }, + { + {0x00,0xf4,0x10,0x38}, /* PAL-M */ + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x10,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x15,0x25,0xf6} + }, + { + {0x00,0xf4,0x10,0x38}, /* PAL-N */ + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x10,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x15,0x25,0xf6} + } +}; + +static const UCHAR SiS310_TVYFilter2[5][9][7] = +{ + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* NTSC */ + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* PAL */ + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, /* HiVision */ + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* PAL-M */ + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* PAL-N */ + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + } +}; + +static const UCHAR SiS310_TVPhaseIncr1[3][2][4] = +{ + { + {0x21,0xed,0xba,0x08}, + {0x21,0xed,0xba,0x08} + }, + { + {0x2a,0x05,0xe3,0x00}, + {0x2a,0x05,0xe3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + } +}; + +static const UCHAR SiS310_TVPhaseIncr2[3][2][4] = +{ + { + {0x21,0xf0,0x7b,0xd6}, + {0x21,0xf0,0x7b,0xd6} + }, + { + {0x2a,0x0a,0x41,0xe9}, + {0x2a,0x0a,0x41,0xe9} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + } +}; + +static const UCHAR SiS661_TVPhase[] = { + 0x21,0xED,0xBA,0x08, + 0x2A,0x05,0xE3,0x00, + 0x21,0xE4,0x2E,0x9B, + 0x21,0xF4,0x3E,0xBA, + 0x1E,0x8B,0xA2,0xA7, + 0x1E,0x83,0x0A,0xE0, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x21,0xF0,0x7B,0xD6, + 0x2A,0x09,0x86,0xE9, + 0x21,0xE6,0xEF,0xA4, + 0x21,0xF6,0x94,0x46, + 0x1E,0x8B,0xA2,0xA7, + 0x1E,0x83,0x0A,0xE0, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 +}; + +/**************************************************************/ +/* CUSTOM TIMING DATA --------------------------------------- */ +/**************************************************************/ + +/* Inventec / Compaq Presario 3045US, 3017 */ + +static const SiS_LCDDataStruct SiS310_ExtCompaq1280x1024Data[] = +{ + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 32, 15,1696, 501,1696,1066}, + { 212, 75,1024, 621,1696,1066}, + { 4, 3,1696, 810,1696,1066}, + { 1, 1,1696,1066,1696,1066} +}; + +/* Asus A2xxxH _2 */ + +static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Asus1024x768_3[] = +{ + {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x2c,0x13,0x9a,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x38,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x38,0x13,0x16,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x36,0x13,0x13,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}} +}; + + + + diff --git a/drivers/video/sis/osdef.h b/drivers/video/sis/osdef.h new file mode 100644 index 000000000000..15939b057713 --- /dev/null +++ b/drivers/video/sis/osdef.h @@ -0,0 +1,131 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * OS depending defines + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * Silicon Integrated Systems, Inc. (used by permission) + * + */ + +#ifndef _SIS_OSDEF_H_ +#define _SIS_OSDEF_H_ + +/* The choices are: */ +#define LINUX_KERNEL /* Linux kernel framebuffer */ +/* #define LINUX_XF86 */ /* XFree86/X.org */ + +#ifdef OutPortByte +#undef OutPortByte +#endif + +#ifdef OutPortWord +#undef OutPortWord +#endif + +#ifdef OutPortLong +#undef OutPortLong +#endif + +#ifdef InPortByte +#undef InPortByte +#endif + +#ifdef InPortWord +#undef InPortWord +#endif + +#ifdef InPortLong +#undef InPortLong +#endif + +/**********************************************************************/ +/* LINUX KERNEL */ +/**********************************************************************/ + +#ifdef LINUX_KERNEL +#include <linux/config.h> + +#ifdef CONFIG_FB_SIS_300 +#define SIS300 +#endif + +#ifdef CONFIG_FB_SIS_315 +#define SIS315H +#endif + +#if !defined(SIS300) && !defined(SIS315H) +#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set +#warning sisfb will not work! +#endif + +#define OutPortByte(p,v) outb((u8)(v),(SISIOADDRESS)(p)) +#define OutPortWord(p,v) outw((u16)(v),(SISIOADDRESS)(p)) +#define OutPortLong(p,v) outl((u32)(v),(SISIOADDRESS)(p)) +#define InPortByte(p) inb((SISIOADDRESS)(p)) +#define InPortWord(p) inw((SISIOADDRESS)(p)) +#define InPortLong(p) inl((SISIOADDRESS)(p)) +#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset_io(MemoryAddress, value, MemorySize) +#endif + +/**********************************************************************/ +/* XFree86/X.org */ +/**********************************************************************/ + +#ifdef LINUX_XF86 +#define SIS300 +#define SIS315H + +#define OutPortByte(p,v) outSISREG((IOADDRESS)(p),(CARD8)(v)) +#define OutPortWord(p,v) outSISREGW((IOADDRESS)(p),(CARD16)(v)) +#define OutPortLong(p,v) outSISREGL((IOADDRESS)(p),(CARD32)(v)) +#define InPortByte(p) inSISREG((IOADDRESS)(p)) +#define InPortWord(p) inSISREGW((IOADDRESS)(p)) +#define InPortLong(p) inSISREGL((IOADDRESS)(p)) +#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize) +#endif + +#endif /* _OSDEF_H_ */ diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h new file mode 100644 index 000000000000..d0103c162e43 --- /dev/null +++ b/drivers/video/sis/sis.h @@ -0,0 +1,573 @@ +/* + * SiS 300/630/730/540/315/550/[M]650/651/[M]661[FM]X/740/[M]741[GX]/330/[M]760[GX] + * frame buffer driver for Linux kernels >=2.4.14 and >=2.6.3 + * + * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the named License, + * or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef _SIS_H +#define _SIS_H + +#include <linux/config.h> +#include <linux/version.h> + +#include "osdef.h" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#include <video/sisfb.h> +#else +#include <linux/sisfb.h> +#endif + +#include "vgatypes.h" +#include "vstruct.h" + +#define VER_MAJOR 1 +#define VER_MINOR 7 +#define VER_LEVEL 17 + +#undef SIS_CONFIG_COMPAT + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#include <linux/spinlock.h> +#ifdef CONFIG_COMPAT +#include <linux/ioctl32.h> +#define SIS_CONFIG_COMPAT +#endif +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19) +#ifdef __x86_64__ +/* Shouldn't we check for CONFIG_IA32_EMULATION here? */ +#include <asm/ioctl32.h> +#define SIS_CONFIG_COMPAT +#endif +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) +#define SIS_IOTYPE1 void __iomem +#define SIS_IOTYPE2 __iomem +#define SISINITSTATIC static +#else +#define SIS_IOTYPE1 unsigned char +#define SIS_IOTYPE2 +#define SISINITSTATIC +#endif + +#undef SISFBDEBUG + +#ifdef SISFBDEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#define TWDEBUG(x) printk(KERN_INFO x "\n"); +#else +#define DPRINTK(fmt, args...) +#define TWDEBUG(x) +#endif + +#define SISFAIL(x) do { printk(x "\n"); return -EINVAL; } while(0) + +/* To be included in pci_ids.h */ +#ifndef PCI_DEVICE_ID_SI_650_VGA +#define PCI_DEVICE_ID_SI_650_VGA 0x6325 +#endif +#ifndef PCI_DEVICE_ID_SI_650 +#define PCI_DEVICE_ID_SI_650 0x0650 +#endif +#ifndef PCI_DEVICE_ID_SI_651 +#define PCI_DEVICE_ID_SI_651 0x0651 +#endif +#ifndef PCI_DEVICE_ID_SI_740 +#define PCI_DEVICE_ID_SI_740 0x0740 +#endif +#ifndef PCI_DEVICE_ID_SI_330 +#define PCI_DEVICE_ID_SI_330 0x0330 +#endif +#ifndef PCI_DEVICE_ID_SI_660_VGA +#define PCI_DEVICE_ID_SI_660_VGA 0x6330 +#endif +#ifndef PCI_DEVICE_ID_SI_661 +#define PCI_DEVICE_ID_SI_661 0x0661 +#endif +#ifndef PCI_DEVICE_ID_SI_741 +#define PCI_DEVICE_ID_SI_741 0x0741 +#endif +#ifndef PCI_DEVICE_ID_SI_660 +#define PCI_DEVICE_ID_SI_660 0x0660 +#endif +#ifndef PCI_DEVICE_ID_SI_760 +#define PCI_DEVICE_ID_SI_760 0x0760 +#endif + +/* To be included in fb.h */ +#ifndef FB_ACCEL_SIS_GLAMOUR_2 +#define FB_ACCEL_SIS_GLAMOUR_2 40 /* SiS 315, 65x, 740, 661, 741 */ +#endif +#ifndef FB_ACCEL_SIS_XABRE +#define FB_ACCEL_SIS_XABRE 41 /* SiS 330 ("Xabre"), 760 */ +#endif + +#define MAX_ROM_SCAN 0x10000 + +/* ivideo->caps */ +#define HW_CURSOR_CAP 0x80 +#define TURBO_QUEUE_CAP 0x40 +#define AGP_CMD_QUEUE_CAP 0x20 +#define VM_CMD_QUEUE_CAP 0x10 +#define MMIO_CMD_QUEUE_CAP 0x08 + +/* For 300 series */ +#define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */ +#define HW_CURSOR_AREA_SIZE_300 0x1000 /* 4K */ + +/* For 315/Xabre series */ +#define COMMAND_QUEUE_AREA_SIZE 0x80000 /* 512K */ +#define COMMAND_QUEUE_THRESHOLD 0x1F +#define HW_CURSOR_AREA_SIZE_315 0x4000 /* 16K */ + +#define SIS_OH_ALLOC_SIZE 4000 +#define SENTINEL 0x7fffffff + +#define SEQ_ADR 0x14 +#define SEQ_DATA 0x15 +#define DAC_ADR 0x18 +#define DAC_DATA 0x19 +#define CRTC_ADR 0x24 +#define CRTC_DATA 0x25 +#define DAC2_ADR (0x16-0x30) +#define DAC2_DATA (0x17-0x30) +#define VB_PART1_ADR (0x04-0x30) +#define VB_PART1_DATA (0x05-0x30) +#define VB_PART2_ADR (0x10-0x30) +#define VB_PART2_DATA (0x11-0x30) +#define VB_PART3_ADR (0x12-0x30) +#define VB_PART3_DATA (0x13-0x30) +#define VB_PART4_ADR (0x14-0x30) +#define VB_PART4_DATA (0x15-0x30) + +#define SISSR ivideo->SiS_Pr.SiS_P3c4 +#define SISCR ivideo->SiS_Pr.SiS_P3d4 +#define SISDACA ivideo->SiS_Pr.SiS_P3c8 +#define SISDACD ivideo->SiS_Pr.SiS_P3c9 +#define SISPART1 ivideo->SiS_Pr.SiS_Part1Port +#define SISPART2 ivideo->SiS_Pr.SiS_Part2Port +#define SISPART3 ivideo->SiS_Pr.SiS_Part3Port +#define SISPART4 ivideo->SiS_Pr.SiS_Part4Port +#define SISPART5 ivideo->SiS_Pr.SiS_Part5Port +#define SISDAC2A SISPART5 +#define SISDAC2D (SISPART5 + 1) +#define SISMISCR (ivideo->SiS_Pr.RelIO + 0x1c) +#define SISMISCW ivideo->SiS_Pr.SiS_P3c2 +#define SISINPSTAT (ivideo->SiS_Pr.RelIO + 0x2a) +#define SISPEL ivideo->SiS_Pr.SiS_P3c6 + +#define IND_SIS_PASSWORD 0x05 /* SRs */ +#define IND_SIS_COLOR_MODE 0x06 +#define IND_SIS_RAMDAC_CONTROL 0x07 +#define IND_SIS_DRAM_SIZE 0x14 +#define IND_SIS_MODULE_ENABLE 0x1E +#define IND_SIS_PCI_ADDRESS_SET 0x20 +#define IND_SIS_TURBOQUEUE_ADR 0x26 +#define IND_SIS_TURBOQUEUE_SET 0x27 +#define IND_SIS_POWER_ON_TRAP 0x38 +#define IND_SIS_POWER_ON_TRAP2 0x39 +#define IND_SIS_CMDQUEUE_SET 0x26 +#define IND_SIS_CMDQUEUE_THRESHOLD 0x27 + +#define IND_SIS_AGP_IO_PAD 0x48 + +#define SIS_CRT2_WENABLE_300 0x24 /* Part1 */ +#define SIS_CRT2_WENABLE_315 0x2F + +#define SIS_PASSWORD 0x86 /* SR05 */ + +#define SIS_INTERLACED_MODE 0x20 /* SR06 */ +#define SIS_8BPP_COLOR_MODE 0x0 +#define SIS_15BPP_COLOR_MODE 0x1 +#define SIS_16BPP_COLOR_MODE 0x2 +#define SIS_32BPP_COLOR_MODE 0x4 + +#define SIS_ENABLE_2D 0x40 /* SR1E */ + +#define SIS_MEM_MAP_IO_ENABLE 0x01 /* SR20 */ +#define SIS_PCI_ADDR_ENABLE 0x80 + +#define SIS_AGP_CMDQUEUE_ENABLE 0x80 /* 315/330 series SR26 */ +#define SIS_VRAM_CMDQUEUE_ENABLE 0x40 +#define SIS_MMIO_CMD_ENABLE 0x20 +#define SIS_CMD_QUEUE_SIZE_512k 0x00 +#define SIS_CMD_QUEUE_SIZE_1M 0x04 +#define SIS_CMD_QUEUE_SIZE_2M 0x08 +#define SIS_CMD_QUEUE_SIZE_4M 0x0C +#define SIS_CMD_QUEUE_RESET 0x01 +#define SIS_CMD_AUTO_CORR 0x02 + +#define SIS_SIMULTANEOUS_VIEW_ENABLE 0x01 /* CR30 */ +#define SIS_MODE_SELECT_CRT2 0x02 +#define SIS_VB_OUTPUT_COMPOSITE 0x04 +#define SIS_VB_OUTPUT_SVIDEO 0x08 +#define SIS_VB_OUTPUT_SCART 0x10 +#define SIS_VB_OUTPUT_LCD 0x20 +#define SIS_VB_OUTPUT_CRT2 0x40 +#define SIS_VB_OUTPUT_HIVISION 0x80 + +#define SIS_VB_OUTPUT_DISABLE 0x20 /* CR31 */ +#define SIS_DRIVER_MODE 0x40 + +#define SIS_VB_COMPOSITE 0x01 /* CR32 */ +#define SIS_VB_SVIDEO 0x02 +#define SIS_VB_SCART 0x04 +#define SIS_VB_LCD 0x08 +#define SIS_VB_CRT2 0x10 +#define SIS_CRT1 0x20 +#define SIS_VB_HIVISION 0x40 +#define SIS_VB_YPBPR 0x80 +#define SIS_VB_TV (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | \ + SIS_VB_SCART | SIS_VB_HIVISION | SIS_VB_YPBPR) + +#define SIS_EXTERNAL_CHIP_MASK 0x0E /* CR37 (< SiS 660) */ +#define SIS_EXTERNAL_CHIP_SIS301 0x01 /* in CR37 << 1 ! */ +#define SIS_EXTERNAL_CHIP_LVDS 0x02 +#define SIS_EXTERNAL_CHIP_TRUMPION 0x03 +#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL 0x04 +#define SIS_EXTERNAL_CHIP_CHRONTEL 0x05 +#define SIS310_EXTERNAL_CHIP_LVDS 0x02 +#define SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL 0x03 + +#define SIS_AGP_2X 0x20 /* CR48 */ + +#define HW_DEVICE_EXTENSION SIS_HW_INFO +#define PHW_DEVICE_EXTENSION PSIS_HW_INFO + +/* I/O port access macros */ +#define inSISREG(base) inb(base) + +#define outSISREG(base,val) outb(val,base) + +#define orSISREG(base,val) \ + do { \ + u8 __Temp = inSISREG(base); \ + outSISREG(base, __Temp | (val)); \ + } while (0) + +#define andSISREG(base,val) \ + do { \ + u8 __Temp = inSISREG(base); \ + outSISREG(base, __Temp & (val)); \ + } while (0) + +#define inSISIDXREG(base,idx,var) \ + do { \ + outSISREG(base, idx); \ + var = inSISREG((base)+1); \ + } while (0) + +#define outSISIDXREG(base,idx,val) \ + do { \ + outSISREG(base, idx); \ + outSISREG((base)+1, val); \ + } while (0) + +#define orSISIDXREG(base,idx,val) \ + do { \ + u8 __Temp; \ + outSISREG(base, idx); \ + __Temp = inSISREG((base)+1) | (val); \ + outSISREG((base)+1, __Temp); \ + } while (0) + +#define andSISIDXREG(base,idx,and) \ + do { \ + u8 __Temp; \ + outSISREG(base, idx); \ + __Temp = inSISREG((base)+1) & (and); \ + outSISREG((base)+1, __Temp); \ + } while (0) + +#define setSISIDXREG(base,idx,and,or) \ + do { \ + u8 __Temp; \ + outSISREG(base, idx); \ + __Temp = (inSISREG((base)+1) & (and)) | (or); \ + outSISREG((base)+1, __Temp); \ + } while (0) + +/* MMIO access macros */ +#define MMIO_IN8(base, offset) readb((base+offset)) +#define MMIO_IN16(base, offset) readw((base+offset)) +#define MMIO_IN32(base, offset) readl((base+offset)) + +#define MMIO_OUT8(base, offset, val) writeb(((u8)(val)), (base+offset)) +#define MMIO_OUT16(base, offset, val) writew(((u16)(val)), (base+offset)) +#define MMIO_OUT32(base, offset, val) writel(((u32)(val)), (base+offset)) + +/* Queue control MMIO registers */ +#define Q_BASE_ADDR 0x85C0 /* Base address of software queue */ +#define Q_WRITE_PTR 0x85C4 /* Current write pointer */ +#define Q_READ_PTR 0x85C8 /* Current read pointer */ +#define Q_STATUS 0x85CC /* queue status */ + +#define MMIO_QUEUE_PHYBASE Q_BASE_ADDR +#define MMIO_QUEUE_WRITEPORT Q_WRITE_PTR +#define MMIO_QUEUE_READPORT Q_READ_PTR + +#ifndef FB_BLANK_UNBLANK +#define FB_BLANK_UNBLANK 0 +#endif +#ifndef FB_BLANK_NORMAL +#define FB_BLANK_NORMAL 1 +#endif +#ifndef FB_BLANK_VSYNC_SUSPEND +#define FB_BLANK_VSYNC_SUSPEND 2 +#endif +#ifndef FB_BLANK_HSYNC_SUSPEND +#define FB_BLANK_HSYNC_SUSPEND 3 +#endif +#ifndef FB_BLANK_POWERDOWN +#define FB_BLANK_POWERDOWN 4 +#endif + +enum _SIS_LCD_TYPE { + LCD_INVALID = 0, + LCD_800x600, + LCD_1024x768, + LCD_1280x1024, + LCD_1280x960, + LCD_640x480, + LCD_1600x1200, + LCD_1920x1440, + LCD_2048x1536, + LCD_320x480, /* FSTN */ + LCD_1400x1050, + LCD_1152x864, + LCD_1152x768, + LCD_1280x768, + LCD_1024x600, + LCD_640x480_2, /* DSTN */ + LCD_640x480_3, /* DSTN */ + LCD_848x480, + LCD_1280x800, + LCD_1680x1050, + LCD_1280x720, + LCD_CUSTOM, + LCD_UNKNOWN +}; + +enum _SIS_CMDTYPE { + MMIO_CMD = 0, + AGP_CMD_QUEUE, + VM_CMD_QUEUE, +}; +typedef unsigned int SIS_CMDTYPE; + +/* Our "par" */ +struct sis_video_info { + int cardnumber; + struct fb_info *memyselfandi; + + SIS_HW_INFO sishw_ext; + SiS_Private SiS_Pr; + + sisfb_info sisfbinfo; /* For ioctl SISFB_GET_INFO */ + + struct fb_var_screeninfo default_var; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + struct fb_fix_screeninfo sisfb_fix; + u32 pseudo_palette[17]; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + struct display sis_disp; + struct display_switch sisfb_sw; + struct { + u16 red, green, blue, pad; + } sis_palette[256]; + union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif + } sis_fbcon_cmap; +#endif + + struct sisfb_monitor { + u16 hmin; + u16 hmax; + u16 vmin; + u16 vmax; + u32 dclockmax; + u8 feature; + BOOLEAN datavalid; + } sisfb_thismonitor; + + int chip_id; + char myid[40]; + + struct pci_dev *nbridge; + + int mni; /* Mode number index */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + int currcon; +#endif + + unsigned long video_size; + unsigned long video_base; + unsigned long mmio_size; + unsigned long mmio_base; + unsigned long vga_base; + + SIS_IOTYPE1 *video_vbase; + SIS_IOTYPE1 *mmio_vbase; + + unsigned char *bios_abase; + + int mtrr; + + u32 sisfb_mem; + + u32 sisfb_parm_mem; + int sisfb_accel; + int sisfb_ypan; + int sisfb_max; + int sisfb_userom; + int sisfb_useoem; + int sisfb_mode_idx; + int sisfb_parm_rate; + int sisfb_crt1off; + int sisfb_forcecrt1; + int sisfb_crt2type; + int sisfb_crt2flags; + int sisfb_dstn; + int sisfb_fstn; + int sisfb_tvplug; + int sisfb_tvstd; + int sisfb_filter; + int sisfb_nocrt2rate; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + int sisfb_inverse; +#endif + + u32 heapstart; /* offset */ + SIS_IOTYPE1 *sisfb_heap_start; /* address */ + SIS_IOTYPE1 *sisfb_heap_end; /* address */ + u32 sisfb_heap_size; + int havenoheap; +#if 0 + SIS_HEAP sisfb_heap; +#endif + + + int video_bpp; + int video_cmap_len; + int video_width; + int video_height; + unsigned int refresh_rate; + + unsigned int chip; + u8 revision_id; + + int video_linelength; /* real pitch */ + int scrnpitchCRT1; /* pitch regarding interlace */ + + u16 DstColor; /* For 2d acceleration */ + u32 SiS310_AccelDepth; + u32 CommandReg; + int cmdqueuelength; + + spinlock_t lockaccel; /* Do not use outside of kernel! */ + + unsigned int pcibus; + unsigned int pcislot; + unsigned int pcifunc; + + int accel; + + u16 subsysvendor; + u16 subsysdevice; + + u32 vbflags; /* Replacing deprecated stuff from above */ + u32 currentvbflags; + + int lcdxres, lcdyres; + int lcddefmodeidx, tvdefmodeidx, defmodeidx; + u32 CRT2LCDType; /* defined in "SIS_LCD_TYPE" */ + + int current_bpp; + int current_width; + int current_height; + int current_htotal; + int current_vtotal; + int current_linelength; + __u32 current_pixclock; + int current_refresh_rate; + + u8 mode_no; + u8 rate_idx; + int modechanged; + unsigned char modeprechange; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + u8 sisfb_lastrates[128]; +#endif + + int newrom; + int registered; + int warncount; + + int sisvga_engine; + int hwcursor_size; + int CRT2_write_enable; + u8 caps; + + u8 detectedpdc; + u8 detectedpdca; + u8 detectedlcda; + + SIS_IOTYPE1 *hwcursor_vbase; + + int chronteltype; + int tvxpos, tvypos; + u8 p2_1f,p2_20,p2_2b,p2_42,p2_43,p2_01,p2_02; + int tvx, tvy; + + u8 sisfblocked; + + struct sis_video_info *next; +}; + +typedef struct _SIS_OH { + struct _SIS_OH *poh_next; + struct _SIS_OH *poh_prev; + u32 offset; + u32 size; +} SIS_OH; + +typedef struct _SIS_OHALLOC { + struct _SIS_OHALLOC *poha_next; + SIS_OH aoh[1]; +} SIS_OHALLOC; + +typedef struct _SIS_HEAP { + SIS_OH oh_free; + SIS_OH oh_used; + SIS_OH *poh_freelist; + SIS_OHALLOC *poha_chain; + u32 max_freesize; + struct sis_video_info *vinfo; +} SIS_HEAP; + +#endif diff --git a/drivers/video/sis/sis_accel.c b/drivers/video/sis/sis_accel.c new file mode 100644 index 000000000000..30e90a553e80 --- /dev/null +++ b/drivers/video/sis/sis_accel.c @@ -0,0 +1,678 @@ +/* + * SiS 300/630/730/540/315/550/65x/74x/330/760 frame buffer driver + * for Linux kernels 2.4.x and 2.6.x + * + * 2D acceleration part + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the named License, + * or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Based on the XFree86/X.org driver which is + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * (see http://www.winischhofer.net/ + * for more information and updates) + */ + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/console.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/capability.h> +#include <linux/fs.h> +#include <linux/types.h> + +#include <asm/io.h> + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> +#endif + +#include "sis.h" +#include "sis_accel.h" + +static const u8 sisALUConv[] = +{ + 0x00, /* dest = 0; 0, GXclear, 0 */ + 0x88, /* dest &= src; DSa, GXand, 0x1 */ + 0x44, /* dest = src & ~dest; SDna, GXandReverse, 0x2 */ + 0xCC, /* dest = src; S, GXcopy, 0x3 */ + 0x22, /* dest &= ~src; DSna, GXandInverted, 0x4 */ + 0xAA, /* dest = dest; D, GXnoop, 0x5 */ + 0x66, /* dest = ^src; DSx, GXxor, 0x6 */ + 0xEE, /* dest |= src; DSo, GXor, 0x7 */ + 0x11, /* dest = ~src & ~dest; DSon, GXnor, 0x8 */ + 0x99, /* dest ^= ~src ; DSxn, GXequiv, 0x9 */ + 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */ + 0xDD, /* dest = src|~dest ; SDno, GXorReverse, 0xB */ + 0x33, /* dest = ~src; Sn, GXcopyInverted, 0xC */ + 0xBB, /* dest |= ~src; DSno, GXorInverted, 0xD */ + 0x77, /* dest = ~src|~dest; DSan, GXnand, 0xE */ + 0xFF, /* dest = 0xFF; 1, GXset, 0xF */ +}; +/* same ROP but with Pattern as Source */ +static const u8 sisPatALUConv[] = +{ + 0x00, /* dest = 0; 0, GXclear, 0 */ + 0xA0, /* dest &= src; DPa, GXand, 0x1 */ + 0x50, /* dest = src & ~dest; PDna, GXandReverse, 0x2 */ + 0xF0, /* dest = src; P, GXcopy, 0x3 */ + 0x0A, /* dest &= ~src; DPna, GXandInverted, 0x4 */ + 0xAA, /* dest = dest; D, GXnoop, 0x5 */ + 0x5A, /* dest = ^src; DPx, GXxor, 0x6 */ + 0xFA, /* dest |= src; DPo, GXor, 0x7 */ + 0x05, /* dest = ~src & ~dest; DPon, GXnor, 0x8 */ + 0xA5, /* dest ^= ~src ; DPxn, GXequiv, 0x9 */ + 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */ + 0xF5, /* dest = src|~dest ; PDno, GXorReverse, 0xB */ + 0x0F, /* dest = ~src; Pn, GXcopyInverted, 0xC */ + 0xAF, /* dest |= ~src; DPno, GXorInverted, 0xD */ + 0x5F, /* dest = ~src|~dest; DPan, GXnand, 0xE */ + 0xFF, /* dest = 0xFF; 1, GXset, 0xF */ +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34) +static const int myrops[] = { + 3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 +}; +#endif + +/* 300 series ----------------------------------------------------- */ +#ifdef CONFIG_FB_SIS_300 +static void +SiS300Sync(struct sis_video_info *ivideo) +{ + SiS300Idle +} + +static void +SiS300SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int xdir, int ydir, + int rop, int trans_color) +{ + SiS300SetupDSTColorDepth(ivideo->DstColor); + SiS300SetupSRCPitch(ivideo->video_linelength) + SiS300SetupDSTRect(ivideo->video_linelength, 0xffff) + + if(trans_color != -1) { + SiS300SetupROP(0x0A) + SiS300SetupSRCTrans(trans_color) + SiS300SetupCMDFlag(TRANSPARENT_BITBLT) + } else { + SiS300SetupROP(sisALUConv[rop]) + } + if(xdir > 0) { + SiS300SetupCMDFlag(X_INC) + } + if(ydir > 0) { + SiS300SetupCMDFlag(Y_INC) + } +} + +static void +SiS300SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, + int src_y, int dst_x, int dst_y, int width, int height) +{ + u32 srcbase = 0, dstbase = 0; + + if(src_y >= 2048) { + srcbase = ivideo->video_linelength * src_y; + src_y = 0; + } + if(dst_y >= 2048) { + dstbase = ivideo->video_linelength * dst_y; + dst_y = 0; + } + + SiS300SetupSRCBase(srcbase); + SiS300SetupDSTBase(dstbase); + + if(!(ivideo->CommandReg & X_INC)) { + src_x += width-1; + dst_x += width-1; + } + if(!(ivideo->CommandReg & Y_INC)) { + src_y += height-1; + dst_y += height-1; + } + SiS300SetupRect(width, height) + SiS300SetupSRCXY(src_x, src_y) + SiS300SetupDSTXY(dst_x, dst_y) + SiS300DoCMD +} + +static void +SiS300SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop) +{ + SiS300SetupPATFG(color) + SiS300SetupDSTRect(ivideo->video_linelength, 0xffff) + SiS300SetupDSTColorDepth(ivideo->DstColor); + SiS300SetupROP(sisPatALUConv[rop]) + SiS300SetupCMDFlag(PATFG) +} + +static void +SiS300SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h) +{ + u32 dstbase = 0; + + if(y >= 2048) { + dstbase = ivideo->video_linelength * y; + y = 0; + } + SiS300SetupDSTBase(dstbase) + SiS300SetupDSTXY(x,y) + SiS300SetupRect(w,h) + SiS300SetupCMDFlag(X_INC | Y_INC | BITBLT) + SiS300DoCMD +} +#endif + +/* 315/330 series ------------------------------------------------- */ + +#ifdef CONFIG_FB_SIS_315 +static void +SiS310Sync(struct sis_video_info *ivideo) +{ + SiS310Idle +} + +static void +SiS310SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int rop, int trans_color) +{ + SiS310SetupDSTColorDepth(ivideo->DstColor); + SiS310SetupSRCPitch(ivideo->video_linelength) + SiS310SetupDSTRect(ivideo->video_linelength, 0xffff) + if(trans_color != -1) { + SiS310SetupROP(0x0A) + SiS310SetupSRCTrans(trans_color) + SiS310SetupCMDFlag(TRANSPARENT_BITBLT) + } else { + SiS310SetupROP(sisALUConv[rop]) + /* Set command - not needed, both 0 */ + /* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */ + } + SiS310SetupCMDFlag(ivideo->SiS310_AccelDepth) + /* The 315 series is smart enough to know the direction */ +} + +static void +SiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int src_y, + int dst_x, int dst_y, int width, int height) +{ + u32 srcbase = 0, dstbase = 0; + int mymin = min(src_y, dst_y); + int mymax = max(src_y, dst_y); + + /* Although the chip knows the direction to use + * if the source and destination areas overlap, + * that logic fails if we fiddle with the bitmap + * addresses. Therefore, we check if the source + * and destination blitting areas overlap and + * adapt the bitmap addresses synchronously + * if the coordinates exceed the valid range. + * The the areas do not overlap, we do our + * normal check. + */ + if((mymax - mymin) < height) { + if((src_y >= 2048) || (dst_y >= 2048)) { + srcbase = ivideo->video_linelength * mymin; + dstbase = ivideo->video_linelength * mymin; + src_y -= mymin; + dst_y -= mymin; + } + } else { + if(src_y >= 2048) { + srcbase = ivideo->video_linelength * src_y; + src_y = 0; + } + if(dst_y >= 2048) { + dstbase = ivideo->video_linelength * dst_y; + dst_y = 0; + } + } + + SiS310SetupSRCBase(srcbase); + SiS310SetupDSTBase(dstbase); + SiS310SetupRect(width, height) + SiS310SetupSRCXY(src_x, src_y) + SiS310SetupDSTXY(dst_x, dst_y) + SiS310DoCMD +} + +static void +SiS310SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop) +{ + SiS310SetupPATFG(color) + SiS310SetupDSTRect(ivideo->video_linelength, 0xffff) + SiS310SetupDSTColorDepth(ivideo->DstColor); + SiS310SetupROP(sisPatALUConv[rop]) + SiS310SetupCMDFlag(PATFG | ivideo->SiS310_AccelDepth) +} + +static void +SiS310SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h) +{ + u32 dstbase = 0; + + if(y >= 2048) { + dstbase = ivideo->video_linelength * y; + y = 0; + } + SiS310SetupDSTBase(dstbase) + SiS310SetupDSTXY(x,y) + SiS310SetupRect(w,h) + SiS310SetupCMDFlag(BITBLT) + SiS310DoCMD +} +#endif + +/* --------------------------------------------------------------------- */ + +/* The exported routines */ + +int sisfb_initaccel(struct sis_video_info *ivideo) +{ +#ifdef SISFB_USE_SPINLOCKS + spin_lock_init(&ivideo->lockaccel); +#endif + return(0); +} + +void sisfb_syncaccel(struct sis_video_info *ivideo) +{ + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + SiS300Sync(ivideo); +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + SiS310Sync(ivideo); +#endif + } +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) /* --------------- 2.5 --------------- */ + +int fbcon_sis_sync(struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + CRITFLAGS + + if(!ivideo->accel) + return 0; + + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + SiS300Sync(ivideo); +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + SiS310Sync(ivideo); +#endif + } + CRITEND + return 0; +} + +void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + u32 col = 0; + u32 vxres = info->var.xres_virtual; + u32 vyres = info->var.yres_virtual; + int width, height; + CRITFLAGS + + if(info->state != FBINFO_STATE_RUNNING) { + return; + } + + if(!ivideo->accel) { + cfb_fillrect(info, rect); + return; + } + + if(!rect->width || !rect->height || rect->dx >= vxres || rect->dy >= vyres) { + return; + } + + /* Clipping */ + width = ((rect->dx + rect->width) > vxres) ? (vxres - rect->dx) : rect->width; + height = ((rect->dy + rect->height) > vyres) ? (vyres - rect->dy) : rect->height; + + switch(info->var.bits_per_pixel) { + case 8: col = rect->color; + break; + case 16: + case 32: col = ((u32 *)(info->pseudo_palette))[rect->color]; + break; + } + + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + CRITBEGIN + SiS300SetupForSolidFill(ivideo, col, myrops[rect->rop]); + SiS300SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height); + CRITEND + SiS300Sync(ivideo); +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + CRITBEGIN + SiS310SetupForSolidFill(ivideo, col, myrops[rect->rop]); + SiS310SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height); + CRITEND + SiS310Sync(ivideo); +#endif + } + +} + +void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + u32 vxres = info->var.xres_virtual; + u32 vyres = info->var.yres_virtual; + int width = area->width; + int height = area->height; + CRITFLAGS + + if(info->state != FBINFO_STATE_RUNNING) { + return; + } + + if(!ivideo->accel) { + cfb_copyarea(info, area); + return; + } + + if(!width || !height || + area->sx >= vxres || area->sy >= vyres || + area->dx >= vxres || area->dy >= vyres) { + return; + } + + /* Clipping */ + if((area->sx + width) > vxres) width = vxres - area->sx; + if((area->dx + width) > vxres) width = vxres - area->dx; + if((area->sy + height) > vyres) height = vyres - area->sy; + if((area->dy + height) > vyres) height = vyres - area->dy; + + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + int xdir, ydir; + + if(area->sx < area->dx) xdir = 0; + else xdir = 1; + if(area->sy < area->dy) ydir = 0; + else ydir = 1; + + CRITBEGIN + SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1); + SiS300SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, area->dx, area->dy, + width, height); + CRITEND + SiS300Sync(ivideo); +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + CRITBEGIN + SiS310SetupForScreenToScreenCopy(ivideo, 3, -1); + SiS310SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, area->dx, area->dy, + width, height); + CRITEND + SiS310Sync(ivideo); +#endif + } +} + +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* -------------- 2.4 --------------- */ + +void fbcon_sis_bmove(struct display *p, int srcy, int srcx, + int dsty, int dstx, int height, int width) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par; + + CRITFLAGS + + if(!ivideo->accel) { + switch(ivideo->video_bpp) { + case 8: +#ifdef FBCON_HAS_CFB8 + fbcon_cfb8_bmove(p, srcy, srcx, dsty, dstx, height, width); +#endif + break; + case 16: +#ifdef FBCON_HAS_CFB16 + fbcon_cfb16_bmove(p, srcy, srcx, dsty, dstx, height, width); +#endif + break; + case 32: +#ifdef FBCON_HAS_CFB32 + fbcon_cfb32_bmove(p, srcy, srcx, dsty, dstx, height, width); +#endif + break; + } + return; + } + + srcx *= fontwidth(p); + srcy *= fontheight(p); + dstx *= fontwidth(p); + dsty *= fontheight(p); + width *= fontwidth(p); + height *= fontheight(p); + + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + int xdir, ydir; + + if(srcx < dstx) xdir = 0; + else xdir = 1; + if(srcy < dsty) ydir = 0; + else ydir = 1; + + CRITBEGIN + SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1); + SiS300SubsequentScreenToScreenCopy(ivideo, srcx, srcy, dstx, dsty, width, height); + CRITEND + SiS300Sync(ivideo); +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + CRITBEGIN + SiS310SetupForScreenToScreenCopy(ivideo, 3, -1); + SiS310SubsequentScreenToScreenCopy(ivideo, srcx, srcy, dstx, dsty, width, height); + CRITEND + SiS310Sync(ivideo); +#endif + } +} + +static void fbcon_sis_clear(struct vc_data *conp, struct display *p, + int srcy, int srcx, int height, int width, int color) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par; + CRITFLAGS + + srcx *= fontwidth(p); + srcy *= fontheight(p); + width *= fontwidth(p); + height *= fontheight(p); + + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + CRITBEGIN + SiS300SetupForSolidFill(ivideo, color, 3); + SiS300SubsequentSolidFillRect(ivideo, srcx, srcy, width, height); + CRITEND + SiS300Sync(ivideo); +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + CRITBEGIN + SiS310SetupForSolidFill(ivideo, color, 3); + SiS310SubsequentSolidFillRect(ivideo, srcx, srcy, width, height); + CRITEND + SiS310Sync(ivideo); +#endif + } +} + +void fbcon_sis_clear8(struct vc_data *conp, struct display *p, + int srcy, int srcx, int height, int width) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par; + u32 bgx; + + if(!ivideo->accel) { +#ifdef FBCON_HAS_CFB8 + fbcon_cfb8_clear(conp, p, srcy, srcx, height, width); +#endif + return; + } + + bgx = attr_bgcol_ec(p, conp); + fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx); +} + +void fbcon_sis_clear16(struct vc_data *conp, struct display *p, + int srcy, int srcx, int height, int width) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par; + u32 bgx; + + if(!ivideo->accel) { +#ifdef FBCON_HAS_CFB16 + fbcon_cfb16_clear(conp, p, srcy, srcx, height, width); +#endif + return; + } + + bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; + fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx); +} + +void fbcon_sis_clear32(struct vc_data *conp, struct display *p, + int srcy, int srcx, int height, int width) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par; + u32 bgx; + + if(!ivideo->accel) { +#ifdef FBCON_HAS_CFB32 + fbcon_cfb32_clear(conp, p, srcy, srcx, height, width); +#endif + return; + } + + bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; + fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx); +} + +void fbcon_sis_revc(struct display *p, int srcx, int srcy) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par; + CRITFLAGS + + if(!ivideo->accel) { + switch(ivideo->video_bpp) { + case 16: +#ifdef FBCON_HAS_CFB16 + fbcon_cfb16_revc(p, srcx, srcy); +#endif + break; + case 32: +#ifdef FBCON_HAS_CFB32 + fbcon_cfb32_revc(p, srcx, srcy); +#endif + break; + } + return; + } + + srcx *= fontwidth(p); + srcy *= fontheight(p); + + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + CRITBEGIN + SiS300SetupForSolidFill(ivideo, 0, 0x0a); + SiS300SubsequentSolidFillRect(ivideo, srcx, srcy, fontwidth(p), fontheight(p)); + CRITEND + SiS300Sync(ivideo); +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + CRITBEGIN + SiS310SetupForSolidFill(ivideo, 0, 0x0a); + SiS310SubsequentSolidFillRect(ivideo, srcx, srcy, fontwidth(p), fontheight(p)); + CRITEND + SiS310Sync(ivideo); +#endif + } +} + +#ifdef FBCON_HAS_CFB8 +struct display_switch fbcon_sis8 = { + .setup = fbcon_cfb8_setup, + .bmove = fbcon_sis_bmove, + .clear = fbcon_sis_clear8, + .putc = fbcon_cfb8_putc, + .putcs = fbcon_cfb8_putcs, + .revc = fbcon_cfb8_revc, + .clear_margins = fbcon_cfb8_clear_margins, + .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif +#ifdef FBCON_HAS_CFB16 +struct display_switch fbcon_sis16 = { + .setup = fbcon_cfb16_setup, + .bmove = fbcon_sis_bmove, + .clear = fbcon_sis_clear16, + .putc = fbcon_cfb16_putc, + .putcs = fbcon_cfb16_putcs, + .revc = fbcon_sis_revc, + .clear_margins = fbcon_cfb16_clear_margins, + .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif +#ifdef FBCON_HAS_CFB32 +struct display_switch fbcon_sis32 = { + .setup = fbcon_cfb32_setup, + .bmove = fbcon_sis_bmove, + .clear = fbcon_sis_clear32, + .putc = fbcon_cfb32_putc, + .putcs = fbcon_cfb32_putcs, + .revc = fbcon_sis_revc, + .clear_margins = fbcon_cfb32_clear_margins, + .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif + +#endif /* KERNEL VERSION */ + + diff --git a/drivers/video/sis/sis_accel.h b/drivers/video/sis/sis_accel.h new file mode 100644 index 000000000000..bb28f331d60d --- /dev/null +++ b/drivers/video/sis/sis_accel.h @@ -0,0 +1,409 @@ +/* + * SiS 300/630/730/540/315/550/650/740 frame buffer driver + * for Linux kernels 2.4.x and 2.5.x + * + * 2D acceleration part + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the named License, + * or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Based on the X driver's sis300_accel.h which is + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * and sis310_accel.h which is + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * Author: Thomas Winischhofer <thomas@winischhofer.net>: + * (see http://www.winischhofer.net/ + * for more information and updates) + */ + +#ifndef _SISFB_ACCEL_H +#define _SISFB_ACCEL_H + +/* Guard accelerator accesses with spin_lock_irqsave? Works well without. */ +#undef SISFB_USE_SPINLOCKS + +#ifdef SISFB_USE_SPINLOCKS +#include <linux/spinlock.h> +#define CRITBEGIN spin_lock_irqsave(&ivideo->lockaccel, critflags); +#define CRITEND spin_unlock_irqrestore(&ivideo->lockaccel, critflags); +#define CRITFLAGS unsigned long critflags; +#else +#define CRITBEGIN +#define CRITEND +#define CRITFLAGS +#endif + +/* Definitions for the SIS engine communication. */ + +#define PATREGSIZE 384 /* Pattern register size. 384 bytes @ 0x8300 */ +#define BR(x) (0x8200 | (x) << 2) +#define PBR(x) (0x8300 | (x) << 2) + +/* SiS300 engine commands */ +#define BITBLT 0x00000000 /* Blit */ +#define COLOREXP 0x00000001 /* Color expand */ +#define ENCOLOREXP 0x00000002 /* Enhanced color expand */ +#define MULTIPLE_SCANLINE 0x00000003 /* ? */ +#define LINE 0x00000004 /* Draw line */ +#define TRAPAZOID_FILL 0x00000005 /* Fill trapezoid */ +#define TRANSPARENT_BITBLT 0x00000006 /* Transparent Blit */ + +/* Additional engine commands for 315 */ +#define ALPHA_BLEND 0x00000007 /* Alpha blend ? */ +#define A3D_FUNCTION 0x00000008 /* 3D command ? */ +#define CLEAR_Z_BUFFER 0x00000009 /* ? */ +#define GRADIENT_FILL 0x0000000A /* Gradient fill */ + +/* source select */ +#define SRCVIDEO 0x00000000 /* source is video RAM */ +#define SRCSYSTEM 0x00000010 /* source is system memory */ +#define SRCCPUBLITBUF SRCSYSTEM /* source is CPU-driven BitBuffer (for color expand) */ +#define SRCAGP 0x00000020 /* source is AGP memory (?) */ + +/* Pattern flags */ +#define PATFG 0x00000000 /* foreground color */ +#define PATPATREG 0x00000040 /* pattern in pattern buffer (0x8300) */ +#define PATMONO 0x00000080 /* mono pattern */ + +/* blitting direction (300 series only) */ +#define X_INC 0x00010000 +#define X_DEC 0x00000000 +#define Y_INC 0x00020000 +#define Y_DEC 0x00000000 + +/* Clipping flags */ +#define NOCLIP 0x00000000 +#define NOMERGECLIP 0x04000000 +#define CLIPENABLE 0x00040000 +#define CLIPWITHOUTMERGE 0x04040000 + +/* Transparency */ +#define OPAQUE 0x00000000 +#define TRANSPARENT 0x00100000 + +/* ? */ +#define DSTAGP 0x02000000 +#define DSTVIDEO 0x02000000 + +/* Subfunctions for Color/Enhanced Color Expansion (315 only) */ +#define COLOR_TO_MONO 0x00100000 +#define AA_TEXT 0x00200000 + +/* Some general registers for 315 series */ +#define SRC_ADDR 0x8200 +#define SRC_PITCH 0x8204 +#define AGP_BASE 0x8206 /* color-depth dependent value */ +#define SRC_Y 0x8208 +#define SRC_X 0x820A +#define DST_Y 0x820C +#define DST_X 0x820E +#define DST_ADDR 0x8210 +#define DST_PITCH 0x8214 +#define DST_HEIGHT 0x8216 +#define RECT_WIDTH 0x8218 +#define RECT_HEIGHT 0x821A +#define PAT_FGCOLOR 0x821C +#define PAT_BGCOLOR 0x8220 +#define SRC_FGCOLOR 0x8224 +#define SRC_BGCOLOR 0x8228 +#define MONO_MASK 0x822C +#define LEFT_CLIP 0x8234 +#define TOP_CLIP 0x8236 +#define RIGHT_CLIP 0x8238 +#define BOTTOM_CLIP 0x823A +#define COMMAND_READY 0x823C +#define FIRE_TRIGGER 0x8240 + +#define PATTERN_REG 0x8300 /* 384 bytes pattern buffer */ + +/* Transparent bitblit registers */ +#define TRANS_DST_KEY_HIGH PAT_FGCOLOR +#define TRANS_DST_KEY_LOW PAT_BGCOLOR +#define TRANS_SRC_KEY_HIGH SRC_FGCOLOR +#define TRANS_SRC_KEY_LOW SRC_BGCOLOR + +/* Store queue length in par */ +#define CmdQueLen ivideo->cmdqueuelength + +/* ------------- SiS 300 series -------------- */ + +/* BR(16) (0x8240): + + bit 31 2D engine: 1 is idle, + bit 30 3D engine: 1 is idle, + bit 29 Command queue: 1 is empty + bits 28:24: Current CPU driven BitBlt buffer stage bit[4:0] + bits 15:0: Current command queue length + +*/ + +#define SiS300Idle \ + { \ + while((MMIO_IN16(ivideo->mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \ + while((MMIO_IN16(ivideo->mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \ + while((MMIO_IN16(ivideo->mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \ + CmdQueLen = MMIO_IN16(ivideo->mmio_vbase, 0x8240); \ + } +/* (do three times, because 2D engine seems quite unsure about whether or not it's idle) */ + +#define SiS300SetupSRCBase(base) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(0), base);\ + CmdQueLen--; + +#define SiS300SetupSRCPitch(pitch) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT16(ivideo->mmio_vbase, BR(1), pitch);\ + CmdQueLen--; + +#define SiS300SetupSRCXY(x,y) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(2), (x)<<16 | (y) );\ + CmdQueLen--; + +#define SiS300SetupDSTBase(base) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(4), base);\ + CmdQueLen--; + +#define SiS300SetupDSTXY(x,y) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(3), (x)<<16 | (y) );\ + CmdQueLen--; + +#define SiS300SetupDSTRect(x,y) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(5), (y)<<16 | (x) );\ + CmdQueLen--; + +#define SiS300SetupDSTColorDepth(bpp) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT16(ivideo->mmio_vbase, BR(1)+2, bpp);\ + CmdQueLen--; + +#define SiS300SetupRect(w,h) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(6), (h)<<16 | (w) );\ + CmdQueLen--; + +#define SiS300SetupPATFG(color) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(7), color);\ + CmdQueLen--; + +#define SiS300SetupPATBG(color) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(8), color);\ + CmdQueLen--; + +#define SiS300SetupSRCFG(color) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(9), color);\ + CmdQueLen--; + +#define SiS300SetupSRCBG(color) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(10), color);\ + CmdQueLen--; + +/* 0x8224 src colorkey high */ +/* 0x8228 src colorkey low */ +/* 0x821c dest colorkey high */ +/* 0x8220 dest colorkey low */ +#define SiS300SetupSRCTrans(color) \ + if(CmdQueLen <= 1) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, 0x8224, color);\ + MMIO_OUT32(ivideo->mmio_vbase, 0x8228, color);\ + CmdQueLen -= 2; + +#define SiS300SetupDSTTrans(color) \ + if(CmdQueLen <= 1) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, 0x821C, color); \ + MMIO_OUT32(ivideo->mmio_vbase, 0x8220, color); \ + CmdQueLen -= 2; + +#define SiS300SetupMONOPAT(p0,p1) \ + if(CmdQueLen <= 1) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(11), p0);\ + MMIO_OUT32(ivideo->mmio_vbase, BR(12), p1);\ + CmdQueLen -= 2; + +#define SiS300SetupClipLT(left,top) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(13), ((left) & 0xFFFF) | (top)<<16 );\ + CmdQueLen--; + +#define SiS300SetupClipRB(right,bottom) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(14), ((right) & 0xFFFF) | (bottom)<<16 );\ + CmdQueLen--; + +/* General */ +#define SiS300SetupROP(rop) \ + ivideo->CommandReg = (rop) << 8; + +#define SiS300SetupCMDFlag(flags) \ + ivideo->CommandReg |= (flags); + +#define SiS300DoCMD \ + if(CmdQueLen <= 1) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(15), ivideo->CommandReg); \ + MMIO_OUT32(ivideo->mmio_vbase, BR(16), 0);\ + CmdQueLen -= 2; + +/* -------------- SiS 315/330 series --------------- */ + +/* Q_STATUS: + bit 31 = 1: All engines idle and all queues empty + bit 30 = 1: Hardware Queue (=HW CQ, 2D queue, 3D queue) empty + bit 29 = 1: 2D engine is idle + bit 28 = 1: 3D engine is idle + bit 27 = 1: HW command queue empty + bit 26 = 1: 2D queue empty + bit 25 = 1: 3D queue empty + bit 24 = 1: SW command queue empty + bits 23:16: 2D counter 3 + bits 15:8: 2D counter 2 + bits 7:0: 2D counter 1 +*/ + +#define SiS310Idle \ + { \ + while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \ + while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \ + CmdQueLen = 0; \ + } + +#define SiS310SetupSRCBase(base) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, SRC_ADDR, base);\ + CmdQueLen--; + +#define SiS310SetupSRCPitch(pitch) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT16(ivideo->mmio_vbase, SRC_PITCH, pitch);\ + CmdQueLen--; + +#define SiS310SetupSRCXY(x,y) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, SRC_Y, (x)<<16 | (y) );\ + CmdQueLen--; + +#define SiS310SetupDSTBase(base) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, DST_ADDR, base);\ + CmdQueLen--; + +#define SiS310SetupDSTXY(x,y) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, DST_Y, (x)<<16 | (y) );\ + CmdQueLen--; + +#define SiS310SetupDSTRect(x,y) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, DST_PITCH, (y)<<16 | (x) );\ + CmdQueLen--; + +#define SiS310SetupDSTColorDepth(bpp) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT16(ivideo->mmio_vbase, AGP_BASE, bpp);\ + CmdQueLen--; + +#define SiS310SetupRect(w,h) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, RECT_WIDTH, (h)<<16 | (w) );\ + CmdQueLen--; + +#define SiS310SetupPATFG(color) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, PAT_FGCOLOR, color);\ + CmdQueLen--; + +#define SiS310SetupPATBG(color) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, PAT_BGCOLOR, color);\ + CmdQueLen--; + +#define SiS310SetupSRCFG(color) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, SRC_FGCOLOR, color);\ + CmdQueLen--; + +#define SiS310SetupSRCBG(color) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, SRC_BGCOLOR, color);\ + CmdQueLen--; + +#define SiS310SetupSRCTrans(color) \ + if(CmdQueLen <= 1) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, TRANS_SRC_KEY_HIGH, color);\ + MMIO_OUT32(ivideo->mmio_vbase, TRANS_SRC_KEY_LOW, color);\ + CmdQueLen -= 2; + +#define SiS310SetupDSTTrans(color) \ + if(CmdQueLen <= 1) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, TRANS_DST_KEY_HIGH, color); \ + MMIO_OUT32(ivideo->mmio_vbase, TRANS_DST_KEY_LOW, color); \ + CmdQueLen -= 2; + +#define SiS310SetupMONOPAT(p0,p1) \ + if(CmdQueLen <= 1) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, MONO_MASK, p0);\ + MMIO_OUT32(ivideo->mmio_vbase, MONO_MASK+4, p1);\ + CmdQueLen -= 2; + +#define SiS310SetupClipLT(left,top) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, LEFT_CLIP, ((left) & 0xFFFF) | (top)<<16 );\ + CmdQueLen--; + +#define SiS310SetupClipRB(right,bottom) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, RIGHT_CLIP, ((right) & 0xFFFF) | (bottom)<<16 );\ + CmdQueLen--; + +#define SiS310SetupROP(rop) \ + ivideo->CommandReg = (rop) << 8; + +#define SiS310SetupCMDFlag(flags) \ + ivideo->CommandReg |= (flags); + +#define SiS310DoCMD \ + if(CmdQueLen <= 1) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, COMMAND_READY, ivideo->CommandReg); \ + MMIO_OUT32(ivideo->mmio_vbase, FIRE_TRIGGER, 0); \ + CmdQueLen -= 2; + + +int sisfb_initaccel(struct sis_video_info *ivideo); +void sisfb_syncaccel(struct sis_video_info *ivideo); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33) +void fbcon_sis_bmove(struct display *p, int srcy, int srcx, int dsty, + int dstx, int height, int width); +void fbcon_sis_revc(struct display *p, int srcy, int srcx); +void fbcon_sis_clear8(struct vc_data *conp, struct display *p, int srcy, + int srcx, int height, int width); +void fbcon_sis_clear16(struct vc_data *conp, struct display *p, int srcy, + int srcx, int height, int width); +void fbcon_sis_clear32(struct vc_data *conp, struct display *p, int srcy, + int srcx, int height, int width); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34) +void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area); +#endif + +#endif diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c new file mode 100644 index 000000000000..b773c98f6513 --- /dev/null +++ b/drivers/video/sis/sis_main.c @@ -0,0 +1,6027 @@ +/* + * SiS 300/305/540/630(S)/730(S) + * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760 + * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 + * + * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the named License, + * or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + * Author of (practically wiped) code base: + * SiS (www.sis.com) + * Copyright (C) 1999 Silicon Integrated Systems, Inc. + * + * See http://www.winischhofer.net/ for more information and updates + * + * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver, + * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * + */ + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#include <linux/moduleparam.h> +#endif +#include <linux/kernel.h> +#include <linux/smp_lock.h> +#include <linux/spinlock.h> +#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/console.h> +#include <linux/selection.h> +#include <linux/smp_lock.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/vmalloc.h> +#include <linux/vt_kern.h> +#include <linux/capability.h> +#include <linux/fs.h> +#include <linux/types.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> +#endif + +#include "sis.h" +#include "sis_main.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3) +#error "This version of sisfb requires at least 2.6.3" +#endif +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#ifdef FBCON_HAS_CFB8 +extern struct display_switch fbcon_sis8; +#endif +#ifdef FBCON_HAS_CFB16 +extern struct display_switch fbcon_sis16; +#endif +#ifdef FBCON_HAS_CFB32 +extern struct display_switch fbcon_sis32; +#endif +#endif + +/* ------------------ Internal helper routines ----------------- */ + +static void __init +sisfb_setdefaultparms(void) +{ + sisfb_off = 0; + sisfb_parm_mem = 0; + sisfb_accel = -1; + sisfb_ypan = -1; + sisfb_max = -1; + sisfb_userom = -1; + sisfb_useoem = -1; +#ifdef MODULE + /* Module: "None" for 2.4, default mode for 2.5+ */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + sisfb_mode_idx = -1; +#else + sisfb_mode_idx = MODE_INDEX_NONE; +#endif +#else + /* Static: Default mode */ + sisfb_mode_idx = -1; +#endif + sisfb_parm_rate = -1; + sisfb_crt1off = 0; + sisfb_forcecrt1 = -1; + sisfb_crt2type = -1; + sisfb_crt2flags = 0; + sisfb_pdc = 0xff; + sisfb_pdca = 0xff; + sisfb_scalelcd = -1; + sisfb_specialtiming = CUT_NONE; + sisfb_lvdshl = -1; + sisfb_dstn = 0; + sisfb_fstn = 0; + sisfb_tvplug = -1; + sisfb_tvstd = -1; + sisfb_tvxposoffset = 0; + sisfb_tvyposoffset = 0; + sisfb_filter = -1; + sisfb_nocrt2rate = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + sisfb_inverse = 0; + sisfb_fontname[0] = 0; +#endif +#if !defined(__i386__) && !defined(__x86_64__) + sisfb_resetcard = 0; + sisfb_videoram = 0; +#endif +} + +static void __devinit +sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet) +{ + int i = 0, j = 0; + + /* BEWARE: We don't know the hardware specs yet and there is no ivideo */ + + if(vesamode == 0) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + sisfb_mode_idx = MODE_INDEX_NONE; +#else + if(!quiet) { + printk(KERN_ERR "sisfb: Invalid mode. Using default.\n"); + } + sisfb_mode_idx = DEFAULT_MODE; +#endif + return; + } + + vesamode &= 0x1dff; /* Clean VESA mode number from other flags */ + + while(sisbios_mode[i++].mode_no[0] != 0) { + if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) || + (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) { + if(sisfb_fstn) { + if(sisbios_mode[i-1].mode_no[1] == 0x50 || + sisbios_mode[i-1].mode_no[1] == 0x56 || + sisbios_mode[i-1].mode_no[1] == 0x53) continue; + } else { + if(sisbios_mode[i-1].mode_no[1] == 0x5a || + sisbios_mode[i-1].mode_no[1] == 0x5b) continue; + } + sisfb_mode_idx = i - 1; + j = 1; + break; + } + } + if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode); +} + +static void +sisfb_search_mode(char *name, BOOLEAN quiet) +{ + int i = 0; + unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0; + char strbuf[16], strbuf1[20]; + char *nameptr = name; + + /* BEWARE: We don't know the hardware specs yet and there is no ivideo */ + + if(name == NULL) { + if(!quiet) { + printk(KERN_ERR "sisfb: Internal error, using default mode.\n"); + } + sisfb_mode_idx = DEFAULT_MODE; + return; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) { + if(!quiet) { + printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n"); + } + sisfb_mode_idx = DEFAULT_MODE; + return; + } +#endif + if(strlen(name) <= 19) { + strcpy(strbuf1, name); + for(i=0; i<strlen(strbuf1); i++) { + if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' '; + } + + /* This does some fuzzy mode naming detection */ + if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) { + if((rate <= 32) || (depth > 32)) { + j = rate; rate = depth; depth = j; + } + sprintf(strbuf, "%ux%ux%u", xres, yres, depth); + nameptr = strbuf; + sisfb_parm_rate = rate; + } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) { + sprintf(strbuf, "%ux%ux%u", xres, yres, depth); + nameptr = strbuf; + } else { + xres = 0; + if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) { + sprintf(strbuf, "%ux%ux8", xres, yres); + nameptr = strbuf; + } else { + sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet); + return; + } + } + } + + i = 0; j = 0; + while(sisbios_mode[i].mode_no[0] != 0) { + if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) { + if(sisfb_fstn) { + if(sisbios_mode[i-1].mode_no[1] == 0x50 || + sisbios_mode[i-1].mode_no[1] == 0x56 || + sisbios_mode[i-1].mode_no[1] == 0x53) continue; + } else { + if(sisbios_mode[i-1].mode_no[1] == 0x5a || + sisbios_mode[i-1].mode_no[1] == 0x5b) continue; + } + sisfb_mode_idx = i - 1; + j = 1; + break; + } + } + if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr); +} + +#ifndef MODULE +static void __devinit +sisfb_get_vga_mode_from_kernel(void) +{ +#if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT) + char mymode[32]; + int mydepth = screen_info.lfb_depth; + + if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return; + + if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) && + (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) && + (mydepth >= 8) && (mydepth <= 32) ) { + + if(mydepth == 24) mydepth = 32; + + sprintf(mymode, "%ux%ux%u", screen_info.lfb_width, + screen_info.lfb_height, + mydepth); + + printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode); + + sisfb_search_mode(mymode, TRUE); + } +#endif + return; +} +#endif + +static void __init +sisfb_search_crt2type(const char *name) +{ + int i = 0; + + /* BEWARE: We don't know the hardware specs yet and there is no ivideo */ + + if(name == NULL) return; + + while(sis_crt2type[i].type_no != -1) { + if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) { + sisfb_crt2type = sis_crt2type[i].type_no; + sisfb_tvplug = sis_crt2type[i].tvplug_no; + sisfb_crt2flags = sis_crt2type[i].flags; + break; + } + i++; + } + + sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0; + sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0; + + if(sisfb_crt2type < 0) { + printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name); + } +} + +static void __init +sisfb_search_tvstd(const char *name) +{ + int i = 0; + + /* BEWARE: We don't know the hardware specs yet and there is no ivideo */ + + if(name == NULL) return; + + while(sis_tvtype[i].type_no != -1) { + if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) { + sisfb_tvstd = sis_tvtype[i].type_no; + break; + } + i++; + } +} + +static void __init +sisfb_search_specialtiming(const char *name) +{ + int i = 0; + BOOLEAN found = FALSE; + + /* BEWARE: We don't know the hardware specs yet and there is no ivideo */ + + if(name == NULL) return; + + if(!strnicmp(name, "none", 4)) { + sisfb_specialtiming = CUT_FORCENONE; + printk(KERN_DEBUG "sisfb: Special timing disabled\n"); + } else { + while(mycustomttable[i].chipID != 0) { + if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) { + sisfb_specialtiming = mycustomttable[i].SpecialID; + found = TRUE; + printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n", + mycustomttable[i].vendorName, mycustomttable[i].cardName, + mycustomttable[i].optionName); + break; + } + i++; + } + if(!found) { + printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:"); + printk(KERN_WARNING "\t\"none\" (to disable special timings)\n"); + i = 0; + while(mycustomttable[i].chipID != 0) { + printk(KERN_WARNING "\t\"%s\" (for %s %s)\n", + mycustomttable[i].optionName, + mycustomttable[i].vendorName, + mycustomttable[i].cardName); + i++; + } + } + } +} + +static BOOLEAN __devinit +sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer) +{ + int i, j, xres, yres, refresh, index; + u32 emodes; + + if(buffer[0] != 0x00 || buffer[1] != 0xff || + buffer[2] != 0xff || buffer[3] != 0xff || + buffer[4] != 0xff || buffer[5] != 0xff || + buffer[6] != 0xff || buffer[7] != 0x00) { + printk(KERN_DEBUG "sisfb: Bad EDID header\n"); + return FALSE; + } + + if(buffer[0x12] != 0x01) { + printk(KERN_INFO "sisfb: EDID version %d not supported\n", + buffer[0x12]); + return FALSE; + } + + monitor->feature = buffer[0x18]; + + if(!buffer[0x14] & 0x80) { + if(!(buffer[0x14] & 0x08)) { + printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n"); + } + } + + if(buffer[0x13] >= 0x01) { + /* EDID V1 rev 1 and 2: Search for monitor descriptor + * to extract ranges + */ + j = 0x36; + for(i=0; i<4; i++) { + if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 && + buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd && + buffer[j + 4] == 0x00) { + monitor->hmin = buffer[j + 7]; + monitor->hmax = buffer[j + 8]; + monitor->vmin = buffer[j + 5]; + monitor->vmax = buffer[j + 6]; + monitor->dclockmax = buffer[j + 9] * 10 * 1000; + monitor->datavalid = TRUE; + break; + } + j += 18; + } + } + + if(!monitor->datavalid) { + /* Otherwise: Get a range from the list of supported + * Estabished Timings. This is not entirely accurate, + * because fixed frequency monitors are not supported + * that way. + */ + monitor->hmin = 65535; monitor->hmax = 0; + monitor->vmin = 65535; monitor->vmax = 0; + monitor->dclockmax = 0; + emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16); + for(i = 0; i < 13; i++) { + if(emodes & sisfb_ddcsmodes[i].mask) { + if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h; + if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1; + if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v; + if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v; + if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d; + } + } + index = 0x26; + for(i = 0; i < 8; i++) { + xres = (buffer[index] + 31) * 8; + switch(buffer[index + 1] & 0xc0) { + case 0xc0: yres = (xres * 9) / 16; break; + case 0x80: yres = (xres * 4) / 5; break; + case 0x40: yres = (xres * 3) / 4; break; + default: yres = xres; break; + } + refresh = (buffer[index + 1] & 0x3f) + 60; + if((xres >= 640) && (yres >= 480)) { + for(j = 0; j < 8; j++) { + if((xres == sisfb_ddcfmodes[j].x) && + (yres == sisfb_ddcfmodes[j].y) && + (refresh == sisfb_ddcfmodes[j].v)) { + if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h; + if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1; + if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v; + if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v; + if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[i].d; + } + } + } + index += 2; + } + if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) { + monitor->datavalid = TRUE; + } + } + + return(monitor->datavalid); +} + +static void __devinit +sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno) +{ + USHORT temp, i, realcrtno = crtno; + u8 buffer[256]; + + monitor->datavalid = FALSE; + + if(crtno) { + if(ivideo->vbflags & CRT2_LCD) realcrtno = 1; + else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2; + else return; + } + + if((ivideo->sisfb_crt1off) && (!crtno)) return; + + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, + realcrtno, 0, &buffer[0]); + if((!temp) || (temp == 0xffff)) { + printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1); + return; + } else { + printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1); + printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n", + crtno + 1, + (temp & 0x1a) ? "" : "[none of the supported]", + (temp & 0x02) ? "2 " : "", + (temp & 0x08) ? "D&P" : "", + (temp & 0x10) ? "FPDI-2" : ""); + if(temp & 0x02) { + i = 3; /* Number of retrys */ + do { + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, + realcrtno, 1, &buffer[0]); + } while((temp) && i--); + if(!temp) { + if(sisfb_interpret_edid(monitor, &buffer[0])) { + printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n", + monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax, + monitor->dclockmax / 1000); + } else { + printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1); + } + } else { + printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1); + } + } else { + printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n"); + } + } +} + +static BOOLEAN +sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, + int mode_idx, int rate_idx, int rate) +{ + int htotal, vtotal; + unsigned int dclock, hsync; + + if(!monitor->datavalid) return TRUE; + + if(mode_idx < 0) return FALSE; + + /* Skip for 320x200, 320x240, 640x400 */ + switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) { + case 0x59: + case 0x41: + case 0x4f: + case 0x50: + case 0x56: + case 0x53: + case 0x2f: + case 0x5d: + case 0x5e: + return TRUE; +#ifdef CONFIG_FB_SIS_315 + case 0x5a: + case 0x5b: + if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE; +#endif + } + + if(rate < (monitor->vmin - 1)) return FALSE; + if(rate > (monitor->vmax + 1)) return FALSE; + + if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, &ivideo->sishw_ext, + sisbios_mode[mode_idx].mode_no[ivideo->mni], + &htotal, &vtotal, rate_idx)) { + dclock = (htotal * vtotal * rate) / 1000; + if(dclock > (monitor->dclockmax + 1000)) return FALSE; + hsync = dclock / htotal; + if(hsync < (monitor->hmin - 1)) return FALSE; + if(hsync > (monitor->hmax + 1)) return FALSE; + } else { + return FALSE; + } + return TRUE; +} + +static int +sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags) +{ + u16 xres=0, yres, myres; + +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1); + } +#endif + + myres = sisbios_mode[myindex].yres; + + switch(vbflags & VB_DISPTYPE_DISP2) { + + case CRT2_LCD: + + xres = ivideo->lcdxres; yres = ivideo->lcdyres; + + if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) { + if(sisbios_mode[myindex].xres > xres) return(-1); + if(myres > yres) return(-1); + } + + if(vbflags & (VB_LVDS | VB_30xBDH)) { + if(sisbios_mode[myindex].xres == 320) { + if((myres == 240) || (myres == 480)) { + if(!ivideo->sisfb_fstn) { + if(sisbios_mode[myindex].mode_no[1] == 0x5a || + sisbios_mode[myindex].mode_no[1] == 0x5b) + return(-1); + } else { + if(sisbios_mode[myindex].mode_no[1] == 0x50 || + sisbios_mode[myindex].mode_no[1] == 0x56 || + sisbios_mode[myindex].mode_no[1] == 0x53) + return(-1); + } + } + } + } + + if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, + sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn, + ivideo->SiS_Pr.SiS_CustomT, xres, yres) < 0x14) { + return(-1); + } + break; + + case CRT2_TV: + if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, + sisbios_mode[myindex].yres, 0) < 0x14) { + return(-1); + } + break; + + case CRT2_VGA: + if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, + sisbios_mode[myindex].yres, 0) < 0x14) { + return(-1); + } + break; + } + + return(myindex); +} + +static u8 +sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx) +{ + u16 xres, yres; + int i = 0; + + xres = sisbios_mode[mode_idx].xres; + yres = sisbios_mode[mode_idx].yres; + + ivideo->rate_idx = 0; + while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) { + if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) { + if(sisfb_vrate[i].refresh == rate) { + ivideo->rate_idx = sisfb_vrate[i].idx; + break; + } else if(sisfb_vrate[i].refresh > rate) { + if((sisfb_vrate[i].refresh - rate) <= 3) { + DPRINTK("sisfb: Adjusting rate from %d up to %d\n", + rate, sisfb_vrate[i].refresh); + ivideo->rate_idx = sisfb_vrate[i].idx; + ivideo->refresh_rate = sisfb_vrate[i].refresh; + } else if(((rate - sisfb_vrate[i-1].refresh) <= 2) + && (sisfb_vrate[i].idx != 1)) { + DPRINTK("sisfb: Adjusting rate from %d down to %d\n", + rate, sisfb_vrate[i-1].refresh); + ivideo->rate_idx = sisfb_vrate[i-1].idx; + ivideo->refresh_rate = sisfb_vrate[i-1].refresh; + } + break; + } else if((rate - sisfb_vrate[i].refresh) <= 2) { + DPRINTK("sisfb: Adjusting rate from %d down to %d\n", + rate, sisfb_vrate[i].refresh); + ivideo->rate_idx = sisfb_vrate[i].idx; + break; + } + } + i++; + } + if(ivideo->rate_idx > 0) { + return ivideo->rate_idx; + } else { + printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n", + rate, xres, yres); + return 0; + } +} + +static BOOLEAN +sisfb_bridgeisslave(struct sis_video_info *ivideo) +{ + unsigned char P1_00; + + if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE; + + inSISIDXREG(SISPART1,0x00,P1_00); + if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) || + ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) { + return TRUE; + } else { + return FALSE; + } +} + +static BOOLEAN +sisfballowretracecrt1(struct sis_video_info *ivideo) +{ + u8 temp; + + inSISIDXREG(SISCR,0x17,temp); + if(!(temp & 0x80)) return FALSE; + + inSISIDXREG(SISSR,0x1f,temp); + if(temp & 0xc0) return FALSE; + + return TRUE; +} + +static BOOLEAN +sisfbcheckvretracecrt1(struct sis_video_info *ivideo) +{ + if(!sisfballowretracecrt1(ivideo)) return FALSE; + + if(inSISREG(SISINPSTAT) & 0x08) return TRUE; + else return FALSE; +} + +static void +sisfbwaitretracecrt1(struct sis_video_info *ivideo) +{ + int watchdog; + + if(!sisfballowretracecrt1(ivideo)) return; + + watchdog = 65536; + while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog); + watchdog = 65536; + while((inSISREG(SISINPSTAT) & 0x08) && --watchdog); +} + +static BOOLEAN +sisfbcheckvretracecrt2(struct sis_video_info *ivideo) +{ + unsigned char temp, reg; + + switch(ivideo->sisvga_engine) { + case SIS_300_VGA: reg = 0x25; break; + case SIS_315_VGA: reg = 0x30; break; + default: return FALSE; + } + + inSISIDXREG(SISPART1, reg, temp); + if(temp & 0x02) return TRUE; + else return FALSE; +} + +static BOOLEAN +sisfb_CheckVBRetrace(struct sis_video_info *ivideo) +{ + if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { + if(sisfb_bridgeisslave(ivideo)) { + return(sisfbcheckvretracecrt1(ivideo)); + } else { + return(sisfbcheckvretracecrt2(ivideo)); + } + } + return(sisfbcheckvretracecrt1(ivideo)); +} + +static u32 +sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount) +{ + u8 idx, reg1, reg2, reg3, reg4; + u32 ret = 0; + + (*vcount) = (*hcount) = 0; + + if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) { + ret |= (FB_VBLANK_HAVE_VSYNC | + FB_VBLANK_HAVE_HBLANK | + FB_VBLANK_HAVE_VBLANK | + FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_HCOUNT); + switch(ivideo->sisvga_engine) { + case SIS_300_VGA: idx = 0x25; break; + default: + case SIS_315_VGA: idx = 0x30; break; + } + inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */ + inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */ + inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */ + inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */ + if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING; + if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING; + if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING; + (*vcount) = reg3 | ((reg4 & 0x70) << 4); + (*hcount) = reg2 | ((reg4 & 0x0f) << 8); + } else if(sisfballowretracecrt1(ivideo)) { + ret |= (FB_VBLANK_HAVE_VSYNC | + FB_VBLANK_HAVE_VBLANK | + FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_HCOUNT); + reg1 = inSISREG(SISINPSTAT); + if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING; + if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING; + inSISIDXREG(SISCR,0x20,reg1); + inSISIDXREG(SISCR,0x1b,reg1); + inSISIDXREG(SISCR,0x1c,reg2); + inSISIDXREG(SISCR,0x1d,reg3); + (*vcount) = reg2 | ((reg3 & 0x07) << 8); + (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3; + } + return ret; +} + +static int +sisfb_myblank(struct sis_video_info *ivideo, int blank) +{ + u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13; + BOOLEAN backlight = TRUE; + + switch(blank) { + case FB_BLANK_UNBLANK: /* on */ + sr01 = 0x00; + sr11 = 0x00; + sr1f = 0x00; + cr63 = 0x00; + p2_0 = 0x20; + p1_13 = 0x00; + backlight = TRUE; + break; + case FB_BLANK_NORMAL: /* blank */ + sr01 = 0x20; + sr11 = 0x00; + sr1f = 0x00; + cr63 = 0x00; + p2_0 = 0x20; + p1_13 = 0x00; + backlight = TRUE; + break; + case FB_BLANK_VSYNC_SUSPEND: /* no vsync */ + sr01 = 0x20; + sr11 = 0x08; + sr1f = 0x80; + cr63 = 0x40; + p2_0 = 0x40; + p1_13 = 0x80; + backlight = FALSE; + break; + case FB_BLANK_HSYNC_SUSPEND: /* no hsync */ + sr01 = 0x20; + sr11 = 0x08; + sr1f = 0x40; + cr63 = 0x40; + p2_0 = 0x80; + p1_13 = 0x40; + backlight = FALSE; + break; + case FB_BLANK_POWERDOWN: /* off */ + sr01 = 0x20; + sr11 = 0x08; + sr1f = 0xc0; + cr63 = 0x40; + p2_0 = 0xc0; + p1_13 = 0xc0; + backlight = FALSE; + break; + default: + return 1; + } + + if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) { + + if( (!ivideo->sisfb_thismonitor.datavalid) || + ((ivideo->sisfb_thismonitor.datavalid) && + (ivideo->sisfb_thismonitor.feature & 0xe0))) { + + if(ivideo->sisvga_engine == SIS_315_VGA) { + setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63); + } + + if(!(sisfb_bridgeisslave(ivideo))) { + setSISIDXREG(SISSR, 0x01, ~0x20, sr01); + setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f); + } + } + + } + + if(ivideo->currentvbflags & CRT2_LCD) { + + if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) { + if(backlight) { + SiS_SiS30xBLOn(&ivideo->SiS_Pr, &ivideo->sishw_ext); + } else { + SiS_SiS30xBLOff(&ivideo->SiS_Pr, &ivideo->sishw_ext); + } + } else if(ivideo->sisvga_engine == SIS_315_VGA) { + if(ivideo->vbflags & VB_CHRONTEL) { + if(backlight) { + SiS_Chrontel701xBLOn(&ivideo->SiS_Pr,&ivideo->sishw_ext); + } else { + SiS_Chrontel701xBLOff(&ivideo->SiS_Pr); + } + } + } + + if(((ivideo->sisvga_engine == SIS_300_VGA) && + (ivideo->vbflags & (VB_301|VB_30xBDH|VB_LVDS))) || + ((ivideo->sisvga_engine == SIS_315_VGA) && + ((ivideo->vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) { + setSISIDXREG(SISSR, 0x11, ~0x0c, sr11); + } + + if(ivideo->sisvga_engine == SIS_300_VGA) { + if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) && + (!(ivideo->vbflags & VB_30xBDH))) { + setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13); + } + } else if(ivideo->sisvga_engine == SIS_315_VGA) { + if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) && + (!(ivideo->vbflags & VB_30xBDH))) { + setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0); + } + } + + } else if(ivideo->currentvbflags & CRT2_VGA) { + + if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) { + setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0); + } + + } + + return(0); +} + +/* ----------- FBDev related routines for all series ----------- */ + +static int +sisfb_get_cmap_len(const struct fb_var_screeninfo *var) +{ + return (var->bits_per_pixel == 8) ? 256 : 16; +} + +static void +sisfb_set_vparms(struct sis_video_info *ivideo) +{ + switch(ivideo->video_bpp) { + case 8: + ivideo->DstColor = 0x0000; + ivideo->SiS310_AccelDepth = 0x00000000; + ivideo->video_cmap_len = 256; + break; + case 16: + ivideo->DstColor = 0x8000; + ivideo->SiS310_AccelDepth = 0x00010000; + ivideo->video_cmap_len = 16; + break; + case 32: + ivideo->DstColor = 0xC000; + ivideo->SiS310_AccelDepth = 0x00020000; + ivideo->video_cmap_len = 16; + break; + default: + ivideo->video_cmap_len = 16; + printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp); + ivideo->accel = 0; + break; + } +} + +static int +sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) +{ + int maxyres = ivideo->heapstart / (var->xres_virtual * (var->bits_per_pixel >> 3)); + + if(maxyres > 32767) maxyres = 32767; + + return maxyres; +} + +static void +sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) +{ + ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3); + ivideo->scrnpitchCRT1 = ivideo->video_linelength; + if(!(ivideo->currentvbflags & CRT1_LCDA)) { + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + ivideo->scrnpitchCRT1 <<= 1; + } + } + +} + +static void +sisfb_set_pitch(struct sis_video_info *ivideo) +{ + BOOLEAN isslavemode = FALSE; + unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3; + unsigned short HDisplay2 = ivideo->video_linelength >> 3; + + if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE; + + /* We need to set pitch for CRT1 if bridge is in slave mode, too */ + if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) { + outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF)); + setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8)); + } + + /* We must not set the pitch for CRT2 if bridge is in slave mode */ + if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) { + orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01); + outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF)); + setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8)); + } +} + +static void +sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) +{ + ivideo->video_cmap_len = sisfb_get_cmap_len(var); + + switch(var->bits_per_pixel) { + case 8: + var->red.offset = var->green.offset = var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = 6; + break; + case 16: + 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 32: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + } +} + +static int +sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + unsigned int htotal = 0, vtotal = 0; + unsigned int drate = 0, hrate = 0; + int found_mode = 0; + int old_mode; + u32 pixclock; + + htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len; + + vtotal = var->upper_margin + var->lower_margin + var->vsync_len; + + pixclock = var->pixclock; + + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + vtotal += var->yres; + vtotal <<= 1; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + vtotal += var->yres; + vtotal <<= 2; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + vtotal += var->yres; + vtotal <<= 1; + } else vtotal += var->yres; + + if(!(htotal) || !(vtotal)) { + DPRINTK("sisfb: Invalid 'var' information\n"); + return -EINVAL; + } + + if(pixclock && htotal && vtotal) { + drate = 1000000000 / pixclock; + hrate = (drate * 1000) / htotal; + ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal); + } else { + ivideo->refresh_rate = 60; + } + + old_mode = ivideo->sisfb_mode_idx; + ivideo->sisfb_mode_idx = 0; + + while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) && + (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) { + if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) && + (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) && + (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) { + ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]; + found_mode = 1; + break; + } + ivideo->sisfb_mode_idx++; + } + + if(found_mode) { + ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo, + ivideo->sisfb_mode_idx, ivideo->currentvbflags); + } else { + ivideo->sisfb_mode_idx = -1; + } + + if(ivideo->sisfb_mode_idx < 0) { + printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres, + var->yres, var->bits_per_pixel); + ivideo->sisfb_mode_idx = old_mode; + return -EINVAL; + } + + if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) { + ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx; + ivideo->refresh_rate = 60; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + if(ivideo->sisfb_thismonitor.datavalid) { + if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx, + ivideo->rate_idx, ivideo->refresh_rate)) { + printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n"); + } + } +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) { +#else + if(isactive) { +#endif + sisfb_pre_setmode(ivideo); + + if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) { + printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no); + return -EINVAL; + } + + outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); + + sisfb_post_setmode(ivideo); + + ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp; + ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres; + ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres; + + sisfb_calc_pitch(ivideo, var); + sisfb_set_pitch(ivideo); + + ivideo->accel = 0; +#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN) +#ifdef STUPID_ACCELF_TEXT_SHIT + if(var->accel_flags & FB_ACCELF_TEXT) { + info->flags &= ~FBINFO_HWACCEL_DISABLED; + } else { + info->flags |= FBINFO_HWACCEL_DISABLED; + } +#endif + if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1; +#else + if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1; +#endif + + sisfb_set_vparms(ivideo); + + ivideo->current_width = ivideo->video_width; + ivideo->current_height = ivideo->video_height; + ivideo->current_bpp = ivideo->video_bpp; + ivideo->current_htotal = htotal; + ivideo->current_vtotal = vtotal; + ivideo->current_linelength = ivideo->video_linelength; + ivideo->current_pixclock = var->pixclock; + ivideo->current_refresh_rate = ivideo->refresh_rate; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate; +#endif + } + + return 0; +} + +static int +sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) +{ + unsigned int base; + + if(var->xoffset > (var->xres_virtual - var->xres)) { + return -EINVAL; + } + if(var->yoffset > (var->yres_virtual - var->yres)) { + return -EINVAL; + } + + base = (var->yoffset * var->xres_virtual) + var->xoffset; + + /* calculate base bpp dep. */ + switch(var->bits_per_pixel) { + case 32: + break; + case 16: + base >>= 1; + break; + case 8: + default: + base >>= 2; + break; + } + + outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); + + outSISIDXREG(SISCR, 0x0D, base & 0xFF); + outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF); + outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF); + if(ivideo->sisvga_engine == SIS_315_VGA) { + setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01); + } + if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { + orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01); + outSISIDXREG(SISPART1, 0x06, (base & 0xFF)); + outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF)); + outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF)); + if(ivideo->sisvga_engine == SIS_315_VGA) { + setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7); + } + } + return 0; +} + +/* ------------ FBDev related routines for 2.4 series ----------- */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + +static void +sisfb_crtc_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) +{ + u16 VRE, VBE, VRS, VBS, VDE, VT; + u16 HRE, HBE, HRS, HBS, HDE, HT; + u8 sr_data, cr_data, cr_data2, cr_data3, mr_data; + int A, B, C, D, E, F, temp; + unsigned int hrate, drate, maxyres; + + inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data); + + if(sr_data & SIS_INTERLACED_MODE) + var->vmode = FB_VMODE_INTERLACED; + else + var->vmode = FB_VMODE_NONINTERLACED; + + switch((sr_data & 0x1C) >> 2) { + case SIS_8BPP_COLOR_MODE: + var->bits_per_pixel = 8; + break; + case SIS_16BPP_COLOR_MODE: + var->bits_per_pixel = 16; + break; + case SIS_32BPP_COLOR_MODE: + var->bits_per_pixel = 32; + break; + } + + sisfb_bpp_to_var(ivideo, var); + + inSISIDXREG(SISSR, 0x0A, sr_data); + inSISIDXREG(SISCR, 0x06, cr_data); + inSISIDXREG(SISCR, 0x07, cr_data2); + + VT = (cr_data & 0xFF) | + ((u16) (cr_data2 & 0x01) << 8) | + ((u16) (cr_data2 & 0x20) << 4) | + ((u16) (sr_data & 0x01) << 10); + A = VT + 2; + + inSISIDXREG(SISCR, 0x12, cr_data); + + VDE = (cr_data & 0xff) | + ((u16) (cr_data2 & 0x02) << 7) | + ((u16) (cr_data2 & 0x40) << 3) | + ((u16) (sr_data & 0x02) << 9); + E = VDE + 1; + + inSISIDXREG(SISCR, 0x10, cr_data); + + VRS = (cr_data & 0xff) | + ((u16) (cr_data2 & 0x04) << 6) | + ((u16) (cr_data2 & 0x80) << 2) | + ((u16) (sr_data & 0x08) << 7); + F = VRS + 1 - E; + + inSISIDXREG(SISCR, 0x15, cr_data); + inSISIDXREG(SISCR, 0x09, cr_data3); + + if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE; + + VBS = (cr_data & 0xff) | + ((u16) (cr_data2 & 0x08) << 5) | + ((u16) (cr_data3 & 0x20) << 4) | + ((u16) (sr_data & 0x04) << 8); + + inSISIDXREG(SISCR, 0x16, cr_data); + + VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4); + temp = VBE - ((E - 1) & 511); + B = (temp > 0) ? temp : (temp + 512); + + inSISIDXREG(SISCR, 0x11, cr_data); + + VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1); + temp = VRE - ((E + F - 1) & 31); + C = (temp > 0) ? temp : (temp + 32); + + D = B - F - C; + + var->yres = E; + var->upper_margin = D; + var->lower_margin = F; + var->vsync_len = C; + + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + var->yres <<= 1; + var->upper_margin <<= 1; + var->lower_margin <<= 1; + var->vsync_len <<= 1; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + var->yres >>= 1; + var->upper_margin >>= 1; + var->lower_margin >>= 1; + var->vsync_len >>= 1; + } + + inSISIDXREG(SISSR, 0x0b, sr_data); + inSISIDXREG(SISCR, 0x00, cr_data); + + HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8); + A = HT + 5; + + inSISIDXREG(SISCR, 0x01, cr_data); + + HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6); + E = HDE + 1; + + inSISIDXREG(SISCR, 0x04, cr_data); + + HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2); + F = HRS - E - 3; + + inSISIDXREG(SISCR, 0x02, cr_data); + + HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4); + + inSISIDXREG(SISSR, 0x0c, sr_data); + inSISIDXREG(SISCR, 0x03, cr_data); + inSISIDXREG(SISCR, 0x05, cr_data2); + + HBE = (cr_data & 0x1f) | + ((u16) (cr_data2 & 0x80) >> 2) | + ((u16) (sr_data & 0x03) << 6); + HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3); + + temp = HBE - ((E - 1) & 255); + B = (temp > 0) ? temp : (temp + 256); + + temp = HRE - ((E + F + 3) & 63); + C = (temp > 0) ? temp : (temp + 64); + + D = B - F - C; + + var->xres = E * 8; + if(var->xres_virtual < var->xres) { + var->xres_virtual = var->xres; + } + + if((var->xres == 320) && + (var->yres == 200 || var->yres == 240)) { + /* Terrible hack, but the correct CRTC data for + * these modes only produces a black screen... + */ + var->left_margin = (400 - 376); + var->right_margin = (328 - 320); + var->hsync_len = (376 - 328); + } else { + var->left_margin = D * 8; + var->right_margin = F * 8; + var->hsync_len = C * 8; + } + var->activate = FB_ACTIVATE_NOW; + + var->sync = 0; + + mr_data = inSISREG(SISMISCR); + if(mr_data & 0x80) + var->sync &= ~FB_SYNC_VERT_HIGH_ACT; + else + var->sync |= FB_SYNC_VERT_HIGH_ACT; + + if(mr_data & 0x40) + var->sync &= ~FB_SYNC_HOR_HIGH_ACT; + else + var->sync |= FB_SYNC_HOR_HIGH_ACT; + + VT += 2; + VT <<= 1; + HT = (HT + 5) * 8; + + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + VT <<= 1; + } + hrate = ivideo->refresh_rate * VT / 2; + drate = (hrate * HT) / 1000; + var->pixclock = (u32) (1000000000 / drate); + + if(ivideo->sisfb_ypan) { + maxyres = sisfb_calc_maxyres(ivideo, var); + if(ivideo->sisfb_max) { + var->yres_virtual = maxyres; + } else { + if(var->yres_virtual > maxyres) { + var->yres_virtual = maxyres; + } + } + if(var->yres_virtual <= var->yres) { + var->yres_virtual = var->yres; + } + } else { + var->yres_virtual = var->yres; + } + +} + +static int +sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue, + unsigned *transp, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + + if(regno >= ivideo->video_cmap_len) return 1; + + *red = ivideo->sis_palette[regno].red; + *green = ivideo->sis_palette[regno].green; + *blue = ivideo->sis_palette[regno].blue; + *transp = 0; + + return 0; +} + +static int +sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + + if(regno >= ivideo->video_cmap_len) return 1; + + ivideo->sis_palette[regno].red = red; + ivideo->sis_palette[regno].green = green; + ivideo->sis_palette[regno].blue = blue; + + switch(ivideo->video_bpp) { +#ifdef FBCON_HAS_CFB8 + case 8: + outSISREG(SISDACA, regno); + outSISREG(SISDACD, (red >> 10)); + outSISREG(SISDACD, (green >> 10)); + outSISREG(SISDACD, (blue >> 10)); + if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { + outSISREG(SISDAC2A, regno); + outSISREG(SISDAC2D, (red >> 8)); + outSISREG(SISDAC2D, (green >> 8)); + outSISREG(SISDAC2D, (blue >> 8)); + } + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + ivideo->sis_fbcon_cmap.cfb16[regno] = + ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + red >>= 8; + green >>= 8; + blue >>= 8; + ivideo->sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue); + break; +#endif + } + + return 0; +} + +static void +sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + struct display *display; + struct display_switch *sw; + struct fb_fix_screeninfo fix; + long flags; + + display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp; + + sisfb_get_fix(&fix, con, info); + + display->var = *var; + display->screen_base = (char *)ivideo->video_vbase; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->can_soft_blank = 1; + display->inverse = ivideo->sisfb_inverse; + display->next_line = fix.line_length; + + save_flags(flags); + + switch(ivideo->video_bpp) { +#ifdef FBCON_HAS_CFB8 + case 8: sw = ivideo->accel ? &fbcon_sis8 : &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16:sw = ivideo->accel ? &fbcon_sis16 : &fbcon_cfb16; + display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32:sw = ivideo->accel ? &fbcon_sis32 : &fbcon_cfb32; + display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb32; + break; +#endif + default:sw = &fbcon_dummy; + break; + } + memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw)); + display->dispsw = &ivideo->sisfb_sw; + + restore_flags(flags); + + if(ivideo->sisfb_ypan) { + /* display->scrollmode = 0; */ + } else { + display->scrollmode = SCROLL_YREDRAW; + ivideo->sisfb_sw.bmove = fbcon_redraw_bmove; + } +} + +static void +sisfb_do_install_cmap(int con, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + + if(con != ivideo->currcon) return; + + if(fb_display[con].cmap.len) { + fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info); + } else { + int size = sisfb_get_cmap_len(&fb_display[con].var); + fb_set_cmap(fb_default_cmap(size), 1, sisfb_setcolreg, info); + } +} + +static int +sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + + if(con == -1) { + memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo)); + } else { + *var = fb_display[con].var; + } + + if(ivideo->sisfb_fstn) { + if(var->xres == 320 && var->yres == 480) var->yres = 240; + } + + return 0; +} + +static int +sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + int err; + + fb_display[con].var.activate = FB_ACTIVATE_NOW; + + if(sisfb_do_set_var(var, con == ivideo->currcon, info)) { + sisfb_crtc_to_var(ivideo, var); + return -EINVAL; + } + + sisfb_crtc_to_var(ivideo, var); + + sisfb_set_disp(con, var, info); + + if(info->changevar) { + (*info->changevar)(con); + } + + if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) { + return err; + } + + sisfb_do_install_cmap(con, info); + +#if 0 /* Why was this called here? */ + unsigned int cols, rows; + cols = sisbios_mode[ivideo->sisfb_mode_idx].cols; + rows = sisbios_mode[ivideo->sisfb_mode_idx].rows; + vc_resize_con(rows, cols, fb_display[con].conp->vc_num); +#endif + return 0; +} + +static int +sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + struct display *display; + + display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp; + + if(con == ivideo->currcon) { + + return fb_get_cmap(cmap, kspc, sis_getcolreg, info); + + } else if(display->cmap.len) { + + fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2); + + } else { + + int size = sisfb_get_cmap_len(&display->var); + fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); + + } + + return 0; +} + +static int +sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + struct display *display; + int err, size; + + display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp; + + size = sisfb_get_cmap_len(&display->var); + if(display->cmap.len != size) { + err = fb_alloc_cmap(&display->cmap, size, 0); + if(err) return err; + } + + if(con == ivideo->currcon) { + return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info); + } else { + fb_copy_cmap(cmap, &display->cmap, kspc ? 0 : 1); + } + + return 0; +} + +static int +sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + int err; + + if(var->vmode & FB_VMODE_YWRAP) return -EINVAL; + + if((var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual) || + (var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)) { + return -EINVAL; + } + + if(con == ivideo->currcon) { + if((err = sisfb_pan_var(ivideo, var)) < 0) return err; + } + + fb_display[con].var.xoffset = var->xoffset; + fb_display[con].var.yoffset = var->yoffset; + + return 0; +} + +static int +sisfb_update_var(int con, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + + return(sisfb_pan_var(ivideo, &fb_display[con].var)); +} + +static int +sisfb_switch(int con, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + int cols, rows; + + if(fb_display[ivideo->currcon].cmap.len) { + fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info); + } + + fb_display[con].var.activate = FB_ACTIVATE_NOW; + + if(!memcmp(&fb_display[con].var, &fb_display[ivideo->currcon].var, + sizeof(struct fb_var_screeninfo))) { + ivideo->currcon = con; + return 1; + } + + ivideo->currcon = con; + + sisfb_do_set_var(&fb_display[con].var, 1, info); + + sisfb_set_disp(con, &fb_display[con].var, info); + + sisfb_do_install_cmap(con, info); + + cols = sisbios_mode[ivideo->sisfb_mode_idx].cols; + rows = sisbios_mode[ivideo->sisfb_mode_idx].rows; + vc_resize_con(rows, cols, fb_display[con].conp->vc_num); + + sisfb_update_var(con, info); + + return 1; +} + +static void +sisfb_blank(int blank, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + + sisfb_myblank(ivideo, blank); +} +#endif + +/* ------------ FBDev related routines for 2.6 series ----------- */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + +static int +sisfb_open(struct fb_info *info, int user) +{ + return 0; +} + +static int +sisfb_release(struct fb_info *info, int user) +{ + return 0; +} + +static int +sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + + if(regno >= sisfb_get_cmap_len(&info->var)) return 1; + + switch(info->var.bits_per_pixel) { + case 8: + outSISREG(SISDACA, regno); + outSISREG(SISDACD, (red >> 10)); + outSISREG(SISDACD, (green >> 10)); + outSISREG(SISDACD, (blue >> 10)); + if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { + outSISREG(SISDAC2A, regno); + outSISREG(SISDAC2D, (red >> 8)); + outSISREG(SISDAC2D, (green >> 8)); + outSISREG(SISDAC2D, (blue >> 8)); + } + break; + case 16: + ((u32 *)(info->pseudo_palette))[regno] = + ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); + break; + case 32: + red >>= 8; + green >>= 8; + blue >>= 8; + ((u32 *)(info->pseudo_palette))[regno] = + (red << 16) | (green << 8) | (blue); + break; + } + return 0; +} + +static int +sisfb_set_par(struct fb_info *info) +{ + int err; + + if((err = sisfb_do_set_var(&info->var, 1, info))) { + return err; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) + sisfb_get_fix(&info->fix, info->currcon, info); +#else + sisfb_get_fix(&info->fix, -1, info); +#endif + return 0; +} + +static int +sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + unsigned int htotal = 0, vtotal = 0, myrateindex = 0; + unsigned int drate = 0, hrate = 0, maxyres; + int found_mode = 0; + int refresh_rate, search_idx; + BOOLEAN recalc_clock = FALSE; + u32 pixclock; + + htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len; + + vtotal = var->upper_margin + var->lower_margin + var->vsync_len; + + pixclock = var->pixclock; + + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + vtotal += var->yres; + vtotal <<= 1; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + vtotal += var->yres; + vtotal <<= 2; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + vtotal += var->yres; + vtotal <<= 1; + } else vtotal += var->yres; + + if(!(htotal) || !(vtotal)) { + SISFAIL("sisfb: no valid timing data"); + } + + search_idx = 0; + while( (sisbios_mode[search_idx].mode_no[0] != 0) && + (sisbios_mode[search_idx].xres <= var->xres) ) { + if( (sisbios_mode[search_idx].xres == var->xres) && + (sisbios_mode[search_idx].yres == var->yres) && + (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) { + if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) { + found_mode = 1; + break; + } + } + search_idx++; + } + + if(!found_mode) { + search_idx = 0; + while(sisbios_mode[search_idx].mode_no[0] != 0) { + if( (var->xres <= sisbios_mode[search_idx].xres) && + (var->yres <= sisbios_mode[search_idx].yres) && + (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) { + if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) { + found_mode = 1; + break; + } + } + search_idx++; + } + if(found_mode) { + printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n", + var->xres, var->yres, var->bits_per_pixel, + sisbios_mode[search_idx].xres, + sisbios_mode[search_idx].yres, + var->bits_per_pixel); + var->xres = sisbios_mode[search_idx].xres; + var->yres = sisbios_mode[search_idx].yres; + + + } else { + printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + } + + if( ((ivideo->vbflags & VB_LVDS) || /* Slave modes on LVDS and 301B-DH */ + ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) && + (var->bits_per_pixel == 8) ) { + refresh_rate = 60; + recalc_clock = TRUE; + } else if( (ivideo->current_htotal == htotal) && /* x=x & y=y & c=c -> assume depth change */ + (ivideo->current_vtotal == vtotal) && + (ivideo->current_pixclock == pixclock) ) { + drate = 1000000000 / pixclock; + hrate = (drate * 1000) / htotal; + refresh_rate = (unsigned int) (hrate * 2 / vtotal); + } else if( ( (ivideo->current_htotal != htotal) || /* x!=x | y!=y & c=c -> invalid pixclock */ + (ivideo->current_vtotal != vtotal) ) && + (ivideo->current_pixclock == var->pixclock) ) { + if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) { + refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]; + } else if(ivideo->sisfb_parm_rate != -1) { + /* Sic, sisfb_parm_rate - want to know originally desired rate here */ + refresh_rate = ivideo->sisfb_parm_rate; + } else { + refresh_rate = 60; + } + recalc_clock = TRUE; + } else if((pixclock) && (htotal) && (vtotal)) { + drate = 1000000000 / pixclock; + hrate = (drate * 1000) / htotal; + refresh_rate = (unsigned int) (hrate * 2 / vtotal); + } else if(ivideo->current_refresh_rate) { + refresh_rate = ivideo->current_refresh_rate; + recalc_clock = TRUE; + } else { + refresh_rate = 60; + recalc_clock = TRUE; + } + + myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx); + + /* Eventually recalculate timing and clock */ + if(recalc_clock) { + if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx; + var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, + &ivideo->sishw_ext, + sisbios_mode[search_idx].mode_no[ivideo->mni], + myrateindex)); + sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext, + sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex, var); + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + var->pixclock <<= 1; + } + } + + if(ivideo->sisfb_thismonitor.datavalid) { + if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx, + myrateindex, refresh_rate)) { + printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n"); + } + } + + /* Adapt RGB settings */ + sisfb_bpp_to_var(ivideo, var); + + /* Sanity check for offsets */ + if(var->xoffset < 0) var->xoffset = 0; + if(var->yoffset < 0) var->yoffset = 0; + + if(var->xres > var->xres_virtual) { + var->xres_virtual = var->xres; + } + + if(ivideo->sisfb_ypan) { + maxyres = sisfb_calc_maxyres(ivideo, var); + if(ivideo->sisfb_max) { + var->yres_virtual = maxyres; + } else { + if(var->yres_virtual > maxyres) { + var->yres_virtual = maxyres; + } + } + if(var->yres_virtual <= var->yres) { + var->yres_virtual = var->yres; + } + } else { + if(var->yres != var->yres_virtual) { + var->yres_virtual = var->yres; + } + var->xoffset = 0; + var->yoffset = 0; + } + + /* Truncate offsets to maximum if too high */ + if(var->xoffset > var->xres_virtual - var->xres) { + var->xoffset = var->xres_virtual - var->xres - 1; + } + + if(var->yoffset > var->yres_virtual - var->yres) { + var->yoffset = var->yres_virtual - var->yres - 1; + } + + /* Set everything else to 0 */ + var->red.msb_right = + var->green.msb_right = + var->blue.msb_right = + var->transp.offset = + var->transp.length = + var->transp.msb_right = 0; + + return 0; +} + +static int +sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + int err; + + if(var->xoffset > (var->xres_virtual - var->xres)) { + return -EINVAL; + } + if(var->yoffset > (var->yres_virtual - var->yres)) { + return -EINVAL; + } + + if(var->vmode & FB_VMODE_YWRAP) return -EINVAL; + + if(var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) { + return -EINVAL; + } + + if((err = sisfb_pan_var(ivideo, var)) < 0) return err; + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + return 0; +} + +static int +sisfb_blank(int blank, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + + return(sisfb_myblank(ivideo, blank)); +} + +#endif + +/* ----------- FBDev related routines for all series ---------- */ + +static int +sisfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + int con, +#endif + struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + struct sis_memreq sismemreq; + struct fb_vblank sisvbblank; + sisfb_info x; + u32 gpu32 = 0; +#ifndef __user +#define __user +#endif + u32 __user *argp = (u32 __user *)arg; + + switch (cmd) { + case FBIO_ALLOC: + if(!capable(CAP_SYS_RAWIO)) { + return -EPERM; + } + if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq))) { + return -EFAULT; + } + sis_malloc(&sismemreq); + if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) { + sis_free((u32)sismemreq.offset); + return -EFAULT; + } + break; + + case FBIO_FREE: + if(!capable(CAP_SYS_RAWIO)) { + return -EPERM; + } + if(get_user(gpu32, argp)) { + return -EFAULT; + } + sis_free(gpu32); + break; + + case FBIOGET_VBLANK: + sisvbblank.count = 0; + sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount); + if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank))) { + return -EFAULT; + } + break; + + case SISFB_GET_INFO_SIZE: + return put_user(sizeof(sisfb_info), argp); + + case SISFB_GET_INFO_OLD: + if(ivideo->warncount++ < 50) { + printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); + } + case SISFB_GET_INFO: /* For communication with X driver */ + x.sisfb_id = SISFB_ID; + x.sisfb_version = VER_MAJOR; + x.sisfb_revision = VER_MINOR; + x.sisfb_patchlevel = VER_LEVEL; + x.chip_id = ivideo->chip_id; + x.memory = ivideo->video_size / 1024; + x.heapstart = ivideo->heapstart / 1024; + if(ivideo->modechanged) { + x.fbvidmode = ivideo->mode_no; + } else { + x.fbvidmode = ivideo->modeprechange; + } + x.sisfb_caps = ivideo->caps; + x.sisfb_tqlen = 512; /* yet fixed */ + x.sisfb_pcibus = ivideo->pcibus; + x.sisfb_pcislot = ivideo->pcislot; + x.sisfb_pcifunc = ivideo->pcifunc; + x.sisfb_lcdpdc = ivideo->detectedpdc; + x.sisfb_lcdpdca = ivideo->detectedpdca; + x.sisfb_lcda = ivideo->detectedlcda; + x.sisfb_vbflags = ivideo->vbflags; + x.sisfb_currentvbflags = ivideo->currentvbflags; + x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler; + x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT; + x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0; + x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0; + x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30; + x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31; + x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32; + x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33; + x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32); + x.sisfb_tvypos = (u16)(ivideo->tvypos + 32); + + if(copy_to_user((void __user *)arg, &x, sizeof(x))) { + return -EFAULT; + } + break; + + case SISFB_GET_VBRSTATUS_OLD: + if(ivideo->warncount++ < 50) { + printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); + } + case SISFB_GET_VBRSTATUS: + if(sisfb_CheckVBRetrace(ivideo)) { + return put_user((u32)1, argp); + } else { + return put_user((u32)0, argp); + } + + case SISFB_GET_AUTOMAXIMIZE_OLD: + if(ivideo->warncount++ < 50) { + printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); + } + case SISFB_GET_AUTOMAXIMIZE: + if(ivideo->sisfb_max) return put_user((u32)1, argp); + else return put_user((u32)0, argp); + + case SISFB_SET_AUTOMAXIMIZE_OLD: + if(ivideo->warncount++ < 50) { + printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); + } + case SISFB_SET_AUTOMAXIMIZE: + if(copy_from_user(&gpu32, argp, sizeof(gpu32))) { + return -EFAULT; + } + ivideo->sisfb_max = (gpu32) ? 1 : 0; + break; + + case SISFB_SET_TVPOSOFFSET: + if(copy_from_user(&gpu32, argp, sizeof(gpu32))) { + return -EFAULT; + } + sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32); + sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32); + break; + + case SISFB_GET_TVPOSOFFSET: + return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)), + argp); + + case SISFB_SET_LOCK: + if(copy_from_user(&gpu32, argp, sizeof(gpu32))) { + return -EFAULT; + } + ivideo->sisfblocked = (gpu32) ? 1 : 0; + break; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +#ifdef CONFIG_COMPAT +static long sisfb_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg, struct fb_info *info) +{ + int ret; + lock_kernel(); + ret = sisfb_ioctl(NULL, f, cmd, arg, info); + unlock_kernel(); + return ret; +} +#endif + +static int +sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + + strcpy(fix->id, ivideo->myid); + + fix->smem_start = ivideo->video_base; + fix->smem_len = ivideo->sisfb_mem; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0; + fix->ywrapstep = 0; + fix->line_length = ivideo->video_linelength; + fix->mmio_start = ivideo->mmio_base; + fix->mmio_len = ivideo->mmio_size; + if(ivideo->sisvga_engine == SIS_300_VGA) { + fix->accel = FB_ACCEL_SIS_GLAMOUR; + } else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) { + fix->accel = FB_ACCEL_SIS_XABRE; + } else { + fix->accel = FB_ACCEL_SIS_GLAMOUR_2; + } + + return 0; +} + +/* ---------------- fb_ops structures ----------------- */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static struct fb_ops sisfb_ops = { + .owner = THIS_MODULE, + .fb_get_fix = sisfb_get_fix, + .fb_get_var = sisfb_get_var, + .fb_set_var = sisfb_set_var, + .fb_get_cmap = sisfb_get_cmap, + .fb_set_cmap = sisfb_set_cmap, + .fb_pan_display = sisfb_pan_display, + .fb_ioctl = sisfb_ioctl +}; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +static struct fb_ops sisfb_ops = { + .owner = THIS_MODULE, + .fb_open = sisfb_open, + .fb_release = sisfb_release, + .fb_check_var = sisfb_check_var, + .fb_set_par = sisfb_set_par, + .fb_setcolreg = sisfb_setcolreg, + .fb_pan_display = sisfb_pan_display, + .fb_blank = sisfb_blank, + .fb_fillrect = fbcon_sis_fillrect, + .fb_copyarea = fbcon_sis_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + .fb_sync = fbcon_sis_sync, + .fb_ioctl = sisfb_ioctl, +#ifdef CONFIG_COMPAT + .fb_compat_ioctl = sisfb_compat_ioctl, +#endif +}; +#endif + +/* ---------------- Chip generation dependent routines ---------------- */ + +static struct pci_dev * sisfb_get_northbridge(int basechipid) +{ + struct pci_dev *pdev = NULL; + int nbridgenum, nbridgeidx, i; + const unsigned short nbridgeids[] = { + PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */ + PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */ + PCI_DEVICE_ID_SI_730, + PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */ + PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */ + PCI_DEVICE_ID_SI_651, + PCI_DEVICE_ID_SI_740, + PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760 VGA */ + PCI_DEVICE_ID_SI_741, + PCI_DEVICE_ID_SI_660, + PCI_DEVICE_ID_SI_760 + }; + + switch(basechipid) { +#ifdef CONFIG_FB_SIS_300 + case SIS_540: nbridgeidx = 0; nbridgenum = 1; break; + case SIS_630: nbridgeidx = 1; nbridgenum = 2; break; +#endif +#ifdef CONFIG_FB_SIS_315 + case SIS_550: nbridgeidx = 3; nbridgenum = 1; break; + case SIS_650: nbridgeidx = 4; nbridgenum = 3; break; + case SIS_660: nbridgeidx = 7; nbridgenum = 4; break; +#endif + default: return NULL; + } + for(i = 0; i < nbridgenum; i++) { + if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break; + } + return pdev; +} + +static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo) +{ +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) + u8 reg; +#endif + + ivideo->video_size = 0; + + switch(ivideo->chip) { +#ifdef CONFIG_FB_SIS_300 + case SIS_300: + inSISIDXREG(SISSR, 0x14, reg); + ivideo->video_size = ((reg & 0x3F) + 1) << 20; + break; + case SIS_540: + case SIS_630: + case SIS_730: + if(!ivideo->nbridge) return -1; + pci_read_config_byte(ivideo->nbridge, 0x63, ®); + ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21); + break; +#endif +#ifdef CONFIG_FB_SIS_315 + case SIS_315H: + case SIS_315PRO: + case SIS_315: + inSISIDXREG(SISSR, 0x14, reg); + ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; + switch((reg >> 2) & 0x03) { + case 0x01: + case 0x03: + ivideo->video_size <<= 1; + break; + case 0x02: + ivideo->video_size += (ivideo->video_size/2); + } + break; + case SIS_330: + inSISIDXREG(SISSR, 0x14, reg); + ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; + if(reg & 0x0c) ivideo->video_size <<= 1; + break; + case SIS_550: + case SIS_650: + case SIS_740: + inSISIDXREG(SISSR, 0x14, reg); + ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20; + break; + case SIS_661: + case SIS_741: + inSISIDXREG(SISCR, 0x79, reg); + ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; + break; + case SIS_660: + case SIS_760: + inSISIDXREG(SISCR, 0x79, reg); + reg = (reg & 0xf0) >> 4; + if(reg) ivideo->video_size = (1 << reg) << 20; + inSISIDXREG(SISCR, 0x78, reg); + reg &= 0x30; + if(reg) { + if(reg == 0x10) ivideo->video_size += (32 << 20); + else ivideo->video_size += (64 << 20); + } + break; +#endif + default: + return -1; + } + return 0; +} + +/* -------------- video bridge device detection --------------- */ + +static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo) +{ + u8 cr32, temp; + +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + inSISIDXREG(SISSR, 0x17, temp); + if((temp & 0x0F) && (ivideo->chip != SIS_300)) { + /* PAL/NTSC is stored on SR16 on such machines */ + if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) { + inSISIDXREG(SISSR, 0x16, temp); + if(temp & 0x20) + ivideo->vbflags |= TV_PAL; + else + ivideo->vbflags |= TV_NTSC; + } + } + } +#endif + + inSISIDXREG(SISCR, 0x32, cr32); + + if(cr32 & SIS_CRT1) { + ivideo->sisfb_crt1off = 0; + } else { + ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0; + } + + ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA); + + if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV; + if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD; + if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA; + + /* Check given parms for hardware compatibility. + * (Cannot do this in the search_xx routines since we don't + * know what hardware we are running on then) + */ + + if(ivideo->chip != SIS_550) { + ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0; + } + + if(ivideo->sisfb_tvplug != -1) { + if( (ivideo->sisvga_engine != SIS_315_VGA) || + (!(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) ) { + if(ivideo->sisfb_tvplug & TV_YPBPR) { + ivideo->sisfb_tvplug = -1; + printk(KERN_ERR "sisfb: YPbPr not supported\n"); + } + } + } + if(ivideo->sisfb_tvplug != -1) { + if( (ivideo->sisvga_engine != SIS_315_VGA) || + (!(ivideo->vbflags & (VB_301|VB_301B|VB_302B))) ) { + if(ivideo->sisfb_tvplug & TV_HIVISION) { + ivideo->sisfb_tvplug = -1; + printk(KERN_ERR "sisfb: HiVision not supported\n"); + } + } + } + if(ivideo->sisfb_tvstd != -1) { + if( (!(ivideo->vbflags & VB_SISBRIDGE)) && + (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags & VB_CHRONTEL))) ) { + if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) { + ivideo->sisfb_tvstd = -1; + printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n"); + } + } + } + + /* Detect/set TV plug & type */ + if(ivideo->sisfb_tvplug != -1) { + ivideo->vbflags |= ivideo->sisfb_tvplug; + } else { + if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */ + else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION; + else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART; + else { + if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO; + if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO; + } + } + + if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) { + if(ivideo->sisfb_tvstd != -1) { + ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ); + ivideo->vbflags |= ivideo->sisfb_tvstd; + } + if(ivideo->vbflags & TV_SCART) { + ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ); + ivideo->vbflags |= TV_PAL; + } + if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) { + if(ivideo->sisvga_engine == SIS_300_VGA) { + inSISIDXREG(SISSR, 0x38, temp); + if(temp & 0x01) ivideo->vbflags |= TV_PAL; + else ivideo->vbflags |= TV_NTSC; + } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) { + inSISIDXREG(SISSR, 0x38, temp); + if(temp & 0x01) ivideo->vbflags |= TV_PAL; + else ivideo->vbflags |= TV_NTSC; + } else { + inSISIDXREG(SISCR, 0x79, temp); + if(temp & 0x20) ivideo->vbflags |= TV_PAL; + else ivideo->vbflags |= TV_NTSC; + } + } + } + + /* Copy forceCRT1 option to CRT1off if option is given */ + if(ivideo->sisfb_forcecrt1 != -1) { + ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1; + } +} + +static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo) +{ + char stdstr[] = "sisfb: Detected"; + char bridgestr[] = "video bridge"; + u8 vb_chipid; + u8 reg; + + inSISIDXREG(SISPART4, 0x00, vb_chipid); + switch(vb_chipid) { + case 0x01: + inSISIDXREG(SISPART4, 0x01, reg); + if(reg < 0xb0) { + ivideo->vbflags |= VB_301; + printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr); + } else if(reg < 0xc0) { + ivideo->vbflags |= VB_301B; + inSISIDXREG(SISPART4,0x23,reg); + if(!(reg & 0x02)) { + ivideo->vbflags |= VB_30xBDH; + printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr); + } else { + printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr); + } + } else if(reg < 0xd0) { + ivideo->vbflags |= VB_301C; + printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr); + } else if(reg < 0xe0) { + ivideo->vbflags |= VB_301LV; + printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr); + } else if(reg <= 0xe1) { + inSISIDXREG(SISPART4,0x39,reg); + if(reg == 0xff) { + ivideo->vbflags |= VB_302LV; + printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr); + } else { + ivideo->vbflags |= VB_301C; + printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr); +#if 0 + ivideo->vbflags |= VB_302ELV; + printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr); +#endif + } + } + break; + case 0x02: + ivideo->vbflags |= VB_302B; + printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr); + break; + } + + if((!(ivideo->vbflags & VB_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) { + inSISIDXREG(SISCR, 0x37, reg); + reg &= SIS_EXTERNAL_CHIP_MASK; + reg >>= 1; + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + switch(reg) { + case SIS_EXTERNAL_CHIP_LVDS: + ivideo->vbflags |= VB_LVDS; + break; + case SIS_EXTERNAL_CHIP_TRUMPION: + ivideo->vbflags |= VB_TRUMPION; + break; + case SIS_EXTERNAL_CHIP_CHRONTEL: + ivideo->vbflags |= VB_CHRONTEL; + break; + case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL: + ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); + break; + } + if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 1; +#endif + } else if(ivideo->chip < SIS_661) { +#ifdef CONFIG_FB_SIS_315 + switch (reg) { + case SIS310_EXTERNAL_CHIP_LVDS: + ivideo->vbflags |= VB_LVDS; + break; + case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL: + ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); + break; + } + if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2; +#endif + } else if(ivideo->chip >= SIS_661) { +#ifdef CONFIG_FB_SIS_315 + inSISIDXREG(SISCR, 0x38, reg); + reg >>= 5; + switch(reg) { + case 0x02: + ivideo->vbflags |= VB_LVDS; + break; + case 0x03: + ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); + break; + case 0x04: + ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); + break; + } + if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2; +#endif + } + if(ivideo->vbflags & VB_LVDS) { + printk(KERN_INFO "%s LVDS transmitter\n", stdstr); + } + if(ivideo->vbflags & VB_TRUMPION) { + printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr); + } + if(ivideo->vbflags & VB_CHRONTEL) { + printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr); + } + if(ivideo->vbflags & VB_CONEXANT) { + printk(KERN_INFO "%s Conexant external device\n", stdstr); + } + } + + if(ivideo->vbflags & VB_SISBRIDGE) { + SiS_Sense30x(ivideo); + } else if(ivideo->vbflags & VB_CHRONTEL) { + SiS_SenseCh(ivideo); + } +} + +/* ------------------ Sensing routines ------------------ */ + +static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo) +{ + unsigned short old; + int count = 48; + + old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr); + do { + if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break; + } while(count--); + return (count == -1) ? FALSE : TRUE; +} + +static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo) +{ + BOOLEAN mustwait = FALSE; + u8 sr1F, cr17; +#ifdef CONFIG_FB_SIS_315 + u8 cr63=0; +#endif + u16 temp = 0xffff; + int i; + + inSISIDXREG(SISSR,0x1F,sr1F); + orSISIDXREG(SISSR,0x1F,0x04); + andSISIDXREG(SISSR,0x1F,0x3F); + if(sr1F & 0xc0) mustwait = TRUE; + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63); + cr63 &= 0x40; + andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF); + } +#endif + + inSISIDXREG(SISCR,0x17,cr17); + cr17 &= 0x80; + if(!cr17) { + orSISIDXREG(SISCR,0x17,0x80); + mustwait = TRUE; + outSISIDXREG(SISSR, 0x00, 0x01); + outSISIDXREG(SISSR, 0x00, 0x03); + } + + if(mustwait) { + for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo); + } + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->chip >= SIS_330) { + andSISIDXREG(SISCR,0x32,~0x20); + if(ivideo->chip >= SIS_340) { + outSISIDXREG(SISCR, 0x57, 0x4a); + } else { + outSISIDXREG(SISCR, 0x57, 0x5f); + } + orSISIDXREG(SISCR, 0x53, 0x02); + while((inSISREG(SISINPSTAT)) & 0x01) break; + while(!((inSISREG(SISINPSTAT)) & 0x01)) break; + if((inSISREG(SISMISCW)) & 0x10) temp = 1; + andSISIDXREG(SISCR, 0x53, 0xfd); + andSISIDXREG(SISCR, 0x57, 0x00); + } +#endif + + if(temp == 0xffff) { + i = 3; + do { + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, 0, 0, NULL); + } while(((temp == 0) || (temp == 0xffff)) && i--); + + if((temp == 0) || (temp == 0xffff)) { + if(sisfb_test_DDC1(ivideo)) temp = 1; + } + } + + if((temp) && (temp != 0xffff)) { + orSISIDXREG(SISCR,0x32,0x20); + } + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63); + } +#endif + + setSISIDXREG(SISCR,0x17,0x7F,cr17); + + outSISIDXREG(SISSR,0x1F,sr1F); +} + +/* Determine and detect attached devices on SiS30x */ +static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test) +{ + int temp, mytest, result, i, j; + + for(j = 0; j < 10; j++) { + result = 0; + for(i = 0; i < 3; i++) { + mytest = test; + outSISIDXREG(SISPART4,0x11,(type & 0x00ff)); + temp = (type >> 8) | (mytest & 0x00ff); + setSISIDXREG(SISPART4,0x10,0xe0,temp); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500); + mytest >>= 8; + mytest &= 0x7f; + inSISIDXREG(SISPART4,0x03,temp); + temp ^= 0x0e; + temp &= mytest; + if(temp == mytest) result++; +#if 1 + outSISIDXREG(SISPART4,0x11,0x00); + andSISIDXREG(SISPART4,0x10,0xe0); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000); +#endif + } + if((result == 0) || (result >= 2)) break; + } + return(result); +} + +static void __devinit SiS_Sense30x(struct sis_video_info *ivideo) +{ + u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0; + u16 svhs=0, svhs_c=0; + u16 cvbs=0, cvbs_c=0; + u16 vga2=0, vga2_c=0; + int myflag, result; + char stdstr[] = "sisfb: Detected"; + char tvstr[] = "TV connected to"; + + if(ivideo->vbflags & VB_301) { + svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1; + inSISIDXREG(SISPART4,0x01,myflag); + if(myflag & 0x04) { + svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd; + } + } else if(ivideo->vbflags & (VB_301B | VB_302B)) { + svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190; + } else if(ivideo->vbflags & (VB_301LV | VB_302LV)) { + svhs = 0x0200; cvbs = 0x0100; + } else if(ivideo->vbflags & (VB_301C | VB_302ELV)) { + svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190; + } else return; + + vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804; + if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) { + svhs_c = 0x0408; cvbs_c = 0x0808; + } + biosflag = 2; + + if(ivideo->chip == SIS_300) { + inSISIDXREG(SISSR,0x3b,myflag); + if(!(myflag & 0x01)) vga2 = vga2_c = 0; + } + + inSISIDXREG(SISSR,0x1e,backupSR_1e); + orSISIDXREG(SISSR,0x1e,0x20); + + inSISIDXREG(SISPART4,0x0d,backupP4_0d); + if(ivideo->vbflags & VB_301C) { + setSISIDXREG(SISPART4,0x0d,~0x07,0x01); + } else { + orSISIDXREG(SISPART4,0x0d,0x04); + } + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000); + + inSISIDXREG(SISPART2,0x00,backupP2_00); + outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc)); + + inSISIDXREG(SISPART2,0x4d,backupP2_4d); + if(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV)) { + outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10)); + } + + if(!(ivideo->vbflags & VB_301C)) { + SISDoSense(ivideo, 0, 0); + } + + andSISIDXREG(SISCR, 0x32, ~0x14); + + if(vga2_c || vga2) { + if(SISDoSense(ivideo, vga2, vga2_c)) { + if(biosflag & 0x01) { + printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr); + orSISIDXREG(SISCR, 0x32, 0x04); + } else { + printk(KERN_INFO "%s secondary VGA connection\n", stdstr); + orSISIDXREG(SISCR, 0x32, 0x10); + } + } + } + + andSISIDXREG(SISCR, 0x32, 0x3f); + + if(ivideo->vbflags & VB_301C) { + orSISIDXREG(SISPART4,0x0d,0x04); + } + + if((ivideo->sisvga_engine == SIS_315_VGA) && + (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV))) { + outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10)); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000); + if((result = SISDoSense(ivideo, svhs, 0x0604))) { + if((result = SISDoSense(ivideo, cvbs, 0x0804))) { + printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr); + orSISIDXREG(SISCR,0x32,0x80); + } + } + outSISIDXREG(SISPART2,0x4d,backupP2_4d); + } + + andSISIDXREG(SISCR, 0x32, ~0x03); + + if(!(ivideo->vbflags & TV_YPBPR)) { + if((result = SISDoSense(ivideo, svhs, svhs_c))) { + printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr); + orSISIDXREG(SISCR, 0x32, 0x02); + } + if((biosflag & 0x02) || (!result)) { + if(SISDoSense(ivideo, cvbs, cvbs_c)) { + printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr); + orSISIDXREG(SISCR, 0x32, 0x01); + } + } + } + + SISDoSense(ivideo, 0, 0); + + outSISIDXREG(SISPART2,0x00,backupP2_00); + outSISIDXREG(SISPART4,0x0d,backupP4_0d); + outSISIDXREG(SISSR,0x1e,backupSR_1e); + + if(ivideo->vbflags & VB_301C) { + inSISIDXREG(SISPART2,0x00,biosflag); + if(biosflag & 0x20) { + for(myflag = 2; myflag > 0; myflag--) { + biosflag ^= 0x20; + outSISIDXREG(SISPART2,0x00,biosflag); + } + } + } + + outSISIDXREG(SISPART2,0x00,backupP2_00); +} + +/* Determine and detect attached TV's on Chrontel */ +static void __devinit SiS_SenseCh(struct sis_video_info *ivideo) +{ +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) + u8 temp1, temp2; + char stdstr[] = "sisfb: Chrontel: Detected TV connected to"; +#endif +#ifdef CONFIG_FB_SIS_300 + unsigned char test[3]; + int i; +#endif + + if(ivideo->chip < SIS_315H) { + +#ifdef CONFIG_FB_SIS_300 + ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */ + SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */ + SiS_DDC2Delay(&ivideo->SiS_Pr, 1000); + temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25); + /* See Chrontel TB31 for explanation */ + temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e); + if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) { + SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b0e); + SiS_DDC2Delay(&ivideo->SiS_Pr, 300); + } + temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25); + if(temp2 != temp1) temp1 = temp2; + + if((temp1 >= 0x22) && (temp1 <= 0x50)) { + /* Read power status */ + temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e); + if((temp1 & 0x03) != 0x03) { + /* Power all outputs */ + SiS_SetCH700x(&ivideo->SiS_Pr, 0x0B0E); + SiS_DDC2Delay(&ivideo->SiS_Pr, 300); + } + /* Sense connected TV devices */ + for(i = 0; i < 3; i++) { + SiS_SetCH700x(&ivideo->SiS_Pr, 0x0110); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); + SiS_SetCH700x(&ivideo->SiS_Pr, 0x0010); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); + temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10); + if(!(temp1 & 0x08)) test[i] = 0x02; + else if(!(temp1 & 0x02)) test[i] = 0x01; + else test[i] = 0; + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); + } + + if(test[0] == test[1]) temp1 = test[0]; + else if(test[0] == test[2]) temp1 = test[0]; + else if(test[1] == test[2]) temp1 = test[1]; + else { + printk(KERN_INFO + "sisfb: TV detection unreliable - test results varied\n"); + temp1 = test[2]; + } + if(temp1 == 0x02) { + printk(KERN_INFO "%s SVIDEO output\n", stdstr); + ivideo->vbflags |= TV_SVIDEO; + orSISIDXREG(SISCR, 0x32, 0x02); + andSISIDXREG(SISCR, 0x32, ~0x05); + } else if (temp1 == 0x01) { + printk(KERN_INFO "%s CVBS output\n", stdstr); + ivideo->vbflags |= TV_AVIDEO; + orSISIDXREG(SISCR, 0x32, 0x01); + andSISIDXREG(SISCR, 0x32, ~0x06); + } else { + SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8); + andSISIDXREG(SISCR, 0x32, ~0x07); + } + } else if(temp1 == 0) { + SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8); + andSISIDXREG(SISCR, 0x32, ~0x07); + } + /* Set general purpose IO for Chrontel communication */ + SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00); +#endif + + } else { + +#ifdef CONFIG_FB_SIS_315 + ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */ + temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49); + SiS_SetCH701x(&ivideo->SiS_Pr, 0x2049); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); + temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20); + temp2 |= 0x01; + SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); + temp2 ^= 0x01; + SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); + temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20); + SiS_SetCH701x(&ivideo->SiS_Pr, (temp1 << 8) | 0x49); + temp1 = 0; + if(temp2 & 0x02) temp1 |= 0x01; + if(temp2 & 0x10) temp1 |= 0x01; + if(temp2 & 0x04) temp1 |= 0x02; + if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04; + switch(temp1) { + case 0x01: + printk(KERN_INFO "%s CVBS output\n", stdstr); + ivideo->vbflags |= TV_AVIDEO; + orSISIDXREG(SISCR, 0x32, 0x01); + andSISIDXREG(SISCR, 0x32, ~0x06); + break; + case 0x02: + printk(KERN_INFO "%s SVIDEO output\n", stdstr); + ivideo->vbflags |= TV_SVIDEO; + orSISIDXREG(SISCR, 0x32, 0x02); + andSISIDXREG(SISCR, 0x32, ~0x05); + break; + case 0x04: + printk(KERN_INFO "%s SCART output\n", stdstr); + orSISIDXREG(SISCR, 0x32, 0x04); + andSISIDXREG(SISCR, 0x32, ~0x03); + break; + default: + andSISIDXREG(SISCR, 0x32, ~0x07); + } +#endif + } +} + +/* ------------------------ Heap routines -------------------------- */ + +static u32 __devinit +sisfb_getheapstart(struct sis_video_info *ivideo) +{ + u32 ret = ivideo->sisfb_parm_mem * 1024; + u32 max = ivideo->video_size - ivideo->hwcursor_size; + u32 def; + + /* Calculate heap start = end of memory for console + * + * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ + * C = console, D = heap, H = HWCursor, Q = cmd-queue + * + * Basically given by "mem" parameter + * + * maximum = videosize - cmd_queue - hwcursor + * (results in a heap of size 0) + * default = SiS 300: depends on videosize + * SiS 315/330: 32k below max + */ + + if(ivideo->sisvga_engine == SIS_300_VGA) { + max -= TURBO_QUEUE_AREA_SIZE; + if(ivideo->video_size > 0x1000000) { + def = 0xc00000; + } else if(ivideo->video_size > 0x800000) { + def = 0x800000; + } else { + def = 0x400000; + } + } else { + max -= COMMAND_QUEUE_AREA_SIZE; + def = max - 0x8000; + } + + if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) { + ret = def; + } + + return ret; +} + +static int __devinit +sisfb_heap_init(struct sis_video_info *ivideo) +{ + SIS_OH *poh; + + ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo); + + ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart; + ivideo->sisfb_heap_end = ivideo->video_vbase + ivideo->video_size; + + /* Initialize command queue (We use MMIO only) */ + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + u32 tempq = 0; + u8 temp = 0; + + ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE; + + outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD); + outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET); + + tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT); + MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq); + + temp = SIS_CMD_QUEUE_SIZE_512k; + temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR); + outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp); + + tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE); + MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq); + + ivideo->caps |= MMIO_CMD_QUEUE_CAP; + } +#endif + +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + unsigned long tqueue_pos; + u8 tq_state; + + ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE; + + tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024); + + inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state); + tq_state |= 0xf0; + tq_state &= 0xfc; + tq_state |= (u8)(tqueue_pos >> 8); + outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state); + + outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff)); + + ivideo->caps |= TURBO_QUEUE_CAP; + } +#endif + + /* Reserve memory for the HWCursor */ + ivideo->sisfb_heap_end -= ivideo->hwcursor_size; + ivideo->hwcursor_vbase = ivideo->sisfb_heap_end; + ivideo->caps |= HW_CURSOR_CAP; + + ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start; + + if(ivideo->cardnumber == 0) { + + printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n", + (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024)); + + sisfb_heap.vinfo = ivideo; + + sisfb_heap.poha_chain = NULL; + sisfb_heap.poh_freelist = NULL; + + poh = sisfb_poh_new_node(); + if(poh == NULL) return 1; + + poh->poh_next = &sisfb_heap.oh_free; + poh->poh_prev = &sisfb_heap.oh_free; + poh->size = ivideo->sisfb_heap_size; + poh->offset = ivideo->heapstart; + + sisfb_heap.oh_free.poh_next = poh; + sisfb_heap.oh_free.poh_prev = poh; + sisfb_heap.oh_free.size = 0; + sisfb_heap.max_freesize = poh->size; + + sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used; + sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used; + sisfb_heap.oh_used.size = SENTINEL; + + } else { + + printk(KERN_INFO "Skipped heap initialization for secondary cards\n"); + + } + + return 0; +} + +static SIS_OH * +sisfb_poh_new_node(void) +{ + int i; + unsigned long cOhs; + SIS_OHALLOC *poha; + SIS_OH *poh; + + if(sisfb_heap.poh_freelist == NULL) { + poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL); + if(!poha) return NULL; + + poha->poha_next = sisfb_heap.poha_chain; + sisfb_heap.poha_chain = poha; + + cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1; + + poh = &poha->aoh[0]; + for(i = cOhs - 1; i != 0; i--) { + poh->poh_next = poh + 1; + poh = poh + 1; + } + + poh->poh_next = NULL; + sisfb_heap.poh_freelist = &poha->aoh[0]; + } + + poh = sisfb_heap.poh_freelist; + sisfb_heap.poh_freelist = poh->poh_next; + + return (poh); +} + +static SIS_OH * +sisfb_poh_allocate(u32 size) +{ + SIS_OH *pohThis; + SIS_OH *pohRoot; + int bAllocated = 0; + + if(size > sisfb_heap.max_freesize) { + DPRINTK("sisfb: Can't allocate %dk video memory\n", + (unsigned int) size / 1024); + return (NULL); + } + + pohThis = sisfb_heap.oh_free.poh_next; + + while(pohThis != &sisfb_heap.oh_free) { + if (size <= pohThis->size) { + bAllocated = 1; + break; + } + pohThis = pohThis->poh_next; + } + + if(!bAllocated) { + DPRINTK("sisfb: Can't allocate %dk video memory\n", + (unsigned int) size / 1024); + return (NULL); + } + + if(size == pohThis->size) { + pohRoot = pohThis; + sisfb_delete_node(pohThis); + } else { + pohRoot = sisfb_poh_new_node(); + + if(pohRoot == NULL) { + return (NULL); + } + + pohRoot->offset = pohThis->offset; + pohRoot->size = size; + + pohThis->offset += size; + pohThis->size -= size; + } + + sisfb_heap.max_freesize -= size; + + pohThis = &sisfb_heap.oh_used; + sisfb_insert_node(pohThis, pohRoot); + + return (pohRoot); +} + +static void +sisfb_delete_node(SIS_OH *poh) +{ + SIS_OH *poh_prev; + SIS_OH *poh_next; + + poh_prev = poh->poh_prev; + poh_next = poh->poh_next; + + poh_prev->poh_next = poh_next; + poh_next->poh_prev = poh_prev; +} + +static void +sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh) +{ + SIS_OH *pohTemp; + + pohTemp = pohList->poh_next; + + pohList->poh_next = poh; + pohTemp->poh_prev = poh; + + poh->poh_prev = pohList; + poh->poh_next = pohTemp; +} + +static SIS_OH * +sisfb_poh_free(u32 base) +{ + SIS_OH *pohThis; + SIS_OH *poh_freed; + SIS_OH *poh_prev; + SIS_OH *poh_next; + u32 ulUpper; + u32 ulLower; + int foundNode = 0; + + poh_freed = sisfb_heap.oh_used.poh_next; + + while(poh_freed != &sisfb_heap.oh_used) { + if(poh_freed->offset == base) { + foundNode = 1; + break; + } + + poh_freed = poh_freed->poh_next; + } + + if(!foundNode) return(NULL); + + sisfb_heap.max_freesize += poh_freed->size; + + poh_prev = poh_next = NULL; + ulUpper = poh_freed->offset + poh_freed->size; + ulLower = poh_freed->offset; + + pohThis = sisfb_heap.oh_free.poh_next; + + while(pohThis != &sisfb_heap.oh_free) { + if(pohThis->offset == ulUpper) { + poh_next = pohThis; + } else if((pohThis->offset + pohThis->size) == ulLower) { + poh_prev = pohThis; + } + pohThis = pohThis->poh_next; + } + + sisfb_delete_node(poh_freed); + + if(poh_prev && poh_next) { + poh_prev->size += (poh_freed->size + poh_next->size); + sisfb_delete_node(poh_next); + sisfb_free_node(poh_freed); + sisfb_free_node(poh_next); + return(poh_prev); + } + + if(poh_prev) { + poh_prev->size += poh_freed->size; + sisfb_free_node(poh_freed); + return(poh_prev); + } + + if(poh_next) { + poh_next->size += poh_freed->size; + poh_next->offset = poh_freed->offset; + sisfb_free_node(poh_freed); + return(poh_next); + } + + sisfb_insert_node(&sisfb_heap.oh_free, poh_freed); + + return(poh_freed); +} + +static void +sisfb_free_node(SIS_OH *poh) +{ + if(poh == NULL) return; + + poh->poh_next = sisfb_heap.poh_freelist; + sisfb_heap.poh_freelist = poh; +} + +void +sis_malloc(struct sis_memreq *req) +{ + struct sis_video_info *ivideo = sisfb_heap.vinfo; + SIS_OH *poh = NULL; + + if((ivideo) && (!ivideo->havenoheap)) { + poh = sisfb_poh_allocate((u32)req->size); + } + + if(poh == NULL) { + req->offset = req->size = 0; + DPRINTK("sisfb: Video RAM allocation failed\n"); + } else { + req->offset = poh->offset; + req->size = poh->size; + DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n", + (poh->offset + ivideo->video_vbase)); + } +} + +/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */ + +void +sis_free(u32 base) +{ + struct sis_video_info *ivideo = sisfb_heap.vinfo; + SIS_OH *poh; + + if((!ivideo) || (ivideo->havenoheap)) return; + + poh = sisfb_poh_free((u32)base); + + if(poh == NULL) { + DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n", + (unsigned int) base); + } +} + +/* --------------------- SetMode routines ------------------------- */ + +static void +sisfb_pre_setmode(struct sis_video_info *ivideo) +{ + u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0; + int tvregnum = 0; + + ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2); + + inSISIDXREG(SISCR, 0x31, cr31); + cr31 &= ~0x60; + cr31 |= 0x04; + + cr33 = ivideo->rate_idx & 0x0F; + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + if(ivideo->chip >= SIS_661) { + inSISIDXREG(SISCR, 0x38, cr38); + cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */ + } else { + tvregnum = 0x38; + inSISIDXREG(SISCR, tvregnum, cr38); + cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */ + } + } +#endif +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + tvregnum = 0x35; + inSISIDXREG(SISCR, tvregnum, cr38); + } +#endif + + SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE); + SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE); + + switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { + + case CRT2_TV: + cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */ + if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) { +#ifdef CONFIG_FB_SIS_315 + if(ivideo->chip >= SIS_661) { + cr38 |= 0x04; + if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20; + else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40; + else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60; + cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE; + cr35 &= ~0x01; + ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL)); + } else if(ivideo->sisvga_engine == SIS_315_VGA) { + cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr38 |= 0x08; + if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10; + else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20; + else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30; + cr31 &= ~0x01; + ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL)); + } +#endif + } else if((ivideo->vbflags & TV_HIVISION) && (ivideo->vbflags & (VB_301|VB_301B|VB_302B))) { + if(ivideo->chip >= SIS_661) { + cr38 |= 0x04; + cr35 |= 0x60; + } else { + cr30 |= 0x80; + } + cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE; + cr31 |= 0x01; + cr35 |= 0x01; + ivideo->currentvbflags |= TV_HIVISION; + } else if(ivideo->vbflags & TV_SCART) { + cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr31 |= 0x01; + cr35 |= 0x01; + ivideo->currentvbflags |= TV_SCART; + } else { + if(ivideo->vbflags & TV_SVIDEO) { + cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE); + ivideo->currentvbflags |= TV_SVIDEO; + } + if(ivideo->vbflags & TV_AVIDEO) { + cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE); + ivideo->currentvbflags |= TV_AVIDEO; + } + } + cr31 |= SIS_DRIVER_MODE; + + if(ivideo->vbflags & (TV_AVIDEO|TV_SVIDEO)) { + if(ivideo->vbflags & TV_PAL) { + cr31 |= 0x01; cr35 |= 0x01; + ivideo->currentvbflags |= TV_PAL; + if(ivideo->vbflags & TV_PALM) { + cr38 |= 0x40; cr35 |= 0x04; + ivideo->currentvbflags |= TV_PALM; + } else if(ivideo->vbflags & TV_PALN) { + cr38 |= 0x80; cr35 |= 0x08; + ivideo->currentvbflags |= TV_PALN; + } + } else { + cr31 &= ~0x01; cr35 &= ~0x01; + ivideo->currentvbflags |= TV_NTSC; + if(ivideo->vbflags & TV_NTSCJ) { + cr38 |= 0x40; cr35 |= 0x02; + ivideo->currentvbflags |= TV_NTSCJ; + } + } + } + break; + + case CRT2_LCD: + cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr31 |= SIS_DRIVER_MODE; + SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn); + SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn); + break; + + case CRT2_VGA: + cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr31 |= SIS_DRIVER_MODE; + if(ivideo->sisfb_nocrt2rate) { + cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4); + } else { + cr33 |= ((ivideo->rate_idx & 0x0F) << 4); + } + break; + + default: /* disable CRT2 */ + cr30 = 0x00; + cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE); + } + + outSISIDXREG(SISCR, 0x30, cr30); + outSISIDXREG(SISCR, 0x33, cr33); + + if(ivideo->chip >= SIS_661) { +#ifdef CONFIG_FB_SIS_315 + cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */ + setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */ + cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */ + setSISIDXREG(SISCR, 0x38, 0xf8, cr38); +#endif + } else if(ivideo->chip != SIS_300) { + outSISIDXREG(SISCR, tvregnum, cr38); + } + outSISIDXREG(SISCR, 0x31, cr31); + + if(ivideo->accel) sisfb_syncaccel(ivideo); + + ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem; +} + +/* Fix SR11 for 661 and later */ +#ifdef CONFIG_FB_SIS_315 +static void +sisfb_fixup_SR11(struct sis_video_info *ivideo) +{ + u8 tmpreg; + + if(ivideo->chip >= SIS_661) { + inSISIDXREG(SISSR,0x11,tmpreg); + if(tmpreg & 0x20) { + inSISIDXREG(SISSR,0x3e,tmpreg); + tmpreg = (tmpreg + 1) & 0xff; + outSISIDXREG(SISSR,0x3e,tmpreg); + inSISIDXREG(SISSR,0x11,tmpreg); + } + if(tmpreg & 0xf0) { + andSISIDXREG(SISSR,0x11,0x0f); + } + } +} +#endif + +static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val) +{ + if(val > 32) val = 32; + if(val < -32) val = -32; + ivideo->tvxpos = val; + + if(ivideo->sisfblocked) return; + if(!ivideo->modechanged) return; + + if(ivideo->currentvbflags & CRT2_TV) { + + if(ivideo->vbflags & VB_CHRONTEL) { + + int x = ivideo->tvx; + + switch(ivideo->chronteltype) { + case 1: + x += val; + if(x < 0) x = 0; + outSISIDXREG(SISSR,0x05,0x86); + SiS_SetCH700x(&ivideo->SiS_Pr, (((x & 0xff) << 8) | 0x0a)); + SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD); + break; + case 2: + /* Not supported by hardware */ + break; + } + + } else if(ivideo->vbflags & VB_SISBRIDGE) { + + u8 p2_1f,p2_20,p2_2b,p2_42,p2_43; + unsigned short temp; + + p2_1f = ivideo->p2_1f; + p2_20 = ivideo->p2_20; + p2_2b = ivideo->p2_2b; + p2_42 = ivideo->p2_42; + p2_43 = ivideo->p2_43; + + temp = p2_1f | ((p2_20 & 0xf0) << 4); + temp += (val * 2); + p2_1f = temp & 0xff; + p2_20 = (temp & 0xf00) >> 4; + p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f; + temp = p2_43 | ((p2_42 & 0xf0) << 4); + temp += (val * 2); + p2_43 = temp & 0xff; + p2_42 = (temp & 0xf00) >> 4; + outSISIDXREG(SISPART2,0x1f,p2_1f); + setSISIDXREG(SISPART2,0x20,0x0F,p2_20); + setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b); + setSISIDXREG(SISPART2,0x42,0x0F,p2_42); + outSISIDXREG(SISPART2,0x43,p2_43); + } + } +} + +static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val) +{ + if(val > 32) val = 32; + if(val < -32) val = -32; + ivideo->tvypos = val; + + if(ivideo->sisfblocked) return; + if(!ivideo->modechanged) return; + + if(ivideo->currentvbflags & CRT2_TV) { + + if(ivideo->vbflags & VB_CHRONTEL) { + + int y = ivideo->tvy; + + switch(ivideo->chronteltype) { + case 1: + y -= val; + if(y < 0) y = 0; + outSISIDXREG(SISSR,0x05,0x86); + SiS_SetCH700x(&ivideo->SiS_Pr, (((y & 0xff) << 8) | 0x0b)); + SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, ((y & 0x0100) | 0x08),0xFE); + break; + case 2: + /* Not supported by hardware */ + break; + } + + } else if(ivideo->vbflags & VB_SISBRIDGE) { + + char p2_01, p2_02; + val /= 2; + p2_01 = ivideo->p2_01; + p2_02 = ivideo->p2_02; + + p2_01 += val; + p2_02 += val; + while((p2_01 <= 0) || (p2_02 <= 0)) { + p2_01 += 2; + p2_02 += 2; + } + outSISIDXREG(SISPART2,0x01,p2_01); + outSISIDXREG(SISPART2,0x02,p2_02); + } + } +} + +static void +sisfb_post_setmode(struct sis_video_info *ivideo) +{ + BOOLEAN crt1isoff = FALSE; + BOOLEAN doit = TRUE; +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) + u8 reg; +#endif +#ifdef CONFIG_FB_SIS_315 + u8 reg1; +#endif + + outSISIDXREG(SISSR,0x05,0x86); + +#ifdef CONFIG_FB_SIS_315 + sisfb_fixup_SR11(ivideo); +#endif + + /* Now we actually HAVE changed the display mode */ + ivideo->modechanged = 1; + + /* We can't switch off CRT1 if bridge is in slave mode */ + if(ivideo->vbflags & VB_VIDEOBRIDGE) { + if(sisfb_bridgeisslave(ivideo)) doit = FALSE; + } else ivideo->sisfb_crt1off = 0; + +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + if((ivideo->sisfb_crt1off) && (doit)) { + crt1isoff = TRUE; + reg = 0x00; + } else { + crt1isoff = FALSE; + reg = 0x80; + } + setSISIDXREG(SISCR, 0x17, 0x7f, reg); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + if((ivideo->sisfb_crt1off) && (doit)) { + crt1isoff = TRUE; + reg = 0x40; + reg1 = 0xc0; + } else { + crt1isoff = FALSE; + reg = 0x00; + reg1 = 0x00; + + } + setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg); + setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1); + } +#endif + + if(crt1isoff) { + ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1; + ivideo->currentvbflags |= VB_SINGLE_MODE; + } else { + ivideo->currentvbflags |= VB_DISPTYPE_CRT1; + if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) { + ivideo->currentvbflags |= VB_MIRROR_MODE; + } else { + ivideo->currentvbflags |= VB_SINGLE_MODE; + } + } + + andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04); + + if(ivideo->currentvbflags & CRT2_TV) { + if(ivideo->vbflags & VB_SISBRIDGE) { + inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f); + inSISIDXREG(SISPART2,0x20,ivideo->p2_20); + inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b); + inSISIDXREG(SISPART2,0x42,ivideo->p2_42); + inSISIDXREG(SISPART2,0x43,ivideo->p2_43); + inSISIDXREG(SISPART2,0x01,ivideo->p2_01); + inSISIDXREG(SISPART2,0x02,ivideo->p2_02); + } else if(ivideo->vbflags & VB_CHRONTEL) { + if(ivideo->chronteltype == 1) { + ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a); + ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8); + ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b); + ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8); + } + } + } + + if(ivideo->tvxpos) { + sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos); + } + if(ivideo->tvypos) { + sisfb_set_TVyposoffset(ivideo, ivideo->tvypos); + } + + if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) { /* Set filter for SiS301 */ + + unsigned char filter_tb = 0; + + switch (ivideo->video_width) { + case 320: + filter_tb = (ivideo->vbflags & TV_NTSC) ? 4 : 12; + break; + case 640: + filter_tb = (ivideo->vbflags & TV_NTSC) ? 5 : 13; + break; + case 720: + filter_tb = (ivideo->vbflags & TV_NTSC) ? 6 : 14; + break; + case 400: + case 800: + filter_tb = (ivideo->vbflags & TV_NTSC) ? 7 : 15; + break; + default: + ivideo->sisfb_filter = -1; + break; + } + + orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01); + + if(ivideo->vbflags & TV_NTSC) { + + andSISIDXREG(SISPART2, 0x3a, 0x1f); + + if (ivideo->vbflags & TV_SVIDEO) { + + andSISIDXREG(SISPART2, 0x30, 0xdf); + + } else if (ivideo->vbflags & TV_AVIDEO) { + + orSISIDXREG(SISPART2, 0x30, 0x20); + + switch (ivideo->video_width) { + case 640: + outSISIDXREG(SISPART2, 0x35, 0xEB); + outSISIDXREG(SISPART2, 0x36, 0x04); + outSISIDXREG(SISPART2, 0x37, 0x25); + outSISIDXREG(SISPART2, 0x38, 0x18); + break; + case 720: + outSISIDXREG(SISPART2, 0x35, 0xEE); + outSISIDXREG(SISPART2, 0x36, 0x0C); + outSISIDXREG(SISPART2, 0x37, 0x22); + outSISIDXREG(SISPART2, 0x38, 0x08); + break; + case 400: + case 800: + outSISIDXREG(SISPART2, 0x35, 0xEB); + outSISIDXREG(SISPART2, 0x36, 0x15); + outSISIDXREG(SISPART2, 0x37, 0x25); + outSISIDXREG(SISPART2, 0x38, 0xF6); + break; + } + } + + } else if(ivideo->vbflags & TV_PAL) { + + andSISIDXREG(SISPART2, 0x3A, 0x1F); + + if (ivideo->vbflags & TV_SVIDEO) { + + andSISIDXREG(SISPART2, 0x30, 0xDF); + + } else if (ivideo->vbflags & TV_AVIDEO) { + + orSISIDXREG(SISPART2, 0x30, 0x20); + + switch (ivideo->video_width) { + case 640: + outSISIDXREG(SISPART2, 0x35, 0xF1); + outSISIDXREG(SISPART2, 0x36, 0xF7); + outSISIDXREG(SISPART2, 0x37, 0x1F); + outSISIDXREG(SISPART2, 0x38, 0x32); + break; + case 720: + outSISIDXREG(SISPART2, 0x35, 0xF3); + outSISIDXREG(SISPART2, 0x36, 0x00); + outSISIDXREG(SISPART2, 0x37, 0x1D); + outSISIDXREG(SISPART2, 0x38, 0x20); + break; + case 400: + case 800: + outSISIDXREG(SISPART2, 0x35, 0xFC); + outSISIDXREG(SISPART2, 0x36, 0xFB); + outSISIDXREG(SISPART2, 0x37, 0x14); + outSISIDXREG(SISPART2, 0x38, 0x2A); + break; + } + } + } + + if((ivideo->sisfb_filter >= 0) && (ivideo->sisfb_filter <= 7)) { + outSISIDXREG(SISPART2,0x35,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][0])); + outSISIDXREG(SISPART2,0x36,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][1])); + outSISIDXREG(SISPART2,0x37,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][2])); + outSISIDXREG(SISPART2,0x38,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][3])); + } + + } +} + +#ifndef MODULE +SISINITSTATIC int __init sisfb_setup(char *options) +{ + char *this_opt; + + sisfb_setdefaultparms(); + + printk(KERN_DEBUG "sisfb: Options %s\n", options); + + if(!options || !(*options)) { + return 0; + } + + while((this_opt = strsep(&options, ",")) != NULL) { + + if(!(*this_opt)) continue; + + if(!strnicmp(this_opt, "off", 3)) { + sisfb_off = 1; + } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) { + /* Need to check crt2 type first for fstn/dstn */ + sisfb_search_crt2type(this_opt + 14); + } else if(!strnicmp(this_opt, "tvmode:",7)) { + sisfb_search_tvstd(this_opt + 7); + } else if(!strnicmp(this_opt, "tvstandard:",11)) { + sisfb_search_tvstd(this_opt + 7); + } else if(!strnicmp(this_opt, "mode:", 5)) { + sisfb_search_mode(this_opt + 5, FALSE); + } else if(!strnicmp(this_opt, "vesa:", 5)) { + sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + } else if(!strnicmp(this_opt, "inverse", 7)) { + sisfb_inverse = 1; + /* fb_invert_cmaps(); */ + } else if(!strnicmp(this_opt, "font:", 5)) { + if(strlen(this_opt + 5) < 40) { + strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1); + sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0'; + } +#endif + } else if(!strnicmp(this_opt, "rate:", 5)) { + sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0); + } else if(!strnicmp(this_opt, "filter:", 7)) { + sisfb_filter = (int)simple_strtoul(this_opt + 7, NULL, 0); + } else if(!strnicmp(this_opt, "forcecrt1:", 10)) { + sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0); + } else if(!strnicmp(this_opt, "mem:",4)) { + sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0); + } else if(!strnicmp(this_opt, "pdc:", 4)) { + sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0); + } else if(!strnicmp(this_opt, "pdc1:", 5)) { + sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0); + } else if(!strnicmp(this_opt, "noaccel", 7)) { + sisfb_accel = 0; + } else if(!strnicmp(this_opt, "accel", 5)) { + sisfb_accel = -1; + } else if(!strnicmp(this_opt, "noypan", 6)) { + sisfb_ypan = 0; + } else if(!strnicmp(this_opt, "ypan", 4)) { + sisfb_ypan = -1; + } else if(!strnicmp(this_opt, "nomax", 5)) { + sisfb_max = 0; + } else if(!strnicmp(this_opt, "max", 3)) { + sisfb_max = -1; + } else if(!strnicmp(this_opt, "userom:", 7)) { + sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0); + } else if(!strnicmp(this_opt, "useoem:", 7)) { + sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0); + } else if(!strnicmp(this_opt, "nocrt2rate", 10)) { + sisfb_nocrt2rate = 1; + } else if(!strnicmp(this_opt, "scalelcd:", 9)) { + unsigned long temp = 2; + temp = simple_strtoul(this_opt + 9, NULL, 0); + if((temp == 0) || (temp == 1)) { + sisfb_scalelcd = temp ^ 1; + } + } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) { + int temp = 0; + temp = (int)simple_strtol(this_opt + 13, NULL, 0); + if((temp >= -32) && (temp <= 32)) { + sisfb_tvxposoffset = temp; + } + } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) { + int temp = 0; + temp = (int)simple_strtol(this_opt + 13, NULL, 0); + if((temp >= -32) && (temp <= 32)) { + sisfb_tvyposoffset = temp; + } + } else if(!strnicmp(this_opt, "specialtiming:", 14)) { + sisfb_search_specialtiming(this_opt + 14); + } else if(!strnicmp(this_opt, "lvdshl:", 7)) { + int temp = 4; + temp = simple_strtoul(this_opt + 7, NULL, 0); + if((temp >= 0) && (temp <= 3)) { + sisfb_lvdshl = temp; + } + } else if(this_opt[0] >= '0' && this_opt[0] <= '9') { + sisfb_search_mode(this_opt, TRUE); +#if !defined(__i386__) && !defined(__x86_64__) + } else if(!strnicmp(this_opt, "resetcard", 9)) { + sisfb_resetcard = 1; + } else if(!strnicmp(this_opt, "videoram:", 9)) { + sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0); +#endif + } else { + printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt); + } + + } + + + + return 0; +} +#endif + +static UCHAR * __devinit sis_find_rom(struct pci_dev *pdev) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + USHORT pciid; + int romptr; + UCHAR *myrombase; + u32 temp; + SIS_IOTYPE1 *rom_base, *rom; + + if(!(myrombase = vmalloc(65536))) return NULL; + +#if defined(__i386__) || defined(__x86_64__) + + for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) { + + rom_base = ioremap(temp, 0x10000); + if(!rom_base) continue; + + if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) { + iounmap(rom_base); + continue; + } + + romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8)); + if(romptr > (0x10000 - 8)) { + iounmap(rom_base); + continue; + } + + rom = rom_base + romptr; + + if((readb(rom) != 'P') || (readb(rom + 1) != 'C') || + (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) { + iounmap(rom_base); + continue; + } + + pciid = readb(rom + 4) | (readb(rom + 5) << 8); + if(pciid != 0x1039) { + iounmap(rom_base); + continue; + } + + pciid = readb(rom + 6) | (readb(rom + 7) << 8); + if(pciid == ivideo->chip_id) { + memcpy_fromio(myrombase, rom_base, 65536); + iounmap(rom_base); + return myrombase; + } + + iounmap(rom_base); + } + +#else + + pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp); + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, + (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE); + + rom_base = ioremap(ivideo->video_base, 65536); + if(rom_base) { + if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) { + romptr = (u16)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8)); + if(romptr <= (0x10000 - 8)) { + rom = rom_base + romptr; + if((readb(rom) == 'P') && (readb(rom + 1) == 'C') && + (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) { + pciid = readb(rom + 4) | (readb(rom + 5) << 8); + if(pciid == 0x1039) { + pciid = readb(rom + 6) | (readb(rom + 7) << 8); + if(pciid == ivideo->chip_id) { + memcpy_fromio(myrombase, rom_base, 65536); + iounmap(rom_base); + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp); + return myrombase; + } + } + } + } + } + iounmap(rom_base); + } + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp); + +#endif + + vfree(myrombase); + return NULL; +} + +#ifdef CONFIG_FB_SIS_300 +static int __devinit +sisfb_chkbuswidth300(struct pci_dev *pdev, SIS_IOTYPE1 *FBAddress) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + int i, j; + USHORT temp; + UCHAR reg; + + andSISIDXREG(SISSR,0x15,0xFB); + orSISIDXREG(SISSR,0x15,0x04); + outSISIDXREG(SISSR,0x13,0x00); + outSISIDXREG(SISSR,0x14,0xBF); + + for(i=0; i<2; i++) { + temp = 0x1234; + for(j=0; j<4; j++) { + writew(temp, FBAddress); + if(readw(FBAddress) == temp) break; + orSISIDXREG(SISSR,0x3c,0x01); + inSISIDXREG(SISSR,0x05,reg); + inSISIDXREG(SISSR,0x05,reg); + andSISIDXREG(SISSR,0x3c,0xfe); + inSISIDXREG(SISSR,0x05,reg); + inSISIDXREG(SISSR,0x05,reg); + temp++; + } + } + + writel(0x01234567L, FBAddress); + writel(0x456789ABL, (FBAddress+4)); + writel(0x89ABCDEFL, (FBAddress+8)); + writel(0xCDEF0123L, (FBAddress+12)); + inSISIDXREG(SISSR,0x3b,reg); + if(reg & 0x01) { + if(readl((FBAddress+12)) == 0xCDEF0123L) return(4); /* Channel A 128bit */ + } + if(readl((FBAddress+4)) == 0x456789ABL) return(2); /* Channel B 64bit */ + return(1); /* 32bit */ +} + +static void __devinit +sisfb_setramsize300(struct pci_dev *pdev) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + SIS_IOTYPE1 *FBAddr = ivideo->video_vbase; + SIS_IOTYPE1 *Addr; + USHORT sr13, sr14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0; + int PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount; + int RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank; + int PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k; + const USHORT SiS_DRAMType[17][5] = { + {0x0C,0x0A,0x02,0x40,0x39}, + {0x0D,0x0A,0x01,0x40,0x48}, + {0x0C,0x09,0x02,0x20,0x35}, + {0x0D,0x09,0x01,0x20,0x44}, + {0x0C,0x08,0x02,0x10,0x31}, + {0x0D,0x08,0x01,0x10,0x40}, + {0x0C,0x0A,0x01,0x20,0x34}, + {0x0C,0x09,0x01,0x08,0x32}, + {0x0B,0x08,0x02,0x08,0x21}, + {0x0C,0x08,0x01,0x08,0x30}, + {0x0A,0x08,0x02,0x04,0x11}, + {0x0B,0x0A,0x01,0x10,0x28}, + {0x09,0x08,0x02,0x02,0x01}, + {0x0B,0x09,0x01,0x08,0x24}, + {0x0B,0x08,0x01,0x04,0x20}, + {0x0A,0x08,0x01,0x02,0x10}, + {0x09,0x08,0x01,0x01,0x00} + }; + + buswidth = sisfb_chkbuswidth300(pdev, FBAddr); + + MB2Bank = 16; + Done = 0; + for(i = 6; i >= 0; i--) { + if(Done) break; + PseudoRankCapacity = 1 << i; + for(j = 4; j >= 1; j--) { + if(Done) break; + PseudoTotalCapacity = PseudoRankCapacity * j; + PseudoAdrPinCount = 15 - j; + if(PseudoTotalCapacity <= 64) { + for(k = 0; k <= 16; k++) { + if(Done) break; + RankCapacity = buswidth * SiS_DRAMType[k][3]; + AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0]; + if(RankCapacity == PseudoRankCapacity) + if(AdrPinCount <= PseudoAdrPinCount) { + if(j == 3) { /* Rank No */ + BankNumHigh = RankCapacity * MB2Bank * 3 - 1; + BankNumMid = RankCapacity * MB2Bank * 1 - 1; + } else { + BankNumHigh = RankCapacity * MB2Bank * j - 1; + BankNumMid = RankCapacity * MB2Bank * j / 2 - 1; + } + PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4; + PhysicalAdrHigh = BankNumHigh; + PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity; + PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh; + /* Write data */ + andSISIDXREG(SISSR,0x15,0xFB); /* Test */ + orSISIDXREG(SISSR,0x15,0x04); /* Test */ + TotalCapacity = SiS_DRAMType[k][3] * buswidth; + sr13 = SiS_DRAMType[k][4]; + if(buswidth == 4) sr14 = (TotalCapacity - 1) | 0x80; + if(buswidth == 2) sr14 = (TotalCapacity - 1) | 0x40; + if(buswidth == 1) sr14 = (TotalCapacity - 1) | 0x00; + outSISIDXREG(SISSR,0x13,sr13); + outSISIDXREG(SISSR,0x14,sr14); + Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh; + /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */ + writew(((USHORT)PhysicalAdrHigh), Addr); + Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh; + /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */ + writew(((USHORT)BankNumMid), Addr); + Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage; + /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */ + writew(((USHORT)PhysicalAdrHalfPage), Addr); + Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage; + /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */ + writew(((USHORT)PhysicalAdrOtherPage), Addr); + /* Read data */ + Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh; + data = readw(Addr); /* *((USHORT *)(Addr)); */ + if(data == PhysicalAdrHigh) Done = 1; + } /* if */ + } /* for k */ + } /* if */ + } /* for j */ + } /* for i */ +} + +static void __devinit sisfb_post_sis300(struct pci_dev *pdev) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + u8 reg, v1, v2, v3, v4, v5, v6, v7, v8; + u16 index, rindex, memtype = 0; + + outSISIDXREG(SISSR,0x05,0x86); + + if(ivideo->sishw_ext.UseROM) { + if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80) { + memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52]; + } else { + inSISIDXREG(SISSR,0x3a,memtype); + } + memtype &= 0x07; + } + + if(ivideo->revision_id <= 0x13) { + v1 = 0x44; v2 = 0x42; v3 = 0x80; + v4 = 0x44; v5 = 0x42; v6 = 0x80; + } else { + v1 = 0x68; v2 = 0x43; v3 = 0x80; /* Assume 125Mhz MCLK */ + v4 = 0x68; v5 = 0x43; v6 = 0x80; /* Assume 125Mhz ECLK */ + if(ivideo->sishw_ext.UseROM) { + index = memtype * 5; + rindex = index + 0x54; + v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; + v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; + rindex = index + 0x7c; + v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; + v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; + v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; + } + } + outSISIDXREG(SISSR,0x28,v1); + outSISIDXREG(SISSR,0x29,v2); + outSISIDXREG(SISSR,0x2a,v3); + outSISIDXREG(SISSR,0x2e,v4); + outSISIDXREG(SISSR,0x2f,v5); + outSISIDXREG(SISSR,0x30,v6); + v1 = 0x10; + if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0xa4]; + outSISIDXREG(SISSR,0x07,v1); /* DAC speed */ + outSISIDXREG(SISSR,0x11,0x0f); /* DDC, power save */ + v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a; + v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00; + if(ivideo->sishw_ext.UseROM) { + memtype += 0xa5; + v1 = ivideo->sishw_ext.pjVirtualRomBase[memtype]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 8]; + v3 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 16]; + v4 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 24]; + v5 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 32]; + v6 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 40]; + v7 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 48]; + v8 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 56]; + } + if(ivideo->revision_id >= 0x80) v3 &= 0xfd; + outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */ + outSISIDXREG(SISSR,0x16,v2); + outSISIDXREG(SISSR,0x17,v3); + outSISIDXREG(SISSR,0x18,v4); + outSISIDXREG(SISSR,0x19,v5); + outSISIDXREG(SISSR,0x1a,v6); + outSISIDXREG(SISSR,0x1b,v7); + outSISIDXREG(SISSR,0x1c,v8); /* ---- */ + andSISIDXREG(SISSR,0x15,0xfb); + orSISIDXREG(SISSR,0x15,0x04); + if(ivideo->sishw_ext.UseROM) { + if(ivideo->sishw_ext.pjVirtualRomBase[0x53] & 0x02) { + orSISIDXREG(SISSR,0x19,0x20); + } + } + v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */ + if(ivideo->revision_id >= 0x80) v1 |= 0x01; + outSISIDXREG(SISSR,0x1f,v1); + outSISIDXREG(SISSR,0x20,0xa0); /* linear & relocated io */ + v1 = 0xf6; v2 = 0x0d; v3 = 0x00; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe8]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe9]; + v3 = ivideo->sishw_ext.pjVirtualRomBase[0xea]; + } + outSISIDXREG(SISSR,0x23,v1); + outSISIDXREG(SISSR,0x24,v2); + outSISIDXREG(SISSR,0x25,v3); + outSISIDXREG(SISSR,0x21,0x84); + outSISIDXREG(SISSR,0x22,0x00); + outSISIDXREG(SISCR,0x37,0x00); + orSISIDXREG(SISPART1,0x24,0x01); /* unlock crt2 */ + outSISIDXREG(SISPART1,0x00,0x00); + v1 = 0x40; v2 = 0x11; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0xec]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[0xeb]; + } + outSISIDXREG(SISPART1,0x02,v1); + if(ivideo->revision_id >= 0x80) v2 &= ~0x01; + inSISIDXREG(SISPART4,0x00,reg); + if((reg == 1) || (reg == 2)) { + outSISIDXREG(SISCR,0x37,0x02); + outSISIDXREG(SISPART2,0x00,0x1c); + v4 = 0x00; v5 = 0x00; v6 = 0x10; + if(ivideo->sishw_ext.UseROM) { + v4 = ivideo->sishw_ext.pjVirtualRomBase[0xf5]; + v5 = ivideo->sishw_ext.pjVirtualRomBase[0xf6]; + v6 = ivideo->sishw_ext.pjVirtualRomBase[0xf7]; + } + outSISIDXREG(SISPART4,0x0d,v4); + outSISIDXREG(SISPART4,0x0e,v5); + outSISIDXREG(SISPART4,0x10,v6); + outSISIDXREG(SISPART4,0x0f,0x3f); + inSISIDXREG(SISPART4,0x01,reg); + if(reg >= 0xb0) { + inSISIDXREG(SISPART4,0x23,reg); + reg &= 0x20; + reg <<= 1; + outSISIDXREG(SISPART4,0x23,reg); + } + } else { + v2 &= ~0x10; + } + outSISIDXREG(SISSR,0x32,v2); + andSISIDXREG(SISPART1,0x24,0xfe); /* Lock CRT2 */ + inSISIDXREG(SISSR,0x16,reg); + reg &= 0xc3; + outSISIDXREG(SISCR,0x35,reg); + outSISIDXREG(SISCR,0x83,0x00); +#if !defined(__i386__) && !defined(__x86_64__) + if(sisfb_videoram) { + outSISIDXREG(SISSR,0x13,0x28); /* ? */ + reg = ((sisfb_videoram >> 10) - 1) | 0x40; + outSISIDXREG(SISSR,0x14,reg); + } else { +#endif + /* Need to map max FB size for finding out about RAM size */ + ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000); + if(ivideo->video_vbase) { + sisfb_setramsize300(pdev); + iounmap(ivideo->video_vbase); + } else { + printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n"); + outSISIDXREG(SISSR,0x13,0x28); /* ? */ + outSISIDXREG(SISSR,0x14,0x47); /* 8MB, 64bit default */ + } +#if !defined(__i386__) && !defined(__x86_64__) + } +#endif + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe6]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe7]; + } else { + inSISIDXREG(SISSR,0x3a,reg); + if((reg & 0x30) == 0x30) { + v1 = 0x04; /* PCI */ + v2 = 0x92; + } else { + v1 = 0x14; /* AGP */ + v2 = 0xb2; + } + } + outSISIDXREG(SISSR,0x21,v1); + outSISIDXREG(SISSR,0x22,v2); +} +#endif + +#ifdef CONFIG_FB_SIS_315 +static void __devinit sisfb_post_sis315330(struct pci_dev *pdev) +{ +#ifdef YET_TO_BE_DONE + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + u8 reg, v1, v2, v3, v4, v5, v6, v7, v8; + u16 index, rindex, memtype = 0; + u32 reg1_32, reg2_32, reg3_32; + int i; + + /* Unlock */ + /* outSISIDXREG(0x3c4,0x05,0x86); */ + outSISIDXREG(SISSR,0x05,0x86); + + /* Enable relocated i/o ports */ + /* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */ + setSISIDXREG(SISSR,0x20,~0x10,0x20); + + /* Clear regs */ + for(i = 0; i < 0x22; i++) { + outSISIDXREG(SISSR,(0x06 + i),0x00); + } + v1 = 0x0d; + if( is 330) v1 = 0x0b; + for(i = 0; i < v1; i++) { + outSISIDXREG(SISSR,(0x31 + i),0x00); + } + for(i = 0; i < 0x10; i++) { + outSISIDXREG(SISCR,(0x30 + i),0x00); + } + + /* Reset clocks */ + reg = inSISREG(SISMISCR); + outSISIDXREG(SISSR,0x28,0x81); + outSISIDXREG(SISSR,0x2A,0x00); + outSISIDXREG(SISSR,0x29,0xE1); + outSISREG(SISMISCW,(reg | 0x0c)); + outSISIDXREG(SISSR,0x2B,0x81); + outSISIDXREG(SISSR,0x2D,0x00); + outSISIDXREG(SISSR,0x2C,0xE1); + outSISIDXREG(SISSR,0x2E,0x81); + outSISIDXREG(SISSR,0x30,0x00); + outSISIDXREG(SISSR,0x2F,0xE1); + SiS_DDC2Delay(....); + outSISREG(SISMISCW,reg); + + /* Get memory type */ + if(ivideo->sishw_ext.UseROM) { + if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80)) { + memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52]; + } else { + inSISIDXREG(SISSR,0x3a,memtype); + } + memtype &= 0x03; + if( is 330 ) { + if(memtype <= 1) memtype = 0; + else { + inSISIDXREG(SISCR,0x5F,reg); + reg &= 0x30; + switch(reg) { + case 0x00: memtype = 1; break; + case 0x10: memtype = 3; break; + case 0x20: memtype = 3; break; + default: memtype = 2; + } + } + } + } + + /* Set clocks */ + v1 = 0x3b; v2 = 0x22; v3 = 0x01; /* Assume 143Mhz MCLK */ + v4 = 0x5c; v5 = 0x23; v6 = 0x01; /* Assume 166Mhz ECLK */ + if(ivideo->sishw_ext.UseROM) { + index = memtype * 5; + rindex = index + 0x54; + v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; + v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; + rindex = index + 0x68; + v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; + v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; + v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; + } + outSISIDXREG(SISSR,0x28,v1); + outSISIDXREG(SISSR,0x29,v2); + outSISIDXREG(SISSR,0x2a,v3); + if( is 330 ) { + inSISIDXREG(SISSR,0x3a,reg); + reg &= 0x03; + if(reg >= 2) { + ... + } + } + outSISIDXREG(SISSR,0x2e,v4); + outSISIDXREG(SISSR,0x2f,v5); + outSISIDXREG(SISSR,0x30,v6); + + /* End of comp with 330 */ + + v1 = 0x18; + if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0x7c]; + outSISIDXREG(SISSR,0x07,v1); + outSISIDXREG(SISSR,0x11,0x0f); + + v1 = 0x00; v2 = 0x0f; v3 = 0xba; v4 = 0xa9; + v5 = 0xa0; v6 = 0x00; v7 = 0x30; + if(ivideo->sishw_ext.UseROM) { + index = memtype + 0x7d; + v1 = ivideo->sishw_ext.pjVirtualRomBase[index]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4]; + v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8]; + v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12]; + v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16]; + v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20]; + v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24]; + } + outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0x7d step 4) */ + outSISIDXREG(SISSR,0x16,v2); + outSISIDXREG(SISSR,0x17,v3); + outSISIDXREG(SISSR,0x18,v4); + outSISIDXREG(SISSR,0x19,v5); + outSISIDXREG(SISSR,0x1a,v6); + outSISIDXREG(SISSR,0x1b,v7); + outSISIDXREG(SISSR,0x1c,v8); /* ---- */ + + v1 = 0x77; v2 = 0x77; v3 = 0x00; v4 = 0x5b; v5 = 0x00; + if(ivideo->sishw_ext.UseROM) { + index = memtype + 0xa2; + v1 = ivideo->sishw_ext.pjVirtualRomBase[index]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4]; + v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8]; + v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12]; + v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16]; + } + outSISIDXREG(SISCR,0x40,v1); + outSISIDXREG(SISCR,0x41,v2); + outSISIDXREG(SISCR,0x42,v3); + outSISIDXREG(SISCR,0x43,v4); + outSISIDXREG(SISCR,0x44,v5); + + if( is 330 ) { + + v1 = 0x; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA]; + } + outSISIDXREG(SISCR,0x59,v1); + + v1 = 0x; v2 = 0x; v3 = 0x; v4 = 0x; + v5 = 0x; v6 = 0x; v7 = 0x; v8 = 0x; + if(ivideo->sishw_ext.UseROM) { + index = memtype + 0xbe; + v1 = ivideo->sishw_ext.pjVirtualRomBase[index]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4]; + v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8]; + v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12]; + v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16]; + v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20]; + v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24]; + v8 = ivideo->sishw_ext.pjVirtualRomBase[index + 28]; + } + outSISIDXREG(SISCR,0x68,v1); + outSISIDXREG(SISCR,0x69,v2); + outSISIDXREG(SISCR,0x6a,v3); + outSISIDXREG(SISCR,0x6b,v4); + outSISIDXREG(SISCR,0x6c,v5); + outSISIDXREG(SISCR,0x6d,v6); + outSISIDXREG(SISCR,0x6e,v7); + outSISIDXREG(SISCR,0x6f,v8); + + v1 = 0x20; + inSISIDXREG(SISSR,0x3b,reg); + + if(!(reg & 0x04)) { + inSISIDXREG(SISCR,0x5F,reg); + reg &= 0x30; + if(reg) v1 = 0x23; + } + outSISIDXREG(SISCR,0x48,v1); + outSISIDXREG(SISCR,0x4c,0x20); + + xx= xxx(); + if(xx >= 1) { + v1 = 0x; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA]; + } + outSISIDXREG(SISCR,0x59,v1); + } + + + + } else { + + outSISIDXREG(SISCR,0x48,0x23); + + andSISIDXREG(SISSR,0x16,0x0f); + if(memtype <= 1) { + orSISIDXREG(SISSR,0x16,0x80); + } else { + v1 = 0x0f; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0x81 + memtype]; + } + if(!(v1 & 0x10)) v2 = 0xc0; + else v2 = 0xd0; + orSISIDXREG(SISSR,0x16,v2); + andSISIDXREG(SISSR,0x16,0x0f); + if(!(v1 & 0x10)) v2 = 0x80; + else v2 = 0xA0; + orSISIDXREG(SISSR,0x16,v2); + } + + if(memtype >= 2) { + const u8 sr3cseq1[] = { 0xc0,0xe0,0xf0,0xe0,0xf0,0xa0,0xb0,0xa0,0xb0,0x90,0xd0 }; + const u8 sr3cseq2[] = { 0xc0,0xa0,0xb0,0xa0,0xb0,0xe0,0xf0,0xa0,0xb0,0x90,0xd0 }; + for(i = 0; i < 11; i++) { + outSISIDXREG(SISSR,0x3c,sr3cseq1[i]); + } + outSISIDXREG(SISSR,0x3d,0x00); + outSISIDXREG(SISSR,0x3d,0x04); + SiS_DDC2Delay(0x200); + v1 = inSISIDXREG(SISCR,0xEC); + v2 = inSISIDXREG(SISCR,0xED); + reg1_32 = (v2 << 8) | v1; + outSISIDXREG(SISSR,0x3D,0x00); + for(i = 0; i < 11; i++) { + outSISIDXREG(SISSR,0x3c,sr3cseq2[i]); + } + outSISIDXREG(SISSR,0x3d,0x00); + outSISIDXREG(SISSR,0x3d,0x04); + SiS_DDC2Delay(0x200); + v1 = inSISIDXREG(SISCR,0xEC); + v2 = inSISIDXREG(SISCR,0xED); + reg2_32 = (v2 << 8) | v1; + outSISIDXREG(SISSR,0x3D,0x00); + reg3_32 = reg2_32 << 1; + reg2_32 >>= 1; + reg3_32 += reg2_32; + v1 = 0x40; + if(reg3_32 > reg1_32) v1 = 0x10; + outSISIDXREG(SISCR,0x59,v1); + } + + } + + v1 = 0x00; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0x99]; + } + outSISIDXREG(SISSR,0x1f,v1); + + outSISIDXREG(SISSR,0x20,0x20); + + v1 = 0xf6; v2 = 0x0d; v3 = 0x33; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9c]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9d]; + v3 = ivideo->sishw_ext.pjVirtualRomBase[0x9e]; + } + outSISIDXREG(SISSR,0x23,v1); + outSISIDXREG(SISSR,0x24,v2); + outSISIDXREG(SISSR,0x25,v3); + + outSISIDXREG(SISSR,0x21,0x84); + outSISIDXREG(SISSR,0x22,0x00); + outSISIDXREG(SISSR,0x27,0x1f); + + v1 = 0x00; v2 = 0x00; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9F]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[0xA1]; + } + outSISIDXREG(SISSR,0x31,v1); + outSISIDXREG(SISSR,0x33,v2); + + v1 = 0x11; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0xA0]; + } + v2 = inSISIDXREG(SISPART4,0x00); + if((v2 != 1) && (v2 != 2)) v1 &= 0xef; + outSISIDXREG(SISSR,0x32,v1); + + /* AGP */ + pci_read_config_long(pdev, 0x50, ®1_32); + reg1_32 >>= 20; + reg1_32 &= 0x0f; + if(reg1_32 == 1) { + v1 = 0xAA; v2 = 0x33; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF7]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9E]; + } + } else { + v1 = 0x88; v2 = 0x03; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF8]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[0xF6]; + } + } + outSISIDXREG(SISCR,0x49,v1); + outSISIDXREG(SISSR,0x25,v2); + + v1 = inSISIDXREG(SISPART4,0x00); + if((v1 == 1) || (v1 == 2)) { + orSISIDXREG(SISPART1,0x2F,0x01); /* Unlock CRT2 */ + outSISIDXREG(SISPART1,0x00,0x00); + v1 = 0x00; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb6]; + } + outSISIDXREG(SISPART1,0x02,v1); + outSISIDXREG(SISPART1,0x2E,0x08); + outSISIDXREG(SISPART2,0x00,0x1c); + v1 = 0x40; v2 = 0x00; v3 = 0x80; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb7]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[0xb8]; + v3 = ivideo->sishw_ext.pjVirtualRomBase[0xbb]; + } + outSISIDXREG(SISPART4,0x0d,v1); + outSISIDXREG(SISPART4,0x0e,v2); + outSISIDXREG(SISPART4,0x10,v3); + outSISIDXREG(SISPART4,0x0F,0x3F); + + inSISIDXREG(SISPART4,0x01,reg); + if(reg >= 0xb0) { + inSISIDXREG(SISPART4,0x23,reg); + reg &= 0x20; + reg <<= 1; + outSISIDXREG(SISPART4,0x23,reg); + } + } + outSISIDXREG(SISCR,0x37,0x02); /* Why? */ + + outSISIDXREG(SISCR,0x83,0x00); + outSISIDXREG(SISCR,0x90,0x00); + andSISIDXREG(SISSR,0x5B,0xDF); + outSISIDXREG(SISVID,0x00,0x86); + outSISIDXREG(SISVID,0x32,0x00); + outSISIDXREG(SISVID,0x30,0x00); + outSISIDXREG(SISVID,0x32,0x01); + outSISIDXREG(SISVID,0x30,0x00); + orSISIDXREG(SISCR,0x63,0x80); + /* End of Init1 */ + + /* Set Mode 0x2e */ + + /* Ramsize */ + orSISIDXREG(SISSR,0x16,0x0f); + orSISIDXREG(SISSR,0x18,0xA9); + orSISIDXREG(SISSR,0x19,0xA0); + orSISIDXREG(SISSR,0x1B,0x30); + andSISIDXREG(SISSR,0x17,0xF8); + orSISIDXREG(SISSR,0x19,0x03); + andSIDIDXREG(SISSR,0x13,0x00); + + /* Need to map max FB size for finding out about RAM size */ + ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000); + if(ivideo->video_vbase) { + /* Find out about bus width */ + if(memtype <= 1) { + outSISIDXREG(SISSR,0x14,0x02); + andSISIDXREG(SISSR,0x16,0x0F); + orSISIDXREG(SISSR,0x16,0x80); + + ... + + } else { + + ... + + } + + /* Find out about size */ + + + iounmap(ivideo->video_vbase); + } else { + printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n"); + outSISIDXREG(SISSR,0x14,0x??); /* 8MB, 64bit default */ + } + + /* AGP (Missing: Checks for VIA and AMD hosts) */ + v1 = 0xA5; v2 = 0xFB; + if(ivideo->sishw_ext.UseROM) { + v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9A]; + v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9B]; + } + outSISIDXREG(SISSR,0x21,v1); + outSISIDXREG(SISSR,0x22,v2); + +#endif + return; +} +#endif + + +int __devinit sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data]; + struct sis_video_info *ivideo = NULL; + struct fb_info *sis_fb_info = NULL; + u16 reg16; + u8 reg; + int sisvga_enabled = 0, i; + + if(sisfb_off) return -ENXIO; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3)) + sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev); + if(!sis_fb_info) return -ENOMEM; +#else + sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL); + if(!sis_fb_info) return -ENOMEM; + memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo)); + sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info)); +#endif + + ivideo = (struct sis_video_info *)sis_fb_info->par; + ivideo->memyselfandi = sis_fb_info; + + if(card_list == NULL) { + ivideo->cardnumber = 0; + } else { + struct sis_video_info *countvideo = card_list; + ivideo->cardnumber = 1; + while((countvideo = countvideo->next) != NULL) ivideo->cardnumber++; + } + + strncpy(ivideo->myid, chipinfo->chip_name, 30); + + ivideo->warncount = 0; + ivideo->chip_id = pdev->device; + pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id); + ivideo->sishw_ext.jChipRevision = ivideo->revision_id; + pci_read_config_word(pdev, PCI_COMMAND, ®16); + sisvga_enabled = reg16 & 0x01; + ivideo->pcibus = pdev->bus->number; + ivideo->pcislot = PCI_SLOT(pdev->devfn); + ivideo->pcifunc = PCI_FUNC(pdev->devfn); + ivideo->subsysvendor = pdev->subsystem_vendor; + ivideo->subsysdevice = pdev->subsystem_device; + +#ifndef MODULE + if(sisfb_mode_idx == -1) { + sisfb_get_vga_mode_from_kernel(); + } +#endif + + ivideo->chip = chipinfo->chip; + ivideo->sisvga_engine = chipinfo->vgaengine; + ivideo->hwcursor_size = chipinfo->hwcursor_size; + ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable; + ivideo->mni = chipinfo->mni; + + ivideo->detectedpdc = 0xff; + ivideo->detectedpdca = 0xff; + ivideo->detectedlcda = 0xff; + + ivideo->sisfb_thismonitor.datavalid = FALSE; + + ivideo->sisfb_parm_mem = sisfb_parm_mem; + ivideo->sisfb_accel = sisfb_accel; + ivideo->sisfb_ypan = sisfb_ypan; + ivideo->sisfb_max = sisfb_max; + ivideo->sisfb_userom = sisfb_userom; + ivideo->sisfb_useoem = sisfb_useoem; + ivideo->sisfb_mode_idx = sisfb_mode_idx; + ivideo->sisfb_parm_rate = sisfb_parm_rate; + ivideo->sisfb_crt1off = sisfb_crt1off; + ivideo->sisfb_forcecrt1 = sisfb_forcecrt1; + ivideo->sisfb_crt2type = sisfb_crt2type; + ivideo->sisfb_crt2flags = sisfb_crt2flags; + /* pdc(a), scalelcd, special timing, lvdshl handled below */ + ivideo->sisfb_dstn = sisfb_dstn; + ivideo->sisfb_fstn = sisfb_fstn; + ivideo->sisfb_tvplug = sisfb_tvplug; + ivideo->sisfb_tvstd = sisfb_tvstd; + ivideo->tvxpos = sisfb_tvxposoffset; + ivideo->tvypos = sisfb_tvyposoffset; + ivideo->sisfb_filter = sisfb_filter; + ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) + ivideo->sisfb_inverse = sisfb_inverse; +#endif + + ivideo->refresh_rate = 0; + if(ivideo->sisfb_parm_rate != -1) { + ivideo->refresh_rate = ivideo->sisfb_parm_rate; + } + + ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd; + ivideo->SiS_Pr.CenterScreen = -1; + ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming; + ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl; + + ivideo->SiS_Pr.SiS_Backup70xx = 0xff; + ivideo->SiS_Pr.SiS_CHOverScan = -1; + ivideo->SiS_Pr.SiS_ChSW = FALSE; + ivideo->SiS_Pr.SiS_UseLCDA = FALSE; + ivideo->SiS_Pr.HaveEMI = FALSE; + ivideo->SiS_Pr.HaveEMILCD = FALSE; + ivideo->SiS_Pr.OverruleEMI = FALSE; + ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE; + ivideo->SiS_Pr.SiS_MyCR63 = 0x63; + ivideo->SiS_Pr.PDC = -1; + ivideo->SiS_Pr.PDCA = -1; +#ifdef CONFIG_FB_SIS_315 + if(ivideo->chip >= SIS_330) { + ivideo->SiS_Pr.SiS_MyCR63 = 0x53; + if(ivideo->chip >= SIS_661) { + ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE; + } + } +#endif + + memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var)); + + pci_set_drvdata(pdev, ivideo); + + /* Patch special cases */ + if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) { + switch(ivideo->nbridge->device) { +#ifdef CONFIG_FB_SIS_300 + case PCI_DEVICE_ID_SI_730: + ivideo->chip = SIS_730; + strcpy(ivideo->myid, "SiS 730"); + break; +#endif +#ifdef CONFIG_FB_SIS_315 + case PCI_DEVICE_ID_SI_651: + /* ivideo->chip is ok */ + strcpy(ivideo->myid, "SiS 651"); + break; + case PCI_DEVICE_ID_SI_740: + ivideo->chip = SIS_740; + strcpy(ivideo->myid, "SiS 740"); + break; + case PCI_DEVICE_ID_SI_661: + ivideo->chip = SIS_661; + strcpy(ivideo->myid, "SiS 661"); + break; + case PCI_DEVICE_ID_SI_741: + ivideo->chip = SIS_741; + strcpy(ivideo->myid, "SiS 741"); + break; + case PCI_DEVICE_ID_SI_760: + ivideo->chip = SIS_760; + strcpy(ivideo->myid, "SiS 760"); + break; +#endif + } + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + strcpy(sis_fb_info->modename, ivideo->myid); +#endif + + ivideo->sishw_ext.jChipType = ivideo->chip; + +#ifdef CONFIG_FB_SIS_315 + if((ivideo->sishw_ext.jChipType == SIS_315PRO) || + (ivideo->sishw_ext.jChipType == SIS_315)) { + ivideo->sishw_ext.jChipType = SIS_315H; + } +#endif + + ivideo->video_base = pci_resource_start(pdev, 0); + ivideo->mmio_base = pci_resource_start(pdev, 1); + ivideo->mmio_size = pci_resource_len(pdev, 1); + ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30; + ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO; + + if(!sisvga_enabled) { + if(pci_enable_device(pdev)) { + pci_set_drvdata(pdev, NULL); + kfree(sis_fb_info); + return -EIO; + } + } + + SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress); + +#ifdef CONFIG_FB_SIS_300 + /* Find PCI systems for Chrontel/GPIO communication setup */ + if(ivideo->chip == SIS_630) { + i=0; + do { + if(mychswtable[i].subsysVendor == ivideo->subsysvendor && + mychswtable[i].subsysCard == ivideo->subsysdevice) { + ivideo->SiS_Pr.SiS_ChSW = TRUE; + printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n", + mychswtable[i].vendorName, mychswtable[i].cardName); + break; + } + i++; + } while(mychswtable[i].subsysVendor != 0); + } +#endif + + outSISIDXREG(SISSR, 0x05, 0x86); + + if( (!sisvga_enabled) +#if !defined(__i386__) && !defined(__x86_64__) + || (sisfb_resetcard) +#endif + ) { + for(i = 0x30; i <= 0x3f; i++) { + outSISIDXREG(SISCR,i,0x00); + } + } + + /* Find out about current video mode */ + ivideo->modeprechange = 0x03; + inSISIDXREG(SISCR,0x34,reg); + if(reg & 0x7f) { + ivideo->modeprechange = reg & 0x7f; + } else if(sisvga_enabled) { +#if defined(__i386__) || defined(__x86_64__) + unsigned char SIS_IOTYPE2 *tt = ioremap(0, 0x1000); + if(tt) { + ivideo->modeprechange = readb(tt + 0x449); + iounmap(tt); + } +#endif + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#ifdef MODULE + if((reg & 0x80) && (reg != 0xff)) { + if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) { + printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n"); + pci_set_drvdata(pdev, NULL); + kfree(sis_fb_info); + return -EBUSY; + } + } +#endif +#endif + + ivideo->sishw_ext.bIntegratedMMEnabled = TRUE; +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + if(ivideo->chip != SIS_300) { + inSISIDXREG(SISSR, 0x1a, reg); + if(!(reg & 0x10)) { + ivideo->sishw_ext.bIntegratedMMEnabled = FALSE; + } + } + } +#endif + + ivideo->bios_abase = NULL; + if(ivideo->sisfb_userom) { + ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev); + ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase; + if(ivideo->sishw_ext.pjVirtualRomBase) { + printk(KERN_INFO "sisfb: Video ROM found and copied\n"); + ivideo->sishw_ext.UseROM = TRUE; + } else { + ivideo->sishw_ext.UseROM = FALSE; + printk(KERN_INFO "sisfb: Video ROM not found\n"); + } + } else { + ivideo->sishw_ext.pjVirtualRomBase = NULL; + ivideo->sishw_ext.UseROM = FALSE; + printk(KERN_INFO "sisfb: Video ROM usage disabled\n"); + } + + /* Find systems for special custom timing */ + if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) { + int j; + unsigned char *biosver = NULL; + unsigned char *biosdate = NULL; + BOOLEAN footprint; + u32 chksum = 0; + + if(ivideo->sishw_ext.UseROM) { + biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06; + biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c; + for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i]; + } + + i=0; + do { + if( (mycustomttable[i].chipID == ivideo->chip) && + ((!strlen(mycustomttable[i].biosversion)) || + (ivideo->sishw_ext.UseROM && + (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) && + ((!strlen(mycustomttable[i].biosdate)) || + (ivideo->sishw_ext.UseROM && + (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) && + ((!mycustomttable[i].bioschksum) || + (ivideo->sishw_ext.UseROM && + (mycustomttable[i].bioschksum == chksum))) && + (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) && + (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) { + footprint = TRUE; + for(j = 0; j < 5; j++) { + if(mycustomttable[i].biosFootprintAddr[j]) { + if(ivideo->sishw_ext.UseROM) { + if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] != + mycustomttable[i].biosFootprintData[j]) { + footprint = FALSE; + } + } else footprint = FALSE; + } + } + if(footprint) { + ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID; + printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n", + mycustomttable[i].vendorName, + mycustomttable[i].cardName); + printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n", + mycustomttable[i].optionName); + break; + } + } + i++; + } while(mycustomttable[i].chipID); + } + +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + if( (!sisvga_enabled) +#if !defined(__i386__) && !defined(__x86_64__) + || (sisfb_resetcard) +#endif + ) { + if(ivideo->chip == SIS_300) { + sisfb_post_sis300(pdev); + } + } + } +#endif + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + if( (!sisvga_enabled) +#if !defined(__i386__) && !defined(__x86_64__) + || (sisfb_resetcard) +#endif + ) { + if((ivideo->chip == SIS_315H) || + (ivideo->chip == SIS_315) || + (ivideo->chip == SIS_315PRO) || + (ivideo->chip == SIS_330)) { + sisfb_post_sis315330(pdev); + } + } + } +#endif + + if(sisfb_get_dram_size(ivideo)) { + printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n"); + if(ivideo->bios_abase) vfree(ivideo->bios_abase); + pci_set_drvdata(pdev, NULL); + kfree(sis_fb_info); + return -ENODEV; + } + + if((ivideo->sisfb_mode_idx < 0) || + ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) { + /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */ + orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE)); + /* Enable 2D accelerator engine */ + orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D); + } + + if(sisfb_pdc != 0xff) { + if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c; + else sisfb_pdc &= 0x1f; + ivideo->SiS_Pr.PDC = sisfb_pdc; + } +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f; + } +#endif + + if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) { + printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n"); + printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n"); + if(ivideo->bios_abase) vfree(ivideo->bios_abase); + pci_set_drvdata(pdev, NULL); + kfree(sis_fb_info); + return -ENODEV; + } + + if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) { + printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n"); + release_mem_region(ivideo->video_base, ivideo->video_size); + if(ivideo->bios_abase) vfree(ivideo->bios_abase); + pci_set_drvdata(pdev, NULL); + kfree(sis_fb_info); + return -ENODEV; + } + + ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size); + ivideo->sishw_ext.pjVideoMemoryAddress = ivideo->video_vbase; + if(!ivideo->video_vbase) { + printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n"); + release_mem_region(ivideo->video_base, ivideo->video_size); + release_mem_region(ivideo->mmio_base, ivideo->mmio_size); + if(ivideo->bios_abase) vfree(ivideo->bios_abase); + pci_set_drvdata(pdev, NULL); + kfree(sis_fb_info); + return -ENODEV; + } + + ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size); + if(!ivideo->mmio_vbase) { + printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n"); + iounmap(ivideo->video_vbase); + release_mem_region(ivideo->video_base, ivideo->video_size); + release_mem_region(ivideo->mmio_base, ivideo->mmio_size); + if(ivideo->bios_abase) vfree(ivideo->bios_abase); + pci_set_drvdata(pdev, NULL); + kfree(sis_fb_info); + return -ENODEV; + } + + printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n", + ivideo->video_base, (ULONG)ivideo->video_vbase, ivideo->video_size / 1024); + + printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n", + ivideo->mmio_base, (ULONG)ivideo->mmio_vbase, ivideo->mmio_size / 1024); + + if((ivideo->havenoheap = sisfb_heap_init(ivideo))) { + printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n"); + } + + /* Used for clearing the screen only, therefore respect our mem limit */ + ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem; + + ivideo->mtrr = 0; + + ivideo->vbflags = 0; + ivideo->lcddefmodeidx = DEFAULT_LCDMODE; + ivideo->tvdefmodeidx = DEFAULT_TVMODE; + ivideo->defmodeidx = DEFAULT_MODE; + + ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext); + + if((ivideo->sisfb_mode_idx < 0) || + ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) { + + sisfb_sense_crt1(ivideo); + + sisfb_get_VB_type(ivideo); + + if(ivideo->vbflags & VB_VIDEOBRIDGE) { + sisfb_detect_VB_connect(ivideo); + } + + ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD); + + if(ivideo->vbflags & VB_VIDEOBRIDGE) { + if(ivideo->sisfb_crt2type != -1) { + if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) { + ivideo->currentvbflags |= CRT2_LCD; + } else if(ivideo->sisfb_crt2type != CRT2_LCD) { + ivideo->currentvbflags |= ivideo->sisfb_crt2type; + } + } else { + /* Chrontel 700x TV detection often unreliable, therefore use a + * different default order on such machines + */ + if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) { + if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD; + else if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV; + else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA; + } else { + if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV; + else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD; + else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA; + } + } + } + + if(ivideo->vbflags & CRT2_LCD) { + inSISIDXREG(SISCR, 0x36, reg); + reg &= 0x0f; + if(ivideo->sisvga_engine == SIS_300_VGA) { + ivideo->CRT2LCDType = sis300paneltype[reg]; + } else if(ivideo->chip >= SIS_661) { + ivideo->CRT2LCDType = sis661paneltype[reg]; + } else { + ivideo->CRT2LCDType = sis310paneltype[reg]; + if((ivideo->chip == SIS_550) && (sisfb_fstn)) { + if((ivideo->CRT2LCDType != LCD_640x480_2) && + (ivideo->CRT2LCDType != LCD_640x480_3)) { + ivideo->CRT2LCDType = LCD_320x480; + } + } + } + if(ivideo->CRT2LCDType == LCD_UNKNOWN) { + /* For broken BIOSes: Assume 1024x768, RGB18 */ + ivideo->CRT2LCDType = LCD_1024x768; + setSISIDXREG(SISCR,0x36,0xf0,0x02); + setSISIDXREG(SISCR,0x37,0xee,0x01); + printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg); + } + for(i = 0; i < SIS_LCD_NUMBER; i++) { + if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) { + ivideo->lcdxres = sis_lcd_data[i].xres; + ivideo->lcdyres = sis_lcd_data[i].yres; + ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx; + break; + } + } + if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) { + ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99; + } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) { + ivideo->lcdxres = 848; ivideo->lcdyres = 480; ivideo->lcddefmodeidx = 47; + } + printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n", + ivideo->lcdxres, ivideo->lcdyres); + } + +#ifdef CONFIG_FB_SIS_300 + /* Save the current PanelDelayCompensation if the LCD is currently used */ + if(ivideo->sisvga_engine == SIS_300_VGA) { + if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) { + int tmp; + inSISIDXREG(SISCR,0x30,tmp); + if(tmp & 0x20) { + /* Currently on LCD? If yes, read current pdc */ + inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc); + ivideo->detectedpdc &= 0x3c; + if(ivideo->SiS_Pr.PDC == -1) { + /* Let option override detection */ + ivideo->SiS_Pr.PDC = ivideo->detectedpdc; + } + printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n", + ivideo->detectedpdc); + } + if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) { + printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n", + ivideo->SiS_Pr.PDC); + } + } + } +#endif + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + + /* Try to find about LCDA */ + if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) { + int tmp; + inSISIDXREG(SISPART1,0x13,tmp); + if(tmp & 0x04) { + ivideo->SiS_Pr.SiS_UseLCDA = TRUE; + ivideo->detectedlcda = 0x03; + } + } + + /* Save PDC */ + if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) { + int tmp; + inSISIDXREG(SISCR,0x30,tmp); + if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) { + /* Currently on LCD? If yes, read current pdc */ + u8 pdc; + inSISIDXREG(SISPART1,0x2D,pdc); + ivideo->detectedpdc = (pdc & 0x0f) << 1; + ivideo->detectedpdca = (pdc & 0xf0) >> 3; + inSISIDXREG(SISPART1,0x35,pdc); + ivideo->detectedpdc |= ((pdc >> 7) & 0x01); + inSISIDXREG(SISPART1,0x20,pdc); + ivideo->detectedpdca |= ((pdc >> 6) & 0x01); + if(ivideo->newrom) { + /* New ROM invalidates other PDC resp. */ + if(ivideo->detectedlcda != 0xff) { + ivideo->detectedpdc = 0xff; + } else { + ivideo->detectedpdca = 0xff; + } + } + if(ivideo->SiS_Pr.PDC == -1) { + if(ivideo->detectedpdc != 0xff) { + ivideo->SiS_Pr.PDC = ivideo->detectedpdc; + } + } + if(ivideo->SiS_Pr.PDCA == -1) { + if(ivideo->detectedpdca != 0xff) { + ivideo->SiS_Pr.PDCA = ivideo->detectedpdca; + } + } + if(ivideo->detectedpdc != 0xff) { + printk(KERN_INFO + "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n", + ivideo->detectedpdc); + } + if(ivideo->detectedpdca != 0xff) { + printk(KERN_INFO + "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n", + ivideo->detectedpdca); + } + } + + /* Save EMI */ + if(ivideo->vbflags & (VB_302LV | VB_302ELV)) { + inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30); + inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31); + inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32); + inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33); + ivideo->SiS_Pr.HaveEMI = TRUE; + if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) { + ivideo->SiS_Pr.HaveEMILCD = TRUE; + } + } + } + + /* Let user override detected PDCs (all bridges) */ + if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) { + if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) { + printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n", + ivideo->SiS_Pr.PDC); + } + if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) { + printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n", + ivideo->SiS_Pr.PDCA); + } + } + + } +#endif + + if(!ivideo->sisfb_crt1off) { + sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0); + } else { + if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) && + (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) { + sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1); + } + } + + if(ivideo->sisfb_mode_idx >= 0) { + int bu = ivideo->sisfb_mode_idx; + ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo, + ivideo->sisfb_mode_idx, ivideo->currentvbflags); + if(bu != ivideo->sisfb_mode_idx) { + printk(KERN_ERR "Mode %dx%dx%d failed validation\n", + sisbios_mode[bu].xres, + sisbios_mode[bu].yres, + sisbios_mode[bu].bpp); + } + } + + if(ivideo->sisfb_mode_idx < 0) { + switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { + case CRT2_LCD: + ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx; + break; + case CRT2_TV: + ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx; + break; + default: + ivideo->sisfb_mode_idx = ivideo->defmodeidx; + break; + } + } + + ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]; + + if(ivideo->refresh_rate != 0) { + sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx); + } + + if(ivideo->rate_idx == 0) { + ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx; + ivideo->refresh_rate = 60; + } + + if(ivideo->sisfb_thismonitor.datavalid) { + if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx, + ivideo->rate_idx, ivideo->refresh_rate)) { + printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n"); + } + } + + ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp; + ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres; + ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres; + + sisfb_set_vparms(ivideo); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + + /* ---------------- For 2.4: Now switch the mode ------------------ */ + + printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n", + ivideo->video_width, ivideo->video_height, ivideo->video_bpp, + ivideo->refresh_rate); + + sisfb_pre_setmode(ivideo); + + if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) { + printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n", + ivideo->mode_no); + iounmap(ivideo->video_vbase); + iounmap(ivideo->mmio_vbase); + release_mem_region(ivideo->video_base, ivideo->video_size); + release_mem_region(ivideo->mmio_base, ivideo->mmio_size); + if(ivideo->bios_abase) vfree(ivideo->bios_abase); + pci_set_drvdata(pdev, NULL); + kfree(sis_fb_info); + return -EINVAL; + } + + outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); + + sisfb_post_setmode(ivideo); + + /* Maximize regardless of sisfb_max at startup */ + ivideo->default_var.yres_virtual = 32767; + + /* Force reset of x virtual in crtc_to_var */ + ivideo->default_var.xres_virtual = 0; + + sisfb_crtc_to_var(ivideo, &ivideo->default_var); + + sisfb_calc_pitch(ivideo, &ivideo->default_var); + sisfb_set_pitch(ivideo); + + ivideo->accel = 0; + if(ivideo->sisfb_accel) { + ivideo->accel = -1; + ivideo->default_var.accel_flags |= FB_ACCELF_TEXT; + } + sisfb_initaccel(ivideo); + + sis_fb_info->node = -1; + sis_fb_info->flags = FBINFO_FLAG_DEFAULT; + sis_fb_info->fbops = &sisfb_ops; + sis_fb_info->disp = &ivideo->sis_disp; + sis_fb_info->blank = &sisfb_blank; + sis_fb_info->switch_con = &sisfb_switch; + sis_fb_info->updatevar = &sisfb_update_var; + sis_fb_info->changevar = NULL; + strcpy(sis_fb_info->fontname, sisfb_fontname); + + sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info); + +#else /* --------- For 2.6: Setup a somewhat sane default var ------------ */ + + printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n", + ivideo->video_width, ivideo->video_height, ivideo->video_bpp, + ivideo->refresh_rate); + + ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width; + ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height; + ivideo->default_var.bits_per_pixel = ivideo->video_bpp; + + sisfb_bpp_to_var(ivideo, &ivideo->default_var); + + ivideo->default_var.pixclock = (u32) (1000000000 / + sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext, + ivideo->mode_no, ivideo->rate_idx)); + + if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext, + ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) { + if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + ivideo->default_var.pixclock <<= 1; + } + } + + if(ivideo->sisfb_ypan) { + /* Maximize regardless of sisfb_max at startup */ + ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var); + if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) { + ivideo->default_var.yres_virtual = ivideo->default_var.yres; + } + } + + sisfb_calc_pitch(ivideo, &ivideo->default_var); + + ivideo->accel = 0; + if(ivideo->sisfb_accel) { + ivideo->accel = -1; +#ifdef STUPID_ACCELF_TEXT_SHIT + ivideo->default_var.accel_flags |= FB_ACCELF_TEXT; +#endif + } + sisfb_initaccel(ivideo); + +#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN) + sis_fb_info->flags = FBINFO_DEFAULT | + FBINFO_HWACCEL_YPAN | + FBINFO_HWACCEL_XPAN | + FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_FILLRECT | + ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED); +#else + sis_fb_info->flags = FBINFO_FLAG_DEFAULT; +#endif + sis_fb_info->var = ivideo->default_var; + sis_fb_info->fix = ivideo->sisfb_fix; + sis_fb_info->screen_base = ivideo->video_vbase; + sis_fb_info->fbops = &sisfb_ops; + + sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info); + sis_fb_info->pseudo_palette = ivideo->pseudo_palette; + + fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0); +#endif /* 2.6 */ + + printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags); + +#ifdef CONFIG_MTRR + ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size, + MTRR_TYPE_WRCOMB, 1); + if(!ivideo->mtrr) { + printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n"); + } +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + vc_resize_con(1, 1, 0); +#endif + + if(register_framebuffer(sis_fb_info) < 0) { + printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n"); + iounmap(ivideo->video_vbase); + iounmap(ivideo->mmio_vbase); + release_mem_region(ivideo->video_base, ivideo->video_size); + release_mem_region(ivideo->mmio_base, ivideo->mmio_size); + if(ivideo->bios_abase) vfree(ivideo->bios_abase); + pci_set_drvdata(pdev, NULL); + kfree(sis_fb_info); + return -EINVAL; + } + + ivideo->registered = 1; + + /* Enlist us */ + ivideo->next = card_list; + card_list = ivideo; + + printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n", + ivideo->sisfb_accel ? "enabled" : "disabled", + ivideo->sisfb_ypan ? + (ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled"); + + + printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n", +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + GET_FB_IDX(sis_fb_info->node), +#else + sis_fb_info->node, +#endif + ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL); + + printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n"); + + } /* if mode = "none" */ + + return 0; +} + +/*****************************************************/ +/* PCI DEVICE HANDLING */ +/*****************************************************/ + +static void __devexit sisfb_remove(struct pci_dev *pdev) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + struct fb_info *sis_fb_info = ivideo->memyselfandi; + int registered = ivideo->registered; + + /* Unmap */ + iounmap(ivideo->video_vbase); + iounmap(ivideo->mmio_vbase); + vfree(ivideo->bios_abase); + + /* Release mem regions */ + release_mem_region(ivideo->video_base, ivideo->video_size); + release_mem_region(ivideo->mmio_base, ivideo->mmio_size); + +#ifdef CONFIG_MTRR + /* Release MTRR region */ + if(ivideo->mtrr) { + mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size); + } +#endif + + /* Unregister the framebuffer */ + if(ivideo->registered) { + unregister_framebuffer(sis_fb_info); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3)) + framebuffer_release(sis_fb_info); +#else + kfree(sis_fb_info); +#endif + } + + pci_set_drvdata(pdev, NULL); + + /* TODO: Restore the initial mode + * This sounds easy but is as good as impossible + * on many machines with SiS chip and video bridge + * since text modes are always set up differently + * from machine to machine. Depends on the type + * of integration between chipset and bridge. + */ + if(registered) { + printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n"); + } +}; + +static struct pci_driver sisfb_driver = { + .name = "sisfb", + .id_table = sisfb_pci_table, + .probe = sisfb_probe, + .remove = __devexit_p(sisfb_remove) +}; + +SISINITSTATIC int __init sisfb_init(void) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) +#ifndef MODULE + char *options = NULL; + + if(fb_get_options("sisfb", &options)) + return -ENODEV; + sisfb_setup(options); +#endif +#endif + return(pci_register_driver(&sisfb_driver)); +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) +#ifndef MODULE +module_init(sisfb_init); +#endif +#endif + +/*****************************************************/ +/* MODULE */ +/*****************************************************/ + +#ifdef MODULE + +static char *mode = NULL; +static int vesa = -1; +static unsigned int rate = 0; +static unsigned int crt1off = 1; +static unsigned int mem = 0; +static char *forcecrt2type = NULL; +static int forcecrt1 = -1; +static int pdc = -1; +static int pdc1 = -1; +static int noaccel = -1; +static int noypan = -1; +static int nomax = -1; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static int inverse = 0; +#endif +static int userom = -1; +static int useoem = -1; +static char *tvstandard = NULL; +static int nocrt2rate = 0; +static int scalelcd = -1; +static char *specialtiming = NULL; +static int lvdshl = -1; +static int tvxposoffset = 0, tvyposoffset = 0; +static int filter = -1; +#if !defined(__i386__) && !defined(__x86_64__) +static int resetcard = 0; +static int videoram = 0; +#endif + +MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others"); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +MODULE_PARM(mem, "i"); +MODULE_PARM(noaccel, "i"); +MODULE_PARM(noypan, "i"); +MODULE_PARM(nomax, "i"); +MODULE_PARM(userom, "i"); +MODULE_PARM(useoem, "i"); +MODULE_PARM(mode, "s"); +MODULE_PARM(vesa, "i"); +MODULE_PARM(rate, "i"); +MODULE_PARM(forcecrt1, "i"); +MODULE_PARM(forcecrt2type, "s"); +MODULE_PARM(scalelcd, "i"); +MODULE_PARM(pdc, "i"); +MODULE_PARM(pdc1, "i"); +MODULE_PARM(specialtiming, "s"); +MODULE_PARM(lvdshl, "i"); +MODULE_PARM(tvstandard, "s"); +MODULE_PARM(tvxposoffset, "i"); +MODULE_PARM(tvyposoffset, "i"); +MODULE_PARM(filter, "i"); +MODULE_PARM(nocrt2rate, "i"); +MODULE_PARM(inverse, "i"); +#if !defined(__i386__) && !defined(__x86_64__) +MODULE_PARM(resetcard, "i"); +MODULE_PARM(videoram, "i"); +#endif +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +module_param(mem, int, 0); +module_param(noaccel, int, 0); +module_param(noypan, int, 0); +module_param(nomax, int, 0); +module_param(userom, int, 0); +module_param(useoem, int, 0); +module_param(mode, charp, 0); +module_param(vesa, int, 0); +module_param(rate, int, 0); +module_param(forcecrt1, int, 0); +module_param(forcecrt2type, charp, 0); +module_param(scalelcd, int, 0); +module_param(pdc, int, 0); +module_param(pdc1, int, 0); +module_param(specialtiming, charp, 0); +module_param(lvdshl, int, 0); +module_param(tvstandard, charp, 0); +module_param(tvxposoffset, int, 0); +module_param(tvyposoffset, int, 0); +module_param(filter, int, 0); +module_param(nocrt2rate, int, 0); +#if !defined(__i386__) && !defined(__x86_64__) +module_param(resetcard, int, 0); +module_param(videoram, int, 0); +#endif +#endif + +MODULE_PARM_DESC(mem, + "\nDetermines the beginning of the video memory heap in KB. This heap is used\n" + "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n" + "on the amount of video RAM available. If 8MB of video RAM or less is available,\n" + "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n" + "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n" + "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n" + "for XFree86 4.x/X.org 6.7 and later.\n"); + +MODULE_PARM_DESC(noaccel, + "\nIf set to anything other than 0, 2D acceleration will be disabled.\n" + "(default: 0)\n"); + +MODULE_PARM_DESC(noypan, + "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n" + "will be performed by redrawing the screen. (default: 0)\n"); + +MODULE_PARM_DESC(nomax, + "\nIf y-panning is enabled, sisfb will by default use the entire available video\n" + "memory for the virtual screen in order to optimize scrolling performance. If\n" + "this is set to anything other than 0, sisfb will not do this and thereby \n" + "enable the user to positively specify a virtual Y size of the screen using\n" + "fbset. (default: 0)\n"); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +MODULE_PARM_DESC(mode, + "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n" + "1024x768x16. Other formats supported include XxY-Depth and\n" + "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n" + "number, it will be interpreted as a VESA mode number. (default: none if\n" + "sisfb is a module; this leaves the console untouched and the driver will\n" + "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n" + "is in the kernel)\n"); +MODULE_PARM_DESC(vesa, + "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n" + "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n" + "and the driver will only do the video memory management for eg. DRM/DRI;\n" + "0x0103 if sisfb is in the kernel)\n"); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +MODULE_PARM_DESC(mode, + "\nSelects the desired default display mode in the format XxYxDepth,\n" + "eg. 1024x768x16. Other formats supported include XxY-Depth and\n" + "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n" + "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n"); + +MODULE_PARM_DESC(vesa, + "\nSelects the desired default display mode by VESA defined mode number, eg.\n" + "0x117 (default: 0x0103)\n"); +#endif + +MODULE_PARM_DESC(rate, + "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n" + "If the mode is specified in the format XxY-Depth@Rate, this parameter\n" + "will be ignored (default: 60)\n"); + +MODULE_PARM_DESC(forcecrt1, + "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n" + "connected. With this option, the detection can be overridden (1=CRT1 ON,\n" + "0=CRT1 OFF) (default: [autodetected])\n"); + +MODULE_PARM_DESC(forcecrt2type, + "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n" + "LCD, TV or secondary VGA. With this option, this autodetection can be\n" + "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n" + "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n" + "be used instead of TV to override the TV detection. Furthermore, on systems\n" + "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n" + "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n" + "depends on the very hardware in use. (default: [autodetected])\n"); + +MODULE_PARM_DESC(scalelcd, + "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n" + "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n" + "show black bars around the image, TMDS panels will probably do the scaling\n" + "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n"); + +MODULE_PARM_DESC(pdc, + "\nThis is for manually selecting the LCD panel delay compensation. The driver\n" + "should detect this correctly in most cases; however, sometimes this is not\n" + "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n" + "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n" + "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n" + "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n"); + +#ifdef CONFIG_FB_SIS_315 +MODULE_PARM_DESC(pdc1, + "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n" + "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n" + "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n" + "implemented yet.\n"); +#endif + +MODULE_PARM_DESC(specialtiming, + "\nPlease refer to documentation for more information on this option.\n"); + +MODULE_PARM_DESC(lvdshl, + "\nPlease refer to documentation for more information on this option.\n"); + +MODULE_PARM_DESC(tvstandard, + "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n" + "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n"); + +MODULE_PARM_DESC(tvxposoffset, + "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n" + "Default: 0\n"); + +MODULE_PARM_DESC(tvyposoffset, + "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n" + "Default: 0\n"); + +MODULE_PARM_DESC(filter, + "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n" + "(Possible values 0-7, default: [no filter])\n"); + +MODULE_PARM_DESC(nocrt2rate, + "\nSetting this to 1 will force the driver to use the default refresh rate for\n" + "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n"); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +MODULE_PARM_DESC(inverse, + "\nSetting this to anything but 0 should invert the display colors, but this\n" + "does not seem to work. (default: 0)\n"); +#endif + +#if !defined(__i386__) && !defined(__x86_64__) +#ifdef CONFIG_FB_SIS_300 +MODULE_PARM_DESC(resetcard, + "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n" + "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n" + "Default: 0\n"); + +MODULE_PARM_DESC(videoram, + "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n" + "some non-x86 architectures where the memory auto detection fails. Only\n" + "relevant if resetcard is set, too. Default: [auto-detect]\n"); +#endif +#endif + +int __devinit sisfb_init_module(void) +{ + sisfb_setdefaultparms(); + + if(rate) sisfb_parm_rate = rate; + + if((scalelcd == 0) || (scalelcd == 1)) { + sisfb_scalelcd = scalelcd ^ 1; + } + + /* Need to check crt2 type first for fstn/dstn */ + + if(forcecrt2type) + sisfb_search_crt2type(forcecrt2type); + + if(tvstandard) + sisfb_search_tvstd(tvstandard); + + if(mode) + sisfb_search_mode(mode, FALSE); + else if(vesa != -1) + sisfb_search_vesamode(vesa, FALSE); + + sisfb_crt1off = (crt1off == 0) ? 1 : 0; + + sisfb_forcecrt1 = forcecrt1; + if(forcecrt1 == 1) sisfb_crt1off = 0; + else if(forcecrt1 == 0) sisfb_crt1off = 1; + + if(noaccel == 1) sisfb_accel = 0; + else if(noaccel == 0) sisfb_accel = 1; + + if(noypan == 1) sisfb_ypan = 0; + else if(noypan == 0) sisfb_ypan = 1; + + if(nomax == 1) sisfb_max = 0; + else if(nomax == 0) sisfb_max = 1; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + if(inverse) sisfb_inverse = 1; +#endif + + if(mem) sisfb_parm_mem = mem; + + if(userom != -1) sisfb_userom = userom; + if(useoem != -1) sisfb_useoem = useoem; + + if(pdc != -1) sisfb_pdc = (pdc & 0x7f); + if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f); + + sisfb_nocrt2rate = nocrt2rate; + + if(specialtiming) + sisfb_search_specialtiming(specialtiming); + + if((lvdshl >= 0) && (lvdshl <= 3)) sisfb_lvdshl = lvdshl; + + if(filter != -1) sisfb_filter = filter; + + sisfb_tvxposoffset = tvxposoffset; + sisfb_tvyposoffset = tvyposoffset; + +#if !defined(__i386__) && !defined(__x86_64__) + sisfb_resetcard = (resetcard) ? 1 : 0; + if(videoram) sisfb_videoram = videoram; +#endif + + return(sisfb_init()); +} + +static void __exit sisfb_remove_module(void) +{ + pci_unregister_driver(&sisfb_driver); + printk(KERN_DEBUG "sisfb: Module unloaded\n"); +} + +module_init(sisfb_init_module); +module_exit(sisfb_remove_module); + +#endif /* /MODULE */ + +EXPORT_SYMBOL(sis_malloc); +EXPORT_SYMBOL(sis_free); + + diff --git a/drivers/video/sis/sis_main.h b/drivers/video/sis/sis_main.h new file mode 100644 index 000000000000..a6678a7aff35 --- /dev/null +++ b/drivers/video/sis/sis_main.h @@ -0,0 +1,955 @@ +/* + * SiS 300/305/540/630(S)/730(S) + * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760 + * frame buffer driver for Linux kernels >=2.4.14 and >=2.6.3 + * + * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the named License, + * or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef _SISFB_MAIN +#define _SISFB_MAIN + +#include <linux/spinlock.h> + +#include "vstruct.h" +#include "sis.h" + +#define MODE_INDEX_NONE 0 /* index for mode=none */ + +/* Fbcon stuff */ +static struct fb_var_screeninfo my_default_var = { + .xres = 0, + .yres = 0, + .xres_virtual = 0, + .yres_virtual = 0, + .xoffset = 0, + .yoffset = 0, + .bits_per_pixel = 0, + .grayscale = 0, + .red = {0, 8, 0}, + .green = {0, 8, 0}, + .blue = {0, 8, 0}, + .transp = {0, 0, 0}, + .nonstd = 0, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .accel_flags = 0, + .pixclock = 0, + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .hsync_len = 0, + .vsync_len = 0, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, +}; + +/* Boot-time parameters */ +static int sisfb_off = 0; +static int sisfb_parm_mem = 0; +static int sisfb_accel = -1; +static int sisfb_ypan = -1; +static int sisfb_max = -1; +static int sisfb_userom = 1; +static int sisfb_useoem = -1; +#ifdef MODULE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +static int sisfb_mode_idx = -1; +#else +static int sisfb_mode_idx = MODE_INDEX_NONE; /* Don't use a mode by default if we are a module */ +#endif +#else +static int sisfb_mode_idx = -1; /* Use a default mode if we are inside the kernel */ +#endif +static int sisfb_parm_rate = -1; +static int sisfb_crt1off = 0; +static int sisfb_forcecrt1 = -1; +static int sisfb_crt2type = -1; /* CRT2 type (for overriding autodetection) */ +static int sisfb_crt2flags = 0; +static int sisfb_pdc = 0xff; +static int sisfb_pdca = 0xff; +static int sisfb_scalelcd = -1; +static int sisfb_specialtiming = CUT_NONE; +static int sisfb_lvdshl = -1; +static int sisfb_dstn = 0; +static int sisfb_fstn = 0; +static int sisfb_tvplug = -1; /* Tv plug type (for overriding autodetection) */ +static int sisfb_tvstd = -1; +static int sisfb_tvxposoffset = 0; +static int sisfb_tvyposoffset = 0; +static int sisfb_filter = -1; +static int sisfb_nocrt2rate = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static int sisfb_inverse = 0; +static char sisfb_fontname[40]; +#endif +#if !defined(__i386__) && !defined(__x86_64__) +static int sisfb_resetcard = 0; +static int sisfb_videoram = 0; +#endif + +/* List of supported chips */ +static struct sisfb_chip_info { + int chip; + int vgaengine; + int mni; + int hwcursor_size; + int CRT2_write_enable; + const char *chip_name; +} sisfb_chip_info[] __devinitdata = { + { SIS_300, SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 300/305" }, + { SIS_540, SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 540" }, + { SIS_630, SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 630" }, + { SIS_315H, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315H" }, + { SIS_315, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315" }, + { SIS_315PRO, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315PRO" }, + { SIS_550, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 55x" }, + { SIS_650, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 650" }, + { SIS_330, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 330" }, + { SIS_660, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 660" }, +}; + +static struct pci_device_id __devinitdata sisfb_pci_table[] = { +#ifdef CONFIG_FB_SIS_300 + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, +#endif +#ifdef CONFIG_FB_SIS_315 + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315H, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_660_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, +#endif + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, sisfb_pci_table); + +static struct sis_video_info *card_list = NULL; + +/* TODO: This is not handled card-wise because the DRM + does not refer to a unique fb when calling sis_alloc + or sis_free. Therefore, this is handled globally for + now (hoping that nobody is crazy enough to run two + SiS cards at the same time). + */ +static SIS_HEAP sisfb_heap; + +#define MD_SIS300 1 +#define MD_SIS315 2 + +/* Mode table */ +static const struct _sisbios_mode { + char name[15]; + u8 mode_no[2]; + u16 vesa_mode_no_1; /* "SiS defined" VESA mode number */ + u16 vesa_mode_no_2; /* Real VESA mode numbers */ + u16 xres; + u16 yres; + u16 bpp; + u16 rate_idx; + u16 cols; + u16 rows; + u8 chipset; +} sisbios_mode[] = { +/*0*/ {"none", {0xff,0xff}, 0x0000, 0x0000, 0, 0, 0, 0, 0, 0, MD_SIS300|MD_SIS315}, + {"320x200x8", {0x59,0x59}, 0x0138, 0x0000, 320, 200, 8, 1, 40, 12, MD_SIS300|MD_SIS315}, + {"320x200x16", {0x41,0x41}, 0x010e, 0x0000, 320, 200, 16, 1, 40, 12, MD_SIS300|MD_SIS315}, + {"320x200x24", {0x4f,0x4f}, 0x0000, 0x0000, 320, 200, 32, 1, 40, 12, MD_SIS300|MD_SIS315}, /* That's for people who mix up color- and fb depth */ + {"320x200x32", {0x4f,0x4f}, 0x0000, 0x0000, 320, 200, 32, 1, 40, 12, MD_SIS300|MD_SIS315}, + {"320x240x8", {0x50,0x50}, 0x0132, 0x0000, 320, 240, 8, 1, 40, 15, MD_SIS300|MD_SIS315}, + {"320x240x16", {0x56,0x56}, 0x0135, 0x0000, 320, 240, 16, 1, 40, 15, MD_SIS300|MD_SIS315}, + {"320x240x24", {0x53,0x53}, 0x0000, 0x0000, 320, 240, 32, 1, 40, 15, MD_SIS300|MD_SIS315}, + {"320x240x32", {0x53,0x53}, 0x0000, 0x0000, 320, 240, 32, 1, 40, 15, MD_SIS300|MD_SIS315}, + {"320x240x8", {0x5a,0x5a}, 0x0132, 0x0000, 320, 480, 8, 1, 40, 30, MD_SIS315}, /* FSTN */ +/*10*/ {"320x240x16", {0x5b,0x5b}, 0x0135, 0x0000, 320, 480, 16, 1, 40, 30, MD_SIS315}, /* FSTN */ + {"400x300x8", {0x51,0x51}, 0x0133, 0x0000, 400, 300, 8, 1, 50, 18, MD_SIS300|MD_SIS315}, + {"400x300x16", {0x57,0x57}, 0x0136, 0x0000, 400, 300, 16, 1, 50, 18, MD_SIS300|MD_SIS315}, + {"400x300x24", {0x54,0x54}, 0x0000, 0x0000, 400, 300, 32, 1, 50, 18, MD_SIS300|MD_SIS315}, + {"400x300x32", {0x54,0x54}, 0x0000, 0x0000, 400, 300, 32, 1, 50, 18, MD_SIS300|MD_SIS315}, + {"512x384x8", {0x52,0x52}, 0x0000, 0x0000, 512, 384, 8, 1, 64, 24, MD_SIS300|MD_SIS315}, + {"512x384x16", {0x58,0x58}, 0x0000, 0x0000, 512, 384, 16, 1, 64, 24, MD_SIS300|MD_SIS315}, + {"512x384x24", {0x5c,0x5c}, 0x0000, 0x0000, 512, 384, 32, 1, 64, 24, MD_SIS300|MD_SIS315}, + {"512x384x32", {0x5c,0x5c}, 0x0000, 0x0000, 512, 384, 32, 1, 64, 24, MD_SIS300|MD_SIS315}, + {"640x400x8", {0x2f,0x2f}, 0x0000, 0x0000, 640, 400, 8, 1, 80, 25, MD_SIS300|MD_SIS315}, +/*20*/ {"640x400x16", {0x5d,0x5d}, 0x0000, 0x0000, 640, 400, 16, 1, 80, 25, MD_SIS300|MD_SIS315}, + {"640x400x24", {0x5e,0x5e}, 0x0000, 0x0000, 640, 400, 32, 1, 80, 25, MD_SIS300|MD_SIS315}, + {"640x400x32", {0x5e,0x5e}, 0x0000, 0x0000, 640, 400, 32, 1, 80, 25, MD_SIS300|MD_SIS315}, + {"640x480x8", {0x2e,0x2e}, 0x0101, 0x0101, 640, 480, 8, 1, 80, 30, MD_SIS300|MD_SIS315}, + {"640x480x16", {0x44,0x44}, 0x0111, 0x0111, 640, 480, 16, 1, 80, 30, MD_SIS300|MD_SIS315}, + {"640x480x24", {0x62,0x62}, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30, MD_SIS300|MD_SIS315}, + {"640x480x32", {0x62,0x62}, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30, MD_SIS300|MD_SIS315}, + {"720x480x8", {0x31,0x31}, 0x0000, 0x0000, 720, 480, 8, 1, 90, 30, MD_SIS300|MD_SIS315}, + {"720x480x16", {0x33,0x33}, 0x0000, 0x0000, 720, 480, 16, 1, 90, 30, MD_SIS300|MD_SIS315}, + {"720x480x24", {0x35,0x35}, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30, MD_SIS300|MD_SIS315}, +/*30*/ {"720x480x32", {0x35,0x35}, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30, MD_SIS300|MD_SIS315}, + {"720x576x8", {0x32,0x32}, 0x0000, 0x0000, 720, 576, 8, 1, 90, 36, MD_SIS300|MD_SIS315}, + {"720x576x16", {0x34,0x34}, 0x0000, 0x0000, 720, 576, 16, 1, 90, 36, MD_SIS300|MD_SIS315}, + {"720x576x24", {0x36,0x36}, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36, MD_SIS300|MD_SIS315}, + {"720x576x32", {0x36,0x36}, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36, MD_SIS300|MD_SIS315}, + {"768x576x8", {0x5f,0x5f}, 0x0000, 0x0000, 768, 576, 8, 1, 96, 36, MD_SIS300|MD_SIS315}, + {"768x576x16", {0x60,0x60}, 0x0000, 0x0000, 768, 576, 16, 1, 96, 36, MD_SIS300|MD_SIS315}, + {"768x576x24", {0x61,0x61}, 0x0000, 0x0000, 768, 576, 32, 1, 96, 36, MD_SIS300|MD_SIS315}, + {"768x576x32", {0x61,0x61}, 0x0000, 0x0000, 768, 576, 32, 1, 96, 36, MD_SIS300|MD_SIS315}, + {"800x480x8", {0x70,0x70}, 0x0000, 0x0000, 800, 480, 8, 1, 100, 30, MD_SIS300|MD_SIS315}, +/*40*/ {"800x480x16", {0x7a,0x7a}, 0x0000, 0x0000, 800, 480, 16, 1, 100, 30, MD_SIS300|MD_SIS315}, + {"800x480x24", {0x76,0x76}, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30, MD_SIS300|MD_SIS315}, + {"800x480x32", {0x76,0x76}, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30, MD_SIS300|MD_SIS315}, +#define DEFAULT_MODE 43 /* index for 800x600x8 */ +#define DEFAULT_LCDMODE 43 /* index for 800x600x8 */ +#define DEFAULT_TVMODE 43 /* index for 800x600x8 */ + {"800x600x8", {0x30,0x30}, 0x0103, 0x0103, 800, 600, 8, 2, 100, 37, MD_SIS300|MD_SIS315}, + {"800x600x16", {0x47,0x47}, 0x0114, 0x0114, 800, 600, 16, 2, 100, 37, MD_SIS300|MD_SIS315}, + {"800x600x24", {0x63,0x63}, 0x013b, 0x0115, 800, 600, 32, 2, 100, 37, MD_SIS300|MD_SIS315}, + {"800x600x32", {0x63,0x63}, 0x013b, 0x0115, 800, 600, 32, 2, 100, 37, MD_SIS300|MD_SIS315}, + {"848x480x8", {0x39,0x39}, 0x0000, 0x0000, 848, 480, 8, 2, 106, 30, MD_SIS300|MD_SIS315}, + {"848x480x16", {0x3b,0x3b}, 0x0000, 0x0000, 848, 480, 16, 2, 106, 30, MD_SIS300|MD_SIS315}, + {"848x480x24", {0x3e,0x3e}, 0x0000, 0x0000, 848, 480, 32, 2, 106, 30, MD_SIS300|MD_SIS315}, +/*50*/ {"848x480x32", {0x3e,0x3e}, 0x0000, 0x0000, 848, 480, 32, 2, 106, 30, MD_SIS300|MD_SIS315}, + {"856x480x8", {0x3f,0x3f}, 0x0000, 0x0000, 856, 480, 8, 2, 107, 30, MD_SIS300|MD_SIS315}, + {"856x480x16", {0x42,0x42}, 0x0000, 0x0000, 856, 480, 16, 2, 107, 30, MD_SIS300|MD_SIS315}, + {"856x480x24", {0x45,0x45}, 0x0000, 0x0000, 856, 480, 32, 2, 107, 30, MD_SIS300|MD_SIS315}, + {"856x480x32", {0x45,0x45}, 0x0000, 0x0000, 856, 480, 32, 2, 107, 30, MD_SIS300|MD_SIS315}, + {"960x540x8", {0x1d,0x1d}, 0x0000, 0x0000, 960, 540, 8, 1, 120, 33, MD_SIS315}, + {"960x540x16", {0x1e,0x1e}, 0x0000, 0x0000, 960, 540, 16, 1, 120, 33, MD_SIS315}, + {"960x540x24", {0x1f,0x1f}, 0x0000, 0x0000, 960, 540, 32, 1, 120, 33, MD_SIS315}, + {"960x540x32", {0x1f,0x1f}, 0x0000, 0x0000, 960, 540, 32, 1, 120, 33, MD_SIS315}, + {"960x600x8", {0x20,0x20}, 0x0000, 0x0000, 960, 600, 8, 1, 120, 37, MD_SIS315}, +/*60*/ {"960x600x16", {0x21,0x21}, 0x0000, 0x0000, 960, 600, 16, 1, 120, 37, MD_SIS315}, + {"960x600x24", {0x22,0x22}, 0x0000, 0x0000, 960, 600, 32, 1, 120, 37, MD_SIS315}, + {"960x600x32", {0x22,0x22}, 0x0000, 0x0000, 960, 600, 32, 1, 120, 37, MD_SIS315}, + {"1024x576x8", {0x71,0x71}, 0x0000, 0x0000, 1024, 576, 8, 1, 128, 36, MD_SIS300|MD_SIS315}, + {"1024x576x16", {0x74,0x74}, 0x0000, 0x0000, 1024, 576, 16, 1, 128, 36, MD_SIS300|MD_SIS315}, + {"1024x576x24", {0x77,0x77}, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36, MD_SIS300|MD_SIS315}, + {"1024x576x32", {0x77,0x77}, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36, MD_SIS300|MD_SIS315}, + {"1024x600x8", {0x20,0x20}, 0x0000, 0x0000, 1024, 600, 8, 1, 128, 37, MD_SIS300 }, + {"1024x600x16", {0x21,0x21}, 0x0000, 0x0000, 1024, 600, 16, 1, 128, 37, MD_SIS300 }, + {"1024x600x24", {0x22,0x22}, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37, MD_SIS300 }, +/*70*/ {"1024x600x32", {0x22,0x22}, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37, MD_SIS300 }, + {"1024x768x8", {0x38,0x38}, 0x0105, 0x0105, 1024, 768, 8, 2, 128, 48, MD_SIS300|MD_SIS315}, + {"1024x768x16", {0x4a,0x4a}, 0x0117, 0x0117, 1024, 768, 16, 2, 128, 48, MD_SIS300|MD_SIS315}, + {"1024x768x24", {0x64,0x64}, 0x013c, 0x0118, 1024, 768, 32, 2, 128, 48, MD_SIS300|MD_SIS315}, + {"1024x768x32", {0x64,0x64}, 0x013c, 0x0118, 1024, 768, 32, 2, 128, 48, MD_SIS300|MD_SIS315}, + {"1152x768x8", {0x23,0x23}, 0x0000, 0x0000, 1152, 768, 8, 1, 144, 48, MD_SIS300 }, + {"1152x768x16", {0x24,0x24}, 0x0000, 0x0000, 1152, 768, 16, 1, 144, 48, MD_SIS300 }, + {"1152x768x24", {0x25,0x25}, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48, MD_SIS300 }, + {"1152x768x32", {0x25,0x25}, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48, MD_SIS300 }, + {"1152x864x8", {0x29,0x29}, 0x0000, 0x0000, 1152, 864, 8, 1, 144, 54, MD_SIS300|MD_SIS315}, +/*80*/ {"1152x864x16", {0x2a,0x2a}, 0x0000, 0x0000, 1152, 864, 16, 1, 144, 54, MD_SIS300|MD_SIS315}, + {"1152x864x24", {0x2b,0x2b}, 0x0000, 0x0000, 1152, 864, 32, 1, 144, 54, MD_SIS300|MD_SIS315}, + {"1152x864x32", {0x2b,0x2b}, 0x0000, 0x0000, 1152, 864, 32, 1, 144, 54, MD_SIS300|MD_SIS315}, + {"1280x720x8", {0x79,0x79}, 0x0000, 0x0000, 1280, 720, 8, 1, 160, 45, MD_SIS300|MD_SIS315}, + {"1280x720x16", {0x75,0x75}, 0x0000, 0x0000, 1280, 720, 16, 1, 160, 45, MD_SIS300|MD_SIS315}, + {"1280x720x24", {0x78,0x78}, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45, MD_SIS300|MD_SIS315}, + {"1280x720x32", {0x78,0x78}, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45, MD_SIS300|MD_SIS315}, + {"1280x768x8", {0x55,0x23}, 0x0000, 0x0000, 1280, 768, 8, 1, 160, 48, MD_SIS300|MD_SIS315}, + {"1280x768x16", {0x5a,0x24}, 0x0000, 0x0000, 1280, 768, 16, 1, 160, 48, MD_SIS300|MD_SIS315}, + {"1280x768x24", {0x5b,0x25}, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48, MD_SIS300|MD_SIS315}, +/*90*/ {"1280x768x32", {0x5b,0x25}, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48, MD_SIS300|MD_SIS315}, + {"1280x800x8", {0x14,0x14}, 0x0000, 0x0000, 1280, 800, 8, 1, 160, 50, MD_SIS315}, + {"1280x800x16", {0x15,0x15}, 0x0000, 0x0000, 1280, 800, 16, 1, 160, 50, MD_SIS315}, + {"1280x800x24", {0x16,0x16}, 0x0000, 0x0000, 1280, 800, 32, 1, 160, 50, MD_SIS315}, + {"1280x800x32", {0x16,0x16}, 0x0000, 0x0000, 1280, 800, 32, 1, 160, 50, MD_SIS315}, + {"1280x960x8", {0x7c,0x7c}, 0x0000, 0x0000, 1280, 960, 8, 1, 160, 60, MD_SIS300|MD_SIS315}, + {"1280x960x16", {0x7d,0x7d}, 0x0000, 0x0000, 1280, 960, 16, 1, 160, 60, MD_SIS300|MD_SIS315}, + {"1280x960x24", {0x7e,0x7e}, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, MD_SIS300|MD_SIS315}, + {"1280x960x32", {0x7e,0x7e}, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, MD_SIS300|MD_SIS315}, + {"1280x1024x8", {0x3a,0x3a}, 0x0107, 0x0107, 1280, 1024, 8, 2, 160, 64, MD_SIS300|MD_SIS315}, +/*100*/ {"1280x1024x16", {0x4d,0x4d}, 0x011a, 0x011a, 1280, 1024, 16, 2, 160, 64, MD_SIS300|MD_SIS315}, + {"1280x1024x24", {0x65,0x65}, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315}, + {"1280x1024x32", {0x65,0x65}, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315}, + {"1360x768x8", {0x48,0x48}, 0x0000, 0x0000, 1360, 768, 8, 1, 170, 48, MD_SIS300|MD_SIS315}, + {"1360x768x16", {0x4b,0x4b}, 0x0000, 0x0000, 1360, 768, 16, 1, 170, 48, MD_SIS300|MD_SIS315}, + {"1360x768x24", {0x4e,0x4e}, 0x0000, 0x0000, 1360, 768, 32, 1, 170, 48, MD_SIS300|MD_SIS315}, + {"1360x768x32", {0x4e,0x4e}, 0x0000, 0x0000, 1360, 768, 32, 1, 170, 48, MD_SIS300|MD_SIS315}, + {"1360x1024x8", {0x67,0x67}, 0x0000, 0x0000, 1360, 1024, 8, 1, 170, 64, MD_SIS300 }, + {"1360x1024x16", {0x6f,0x6f}, 0x0000, 0x0000, 1360, 1024, 16, 1, 170, 64, MD_SIS300 }, + {"1360x1024x24", {0x72,0x72}, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300 }, +/*110*/ {"1360x1024x32", {0x72,0x72}, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300 }, + {"1400x1050x8", {0x26,0x26}, 0x0000, 0x0000, 1400, 1050, 8, 1, 175, 65, MD_SIS315}, + {"1400x1050x16", {0x27,0x27}, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65, MD_SIS315}, + {"1400x1050x24", {0x28,0x28}, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65, MD_SIS315}, + {"1400x1050x32", {0x28,0x28}, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65, MD_SIS315}, + {"1600x1200x8", {0x3c,0x3c}, 0x0130, 0x011c, 1600, 1200, 8, 1, 200, 75, MD_SIS300|MD_SIS315}, + {"1600x1200x16", {0x3d,0x3d}, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_SIS300|MD_SIS315}, + {"1600x1200x24", {0x66,0x66}, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315}, + {"1600x1200x32", {0x66,0x66}, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315}, + {"1680x1050x8", {0x17,0x17}, 0x0000, 0x0000, 1680, 1050, 8, 1, 210, 65, MD_SIS315}, +/*120*/ {"1680x1050x16", {0x18,0x18}, 0x0000, 0x0000, 1680, 1050, 16, 1, 210, 65, MD_SIS315}, + {"1680x1050x24", {0x19,0x19}, 0x0000, 0x0000, 1680, 1050, 32, 1, 210, 65, MD_SIS315}, + {"1680x1050x32", {0x19,0x19}, 0x0000, 0x0000, 1680, 1050, 32, 1, 210, 65, MD_SIS315}, + {"1920x1080x8", {0x2c,0x2c}, 0x0000, 0x0000, 1920, 1080, 8, 1, 240, 67, MD_SIS315}, + {"1920x1080x16", {0x2d,0x2d}, 0x0000, 0x0000, 1920, 1080, 16, 1, 240, 67, MD_SIS315}, + {"1920x1080x24", {0x73,0x73}, 0x0000, 0x0000, 1920, 1080, 32, 1, 240, 67, MD_SIS315}, + {"1920x1080x32", {0x73,0x73}, 0x0000, 0x0000, 1920, 1080, 32, 1, 240, 67, MD_SIS315}, + {"1920x1440x8", {0x68,0x68}, 0x013f, 0x0000, 1920, 1440, 8, 1, 240, 75, MD_SIS300|MD_SIS315}, + {"1920x1440x16", {0x69,0x69}, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, MD_SIS300|MD_SIS315}, + {"1920x1440x24", {0x6b,0x6b}, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315}, +/*130*/ {"1920x1440x32", {0x6b,0x6b}, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315}, + {"2048x1536x8", {0x6c,0x6c}, 0x0000, 0x0000, 2048, 1536, 8, 1, 256, 96, MD_SIS315}, + {"2048x1536x16", {0x6d,0x6d}, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96, MD_SIS315}, + {"2048x1536x24", {0x6e,0x6e}, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96, MD_SIS315}, + {"2048x1536x32", {0x6e,0x6e}, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96, MD_SIS315}, + {"\0", {0x00,0x00}, 0, 0, 0, 0, 0, 0, 0} +}; + +#define SIS_LCD_NUMBER 17 +static const struct _sis_lcd_data { + u32 lcdtype; + u16 xres; + u16 yres; + u8 default_mode_idx; +} sis_lcd_data[] = { + { LCD_640x480, 640, 480, 23 }, + { LCD_800x600, 800, 600, 43 }, + { LCD_1024x600, 1024, 600, 67 }, + { LCD_1024x768, 1024, 768, 71 }, + { LCD_1152x768, 1152, 768, 75 }, + { LCD_1152x864, 1152, 864, 79 }, + { LCD_1280x720, 1280, 720, 83 }, + { LCD_1280x768, 1280, 768, 87 }, + { LCD_1280x800, 1280, 800, 91 }, + { LCD_1280x960, 1280, 960, 95 }, + { LCD_1280x1024, 1280, 1024, 99 }, + { LCD_1400x1050, 1400, 1050, 111 }, + { LCD_1680x1050, 1680, 1050, 119 }, + { LCD_1600x1200, 1600, 1200, 115 }, + { LCD_640x480_2, 640, 480, 23 }, + { LCD_640x480_3, 640, 480, 23 }, + { LCD_320x480, 320, 480, 9 }, +}; + +/* CR36 evaluation */ +static const USHORT sis300paneltype[] = + { LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, + LCD_1280x960, LCD_640x480, LCD_1024x600, LCD_1152x768, + LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN, + LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN }; + +static const USHORT sis310paneltype[] = + { LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, + LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960, + LCD_1152x768, LCD_1400x1050, LCD_1280x768, LCD_1600x1200, + LCD_640x480_2, LCD_640x480_3, LCD_UNKNOWN, LCD_UNKNOWN }; + +static const USHORT sis661paneltype[] = + { LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, + LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960, + LCD_1152x768, LCD_1400x1050, LCD_1280x768, LCD_1600x1200, + LCD_1280x800, LCD_1680x1050, LCD_1280x720, LCD_UNKNOWN }; + +#define FL_550_DSTN 0x01 +#define FL_550_FSTN 0x02 +#define FL_300 0x04 +#define FL_315 0x08 + +static struct _sis_crt2type { + char name[32]; + u32 type_no; + u32 tvplug_no; + u16 flags; +} sis_crt2type[] __initdata = { + {"NONE", 0, -1, FL_300|FL_315}, + {"LCD", CRT2_LCD, -1, FL_300|FL_315}, + {"TV", CRT2_TV, -1, FL_300|FL_315}, + {"VGA", CRT2_VGA, -1, FL_300|FL_315}, + {"SVIDEO", CRT2_TV, TV_SVIDEO, FL_300|FL_315}, + {"COMPOSITE", CRT2_TV, TV_AVIDEO, FL_300|FL_315}, + {"CVBS", CRT2_TV, TV_AVIDEO, FL_300|FL_315}, + {"SVIDEO+COMPOSITE", CRT2_TV, TV_AVIDEO|TV_SVIDEO, FL_300|FL_315}, + {"COMPOSITE+SVIDEO", CRT2_TV, TV_AVIDEO|TV_SVIDEO, FL_300|FL_315}, + {"SVIDEO+CVBS", CRT2_TV, TV_AVIDEO|TV_SVIDEO, FL_300|FL_315}, + {"CVBS+SVIDEO", CRT2_TV, TV_AVIDEO|TV_SVIDEO, FL_300|FL_315}, + {"SCART", CRT2_TV, TV_SCART, FL_300|FL_315}, + {"HIVISION", CRT2_TV, TV_HIVISION, FL_315}, + {"YPBPR480I", CRT2_TV, TV_YPBPR|TV_YPBPR525I, FL_315}, + {"YPBPR480P", CRT2_TV, TV_YPBPR|TV_YPBPR525P, FL_315}, + {"YPBPR720P", CRT2_TV, TV_YPBPR|TV_YPBPR750P, FL_315}, + {"YPBPR1080I", CRT2_TV, TV_YPBPR|TV_YPBPR1080I, FL_315}, + {"DSTN", CRT2_LCD, -1, FL_315|FL_550_DSTN}, + {"FSTN", CRT2_LCD, -1, FL_315|FL_550_FSTN}, + {"\0", -1, -1, 0} +}; + +/* TV standard */ +static struct _sis_tvtype { + char name[6]; + u32 type_no; +} sis_tvtype[] __initdata = { + {"PAL", TV_PAL}, + {"NTSC", TV_NTSC}, + {"PALM", TV_PAL|TV_PALM}, + {"PALN", TV_PAL|TV_PALN}, + {"NTSCJ", TV_NTSC|TV_NTSCJ}, + {"\0", -1} +}; + +static const struct _sis_vrate { + u16 idx; + u16 xres; + u16 yres; + u16 refresh; + BOOLEAN SiS730valid32bpp; +} sisfb_vrate[] = { + {1, 320, 200, 70, TRUE}, + {1, 320, 240, 60, TRUE}, + {1, 320, 480, 60, TRUE}, + {1, 400, 300, 60, TRUE}, + {1, 512, 384, 60, TRUE}, + {1, 640, 400, 72, TRUE}, + {1, 640, 480, 60, TRUE}, {2, 640, 480, 72, TRUE}, {3, 640, 480, 75, TRUE}, + {4, 640, 480, 85, TRUE}, {5, 640, 480, 100, TRUE}, {6, 640, 480, 120, TRUE}, + {7, 640, 480, 160, TRUE}, {8, 640, 480, 200, TRUE}, + {1, 720, 480, 60, TRUE}, + {1, 720, 576, 58, TRUE}, + {1, 768, 576, 58, TRUE}, + {1, 800, 480, 60, TRUE}, {2, 800, 480, 75, TRUE}, {3, 800, 480, 85, TRUE}, + {1, 800, 600, 56, TRUE}, {2, 800, 600, 60, TRUE}, {3, 800, 600, 72, TRUE}, + {4, 800, 600, 75, TRUE}, {5, 800, 600, 85, TRUE}, {6, 800, 600, 105, TRUE}, + {7, 800, 600, 120, TRUE}, {8, 800, 600, 160, TRUE}, + {1, 848, 480, 39, TRUE}, {2, 848, 480, 60, TRUE}, + {1, 856, 480, 39, TRUE}, {2, 856, 480, 60, TRUE}, + {1, 960, 540, 60, TRUE}, + {1, 960, 600, 60, TRUE}, + {1, 1024, 576, 60, TRUE}, {2, 1024, 576, 75, TRUE}, {3, 1024, 576, 85, TRUE}, + {1, 1024, 600, 60, TRUE}, + {1, 1024, 768, 43, TRUE}, {2, 1024, 768, 60, TRUE}, {3, 1024, 768, 70, FALSE}, + {4, 1024, 768, 75, FALSE}, {5, 1024, 768, 85, TRUE}, {6, 1024, 768, 100, TRUE}, + {7, 1024, 768, 120, TRUE}, + {1, 1152, 768, 60, TRUE}, + {1, 1152, 864, 60, TRUE}, {1, 1152, 864, 75, TRUE}, {2, 1152, 864, 84, TRUE}, + {1, 1280, 720, 60, TRUE}, {2, 1280, 720, 75, TRUE}, {3, 1280, 720, 85, TRUE}, + {1, 1280, 768, 60, TRUE}, + {1, 1280, 800, 60, TRUE}, + {1, 1280, 960, 60, TRUE}, {2, 1280, 960, 85, TRUE}, + {1, 1280, 1024, 43, TRUE}, {2, 1280, 1024, 60, TRUE}, {3, 1280, 1024, 75, TRUE}, + {4, 1280, 1024, 85, TRUE}, + {1, 1360, 768, 60, TRUE}, + {1, 1360, 1024, 59, TRUE}, + {1, 1400, 1050, 60, TRUE}, {2, 1400, 1050, 75, TRUE}, + {1, 1600, 1200, 60, TRUE}, {2, 1600, 1200, 65, TRUE}, {3, 1600, 1200, 70, TRUE}, + {4, 1600, 1200, 75, TRUE}, {5, 1600, 1200, 85, TRUE}, {6, 1600, 1200, 100, TRUE}, + {7, 1600, 1200, 120, TRUE}, + {1, 1680, 1050, 60, TRUE}, + {1, 1920, 1080, 30, TRUE}, + {1, 1920, 1440, 60, TRUE}, {2, 1920, 1440, 65, TRUE}, {3, 1920, 1440, 70, TRUE}, + {4, 1920, 1440, 75, TRUE}, {5, 1920, 1440, 85, TRUE}, {6, 1920, 1440, 100, TRUE}, + {1, 2048, 1536, 60, TRUE}, {2, 2048, 1536, 65, TRUE}, {3, 2048, 1536, 70, TRUE}, + {4, 2048, 1536, 75, TRUE}, {5, 2048, 1536, 85, TRUE}, + {0, 0, 0, 0, FALSE} +}; + +static const struct _sisfbddcsmodes { + u32 mask; + u16 h; + u16 v; + u32 d; +} sisfb_ddcsmodes[] = { + { 0x10000, 67, 75, 108000}, + { 0x08000, 48, 72, 50000}, + { 0x04000, 46, 75, 49500}, + { 0x01000, 35, 43, 44900}, + { 0x00800, 48, 60, 65000}, + { 0x00400, 56, 70, 75000}, + { 0x00200, 60, 75, 78800}, + { 0x00100, 80, 75, 135000}, + { 0x00020, 31, 60, 25200}, + { 0x00008, 38, 72, 31500}, + { 0x00004, 37, 75, 31500}, + { 0x00002, 35, 56, 36000}, + { 0x00001, 38, 60, 40000} +}; + +static const struct _sisfbddcfmodes { + u16 x; + u16 y; + u16 v; + u16 h; + u32 d; +} sisfb_ddcfmodes[] = { + { 1280, 1024, 85, 92, 157500}, + { 1600, 1200, 60, 75, 162000}, + { 1600, 1200, 65, 82, 175500}, + { 1600, 1200, 70, 88, 189000}, + { 1600, 1200, 75, 94, 202500}, + { 1600, 1200, 85, 107,229500}, + { 1920, 1440, 60, 90, 234000}, + { 1920, 1440, 75, 113,297000} +}; + +#ifdef CONFIG_FB_SIS_300 +static struct _chswtable { + u16 subsysVendor; + u16 subsysCard; + char *vendorName; + char *cardName; +} mychswtable[] __devinitdata = { + { 0x1631, 0x1002, "Mitachi", "0x1002" }, + { 0x1071, 0x7521, "Mitac" , "7521P" }, + { 0, 0, "" , "" } +}; +#endif + +static struct _customttable { + u16 chipID; + char *biosversion; + char *biosdate; + u32 bioschksum; + u16 biosFootprintAddr[5]; + u8 biosFootprintData[5]; + u16 pcisubsysvendor; + u16 pcisubsyscard; + char *vendorName; + char *cardName; + u32 SpecialID; + char *optionName; +} mycustomttable[] __devinitdata = { + { SIS_630, "2.00.07", "09/27/2002-13:38:25", + 0x3240A8, + { 0x220, 0x227, 0x228, 0x229, 0x0ee }, + { 0x01, 0xe3, 0x9a, 0x6a, 0xef }, + 0x1039, 0x6300, + "Barco", "iQ R200L/300/400", CUT_BARCO1366, "BARCO_1366" + }, + { SIS_630, "2.00.07", "09/27/2002-13:38:25", + 0x323FBD, + { 0x220, 0x227, 0x228, 0x229, 0x0ee }, + { 0x00, 0x5a, 0x64, 0x41, 0xef }, + 0x1039, 0x6300, + "Barco", "iQ G200L/300/400/500", CUT_BARCO1024, "BARCO_1024" + }, + { SIS_650, "", "", + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x0e11, 0x083c, + "Inventec (Compaq)", "3017cl/3045US", CUT_COMPAQ12802, "COMPAQ_1280" + }, + { SIS_650, "", "", + 0, + { 0x00c, 0, 0, 0, 0 }, + { 'e' , 0, 0, 0, 0 }, + 0x1558, 0x0287, + "Clevo", "L285/L287 (Version 1)", CUT_CLEVO1024, "CLEVO_L28X_1" + }, + { SIS_650, "", "", + 0, + { 0x00c, 0, 0, 0, 0 }, + { 'y' , 0, 0, 0, 0 }, + 0x1558, 0x0287, + "Clevo", "L285/L287 (Version 2)", CUT_CLEVO10242, "CLEVO_L28X_2" + }, + { SIS_650, "", "", + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1558, 0x0400, /* possibly 401 and 402 as well; not panelsize specific (?) */ + "Clevo", "D400S/D410S/D400H/D410H", CUT_CLEVO1400, "CLEVO_D4X0" + }, + { SIS_650, "", "", + 0, /* Shift LCD in LCD-via-CRT1 mode */ + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1558, 0x2263, + "Clevo", "D22ES/D27ES", CUT_UNIWILL1024, "CLEVO_D2X0ES" + }, + { SIS_650, "", "", + 0, /* Shift LCD in LCD-via-CRT1 mode */ + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1734, 0x101f, + "Uniwill", "N243S9", CUT_UNIWILL1024, "UNIWILL_N243S9" + }, + { SIS_650, "", "", + 0, /* Shift LCD in LCD-via-CRT1 mode */ + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1584, 0x5103, + "Uniwill", "N35BS1", CUT_UNIWILL10242, "UNIWILL_N35BS1" + }, + { SIS_650, "1.09.2c", "", /* Other versions, too? */ + 0, /* Shift LCD in LCD-via-CRT1 mode */ + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1019, 0x0f05, + "ECS", "A928", CUT_UNIWILL1024, "ECS_A928" + }, + { SIS_740, "1.11.27a", "", + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1043, 0x1612, + "Asus", "L3000D/L3500D", CUT_ASUSL3000D, "ASUS_L3X00" + }, + { SIS_650, "1.10.9k", "", + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1025, 0x0028, + "Acer", "Aspire 1700", CUT_ACER1280, "ACER_ASPIRE1700" + }, + { SIS_650, "1.10.7w", "", + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x14c0, 0x0012, + "Compal", "??? (V1)", CUT_COMPAL1400_1, "COMPAL_1400_1" + }, + { SIS_650, "1.10.7x", "", + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x14c0, 0x0012, + "Compal", "??? (V2)", CUT_COMPAL1400_2, "COMPAL_1400_2" + }, + { SIS_650, "1.10.8o", "", + 0, /* For EMI (unknown) */ + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1043, 0x1612, + "Asus", "A2H (V1)", CUT_ASUSA2H_1, "ASUS_A2H_1" + }, + { SIS_650, "1.10.8q", "", + 0, /* For EMI */ + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1043, 0x1612, + "Asus", "A2H (V2)", CUT_ASUSA2H_2, "ASUS_A2H_2" + }, + { 4321, "", "", /* never autodetected */ + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0, 0, + "Generic", "LVDS/Parallel 848x480", CUT_PANEL848, "PANEL848x480" + }, + { 0, "", "", + 0, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + 0, 0, + "", "", CUT_NONE, "" + } +}; + +static const struct _sis_TV_filter { + u8 filter[9][4]; +} sis_TV_filter[] = { + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_0 */ + {0x00,0xE0,0x10,0x60}, + {0x00,0xEE,0x10,0x44}, + {0x00,0xF4,0x10,0x38}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0x00,0x00,0x10,0x20}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_1 */ + {0x00,0xE0,0x10,0x60}, + {0x00,0xEE,0x10,0x44}, + {0x00,0xF4,0x10,0x38}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0x00,0x00,0x10,0x20}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_2 */ + {0xF5,0xEE,0x1B,0x44}, + {0xF8,0xF4,0x18,0x38}, + {0xEB,0x04,0x25,0x18}, + {0xF1,0x05,0x1F,0x16}, + {0xF6,0x06,0x1A,0x14}, + {0xFA,0x06,0x16,0x14}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_3 */ + {0xF1,0x04,0x1F,0x18}, + {0xEE,0x0D,0x22,0x06}, + {0xF7,0x06,0x19,0x14}, + {0xF4,0x0B,0x1C,0x0A}, + {0xFA,0x07,0x16,0x12}, + {0xF9,0x0A,0x17,0x0C}, + {0x00,0x07,0x10,0x12}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_4 - 320 */ + {0x00,0xE0,0x10,0x60}, + {0x00,0xEE,0x10,0x44}, + {0x00,0xF4,0x10,0x38}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0x00,0x00,0x10,0x20}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_5 - 640 */ + {0xF5,0xEE,0x1B,0x44}, + {0xF8,0xF4,0x18,0x38}, + {0xEB,0x04,0x25,0x18}, + {0xF1,0x05,0x1F,0x16}, + {0xF6,0x06,0x1A,0x14}, + {0xFA,0x06,0x16,0x14}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_6 - 720 */ + {0xEB,0x04,0x25,0x18}, + {0xE7,0x0E,0x29,0x04}, + {0xEE,0x0C,0x22,0x08}, + {0xF6,0x0B,0x1A,0x0A}, + {0xF9,0x0A,0x17,0x0C}, + {0xFC,0x0A,0x14,0x0C}, + {0x00,0x08,0x10,0x10}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_7 - 800 */ + {0xEC,0x02,0x24,0x1C}, + {0xF2,0x04,0x1E,0x18}, + {0xEB,0x15,0x25,0xF6}, + {0xF4,0x10,0x1C,0x00}, + {0xF8,0x0F,0x18,0x02}, + {0x00,0x04,0x10,0x18}, + {0x01,0x06,0x0F,0x14}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_0 */ + {0x00,0xE0,0x10,0x60}, + {0x00,0xEE,0x10,0x44}, + {0x00,0xF4,0x10,0x38}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0x00,0x00,0x10,0x20}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_1 */ + {0x00,0xE0,0x10,0x60}, + {0x00,0xEE,0x10,0x44}, + {0x00,0xF4,0x10,0x38}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0x00,0x00,0x10,0x20}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_2 */ + {0xF5,0xEE,0x1B,0x44}, + {0xF8,0xF4,0x18,0x38}, + {0xF1,0xF7,0x01,0x32}, + {0xF5,0xFB,0x1B,0x2A}, + {0xF9,0xFF,0x17,0x22}, + {0xFB,0x01,0x15,0x1E}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_3 */ + {0xF5,0xFB,0x1B,0x2A}, + {0xEE,0xFE,0x22,0x24}, + {0xF3,0x00,0x1D,0x20}, + {0xF9,0x03,0x17,0x1A}, + {0xFB,0x02,0x14,0x1E}, + {0xFB,0x04,0x15,0x18}, + {0x00,0x06,0x10,0x14}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_4 - 320 */ + {0x00,0xE0,0x10,0x60}, + {0x00,0xEE,0x10,0x44}, + {0x00,0xF4,0x10,0x38}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0x00,0x00,0x10,0x20}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_5 - 640 */ + {0xF5,0xEE,0x1B,0x44}, + {0xF8,0xF4,0x18,0x38}, + {0xF1,0xF7,0x1F,0x32}, + {0xF5,0xFB,0x1B,0x2A}, + {0xF9,0xFF,0x17,0x22}, + {0xFB,0x01,0x15,0x1E}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_6 - 720 */ + {0xF5,0xEE,0x1B,0x2A}, + {0xEE,0xFE,0x22,0x24}, + {0xF3,0x00,0x1D,0x20}, + {0xF9,0x03,0x17,0x1A}, + {0xFB,0x02,0x14,0x1E}, + {0xFB,0x04,0x15,0x18}, + {0x00,0x06,0x10,0x14}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_7 - 800 */ + {0xF5,0xEE,0x1B,0x44}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0xEB,0x05,0x25,0x16}, + {0xF1,0x05,0x1F,0x16}, + {0xFA,0x07,0x16,0x12}, + {0x00,0x07,0x10,0x12}, + {0xFF,0xFF,0xFF,0xFF} }} +}; + +/* ---------------------- Prototypes ------------------------- */ + +/* Interface used by the world */ +#ifndef MODULE +SISINITSTATIC int sisfb_setup(char *options); +#endif + +/* Interface to the low level console driver */ +SISINITSTATIC int sisfb_init(void); + + +/* fbdev routines */ +static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static int sisfb_get_fix(struct fb_fix_screeninfo *fix, + int con, + struct fb_info *info); +static int sisfb_get_var(struct fb_var_screeninfo *var, + int con, + struct fb_info *info); +static int sisfb_set_var(struct fb_var_screeninfo *var, + int con, + struct fb_info *info); +static void sisfb_crtc_to_var(struct sis_video_info *ivideo, + struct fb_var_screeninfo *var); +static int sisfb_get_cmap(struct fb_cmap *cmap, + int kspc, + int con, + struct fb_info *info); +static int sisfb_set_cmap(struct fb_cmap *cmap, + int kspc, + int con, + struct fb_info *info); +static int sisfb_update_var(int con, + struct fb_info *info); +static int sisfb_switch(int con, + struct fb_info *info); +static void sisfb_blank(int blank, + struct fb_info *info); +static void sisfb_set_disp(int con, + struct fb_var_screeninfo *var, + struct fb_info *info); +static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *fb_info); +static void sisfb_do_install_cmap(int con, + struct fb_info *info); +static int sisfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +static int sisfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + struct fb_info *info); +static int sisfb_set_par(struct fb_info *info); +static int sisfb_blank(int blank, + struct fb_info *info); +extern void fbcon_sis_fillrect(struct fb_info *info, + const struct fb_fillrect *rect); +extern void fbcon_sis_copyarea(struct fb_info *info, + const struct fb_copyarea *area); +extern int fbcon_sis_sync(struct fb_info *info); +#endif + +/* Internal 2D accelerator functions */ +extern int sisfb_initaccel(struct sis_video_info *ivideo); +extern void sisfb_syncaccel(struct sis_video_info *ivideo); + +/* Internal general routines */ +static void sisfb_search_mode(char *name, BOOLEAN quiet); +static int sisfb_validate_mode(struct sis_video_info *ivideo, int modeindex, u32 vbflags); +static u8 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, + int index); +static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info); +static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, + struct fb_info *info); +static void sisfb_pre_setmode(struct sis_video_info *ivideo); +static void sisfb_post_setmode(struct sis_video_info *ivideo); +static BOOLEAN sisfb_CheckVBRetrace(struct sis_video_info *ivideo); +static BOOLEAN sisfbcheckvretracecrt2(struct sis_video_info *ivideo); +static BOOLEAN sisfbcheckvretracecrt1(struct sis_video_info *ivideo); +static BOOLEAN sisfb_bridgeisslave(struct sis_video_info *ivideo); +static void sisfb_detect_VB_connect(struct sis_video_info *ivideo); +static void sisfb_get_VB_type(struct sis_video_info *ivideo); +static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val); +static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val); + +/* SiS-specific exported functions */ +void sis_malloc(struct sis_memreq *req); +void sis_free(u32 base); + +/* Internal heap routines */ +static int sisfb_heap_init(struct sis_video_info *ivideo); +static SIS_OH *sisfb_poh_new_node(void); +static SIS_OH *sisfb_poh_allocate(u32 size); +static void sisfb_delete_node(SIS_OH *poh); +static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh); +static SIS_OH *sisfb_poh_free(u32 base); +static void sisfb_free_node(SIS_OH *poh); + +/* Sensing routines */ +static void SiS_Sense30x(struct sis_video_info *ivideo); +static void SiS_SenseCh(struct sis_video_info *ivideo); + +/* Routines from init.c/init301.c */ +extern USHORT SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, + BOOLEAN FSTN, USHORT CustomT, int LCDwith, int LCDheight); +extern USHORT SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth); +extern USHORT SiS_GetModeID_VGA2(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth); + +extern void SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr); +extern BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo, USHORT ModeNo); +extern void SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable); +extern void SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable); + +extern BOOLEAN SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); + +extern BOOLEAN sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceExtension, + unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +extern int sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr, + PSIS_HW_INFO HwDeviceExtension, + unsigned char modeno, unsigned char rateindex); +extern int sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceExtension, + unsigned char modeno, unsigned char rateindex, + struct fb_var_screeninfo *var); +#endif + +/* Chrontel TV, DDC and DPMS functions */ +extern USHORT SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx); +extern void SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx); +extern USHORT SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempbx); +extern void SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempbx); +extern void SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh); +extern void SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime); +extern void SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo); +extern USHORT SiS_HandleDDC(SiS_Private *SiS_Pr, ULONG VBFlags, int VGAEngine, + USHORT adaptnum, USHORT DDCdatatype, unsigned char *buffer); +extern USHORT SiS_ReadDDC1Bit(SiS_Private *SiS_Pr); +extern void SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo); +extern void SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr); +extern void SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo); +extern void SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo); +#endif + + diff --git a/drivers/video/sis/vgatypes.h b/drivers/video/sis/vgatypes.h new file mode 100644 index 000000000000..507bba1a71b5 --- /dev/null +++ b/drivers/video/sis/vgatypes.h @@ -0,0 +1,242 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * General type definitions for universal mode switching modules + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _VGATYPES_ +#define _VGATYPES_ + +#ifdef LINUX_KERNEL /* We don't want the X driver to depend on kernel source */ +#include <linux/ioctl.h> +#include <linux/version.h> +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CHAR +typedef char CHAR; +#endif + +#ifndef SHORT +typedef short SHORT; +#endif + +#ifndef LONG +typedef long LONG; +#endif + +#ifndef UCHAR +typedef unsigned char UCHAR; +#endif + +#ifndef USHORT +typedef unsigned short USHORT; +#endif + +#ifndef ULONG +typedef unsigned long ULONG; +#endif + +#ifndef BOOLEAN +typedef unsigned char BOOLEAN; +#endif + +#define SISIOMEMTYPE + +#ifdef LINUX_KERNEL +typedef unsigned long SISIOADDRESS; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) +#include <linux/types.h> /* Need __iomem */ +#undef SISIOMEMTYPE +#define SISIOMEMTYPE __iomem +#endif +#endif + +#ifdef LINUX_XF86 +#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,0,0,0) +typedef unsigned long IOADDRESS; +typedef unsigned long SISIOADDRESS; +#else +typedef IOADDRESS SISIOADDRESS; +#endif +#endif + +enum _SIS_CHIP_TYPE { + SIS_VGALegacy = 0, + SIS_530, + SIS_OLD, + SIS_300, + SIS_630, + SIS_730, + SIS_540, + SIS_315H, /* SiS 310 */ + SIS_315, + SIS_315PRO, + SIS_550, + SIS_650, + SIS_740, + SIS_330, + SIS_661, + SIS_741, + SIS_660, + SIS_760, + SIS_761, + SIS_340, + MAX_SIS_CHIP +}; + +#ifndef SIS_HW_INFO +typedef struct _SIS_HW_INFO SIS_HW_INFO, *PSIS_HW_INFO; + +struct _SIS_HW_INFO +{ +#ifdef LINUX_XF86 + PCITAG PciTag; /* PCI Tag */ +#endif + + UCHAR *pjVirtualRomBase; /* ROM image */ + + BOOLEAN UseROM; /* Use the ROM image if provided */ + +#ifdef LINUX_KERNEL + UCHAR SISIOMEMTYPE *pjVideoMemoryAddress; + /* base virtual memory address */ + /* of Linear VGA memory */ + + ULONG ulVideoMemorySize; /* size, in bytes, of the memory on the board */ +#endif + + SISIOADDRESS ulIOAddress; /* base I/O address of VGA ports (0x3B0; relocated) */ + + UCHAR jChipType; /* Used to Identify SiS Graphics Chip */ + /* defined in the enum "SIS_CHIP_TYPE" (above or sisfb.h) */ + + UCHAR jChipRevision; /* Used to Identify SiS Graphics Chip Revision */ + + BOOLEAN bIntegratedMMEnabled;/* supporting integration MM enable */ +}; +#endif + +/* Addtional IOCTLs for communication sisfb <> X driver */ +/* If changing this, sisfb.h must also be changed (for sisfb) */ + +#ifdef LINUX_XF86 /* We don't want the X driver to depend on the kernel source */ + +/* ioctl for identifying and giving some info (esp. memory heap start) */ +#define SISFB_GET_INFO_SIZE 0x8004f300 +#define SISFB_GET_INFO 0x8000f301 /* Must be patched with result from ..._SIZE at D[29:16] */ +/* deprecated ioctl number (for older versions of sisfb) */ +#define SISFB_GET_INFO_OLD 0x80046ef8 + +/* ioctls for tv parameters (position) */ +#define SISFB_SET_TVPOSOFFSET 0x4004f304 + +/* lock sisfb from register access */ +#define SISFB_SET_LOCK 0x4004f306 + +/* Structure argument for SISFB_GET_INFO ioctl */ +typedef struct _SISFB_INFO sisfb_info, *psisfb_info; + +struct _SISFB_INFO { + CARD32 sisfb_id; /* for identifying sisfb */ +#ifndef SISFB_ID +#define SISFB_ID 0x53495346 /* Identify myself with 'SISF' */ +#endif + CARD32 chip_id; /* PCI ID of detected chip */ + CARD32 memory; /* video memory in KB which sisfb manages */ + CARD32 heapstart; /* heap start (= sisfb "mem" argument) in KB */ + CARD8 fbvidmode; /* current sisfb mode */ + + CARD8 sisfb_version; + CARD8 sisfb_revision; + CARD8 sisfb_patchlevel; + + CARD8 sisfb_caps; /* sisfb's capabilities */ + + CARD32 sisfb_tqlen; /* turbo queue length (in KB) */ + + CARD32 sisfb_pcibus; /* The card's PCI ID */ + CARD32 sisfb_pcislot; + CARD32 sisfb_pcifunc; + + CARD8 sisfb_lcdpdc; + + CARD8 sisfb_lcda; + + CARD32 sisfb_vbflags; + CARD32 sisfb_currentvbflags; + + CARD32 sisfb_scalelcd; + CARD32 sisfb_specialtiming; + + CARD8 sisfb_haveemi; + CARD8 sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33; + CARD8 sisfb_haveemilcd; + + CARD8 sisfb_lcdpdca; + + CARD16 sisfb_tvxpos, sisfb_tvypos; /* Warning: Values + 32 ! */ + + CARD8 reserved[208]; /* for future use */ +}; +#endif + +#endif + diff --git a/drivers/video/sis/vstruct.h b/drivers/video/sis/vstruct.h new file mode 100644 index 000000000000..d4d55c98bce6 --- /dev/null +++ b/drivers/video/sis/vstruct.h @@ -0,0 +1,676 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * General structure definitions for universal mode switching modules + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _VSTRUCT_ +#define _VSTRUCT_ + +typedef struct _SiS_PanelDelayTblStruct +{ + UCHAR timer[2]; +} SiS_PanelDelayTblStruct; + +typedef struct _SiS_LCDDataStruct +{ + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS_LCDDataStruct; + +typedef struct _SiS_TVDataStruct +{ + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT TVHDE; + USHORT TVVDE; + USHORT RVBHRS; + UCHAR FlickerMode; + USHORT HALFRVBHRS; + UCHAR RY1COE; + UCHAR RY2COE; + UCHAR RY3COE; + UCHAR RY4COE; +} SiS_TVDataStruct; + +typedef struct _SiS_LVDSDataStruct +{ + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS_LVDSDataStruct; + +typedef struct _SiS_LVDSDesStruct +{ + USHORT LCDHDES; + USHORT LCDVDES; +} SiS_LVDSDesStruct; + +typedef struct _SiS_LVDSCRT1DataStruct +{ + UCHAR CR[15]; +} SiS_LVDSCRT1DataStruct; + +typedef struct _SiS_LCDACRT1DataStruct +{ + UCHAR CR[17]; +} SiS_LCDACRT1DataStruct; + +typedef struct _SiS_CHTVRegDataStruct +{ + UCHAR Reg[16]; +} SiS_CHTVRegDataStruct; + +typedef struct _SiS_StStruct +{ + UCHAR St_ModeID; + USHORT St_ModeFlag; + UCHAR St_StTableIndex; + UCHAR St_CRT2CRTC; + UCHAR St_ResInfo; + UCHAR VB_StTVFlickerIndex; + UCHAR VB_StTVEdgeIndex; + UCHAR VB_StTVYFilterIndex; + UCHAR St_PDC; +} SiS_StStruct; + +typedef struct _SiS_VBModeStruct +{ + UCHAR ModeID; + UCHAR VB_TVDelayIndex; + UCHAR VB_TVFlickerIndex; + UCHAR VB_TVPhaseIndex; + UCHAR VB_TVYFilterIndex; + UCHAR VB_LCDDelayIndex; + UCHAR _VB_LCDHIndex; + UCHAR _VB_LCDVIndex; +} SiS_VBModeStruct; + +typedef struct _SiS_StandTableStruct +{ + UCHAR CRT_COLS; + UCHAR ROWS; + UCHAR CHAR_HEIGHT; + USHORT CRT_LEN; + UCHAR SR[4]; + UCHAR MISC; + UCHAR CRTC[0x19]; + UCHAR ATTR[0x14]; + UCHAR GRC[9]; +} SiS_StandTableStruct; + +typedef struct _SiS_ExtStruct +{ + UCHAR Ext_ModeID; + USHORT Ext_ModeFlag; + USHORT Ext_VESAID; + UCHAR Ext_RESINFO; + UCHAR VB_ExtTVFlickerIndex; + UCHAR VB_ExtTVEdgeIndex; + UCHAR VB_ExtTVYFilterIndex; + UCHAR VB_ExtTVYFilterIndexROM661; + UCHAR REFindex; + CHAR ROMMODEIDX661; +} SiS_ExtStruct; + +typedef struct _SiS_Ext2Struct +{ + USHORT Ext_InfoFlag; + UCHAR Ext_CRT1CRTC; + UCHAR Ext_CRTVCLK; + UCHAR Ext_CRT2CRTC; + UCHAR Ext_CRT2CRTC_NS; + UCHAR ModeID; + USHORT XRes; + USHORT YRes; + UCHAR Ext_PDC; +} SiS_Ext2Struct; + +typedef struct _SiS_Part2PortTblStruct +{ + UCHAR CR[12]; +} SiS_Part2PortTblStruct; + +typedef struct _SiS_CRT1TableStruct +{ + UCHAR CR[17]; +} SiS_CRT1TableStruct; + +typedef struct _SiS_MCLKDataStruct +{ + UCHAR SR28,SR29,SR2A; + USHORT CLOCK; +} SiS_MCLKDataStruct; + +typedef struct _SiS_VCLKDataStruct +{ + UCHAR SR2B,SR2C; + USHORT CLOCK; +} SiS_VCLKDataStruct; + +typedef struct _SiS_VBVCLKDataStruct +{ + UCHAR Part4_A,Part4_B; + USHORT CLOCK; +} SiS_VBVCLKDataStruct; + +typedef struct _SiS_StResInfoStruct +{ + USHORT HTotal; + USHORT VTotal; +} SiS_StResInfoStruct; + +typedef struct _SiS_ModeResInfoStruct +{ + USHORT HTotal; + USHORT VTotal; + UCHAR XChar; + UCHAR YChar; +} SiS_ModeResInfoStruct; + + + +typedef UCHAR DRAM4Type[4]; + +/* Defines for SiS_CustomT */ +/* Never change these for sisfb compatibility */ +#define CUT_NONE 0 +#define CUT_FORCENONE 1 +#define CUT_BARCO1366 2 +#define CUT_BARCO1024 3 +#define CUT_COMPAQ1280 4 +#define CUT_COMPAQ12802 5 +#define CUT_PANEL848 6 +#define CUT_CLEVO1024 7 +#define CUT_CLEVO10242 8 +#define CUT_CLEVO1400 9 +#define CUT_CLEVO14002 10 +#define CUT_UNIWILL1024 11 +#define CUT_ASUSL3000D 12 +#define CUT_UNIWILL10242 13 +#define CUT_ACER1280 14 +#define CUT_COMPAL1400_1 15 +#define CUT_COMPAL1400_2 16 +#define CUT_ASUSA2H_1 17 +#define CUT_ASUSA2H_2 18 + +typedef struct _SiS_Private +{ +#ifdef LINUX_KERNEL + SISIOADDRESS RelIO; +#endif + SISIOADDRESS SiS_P3c4; + SISIOADDRESS SiS_P3d4; + SISIOADDRESS SiS_P3c0; + SISIOADDRESS SiS_P3ce; + SISIOADDRESS SiS_P3c2; + SISIOADDRESS SiS_P3ca; + SISIOADDRESS SiS_P3c6; + SISIOADDRESS SiS_P3c7; + SISIOADDRESS SiS_P3c8; + SISIOADDRESS SiS_P3c9; + SISIOADDRESS SiS_P3cb; + SISIOADDRESS SiS_P3cd; + SISIOADDRESS SiS_P3da; + SISIOADDRESS SiS_Part1Port; + SISIOADDRESS SiS_Part2Port; + SISIOADDRESS SiS_Part3Port; + SISIOADDRESS SiS_Part4Port; + SISIOADDRESS SiS_Part5Port; + SISIOADDRESS SiS_VidCapt; + SISIOADDRESS SiS_VidPlay; + USHORT SiS_IF_DEF_LVDS; + USHORT SiS_IF_DEF_CH70xx; + USHORT SiS_IF_DEF_CONEX; + USHORT SiS_IF_DEF_TRUMPION; + USHORT SiS_IF_DEF_DSTN; + USHORT SiS_IF_DEF_FSTN; + USHORT SiS_SysFlags; + UCHAR SiS_VGAINFO; +#ifdef LINUX_XF86 + USHORT SiS_CP1, SiS_CP2, SiS_CP3, SiS_CP4; +#endif + BOOLEAN SiS_UseROM; + BOOLEAN SiS_ROMNew; + BOOLEAN SiS_NeedRomModeData; + BOOLEAN PanelSelfDetected; + int SiS_CHOverScan; + BOOLEAN SiS_CHSOverScan; + BOOLEAN SiS_ChSW; + BOOLEAN SiS_UseLCDA; + int SiS_UseOEM; + ULONG SiS_CustomT; + USHORT SiS_Backup70xx; + BOOLEAN HaveEMI; + BOOLEAN HaveEMILCD; + BOOLEAN OverruleEMI; + UCHAR EMI_30,EMI_31,EMI_32,EMI_33; + USHORT SiS_EMIOffset; + SHORT PDC, PDCA; + UCHAR SiS_MyCR63; + USHORT SiS_CRT1Mode; + USHORT SiS_flag_clearbuffer; + int SiS_RAMType; + UCHAR SiS_ChannelAB; + UCHAR SiS_DataBusWidth; + USHORT SiS_ModeType; + USHORT SiS_VBInfo; + USHORT SiS_TVMode; + USHORT SiS_LCDResInfo; + USHORT SiS_LCDTypeInfo; + USHORT SiS_LCDInfo; + USHORT SiS_LCDInfo661; + USHORT SiS_VBType; + USHORT SiS_VBExtInfo; + USHORT SiS_YPbPr; + USHORT SiS_SelectCRT2Rate; + USHORT SiS_SetFlag; + USHORT SiS_RVBHCFACT; + USHORT SiS_RVBHCMAX; + USHORT SiS_RVBHRS; + USHORT SiS_VGAVT; + USHORT SiS_VGAHT; + USHORT SiS_VT; + USHORT SiS_HT; + USHORT SiS_VGAVDE; + USHORT SiS_VGAHDE; + USHORT SiS_VDE; + USHORT SiS_HDE; + USHORT SiS_NewFlickerMode; + USHORT SiS_RY1COE; + USHORT SiS_RY2COE; + USHORT SiS_RY3COE; + USHORT SiS_RY4COE; + USHORT SiS_LCDHDES; + USHORT SiS_LCDVDES; + USHORT SiS_DDC_Port; + USHORT SiS_DDC_Index; + USHORT SiS_DDC_Data; + USHORT SiS_DDC_NData; + USHORT SiS_DDC_Clk; + USHORT SiS_DDC_NClk; + USHORT SiS_DDC_DeviceAddr; + USHORT SiS_DDC_ReadAddr; + USHORT SiS_DDC_SecAddr; + USHORT SiS_ChrontelInit; + BOOLEAN SiS_SensibleSR11; + USHORT SiS661LCD2TableSize; + + USHORT SiS_PanelMinLVDS; + USHORT SiS_PanelMin301; + + const SiS_StStruct *SiS_SModeIDTable; + const SiS_StandTableStruct *SiS_StandTable; + const SiS_ExtStruct *SiS_EModeIDTable; + const SiS_Ext2Struct *SiS_RefIndex; + const SiS_VBModeStruct *SiS_VBModeIDTable; + const SiS_CRT1TableStruct *SiS_CRT1Table; + const SiS_MCLKDataStruct *SiS_MCLKData_0; + const SiS_MCLKDataStruct *SiS_MCLKData_1; + SiS_VCLKDataStruct *SiS_VCLKData; + SiS_VBVCLKDataStruct *SiS_VBVCLKData; + const SiS_StResInfoStruct *SiS_StResInfo; + const SiS_ModeResInfoStruct *SiS_ModeResInfo; + + const UCHAR *pSiS_OutputSelect; + const UCHAR *pSiS_SoftSetting; + + const DRAM4Type *SiS_SR15; /* pointer : point to array */ +#ifdef LINUX_KERNEL + UCHAR *pSiS_SR07; + const DRAM4Type *SiS_CR40; /* pointer : point to array */ + UCHAR *SiS_CR49; + UCHAR *SiS_SR25; + UCHAR *pSiS_SR1F; + UCHAR *pSiS_SR21; + UCHAR *pSiS_SR22; + UCHAR *pSiS_SR23; + UCHAR *pSiS_SR24; + UCHAR *pSiS_SR31; + UCHAR *pSiS_SR32; + UCHAR *pSiS_SR33; + UCHAR *pSiS_CRT2Data_1_2; + UCHAR *pSiS_CRT2Data_4_D; + UCHAR *pSiS_CRT2Data_4_E; + UCHAR *pSiS_CRT2Data_4_10; + const USHORT *pSiS_RGBSenseData; + const USHORT *pSiS_VideoSenseData; + const USHORT *pSiS_YCSenseData; + const USHORT *pSiS_RGBSenseData2; + const USHORT *pSiS_VideoSenseData2; + const USHORT *pSiS_YCSenseData2; +#endif + + const SiS_PanelDelayTblStruct *SiS_PanelDelayTbl; + const SiS_PanelDelayTblStruct *SiS_PanelDelayTblLVDS; + + /* SiS bridge */ + + const UCHAR *SiS_NTSCPhase; + const UCHAR *SiS_PALPhase; + const UCHAR *SiS_NTSCPhase2; + const UCHAR *SiS_PALPhase2; + const UCHAR *SiS_PALMPhase; + const UCHAR *SiS_PALNPhase; + const UCHAR *SiS_PALMPhase2; + const UCHAR *SiS_PALNPhase2; + const UCHAR *SiS_SpecialPhase; + const UCHAR *SiS_SpecialPhaseM; + const UCHAR *SiS_SpecialPhaseJ; + const SiS_LCDDataStruct *SiS_ExtLCD1024x768Data; + const SiS_LCDDataStruct *SiS_St2LCD1024x768Data; + const SiS_LCDDataStruct *SiS_LCD1280x720Data; + const SiS_LCDDataStruct *SiS_StLCD1280x768_2Data; + const SiS_LCDDataStruct *SiS_ExtLCD1280x768_2Data; + const SiS_LCDDataStruct *SiS_LCD1280x800Data; + const SiS_LCDDataStruct *SiS_LCD1280x800_2Data; + const SiS_LCDDataStruct *SiS_LCD1280x960Data; + const SiS_LCDDataStruct *SiS_ExtLCD1280x1024Data; + const SiS_LCDDataStruct *SiS_St2LCD1280x1024Data; + const SiS_LCDDataStruct *SiS_StLCD1400x1050Data; + const SiS_LCDDataStruct *SiS_ExtLCD1400x1050Data; + const SiS_LCDDataStruct *SiS_StLCD1600x1200Data; + const SiS_LCDDataStruct *SiS_ExtLCD1600x1200Data; + const SiS_LCDDataStruct *SiS_LCD1680x1050Data; + const SiS_LCDDataStruct *SiS_NoScaleData; + const SiS_TVDataStruct *SiS_StPALData; + const SiS_TVDataStruct *SiS_ExtPALData; + const SiS_TVDataStruct *SiS_StNTSCData; + const SiS_TVDataStruct *SiS_ExtNTSCData; + const SiS_TVDataStruct *SiS_St1HiTVData; + const SiS_TVDataStruct *SiS_St2HiTVData; + const SiS_TVDataStruct *SiS_ExtHiTVData; + const SiS_TVDataStruct *SiS_St525iData; + const SiS_TVDataStruct *SiS_St525pData; + const SiS_TVDataStruct *SiS_St750pData; + const SiS_TVDataStruct *SiS_Ext525iData; + const SiS_TVDataStruct *SiS_Ext525pData; + const SiS_TVDataStruct *SiS_Ext750pData; + const UCHAR *SiS_NTSCTiming; + const UCHAR *SiS_PALTiming; + const UCHAR *SiS_HiTVExtTiming; + const UCHAR *SiS_HiTVSt1Timing; + const UCHAR *SiS_HiTVSt2Timing; + const UCHAR *SiS_HiTVGroup3Data; + const UCHAR *SiS_HiTVGroup3Simu; +#if 0 + const UCHAR *SiS_HiTVTextTiming; + const UCHAR *SiS_HiTVGroup3Text; +#endif + + const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_1; + const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_1; + const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_2; + const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_2; + const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_3; + const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_3; + + /* LVDS, Chrontel */ + + const SiS_LVDSDataStruct *SiS_LVDS800x600Data_1; + const SiS_LVDSDataStruct *SiS_LVDS800x600Data_2; + const SiS_LVDSDataStruct *SiS_LVDS1024x768Data_1; + const SiS_LVDSDataStruct *SiS_LVDS1024x768Data_2; + const SiS_LVDSDataStruct *SiS_LVDS1280x1024Data_1; + const SiS_LVDSDataStruct *SiS_LVDS1280x1024Data_2; + const SiS_LVDSDataStruct *SiS_LVDS1280x960Data_1; + const SiS_LVDSDataStruct *SiS_LVDS1280x960Data_2; + const SiS_LVDSDataStruct *SiS_LVDS1400x1050Data_1; + const SiS_LVDSDataStruct *SiS_LVDS1400x1050Data_2; + const SiS_LVDSDataStruct *SiS_LVDS1600x1200Data_1; + const SiS_LVDSDataStruct *SiS_LVDS1600x1200Data_2; + const SiS_LVDSDataStruct *SiS_LVDS1280x768Data_1; + const SiS_LVDSDataStruct *SiS_LVDS1280x768Data_2; + const SiS_LVDSDataStruct *SiS_LVDS1024x600Data_1; + const SiS_LVDSDataStruct *SiS_LVDS1024x600Data_2; + const SiS_LVDSDataStruct *SiS_LVDS1152x768Data_1; + const SiS_LVDSDataStruct *SiS_LVDS1152x768Data_2; + const SiS_LVDSDataStruct *SiS_LVDS640x480Data_1; + const SiS_LVDSDataStruct *SiS_LVDS640x480Data_2; + const SiS_LVDSDataStruct *SiS_LVDS320x480Data_1; + const SiS_LVDSDataStruct *SiS_LVDSXXXxXXXData_1; + const SiS_LVDSDataStruct *SiS_LVDSBARCO1366Data_1; + const SiS_LVDSDataStruct *SiS_LVDSBARCO1366Data_2; + const SiS_LVDSDataStruct *SiS_LVDSBARCO1024Data_1; + const SiS_LVDSDataStruct *SiS_LVDSBARCO1024Data_2; + const SiS_LVDSDataStruct *SiS_LVDS848x480Data_1; + const SiS_LVDSDataStruct *SiS_LVDS848x480Data_2; + const SiS_LVDSDataStruct *SiS_CHTVUNTSCData; + const SiS_LVDSDataStruct *SiS_CHTVONTSCData; + const SiS_LVDSDataStruct *SiS_CHTVUPALData; + const SiS_LVDSDataStruct *SiS_CHTVOPALData; + const SiS_LVDSDataStruct *SiS_CHTVUPALMData; + const SiS_LVDSDataStruct *SiS_CHTVOPALMData; + const SiS_LVDSDataStruct *SiS_CHTVUPALNData; + const SiS_LVDSDataStruct *SiS_CHTVOPALNData; + const SiS_LVDSDataStruct *SiS_CHTVSOPALData; + + const SiS_LVDSDesStruct *SiS_PanelType00_1; + const SiS_LVDSDesStruct *SiS_PanelType01_1; + const SiS_LVDSDesStruct *SiS_PanelType02_1; + const SiS_LVDSDesStruct *SiS_PanelType03_1; + const SiS_LVDSDesStruct *SiS_PanelType04_1; + const SiS_LVDSDesStruct *SiS_PanelType05_1; + const SiS_LVDSDesStruct *SiS_PanelType06_1; + const SiS_LVDSDesStruct *SiS_PanelType07_1; + const SiS_LVDSDesStruct *SiS_PanelType08_1; + const SiS_LVDSDesStruct *SiS_PanelType09_1; + const SiS_LVDSDesStruct *SiS_PanelType0a_1; + const SiS_LVDSDesStruct *SiS_PanelType0b_1; + const SiS_LVDSDesStruct *SiS_PanelType0c_1; + const SiS_LVDSDesStruct *SiS_PanelType0d_1; + const SiS_LVDSDesStruct *SiS_PanelType0e_1; + const SiS_LVDSDesStruct *SiS_PanelType0f_1; + const SiS_LVDSDesStruct *SiS_PanelTypeNS_1; + const SiS_LVDSDesStruct *SiS_PanelType00_2; + const SiS_LVDSDesStruct *SiS_PanelType01_2; + const SiS_LVDSDesStruct *SiS_PanelType02_2; + const SiS_LVDSDesStruct *SiS_PanelType03_2; + const SiS_LVDSDesStruct *SiS_PanelType04_2; + const SiS_LVDSDesStruct *SiS_PanelType05_2; + const SiS_LVDSDesStruct *SiS_PanelType06_2; + const SiS_LVDSDesStruct *SiS_PanelType07_2; + const SiS_LVDSDesStruct *SiS_PanelType08_2; + const SiS_LVDSDesStruct *SiS_PanelType09_2; + const SiS_LVDSDesStruct *SiS_PanelType0a_2; + const SiS_LVDSDesStruct *SiS_PanelType0b_2; + const SiS_LVDSDesStruct *SiS_PanelType0c_2; + const SiS_LVDSDesStruct *SiS_PanelType0d_2; + const SiS_LVDSDesStruct *SiS_PanelType0e_2; + const SiS_LVDSDesStruct *SiS_PanelType0f_2; + const SiS_LVDSDesStruct *SiS_PanelTypeNS_2; + const SiS_LVDSDesStruct *SiS_CHTVUNTSCDesData; + const SiS_LVDSDesStruct *SiS_CHTVONTSCDesData; + const SiS_LVDSDesStruct *SiS_CHTVUPALDesData; + const SiS_LVDSDesStruct *SiS_CHTVOPALDesData; + + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_1; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_1; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_1; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11400x1050_1; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x768_1; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x600_1; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11152x768_1; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11600x1200_1; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_1_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_1_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_1_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11400x1050_1_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x768_1_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x600_1_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11152x768_1_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11600x1200_1_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_2; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_2; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_2; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11400x1050_2; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x768_2; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x600_2; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11152x768_2; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11600x1200_2; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_2_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_2_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_2_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11400x1050_2_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x768_2_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x600_2_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11152x768_2_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11600x1200_2_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1XXXxXXX_1; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1XXXxXXX_1_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_1; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_1_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_2; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_2_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_3; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_3_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1320x480_1; + const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1UNTSC; + const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1ONTSC; + const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1UPAL; + const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1OPAL; + const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1SOPAL; + + const SiS_CHTVRegDataStruct *SiS_CHTVReg_UNTSC; + const SiS_CHTVRegDataStruct *SiS_CHTVReg_ONTSC; + const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPAL; + const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPAL; + const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPALM; + const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPALM; + const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPALN; + const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPALN; + const SiS_CHTVRegDataStruct *SiS_CHTVReg_SOPAL; + + const UCHAR *SiS_CHTVVCLKUNTSC; + const UCHAR *SiS_CHTVVCLKONTSC; + const UCHAR *SiS_CHTVVCLKUPAL; + const UCHAR *SiS_CHTVVCLKOPAL; + const UCHAR *SiS_CHTVVCLKUPALM; + const UCHAR *SiS_CHTVVCLKOPALM; + const UCHAR *SiS_CHTVVCLKUPALN; + const UCHAR *SiS_CHTVVCLKOPALN; + const UCHAR *SiS_CHTVVCLKSOPAL; + + USHORT PanelXRes, PanelHT; + USHORT PanelYRes, PanelVT; + USHORT PanelHRS, PanelHRE; + USHORT PanelVRS, PanelVRE; + USHORT PanelVCLKIdx300; + USHORT PanelVCLKIdx315; + + BOOLEAN UseCustomMode; + BOOLEAN CRT1UsesCustomMode; + USHORT CHDisplay; + USHORT CHSyncStart; + USHORT CHSyncEnd; + USHORT CHTotal; + USHORT CHBlankStart; + USHORT CHBlankEnd; + USHORT CVDisplay; + USHORT CVSyncStart; + USHORT CVSyncEnd; + USHORT CVTotal; + USHORT CVBlankStart; + USHORT CVBlankEnd; + ULONG CDClock; + ULONG CFlags; + UCHAR CCRT1CRTC[17]; + UCHAR CSR2B; + UCHAR CSR2C; + USHORT CSRClock; + USHORT CSRClock_CRT1; + USHORT CModeFlag; + USHORT CModeFlag_CRT1; + USHORT CInfoFlag; + + int LVDSHL; + + BOOLEAN Backup; + UCHAR Backup_Mode; + UCHAR Backup_14; + UCHAR Backup_15; + UCHAR Backup_16; + UCHAR Backup_17; + UCHAR Backup_18; + UCHAR Backup_19; + UCHAR Backup_1a; + UCHAR Backup_1b; + UCHAR Backup_1c; + UCHAR Backup_1d; + + int UsePanelScaler; + int CenterScreen; + + USHORT CP_Vendor, CP_Product; + BOOLEAN CP_HaveCustomData; + int CP_PreferredX, CP_PreferredY, CP_PreferredIndex; + int CP_MaxX, CP_MaxY, CP_MaxClock; + UCHAR CP_PrefSR2B, CP_PrefSR2C; + USHORT CP_PrefClock; + BOOLEAN CP_Supports64048075; + int CP_HDisplay[7], CP_VDisplay[7]; /* For Custom LCD panel dimensions */ + int CP_HTotal[7], CP_VTotal[7]; + int CP_HSyncStart[7], CP_VSyncStart[7]; + int CP_HSyncEnd[7], CP_VSyncEnd[7]; + int CP_HBlankStart[7], CP_VBlankStart[7]; + int CP_HBlankEnd[7], CP_VBlankEnd[7]; + int CP_Clock[7]; + BOOLEAN CP_DataValid[7]; + BOOLEAN CP_HSync_P[7], CP_VSync_P[7], CP_SyncValid[7]; +} SiS_Private; + +#endif + diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c new file mode 100644 index 000000000000..7b43716ab665 --- /dev/null +++ b/drivers/video/skeletonfb.c @@ -0,0 +1,684 @@ +/* + * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device + * + * Modified to new api Jan 2001 by James Simmons (jsimmons@transvirtual.com) + * + * Created 28 Dec 1997 by Geert Uytterhoeven + * + * + * I have started rewriting this driver as a example of the upcoming new API + * The primary goal is to remove the console code from fbdev and place it + * into fbcon.c. This reduces the code and makes writing a new fbdev driver + * easy since the author doesn't need to worry about console internals. It + * also allows the ability to run fbdev without a console/tty system on top + * of it. + * + * First the roles of struct fb_info and struct display have changed. Struct + * display will go away. The way the the new framebuffer console code will + * work is that it will act to translate data about the tty/console in + * struct vc_data to data in a device independent way in struct fb_info. Then + * various functions in struct fb_ops will be called to store the device + * dependent state in the par field in struct fb_info and to change the + * hardware to that state. This allows a very clean separation of the fbdev + * layer from the console layer. It also allows one to use fbdev on its own + * which is a bounus for embedded devices. The reason this approach works is + * for each framebuffer device when used as a tty/console device is allocated + * a set of virtual terminals to it. Only one virtual terminal can be active + * per framebuffer device. We already have all the data we need in struct + * vc_data so why store a bunch of colormaps and other fbdev specific data + * per virtual terminal. + * + * As you can see doing this makes the con parameter pretty much useless + * for struct fb_ops functions, as it should be. Also having struct + * fb_var_screeninfo and other data in fb_info pretty much eliminates the + * need for get_fix and get_var. Once all drivers use the fix, var, and cmap + * fbcon can be written around these fields. This will also eliminate the + * need to regenerate struct fb_var_screeninfo, struct fb_fix_screeninfo + * struct fb_cmap every time get_var, get_fix, get_cmap functions are called + * as many drivers do now. + * + * 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/kernel.h> +#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> + + /* + * This is just simple sample code. + * + * No warranty that it actually compiles. + * Even less warranty that it actually works :-) + */ + +/* + * If your driver supports multiple boards, you should make the + * below data types arrays, or allocate them dynamically (using kmalloc()). + */ + +/* + * This structure defines the hardware state of the graphics card. Normally + * you place this in a header file in linux/include/video. This file usually + * also includes register information. That allows other driver subsystems + * and userland applications the ability to use the same header file to + * avoid duplicate work and easy porting of software. + */ +struct xxx_par; + +/* + * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo + * if we don't use modedb. If we do use modedb see xxxfb_init how to use it + * to get a fb_var_screeninfo. Otherwise define a default var as well. + */ +static struct fb_fix_screeninfo xxxfb_fix __initdata = { + .id = "FB's name", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .xpanstep = 1, + .ypanstep = 1, + .ywrapstep = 1, + .accel = FB_ACCEL_NONE, +}; + + /* + * Modern graphical hardware not only supports pipelines but some + * also support multiple monitors where each display can have its + * its own unique data. In this case each display could be + * represented by a separate framebuffer device thus a separate + * struct fb_info. Now the struct xxx_par represents the graphics + * hardware state thus only one exist per card. In this case the + * struct xxx_par for each graphics card would be shared between + * every struct fb_info that represents a framebuffer on that card. + * This allows when one display changes it video resolution (info->var) + * the other displays know instantly. Each display can always be + * aware of the entire hardware state that affects it because they share + * the same xxx_par struct. The other side of the coin is multiple + * graphics cards that pass data around until it is finally displayed + * on one monitor. Such examples are the voodoo 1 cards and high end + * NUMA graphics servers. For this case we have a bunch of pars, each + * one that represents a graphics state, that belong to one struct + * fb_info. Their you would want to have *par point to a array of device + * states and have each struct fb_ops function deal with all those + * states. I hope this covers every possible hardware design. If not + * feel free to send your ideas at jsimmons@users.sf.net + */ + + /* + * If your driver supports multiple boards or it supports multiple + * framebuffers, you should make these arrays, or allocate them + * dynamically (using kmalloc()). + */ +static struct fb_info info; + + /* + * Each one represents the state of the hardware. Most hardware have + * just one hardware state. These here represent the default state(s). + */ +static struct xxx_par __initdata current_par; + +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. + * + * Returns negative errno on error, or zero on success. + */ +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. + * + * Returns negative errno on error, or zero on success. + */ +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 + * + * Checks to see if the hardware supports the state requested by + * var passed in. This function does not alter the hardware state!!! + * This means the data stored in struct fb_info and struct xxx_par do + * not change. This includes the var inside of struct fb_info. + * Do NOT change these. This function can be called on its own if we + * intent to only test a mode and not actually set it. The stuff in + * modedb.c is a example of this. If the var passed in is slightly + * 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. 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. + */ +static int xxxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + const struct xxx_par *par = (const struct xxx_par *) info->par; + /* ... */ + return 0; +} + +/** + * xxxfb_set_par - Optional function. Alters the hardware state. + * @info: frame buffer structure that represents a single frame buffer + * + * Using the fb_var_screeninfo in fb_info we set the resolution of the + * this particular framebuffer. This function alters the par AND the + * fb_fix_screeninfo stored in fb_info. It doesn't not alter var in + * 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 change the resolution you don't need this function. + * + * Returns negative errno on error, or zero on success. + */ +static int xxxfb_set_par(struct fb_info *info) +{ + struct xxx_par *par = (struct xxx_par *) info->par; + /* ... */ + return 0; +} + +/** + * xxxfb_setcolreg - Optional function. Sets a color register. + * @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. + * @info: frame buffer info structure + * + * Set a single color register. The values supplied have a 16 bit + * magnitude which needs to be scaled in this function for the hardware. + * Things to take into consideration are how many color registers, if + * any, are supported with the current color visual. With truecolor mode + * no color palettes are supported. Here a pseudo palette is created + * which we store the value in pseudo_palette in struct fb_info. For + * pseudocolor mode we have a limited color palette. To deal with this + * we can program what color is displayed for a particular pixel value. + * DirectColor is similar in that we can program each color field. If + * we have a static colormap we don't need to implement this function. + * + * Returns negative errno on error, or zero on success. + */ +static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + const struct fb_info *info) +{ + if (regno >= 256) /* no. of hw registers */ + return -EINVAL; + /* + * Program hardware... do anything you want with transp + */ + + /* grayscale works only partially under directcolor */ + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + /* Directcolor: + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * {hardwarespecific} contains width of DAC + * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) + * RAMDAC[X] is programmed to (red, green, blue) + * + * Pseudocolor: + * uses offset = 0 && length = DAC register width. + * var->{color}.offset is 0 + * var->{color}.length contains widht of DAC + * cmap is not used + * DAC[X] is programmed to (red, green, blue) + * Truecolor: + * does not use RAMDAC (usually has 3 of them). + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * cmap is programmed to (red << red.offset) | (green << green.offset) | + * (blue << blue.offset) | (transp << transp.offset) + * RAMDAC does not exist + */ +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + case FB_VISUAL_PSEUDOCOLOR: + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + break; + case FB_VISUAL_DIRECTCOLOR: + /* example here assumes 8 bit DAC. Might be different + * for your hardware */ + red = CNVT_TOHW(red, 8); + green = CNVT_TOHW(green, 8); + blue = CNVT_TOHW(blue, 8); + /* hey, there is bug in transp handling... */ + transp = CNVT_TOHW(transp, 8); + break; + } +#undef CNVT_TOHW + /* Truecolor has hardware independent palette */ + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v; + + if (regno >= 16) + return -EINVAL; + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + + switch (info->var.bits_per_pixel) { + case 8: + /* Yes some hand held devices have this. */ + ((u8*)(info->pseudo_palette))[regno] = v; + break; + case 16: + ((u16*)(info->pseudo_palette))[regno] = v; + break; + case 24: + case 32: + ((u32*)(info->pseudo_palette))[regno] = v; + break; + } + return 0; + } + /* ... */ + return 0; +} + +/** + * 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 + * + * Pan (or wrap, depending on the `vmode' field) the display using the + * `xoffset' and `yoffset' fields of the `var' structure. + * 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) +{ + /* ... */ + return 0; +} + +/** + * xxxfb_blank - NOT a required function. Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + * + * Blank the screen if blank_mode != 0, else unblank. Return 0 if + * blanking succeeded, != 0 if un-/blanking failed due to e.g. a + * video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + * + * Returns negative errno on error, or zero on success. + * + */ +static int xxxfb_blank(int blank_mode, const struct fb_info *info) +{ + /* ... */ + return 0; +} + +/* ------------ Accelerated Functions --------------------- */ + +/* + * We provide our own functions if we have hardware acceleration + * or non packed pixel format layouts. If we have no hardware + * 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. + */ + +/** + * xxxfb_fillrect - REQUIRED function. Can use generic routines if + * non acclerated hardware and packed pixel based. + * Draws a rectangle on the screen. + * + * @info: frame buffer structure that represents a single frame buffer + * @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 xxfb_fillrect(struct fb_info *p, const 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 one area of the screen to another area. + * + * @info: frame buffer structure that represents a single frame buffer + * @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, const 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. + * Copies a image from system memory to the screen. + * + * @info: frame buffer structure that represents a single frame buffer + * @image: structure defining the image. + * + * This drawing operation draws a image on the screen. It can be a + * mono image (needed for font handling) or a color image (needed for + * tux). + */ +void xxxfb_imageblit(struct fb_info *p, const 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. + */ +} + +/** + * 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. + * + * NOTES ON FLAGS (cursor->set): + * + * FB_CUR_SETIMAGE - the cursor image has changed (cursor->image.data) + * FB_CUR_SETPOS - the cursor position has changed (cursor->image.dx|dy) + * FB_CUR_SETHOT - the cursor hot spot has changed (cursor->hot.dx|dy) + * FB_CUR_SETCMAP - the cursor colors has changed (cursor->fg_color|bg_color) + * FB_CUR_SETSHAPE - the cursor bitmask has changed (cursor->mask) + * FB_CUR_SETSIZE - the cursor size has changed (cursor->width|height) + * FB_CUR_SETALL - everything has changed + * + * NOTES ON ROPs (cursor->rop, Raster Operation) + * + * ROP_XOR - cursor->image.data XOR cursor->mask + * ROP_COPY - curosr->image.data AND cursor->mask + * + * OTHER NOTES: + * + * - fbcon only supports a 2-color cursor (cursor->image.depth = 1) + * - The fb_cursor structure, @cursor, _will_ always contain valid + * fields, whether any particular bitfields in cursor->set is set + * or not. + */ +} + +/** + * 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 consistent display output. + * + * @info: frame buffer structure that represents a single frame buffer + */ +void xxxfb_sync(struct fb_info *info) +{ +} + + /* + * Initialization + */ + +int __init xxxfb_init(void) +{ + int cmap_len, retval; + + /* + * For kernel boot options (in 'video=xxxfb:<options>' format) + */ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("xxxfb", &option)) + return -ENODEV; + xxxfb_setup(option); +#endif + + /* + * Here we set the screen_base to the virtual memory address + * for the framebuffer. Usually we obtain the resource address + * from the bus layer and then translate it to virtual memory + * space via ioremap. Consult ioport.h. + */ + info.screen_base = framebuffer_virtual_memory; + info.fbops = &xxxfb_ops; + info.fix = xxxfb_fix; + info.pseudo_palette = pseudo_palette; + + /* + * Set up flags to indicate what sort of acceleration your + * driver can provide (pan/wrap/copyarea/etc.) and whether it + * is a module -- see FBINFO_* in include/linux/fb.h + */ + info.flags = FBINFO_DEFAULT; + info.par = current_par; + + /* + * This should give a reasonable default video mode. The following is + * done when we can set a video mode. + */ + if (!mode_option) + mode_option = "640x480@60"; + + retval = fb_find_mode(&info.var, &info, mode_option, NULL, 0, NULL, 8); + + if (!retval || retval == 4) + return -EINVAL; + + /* This has to been done !!! */ + fb_alloc_cmap(&info.cmap, cmap_len, 0); + + /* + * The following is done in the case of having hardware with a static + * mode. If we are setting the mode ourselves we don't call this. + */ + info.var = xxxfb_var; + + if (register_framebuffer(&info) < 0) + return -EINVAL; + printk(KERN_INFO "fb%d: %s frame buffer device\n", info.node, + info.fix.id); + return 0; +} + + /* + * Cleanup + */ + +static void __exit xxxfb_cleanup(void) +{ + /* + * If your driver supports multiple boards, you should unregister and + * clean up all instances. + */ + + unregister_framebuffer(info); + fb_dealloc_cmap(&info.cmap); + /* ... */ +} + + /* + * Setup + */ + +/* + * Only necessary if your driver takes special options, + * otherwise we fall back on the generic fb_setup(). + */ +int __init xxxfb_setup(char *options) +{ + /* Parse user speficied options (`video=xxxfb:') */ +} + +/* ------------------------------------------------------------------------- */ + + /* + * Frame buffer operations + */ + +static struct fb_ops xxxfb_ops = { + .owner = THIS_MODULE, + .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, + .fb_setcolreg = xxxfb_setcolreg, + .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, +}; + +/* ------------------------------------------------------------------------- */ + + + /* + * Modularization + */ + +module_init(xxxfb_init); +module_exit(xxxfb_cleanup); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/softcursor.c b/drivers/video/softcursor.c new file mode 100644 index 000000000000..13a4511539a1 --- /dev/null +++ b/drivers/video/softcursor.c @@ -0,0 +1,79 @@ +/* + * linux/drivers/video/softcursor.c -- Generic software cursor for frame buffer devices + * + * Created 14 Nov 2002 by James Simmons + * + * 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/string.h> +#include <linux/tty.h> +#include <linux/fb.h> +#include <linux/slab.h> + +#include <asm/uaccess.h> +#include <asm/io.h> + +int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + unsigned int scan_align = info->pixmap.scan_align - 1; + unsigned int buf_align = info->pixmap.buf_align - 1; + unsigned int i, size, dsize, s_pitch, d_pitch; + struct fb_image *image; + u8 *dst, *src; + + if (info->state != FBINFO_STATE_RUNNING) + return 0; + + s_pitch = (cursor->image.width + 7) >> 3; + dsize = s_pitch * cursor->image.height; + + src = kmalloc(dsize + sizeof(struct fb_image), GFP_ATOMIC); + if (!src) + return -ENOMEM; + + image = (struct fb_image *) (src + dsize); + *image = cursor->image; + d_pitch = (s_pitch + scan_align) & ~scan_align; + + size = d_pitch * image->height + buf_align; + size &= ~buf_align; + dst = fb_get_buffer_offset(info, &info->pixmap, size); + + if (cursor->enable) { + switch (cursor->rop) { + case ROP_XOR: + for (i = 0; i < dsize; i++) + src[i] = image->data[i] ^ cursor->mask[i]; + break; + case ROP_COPY: + default: + for (i = 0; i < dsize; i++) + src[i] = image->data[i] & cursor->mask[i]; + break; + } + } else + memcpy(src, image->data, dsize); + + if (info->pixmap.outbuf) + fb_iomove_buf_aligned(info, &info->pixmap, dst, d_pitch, src, + s_pitch, image->height); + else + fb_sysmove_buf_aligned(info, &info->pixmap, dst, d_pitch, src, + s_pitch, image->height); + + image->data = dst; + info->fbops->fb_imageblit(info, image); + kfree(src); + + return 0; +} + +EXPORT_SYMBOL(soft_cursor); + +MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); +MODULE_DESCRIPTION("Generic software cursor"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c new file mode 100644 index 000000000000..663d53657fa4 --- /dev/null +++ b/drivers/video/sstfb.c @@ -0,0 +1,1722 @@ +/* + * linux/drivers/video/sstfb.c -- voodoo graphics frame buffer + * + * Copyright (c) 2000-2002 Ghozlane Toumi <gtoumi@laposte.net> + * + * Created 15 Jan 2000 by Ghozlane Toumi + * + * Contributions (and many thanks) : + * + * 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) + * 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) + * 01/2003 Helge Deller <deller@gmx.de> + * (initial work on fb hardware acceleration for voodoo2) + * + */ + +/* + * The voodoo1 has the following memory mapped address space: + * 0x000000 - 0x3fffff : registers (4MB) + * 0x400000 - 0x7fffff : linear frame buffer (4MB) + * 0x800000 - 0xffffff : texture memory (8MB) + */ + +/* + * misc notes, TODOs, toASKs, and deep thoughts + +-TODO: at one time or another test that the mode is acceptable by the monitor +-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 ... +-TODO: in set_var check the validity of timings (hsync vsync)... +-TODO: check and recheck the use of sst_wait_idle : we don't flush the fifo via + a nop command. so it's ok as long as the commands we pass don't go + through the fifo. warning: issuing a nop command seems to need pci_fifo +-FIXME: in case of failure in the init sequence, be sure we return to a safe + state. +-FIXME: 4MB boards have banked memory (FbiInit2 bits 1 & 20) + */ + +/* + * debug info + * SST_DEBUG : enable debugging + * SST_DEBUG_REG : debug registers + * 0 : no debug + * 1 : dac calls, [un]set_bits, FbiInit + * 2 : insane debug level (log every register read/write) + * SST_DEBUG_FUNC : functions + * 0 : no debug + * 1 : function call / debug ioctl + * 2 : variables + * 3 : flood . you don't want to do that. trust me. + * SST_DEBUG_VAR : debug display/var structs + * 0 : no debug + * 1 : dumps display, fb_var + * + * sstfb specific ioctls: + * toggle vga (0x46db) : toggle vga_pass_through + * fill fb (0x46dc) : fills fb + * test disp (0x46de) : draws a test image + */ + +#undef SST_DEBUG + +/* enable 24/32 bpp functions ? (completely untested!) */ +#undef EN_24_32_BPP + +/* + Default video mode . + 0 800x600@60 took from glide + 1 640x480@75 took from glide + 2 1024x768@76 std fb.mode + 3 640x480@60 glide default */ +#define DEFAULT_MODE 3 + +/* + * Includes + */ + +#include <linux/config.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fb.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <asm/io.h> +#include <asm/ioctl.h> +#include <asm/uaccess.h> +#include <video/sstfb.h> + + +/* initialized by setup */ + +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; /* force FBI freq in Mhz . Dangerous */ +static int slowpci; /* slow PCI settings */ + +static char *mode_option __devinitdata; + +enum { + ID_VOODOO1 = 0, + ID_VOODOO2 = 1, +}; + +#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 fb_var_screeninfo sstfb_default = +#if ( DEFAULT_MODE == 0 ) + { /* 800x600@60, 16 bpp .borowed from glide/sst1/include/sst1init.h */ + 800, 600, 800, 600, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, + 25000, 86, 41, 23, 1, 127, 4, + 0, FB_VMODE_NONINTERLACED }; +#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 }; +#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 }; +#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 + + +/* + * debug functions + */ + +static void sstfb_drawdebugimage(struct fb_info *info); +static int sstfb_dump_regs(struct fb_info *info); + + +#if (SST_DEBUG_REG > 0) +static void sst_dbg_print_read_reg(u32 reg, u32 val) { + 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; + default: regname = NULL; break; + } + if (regname == NULL) + r_ddprintk("sst_read(%#x): %#x\n", reg, val); + else + r_dprintk(" sst_read(%s): %#x\n", regname, val); +} + +static void sst_dbg_print_write_reg(u32 reg, u32 val) { + 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; + default: regname = NULL; break; + } + if (regname == NULL) + r_ddprintk("sst_write(%#x, %#x)\n", reg, val); + else + 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) +#endif /* (SST_DEBUG_REG > 0) */ + +/* + * hardware access functions + */ + +/* register access */ +#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(u8 __iomem *vbase, u32 reg) +{ + u32 ret = readl(vbase + reg); + sst_dbg_print_read_reg(reg, ret); + return ret; +} + +static inline void __sst_write(u8 __iomem *vbase, u32 reg, u32 val) +{ + sst_dbg_print_write_reg(reg, val); + writel(val, vbase + reg); +} + +static inline void __sst_set_bits(u8 __iomem *vbase, u32 reg, u32 val) +{ + r_dprintk("sst_set_bits(%#x, %#x)\n", reg, val); + __sst_write(vbase, reg, __sst_read(vbase, reg) | val); +} + +static inline void __sst_unset_bits(u8 __iomem *vbase, u32 reg, u32 val) +{ + r_dprintk("sst_unset_bits(%#x, %#x)\n", reg, 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(u8 __iomem *vbase) +{ + int count = 0; + + /* if (doFBINOP) __sst_write(vbase, NOPCMD, 0); */ + + 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(u8 __iomem *vbase, u8 reg) +{ + u8 ret; + + 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; + r_dprintk("sst_dac_read(%#x): %#x\n", reg, ret); + + return ret; +} + +static void __sst_dac_write(u8 __iomem *vbase, u8 reg, u8 val) +{ + r_dprintk("sst_dac_write(%#x, %#x)\n", reg, val); + reg &= 0x07; + __sst_write(vbase, DAC_DATA,(((u32)reg << 8)) | (u32)val); +} + +/* indexed access to ti/att dacs */ +static u32 __dac_i_read(u8 __iomem *vbase, u8 reg) +{ + u32 ret; + + __sst_dac_write(vbase, DACREG_ADDR_I, reg); + ret = __sst_dac_read(vbase, DACREG_DATA_I); + r_dprintk("sst_dac_read_i(%#x): %#x\n", reg, ret); + return ret; +} +static void __dac_i_write(u8 __iomem *vbase, u8 reg,u8 val) +{ + r_dprintk("sst_dac_write_i(%#x, %#x)\n", reg, val); + __sst_dac_write(vbase, DACREG_ADDR_I, reg); + __sst_dac_write(vbase, DACREG_DATA_I, val); +} + +/* 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; + + 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; +} + +/* + * clear lfb screen + */ +static void sstfb_clear_screen(struct fb_info *info) +{ + /* clear screen */ + fb_memset(info->screen_base, 0, info->fix.smem_len); +} + + +/** + * sstfb_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 + */ +static int sstfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + 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; + int vSyncOn = var->vsync_len; + int tiles_in_X, real_length; + unsigned int freq; + + if (sst_calc_pll(PICOS2KHZ(var->pixclock), &freq, &par->pll)) { + eprintk("Pixclock at %ld KHZ out of range\n", + PICOS2KHZ(var->pixclock)); + return -EINVAL; + } + 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 : + var->bits_per_pixel = 16; + break; +#ifdef EN_24_32_BPP + case 17 ... 24 : + var->bits_per_pixel = 24; + break; + case 25 ... 32 : + var->bits_per_pixel = 32; + break; +#endif + default : + eprintk("Unsupported bpp %d\n", var->bits_per_pixel); + return -EINVAL; + } + + /* validity tests */ + 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(par)) { + /* Voodoo 2 limits */ + 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 (((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 */ + tiles_in_X = (var->xres + 63 ) / 64; + + if (var->vmode) { + eprintk("Interlace/Doublescan not supported %#x\n", + var->vmode); + return -EINVAL; + } + if (((var->xres - 1) >= POW2(10)) || (var->yres >= POW2(10))) { + eprintk("Unsupported resolution %dx%d\n", + var->xres, var->yres); + return -EINVAL; + } + 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 = tiles_in_X * (IS_VOODOO2(par) ? 32 : 64 ) + * ((var->bits_per_pixel == 16) ? 2 : 4); + + if ((real_length * yDim) > info->fix.smem_len) { + eprintk("Not enough video memory\n"); + return -ENOMEM; + } + + 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; */ + + switch (var->bits_per_pixel) { + case 16: /* RGB 565 LfbMode 0 */ + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + var->transp.length = 0; + + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->transp.offset = 0; + break; +#ifdef EN_24_32_BPP + case 24: /* RGB 888 LfbMode 4 */ + case 32: /* ARGB 8888 LfbMode 5 */ + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->transp.offset = 0; /* in 24bpp we fake a 32 bpp mode */ + break; +#endif + default: + return -EINVAL; + } + return 0; +} + +/** + * sstfb_set_par - Optional function. Alters the hardware state. + * @info: frame buffer structure that represents a single frame buffer + */ +static int sstfb_set_par(struct fb_info *info) +{ + 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; + + par->hSyncOff = info->var.xres + info->var.right_margin + info->var.left_margin; + + 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; + + /* We need par->pll */ + sst_calc_pll(PICOS2KHZ(info->var.pixclock), &freq, &par->pll); + + 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; + } + + 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; + } + + f_ddprintk("hsync_len hSyncOff vsync_len vSyncOff\n"); + f_ddprintk("%-7d %-8d %-7d %-8d\n", + info->var.hsync_len, par->hSyncOff, + par->vSyncOn, par->vSyncOff); + f_ddprintk("left_margin upper_margin xres yres Freq\n"); + f_ddprintk("%-10d %-10d %-4d %-4d %-8ld\n", + info->var.left_margin, info->var.upper_margin, + info->var.xres, info->var.yres, PICOS2KHZ(info->var.pixclock)); + + 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 | (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); + + 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 ); + + 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; + } + 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 + case 24: + case 32: + /* sst_set_bits(FBIINIT1, SEL_SOURCE_VCLK_2X_DIV2 | EN_24BPP);*/ + fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL | EN_24BPP; + break; +#endif + default: + return -EINVAL; + } + 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); + } + 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 */ + 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: + return -EINVAL; + } + +#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, Helge Deller <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_ddprintk("setting clipping dimensions 0..%d, 0..%d\n", + info->var.xres - 1, par->yDim - 1); + + 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 { + /* no clipping : direct access, no pipeline */ + sst_write(LFBMODE, lfbmode); + } + return 0; +} + +/** + * sstfb_setcolreg - Optional function. Sets a color register. + * @regno: hardware colormap register + * @red: frame buffer colormap structure + * @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. + * @info: frame buffer info structure + */ +static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + u32 col; + + f_dddprintk("sstfb_setcolreg\n"); + f_dddprintk("%-2d rgbt: %#x, %#x, %#x, %#x\n", + regno, red, green, blue, transp); + if (regno >= 16) + return -EINVAL; + + 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); + + ((u32 *)info->pseudo_palette)[regno] = col; + + return 0; +} + +static int sstfb_ioctl(struct inode *inode, struct file *file, + u_int cmd, u_long arg, struct fb_info *info ) +{ + struct sstfb_par *par = (struct sstfb_par *) info->par; + struct pci_dev *sst_dev = par->dev; + u32 fbiinit0, tmp, val; + u_long p; + + switch (cmd) { + + /* dump current FBIINIT values to system log */ + case _IO('F', 0xdb): /* 0x46db */ + return sstfb_dump_regs(info); + + /* fills lfb with #arg pixels */ + case _IOW('F', 0xdc, u32): /* 0x46dc */ + if (copy_from_user(&val, (void __user *)arg, sizeof(val))) + return -EFAULT; + if (val > info->fix.smem_len) + val = info->fix.smem_len; + printk("filling %#x \n", val); + for (p=0 ; p<val; p+=2) + writew(p >> 6, info->screen_base + p); + return 0; + + /* change VGA pass_through mode */ + case _IOW('F', 0xdd, u32): /* 0x46dd */ + if (copy_from_user(&val, (void __user *)arg, sizeof(val))) + return -EFAULT; + 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 (val) { + sst_write(FBIINIT0, fbiinit0 & ~EN_VGA_PASSTHROUGH); + iprintk("Disabling VGA pass-through\n"); + } else { + sst_write(FBIINIT0, fbiinit0 | EN_VGA_PASSTHROUGH); + 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 at %d bpp\n", + info->var.bits_per_pixel); + sstfb_drawdebugimage(info); + return 0; + } + return -EINVAL; +} + + +/* + * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) - Voodoo2 only + */ +#if 0 +static void sstfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct sstfb_par *par = (struct sstfb_par *) info->par; + u32 stride = info->fix.line_length; + + if (!IS_VOODOO2(par)) + return; + + sst_write(BLTSRCBASEADDR, 0); + sst_write(BLTDSTBASEADDR, 0); + sst_write(BLTROP, BLTROP_COPY); + sst_write(BLTXYSTRIDES, stride | (stride << 16)); + sst_write(BLTSRCXY, area->sx | (area->sy << 16)); + sst_write(BLTDSTXY, area->dx | (area->dy << 16)); + sst_write(BLTSIZE, area->width | (area->height << 16)); + sst_write(BLTCOMMAND, BLT_SCR2SCR_BITBLT | LAUNCH_BITBLT | + (BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) ); + sst_wait_idle(); +} +#endif + + +/* + * FillRect 2D command (solidfill or invert (via ROP_XOR)) - Voodoo2 only + */ +static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct sstfb_par *par = (struct sstfb_par *) info->par; + u32 stride = info->fix.line_length; + + if (!IS_VOODOO2(par)) + return; + + sst_write(BLTCLIPX, info->var.xres); + sst_write(BLTCLIPY, info->var.yres); + + sst_write(BLTDSTBASEADDR, 0); + sst_write(BLTCOLOR, rect->color); + sst_write(BLTROP, rect->rop == ROP_COPY ? BLTROP_COPY : BLTROP_XOR); + sst_write(BLTXYSTRIDES, stride | (stride << 16)); + sst_write(BLTDSTXY, rect->dx | (rect->dy << 16)); + sst_write(BLTSIZE, rect->width | (rect->height << 16)); + sst_write(BLTCOMMAND, BLT_RECFILL_BITBLT | LAUNCH_BITBLT + | (BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) | BIT(16) ); + sst_wait_idle(); +} + + + +/* + * get lfb size + */ +static int __devinit sst_get_memsize(struct fb_info *info, __u32 *memsize) +{ + u8 __iomem *fbbase_virt = info->screen_base; + + /* force memsize */ + if ((mem >= 1 ) && (mem <= 4)) { + *memsize = (mem * 0x100000); + iprintk("supplied memsize: %#x\n", *memsize); + return 1; + } + + writel(0xdeadbeef, fbbase_virt); + writel(0xdeadbeef, fbbase_virt+0x100000); + writel(0xdeadbeef, fbbase_virt+0x200000); + f_ddprintk("0MB: %#x, 1MB: %#x, 2MB: %#x\n", + readl(fbbase_virt), readl(fbbase_virt + 0x100000), + readl(fbbase_virt + 0x200000)); + + writel(0xabcdef01, fbbase_virt); + + f_ddprintk("0MB: %#x, 1MB: %#x, 2MB: %#x\n", + readl(fbbase_virt), readl(fbbase_virt + 0x100000), + readl(fbbase_virt + 0x200000)); + + /* checks for 4mb lfb, then 2, then defaults to 1 */ + if (readl(fbbase_virt + 0x200000) == 0xdeadbeef) + *memsize = 0x400000; + else if (readl(fbbase_virt + 0x100000) == 0xdeadbeef) + *memsize = 0x200000; + else + *memsize = 0x100000; + f_ddprintk("detected memsize: %dMB\n", *memsize >> 20); + return 1; +} + + +/* + * DAC detection routines + */ + +/* 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 fb_info *info) +{ + struct sstfb_par *par = (struct sstfb_par *) info->par; + int i, mir, dir; + + 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); + sst_dac_read(DACREG_RMR); + sst_dac_read(DACREG_RMR); + /* the fifth time, CR0 is read */ + sst_dac_read(DACREG_RMR); + /* the 6th, manufacturer id register */ + mir = sst_dac_read(DACREG_RMR); + /*the 7th, device ID register */ + dir = sst_dac_read(DACREG_RMR); + f_ddprintk("mir: %#x, dir: %#x\n", mir, dir); + if ((mir == DACREG_MIR_ATT ) && (dir == DACREG_DIR_ATT)) { + return 1; + } + } + return 0; +} + +static int __devinit sst_detect_ti(struct fb_info *info) +{ + struct sstfb_par *par = (struct sstfb_par *) info->par; + int i, mir, dir; + + 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); + sst_dac_read(DACREG_RMR); + sst_dac_read(DACREG_RMR); + /* the fifth time, CR0 is read */ + sst_dac_read(DACREG_RMR); + /* the 6th, manufacturer id register */ + mir = sst_dac_read(DACREG_RMR); + /*the 7th, device ID register */ + dir = sst_dac_read(DACREG_RMR); + f_ddprintk("mir: %#x, dir: %#x\n", mir, dir); + if ((mir == DACREG_MIR_TI ) && (dir == DACREG_DIR_TI)) { + return 1; + } + } + return 0; +} + +/* + * try to detect ICS5342 ramdac + * we get the 1st byte (M value) of preset f1,f7 and fB + * why those 3 ? mmmh... for now, i'll do it the glide way... + * and ask questions later. anyway, it seems that all the freq registers are + * realy at their default state (cf specs) so i ask again, why those 3 regs ? + * mmmmh.. it seems that's much more ugly than i thought. we use f0 and fA for + * pll programming, so in fact, we *hope* that the f1, f7 & fB won't be + * touched... + * is it realy safe ? how can i reset this ramdac ? geee... + */ +static int __devinit sst_detect_ics(struct fb_info *info) +{ + 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; + + for (i = 0; i<5; i++ ) { + sst_dac_write(DACREG_ICS_PLLRMA, 0x1); /* f1 */ + m_clk0_1 = sst_dac_read(DACREG_ICS_PLLDATA); + n_clk0_1 = sst_dac_read(DACREG_ICS_PLLDATA); + sst_dac_write(DACREG_ICS_PLLRMA, 0x7); /* f7 */ + m_clk0_7 = sst_dac_read(DACREG_ICS_PLLDATA); + n_clk0_7 = sst_dac_read(DACREG_ICS_PLLDATA); + sst_dac_write(DACREG_ICS_PLLRMA, 0xb); /* fB */ + m_clk1_b= sst_dac_read(DACREG_ICS_PLLDATA); + n_clk1_b= sst_dac_read(DACREG_ICS_PLLDATA); + f_ddprintk("m_clk0_1: %#x, m_clk0_7: %#x, m_clk1_b: %#x\n", + m_clk0_1, m_clk0_7, m_clk1_b); + f_ddprintk("n_clk0_1: %#x, n_clk0_7: %#x, n_clk1_b: %#x\n", + n_clk0_1, n_clk0_7, n_clk1_b); + if (( m_clk0_1 == DACREG_ICS_PLL_CLK0_1_INI) + && (m_clk0_7 == DACREG_ICS_PLL_CLK0_7_INI) + && (m_clk1_b == DACREG_ICS_PLL_CLK1_B_INI)) { + return 1; + } + } + return 0; +} + + +/* + * gfx, video, pci fifo should be reset, dram refresh disabled + * see detect_dac + */ + +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; + + /* enable indexed mode */ + sst_dac_write(DACREG_WMA, 0); /* backdoor */ + sst_dac_read(DACREG_RMR); /* 1 time: RMR */ + sst_dac_read(DACREG_RMR); /* 2 RMR */ + sst_dac_read(DACREG_RMR); /* 3 // */ + sst_dac_read(DACREG_RMR); /* 4 // */ + cr0 = sst_dac_read(DACREG_RMR); /* 5 CR0 */ + + sst_dac_write(DACREG_WMA, 0); + sst_dac_read(DACREG_RMR); + sst_dac_read(DACREG_RMR); + sst_dac_read(DACREG_RMR); + sst_dac_read(DACREG_RMR); + sst_dac_write(DACREG_RMR, (cr0 & 0xf0) + | DACREG_CR0_EN_INDEXED + | DACREG_CR0_8BIT + | DACREG_CR0_PWDOWN ); + /* so, now we are in indexed mode . dunno if its common, but + i find this way of doing things a little bit weird :p */ + + udelay(300); + cc = dac_i_read(DACREG_CC_I); + switch (clock) { + case VID_CLOCK: + dac_i_write(DACREG_AC0_I, t->m); + dac_i_write(DACREG_AC1_I, t->p << 6 | t->n); + dac_i_write(DACREG_CC_I, + (cc & 0x0f) | DACREG_CC_CLKA | DACREG_CC_CLKA_C); + break; + case GFX_CLOCK: + dac_i_write(DACREG_BD0_I, t->m); + dac_i_write(DACREG_BD1_I, t->p << 6 | t->n); + dac_i_write(DACREG_CC_I, + (cc & 0xf0) | DACREG_CC_CLKB | DACREG_CC_CLKB_D); + break; + default: + dprintk("%s: wrong clock code '%d'\n", + __FUNCTION__, clock); + return 0; + } + udelay(300); + + /* power up the dac & return to "normal" non-indexed mode */ + dac_i_write(DACREG_CR0_I, + cr0 & ~DACREG_CR0_PWDOWN & ~DACREG_CR0_EN_INDEXED); + return 1; +} + +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; + + sst_dac_write(DACREG_ICS_PLLRMA, DACREG_ICS_PLL_CTRL); + pll_ctrl = sst_dac_read(DACREG_ICS_PLLDATA); + switch(clock) { + case VID_CLOCK: + sst_dac_write(DACREG_ICS_PLLWMA, 0x0); /* CLK0, f0 */ + sst_dac_write(DACREG_ICS_PLLDATA, t->m); + sst_dac_write(DACREG_ICS_PLLDATA, t->p << 5 | t->n); + /* selects freq f0 for clock 0 */ + sst_dac_write(DACREG_ICS_PLLWMA, DACREG_ICS_PLL_CTRL); + sst_dac_write(DACREG_ICS_PLLDATA, + (pll_ctrl & 0xd8) + | DACREG_ICS_CLK0 + | DACREG_ICS_CLK0_0); + break; + case GFX_CLOCK : + sst_dac_write(DACREG_ICS_PLLWMA, 0xa); /* CLK1, fA */ + sst_dac_write(DACREG_ICS_PLLDATA, t->m); + sst_dac_write(DACREG_ICS_PLLDATA, t->p << 5 | t->n); + /* selects freq fA for clock 1 */ + sst_dac_write(DACREG_ICS_PLLWMA, DACREG_ICS_PLL_CTRL); + sst_dac_write(DACREG_ICS_PLLDATA, + (pll_ctrl & 0xef) | DACREG_ICS_CLK1_A); + break; + default: + dprintk("%s: wrong clock code '%d'\n", + __FUNCTION__, clock); + return 0; + } + udelay(300); + return 1; +} + +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; + + sst_dac_write(DACREG_WMA, 0); /* backdoor */ + sst_dac_read(DACREG_RMR); /* read 4 times RMR */ + sst_dac_read(DACREG_RMR); + sst_dac_read(DACREG_RMR); + sst_dac_read(DACREG_RMR); + /* the fifth time, CR0 is read */ + cr0 = sst_dac_read(DACREG_RMR); + + sst_dac_write(DACREG_WMA, 0); /* backdoor */ + sst_dac_read(DACREG_RMR); /* read 4 times RMR */ + sst_dac_read(DACREG_RMR); + sst_dac_read(DACREG_RMR); + sst_dac_read(DACREG_RMR); + /* cr0 */ + switch(bpp) { + case 16: + sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_16BPP); + break; +#ifdef EN_24_32_BPP + case 24: + case 32: + sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_24BPP); + break; +#endif + default: + dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp); + break; + } +} + +static void sst_set_vidmod_ics(struct fb_info *info, const int bpp) +{ + struct sstfb_par *par = (struct sstfb_par *) info->par; + + switch(bpp) { + case 16: + sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_16BPP); + break; +#ifdef EN_24_32_BPP + case 24: + case 32: + sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_24BPP); + break; +#endif + default: + dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp); + break; + } +} + +/* + * 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 i, ret = 0; + + for (i=0; i<sizeof(dacs)/sizeof(dacs[0]); i++) { + ret = dacs[i].detect(info); + if (ret) break; + } + if (!ret) + return 0; + f_dprintk("%s found %s\n", __FUNCTION__, 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; + int Fout; + + spec = &voodoo_spec[par->type]; + f_ddprintk(" fbiinit0 fbiinit1 fbiinit2 fbiinit3 fbiinit4 " + " fbiinit6\n"); + f_ddprintk("%0#10x %0#10x %0#10x %0#10x %0#10x %0#10x\n", + 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(dev, PCI_VCLK_DISABLE, 0); + + /* enable writing to init registers, disable pci fifo */ + pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); + /* reset video */ + sst_set_bits(FBIINIT1, VIDEO_RESET); + sst_wait_idle(); + /* reset gfx + pci fifo */ + sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET); + sst_wait_idle(); + + /* unreset fifo */ + /*sst_unset_bits(FBIINIT0, FIFO_RESET); + sst_wait_idle();*/ + /* unreset FBI */ + /*sst_unset_bits(FBIINIT0, FBI_RESET); + sst_wait_idle();*/ + + /* disable dram refresh */ + sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH); + sst_wait_idle(); + /* remap fbinit2/3 to dac */ + pci_write_config_dword(dev, PCI_INIT_ENABLE, + PCI_EN_INIT_WR | PCI_REMAP_DAC ); + /* detect dac type */ + if (!sst_detect_dactype(info, par)) { + eprintk("Unknown dac type\n"); + //FIXME watch it: we are not in a safe state, bad bad bad. + return 0; + } + + /* set graphic clock */ + par->gfx_clock = spec->default_gfx_clock; + if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) { + iprintk("Using supplied graphic freq : %dMHz\n", gfxclk); + par->gfx_clock = gfxclk *1000; + } else if (gfxclk) { + wprintk ("%dMhz is way out of spec! Using default\n", gfxclk); + } + + 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(dev, PCI_INIT_ENABLE, + PCI_EN_INIT_WR| PCI_EN_FIFO_WR ); + /* defaults init registers */ + /* FbiInit0: unreset gfx, unreset fifo */ + fbiinit0 = FBIINIT0_DEFAULT; + fbiinit1 = FBIINIT1_DEFAULT; + fbiinit4 = FBIINIT4_DEFAULT; + if (vgapass) + fbiinit0 &= ~EN_VGA_PASSTHROUGH; + else + fbiinit0 |= EN_VGA_PASSTHROUGH; + if (slowpci) { + fbiinit1 |= SLOW_PCI_WRITES; + fbiinit4 |= SLOW_PCI_READS; + } else { + fbiinit1 &= ~SLOW_PCI_WRITES; + fbiinit4 &= ~SLOW_PCI_READS; + } + sst_write(FBIINIT0, fbiinit0); + sst_wait_idle(); + sst_write(FBIINIT1, fbiinit1); + sst_wait_idle(); + sst_write(FBIINIT2, FBIINIT2_DEFAULT); + sst_wait_idle(); + sst_write(FBIINIT3, FBIINIT3_DEFAULT); + sst_wait_idle(); + sst_write(FBIINIT4, fbiinit4); + sst_wait_idle(); + if (IS_VOODOO2(par)) { + sst_write(FBIINIT6, FBIINIT6_DEFAULT); + sst_wait_idle(); + } + + 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 fb_info *info) +{ + struct sstfb_par *par = (struct sstfb_par *) info->par; + struct pci_dev *dev = par->dev; + struct pll_timing gfx_timings; + int Fout; + + /* reset video, gfx, fifo, disable dram + remap fbiinit2/3 */ + 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(dev, PCI_INIT_ENABLE, + PCI_EN_INIT_WR | PCI_REMAP_DAC); + /* set 20Mhz gfx clock */ + sst_calc_pll(20000, &Fout, &gfx_timings); + par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK); + /* TODO maybe shutdown the dac, vrefresh and so on... */ + 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(dev, PCI_VCLK_DISABLE,0); + /* maybe keep fbiinit* and PCI_INIT_enable in the fb_info struct + * from start ? */ + pci_write_config_dword(dev, PCI_INIT_ENABLE, 0); + +} + +/* + * Interface to the world + */ +#ifndef MODULE +static int __init sstfb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) continue; + + f_ddprintk("option %s\n", this_opt); + + if (!strcmp(this_opt, "vganopass")) + vgapass = 0; + else if (!strcmp(this_opt, "vgapass")) + vgapass = 1; + else if (!strcmp(this_opt, "clipping")) + clipping = 1; + else if (!strcmp(this_opt, "noclipping")) + clipping = 0; + else if (!strcmp(this_opt, "fastpci")) + slowpci = 0; + else if (!strcmp(this_opt, "slowpci")) + slowpci = 1; + else if (!strncmp(this_opt, "mem:",4)) + mem = simple_strtoul (this_opt+4, NULL, 0); + else if (!strncmp(this_opt, "gfxclk:",7)) + gfxclk = simple_strtoul (this_opt+7, NULL, 0); + else + mode_option = this_opt; + } + return 0; +} +#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, /* sstfb_fillrect */ + .fb_copyarea = cfb_copyarea, /* sstfb_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_info *info; + struct fb_fix_screeninfo *fix; + struct sstfb_par *par; + struct sst_spec *spec; + int err; + + struct all_info { + struct fb_info info; + struct sstfb_par par; + u32 pseudo_palette[16]; + } *all; + + /* Enable device in PCI config. */ + if ((err=pci_enable_device(pdev))) { + eprintk("cannot enable device\n"); + return err; + } + + /* Allocate the fb and par structures. */ + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) + return -ENOMEM; + memset(all, 0, sizeof(*all)); + pci_set_drvdata(pdev, all); + + info = &all->info; + par = info->par = &all->par; + fix = &info->fix; + + par->type = id->driver_data; + spec = &voodoo_spec[par->type]; + f_ddprintk("found device : %s\n", spec->name); + + par->dev = pdev; + pci_read_config_byte(pdev, PCI_REVISION_ID, &par->revision); + + fix->mmio_start = pci_resource_start(pdev,0); + fix->mmio_len = 0x400000; + fix->smem_start = fix->mmio_start + 0x400000; + + if (!request_mem_region(fix->mmio_start, fix->mmio_len, "sstfb MMIO")) { + eprintk("cannot reserve mmio memory\n"); + goto fail_mmio_mem; + } + + if (!request_mem_region(fix->smem_start, 0x400000,"sstfb FB")) { + eprintk("cannot reserve fb memory\n"); + goto fail_fb_mem; + } + + par->mmio_vbase = ioremap_nocache(fix->mmio_start, + fix->mmio_len); + if (!par->mmio_vbase) { + eprintk("cannot remap register area %#lx\n", + fix->mmio_start); + goto fail_mmio_remap; + } + info->screen_base = ioremap_nocache(fix->smem_start, 0x400000); + if (!info->screen_base) { + eprintk("cannot remap framebuffer %#lx\n", + fix->smem_start); + goto fail_fb_remap; + } + + if (!sst_init(info, par)) { + eprintk("Init failed\n"); + goto fail; + } + sst_get_memsize(info, &fix->smem_len); + strlcpy(fix->id, spec->name, sizeof(fix->id)); + + iprintk("%s (revision %d) with %s dac\n", + fix->id, par->revision, par->dac_sw.name); + iprintk("framebuffer at %#lx, mapped to 0x%p, size %dMB\n", + fix->smem_start, info->screen_base, + fix->smem_len >> 20); + + f_ddprintk("regbase_virt: %#lx\n", par->mmio_vbase); + f_ddprintk("membase_phys: %#lx\n", fix->smem_start); + f_ddprintk("fbbase_virt: %p\n", info->screen_base); + + info->flags = FBINFO_DEFAULT; + info->fbops = &sstfb_ops; + info->pseudo_palette = &all->pseudo_palette; + + 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("invalid default video mode.\n"); + goto fail; + } + + if (sstfb_set_par(info)) { + eprintk("can't set default video mode.\n"); + goto fail; + } + + fb_alloc_cmap(&info->cmap, 256, 0); + + /* register fb */ + info->device = &pdev->dev; + if (register_framebuffer(info) < 0) { + eprintk("can't register framebuffer.\n"); + goto fail; + } + + if (1) /* set to 0 to see an initial bitmap instead */ + sstfb_clear_screen(info); + else + sstfb_drawdebugimage(info); + + printk(KERN_INFO "fb%d: %s frame buffer device at 0x%p\n", + info->node, fix->id, info->screen_base); + + return 0; + +fail: + iounmap(info->screen_base); +fail_fb_remap: + iounmap(par->mmio_vbase); +fail_mmio_remap: + release_mem_region(fix->smem_start, 0x400000); +fail_fb_mem: + release_mem_region(fix->mmio_start, info->fix.mmio_len); +fail_mmio_mem: + kfree(info); + return -ENXIO; /* no voodoo detected */ +} + +static void __devexit sstfb_remove(struct pci_dev *pdev) +{ + struct sstfb_par *par; + struct fb_info *info; + + info = pci_get_drvdata(pdev); + par = (struct sstfb_par *) info->par; + + sst_shutdown(info); + unregister_framebuffer(info); + iounmap(info->screen_base); + iounmap(par->mmio_vbase); + release_mem_region(info->fix.smem_start, 0x400000); + release_mem_region(info->fix.mmio_start, info->fix.mmio_len); + kfree(info); +} + + +static struct pci_device_id sstfb_id_tbl[] = { + { 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), +}; + + +static int __devinit sstfb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("sstfb", &option)) + return -ENODEV; + sstfb_setup(option); +#endif + return pci_register_driver(&sstfb_driver); +} + +#ifdef MODULE +static void __devexit sstfb_exit(void) +{ + pci_unregister_driver(&sstfb_driver); +} +#endif + + +/* + * testing and debugging functions + */ + +static int sstfb_dump_regs(struct fb_info *info) +{ +#ifdef SST_DEBUG + static struct { u32 reg ; const char *reg_name;} pci_regs[] = { + { PCI_INIT_ENABLE, "initenable"}, + { PCI_VCLK_ENABLE, "enable vclk"}, + { PCI_VCLK_DISABLE, "disable vclk"}, + }; + + static struct { u32 reg ; const 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"}, + }; + + const int pci_s = sizeof(pci_regs)/sizeof(pci_regs[0]); + const int sst_s = sizeof(sst_regs)/sizeof(sst_regs[0]); + struct sstfb_par *par = (struct sstfb_par *) info->par; + struct pci_dev *dev = par->dev; + u32 pci_res[pci_s]; + u32 sst_res[sst_s]; + 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("hardware register dump:\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]); + } + return 0; +#else + return -EINVAL; +#endif +} + +static void sstfb_fillrect_softw( struct fb_info *info, const struct fb_fillrect *rect) +{ + u8 __iomem *fbbase_virt = info->screen_base; + int x, y, w = info->var.bits_per_pixel == 16 ? 2 : 4; + u32 color = rect->color, height = rect->height; + u8 __iomem *p; + + if (w==2) color |= color<<16; + for (y=rect->dy; height; y++, height--) { + p = fbbase_virt + y*info->fix.line_length + rect->dx*w; + x = rect->width; + if (w==2) x>>=1; + while (x) { + writel(color, p); + p += 4; + x--; + } + } +} + +static void sstfb_drawrect_XY( struct fb_info *info, int x, int y, + int w, int h, int color, int hwfunc) +{ + struct fb_fillrect rect; + rect.dx = x; + rect.dy = y; + rect.height = h; + rect.width = w; + rect.color = color; + rect.rop = ROP_COPY; + if (hwfunc) + sstfb_fillrect(info, &rect); + else + sstfb_fillrect_softw(info, &rect); +} + +/* print some squares on the fb */ +static void sstfb_drawdebugimage(struct fb_info *info) +{ + static int idx; + + /* clear screen */ + sstfb_clear_screen(info); + + idx = (idx+1) & 1; + + /* white rect */ + sstfb_drawrect_XY(info, 0, 0, 50, 50, 0xffff, idx); + + /* blue rect */ + sstfb_drawrect_XY(info, 50, 50, 50, 50, 0x001f, idx); + + /* green rect */ + sstfb_drawrect_XY(info, 100, 100, 80, 80, 0x07e0, idx); + + /* red rect */ + sstfb_drawrect_XY(info, 250, 250, 120, 100, 0xf800, idx); +} + +module_init(sstfb_init); + +#ifdef MODULE +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"); +MODULE_LICENSE("GPL"); + +module_param(mem, int, 0); +MODULE_PARM_DESC(mem, "Size of frame buffer memory in MB (1, 2, 4 MB, default=autodetect)"); +module_param(vgapass, bool, 0); +MODULE_PARM_DESC(vgapass, "Enable VGA PassThrough mode (0 or 1) (default=0)"); +module_param(clipping, bool, 0); +MODULE_PARM_DESC(clipping, "Enable clipping (slower, safer) (0 or 1) (default=1)"); +module_param(gfxclk, int, 0); +MODULE_PARM_DESC(gfxclk, "Force graphic chip frequency in MHz. DANGEROUS. (default=auto)"); +module_param(slowpci, bool, 0); +MODULE_PARM_DESC(slowpci, "Uses slow PCI settings (0 or 1) (default=0)"); + diff --git a/drivers/video/sticore.h b/drivers/video/sticore.h new file mode 100644 index 000000000000..dc93336af557 --- /dev/null +++ b/drivers/video/sticore.h @@ -0,0 +1,380 @@ +#ifndef STICORE_H +#define STICORE_H + +/* generic STI structures & functions */ + +#if 0 +#define DPRINTK(x) printk x +#else +#define DPRINTK(x) +#endif + +#define MAX_STI_ROMS 4 /* max no. of ROMs which this driver handles */ + +#define STI_REGION_MAX 8 /* hardcoded STI constants */ +#define STI_DEV_NAME_LENGTH 32 +#define STI_MONITOR_MAX 256 + +#define STI_FONT_HPROMAN8 1 +#define STI_FONT_KANA8 2 + +/* 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 + */ + +#define STI_WAIT 1 + +#include <asm/io.h> /* for USE_HPPA_IOREMAP */ + +#if USE_HPPA_IOREMAP + +#define STI_PTR(p) (p) +#define PTR_STI(p) (p) +static inline int STI_CALL( unsigned long func, + void *flags, void *inptr, void *outptr, void *glob_cfg ) +{ + int (*f)(void *,void *,void *,void *); + f = (void*)func; + return f(flags, inptr, outptr, glob_cfg); +} + +#else /* !USE_HPPA_IOREMAP */ + +#define STI_PTR(p) ( virt_to_phys(p) ) +#define PTR_STI(p) ( phys_to_virt((long)p) ) +#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \ + ({ \ + pdc_sti_call( func, (unsigned long)STI_PTR(flags), \ + (unsigned long)STI_PTR(inptr), \ + (unsigned long)STI_PTR(outptr), \ + (unsigned long)STI_PTR(glob_cfg)); \ + }) + +#endif /* USE_HPPA_IOREMAP */ + + +#define sti_onscreen_x(sti) (sti->glob_cfg->onscreen_x) +#define sti_onscreen_y(sti) (sti->glob_cfg->onscreen_y) + +/* sti_font_xy() use the native font ROM ! */ +#define sti_font_x(sti) (PTR_STI(sti->font)->width) +#define sti_font_y(sti) (PTR_STI(sti->font)->height) + + +/* STI function configuration structs */ + +typedef union region { + struct { + u32 offset : 14; /* offset in 4kbyte page */ + u32 sys_only : 1; /* don't map to user space */ + u32 cache : 1; /* map to data cache */ + u32 btlb : 1; /* map to block tlb */ + u32 last : 1; /* last region in list */ + u32 length : 14; /* length in 4kbyte page */ + } region_desc; + + u32 region; /* complete region value */ +} region_t; + +#define REGION_OFFSET_TO_PHYS( rt, hpa ) \ + (((rt).region_desc.offset << 12) + (hpa)) + +struct sti_glob_cfg_ext { + u8 curr_mon; /* current monitor configured */ + u8 friendly_boot; /* in friendly boot mode */ + s16 power; /* power calculation (in Watts) */ + s32 freq_ref; /* frequency refrence */ + u32 sti_mem_addr; /* pointer to global sti memory (size=sti_mem_request) */ + u32 future_ptr; /* pointer to future data */ +}; + +struct sti_glob_cfg { + s32 text_planes; /* number of planes used for text */ + s16 onscreen_x; /* screen width in pixels */ + s16 onscreen_y; /* screen height in pixels */ + s16 offscreen_x; /* offset width in pixels */ + s16 offscreen_y; /* offset height in pixels */ + s16 total_x; /* frame buffer width in pixels */ + s16 total_y; /* frame buffer height in pixels */ + u32 region_ptrs[STI_REGION_MAX]; /* region pointers */ + s32 reent_lvl; /* storage for reentry level value */ + u32 save_addr; /* where to save or restore reentrant state */ + u32 ext_ptr; /* pointer to extended glob_cfg data structure */ +}; + + +/* STI init function structs */ + +struct sti_init_flags { + u32 wait : 1; /* should routine idle wait or not */ + u32 reset : 1; /* hard reset the device? */ + u32 text : 1; /* turn on text display planes? */ + u32 nontext : 1; /* turn on non-text display planes? */ + u32 clear : 1; /* clear text display planes? */ + u32 cmap_blk : 1; /* non-text planes cmap black? */ + u32 enable_be_timer : 1; /* enable bus error timer */ + u32 enable_be_int : 1; /* enable bus error timer interrupt */ + u32 no_chg_tx : 1; /* don't change text settings */ + u32 no_chg_ntx : 1; /* don't change non-text settings */ + u32 no_chg_bet : 1; /* don't change berr timer settings */ + u32 no_chg_bei : 1; /* don't change berr int settings */ + u32 init_cmap_tx : 1; /* initialize cmap for text planes */ + u32 cmt_chg : 1; /* change current monitor type */ + u32 retain_ie : 1; /* don't allow reset to clear int enables */ + u32 caller_bootrom : 1; /* set only by bootrom for each call */ + u32 caller_kernel : 1; /* set only by kernel for each call */ + u32 caller_other : 1; /* set only by non-[BR/K] caller */ + u32 pad : 14; /* pad to word boundary */ + u32 future_ptr; /* pointer to future data */ +}; + +struct sti_init_inptr_ext { + u8 config_mon_type; /* configure to monitor type */ + u8 pad[1]; /* pad to word boundary */ + u16 inflight_data; /* inflight data possible on PCI */ + u32 future_ptr; /* pointer to future data */ +}; + +struct sti_init_inptr { + s32 text_planes; /* number of planes to use for text */ + u32 ext_ptr; /* pointer to extended init_graph inptr data structure*/ +}; + + +struct sti_init_outptr { + s32 errno; /* error number on failure */ + s32 text_planes; /* number of planes used for text */ + u32 future_ptr; /* pointer to future data */ +}; + + + +/* STI configuration function structs */ + +struct sti_conf_flags { + u32 wait : 1; /* should routine idle wait or not */ + u32 pad : 31; /* pad to word boundary */ + u32 future_ptr; /* pointer to future data */ +}; + +struct sti_conf_inptr { + u32 future_ptr; /* pointer to future data */ +}; + +struct sti_conf_outptr_ext { + u32 crt_config[3]; /* hardware specific X11/OGL information */ + u32 crt_hdw[3]; + u32 future_ptr; +}; + +struct sti_conf_outptr { + s32 errno; /* error number on failure */ + s16 onscreen_x; /* screen width in pixels */ + s16 onscreen_y; /* screen height in pixels */ + s16 offscreen_x; /* offscreen width in pixels */ + s16 offscreen_y; /* offscreen height in pixels */ + s16 total_x; /* frame buffer width in pixels */ + s16 total_y; /* frame buffer height in pixels */ + s32 bits_per_pixel; /* bits/pixel device has configured */ + s32 bits_used; /* bits which can be accessed */ + s32 planes; /* number of fb planes in system */ + u8 dev_name[STI_DEV_NAME_LENGTH]; /* null terminated product name */ + u32 attributes; /* flags denoting attributes */ + u32 ext_ptr; /* pointer to future data */ +}; + +struct sti_rom { + u8 type[4]; + u8 res004; + u8 num_mons; + u8 revno[2]; + u32 graphics_id[2]; + + 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_addr; + u32 state_mgmt_addr; + u32 font_unp_addr; + u32 block_move_addr; + u32 self_test_addr; + u32 excep_hdlr_addr; + u32 inq_conf_addr; + u32 set_cm_entry_addr; + u32 image_unpack_addr; + u32 pa_risx_addrs[7]; +}; + +struct sti_rom_font { + u16 first_char; + u16 last_char; + u8 width; + u8 height; + u8 font_type; /* language type */ + u8 bytes_per_char; + u32 next_font; + u8 underline_height; + u8 underline_pos; + u8 res008[2]; +}; + +/* sticore internal font handling */ + +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; +}; + +/* STI font printing function structs */ + +struct sti_font_inptr { + u32 font_start_addr; /* address of font start */ + s16 index; /* index into font table of character */ + u8 fg_color; /* foreground color of character */ + u8 bg_color; /* background color of character */ + s16 dest_x; /* X location of character upper left */ + s16 dest_y; /* Y location of character upper left */ + u32 future_ptr; /* pointer to future data */ +}; + +struct sti_font_flags { + u32 wait : 1; /* should routine idle wait or not */ + u32 non_text : 1; /* font unpack/move in non_text planes =1, text =0 */ + u32 pad : 30; /* pad to word boundary */ + u32 future_ptr; /* pointer to future data */ +}; + +struct sti_font_outptr { + s32 errno; /* error number on failure */ + u32 future_ptr; /* pointer to future data */ +}; + +/* STI blockmove structs */ + +struct sti_blkmv_flags { + u32 wait : 1; /* should routine idle wait or not */ + u32 color : 1; /* change color during move? */ + u32 clear : 1; /* clear during move? */ + u32 non_text : 1; /* block move in non_text planes =1, text =0 */ + u32 pad : 28; /* pad to word boundary */ + u32 future_ptr; /* pointer to future data */ +}; + +struct sti_blkmv_inptr { + u8 fg_color; /* foreground color after move */ + u8 bg_color; /* background color after move */ + s16 src_x; /* source upper left pixel x location */ + s16 src_y; /* source upper left pixel y location */ + s16 dest_x; /* dest upper left pixel x location */ + s16 dest_y; /* dest upper left pixel y location */ + s16 width; /* block width in pixels */ + s16 height; /* block height in pixels */ + u32 future_ptr; /* pointer to future data */ +}; + +struct sti_blkmv_outptr { + s32 errno; /* error number on failure */ + u32 future_ptr; /* pointer to future data */ +}; + + +/* internal generic STI struct */ + +struct sti_struct { + spinlock_t lock; + + /* the following fields needs to be filled in by the word/byte routines */ + int font_width; + int font_height; + /* char **mon_strings; */ + int sti_mem_request; + u32 graphics_id[2]; + + struct sti_cooked_rom *rom; + + unsigned long font_unpmv; + unsigned long block_move; + unsigned long init_graph; + unsigned long inq_conf; + + /* all following fields are initialized by the generic routines */ + int text_planes; + region_t regions[STI_REGION_MAX]; + unsigned long regions_phys[STI_REGION_MAX]; + + struct sti_glob_cfg *glob_cfg; + struct sti_cooked_font *font; /* ptr to selected font (cooked) */ + + struct sti_conf_outptr outptr; /* configuration */ + struct sti_conf_outptr_ext outptr_ext; + + /* 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; +}; + + +/* sticore interface functions */ + +struct sti_struct *sti_get_rom(unsigned int index); /* 0: default sti */ + +/* functions to call the STI ROM directly */ + +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); +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, int c); +void sti_bmove(struct sti_struct *sti, int src_y, int src_x, + int dst_y, int dst_x, int height, int width); + +#endif /* STICORE_H */ diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c new file mode 100644 index 000000000000..9e52794768e6 --- /dev/null +++ b/drivers/video/stifb.c @@ -0,0 +1,1495 @@ +/* + * linux/drivers/video/stifb.c - + * Low level Frame buffer driver for HP workstations with + * STI (standard text interface) video firmware. + * + * Copyright (C) 2001-2004 Helge Deller <deller@gmx.de> + * Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de> + * + * Based on: + * - linux/drivers/video/artistfb.c -- Artist frame buffer driver + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * - based on skeletonfb, which was + * Created 28 Dec 1997 by Geert Uytterhoeven + * - HP Xhp cfb-based X11 window driver for XFree86 + * (c)Copyright 1992 Hewlett-Packard Co. + * + * + * The following graphics display devices (NGLE family) are supported by this driver: + * + * HPA4070A known as "HCRX", a 1280x1024 color device with 8 planes + * HPA4071A known as "HCRX24", a 1280x1024 color device with 24 planes, + * optionally available with a hardware accelerator as HPA4071A_Z + * HPA1659A known as "CRX", a 1280x1024 color device with 8 planes + * HPA1439A known as "CRX24", a 1280x1024 color device with 24 planes, + * optionally available with a hardware accelerator. + * HPA1924A known as "GRX", a 1280x1024 grayscale device with 8 planes + * HPA2269A known as "Dual CRX", a 1280x1024 color device with 8 planes, + * implements support for two displays on a single graphics card. + * HP710C internal graphics support optionally available on the HP9000s710 SPU, + * supports 1280x1024 color displays with 8 planes. + * HP710G same as HP710C, 1280x1024 grayscale only + * HP710L same as HP710C, 1024x768 color only + * HP712 internal graphics support on HP9000s712 SPU, supports 640x480, + * 1024x768 or 1280x1024 color displays on 8 planes (Artist) + * + * 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: + * - 1bpp mode is completely untested + * - add support for h/w acceleration + * - add hardware cursor + * - automatically disable double buffering (e.g. on RDI precisionbook laptop) + */ + + +/* on supported graphic devices you may: + * #define FALLBACK_TO_1BPP to fall back to 1 bpp, or + * #undef FALLBACK_TO_1BPP to reject support for unsupported cards */ +#undef FALLBACK_TO_1BPP + +#undef DEBUG_STIFB_REGS /* debug sti register accesses */ + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/pci.h> + +#include <asm/grfioctl.h> /* for HP-UX compatibility */ +#include <asm/uaccess.h> + +#include "sticore.h" + +/* REGION_BASE(fb_info, index) returns the virtual address for region <index> */ +#ifdef __LP64__ + #define REGION_BASE(fb_info, index) \ + (fb_info->sti->glob_cfg->region_ptrs[index] | 0xffffffff00000000) +#else + #define REGION_BASE(fb_info, index) \ + fb_info->sti->glob_cfg->region_ptrs[index] +#endif + +#define NGLEDEVDEPROM_CRT_REGION 1 + +typedef struct { + __s32 video_config_reg; + __s32 misc_video_start; + __s32 horiz_timing_fmt; + __s32 serr_timing_fmt; + __s32 vert_timing_fmt; + __s32 horiz_state; + __s32 vert_state; + __s32 vtg_state_elements; + __s32 pipeline_delay; + __s32 misc_video_end; +} video_setup_t; + +typedef struct { + __s16 sizeof_ngle_data; + __s16 x_size_visible; /* visible screen dim in pixels */ + __s16 y_size_visible; + __s16 pad2[15]; + __s16 cursor_pipeline_delay; + __s16 video_interleaves; + __s32 pad3[11]; +} ngle_rom_t; + +struct stifb_info { + struct fb_info info; + unsigned int id; + ngle_rom_t ngle_rom; + struct sti_struct *sti; + int deviceSpecificConfig; + u32 pseudo_palette[256]; +}; + +static int __initdata stifb_bpp_pref[MAX_STI_ROMS]; + +/* ------------------- chipset specific functions -------------------------- */ + +/* offsets to graphic-chip internal registers */ + +#define REG_1 0x000118 +#define REG_2 0x000480 +#define REG_3 0x0004a0 +#define REG_4 0x000600 +#define REG_6 0x000800 +#define REG_8 0x000820 +#define REG_9 0x000a04 +#define REG_10 0x018000 +#define REG_11 0x018004 +#define REG_12 0x01800c +#define REG_13 0x018018 +#define REG_14 0x01801c +#define REG_15 0x200000 +#define REG_15b0 0x200000 +#define REG_16b1 0x200005 +#define REG_16b3 0x200007 +#define REG_21 0x200218 +#define REG_22 0x0005a0 +#define REG_23 0x0005c0 +#define REG_26 0x200118 +#define REG_27 0x200308 +#define REG_32 0x21003c +#define REG_33 0x210040 +#define REG_34 0x200008 +#define REG_35 0x018010 +#define REG_38 0x210020 +#define REG_39 0x210120 +#define REG_40 0x210130 +#define REG_42 0x210028 +#define REG_43 0x21002c +#define REG_44 0x210030 +#define REG_45 0x210034 + +#define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg)) +#define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg)) + + +#ifndef DEBUG_STIFB_REGS +# define DEBUG_OFF() +# define DEBUG_ON() +# define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)) +# define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg)) +#else + static int debug_on = 1; +# define DEBUG_OFF() debug_on=0 +# define DEBUG_ON() debug_on=1 +# define WRITE_BYTE(value,fb,reg) do { if (debug_on) \ + printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \ + __FUNCTION__, reg, value, READ_BYTE(fb,reg)); \ + gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0) +# define WRITE_WORD(value,fb,reg) do { if (debug_on) \ + printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \ + __FUNCTION__, reg, value, READ_WORD(fb,reg)); \ + gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0) +#endif /* DEBUG_STIFB_REGS */ + + +#define ENABLE 1 /* for enabling/disabling screen */ +#define DISABLE 0 + +#define NGLE_LOCK(fb_info) do { } while (0) +#define NGLE_UNLOCK(fb_info) do { } while (0) + +static void +SETUP_HW(struct stifb_info *fb) +{ + char stat; + + do { + stat = READ_BYTE(fb, REG_15b0); + if (!stat) + stat = READ_BYTE(fb, REG_15b0); + } while (stat); +} + + +static void +SETUP_FB(struct stifb_info *fb) +{ + unsigned int reg10_value = 0; + + SETUP_HW(fb); + switch (fb->id) + { + case CRT_ID_VISUALIZE_EG: + case S9000_ID_ARTIST: + case S9000_ID_A1659A: + reg10_value = 0x13601000; + break; + case S9000_ID_A1439A: + if (fb->info.var.bits_per_pixel == 32) + reg10_value = 0xBBA0A000; + else + reg10_value = 0x13601000; + break; + case S9000_ID_HCRX: + if (fb->info.var.bits_per_pixel == 32) + reg10_value = 0xBBA0A000; + else + reg10_value = 0x13602000; + break; + case S9000_ID_TIMBER: + case CRX24_OVERLAY_PLANES: + reg10_value = 0x13602000; + break; + } + if (reg10_value) + WRITE_WORD(reg10_value, fb, REG_10); + WRITE_WORD(0x83000300, fb, REG_14); + SETUP_HW(fb); + WRITE_BYTE(1, fb, REG_16b1); +} + +static void +START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) +{ + SETUP_HW(fb); + WRITE_WORD(0xBBE0F000, fb, REG_10); + WRITE_WORD(0x03000300, fb, REG_14); + WRITE_WORD(~0, fb, REG_13); +} + +static void +WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color) +{ + SETUP_HW(fb); + WRITE_WORD(((0x100+index)<<2), fb, REG_3); + WRITE_WORD(color, fb, REG_4); +} + +static void +FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) +{ + WRITE_WORD(0x400, fb, REG_2); + if (fb->info.var.bits_per_pixel == 32) { + WRITE_WORD(0x83000100, fb, REG_1); + } else { + if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG) + WRITE_WORD(0x80000100, fb, REG_26); + else + WRITE_WORD(0x80000100, fb, REG_1); + } + SETUP_FB(fb); +} + +static void +SETUP_RAMDAC(struct stifb_info *fb) +{ + SETUP_HW(fb); + WRITE_WORD(0x04000000, fb, 0x1020); + WRITE_WORD(0xff000000, fb, 0x1028); +} + +static void +CRX24_SETUP_RAMDAC(struct stifb_info *fb) +{ + SETUP_HW(fb); + WRITE_WORD(0x04000000, fb, 0x1000); + WRITE_WORD(0x02000000, fb, 0x1004); + WRITE_WORD(0xff000000, fb, 0x1008); + WRITE_WORD(0x05000000, fb, 0x1000); + WRITE_WORD(0x02000000, fb, 0x1004); + WRITE_WORD(0x03000000, fb, 0x1008); +} + +#if 0 +static void +HCRX_SETUP_RAMDAC(struct stifb_info *fb) +{ + WRITE_WORD(0xffffffff, fb, REG_32); +} +#endif + +static void +CRX24_SET_OVLY_MASK(struct stifb_info *fb) +{ + SETUP_HW(fb); + WRITE_WORD(0x13a02000, fb, REG_11); + WRITE_WORD(0x03000300, fb, REG_14); + WRITE_WORD(0x000017f0, fb, REG_3); + WRITE_WORD(0xffffffff, fb, REG_13); + WRITE_WORD(0xffffffff, fb, REG_22); + WRITE_WORD(0x00000000, fb, REG_23); +} + +static void +ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) +{ + unsigned int value = enable ? 0x43000000 : 0x03000000; + SETUP_HW(fb); + WRITE_WORD(0x06000000, fb, 0x1030); + WRITE_WORD(value, fb, 0x1038); +} + +static void +CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) +{ + unsigned int value = enable ? 0x10000000 : 0x30000000; + SETUP_HW(fb); + WRITE_WORD(0x01000000, fb, 0x1000); + WRITE_WORD(0x02000000, fb, 0x1004); + WRITE_WORD(value, fb, 0x1008); +} + +static void +ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) +{ + u32 DregsMiscVideo = REG_21; + u32 DregsMiscCtl = REG_27; + + SETUP_HW(fb); + if (enable) { + WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo); + WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl); + } else { + WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo); + WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl); + } +} + +#define GET_ROMTABLE_INDEX(fb) \ + (READ_BYTE(fb, REG_16b3) - 1) + +#define HYPER_CONFIG_PLANES_24 0x00000100 + +#define IS_24_DEVICE(fb) \ + (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24) + +#define IS_888_DEVICE(fb) \ + (!(IS_24_DEVICE(fb))) + +#define GET_FIFO_SLOTS(fb, cnt, numslots) \ +{ while (cnt < numslots) \ + cnt = READ_WORD(fb, REG_34); \ + cnt -= numslots; \ +} + +#define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */ +#define Otc04 2 /* Pixels in each longword transfer (4) */ +#define Otc32 5 /* Pixels in each longword transfer (32) */ +#define Ots08 3 /* Each pixel is size (8)d transfer (1) */ +#define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */ +#define AddrLong 5 /* FB address is Long aligned (pixel) */ +#define BINovly 0x2 /* 8 bit overlay */ +#define BINapp0I 0x0 /* Application Buffer 0, Indexed */ +#define BINapp1I 0x1 /* Application Buffer 1, Indexed */ +#define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */ +#define BINattr 0xd /* Attribute Bitmap */ +#define RopSrc 0x3 +#define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */ +#define BitmapExtent32 5 /* Each write hits (32) bits in depth */ +#define DataDynamic 0 /* Data register reloaded by direct access */ +#define MaskDynamic 1 /* Mask register reloaded by direct access */ +#define MaskOtc 0 /* Mask contains Object Count valid bits */ + +#define MaskAddrOffset(offset) (offset) +#define StaticReg(en) (en) +#define BGx(en) (en) +#define FGx(en) (en) + +#define BAJustPoint(offset) (offset) +#define BAIndexBase(base) (base) +#define BA(F,C,S,A,J,B,I) \ + (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I)) + +#define IBOvals(R,M,X,S,D,L,B,F) \ + (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F)) + +#define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \ + WRITE_WORD(val, fb, REG_14) + +#define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \ + WRITE_WORD(val, fb, REG_11) + +#define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \ + WRITE_WORD(val, fb, REG_12) + +#define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \ + WRITE_WORD(plnmsk32, fb, REG_13) + +#define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \ + WRITE_WORD(fg32, fb, REG_35) + +#define NGLE_SET_TRANSFERDATA(fb, val) \ + WRITE_WORD(val, fb, REG_8) + +#define NGLE_SET_DSTXY(fb, val) \ + WRITE_WORD(val, fb, REG_6) + +#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \ + (u32) (fbaddrbase) + \ + ( (unsigned int) ( (y) << 13 ) | \ + (unsigned int) ( (x) << 2 ) ) \ + ) + +#define NGLE_BINC_SET_DSTADDR(fb, addr) \ + WRITE_WORD(addr, fb, REG_3) + +#define NGLE_BINC_SET_SRCADDR(fb, addr) \ + WRITE_WORD(addr, fb, REG_2) + +#define NGLE_BINC_SET_DSTMASK(fb, mask) \ + WRITE_WORD(mask, fb, REG_22) + +#define NGLE_BINC_WRITE32(fb, data32) \ + WRITE_WORD(data32, fb, REG_23) + +#define START_COLORMAPLOAD(fb, cmapBltCtlData32) \ + WRITE_WORD((cmapBltCtlData32), fb, REG_38) + +#define SET_LENXY_START_RECFILL(fb, lenxy) \ + WRITE_WORD(lenxy, fb, REG_9) + +static void +HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) +{ + u32 DregsHypMiscVideo = REG_33; + unsigned int value; + SETUP_HW(fb); + value = READ_WORD(fb, DregsHypMiscVideo); + if (enable) + value |= 0x0A000000; + else + value &= ~0x0A000000; + WRITE_WORD(value, fb, DregsHypMiscVideo); +} + + +/* BufferNumbers used by SETUP_ATTR_ACCESS() */ +#define BUFF0_CMAP0 0x00001e02 +#define BUFF1_CMAP0 0x02001e02 +#define BUFF1_CMAP3 0x0c001e02 +#define ARTIST_CMAP0 0x00000102 +#define HYPER_CMAP8 0x00000100 +#define HYPER_CMAP24 0x00000800 + +static void +SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber) +{ + SETUP_HW(fb); + WRITE_WORD(0x2EA0D000, fb, REG_11); + WRITE_WORD(0x23000302, fb, REG_14); + WRITE_WORD(BufferNumber, fb, REG_12); + WRITE_WORD(0xffffffff, fb, REG_8); +} + +static void +SET_ATTR_SIZE(struct stifb_info *fb, int width, int height) +{ + /* REG_6 seems to have special values when run on a + RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or + INTERNAL_EG_X1024). The values are: + 0x2f0: internal (LCD) & external display enabled + 0x2a0: external display only + 0x000: zero on standard artist graphic cards + */ + WRITE_WORD(0x00000000, fb, REG_6); + WRITE_WORD((width<<16) | height, fb, REG_9); + WRITE_WORD(0x05000000, fb, REG_6); + WRITE_WORD(0x00040001, fb, REG_9); +} + +static void +FINISH_ATTR_ACCESS(struct stifb_info *fb) +{ + SETUP_HW(fb); + WRITE_WORD(0x00000000, fb, REG_12); +} + +static void +elkSetupPlanes(struct stifb_info *fb) +{ + SETUP_RAMDAC(fb); + SETUP_FB(fb); +} + +static void +ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber) +{ + SETUP_ATTR_ACCESS(fb, BufferNumber); + SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres); + FINISH_ATTR_ACCESS(fb); + SETUP_FB(fb); +} + + +static void +rattlerSetupPlanes(struct stifb_info *fb) +{ + CRX24_SETUP_RAMDAC(fb); + + /* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */ + WRITE_WORD(0x83000300, fb, REG_14); + SETUP_HW(fb); + WRITE_BYTE(1, fb, REG_16b1); + + fb_memset(fb->info.fix.smem_start, 0xff, + fb->info.var.yres*fb->info.fix.line_length); + + CRX24_SET_OVLY_MASK(fb); + SETUP_FB(fb); +} + + +#define HYPER_CMAP_TYPE 0 +#define NGLE_CMAP_INDEXED0_TYPE 0 +#define NGLE_CMAP_OVERLAY_TYPE 3 + +/* typedef of LUT (Colormap) BLT Control Register */ +typedef union /* Note assumption that fields are packed left-to-right */ +{ u32 all; + struct + { + unsigned enable : 1; + unsigned waitBlank : 1; + unsigned reserved1 : 4; + unsigned lutOffset : 10; /* Within destination LUT */ + unsigned lutType : 2; /* Cursor, image, overlay */ + unsigned reserved2 : 4; + unsigned length : 10; + } fields; +} NgleLutBltCtl; + + +#if 0 +static NgleLutBltCtl +setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) +{ + NgleLutBltCtl lutBltCtl; + + /* set enable, zero reserved fields */ + lutBltCtl.all = 0x80000000; + lutBltCtl.fields.length = length; + + switch (fb->id) + { + case S9000_ID_A1439A: /* CRX24 */ + if (fb->var.bits_per_pixel == 8) { + lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE; + lutBltCtl.fields.lutOffset = 0; + } else { + lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE; + lutBltCtl.fields.lutOffset = 0 * 256; + } + break; + + case S9000_ID_ARTIST: + lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE; + lutBltCtl.fields.lutOffset = 0 * 256; + break; + + default: + lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE; + lutBltCtl.fields.lutOffset = 0; + break; + } + + /* Offset points to start of LUT. Adjust for within LUT */ + lutBltCtl.fields.lutOffset += offsetWithinLut; + + return lutBltCtl; +} +#endif + +static NgleLutBltCtl +setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) +{ + NgleLutBltCtl lutBltCtl; + + /* set enable, zero reserved fields */ + lutBltCtl.all = 0x80000000; + + lutBltCtl.fields.length = length; + lutBltCtl.fields.lutType = HYPER_CMAP_TYPE; + + /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */ + if (fb->info.var.bits_per_pixel == 8) + lutBltCtl.fields.lutOffset = 2 * 256; + else + lutBltCtl.fields.lutOffset = 0 * 256; + + /* Offset points to start of LUT. Adjust for within LUT */ + lutBltCtl.fields.lutOffset += offsetWithinLut; + + return lutBltCtl; +} + + +static void hyperUndoITE(struct stifb_info *fb) +{ + int nFreeFifoSlots = 0; + u32 fbAddr; + + NGLE_LOCK(fb); + + GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1); + WRITE_WORD(0xffffffff, fb, REG_32); + + /* Write overlay transparency mask so only entry 255 is transparent */ + + /* Hardware setup for full-depth write to "magic" location */ + GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7); + NGLE_QUICK_SET_DST_BM_ACCESS(fb, + BA(IndexedDcd, Otc04, Ots08, AddrLong, + BAJustPoint(0), BINovly, BAIndexBase(0))); + NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, + IBOvals(RopSrc, MaskAddrOffset(0), + BitmapExtent08, StaticReg(0), + DataDynamic, MaskOtc, BGx(0), FGx(0))); + + /* Now prepare to write to the "magic" location */ + fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0); + NGLE_BINC_SET_DSTADDR(fb, fbAddr); + NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff); + NGLE_BINC_SET_DSTMASK(fb, 0xffffffff); + + /* Finally, write a zero to clear the mask */ + NGLE_BINC_WRITE32(fb, 0); + + NGLE_UNLOCK(fb); +} + +static void +ngleDepth8_ClearImagePlanes(struct stifb_info *fb) +{ + /* FIXME! */ +} + +static void +ngleDepth24_ClearImagePlanes(struct stifb_info *fb) +{ + /* FIXME! */ +} + +static void +ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg) +{ + int nFreeFifoSlots = 0; + u32 packed_dst; + u32 packed_len; + + NGLE_LOCK(fb); + + GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4); + NGLE_QUICK_SET_DST_BM_ACCESS(fb, + BA(IndexedDcd, Otc32, OtsIndirect, + AddrLong, BAJustPoint(0), + BINattr, BAIndexBase(0))); + NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg); + NGLE_SET_TRANSFERDATA(fb, 0xffffffff); + + NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, + IBOvals(RopSrc, MaskAddrOffset(0), + BitmapExtent08, StaticReg(1), + DataDynamic, MaskOtc, + BGx(0), FGx(0))); + packed_dst = 0; + packed_len = (fb->info.var.xres << 16) | fb->info.var.yres; + GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2); + NGLE_SET_DSTXY(fb, packed_dst); + SET_LENXY_START_RECFILL(fb, packed_len); + + /* + * In order to work around an ELK hardware problem (Buffy doesn't + * always flush it's buffers when writing to the attribute + * planes), at least 4 pixels must be written to the attribute + * planes starting at (X == 1280) and (Y != to the last Y written + * by BIF): + */ + + if (fb->id == S9000_ID_A1659A) { /* ELK_DEVICE_ID */ + /* It's safe to use scanline zero: */ + packed_dst = (1280 << 16); + GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2); + NGLE_SET_DSTXY(fb, packed_dst); + packed_len = (4 << 16) | 1; + SET_LENXY_START_RECFILL(fb, packed_len); + } /* ELK Hardware Kludge */ + + /**** Finally, set the Control Plane Register back to zero: ****/ + GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1); + NGLE_QUICK_SET_CTL_PLN_REG(fb, 0); + + NGLE_UNLOCK(fb); +} + +static void +ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data) +{ + int nFreeFifoSlots = 0; + u32 packed_dst; + u32 packed_len; + + NGLE_LOCK(fb); + + /* Hardware setup */ + GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8); + NGLE_QUICK_SET_DST_BM_ACCESS(fb, + BA(IndexedDcd, Otc04, Ots08, AddrLong, + BAJustPoint(0), BINovly, BAIndexBase(0))); + + NGLE_SET_TRANSFERDATA(fb, 0xffffffff); /* Write foreground color */ + + NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data); + NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask); + + packed_dst = 0; + packed_len = (fb->info.var.xres << 16) | fb->info.var.yres; + NGLE_SET_DSTXY(fb, packed_dst); + + /* Write zeroes to overlay planes */ + NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, + IBOvals(RopSrc, MaskAddrOffset(0), + BitmapExtent08, StaticReg(0), + DataDynamic, MaskOtc, BGx(0), FGx(0))); + + SET_LENXY_START_RECFILL(fb, packed_len); + + NGLE_UNLOCK(fb); +} + +static void +hyperResetPlanes(struct stifb_info *fb, int enable) +{ + unsigned int controlPlaneReg; + + NGLE_LOCK(fb); + + if (IS_24_DEVICE(fb)) + if (fb->info.var.bits_per_pixel == 32) + controlPlaneReg = 0x04000F00; + else + controlPlaneReg = 0x00000F00; /* 0x00000800 should be enought, but lets clear all 4 bits */ + else + controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */ + + switch (enable) { + case ENABLE: + /* clear screen */ + if (IS_24_DEVICE(fb)) + ngleDepth24_ClearImagePlanes(fb); + else + ngleDepth8_ClearImagePlanes(fb); + + /* Paint attribute planes for default case. + * On Hyperdrive, this means all windows using overlay cmap 0. */ + ngleResetAttrPlanes(fb, controlPlaneReg); + + /* clear overlay planes */ + ngleClearOverlayPlanes(fb, 0xff, 255); + + /************************************************** + ** Also need to counteract ITE settings + **************************************************/ + hyperUndoITE(fb); + break; + + case DISABLE: + /* clear screen */ + if (IS_24_DEVICE(fb)) + ngleDepth24_ClearImagePlanes(fb); + else + ngleDepth8_ClearImagePlanes(fb); + ngleResetAttrPlanes(fb, controlPlaneReg); + ngleClearOverlayPlanes(fb, 0xff, 0); + break; + + case -1: /* RESET */ + hyperUndoITE(fb); + ngleResetAttrPlanes(fb, controlPlaneReg); + break; + } + + NGLE_UNLOCK(fb); +} + +/* Return pointer to in-memory structure holding ELK device-dependent ROM values. */ + +static void +ngleGetDeviceRomData(struct stifb_info *fb) +{ +#if 0 +XXX: FIXME: !!! + int *pBytePerLongDevDepData;/* data byte == LSB */ + int *pRomTable; + NgleDevRomData *pPackedDevRomData; + int sizePackedDevRomData = sizeof(*pPackedDevRomData); + char *pCard8; + int i; + char *mapOrigin = NULL; + + int romTableIdx; + + pPackedDevRomData = fb->ngle_rom; + + SETUP_HW(fb); + if (fb->id == S9000_ID_ARTIST) { + pPackedDevRomData->cursor_pipeline_delay = 4; + pPackedDevRomData->video_interleaves = 4; + } else { + /* Get pointer to unpacked byte/long data in ROM */ + pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION]; + + /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */ + if (fb->id == S9000_ID_TOMCAT) + { + /* jump to the correct ROM table */ + GET_ROMTABLE_INDEX(romTableIdx); + while (romTableIdx > 0) + { + pCard8 = (Card8 *) pPackedDevRomData; + pRomTable = pBytePerLongDevDepData; + /* Pack every fourth byte from ROM into structure */ + for (i = 0; i < sizePackedDevRomData; i++) + { + *pCard8++ = (Card8) (*pRomTable++); + } + + pBytePerLongDevDepData = (Card32 *) + ((Card8 *) pBytePerLongDevDepData + + pPackedDevRomData->sizeof_ngle_data); + + romTableIdx--; + } + } + + pCard8 = (Card8 *) pPackedDevRomData; + + /* Pack every fourth byte from ROM into structure */ + for (i = 0; i < sizePackedDevRomData; i++) + { + *pCard8++ = (Card8) (*pBytePerLongDevDepData++); + } + } + + SETUP_FB(fb); +#endif +} + + +#define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4 +#define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8 +#define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10 +#define HYPERBOWL_MODE2_8_24 15 + +/* HCRX specific boot-time initialization */ +static void __init +SETUP_HCRX(struct stifb_info *fb) +{ + int hyperbowl; + int nFreeFifoSlots = 0; + + if (fb->id != S9000_ID_HCRX) + return; + + /* Initialize Hyperbowl registers */ + GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7); + + if (IS_24_DEVICE(fb)) { + hyperbowl = (fb->info.var.bits_per_pixel == 32) ? + HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE : + HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE; + + /* First write to Hyperbowl must happen twice (bug) */ + WRITE_WORD(hyperbowl, fb, REG_40); + WRITE_WORD(hyperbowl, fb, REG_40); + + WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39); + + WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */ + WRITE_WORD(0x404c4048, fb, REG_43); + WRITE_WORD(0x034c0348, fb, REG_44); + WRITE_WORD(0x444c4448, fb, REG_45); + } else { + hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES; + + /* First write to Hyperbowl must happen twice (bug) */ + WRITE_WORD(hyperbowl, fb, REG_40); + WRITE_WORD(hyperbowl, fb, REG_40); + + WRITE_WORD(0x00000000, fb, REG_42); + WRITE_WORD(0x00000000, fb, REG_43); + WRITE_WORD(0x00000000, fb, REG_44); + WRITE_WORD(0x444c4048, fb, REG_45); + } +} + + +/* ------------------- driver specific functions --------------------------- */ + +#define TMPBUFLEN 2048 + +static ssize_t +stifb_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + struct inode *inode = file->f_dentry->d_inode; + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + char tmpbuf[TMPBUFLEN]; + + if (!info || ! info->screen_base) + return -ENODEV; + + if (p >= info->fix.smem_len) + return 0; + if (count >= info->fix.smem_len) + count = info->fix.smem_len; + if (count + p > info->fix.smem_len) + count = info->fix.smem_len - p; + if (count > sizeof(tmpbuf)) + count = sizeof(tmpbuf); + if (count) { + char *base_addr; + + base_addr = info->screen_base; + memcpy_fromio(&tmpbuf, base_addr+p, count); + count -= copy_to_user(buf, &tmpbuf, count); + if (!count) + return -EFAULT; + *ppos += count; + } + return count; +} + +static ssize_t +stifb_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + unsigned long p = *ppos; + size_t c; + int err; + char tmpbuf[TMPBUFLEN]; + + if (!info || !info->screen_base) + return -ENODEV; + + if (p > info->fix.smem_len) + return -ENOSPC; + if (count >= info->fix.smem_len) + count = info->fix.smem_len; + err = 0; + if (count + p > info->fix.smem_len) { + count = info->fix.smem_len - p; + err = -ENOSPC; + } + + p += (unsigned long)info->screen_base; + c = count; + while (c) { + int len = c > sizeof(tmpbuf) ? sizeof(tmpbuf) : c; + err = -EFAULT; + if (copy_from_user(&tmpbuf, buf, len)) + break; + memcpy_toio(p, &tmpbuf, len); + c -= len; + p += len; + buf += len; + *ppos += len; + } + if (count-c) + return (count-c); + return err; +} + +static int +stifb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, struct fb_info *info) +{ + struct stifb_info *fb = (struct stifb_info *) info; + u32 color; + + if (regno >= 256) /* no. of hw registers */ + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + DEBUG_OFF(); + + START_IMAGE_COLORMAP_ACCESS(fb); + + if (fb->info.var.grayscale) { + /* gray = 0.30*R + 0.59*G + 0.11*B */ + color = ((red * 77) + + (green * 151) + + (blue * 28)) >> 8; + } else { + color = ((red << 16) | + (green << 8) | + (blue)); + } + + if (info->var.bits_per_pixel == 32) { + ((u32 *)(info->pseudo_palette))[regno] = + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + } else { + ((u32 *)(info->pseudo_palette))[regno] = regno; + } + + WRITE_IMAGE_COLOR(fb, regno, 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); + } + + DEBUG_ON(); + + return 0; +} + +static int +stifb_blank(int blank_mode, struct fb_info *info) +{ + struct stifb_info *fb = (struct stifb_info *) info; + int enable = (blank_mode == 0) ? ENABLE : DISABLE; + + switch (fb->id) { + case S9000_ID_A1439A: + CRX24_ENABLE_DISABLE_DISPLAY(fb, enable); + break; + case CRT_ID_VISUALIZE_EG: + case S9000_ID_ARTIST: + ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable); + break; + case S9000_ID_HCRX: + HYPER_ENABLE_DISABLE_DISPLAY(fb, enable); + break; + case S9000_ID_A1659A:; /* fall through */ + case S9000_ID_TIMBER:; + case CRX24_OVERLAY_PLANES:; + default: + ENABLE_DISABLE_DISPLAY(fb, enable); + break; + } + + SETUP_FB(fb); + return 0; +} + +static void __init +stifb_init_display(struct stifb_info *fb) +{ + int id = fb->id; + + SETUP_FB(fb); + + /* HCRX specific initialization */ + SETUP_HCRX(fb); + + /* + if (id == S9000_ID_HCRX) + hyperInitSprite(fb); + else + ngleInitSprite(fb); + */ + + /* Initialize the image planes. */ + switch (id) { + case S9000_ID_HCRX: + hyperResetPlanes(fb, ENABLE); + break; + case S9000_ID_A1439A: + rattlerSetupPlanes(fb); + break; + case S9000_ID_A1659A: + case S9000_ID_ARTIST: + case CRT_ID_VISUALIZE_EG: + elkSetupPlanes(fb); + break; + } + + /* Clear attribute planes on non HCRX devices. */ + switch (id) { + case S9000_ID_A1659A: + case S9000_ID_A1439A: + if (fb->info.var.bits_per_pixel == 32) + ngleSetupAttrPlanes(fb, BUFF1_CMAP3); + else { + ngleSetupAttrPlanes(fb, BUFF1_CMAP0); + } + if (id == S9000_ID_A1439A) + ngleClearOverlayPlanes(fb, 0xff, 0); + break; + case S9000_ID_ARTIST: + case CRT_ID_VISUALIZE_EG: + if (fb->info.var.bits_per_pixel == 32) + ngleSetupAttrPlanes(fb, BUFF1_CMAP3); + else { + ngleSetupAttrPlanes(fb, ARTIST_CMAP0); + } + break; + } + stifb_blank(0, (struct fb_info *)fb); /* 0=enable screen */ + + SETUP_FB(fb); +} + +/* ------------ Interfaces to hardware functions ------------ */ + +static struct fb_ops stifb_ops = { + .owner = THIS_MODULE, + .fb_read = stifb_read, + .fb_write = stifb_write, + .fb_setcolreg = stifb_setcolreg, + .fb_blank = stifb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + + +/* + * Initialization + */ + +int __init +stifb_init_fb(struct sti_struct *sti, int bpp_pref) +{ + struct fb_fix_screeninfo *fix; + struct fb_var_screeninfo *var; + struct stifb_info *fb; + struct fb_info *info; + unsigned long sti_rom_address; + char *dev_name; + int bpp, xres, yres; + + fb = kmalloc(sizeof(*fb), GFP_ATOMIC); + if (!fb) { + printk(KERN_ERR "stifb: Could not allocate stifb structure\n"); + return -ENODEV; + } + + info = &fb->info; + + /* set struct to a known state */ + memset(fb, 0, sizeof(*fb)); + fix = &info->fix; + var = &info->var; + + fb->sti = sti; + /* store upper 32bits of the graphics id */ + fb->id = fb->sti->graphics_id[0]; + + /* only supported cards are allowed */ + switch (fb->id) { + case CRT_ID_VISUALIZE_EG: + /* look for a double buffering device like e.g. the + "INTERNAL_EG_DX1024" in the RDI precisionbook laptop + which won't work. The same device in non-double + buffering mode returns "INTERNAL_EG_X1024". */ + if (strstr(sti->outptr.dev_name, "EG_DX")) { + printk(KERN_WARNING + "stifb: ignoring '%s'. Disable double buffering in IPL menu.\n", + sti->outptr.dev_name); + goto out_err0; + } + /* fall though */ + case S9000_ID_ARTIST: + case S9000_ID_HCRX: + case S9000_ID_TIMBER: + case S9000_ID_A1659A: + case S9000_ID_A1439A: + break; + default: + printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n", + sti->outptr.dev_name, fb->id); + goto out_err0; + } + + /* default to 8 bpp on most graphic chips */ + bpp = 8; + xres = sti_onscreen_x(fb->sti); + yres = sti_onscreen_y(fb->sti); + + ngleGetDeviceRomData(fb); + + /* get (virtual) io region base addr */ + fix->mmio_start = REGION_BASE(fb,2); + fix->mmio_len = 0x400000; + + /* Reject any device not in the NGLE family */ + switch (fb->id) { + case S9000_ID_A1659A: /* CRX/A1659A */ + break; + case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */ + var->grayscale = 1; + fb->id = S9000_ID_A1659A; + break; + case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */ + dev_name = fb->sti->outptr.dev_name; + if (strstr(dev_name, "GRAYSCALE") || + strstr(dev_name, "Grayscale") || + strstr(dev_name, "grayscale")) + var->grayscale = 1; + break; + case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */ + /* FIXME: TomCat supports two heads: + * fb.iobase = REGION_BASE(fb_info,3); + * fb.screen_base = (void*) REGION_BASE(fb_info,2); + * for now we only support the left one ! */ + xres = fb->ngle_rom.x_size_visible; + yres = fb->ngle_rom.y_size_visible; + fb->id = S9000_ID_A1659A; + break; + case S9000_ID_A1439A: /* CRX24/A1439A */ + bpp = 32; + break; + case S9000_ID_HCRX: /* Hyperdrive/HCRX */ + memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom)); + if ((fb->sti->regions_phys[0] & 0xfc000000) == + (fb->sti->regions_phys[2] & 0xfc000000)) + sti_rom_address = fb->sti->regions_phys[0]; + else + sti_rom_address = fb->sti->regions_phys[1]; +#ifdef __LP64__ + sti_rom_address |= 0xffffffff00000000; +#endif + fb->deviceSpecificConfig = gsc_readl(sti_rom_address); + if (IS_24_DEVICE(fb)) { + if (bpp_pref == 8 || bpp_pref == 32) + bpp = bpp_pref; + else + bpp = 32; + } else + bpp = 8; + READ_WORD(fb, REG_15); + SETUP_HW(fb); + break; + case CRT_ID_VISUALIZE_EG: + case S9000_ID_ARTIST: /* Artist */ + break; + default: +#ifdef FALLBACK_TO_1BPP + printk(KERN_WARNING + "stifb: Unsupported graphics card (id=0x%08x) " + "- now trying 1bpp mode instead\n", + fb->id); + bpp = 1; /* default to 1 bpp */ + break; +#else + printk(KERN_WARNING + "stifb: Unsupported graphics card (id=0x%08x) " + "- skipping.\n", + fb->id); + goto out_err0; +#endif + } + + + /* get framebuffer physical and virtual base addr & len (64bit ready) */ + fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]); + fix->smem_len = fb->sti->regions[1].region_desc.length * 4096; + + fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8; + if (!fix->line_length) + fix->line_length = 2048; /* default */ + + /* limit fbsize to max visible screen size */ + if (fix->smem_len > yres*fix->line_length) + fix->smem_len = yres*fix->line_length; + + fix->accel = FB_ACCEL_NONE; + + switch (bpp) { + case 1: + fix->type = FB_TYPE_PLANES; /* well, sort of */ + fix->visual = FB_VISUAL_MONO10; + var->red.length = var->green.length = var->blue.length = 1; + break; + case 8: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_PSEUDOCOLOR; + var->red.length = var->green.length = var->blue.length = 8; + break; + case 32: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_TRUECOLOR; + 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; + default: + break; + } + + var->xres = var->xres_virtual = xres; + var->yres = var->yres_virtual = yres; + var->bits_per_pixel = bpp; + + strcpy(fix->id, "stifb"); + info->fbops = &stifb_ops; + info->screen_base = (void*) REGION_BASE(fb,1); + info->flags = FBINFO_DEFAULT; + info->pseudo_palette = &fb->pseudo_palette; + + /* This has to been done !!! */ + fb_alloc_cmap(&info->cmap, 256, 0); + stifb_init_display(fb); + + if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) { + printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n", + fix->smem_start, fix->smem_start+fix->smem_len); + goto out_err1; + } + + if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) { + printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n", + fix->mmio_start, fix->mmio_start+fix->mmio_len); + goto out_err2; + } + + 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, %s, id: %04x, mmio: 0x%04lx\n", + fb->info.node, + fix->id, + var->xres, + var->yres, + var->bits_per_pixel, + sti->outptr.dev_name, + fb->id, + fix->mmio_start); + + return 0; + + +out_err3: + release_mem_region(fix->mmio_start, fix->mmio_len); +out_err2: + release_mem_region(fix->smem_start, fix->smem_len); +out_err1: + fb_dealloc_cmap(&info->cmap); +out_err0: + kfree(fb); + return -ENXIO; +} + +static int stifb_disabled __initdata; + +int __init +stifb_setup(char *options); + +int __init +stifb_init(void) +{ + struct sti_struct *sti; + struct sti_struct *def_sti; + int i; + +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("stifb", &option)) + return -ENODEV; + stifb_setup(option); +#endif + if (stifb_disabled) { + printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n"); + return -ENXIO; + } + + def_sti = sti_get_rom(0); + if (def_sti) { + for (i = 1; i <= MAX_STI_ROMS; i++) { + sti = sti_get_rom(i); + if (!sti) + break; + if (sti == def_sti) { + stifb_init_fb(sti, stifb_bpp_pref[i - 1]); + break; + } + } + } + + for (i = 1; i <= MAX_STI_ROMS; i++) { + sti = sti_get_rom(i); + if (!sti) + break; + if (sti == def_sti) + continue; + stifb_init_fb(sti, stifb_bpp_pref[i - 1]); + } + return 0; +} + +/* + * Cleanup + */ + +static void __exit +stifb_cleanup(void) +{ + struct sti_struct *sti; + int i; + + for (i = 1; i <= MAX_STI_ROMS; i++) { + sti = sti_get_rom(i); + if (!sti) + break; + if (sti->info) { + struct fb_info *info = sti->info; + unregister_framebuffer(sti->info); + release_mem_region(info->fix.mmio_start, info->fix.mmio_len); + release_mem_region(info->fix.smem_start, info->fix.smem_len); + fb_dealloc_cmap(&info->cmap); + kfree(info); + } + sti->info = NULL; + } +} + +int __init +stifb_setup(char *options) +{ + int i; + + if (!options || !*options) + return 0; + + if (strncmp(options, "off", 3) == 0) { + stifb_disabled = 1; + options += 3; + } + + if (strncmp(options, "bpp", 3) == 0) { + options += 3; + for (i = 0; i < MAX_STI_ROMS; i++) { + if (*options++ != ':') + break; + stifb_bpp_pref[i] = simple_strtoul(options, &options, 10); + } + } + return 0; +} + +__setup("stifb=", stifb_setup); + +module_init(stifb_init); +module_exit(stifb_cleanup); + +MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>"); +MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines"); +MODULE_LICENSE("GPL v2"); + +MODULE_PARM(bpp, "i"); +MODULE_PARM_DESC(mem, "Bits per pixel (default: 8)"); + diff --git a/drivers/video/sun3fb.c b/drivers/video/sun3fb.c new file mode 100644 index 000000000000..9b36b9df535f --- /dev/null +++ b/drivers/video/sun3fb.c @@ -0,0 +1,704 @@ +/* + * linux/drivers/video/sun3fb.c -- Frame buffer driver for Sun3 + * + * (C) 1998 Thomas Bogendoerfer + * + * This driver is bases on sbusfb.c, which is + * + * Copyright (C) 1998 Jakub Jelinek + * + * This driver is partly based on the Open Firmware console driver + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * and SPARC console subsystem + * + * Copyright (C) 1995 Peter Zaitcev (zaitcev@yahoo.com) + * Copyright (C) 1995-1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995-1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) + * Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + * + * 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/config.h> +#include <linux/module.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/selection.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/kd.h> +#include <linux/vt_kern.h> + +#include <asm/uaccess.h> +#include <asm/pgtable.h> /* io_remap_page_range() */ + +#ifdef CONFIG_SUN3 +#include <asm/oplib.h> +#include <asm/machines.h> +#include <asm/idprom.h> + +#define CGFOUR_OBMEM_ADDR 0x1f300000 +#define BWTWO_OBMEM_ADDR 0x1f000000 +#define BWTWO_OBMEM50_ADDR 0x00100000 + +#endif +#ifdef CONFIG_SUN3X +#include <asm/sun3x.h> +#endif +#include <video/sbusfb.h> + +#define DEFAULT_CURSOR_BLINK_RATE (2*HZ/5) + +#define CURSOR_SHAPE 1 +#define CURSOR_BLINK 2 + +#define mymemset(x,y) memset(x,0,y) + + /* + * Interface used by the world + */ + +int sun3fb_init(void); +void sun3fb_setup(char *options); + +static char fontname[40] __initdata = { 0 }; +static int curblink __initdata = 1; + +static int sun3fb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int sun3fb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int sun3fb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int sun3fb_blank(int blank, struct fb_info *info); +static void sun3fb_cursor(struct display *p, int mode, int x, int y); +static void sun3fb_clear_margin(struct display *p, int s); + + /* + * Interface to the low level console driver + */ + +static int sun3fbcon_switch(int con, struct fb_info *info); +static int sun3fbcon_updatevar(int con, struct fb_info *info); + + /* + * Internal routines + */ + +static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info); + +static struct fb_ops sun3fb_ops = { + .owner = THIS_MODULE, + .fb_get_fix = sun3fb_get_fix, + .fb_get_var = sun3fb_get_var, + .fb_set_var = sun3fb_set_var, + .fb_get_cmap = sun3fb_get_cmap, + .fb_set_cmap = sun3fb_set_cmap, + .fb_setcolreg = sun3fb_setcolreg, + .fb_blank = sun3fb_blank, +}; + +static void sun3fb_clear_margin(struct display *p, int s) +{ + struct fb_info_sbusfb *fb = sbusfbinfod(p); + + return; + + if (fb->switch_from_graph) + (*fb->switch_from_graph)(fb); + if (fb->fill) { + unsigned short rects [16]; + + rects [0] = 0; + rects [1] = 0; + rects [2] = fb->var.xres_virtual; + rects [3] = fb->y_margin; + rects [4] = 0; + rects [5] = fb->y_margin; + rects [6] = fb->x_margin; + rects [7] = fb->var.yres_virtual; + rects [8] = fb->var.xres_virtual - fb->x_margin; + rects [9] = fb->y_margin; + rects [10] = fb->var.xres_virtual; + rects [11] = fb->var.yres_virtual; + rects [12] = fb->x_margin; + rects [13] = fb->var.yres_virtual - fb->y_margin; + rects [14] = fb->var.xres_virtual - fb->x_margin; + rects [15] = fb->var.yres_virtual; + (*fb->fill)(fb, p, s, 4, rects); + } else { + unsigned char *fb_base = fb->info.screen_base, *q; + int skip_bytes = fb->y_margin * fb->var.xres_virtual; + int scr_size = fb->var.xres_virtual * fb->var.yres_virtual; + int h, he, incr, size; + + he = fb->var.yres; + if (fb->var.bits_per_pixel == 1) { + fb_base -= (skip_bytes + fb->x_margin) / 8; + skip_bytes /= 8; + scr_size /= 8; + mymemset (fb_base, skip_bytes - fb->x_margin / 8); + mymemset (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8); + incr = fb->var.xres_virtual / 8; + size = fb->x_margin / 8 * 2; + for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0; + h <= he; q += incr, h++) + mymemset (q, size); + } else { + fb_base -= (skip_bytes + fb->x_margin); + memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin); + memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin); + incr = fb->var.xres_virtual; + size = fb->x_margin * 2; + for (q = fb_base + skip_bytes - fb->x_margin, h = 0; + h <= he; q += incr, h++) + memset (q, attr_bgcol(p,s), size); + } + } +} + +static void sun3fb_disp_setup(struct display *p) +{ + struct fb_info_sbusfb *fb = sbusfbinfod(p); + + if (fb->setup) + fb->setup(p); + sun3fb_clear_margin(p, 0); +} + + /* + * Get the Fixed Part of the Display + */ + +static int sun3fb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct fb_info_sbusfb *fb = sbusfbinfo(info); + + memcpy(fix, &fb->fix, sizeof(struct fb_fix_screeninfo)); + return 0; +} + + /* + * Get the User Defined Part of the Display + */ + +static int sun3fb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct fb_info_sbusfb *fb = sbusfbinfo(info); + + memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo)); + return 0; +} + + /* + * Set the User Defined Part of the Display + */ + +static int sun3fb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct fb_info_sbusfb *fb = sbusfbinfo(info); + + if (var->xres > fb->var.xres || var->yres > fb->var.yres || + var->xres_virtual > fb->var.xres_virtual || + var->yres_virtual > fb->var.yres_virtual || + var->bits_per_pixel != fb->var.bits_per_pixel || + var->nonstd || + (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + return -EINVAL; + memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo)); + return 0; +} + + /* + * Hardware cursor + */ + +static unsigned char hw_cursor_cmap[2] = { 0, 0xff }; + +static void +sun3fb_cursor_timer_handler(unsigned long dev_addr) +{ + struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)dev_addr; + + if (!fb->setcursor) return; + + if (fb->cursor.mode & CURSOR_BLINK) { + fb->cursor.enable ^= 1; + fb->setcursor(fb); + } + + fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate; + add_timer(&fb->cursor.timer); +} + +static void sun3fb_cursor(struct display *p, int mode, int x, int y) +{ + struct fb_info_sbusfb *fb = sbusfbinfod(p); + + switch (mode) { + case CM_ERASE: + fb->cursor.mode &= ~CURSOR_BLINK; + fb->cursor.enable = 0; + (*fb->setcursor)(fb); + break; + + case CM_MOVE: + case CM_DRAW: + if (fb->cursor.mode & CURSOR_SHAPE) { + fb->cursor.size.fbx = fontwidth(p); + fb->cursor.size.fby = fontheight(p); + fb->cursor.chot.fbx = 0; + fb->cursor.chot.fby = 0; + fb->cursor.enable = 1; + memset (fb->cursor.bits, 0, sizeof (fb->cursor.bits)); + fb->cursor.bits[0][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p))); + fb->cursor.bits[1][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p))); + fb->cursor.bits[0][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p))); + fb->cursor.bits[1][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p))); + (*fb->setcursormap) (fb, hw_cursor_cmap, hw_cursor_cmap, hw_cursor_cmap); + (*fb->setcurshape) (fb); + } + fb->cursor.mode = CURSOR_BLINK; + if (fontwidthlog(p)) + fb->cursor.cpos.fbx = (x << fontwidthlog(p)) + fb->x_margin; + else + fb->cursor.cpos.fbx = (x * fontwidth(p)) + fb->x_margin; + if (fontheightlog(p)) + fb->cursor.cpos.fby = (y << fontheightlog(p)) + fb->y_margin; + else + fb->cursor.cpos.fby = (y * fontheight(p)) + fb->y_margin; + (*fb->setcursor)(fb); + break; + } +} + + /* + * Get the Colormap + */ + +static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + if (con == info->currcon) /* current console? */ + return fb_get_cmap(cmap, kspc, sun3fb_getcolreg, info); + else if (fb_display[con].cmap.len) /* non default colormap? */ + 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; +} + + /* + * Set the Colormap + */ + +static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + int err; + + if (!fb_display[con].cmap.len) { /* no colormap allocated? */ + if ((err = fb_alloc_cmap(&fb_display[con].cmap, 1<<fb_display[con].var.bits_per_pixel, 0))) + return err; + } + if (con == info->currcon) { /* current console? */ + err = fb_set_cmap(cmap, kspc, info); + if (!err) { + struct fb_info_sbusfb *fb = sbusfbinfo(info); + + if (fb->loadcmap) + (*fb->loadcmap)(fb, &fb_display[con], cmap->start, cmap->len); + } + return err; + } else + fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); + return 0; +} + + /* + * Setup: parse used options + */ + +void __init sun3fb_setup(char *options) +{ + char *p; + + for (p = options;;) { + if (!strncmp(p, "font=", 5)) { + int i; + + for (i = 0; i < sizeof(fontname) - 1; i++) + if (p[i+5] == ' ' || !p[i+5]) + break; + memcpy(fontname, p+5, i); + fontname[i] = 0; + } else if (!strncmp(p, "noblink", 7)) + curblink = 0; + while (*p && *p != ' ' && *p != ',') p++; + if (*p != ',') break; + p++; + } + + return; +} + +static int sun3fbcon_switch(int con, struct fb_info *info) +{ + int x_margin, y_margin; + struct fb_info_sbusfb *fb = sbusfbinfo(info); + int lastconsole; + + /* Do we have to save the colormap? */ + if (fb_display[info->currcon].cmap.len) + fb_get_cmap(&fb_display[info->currcon].cmap, 1, sun3fb_getcolreg, info); + + if (info->display_fg) { + lastconsole = info->display_fg->vc_num; + if (lastconsole != con && + (fontwidth(&fb_display[lastconsole]) != fontwidth(&fb_display[con]) || + fontheight(&fb_display[lastconsole]) != fontheight(&fb_display[con]))) + fb->cursor.mode |= CURSOR_SHAPE; + } + x_margin = (fb_display[con].var.xres_virtual - fb_display[con].var.xres) / 2; + y_margin = (fb_display[con].var.yres_virtual - fb_display[con].var.yres) / 2; + if (fb->margins) + fb->margins(fb, &fb_display[con], x_margin, y_margin); + if (fb->graphmode || fb->x_margin != x_margin || fb->y_margin != y_margin) { + fb->x_margin = x_margin; fb->y_margin = y_margin; + sun3fb_clear_margin(&fb_display[con], 0); + } + info->currcon = con; + /* Install new colormap */ + do_install_cmap(con, info); + return 0; +} + + /* + * Update the `var' structure (called by fbcon.c) + */ + +static int sun3fbcon_updatevar(int con, struct fb_info *info) +{ + /* Nothing */ + return 0; +} + + /* + * Blank the display. + */ + +static int sun3fb_blank(int blank, struct fb_info *info) +{ + struct fb_info_sbusfb *fb = sbusfbinfo(info); + + if (blank && fb->blank) + return fb->blank(fb); + else if (!blank && fb->unblank) + return fb->unblank(fb); + return 0; +} + + /* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info) +{ + struct fb_info_sbusfb *fb = sbusfbinfo(info); + + if (!fb->color_map || regno > 255) + return 1; + *red = (fb->color_map CM(regno, 0)<<8) | fb->color_map CM(regno, 0); + *green = (fb->color_map CM(regno, 1)<<8) | fb->color_map CM(regno, 1); + *blue = (fb->color_map CM(regno, 2)<<8) | fb->color_map CM(regno, 2); + *transp = 0; + return 0; +} + + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct fb_info_sbusfb *fb = sbusfbinfo(info); + + if (!fb->color_map || regno > 255) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + fb->color_map CM(regno, 0) = red; + fb->color_map CM(regno, 1) = green; + fb->color_map CM(regno, 2) = blue; + return 0; +} + +static int sun3fb_set_font(struct display *p, int width, int height) +{ + int w = p->var.xres_virtual, h = p->var.yres_virtual; + int depth = p->var.bits_per_pixel; + struct fb_info_sbusfb *fb = sbusfbinfod(p); + int x_margin, y_margin; + + if (depth > 8) depth = 8; + x_margin = (w % width) / 2; + y_margin = (h % height) / 2; + + p->var.xres = w - 2*x_margin; + p->var.yres = h - 2*y_margin; + + fb->cursor.mode |= CURSOR_SHAPE; + + if (fb->margins) + fb->margins(fb, p, x_margin, y_margin); + if (fb->x_margin != x_margin || fb->y_margin != y_margin) { + fb->x_margin = x_margin; fb->y_margin = y_margin; + sun3fb_clear_margin(p, 0); + } + + return 1; +} + +void sun3fb_palette(int enter) +{ + int i; + struct display *p; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + p = &fb_display[i]; + if (p->dispsw && p->dispsw->setup == sun3fb_disp_setup && + p->fb_info->display_fg && + p->fb_info->display_fg->vc_num == i) { + struct fb_info_sbusfb *fb = sbusfbinfod(p); + + if (fb->restore_palette) { + if (enter) + fb->restore_palette(fb); + else if (vc_cons[i].d->vc_mode != KD_GRAPHICS) + vc_cons[i].d->vc_sw->con_set_palette(vc_cons[i].d, color_table); + } + } + } +} + + /* + * Initialisation + */ +static int __init sun3fb_init_fb(int fbtype, unsigned long addr) +{ + static struct sbus_dev sdb; + struct fb_fix_screeninfo *fix; + struct fb_var_screeninfo *var; + struct display *disp; + struct fb_info_sbusfb *fb; + struct fbtype *type; + int linebytes, w, h, depth; + char *p = NULL; + + fb = kmalloc(sizeof(struct fb_info_sbusfb), GFP_ATOMIC); + if (!fb) + return -ENOMEM; + + memset(fb, 0, sizeof(struct fb_info_sbusfb)); + fix = &fb->fix; + var = &fb->var; + disp = &fb->disp; + type = &fb->type; + + sdb.reg_addrs[0].phys_addr = addr; + fb->sbdp = &sdb; + + type->fb_type = fbtype; + + type->fb_height = h = 900; + type->fb_width = w = 1152; +sizechange: + type->fb_depth = depth = (fbtype == FBTYPE_SUN2BW) ? 1 : 8; + linebytes = w * depth / 8; + type->fb_size = PAGE_ALIGN((linebytes) * h); +/* + fb->x_margin = (w & 7) / 2; + fb->y_margin = (h & 15) / 2; +*/ + fb->x_margin = fb->y_margin = 0; + + var->xres_virtual = w; + var->yres_virtual = h; + var->xres = w - 2*fb->x_margin; + var->yres = h - 2*fb->y_margin; + + var->bits_per_pixel = depth; + var->height = var->width = -1; + var->pixclock = 10000; + var->vmode = FB_VMODE_NONINTERLACED; + var->red.length = var->green.length = var->blue.length = 8; + + fix->line_length = linebytes; + fix->smem_len = type->fb_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_PSEUDOCOLOR; + + fb->info.fbops = &sun3fb_ops; + fb->info.disp = disp; + fb->info.currcon = -1; + strcpy(fb->info.fontname, fontname); + fb->info.changevar = NULL; + fb->info.switch_con = &sun3fbcon_switch; + fb->info.updatevar = &sun3fbcon_updatevar; + fb->info.flags = FBINFO_FLAG_DEFAULT; + + fb->cursor.hwsize.fbx = 32; + fb->cursor.hwsize.fby = 32; + + if (depth > 1 && !fb->color_map) { + if((fb->color_map = kmalloc(256 * 3, GFP_ATOMIC))==NULL) + return -ENOMEM; + } + + switch(fbtype) { +#ifdef CONFIG_FB_CGSIX + case FBTYPE_SUNFAST_COLOR: + p = cgsixfb_init(fb); break; +#endif +#ifdef CONFIG_FB_BWTWO + case FBTYPE_SUN2BW: + p = bwtwofb_init(fb); break; +#endif +#ifdef CONFIG_FB_CGTHREE + case FBTYPE_SUN4COLOR: + case FBTYPE_SUN3COLOR: + type->fb_size = 0x100000; + p = cgthreefb_init(fb); break; +#endif + } + fix->smem_start = (unsigned long)fb->info.screen_base; // FIXME + + if (!p) { + kfree(fb); + return -ENODEV; + } + + if (p == SBUSFBINIT_SIZECHANGE) + goto sizechange; + + disp->dispsw = &fb->dispsw; + if (fb->setcursor) { + fb->dispsw.cursor = sun3fb_cursor; + if (curblink) { + fb->cursor.blink_rate = DEFAULT_CURSOR_BLINK_RATE; + init_timer(&fb->cursor.timer); + fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate; + fb->cursor.timer.data = (unsigned long)fb; + fb->cursor.timer.function = sun3fb_cursor_timer_handler; + add_timer(&fb->cursor.timer); + } + } + fb->cursor.mode = CURSOR_SHAPE; + fb->dispsw.set_font = sun3fb_set_font; + fb->setup = fb->dispsw.setup; + fb->dispsw.setup = sun3fb_disp_setup; + fb->dispsw.clear_margins = NULL; + + disp->var = *var; + disp->visual = fix->visual; + disp->type = fix->type; + disp->type_aux = fix->type_aux; + disp->line_length = fix->line_length; + + if (fb->blank) + disp->can_soft_blank = 1; + + sun3fb_set_var(var, -1, &fb->info); + + if (register_framebuffer(&fb->info) < 0) { + kfree(fb); + return -EINVAL; + } + printk("fb%d: %s\n", fb->info.node, p); + + return 0; +} + + +int __init sun3fb_init(void) +{ + extern int con_is_present(void); + unsigned long addr; + char p4id; + + if (!con_is_present()) return -ENODEV; +#ifdef CONFIG_SUN3 + switch(*(romvec->pv_fbtype)) + { + case FBTYPE_SUN2BW: + addr = 0xfe20000; + return sun3fb_init_fb(FBTYPE_SUN2BW, addr); + case FBTYPE_SUN3COLOR: + case FBTYPE_SUN4COLOR: + if(idprom->id_machtype != (SM_SUN3|SM_3_60)) { + printk("sun3fb: cgthree/four only supported on 3/60\n"); + return -ENODEV; + } + + addr = CGFOUR_OBMEM_ADDR; + return sun3fb_init_fb(*(romvec->pv_fbtype), addr); + default: + printk("sun3fb: unsupported framebuffer\n"); + return -ENODEV; + } +#else + addr = SUN3X_VIDEO_BASE; + p4id = *(char *)SUN3X_VIDEO_P4ID; + + p4id = (p4id == 0x45) ? p4id : (p4id & 0xf0); + switch (p4id) { + case 0x00: + return sun3fb_init_fb(FBTYPE_SUN2BW, addr); +#if 0 /* not yet */ + case 0x40: + return sun3fb_init_fb(FBTYPE_SUN4COLOR, addr); + break; + case 0x45: + return sun3fb_init_fb(FBTYPE_SUN8COLOR, addr); + break; +#endif + case 0x60: + return sun3fb_init_fb(FBTYPE_SUNFAST_COLOR, addr); + } +#endif + + return -ENODEV; +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c new file mode 100644 index 000000000000..e2fa9e1ddc3b --- /dev/null +++ b/drivers/video/tcx.c @@ -0,0 +1,504 @@ +/* tcx.c: TCX frame buffer driver + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + * + * Driver layout based loosely on tgafb.c, see that file for credits. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> +#include <linux/mm.h> + +#include <asm/io.h> +#include <asm/sbus.h> +#include <asm/oplib.h> +#include <asm/fbio.h> + +#include "sbuslib.h" + +/* + * Local functions. + */ + +static int tcx_setcolreg(unsigned, unsigned, unsigned, unsigned, + unsigned, struct fb_info *); +static int tcx_blank(int, struct fb_info *); + +static int tcx_mmap(struct fb_info *, struct file *, struct vm_area_struct *); +static int tcx_ioctl(struct inode *, struct file *, unsigned int, + unsigned long, struct fb_info *); + +/* + * Frame buffer operations + */ + +static struct fb_ops tcx_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = tcx_setcolreg, + .fb_blank = tcx_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = tcx_mmap, + .fb_ioctl = tcx_ioctl, + .fb_cursor = soft_cursor, +}; + +/* THC definitions */ +#define TCX_THC_MISC_REV_SHIFT 16 +#define TCX_THC_MISC_REV_MASK 15 +#define TCX_THC_MISC_VSYNC_DIS (1 << 25) +#define TCX_THC_MISC_HSYNC_DIS (1 << 24) +#define TCX_THC_MISC_RESET (1 << 12) +#define TCX_THC_MISC_VIDEO (1 << 10) +#define TCX_THC_MISC_SYNC (1 << 9) +#define TCX_THC_MISC_VSYNC (1 << 8) +#define TCX_THC_MISC_SYNC_ENAB (1 << 7) +#define TCX_THC_MISC_CURS_RES (1 << 6) +#define TCX_THC_MISC_INT_ENAB (1 << 5) +#define TCX_THC_MISC_INT (1 << 4) +#define TCX_THC_MISC_INIT 0x9f +#define TCX_THC_REV_REV_SHIFT 20 +#define TCX_THC_REV_REV_MASK 15 +#define TCX_THC_REV_MINREV_SHIFT 28 +#define TCX_THC_REV_MINREV_MASK 15 + +/* The contents are unknown */ +struct tcx_tec { + volatile u32 tec_matrix; + volatile u32 tec_clip; + volatile u32 tec_vdc; +}; + +struct tcx_thc { + volatile u32 thc_rev; + u32 thc_pad0[511]; + volatile u32 thc_hs; /* hsync timing */ + volatile u32 thc_hsdvs; + volatile u32 thc_hd; + volatile u32 thc_vs; /* vsync timing */ + volatile u32 thc_vd; + volatile u32 thc_refresh; + volatile u32 thc_misc; + u32 thc_pad1[56]; + volatile u32 thc_cursxy; /* cursor x,y position (16 bits each) */ + volatile u32 thc_cursmask[32]; /* cursor mask bits */ + volatile u32 thc_cursbits[32]; /* what to show where mask enabled */ +}; + +struct bt_regs { + volatile u32 addr; + volatile u32 color_map; + volatile u32 control; + volatile u32 cursor; +}; + +#define TCX_MMAP_ENTRIES 14 + +struct tcx_par { + spinlock_t lock; + struct bt_regs __iomem *bt; + struct tcx_thc __iomem *thc; + struct tcx_tec __iomem *tec; + volatile u32 __iomem *cplane; + + u32 flags; +#define TCX_FLAG_BLANKED 0x00000001 + + unsigned long physbase; + unsigned long fbsize; + + struct sbus_mmap_map mmap_map[TCX_MMAP_ENTRIES]; + int lowdepth; + + struct sbus_dev *sdev; + struct list_head list; +}; + +/* Reset control plane so that WID is 8-bit plane. */ +static void __tcx_set_control_plane (struct tcx_par *par) +{ + volatile u32 __iomem *p, *pend; + + if (par->lowdepth) + return; + + p = par->cplane; + if (p == NULL) + return; + for (pend = p + par->fbsize; p < pend; p++) { + u32 tmp = sbus_readl(p); + + tmp &= 0xffffff; + sbus_writel(tmp, p); + } +} + +static void tcx_reset (struct fb_info *info) +{ + struct tcx_par *par = (struct tcx_par *) info->par; + unsigned long flags; + + spin_lock_irqsave(&par->lock, flags); + __tcx_set_control_plane(par); + spin_unlock_irqrestore(&par->lock, flags); +} + +/** + * tcx_setcolreg - Optional function. Sets a color register. + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @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. + * @info: frame buffer info structure + */ +static int tcx_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct tcx_par *par = (struct tcx_par *) info->par; + struct bt_regs __iomem *bt = par->bt; + unsigned long flags; + + if (regno >= 256) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + spin_lock_irqsave(&par->lock, flags); + + sbus_writel(regno << 24, &bt->addr); + sbus_writel(red << 24, &bt->color_map); + sbus_writel(green << 24, &bt->color_map); + sbus_writel(blue << 24, &bt->color_map); + + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +/** + * tcx_blank - Optional function. Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + */ +static int +tcx_blank(int blank, struct fb_info *info) +{ + struct tcx_par *par = (struct tcx_par *) info->par; + struct tcx_thc __iomem *thc = par->thc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&par->lock, flags); + + val = sbus_readl(&thc->thc_misc); + + switch (blank) { + case FB_BLANK_UNBLANK: /* Unblanking */ + val &= ~(TCX_THC_MISC_VSYNC_DIS | + TCX_THC_MISC_HSYNC_DIS); + val |= TCX_THC_MISC_VIDEO; + par->flags &= ~TCX_FLAG_BLANKED; + break; + + case FB_BLANK_NORMAL: /* Normal blanking */ + val &= ~TCX_THC_MISC_VIDEO; + par->flags |= TCX_FLAG_BLANKED; + break; + + case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ + val |= TCX_THC_MISC_VSYNC_DIS; + break; + case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ + val |= TCX_THC_MISC_HSYNC_DIS; + break; + + case FB_BLANK_POWERDOWN: /* Poweroff */ + break; + }; + + sbus_writel(val, &thc->thc_misc); + + spin_unlock_irqrestore(&par->lock, flags); + + return 0; +} + +static struct sbus_mmap_map __tcx_mmap_map[TCX_MMAP_ENTRIES] = { + { + .voff = TCX_RAM8BIT, + .size = SBUS_MMAP_FBSIZE(1) + }, + { + .voff = TCX_RAM24BIT, + .size = SBUS_MMAP_FBSIZE(4) + }, + { + .voff = TCX_UNK3, + .size = SBUS_MMAP_FBSIZE(8) + }, + { + .voff = TCX_UNK4, + .size = SBUS_MMAP_FBSIZE(8) + }, + { + .voff = TCX_CONTROLPLANE, + .size = SBUS_MMAP_FBSIZE(4) + }, + { + .voff = TCX_UNK6, + .size = SBUS_MMAP_FBSIZE(8) + }, + { + .voff = TCX_UNK7, + .size = SBUS_MMAP_FBSIZE(8) + }, + { + .voff = TCX_TEC, + .size = PAGE_SIZE + }, + { + .voff = TCX_BTREGS, + .size = PAGE_SIZE + }, + { + .voff = TCX_THC, + .size = PAGE_SIZE + }, + { + .voff = TCX_DHC, + .size = PAGE_SIZE + }, + { + .voff = TCX_ALT, + .size = PAGE_SIZE + }, + { + .voff = TCX_UNK2, + .size = 0x20000 + }, + { .size = 0 } +}; + +static int tcx_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) +{ + struct tcx_par *par = (struct tcx_par *)info->par; + + return sbusfb_mmap_helper(par->mmap_map, + par->physbase, par->fbsize, + par->sdev->reg_addrs[0].which_io, + vma); +} + +static int tcx_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *info) +{ + struct tcx_par *par = (struct tcx_par *) info->par; + + return sbusfb_ioctl_helper(cmd, arg, info, + FBTYPE_TCXCOLOR, + (par->lowdepth ? 8 : 24), + par->fbsize); +} + +/* + * Initialisation + */ + +static void +tcx_init_fix(struct fb_info *info, int linebytes) +{ + struct tcx_par *par = (struct tcx_par *)info->par; + const char *tcx_name; + + if (par->lowdepth) + tcx_name = "TCX8"; + else + tcx_name = "TCX24"; + + strlcpy(info->fix.id, tcx_name, sizeof(info->fix.id)); + + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + + info->fix.line_length = linebytes; + + info->fix.accel = FB_ACCEL_SUN_TCX; +} + +struct all_info { + struct fb_info info; + struct tcx_par par; + struct list_head list; +}; +static LIST_HEAD(tcx_list); + +static void tcx_init_one(struct sbus_dev *sdev) +{ + struct all_info *all; + int linebytes, i; + + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "tcx: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); + + INIT_LIST_HEAD(&all->list); + + spin_lock_init(&all->par.lock); + all->par.sdev = sdev; + + all->par.lowdepth = prom_getbool(sdev->prom_node, "tcx-8-bit"); + + sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); + + linebytes = prom_getintdefault(sdev->prom_node, "linebytes", + all->info.var.xres); + all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + + all->par.tec = sbus_ioremap(&sdev->resource[7], 0, + sizeof(struct tcx_tec), "tcx tec"); + all->par.thc = sbus_ioremap(&sdev->resource[9], 0, + sizeof(struct tcx_thc), "tcx thc"); + all->par.bt = sbus_ioremap(&sdev->resource[8], 0, + sizeof(struct bt_regs), "tcx dac"); + memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map)); + if (!all->par.lowdepth) { + all->par.cplane = sbus_ioremap(&sdev->resource[4], 0, + all->par.fbsize * sizeof(u32), "tcx cplane"); + } else { + all->par.mmap_map[1].size = SBUS_MMAP_EMPTY; + all->par.mmap_map[4].size = SBUS_MMAP_EMPTY; + all->par.mmap_map[5].size = SBUS_MMAP_EMPTY; + all->par.mmap_map[6].size = SBUS_MMAP_EMPTY; + } + + all->par.physbase = 0; + for (i = 0; i < TCX_MMAP_ENTRIES; i++) { + int j; + + switch (i) { + case 10: + j = 12; + break; + + case 11: case 12: + j = i - 1; + break; + + default: + j = i; + break; + }; + all->par.mmap_map[i].poff = sdev->reg_addrs[j].phys_addr; + } + + all->info.flags = FBINFO_DEFAULT; + all->info.fbops = &tcx_ops; +#ifdef CONFIG_SPARC32 + all->info.screen_base = (char __iomem *) + prom_getintdefault(sdev->prom_node, "address", 0); +#endif + if (!all->info.screen_base) + all->info.screen_base = sbus_ioremap(&sdev->resource[0], 0, + all->par.fbsize, "tcx ram"); + all->info.par = &all->par; + + /* Initialize brooktree DAC. */ + sbus_writel(0x04 << 24, &all->par.bt->addr); /* color planes */ + sbus_writel(0xff << 24, &all->par.bt->control); + sbus_writel(0x05 << 24, &all->par.bt->addr); + sbus_writel(0x00 << 24, &all->par.bt->control); + sbus_writel(0x06 << 24, &all->par.bt->addr); /* overlay plane */ + sbus_writel(0x73 << 24, &all->par.bt->control); + sbus_writel(0x07 << 24, &all->par.bt->addr); + sbus_writel(0x00 << 24, &all->par.bt->control); + + tcx_reset(&all->info); + + tcx_blank(0, &all->info); + + if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { + printk(KERN_ERR "tcx: Could not allocate color map.\n"); + kfree(all); + return; + } + + tcx_init_fix(&all->info, linebytes); + + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "tcx: Could not register framebuffer.\n"); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + return; + } + + list_add(&all->list, &tcx_list); + + printk("tcx: %s at %lx:%lx, %s\n", + sdev->prom_name, + (long) sdev->reg_addrs[0].which_io, + (long) sdev->reg_addrs[0].phys_addr, + all->par.lowdepth ? "8-bit only" : "24-bit depth"); +} + +int __init tcx_init(void) +{ + struct sbus_bus *sbus; + struct sbus_dev *sdev; + + if (fb_get_options("tcxfb", NULL)) + return -ENODEV; + + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "tcx")) + tcx_init_one(sdev); + } + + return 0; +} + +void __exit tcx_exit(void) +{ + struct list_head *pos, *tmp; + + list_for_each_safe(pos, tmp, &tcx_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } +} + +int __init +tcx_setup(char *arg) +{ + /* No cmdline options yet... */ + return 0; +} + +module_init(tcx_init); + +#ifdef MODULE +module_exit(tcx_exit); +#endif + +MODULE_DESCRIPTION("framebuffer driver for TCX chipsets"); +MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c new file mode 100644 index 000000000000..c34ba39b6f7e --- /dev/null +++ b/drivers/video/tdfxfb.c @@ -0,0 +1,1366 @@ +/* + * + * tdfxfb.c + * + * Author: Hannu Mallat <hmallat@cc.hut.fi> + * + * Copyright 1999 Hannu Mallat + * All rights reserved + * + * Created : Thu Sep 23 18:17:43 1999, hmallat + * Last modified: Tue Nov 2 21:19:47 1999, hmallat + * + * Lots of the information here comes from the Daryll Strauss' Banshee + * patches to the XF86 server, and the rest comes from the 3dfx + * Banshee specification. I'm very much indebted to Daryll for his + * work on the X server. + * + * Voodoo3 support was contributed Harold Oga. Lots of additions + * (proper acceleration, 24 bpp, hardware cursor) and bug fixes by Attila + * Kesmarki. Thanks guys! + * + * Voodoo1 and Voodoo2 support aren't relevant to this driver as they + * behave very differently from the Voodoo3/4/5. For anyone wanting to + * use frame buffer on the Voodoo1/2, see the sstfb driver (which is + * located at http://www.sourceforge.net/projects/sstfb). + * + * While I _am_ grateful to 3Dfx for releasing the specs for Banshee, + * I do wish the next version is a bit more complete. Without the XF86 + * patches I couldn't have gotten even this far... for instance, the + * extensions to the VGA register set go completely unmentioned in the + * spec! Also, lots of references are made to the 'SST core', but no + * spec is publicly available, AFAIK. + * + * The structure of this driver comes pretty much from the Permedia + * driver by Ilario Nardinocchi, which in turn is based on skeletonfb. + * + * TODO: + * - support for 16/32 bpp needs fixing (funky bootup penguin) + * - multihead support (basically need to support an array of fb_infos) + * - support other architectures (PPC, Alpha); does the fact that the VGA + * core can be accessed only thru I/O (not memory mapped) complicate + * things? + * + * Version history: + * + * 0.1.4 (released 2002-05-28) ported over to new fbdev api by James Simmons + * + * 0.1.3 (released 1999-11-02) added Attila's panning support, code + * reorg, hwcursor address page size alignment + * (for mmaping both frame buffer and regs), + * and my changes to get rid of hardcoded + * VGA i/o register locations (uses PCI + * configuration info now) + * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and + * improvements + * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga. + * 0.1.0 (released 1999-10-06) initial version + * + */ + +#include <linux/config.h> +#include <linux/module.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/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/nvram.h> +#include <asm/io.h> +#include <linux/timer.h> +#include <linux/spinlock.h> + +#include <video/tdfx.h> + +#undef TDFXFB_DEBUG +#ifdef TDFXFB_DEBUG +#define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b) +#else +#define DPRINTK(a,b...) +#endif + +#define BANSHEE_MAX_PIXCLOCK 270000 +#define VOODOO3_MAX_PIXCLOCK 300000 +#define VOODOO5_MAX_PIXCLOCK 350000 + +static struct fb_fix_screeninfo tdfx_fix __devinitdata = { + .id = "3Dfx", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .ypanstep = 1, + .ywrapstep = 1, + .accel = FB_ACCEL_3DFX_BANSHEE +}; + +static struct fb_var_screeninfo tdfx_var __devinitdata = { + /* "640x480, 8 bpp @ 60 Hz */ + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 1024, + .bits_per_pixel =8, + .red = {0, 8, 0}, + .blue = {0, 8, 0}, + .green = {0, 8, 0}, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .accel_flags = FB_ACCELF_TEXT, + .pixclock = 39722, + .left_margin = 40, + .right_margin = 24, + .upper_margin = 32, + .lower_margin = 11, + .hsync_len = 96, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED +}; + +/* + * PCI driver prototypes + */ +static int __devinit tdfxfb_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +static void __devexit tdfxfb_remove(struct pci_dev *pdev); + +static struct pci_device_id tdfxfb_id_table[] = { + { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE, + PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, + 0xff0000, 0 }, + { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3, + PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, + 0xff0000, 0 }, + { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5, + PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, + 0xff0000, 0 }, + { 0, } +}; + +static struct pci_driver tdfxfb_driver = { + .name = "tdfxfb", + .id_table = tdfxfb_id_table, + .probe = tdfxfb_probe, + .remove = __devexit_p(tdfxfb_remove), +}; + +MODULE_DEVICE_TABLE(pci, tdfxfb_id_table); + +/* + * Frame buffer device API + */ +static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb); +static int tdfxfb_set_par(struct fb_info *info); +static int tdfxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int tdfxfb_blank(int blank, struct fb_info *info); +static int tdfxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); +static int banshee_wait_idle(struct fb_info *info); +#ifdef CONFIG_FB_3DFX_ACCEL +static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); +static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image); +#endif /* CONFIG_FB_3DFX_ACCEL */ + +static struct fb_ops tdfxfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = tdfxfb_check_var, + .fb_set_par = tdfxfb_set_par, + .fb_setcolreg = tdfxfb_setcolreg, + .fb_blank = tdfxfb_blank, + .fb_pan_display = tdfxfb_pan_display, + .fb_sync = banshee_wait_idle, +#ifdef CONFIG_FB_3DFX_ACCEL + .fb_fillrect = tdfxfb_fillrect, + .fb_copyarea = tdfxfb_copyarea, + .fb_imageblit = tdfxfb_imageblit, +#else + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +#endif + .fb_cursor = soft_cursor, +}; + +/* + * do_xxx: Hardware-specific functions + */ +static u32 do_calc_pll(int freq, int *freq_out); +static void do_write_regs(struct fb_info *info, struct banshee_reg *reg); +static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short); + +/* + * Driver data + */ +static int nopan = 0; +static int nowrap = 1; // not implemented (yet) +static char *mode_option __devinitdata = NULL; + +/* ------------------------------------------------------------------------- + * Hardware-specific funcions + * ------------------------------------------------------------------------- */ + +#ifdef VGA_REG_IO +static inline u8 vga_inb(struct tdfx_par *par, u32 reg) { return inb(reg); } + +static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val) { outb(val, reg); } +#else +static inline u8 vga_inb(struct tdfx_par *par, u32 reg) { + return inb(par->iobase + reg - 0x300); +} +static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val) { + outb(val, par->iobase + reg - 0x300); +} +#endif + +static inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val) { + vga_outb(par, GRA_I, idx); vga_outb(par, GRA_D, val); +} + +static inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val) { + vga_outb(par, SEQ_I, idx); vga_outb(par, SEQ_D, val); +} + +static inline u8 seq_inb(struct tdfx_par *par, u32 idx) { + vga_outb(par, SEQ_I, idx); return vga_inb(par, SEQ_D); +} + +static inline void crt_outb(struct tdfx_par *par, u32 idx, u8 val) { + vga_outb(par, CRT_I, idx); vga_outb(par, CRT_D, val); +} + +static inline u8 crt_inb(struct tdfx_par *par, u32 idx) { + vga_outb(par, CRT_I, idx); return vga_inb(par, CRT_D); +} + +static inline void att_outb(struct tdfx_par *par, u32 idx, u8 val) +{ + unsigned char tmp; + + tmp = vga_inb(par, IS1_R); + vga_outb(par, ATT_IW, idx); + vga_outb(par, ATT_IW, val); +} + +static inline void vga_disable_video(struct tdfx_par *par) +{ + unsigned char s; + + s = seq_inb(par, 0x01) | 0x20; + seq_outb(par, 0x00, 0x01); + seq_outb(par, 0x01, s); + seq_outb(par, 0x00, 0x03); +} + +static inline void vga_enable_video(struct tdfx_par *par) +{ + unsigned char s; + + s = seq_inb(par, 0x01) & 0xdf; + seq_outb(par, 0x00, 0x01); + seq_outb(par, 0x01, s); + seq_outb(par, 0x00, 0x03); +} + +static inline void vga_enable_palette(struct tdfx_par *par) +{ + vga_inb(par, IS1_R); + vga_outb(par, ATT_IW, 0x20); +} + +static inline u32 tdfx_inl(struct tdfx_par *par, unsigned int reg) +{ + return readl(par->regbase_virt + reg); +} + +static inline void tdfx_outl(struct tdfx_par *par, unsigned int reg, u32 val) +{ + writel(val, par->regbase_virt + reg); +} + +static inline void banshee_make_room(struct tdfx_par *par, int size) +{ + /* Note: The Voodoo3's onboard FIFO has 32 slots. This loop + * won't quit if you ask for more. */ + while((tdfx_inl(par, STATUS) & 0x1f) < size-1); +} + +static int banshee_wait_idle(struct fb_info *info) +{ + struct tdfx_par *par = (struct tdfx_par *) info->par; + int i = 0; + + banshee_make_room(par, 1); + tdfx_outl(par, COMMAND_3D, COMMAND_3D_NOP); + + while(1) { + i = (tdfx_inl(par, STATUS) & STATUS_BUSY) ? 0 : i + 1; + if(i == 3) break; + } + return 0; +} + +/* + * Set the color of a palette entry in 8bpp mode + */ +static inline void do_setpalentry(struct tdfx_par *par, unsigned regno, u32 c) +{ + banshee_make_room(par, 2); + tdfx_outl(par, DACADDR, regno); + tdfx_outl(par, DACDATA, c); +} + +static u32 do_calc_pll(int freq, int* freq_out) +{ + int m, n, k, best_m, best_n, best_k, f_cur, best_error; + int fref = 14318; + + /* this really could be done with more intelligence -- + 255*63*4 = 64260 iterations is silly */ + best_error = freq; + best_n = best_m = best_k = 0; + for (n = 1; n < 256; n++) { + for (m = 1; m < 64; m++) { + for (k = 0; k < 4; k++) { + f_cur = fref*(n + 2)/(m + 2)/(1 << k); + if (abs(f_cur - freq) < best_error) { + best_error = abs(f_cur-freq); + best_n = n; + best_m = m; + best_k = k; + } + } + } + } + n = best_n; + m = best_m; + k = best_k; + *freq_out = fref*(n + 2)/(m + 2)/(1 << k); + return (n << 8) | (m << 2) | k; +} + +static void do_write_regs(struct fb_info *info, struct banshee_reg* reg) +{ + struct tdfx_par *par = (struct tdfx_par *) info->par; + int i; + + banshee_wait_idle(info); + + tdfx_outl(par, MISCINIT1, tdfx_inl(par, MISCINIT1) | 0x01); + + crt_outb(par, 0x11, crt_inb(par, 0x11) & 0x7f); /* CRT unprotect */ + + banshee_make_room(par, 3); + tdfx_outl(par, VGAINIT1, reg->vgainit1 & 0x001FFFFF); + tdfx_outl(par, VIDPROCCFG, reg->vidcfg & ~0x00000001); +#if 0 + tdfx_outl(par, PLLCTRL1, reg->mempll); + tdfx_outl(par, PLLCTRL2, reg->gfxpll); +#endif + tdfx_outl(par, PLLCTRL0, reg->vidpll); + + vga_outb(par, MISC_W, reg->misc[0x00] | 0x01); + + for (i = 0; i < 5; i++) + seq_outb(par, i, reg->seq[i]); + + for (i = 0; i < 25; i++) + crt_outb(par, i, reg->crt[i]); + + for (i = 0; i < 9; i++) + gra_outb(par, i, reg->gra[i]); + + for (i = 0; i < 21; i++) + att_outb(par, i, reg->att[i]); + + crt_outb(par, 0x1a, reg->ext[0]); + crt_outb(par, 0x1b, reg->ext[1]); + + vga_enable_palette(par); + vga_enable_video(par); + + banshee_make_room(par, 11); + tdfx_outl(par, VGAINIT0, reg->vgainit0); + tdfx_outl(par, DACMODE, reg->dacmode); + tdfx_outl(par, VIDDESKSTRIDE, reg->stride); + tdfx_outl(par, HWCURPATADDR, 0); + + tdfx_outl(par, VIDSCREENSIZE,reg->screensize); + tdfx_outl(par, VIDDESKSTART, reg->startaddr); + tdfx_outl(par, VIDPROCCFG, reg->vidcfg); + tdfx_outl(par, VGAINIT1, reg->vgainit1); + tdfx_outl(par, MISCINIT0, reg->miscinit0); + + banshee_make_room(par, 8); + tdfx_outl(par, SRCBASE, reg->srcbase); + tdfx_outl(par, DSTBASE, reg->dstbase); + tdfx_outl(par, COMMANDEXTRA_2D, 0); + tdfx_outl(par, CLIP0MIN, 0); + tdfx_outl(par, CLIP0MAX, 0x0fff0fff); + tdfx_outl(par, CLIP1MIN, 0); + tdfx_outl(par, CLIP1MAX, 0x0fff0fff); + tdfx_outl(par, SRCXY, 0); + + banshee_wait_idle(info); +} + +static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id) +{ + u32 draminit0 = 0; + u32 draminit1 = 0; + u32 miscinit1 = 0; + u32 lfbsize = 0; + int sgram_p = 0; + + draminit0 = tdfx_inl(par, DRAMINIT0); + draminit1 = tdfx_inl(par, DRAMINIT1); + + if ((dev_id == PCI_DEVICE_ID_3DFX_BANSHEE) || + (dev_id == PCI_DEVICE_ID_3DFX_VOODOO3)) { + sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1; + + lfbsize = sgram_p ? + (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) * + ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) : + 16 * 1024 * 1024; + } else { + /* Voodoo4/5 */ + u32 chips, psize, banks; + + chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8; + psize = 1 << ((draminit0 & 0x38000000) >> 28); + banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4; + lfbsize = chips * psize * banks; + lfbsize <<= 20; + } + /* disable block writes for SDRAM (why?) */ + miscinit1 = tdfx_inl(par, MISCINIT1); + miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS; + miscinit1 |= MISCINIT1_CLUT_INV; + + banshee_make_room(par, 1); + tdfx_outl(par, MISCINIT1, miscinit1); + return lfbsize; +} + +/* ------------------------------------------------------------------------- */ + +static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info) +{ + struct tdfx_par *par = (struct tdfx_par *) info->par; + u32 lpitch; + + if (var->bits_per_pixel != 8 && var->bits_per_pixel != 16 && + var->bits_per_pixel != 24 && var->bits_per_pixel != 32) { + DPRINTK("depth not supported: %u\n", var->bits_per_pixel); + return -EINVAL; + } + + if (var->xres != var->xres_virtual) + var->xres_virtual = var->xres; + + if (var->yres > var->yres_virtual) + var->yres_virtual = var->yres; + + if (var->xoffset) { + DPRINTK("xoffset not supported\n"); + return -EINVAL; + } + + /* Banshee doesn't support interlace, but Voodoo4/5 and probably Voodoo3 do. */ + /* no direct information about device id now? use max_pixclock for this... */ + if (((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) && + (par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) { + DPRINTK("interlace not supported\n"); + return -EINVAL; + } + + var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ + lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); + + if (var->xres < 320 || var->xres > 2048) { + DPRINTK("width not supported: %u\n", var->xres); + return -EINVAL; + } + + if (var->yres < 200 || var->yres > 2048) { + DPRINTK("height not supported: %u\n", var->yres); + return -EINVAL; + } + + if (lpitch * var->yres_virtual > info->fix.smem_len) { + var->yres_virtual = info->fix.smem_len/lpitch; + if (var->yres_virtual < var->yres) { + DPRINTK("no memory for screen (%ux%ux%u)\n", + var->xres, var->yres_virtual, var->bits_per_pixel); + return -EINVAL; + } + } + + if (PICOS2KHZ(var->pixclock) > par->max_pixclock) { + DPRINTK("pixclock too high (%ldKHz)\n",PICOS2KHZ(var->pixclock)); + return -EINVAL; + } + + switch(var->bits_per_pixel) { + case 8: + var->red.length = var->green.length = var->blue.length = 8; + break; + case 16: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + case 24: + var->red.offset=16; + var->green.offset=8; + var->blue.offset=0; + var->red.length = var->green.length = var->blue.length = 8; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = 8; + break; + } + var->height = var->width = -1; + + var->accel_flags = FB_ACCELF_TEXT; + + DPRINTK("Checking graphics mode at %dx%d depth %d\n", var->xres, var->yres, var->bits_per_pixel); + return 0; +} + +static int tdfxfb_set_par(struct fb_info *info) +{ + struct tdfx_par *par = (struct tdfx_par *) info->par; + u32 hdispend, hsyncsta, hsyncend, htotal; + u32 hd, hs, he, ht, hbs, hbe; + u32 vd, vs, ve, vt, vbs, vbe; + struct banshee_reg reg; + int fout, freq; + u32 wd, cpp; + + par->baseline = 0; + + memset(®, 0, sizeof(reg)); + cpp = (info->var.bits_per_pixel + 7)/8; + + reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE | VIDCFG_CURS_X11 | ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) | (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0); + + /* PLL settings */ + freq = PICOS2KHZ(info->var.pixclock); + + reg.dacmode = 0; + reg.vidcfg &= ~VIDCFG_2X; + + hdispend = info->var.xres; + hsyncsta = hdispend + info->var.right_margin; + hsyncend = hsyncsta + info->var.hsync_len; + htotal = hsyncend + info->var.left_margin; + + if (freq > par->max_pixclock/2) { + freq = freq > par->max_pixclock ? par->max_pixclock : freq; + reg.dacmode |= DACMODE_2X; + reg.vidcfg |= VIDCFG_2X; + hdispend >>= 1; + hsyncsta >>= 1; + hsyncend >>= 1; + htotal >>= 1; + } + + hd = wd = (hdispend >> 3) - 1; + hs = (hsyncsta >> 3) - 1; + he = (hsyncend >> 3) - 1; + ht = (htotal >> 3) - 1; + hbs = hd; + hbe = ht; + + if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + vbs = vd = (info->var.yres << 1) - 1; + vs = vd + (info->var.lower_margin << 1); + ve = vs + (info->var.vsync_len << 1); + vbe = vt = ve + (info->var.upper_margin << 1) - 1; + } else { + vbs = vd = info->var.yres - 1; + vs = vd + info->var.lower_margin; + ve = vs + info->var.vsync_len; + vbe = vt = ve + info->var.upper_margin - 1; + } + + /* this is all pretty standard VGA register stuffing */ + reg.misc[0x00] = 0x0f | + (info->var.xres < 400 ? 0xa0 : + info->var.xres < 480 ? 0x60 : + info->var.xres < 768 ? 0xe0 : 0x20); + + reg.gra[0x00] = 0x00; + reg.gra[0x01] = 0x00; + reg.gra[0x02] = 0x00; + reg.gra[0x03] = 0x00; + reg.gra[0x04] = 0x00; + reg.gra[0x05] = 0x40; + reg.gra[0x06] = 0x05; + reg.gra[0x07] = 0x0f; + reg.gra[0x08] = 0xff; + + reg.att[0x00] = 0x00; + reg.att[0x01] = 0x01; + reg.att[0x02] = 0x02; + reg.att[0x03] = 0x03; + reg.att[0x04] = 0x04; + reg.att[0x05] = 0x05; + reg.att[0x06] = 0x06; + reg.att[0x07] = 0x07; + reg.att[0x08] = 0x08; + reg.att[0x09] = 0x09; + reg.att[0x0a] = 0x0a; + reg.att[0x0b] = 0x0b; + reg.att[0x0c] = 0x0c; + reg.att[0x0d] = 0x0d; + reg.att[0x0e] = 0x0e; + reg.att[0x0f] = 0x0f; + reg.att[0x10] = 0x41; + reg.att[0x11] = 0x00; + reg.att[0x12] = 0x0f; + reg.att[0x13] = 0x00; + reg.att[0x14] = 0x00; + + reg.seq[0x00] = 0x03; + reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */ + reg.seq[0x02] = 0x0f; + reg.seq[0x03] = 0x00; + reg.seq[0x04] = 0x0e; + + reg.crt[0x00] = ht - 4; + reg.crt[0x01] = hd; + reg.crt[0x02] = hbs; + reg.crt[0x03] = 0x80 | (hbe & 0x1f); + reg.crt[0x04] = hs; + reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f); + reg.crt[0x06] = vt; + reg.crt[0x07] = ((vs & 0x200) >> 2) | + ((vd & 0x200) >> 3) | + ((vt & 0x200) >> 4) | 0x10 | + ((vbs & 0x100) >> 5) | + ((vs & 0x100) >> 6) | + ((vd & 0x100) >> 7) | + ((vt & 0x100) >> 8); + reg.crt[0x08] = 0x00; + reg.crt[0x09] = 0x40 | ((vbs & 0x200) >> 4); + reg.crt[0x0a] = 0x00; + reg.crt[0x0b] = 0x00; + reg.crt[0x0c] = 0x00; + reg.crt[0x0d] = 0x00; + reg.crt[0x0e] = 0x00; + reg.crt[0x0f] = 0x00; + reg.crt[0x10] = vs; + reg.crt[0x11] = (ve & 0x0f) | 0x20; + reg.crt[0x12] = vd; + reg.crt[0x13] = wd; + reg.crt[0x14] = 0x00; + reg.crt[0x15] = vbs; + reg.crt[0x16] = vbe + 1; + reg.crt[0x17] = 0xc3; + reg.crt[0x18] = 0xff; + + /* Banshee's nonvga stuff */ + reg.ext[0x00] = (((ht & 0x100) >> 8) | + ((hd & 0x100) >> 6) | + ((hbs & 0x100) >> 4) | + ((hbe & 0x40) >> 1) | + ((hs & 0x100) >> 2) | + ((he & 0x20) << 2)); + reg.ext[0x01] = (((vt & 0x400) >> 10) | + ((vd & 0x400) >> 8) | + ((vbs & 0x400) >> 6) | + ((vbe & 0x400) >> 4)); + + reg.vgainit0 = VGAINIT0_8BIT_DAC | + VGAINIT0_EXT_ENABLE | + VGAINIT0_WAKEUP_3C3 | + VGAINIT0_ALT_READBACK | + VGAINIT0_EXTSHIFTOUT; + reg.vgainit1 = tdfx_inl(par, VGAINIT1) & 0x1fffff; + + reg.cursloc = 0; + + reg.cursc0 = 0; + reg.cursc1 = 0xffffff; + + reg.stride = info->var.xres * cpp; + reg.startaddr = par->baseline * reg.stride; + reg.srcbase = reg.startaddr; + reg.dstbase = reg.startaddr; + + /* PLL settings */ + freq = PICOS2KHZ(info->var.pixclock); + + reg.dacmode &= ~DACMODE_2X; + reg.vidcfg &= ~VIDCFG_2X; + if (freq > par->max_pixclock/2) { + freq = freq > par->max_pixclock ? par->max_pixclock : freq; + reg.dacmode |= DACMODE_2X; + reg.vidcfg |= VIDCFG_2X; + } + reg.vidpll = do_calc_pll(freq, &fout); +#if 0 + reg.mempll = do_calc_pll(..., &fout); + reg.gfxpll = do_calc_pll(..., &fout); +#endif + + if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + reg.screensize = info->var.xres | (info->var.yres << 13); + reg.vidcfg |= VIDCFG_HALF_MODE; + reg.crt[0x09] |= 0x80; + } else { + reg.screensize = info->var.xres | (info->var.yres << 12); + reg.vidcfg &= ~VIDCFG_HALF_MODE; + } + if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + reg.vidcfg |= VIDCFG_INTERLACE; + reg.miscinit0 = tdfx_inl(par, MISCINIT0); + +#if defined(__BIG_ENDIAN) + switch (info->var.bits_per_pixel) { + case 8: + case 24: + reg.miscinit0 &= ~(1 << 30); + reg.miscinit0 &= ~(1 << 31); + break; + case 16: + reg.miscinit0 |= (1 << 30); + reg.miscinit0 |= (1 << 31); + break; + case 32: + reg.miscinit0 |= (1 << 30); + reg.miscinit0 &= ~(1 << 31); + break; + } +#endif + 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); + info->fix.visual = (info->var.bits_per_pixel == 8) + ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_TRUECOLOR; + DPRINTK("Graphics mode is now set at %dx%d depth %d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel); + return 0; +} + +/* A handy macro shamelessly pinched from matroxfb */ +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) + +static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue,unsigned transp,struct fb_info *info) +{ + struct tdfx_par *par = (struct tdfx_par *) info->par; + u32 rgbcol; + + if (regno >= info->cmap.len || regno > 255) return 1; + + switch (info->fix.visual) { + case FB_VISUAL_PSEUDOCOLOR: + rgbcol =(((u32)red & 0xff00) << 8) | + (((u32)green & 0xff00) << 0) | + (((u32)blue & 0xff00) >> 8); + do_setpalentry(par, regno, rgbcol); + break; + /* Truecolor has no hardware color palettes. */ + case FB_VISUAL_TRUECOLOR: + rgbcol = (CNVT_TOHW( red, info->var.red.length) << info->var.red.offset) | + (CNVT_TOHW( green, info->var.green.length) << info->var.green.offset) | + (CNVT_TOHW( blue, info->var.blue.length) << info->var.blue.offset) | + (CNVT_TOHW( transp, info->var.transp.length) << info->var.transp.offset); + ((u32*)(info->pseudo_palette))[regno] = rgbcol; + break; + default: + DPRINTK("bad depth %u\n", info->var.bits_per_pixel); + break; + } + return 0; +} + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ +static int tdfxfb_blank(int blank, struct fb_info *info) +{ + struct tdfx_par *par = (struct tdfx_par *) info->par; + u32 dacmode, state = 0, vgablank = 0; + + dacmode = tdfx_inl(par, DACMODE); + + switch (blank) { + case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */ + state = 0; + vgablank = 0; + break; + case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */ + state = 0; + vgablank = 1; + break; + case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */ + state = BIT(3); + vgablank = 1; + break; + case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */ + state = BIT(1); + vgablank = 1; + break; + case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */ + state = BIT(1) | BIT(3); + vgablank = 1; + break; + } + + dacmode &= ~(BIT(1) | BIT(3)); + dacmode |= state; + banshee_make_room(par, 1); + tdfx_outl(par, DACMODE, dacmode); + if (vgablank) + vga_disable_video(par); + else + vga_enable_video(par); + return 0; +} + +/* + * Set the starting position of the visible screen to var->yoffset + */ +static int tdfxfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct tdfx_par *par = (struct tdfx_par *) info->par; + u32 addr; + + if (nopan || var->xoffset || (var->yoffset > var->yres_virtual)) + return -EINVAL; + if ((var->yoffset + var->yres > var->yres_virtual && nowrap)) + return -EINVAL; + + addr = var->yoffset * info->fix.line_length; + banshee_make_room(par, 1); + tdfx_outl(par, VIDDESKSTART, addr); + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + return 0; +} + +#ifdef CONFIG_FB_3DFX_ACCEL +/* + * FillRect 2D command (solidfill or invert (via ROP_XOR)) + */ +static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct tdfx_par *par = (struct tdfx_par *) info->par; + u32 bpp = info->var.bits_per_pixel; + u32 stride = info->fix.line_length; + u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); + int tdfx_rop; + + if (rect->rop == ROP_COPY) + tdfx_rop = TDFX_ROP_COPY; + else + tdfx_rop = TDFX_ROP_XOR; + + banshee_make_room(par, 5); + tdfx_outl(par, DSTFORMAT, fmt); + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { + tdfx_outl(par, COLORFORE, rect->color); + } else { /* FB_VISUAL_TRUECOLOR */ + tdfx_outl(par, COLORFORE, ((u32*)(info->pseudo_palette))[rect->color]); + } + tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24)); + tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16)); + tdfx_outl(par, LAUNCH_2D, rect->dx | (rect->dy << 16)); +} + +/* + * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) + */ +static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct tdfx_par *par = (struct tdfx_par *) info->par; + u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy; + u32 bpp = info->var.bits_per_pixel; + u32 stride = info->fix.line_length; + u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24); + u32 fmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); + + if (area->sx <= area->dx) { + //-X + blitcmd |= BIT(14); + sx += area->width - 1; + dx += area->width - 1; + } + if (area->sy <= area->dy) { + //-Y + blitcmd |= BIT(15); + sy += area->height - 1; + dy += area->height - 1; + } + + banshee_make_room(par, 6); + + tdfx_outl(par, SRCFORMAT, fmt); + tdfx_outl(par, DSTFORMAT, fmt); + tdfx_outl(par, COMMAND_2D, blitcmd); + tdfx_outl(par, DSTSIZE, area->width | (area->height << 16)); + tdfx_outl(par, DSTXY, dx | (dy << 16)); + tdfx_outl(par, LAUNCH_2D, sx | (sy << 16)); +} + +static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct tdfx_par *par = (struct tdfx_par *) info->par; + int size = image->height * ((image->width * image->depth + 7)>>3); + int fifo_free; + int i, stride = info->fix.line_length; + u32 bpp = info->var.bits_per_pixel; + u32 dstfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); + u8 *chardata = (u8 *) image->data; + u32 srcfmt; + + if (image->depth != 1) { + //banshee_make_room(par, 6 + ((size + 3) >> 2)); + //srcfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13) | 0x400000; + cfb_imageblit(info, image); + return; + } else { + banshee_make_room(par, 8); + switch (info->fix.visual) { + case FB_VISUAL_PSEUDOCOLOR: + tdfx_outl(par, COLORFORE, image->fg_color); + tdfx_outl(par, COLORBACK, image->bg_color); + break; + case FB_VISUAL_TRUECOLOR: + default: + tdfx_outl(par, COLORFORE, ((u32*)(info->pseudo_palette))[image->fg_color]); + tdfx_outl(par, COLORBACK, ((u32*)(info->pseudo_palette))[image->bg_color]); + } +#ifdef __BIG_ENDIAN + srcfmt = 0x400000 | BIT(20); +#else + srcfmt = 0x400000; +#endif + } + + tdfx_outl(par, SRCXY, 0); + tdfx_outl(par, DSTXY, image->dx | (image->dy << 16)); + tdfx_outl(par, COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24)); + tdfx_outl(par, SRCFORMAT, srcfmt); + tdfx_outl(par, DSTFORMAT, dstfmt); + tdfx_outl(par, DSTSIZE, image->width | (image->height << 16)); + + /* A count of how many free FIFO entries we've requested. + * When this goes negative, we need to request more. */ + fifo_free = 0; + + /* Send four bytes at a time of data */ + for (i = (size >> 2) ; i > 0; i--) { + if(--fifo_free < 0) { + fifo_free=31; + banshee_make_room(par,fifo_free); + } + tdfx_outl(par, LAUNCH_2D,*(u32*)chardata); + chardata += 4; + } + + /* Send the leftovers now */ + banshee_make_room(par,3); + i = size%4; + switch (i) { + case 0: break; + case 1: tdfx_outl(par, LAUNCH_2D,*chardata); break; + case 2: tdfx_outl(par, LAUNCH_2D,*(u16*)chardata); break; + case 3: tdfx_outl(par, LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break; + } +} +#endif /* CONFIG_FB_3DFX_ACCEL */ + +#ifdef TDFX_HARDWARE_CURSOR +static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct tdfx_par *par = (struct tdfx_par *) info->par; + unsigned long flags; + + /* + * If the cursor is not be changed this means either we want the + * current cursor state (if enable is set) or we want to query what + * we can do with the cursor (if enable is not set) + */ + if (!cursor->set) return 0; + + /* Too large of a cursor :-( */ + if (cursor->image.width > 64 || cursor->image.height > 64) + return -ENXIO; + + /* + * If we are going to be changing things we should disable + * the cursor first + */ + if (info->cursor.enable) { + spin_lock_irqsave(&par->DAClock, flags); + info->cursor.enable = 0; + del_timer(&(par->hwcursor.timer)); + tdfx_outl(par, VIDPROCCFG, par->hwcursor.disable); + spin_unlock_irqrestore(&par->DAClock, flags); + } + + /* Disable the Cursor */ + if ((cursor->set && FB_CUR_SETCUR) && !cursor->enable) + return 0; + + /* fix cursor color - XFree86 forgets to restore it properly */ + if (cursor->set && FB_CUR_SETCMAP) { + struct fb_cmap cmap = cursor->image.cmap; + unsigned long bg_color, fg_color; + + cmap.len = 2; /* Voodoo 3+ only support 2 color cursors */ + fg_color = ((cmap.red[cmap.start] << 16) | + (cmap.green[cmap.start] << 8) | + (cmap.blue[cmap.start])); + bg_color = ((cmap.red[cmap.start+1] << 16) | + (cmap.green[cmap.start+1] << 8) | + (cmap.blue[cmap.start+1])); + fb_copy_cmap(&cmap, &info->cursor.image.cmap); + spin_lock_irqsave(&par->DAClock, flags); + banshee_make_room(par, 2); + tdfx_outl(par, HWCURC0, bg_color); + tdfx_outl(par, HWCURC1, fg_color); + spin_unlock_irqrestore(&par->DAClock, flags); + } + + if (cursor->set && FB_CUR_SETPOS) { + int x, y; + + x = cursor->image.dx; + y = cursor->image.dy; + y -= info->var.yoffset; + info->cursor.image.dx = x; + info->cursor.image.dy = y; + x += 63; + y += 63; + spin_lock_irqsave(&par->DAClock, flags); + banshee_make_room(par, 1); + tdfx_outl(par, HWCURLOC, (y << 16) + x); + spin_unlock_irqrestore(&par->DAClock, flags); + } + + /* Not supported so we fake it */ + if (cursor->set && FB_CUR_SETHOT) { + info->cursor.hot.x = cursor->hot.x; + info->cursor.hot.y = cursor->hot.y; + } + + if (cursor->set && FB_CUR_SETSHAPE) { + /* + * Voodoo 3 and above cards use 2 monochrome cursor patterns. + * The reason is so the card can fetch 8 words at a time + * and are stored on chip for use for the next 8 scanlines. + * This reduces the number of times for access to draw the + * cursor for each screen refresh. + * Each pattern is a bitmap of 64 bit wide and 64 bit high + * (total of 8192 bits or 1024 Kbytes). The two patterns are + * stored in such a way that pattern 0 always resides in the + * lower half (least significant 64 bits) of a 128 bit word + * and pattern 1 the upper half. If you examine the data of + * the cursor image the graphics card uses then from the + * begining you see line one of pattern 0, line one of + * pattern 1, line two of pattern 0, line two of pattern 1, + * etc etc. The linear stride for the cursor is always 16 bytes + * (128 bits) which is the maximum cursor width times two for + * the two monochrome patterns. + */ + u8 *cursorbase = (u8 *) info->cursor.image.data; + char *bitmap = (char *)cursor->image.data; + char *mask = (char *) cursor->mask; + int i, j, k, h = 0; + + for (i = 0; i < 64; i++) { + if (i < cursor->image.height) { + j = (cursor->image.width + 7) >> 3; + k = 8 - j; + + for (;j > 0; j--) { + /* Pattern 0. Copy the cursor bitmap to it */ + fb_writeb(*bitmap, cursorbase + h); + bitmap++; + /* Pattern 1. Copy the cursor mask to it */ + fb_writeb(*mask, cursorbase + h + 8); + mask++; + h++; + } + for (;k > 0; k--) { + fb_writeb(0, cursorbase + h); + fb_writeb(~0, cursorbase + h + 8); + h++; + } + } else { + fb_writel(0, cursorbase + h); + fb_writel(0, cursorbase + h + 4); + fb_writel(~0, cursorbase + h + 8); + fb_writel(~0, cursorbase + h + 12); + h += 16; + } + } + } + /* Turn the cursor on */ + cursor->enable = 1; + info->cursor = *cursor; + mod_timer(&par->hwcursor.timer, jiffies+HZ/2); + spin_lock_irqsave(&par->DAClock, flags); + banshee_make_room(par, 1); + tdfx_outl(par, VIDPROCCFG, par->hwcursor.enable); + spin_unlock_irqrestore(&par->DAClock, flags); + return 0; +} +#endif + +/** + * tdfxfb_probe - Device Initializiation + * + * @pdev: PCI Device to initialize + * @id: PCI Device ID + * + * Initializes and allocates resources for PCI device @pdev. + * + */ +static int __devinit tdfxfb_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct tdfx_par *default_par; + struct fb_info *info; + int size, err, lpitch; + + if ((err = pci_enable_device(pdev))) { + printk(KERN_WARNING "tdfxfb: Can't enable pdev: %d\n", err); + return err; + } + + size = sizeof(struct tdfx_par)+256*sizeof(u32); + + info = framebuffer_alloc(size, &pdev->dev); + + if (!info) return -ENOMEM; + + default_par = info->par; + + /* Configure the default fb_fix_screeninfo first */ + switch (pdev->device) { + case PCI_DEVICE_ID_3DFX_BANSHEE: + strcat(tdfx_fix.id, " Banshee"); + default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK; + break; + case PCI_DEVICE_ID_3DFX_VOODOO3: + strcat(tdfx_fix.id, " Voodoo3"); + default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK; + break; + case PCI_DEVICE_ID_3DFX_VOODOO5: + strcat(tdfx_fix.id, " Voodoo5"); + default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK; + break; + } + + tdfx_fix.mmio_start = pci_resource_start(pdev, 0); + tdfx_fix.mmio_len = pci_resource_len(pdev, 0); + default_par->regbase_virt = ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len); + if (!default_par->regbase_virt) { + printk("fb: Can't remap %s register area.\n", tdfx_fix.id); + goto out_err; + } + + if (!request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), "tdfx regbase")) { + printk(KERN_WARNING "tdfxfb: Can't reserve regbase\n"); + goto out_err; + } + + tdfx_fix.smem_start = pci_resource_start(pdev, 1); + if (!(tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device))) { + printk("fb: Can't count %s memory.\n", tdfx_fix.id); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + goto out_err; + } + + if (!request_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1), "tdfx smem")) { + printk(KERN_WARNING "tdfxfb: Can't reserve smem\n"); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + goto out_err; + } + + info->screen_base = ioremap_nocache(tdfx_fix.smem_start, + tdfx_fix.smem_len); + if (!info->screen_base) { + printk("fb: Can't remap %s framebuffer.\n", tdfx_fix.id); + release_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + goto out_err; + } + + default_par->iobase = pci_resource_start(pdev, 2); + + if (!request_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2), "tdfx iobase")) { + printk(KERN_WARNING "tdfxfb: Can't reserve iobase\n"); + release_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + goto out_err; + } + + printk("fb: %s memory = %dK\n", tdfx_fix.id, tdfx_fix.smem_len >> 10); + + tdfx_fix.ypanstep = nopan ? 0 : 1; + tdfx_fix.ywrapstep = nowrap ? 0 : 1; + + info->fbops = &tdfxfb_ops; + info->fix = tdfx_fix; + info->pseudo_palette = (void *)(default_par + 1); + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; +#ifdef CONFIG_FB_3DFX_ACCEL + info->flags |= FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_IMAGEBLIT; +#endif + + if (!mode_option) + mode_option = "640x480@60"; + + err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); + if (!err || err == 4) + info->var = tdfx_var; + + /* maximize virtual vertical length */ + lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3); + info->var.yres_virtual = info->fix.smem_len/lpitch; + if (info->var.yres_virtual < info->var.yres) + goto out_err; + +#ifdef CONFIG_FB_3DFX_ACCEL + /* + * FIXME: Limit var->yres_virtual to 4096 because of screen artifacts + * during scrolling. This is only present if 2D acceleration is + * enabled. + */ + if (info->var.yres_virtual > 4096) + info->var.yres_virtual = 4096; +#endif /* CONFIG_FB_3DFX_ACCEL */ + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + printk(KERN_WARNING "tdfxfb: Can't allocate color map\n"); + goto out_err; + } + + if (register_framebuffer(info) < 0) { + printk("tdfxfb: can't register framebuffer\n"); + fb_dealloc_cmap(&info->cmap); + goto out_err; + } + /* + * Our driver data + */ + pci_set_drvdata(pdev, info); + return 0; + +out_err: + /* + * Cleanup after anything that was remapped/allocated. + */ + if (default_par->regbase_virt) + iounmap(default_par->regbase_virt); + if (info->screen_base) + iounmap(info->screen_base); + framebuffer_release(info); + return -ENXIO; +} + +#ifndef MODULE +void tdfxfb_setup(char *options) +{ + char* this_opt; + + if (!options || !*options) + return; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + if(!strcmp(this_opt, "nopan")) { + nopan = 1; + } else if(!strcmp(this_opt, "nowrap")) { + nowrap = 1; + } else { + mode_option = this_opt; + } + } +} +#endif + +/** + * tdfxfb_remove - Device removal + * + * @pdev: PCI Device to cleanup + * + * Releases all resources allocated during the course of the driver's + * lifetime for the PCI device @pdev. + * + */ +static void __devexit tdfxfb_remove(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct tdfx_par *par = (struct tdfx_par *) info->par; + + unregister_framebuffer(info); + iounmap(par->regbase_virt); + iounmap(info->screen_base); + + /* Clean up after reserved regions */ + release_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + release_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + pci_set_drvdata(pdev, NULL); + framebuffer_release(info); +} + +static int __init tdfxfb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("tdfxfb", &option)) + return -ENODEV; + + tdfxfb_setup(option); +#endif + return pci_register_driver(&tdfxfb_driver); +} + +static void __exit tdfxfb_exit(void) +{ + pci_unregister_driver(&tdfxfb_driver); +} + +MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>"); +MODULE_DESCRIPTION("3Dfx framebuffer device driver"); +MODULE_LICENSE("GPL"); + +module_init(tdfxfb_init); +module_exit(tdfxfb_exit); diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c new file mode 100644 index 000000000000..3099630d0c3d --- /dev/null +++ b/drivers/video/tgafb.c @@ -0,0 +1,1557 @@ +/* + * linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device + * + * Copyright (C) 1995 Jay Estabrook + * Copyright (C) 1997 Geert Uytterhoeven + * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha + * Copyright (C) 2002 Richard Henderson + * + * 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/kernel.h> +#include <linux/sched.h> +#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/init.h> +#include <linux/fb.h> +#include <linux/pci.h> +#include <linux/selection.h> +#include <asm/io.h> +#include <video/tgafb.h> +#include <linux/selection.h> + +/* + * Local functions. + */ + +static int tgafb_check_var(struct fb_var_screeninfo *, struct fb_info *); +static int tgafb_set_par(struct fb_info *); +static void tgafb_set_pll(struct tga_par *, int); +static int tgafb_setcolreg(unsigned, unsigned, unsigned, unsigned, + unsigned, struct fb_info *); +static int tgafb_blank(int, struct fb_info *); +static void tgafb_init_fix(struct fb_info *); + +static void tgafb_imageblit(struct fb_info *, const struct fb_image *); +static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *); +static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *); + +static int tgafb_pci_register(struct pci_dev *, const struct pci_device_id *); +#ifdef MODULE +static void tgafb_pci_unregister(struct pci_dev *); +#endif + +static const char *mode_option = "640x480@60"; + + +/* + * Frame buffer operations + */ + +static struct fb_ops tgafb_ops = { + .owner = THIS_MODULE, + .fb_check_var = tgafb_check_var, + .fb_set_par = tgafb_set_par, + .fb_setcolreg = tgafb_setcolreg, + .fb_blank = tgafb_blank, + .fb_fillrect = tgafb_fillrect, + .fb_copyarea = tgafb_copyarea, + .fb_imageblit = tgafb_imageblit, + .fb_cursor = soft_cursor, +}; + + +/* + * PCI registration operations + */ + +static struct pci_device_id const tgafb_pci_table[] = { + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, 0 } +}; + +static struct pci_driver tgafb_driver = { + .name = "tgafb", + .id_table = tgafb_pci_table, + .probe = tgafb_pci_register, + .remove = __devexit_p(tgafb_pci_unregister), +}; + + +/** + * tgafb_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 + */ +static int +tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct tga_par *par = (struct tga_par *)info->par; + + if (par->tga_type == TGA_TYPE_8PLANE) { + if (var->bits_per_pixel != 8) + return -EINVAL; + } else { + if (var->bits_per_pixel != 32) + return -EINVAL; + } + + if (var->xres_virtual != var->xres || var->yres_virtual != var->yres) + return -EINVAL; + if (var->nonstd) + return -EINVAL; + if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ) + return -EINVAL; + if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + return -EINVAL; + + /* Some of the acceleration routines assume the line width is + a multiple of 64 bytes. */ + if (var->xres * (par->tga_type == TGA_TYPE_8PLANE ? 1 : 4) % 64) + return -EINVAL; + + return 0; +} + +/** + * tgafb_set_par - Optional function. Alters the hardware state. + * @info: frame buffer structure that represents a single frame buffer + */ +static int +tgafb_set_par(struct fb_info *info) +{ + static unsigned int const deep_presets[4] = { + 0x00014000, + 0x0001440d, + 0xffffffff, + 0x0001441d + }; + static unsigned int const rasterop_presets[4] = { + 0x00000003, + 0x00000303, + 0xffffffff, + 0x00000303 + }; + static unsigned int const mode_presets[4] = { + 0x00002000, + 0x00002300, + 0xffffffff, + 0x00002300 + }; + static unsigned int const base_addr_presets[4] = { + 0x00000000, + 0x00000001, + 0xffffffff, + 0x00000001 + }; + + struct tga_par *par = (struct tga_par *) info->par; + u32 htimings, vtimings, pll_freq; + u8 tga_type; + int i, j; + + /* Encode video timings. */ + htimings = (((info->var.xres/4) & TGA_HORIZ_ACT_LSB) + | (((info->var.xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB)); + vtimings = (info->var.yres & TGA_VERT_ACTIVE); + htimings |= ((info->var.right_margin/4) << 9) & TGA_HORIZ_FP; + vtimings |= (info->var.lower_margin << 11) & TGA_VERT_FP; + htimings |= ((info->var.hsync_len/4) << 14) & TGA_HORIZ_SYNC; + vtimings |= (info->var.vsync_len << 16) & TGA_VERT_SYNC; + htimings |= ((info->var.left_margin/4) << 21) & TGA_HORIZ_BP; + vtimings |= (info->var.upper_margin << 22) & TGA_VERT_BP; + + if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) + htimings |= TGA_HORIZ_POLARITY; + if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) + vtimings |= TGA_VERT_POLARITY; + + par->htimings = htimings; + par->vtimings = vtimings; + + par->sync_on_green = !!(info->var.sync & FB_SYNC_ON_GREEN); + + /* Store other useful values in par. */ + par->xres = info->var.xres; + par->yres = info->var.yres; + par->pll_freq = pll_freq = 1000000000 / info->var.pixclock; + par->bits_per_pixel = info->var.bits_per_pixel; + + tga_type = par->tga_type; + + /* First, disable video. */ + TGA_WRITE_REG(par, TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG); + + /* Write the DEEP register. */ + while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */ + continue; + mb(); + TGA_WRITE_REG(par, deep_presets[tga_type], TGA_DEEP_REG); + while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */ + continue; + mb(); + + /* Write some more registers. */ + TGA_WRITE_REG(par, rasterop_presets[tga_type], TGA_RASTEROP_REG); + TGA_WRITE_REG(par, mode_presets[tga_type], TGA_MODE_REG); + TGA_WRITE_REG(par, base_addr_presets[tga_type], TGA_BASE_ADDR_REG); + + /* Calculate & write the PLL. */ + tgafb_set_pll(par, pll_freq); + + /* Write some more registers. */ + TGA_WRITE_REG(par, 0xffffffff, TGA_PLANEMASK_REG); + TGA_WRITE_REG(par, 0xffffffff, TGA_PIXELMASK_REG); + + /* Init video timing regs. */ + TGA_WRITE_REG(par, htimings, TGA_HORIZ_REG); + TGA_WRITE_REG(par, vtimings, TGA_VERT_REG); + + /* Initalise RAMDAC. */ + if (tga_type == TGA_TYPE_8PLANE) { + + /* Init BT485 RAMDAC registers. */ + BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0), + BT485_CMD_0); + BT485_WRITE(par, 0x01, BT485_ADDR_PAL_WRITE); + BT485_WRITE(par, 0x14, BT485_CMD_3); /* cursor 64x64 */ + BT485_WRITE(par, 0x40, BT485_CMD_1); + BT485_WRITE(par, 0x20, BT485_CMD_2); /* cursor off, for now */ + BT485_WRITE(par, 0xff, BT485_PIXEL_MASK); + + /* Fill palette registers. */ + BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE); + TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); + + for (i = 0; i < 16; i++) { + j = color_table[i]; + TGA_WRITE_REG(par, default_red[j]|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, default_grn[j]|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, default_blu[j]|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + } + for (i = 0; i < 240*3; i += 4) { + TGA_WRITE_REG(par, 0x55|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + } + + } else { /* 24-plane or 24plusZ */ + + /* Init BT463 registers. */ + BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_0, 0x40); + BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_1, 0x08); + BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_2, + (par->sync_on_green ? 0x80 : 0x40)); + + BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_0, 0xff); + BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_1, 0xff); + BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_2, 0xff); + BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_3, 0x0f); + + BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00); + BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00); + BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00); + BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00); + + /* Fill the palette. */ + BT463_LOAD_ADDR(par, 0x0000); + TGA_WRITE_REG(par, BT463_PALETTE<<2, TGA_RAMDAC_REG); + + for (i = 0; i < 16; i++) { + j = color_table[i]; + TGA_WRITE_REG(par, default_red[j]|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, default_grn[j]|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, default_blu[j]|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + } + for (i = 0; i < 512*3; i += 4) { + TGA_WRITE_REG(par, 0x55|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + } + + /* Fill window type table after start of vertical retrace. */ + while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01)) + continue; + TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG); + mb(); + while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01)) + continue; + TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG); + + BT463_LOAD_ADDR(par, BT463_WINDOW_TYPE_BASE); + TGA_WRITE_REG(par, BT463_REG_ACC<<2, TGA_RAMDAC_SETUP_REG); + + for (i = 0; i < 16; i++) { + TGA_WRITE_REG(par, 0x00|(BT463_REG_ACC<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x01|(BT463_REG_ACC<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x80|(BT463_REG_ACC<<10), + TGA_RAMDAC_REG); + } + + } + + /* Finally, enable video scan (and pray for the monitor... :-) */ + TGA_WRITE_REG(par, TGA_VALID_VIDEO, TGA_VALID_REG); + + return 0; +} + +#define DIFFCHECK(X) \ +do { \ + if (m <= 0x3f) { \ + int delta = f - (TGA_PLL_BASE_FREQ * (X)) / (r << shift); \ + if (delta < 0) \ + delta = -delta; \ + if (delta < min_diff) \ + min_diff = delta, vm = m, va = a, vr = r; \ + } \ +} while (0) + +static void +tgafb_set_pll(struct tga_par *par, int f) +{ + int n, shift, base, min_diff, target; + int r,a,m,vm = 34, va = 1, vr = 30; + + for (r = 0 ; r < 12 ; r++) + TGA_WRITE_REG(par, !r, TGA_CLOCK_REG); + + if (f > TGA_PLL_MAX_FREQ) + f = TGA_PLL_MAX_FREQ; + + if (f >= TGA_PLL_MAX_FREQ / 2) + shift = 0; + else if (f >= TGA_PLL_MAX_FREQ / 4) + shift = 1; + else + shift = 2; + + TGA_WRITE_REG(par, shift & 1, TGA_CLOCK_REG); + TGA_WRITE_REG(par, shift >> 1, TGA_CLOCK_REG); + + for (r = 0 ; r < 10 ; r++) + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + + if (f <= 120000) { + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + } + else if (f <= 200000) { + TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + } + else { + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); + } + + TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); + + target = (f << shift) / TGA_PLL_BASE_FREQ; + min_diff = TGA_PLL_MAX_FREQ; + + r = 7 / target; + if (!r) r = 1; + + base = target * r; + while (base < 449) { + for (n = base < 7 ? 7 : base; n < base + target && n < 449; n++) { + m = ((n + 3) / 7) - 1; + a = 0; + DIFFCHECK((m + 1) * 7); + m++; + DIFFCHECK((m + 1) * 7); + m = (n / 6) - 1; + if ((a = n % 6)) + DIFFCHECK(n); + } + r++; + base += target; + } + + vr--; + + for (r = 0; r < 8; r++) + TGA_WRITE_REG(par, (vm >> r) & 1, TGA_CLOCK_REG); + for (r = 0; r < 8 ; r++) + TGA_WRITE_REG(par, (va >> r) & 1, TGA_CLOCK_REG); + for (r = 0; r < 7 ; r++) + TGA_WRITE_REG(par, (vr >> r) & 1, TGA_CLOCK_REG); + TGA_WRITE_REG(par, ((vr >> 7) & 1)|2, TGA_CLOCK_REG); +} + + +/** + * tgafb_setcolreg - Optional function. Sets a color register. + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @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. + * @info: frame buffer info structure + */ +static int +tgafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct tga_par *par = (struct tga_par *) info->par; + + if (regno > 255) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + + if (par->tga_type == TGA_TYPE_8PLANE) { + BT485_WRITE(par, regno, BT485_ADDR_PAL_WRITE); + TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); + TGA_WRITE_REG(par, red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); + TGA_WRITE_REG(par, green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); + TGA_WRITE_REG(par, blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); + } else if (regno < 16) { + u32 value = (red << 16) | (green << 8) | blue; + ((u32 *)info->pseudo_palette)[regno] = value; + } + + return 0; +} + + +/** + * tgafb_blank - Optional function. Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + */ +static int +tgafb_blank(int blank, struct fb_info *info) +{ + struct tga_par *par = (struct tga_par *) info->par; + u32 vhcr, vvcr, vvvr; + unsigned long flags; + + local_irq_save(flags); + + vhcr = TGA_READ_REG(par, TGA_HORIZ_REG); + vvcr = TGA_READ_REG(par, TGA_VERT_REG); + vvvr = TGA_READ_REG(par, TGA_VALID_REG); + vvvr &= ~(TGA_VALID_VIDEO | TGA_VALID_BLANK); + + switch (blank) { + case FB_BLANK_UNBLANK: /* Unblanking */ + if (par->vesa_blanked) { + TGA_WRITE_REG(par, vhcr & 0xbfffffff, TGA_HORIZ_REG); + TGA_WRITE_REG(par, vvcr & 0xbfffffff, TGA_VERT_REG); + par->vesa_blanked = 0; + } + TGA_WRITE_REG(par, vvvr | TGA_VALID_VIDEO, TGA_VALID_REG); + break; + + case FB_BLANK_NORMAL: /* Normal blanking */ + TGA_WRITE_REG(par, vvvr | TGA_VALID_VIDEO | TGA_VALID_BLANK, + TGA_VALID_REG); + break; + + case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ + TGA_WRITE_REG(par, vvcr | 0x40000000, TGA_VERT_REG); + TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG); + par->vesa_blanked = 1; + break; + + case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ + TGA_WRITE_REG(par, vhcr | 0x40000000, TGA_HORIZ_REG); + TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG); + par->vesa_blanked = 1; + break; + + case FB_BLANK_POWERDOWN: /* Poweroff */ + TGA_WRITE_REG(par, vhcr | 0x40000000, TGA_HORIZ_REG); + TGA_WRITE_REG(par, vvcr | 0x40000000, TGA_VERT_REG); + TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG); + par->vesa_blanked = 1; + break; + } + + local_irq_restore(flags); + return 0; +} + + +/* + * Acceleration. + */ + +/** + * tgafb_imageblit - REQUIRED function. Can use generic routines if + * non acclerated hardware and packed pixel based. + * Copies a image from system memory to the screen. + * + * @info: frame buffer structure that represents a single frame buffer + * @image: structure defining the image. + */ +static void +tgafb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + static unsigned char const bitrev[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff + }; + + struct tga_par *par = (struct tga_par *) info->par; + u32 fgcolor, bgcolor, dx, dy, width, height, vxres, vyres, pixelmask; + unsigned long rincr, line_length, shift, pos, is8bpp; + unsigned long i, j; + const unsigned char *data; + void __iomem *regs_base; + void __iomem *fb_base; + + dx = image->dx; + dy = image->dy; + width = image->width; + height = image->height; + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + line_length = info->fix.line_length; + rincr = (width + 7) / 8; + + /* Crop the image to the screen. */ + if (dx > vxres || dy > vyres) + return; + if (dx + width > vxres) + width = vxres - dx; + if (dy + height > vyres) + height = vyres - dy; + + /* For copies that aren't pixel expansion, there's little we + can do better than the generic code. */ + /* ??? There is a DMA write mode; I wonder if that could be + made to pull the data from the image buffer... */ + if (image->depth > 1) { + cfb_imageblit(info, image); + return; + } + + regs_base = par->tga_regs_base; + fb_base = par->tga_fb_base; + is8bpp = info->var.bits_per_pixel == 8; + + /* Expand the color values to fill 32-bits. */ + /* ??? Would be nice to notice colour changes elsewhere, so + that we can do this only when necessary. */ + fgcolor = image->fg_color; + bgcolor = image->bg_color; + if (is8bpp) { + fgcolor |= fgcolor << 8; + fgcolor |= fgcolor << 16; + bgcolor |= bgcolor << 8; + bgcolor |= bgcolor << 16; + } else { + if (fgcolor < 16) + fgcolor = ((u32 *)info->pseudo_palette)[fgcolor]; + if (bgcolor < 16) + bgcolor = ((u32 *)info->pseudo_palette)[bgcolor]; + } + __raw_writel(fgcolor, regs_base + TGA_FOREGROUND_REG); + __raw_writel(bgcolor, regs_base + TGA_BACKGROUND_REG); + + /* Acquire proper alignment; set up the PIXELMASK register + so that we only write the proper character cell. */ + pos = dy * line_length; + if (is8bpp) { + pos += dx; + shift = pos & 3; + pos &= -4; + } else { + pos += dx * 4; + shift = (pos & 7) >> 2; + pos &= -8; + } + + data = (const unsigned char *) image->data; + + /* Enable opaque stipple mode. */ + __raw_writel((is8bpp + ? TGA_MODE_SBM_8BPP | TGA_MODE_OPAQUE_STIPPLE + : TGA_MODE_SBM_24BPP | TGA_MODE_OPAQUE_STIPPLE), + regs_base + TGA_MODE_REG); + + if (width + shift <= 32) { + unsigned long bwidth; + + /* Handle common case of imaging a single character, in + a font less than 32 pixels wide. */ + + pixelmask = (1 << width) - 1; + pixelmask <<= shift; + __raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG); + wmb(); + + bwidth = (width + 7) / 8; + + for (i = 0; i < height; ++i) { + u32 mask = 0; + + /* The image data is bit big endian; we need + little endian. */ + for (j = 0; j < bwidth; ++j) + mask |= bitrev[data[j]] << (j * 8); + + __raw_writel(mask << shift, fb_base + pos); + + pos += line_length; + data += rincr; + } + wmb(); + __raw_writel(0xffffffff, regs_base + TGA_PIXELMASK_REG); + } else if (shift == 0) { + unsigned long pos0 = pos; + const unsigned char *data0 = data; + unsigned long bincr = (is8bpp ? 8 : 8*4); + unsigned long bwidth; + + /* Handle another common case in which accel_putcs + generates a large bitmap, which happens to be aligned. + Allow the tail to be misaligned. This case is + interesting because we've not got to hold partial + bytes across the words being written. */ + + wmb(); + + bwidth = (width / 8) & -4; + for (i = 0; i < height; ++i) { + for (j = 0; j < bwidth; j += 4) { + u32 mask = 0; + mask |= bitrev[data[j+0]] << (0 * 8); + mask |= bitrev[data[j+1]] << (1 * 8); + mask |= bitrev[data[j+2]] << (2 * 8); + mask |= bitrev[data[j+3]] << (3 * 8); + __raw_writel(mask, fb_base + pos + j*bincr); + } + pos += line_length; + data += rincr; + } + wmb(); + + pixelmask = (1ul << (width & 31)) - 1; + if (pixelmask) { + __raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG); + wmb(); + + pos = pos0 + bwidth*bincr; + data = data0 + bwidth; + bwidth = ((width & 31) + 7) / 8; + + for (i = 0; i < height; ++i) { + u32 mask = 0; + for (j = 0; j < bwidth; ++j) + mask |= bitrev[data[j]] << (j * 8); + __raw_writel(mask, fb_base + pos); + pos += line_length; + data += rincr; + } + wmb(); + __raw_writel(0xffffffff, regs_base + TGA_PIXELMASK_REG); + } + } else { + unsigned long pos0 = pos; + const unsigned char *data0 = data; + unsigned long bincr = (is8bpp ? 8 : 8*4); + unsigned long bwidth; + + /* Finally, handle the generic case of misaligned start. + Here we split the write into 16-bit spans. This allows + us to use only one pixel mask, instead of four as would + be required by writing 24-bit spans. */ + + pixelmask = 0xffff << shift; + __raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG); + wmb(); + + bwidth = (width / 8) & -2; + for (i = 0; i < height; ++i) { + for (j = 0; j < bwidth; j += 2) { + u32 mask = 0; + mask |= bitrev[data[j+0]] << (0 * 8); + mask |= bitrev[data[j+1]] << (1 * 8); + mask <<= shift; + __raw_writel(mask, fb_base + pos + j*bincr); + } + pos += line_length; + data += rincr; + } + wmb(); + + pixelmask = ((1ul << (width & 15)) - 1) << shift; + if (pixelmask) { + __raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG); + wmb(); + + pos = pos0 + bwidth*bincr; + data = data0 + bwidth; + bwidth = (width & 15) > 8; + + for (i = 0; i < height; ++i) { + u32 mask = bitrev[data[0]]; + if (bwidth) + mask |= bitrev[data[1]] << 8; + mask <<= shift; + __raw_writel(mask, fb_base + pos); + pos += line_length; + data += rincr; + } + wmb(); + } + __raw_writel(0xffffffff, regs_base + TGA_PIXELMASK_REG); + } + + /* Disable opaque stipple mode. */ + __raw_writel((is8bpp + ? TGA_MODE_SBM_8BPP | TGA_MODE_SIMPLE + : TGA_MODE_SBM_24BPP | TGA_MODE_SIMPLE), + regs_base + TGA_MODE_REG); +} + +/** + * tgafb_fillrect - REQUIRED function. Can use generic routines if + * non acclerated hardware and packed pixel based. + * Draws a rectangle on the screen. + * + * @info: frame buffer structure that represents a single frame buffer + * @rect: structure defining the rectagle and operation. + */ +static void +tgafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct tga_par *par = (struct tga_par *) info->par; + int is8bpp = info->var.bits_per_pixel == 8; + u32 dx, dy, width, height, vxres, vyres, color; + unsigned long pos, align, line_length, i, j; + void __iomem *regs_base; + void __iomem *fb_base; + + dx = rect->dx; + dy = rect->dy; + width = rect->width; + height = rect->height; + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + line_length = info->fix.line_length; + regs_base = par->tga_regs_base; + fb_base = par->tga_fb_base; + + /* Crop the rectangle to the screen. */ + if (dx > vxres || dy > vyres || !width || !height) + return; + if (dx + width > vxres) + width = vxres - dx; + if (dy + height > vyres) + height = vyres - dy; + + pos = dy * line_length + dx * (is8bpp ? 1 : 4); + + /* ??? We could implement ROP_XOR with opaque fill mode + and a RasterOp setting of GXxor, but as far as I can + tell, this mode is not actually used in the kernel. + Thus I am ignoring it for now. */ + if (rect->rop != ROP_COPY) { + cfb_fillrect(info, rect); + return; + } + + /* Expand the color value to fill 8 pixels. */ + color = rect->color; + if (is8bpp) { + color |= color << 8; + color |= color << 16; + __raw_writel(color, regs_base + TGA_BLOCK_COLOR0_REG); + __raw_writel(color, regs_base + TGA_BLOCK_COLOR1_REG); + } else { + if (color < 16) + color = ((u32 *)info->pseudo_palette)[color]; + __raw_writel(color, regs_base + TGA_BLOCK_COLOR0_REG); + __raw_writel(color, regs_base + TGA_BLOCK_COLOR1_REG); + __raw_writel(color, regs_base + TGA_BLOCK_COLOR2_REG); + __raw_writel(color, regs_base + TGA_BLOCK_COLOR3_REG); + __raw_writel(color, regs_base + TGA_BLOCK_COLOR4_REG); + __raw_writel(color, regs_base + TGA_BLOCK_COLOR5_REG); + __raw_writel(color, regs_base + TGA_BLOCK_COLOR6_REG); + __raw_writel(color, regs_base + TGA_BLOCK_COLOR7_REG); + } + + /* The DATA register holds the fill mask for block fill mode. + Since we're not stippling, this is all ones. */ + __raw_writel(0xffffffff, regs_base + TGA_DATA_REG); + + /* Enable block fill mode. */ + __raw_writel((is8bpp + ? TGA_MODE_SBM_8BPP | TGA_MODE_BLOCK_FILL + : TGA_MODE_SBM_24BPP | TGA_MODE_BLOCK_FILL), + regs_base + TGA_MODE_REG); + wmb(); + + /* We can fill 2k pixels per operation. Notice blocks that fit + the width of the screen so that we can take advantage of this + and fill more than one line per write. */ + if (width == line_length) + width *= height, height = 1; + + /* The write into the frame buffer must be aligned to 4 bytes, + but we are allowed to encode the offset within the word in + the data word written. */ + align = (pos & 3) << 16; + pos &= -4; + + if (width <= 2048) { + u32 data; + + data = (width - 1) | align; + + for (i = 0; i < height; ++i) { + __raw_writel(data, fb_base + pos); + pos += line_length; + } + } else { + unsigned long Bpp = (is8bpp ? 1 : 4); + unsigned long nwidth = width & -2048; + u32 fdata, ldata; + + fdata = (2048 - 1) | align; + ldata = ((width & 2047) - 1) | align; + + for (i = 0; i < height; ++i) { + for (j = 0; j < nwidth; j += 2048) + __raw_writel(fdata, fb_base + pos + j*Bpp); + if (j < width) + __raw_writel(ldata, fb_base + pos + j*Bpp); + pos += line_length; + } + } + wmb(); + + /* Disable block fill mode. */ + __raw_writel((is8bpp + ? TGA_MODE_SBM_8BPP | TGA_MODE_SIMPLE + : TGA_MODE_SBM_24BPP | TGA_MODE_SIMPLE), + regs_base + TGA_MODE_REG); +} + +/** + * tgafb_copyarea - REQUIRED function. Can use generic routines if + * non acclerated hardware and packed pixel based. + * Copies on area of the screen to another area. + * + * @info: frame buffer structure that represents a single frame buffer + * @area: structure defining the source and destination. + */ + +/* Handle the special case of copying entire lines, e.g. during scrolling. + We can avoid a lot of needless computation in this case. In the 8bpp + case we need to use the COPY64 registers instead of mask writes into + the frame buffer to achieve maximum performance. */ + +static inline void +copyarea_line_8bpp(struct fb_info *info, u32 dy, u32 sy, + u32 height, u32 width) +{ + struct tga_par *par = (struct tga_par *) info->par; + void __iomem *tga_regs = par->tga_regs_base; + unsigned long dpos, spos, i, n64; + + /* Set up the MODE and PIXELSHIFT registers. */ + __raw_writel(TGA_MODE_SBM_8BPP | TGA_MODE_COPY, tga_regs+TGA_MODE_REG); + __raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG); + wmb(); + + n64 = (height * width) / 64; + + if (dy < sy) { + spos = (sy + height) * width; + dpos = (dy + height) * width; + + for (i = 0; i < n64; ++i) { + spos -= 64; + dpos -= 64; + __raw_writel(spos, tga_regs+TGA_COPY64_SRC); + wmb(); + __raw_writel(dpos, tga_regs+TGA_COPY64_DST); + wmb(); + } + } else { + spos = sy * width; + dpos = dy * width; + + for (i = 0; i < n64; ++i) { + __raw_writel(spos, tga_regs+TGA_COPY64_SRC); + wmb(); + __raw_writel(dpos, tga_regs+TGA_COPY64_DST); + wmb(); + spos += 64; + dpos += 64; + } + } + + /* Reset the MODE register to normal. */ + __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG); +} + +static inline void +copyarea_line_32bpp(struct fb_info *info, u32 dy, u32 sy, + u32 height, u32 width) +{ + struct tga_par *par = (struct tga_par *) info->par; + void __iomem *tga_regs = par->tga_regs_base; + void __iomem *tga_fb = par->tga_fb_base; + void __iomem *src; + void __iomem *dst; + unsigned long i, n16; + + /* Set up the MODE and PIXELSHIFT registers. */ + __raw_writel(TGA_MODE_SBM_24BPP | TGA_MODE_COPY, tga_regs+TGA_MODE_REG); + __raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG); + wmb(); + + n16 = (height * width) / 16; + + if (dy < sy) { + src = tga_fb + (sy + height) * width * 4; + dst = tga_fb + (dy + height) * width * 4; + + for (i = 0; i < n16; ++i) { + src -= 64; + dst -= 64; + __raw_writel(0xffff, src); + wmb(); + __raw_writel(0xffff, dst); + wmb(); + } + } else { + src = tga_fb + sy * width * 4; + dst = tga_fb + dy * width * 4; + + for (i = 0; i < n16; ++i) { + __raw_writel(0xffff, src); + wmb(); + __raw_writel(0xffff, dst); + wmb(); + src += 64; + dst += 64; + } + } + + /* Reset the MODE register to normal. */ + __raw_writel(TGA_MODE_SBM_24BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG); +} + +/* The general case of forward copy in 8bpp mode. */ +static inline void +copyarea_foreward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy, + u32 height, u32 width, u32 line_length) +{ + struct tga_par *par = (struct tga_par *) info->par; + unsigned long i, copied, left; + unsigned long dpos, spos, dalign, salign, yincr; + u32 smask_first, dmask_first, dmask_last; + int pixel_shift, need_prime, need_second; + unsigned long n64, n32, xincr_first; + void __iomem *tga_regs; + void __iomem *tga_fb; + + yincr = line_length; + if (dy > sy) { + dy += height - 1; + sy += height - 1; + yincr = -yincr; + } + + /* Compute the offsets and alignments in the frame buffer. + More than anything else, these control how we do copies. */ + dpos = dy * line_length + dx; + spos = sy * line_length + sx; + dalign = dpos & 7; + salign = spos & 7; + dpos &= -8; + spos &= -8; + + /* Compute the value for the PIXELSHIFT register. This controls + both non-co-aligned source and destination and copy direction. */ + if (dalign >= salign) + pixel_shift = dalign - salign; + else + pixel_shift = 8 - (salign - dalign); + + /* Figure out if we need an additional priming step for the + residue register. */ + need_prime = (salign > dalign); + if (need_prime) + dpos -= 8; + + /* Begin by copying the leading unaligned destination. Copy enough + to make the next destination address 32-byte aligned. */ + copied = 32 - (dalign + (dpos & 31)); + if (copied == 32) + copied = 0; + xincr_first = (copied + 7) & -8; + smask_first = dmask_first = (1ul << copied) - 1; + smask_first <<= salign; + dmask_first <<= dalign + need_prime*8; + if (need_prime && copied > 24) + copied -= 8; + left = width - copied; + + /* Care for small copies. */ + if (copied > width) { + u32 t; + t = (1ul << width) - 1; + t <<= dalign + need_prime*8; + dmask_first &= t; + left = 0; + } + + /* Attempt to use 64-byte copies. This is only possible if the + source and destination are co-aligned at 64 bytes. */ + n64 = need_second = 0; + if ((dpos & 63) == (spos & 63) + && (height == 1 || line_length % 64 == 0)) { + /* We may need a 32-byte copy to ensure 64 byte alignment. */ + need_second = (dpos + xincr_first) & 63; + if ((need_second & 32) != need_second) + printk(KERN_ERR "tgafb: need_second wrong\n"); + if (left >= need_second + 64) { + left -= need_second; + n64 = left / 64; + left %= 64; + } else + need_second = 0; + } + + /* Copy trailing full 32-byte sections. This will be the main + loop if the 64 byte loop can't be used. */ + n32 = left / 32; + left %= 32; + + /* Copy the trailing unaligned destination. */ + dmask_last = (1ul << left) - 1; + + tga_regs = par->tga_regs_base; + tga_fb = par->tga_fb_base; + + /* Set up the MODE and PIXELSHIFT registers. */ + __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_COPY, tga_regs+TGA_MODE_REG); + __raw_writel(pixel_shift, tga_regs+TGA_PIXELSHIFT_REG); + wmb(); + + for (i = 0; i < height; ++i) { + unsigned long j; + void __iomem *sfb; + void __iomem *dfb; + + sfb = tga_fb + spos; + dfb = tga_fb + dpos; + if (dmask_first) { + __raw_writel(smask_first, sfb); + wmb(); + __raw_writel(dmask_first, dfb); + wmb(); + sfb += xincr_first; + dfb += xincr_first; + } + + if (need_second) { + __raw_writel(0xffffffff, sfb); + wmb(); + __raw_writel(0xffffffff, dfb); + wmb(); + sfb += 32; + dfb += 32; + } + + if (n64 && (((unsigned long)sfb | (unsigned long)dfb) & 63)) + printk(KERN_ERR + "tgafb: misaligned copy64 (s:%p, d:%p)\n", + sfb, dfb); + + for (j = 0; j < n64; ++j) { + __raw_writel(sfb - tga_fb, tga_regs+TGA_COPY64_SRC); + wmb(); + __raw_writel(dfb - tga_fb, tga_regs+TGA_COPY64_DST); + wmb(); + sfb += 64; + dfb += 64; + } + + for (j = 0; j < n32; ++j) { + __raw_writel(0xffffffff, sfb); + wmb(); + __raw_writel(0xffffffff, dfb); + wmb(); + sfb += 32; + dfb += 32; + } + + if (dmask_last) { + __raw_writel(0xffffffff, sfb); + wmb(); + __raw_writel(dmask_last, dfb); + wmb(); + } + + spos += yincr; + dpos += yincr; + } + + /* Reset the MODE register to normal. */ + __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG); +} + +/* The (almost) general case of backward copy in 8bpp mode. */ +static inline void +copyarea_backward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy, + u32 height, u32 width, u32 line_length, + const struct fb_copyarea *area) +{ + struct tga_par *par = (struct tga_par *) info->par; + unsigned long i, left, yincr; + unsigned long depos, sepos, dealign, sealign; + u32 mask_first, mask_last; + unsigned long n32; + void __iomem *tga_regs; + void __iomem *tga_fb; + + yincr = line_length; + if (dy > sy) { + dy += height - 1; + sy += height - 1; + yincr = -yincr; + } + + /* Compute the offsets and alignments in the frame buffer. + More than anything else, these control how we do copies. */ + depos = dy * line_length + dx + width; + sepos = sy * line_length + sx + width; + dealign = depos & 7; + sealign = sepos & 7; + + /* ??? The documentation appears to be incorrect (or very + misleading) wrt how pixel shifting works in backward copy + mode, i.e. when PIXELSHIFT is negative. I give up for now. + Do handle the common case of co-aligned backward copies, + but frob everything else back on generic code. */ + if (dealign != sealign) { + cfb_copyarea(info, area); + return; + } + + /* We begin the copy with the trailing pixels of the + unaligned destination. */ + mask_first = (1ul << dealign) - 1; + left = width - dealign; + + /* Care for small copies. */ + if (dealign > width) { + mask_first ^= (1ul << (dealign - width)) - 1; + left = 0; + } + + /* Next copy full words at a time. */ + n32 = left / 32; + left %= 32; + + /* Finally copy the unaligned head of the span. */ + mask_last = -1 << (32 - left); + + tga_regs = par->tga_regs_base; + tga_fb = par->tga_fb_base; + + /* Set up the MODE and PIXELSHIFT registers. */ + __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_COPY, tga_regs+TGA_MODE_REG); + __raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG); + wmb(); + + for (i = 0; i < height; ++i) { + unsigned long j; + void __iomem *sfb; + void __iomem *dfb; + + sfb = tga_fb + sepos; + dfb = tga_fb + depos; + if (mask_first) { + __raw_writel(mask_first, sfb); + wmb(); + __raw_writel(mask_first, dfb); + wmb(); + } + + for (j = 0; j < n32; ++j) { + sfb -= 32; + dfb -= 32; + __raw_writel(0xffffffff, sfb); + wmb(); + __raw_writel(0xffffffff, dfb); + wmb(); + } + + if (mask_last) { + sfb -= 32; + dfb -= 32; + __raw_writel(mask_last, sfb); + wmb(); + __raw_writel(mask_last, dfb); + wmb(); + } + + sepos += yincr; + depos += yincr; + } + + /* Reset the MODE register to normal. */ + __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG); +} + +static void +tgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + unsigned long dx, dy, width, height, sx, sy, vxres, vyres; + unsigned long line_length, bpp; + + dx = area->dx; + dy = area->dy; + width = area->width; + height = area->height; + sx = area->sx; + sy = area->sy; + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + line_length = info->fix.line_length; + + /* The top left corners must be in the virtual screen. */ + if (dx > vxres || sx > vxres || dy > vyres || sy > vyres) + return; + + /* Clip the destination. */ + if (dx + width > vxres) + width = vxres - dx; + if (dy + height > vyres) + height = vyres - dy; + + /* The source must be completely inside the virtual screen. */ + if (sx + width > vxres || sy + height > vyres) + return; + + bpp = info->var.bits_per_pixel; + + /* Detect copies of the entire line. */ + if (width * (bpp >> 3) == line_length) { + if (bpp == 8) + copyarea_line_8bpp(info, dy, sy, height, width); + else + copyarea_line_32bpp(info, dy, sy, height, width); + } + + /* ??? The documentation is unclear to me exactly how the pixelshift + register works in 32bpp mode. Since I don't have hardware to test, + give up for now and fall back on the generic routines. */ + else if (bpp == 32) + cfb_copyarea(info, area); + + /* Detect overlapping source and destination that requires + a backward copy. */ + else if (dy == sy && dx > sx && dx < sx + width) + copyarea_backward_8bpp(info, dx, dy, sx, sy, height, + width, line_length, area); + else + copyarea_foreward_8bpp(info, dx, dy, sx, sy, height, + width, line_length); +} + + +/* + * Initialisation + */ + +static void +tgafb_init_fix(struct fb_info *info) +{ + struct tga_par *par = (struct tga_par *)info->par; + u8 tga_type = par->tga_type; + const char *tga_type_name; + + switch (tga_type) { + case TGA_TYPE_8PLANE: + tga_type_name = "Digital ZLXp-E1"; + break; + case TGA_TYPE_24PLANE: + tga_type_name = "Digital ZLXp-E2"; + break; + case TGA_TYPE_24PLUSZ: + tga_type_name = "Digital ZLXp-E3"; + break; + default: + tga_type_name = "Unknown"; + break; + } + + strlcpy(info->fix.id, tga_type_name, sizeof(info->fix.id)); + + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + info->fix.visual = (tga_type == TGA_TYPE_8PLANE + ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_TRUECOLOR); + + info->fix.line_length = par->xres * (par->bits_per_pixel >> 3); + info->fix.smem_start = (size_t) par->tga_fb_base; + info->fix.smem_len = info->fix.line_length * par->yres; + info->fix.mmio_start = (size_t) par->tga_regs_base; + info->fix.mmio_len = 512; + + info->fix.xpanstep = 0; + info->fix.ypanstep = 0; + info->fix.ywrapstep = 0; + + info->fix.accel = FB_ACCEL_DEC_TGA; +} + +static __devinit int +tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static unsigned int const fb_offset_presets[4] = { + TGA_8PLANE_FB_OFFSET, + TGA_24PLANE_FB_OFFSET, + 0xffffffff, + TGA_24PLUSZ_FB_OFFSET + }; + + struct all_info { + struct fb_info info; + struct tga_par par; + u32 pseudo_palette[16]; + } *all; + + void __iomem *mem_base; + unsigned long bar0_start, bar0_len; + u8 tga_type; + int ret; + + /* Enable device in PCI config. */ + if (pci_enable_device(pdev)) { + printk(KERN_ERR "tgafb: Cannot enable PCI device\n"); + return -ENODEV; + } + + /* Allocate the fb and par structures. */ + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "tgafb: Cannot allocate memory\n"); + return -ENOMEM; + } + memset(all, 0, sizeof(*all)); + pci_set_drvdata(pdev, all); + + /* Request the mem regions. */ + bar0_start = pci_resource_start(pdev, 0); + bar0_len = pci_resource_len(pdev, 0); + ret = -ENODEV; + if (!request_mem_region (bar0_start, bar0_len, "tgafb")) { + printk(KERN_ERR "tgafb: cannot reserve FB region\n"); + goto err0; + } + + /* Map the framebuffer. */ + mem_base = ioremap(bar0_start, bar0_len); + if (!mem_base) { + printk(KERN_ERR "tgafb: Cannot map MMIO\n"); + goto err1; + } + + /* Grab info about the card. */ + tga_type = (readl(mem_base) >> 12) & 0x0f; + all->par.pdev = pdev; + all->par.tga_mem_base = mem_base; + all->par.tga_fb_base = mem_base + fb_offset_presets[tga_type]; + all->par.tga_regs_base = mem_base + TGA_REGS_OFFSET; + all->par.tga_type = tga_type; + pci_read_config_byte(pdev, PCI_REVISION_ID, &all->par.tga_chip_rev); + + /* Setup framebuffer. */ + all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT; + all->info.fbops = &tgafb_ops; + all->info.screen_base = all->par.tga_fb_base; + all->info.par = &all->par; + all->info.pseudo_palette = all->pseudo_palette; + + /* This should give a reasonable default video mode. */ + + ret = fb_find_mode(&all->info.var, &all->info, mode_option, + NULL, 0, NULL, + tga_type == TGA_TYPE_8PLANE ? 8 : 32); + if (ret == 0 || ret == 4) { + printk(KERN_ERR "tgafb: Could not find valid video mode\n"); + ret = -EINVAL; + goto err1; + } + + if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { + printk(KERN_ERR "tgafb: Could not allocate color map\n"); + ret = -ENOMEM; + goto err1; + } + + tgafb_set_par(&all->info); + tgafb_init_fix(&all->info); + + all->info.device = &pdev->dev; + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "tgafb: Could not register framebuffer\n"); + ret = -EINVAL; + goto err1; + } + + printk(KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n", + all->par.tga_chip_rev); + printk(KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n", + pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); + printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n", + all->info.node, all->info.fix.id, bar0_start); + + return 0; + + err1: + release_mem_region(bar0_start, bar0_len); + err0: + kfree(all); + return ret; +} + +#ifdef MODULE +static void __exit +tgafb_pci_unregister(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct tga_par *par = info->par; + + if (!info) + return; + unregister_framebuffer(info); + iounmap(par->tga_mem_base); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + kfree(info); +} + +static void __exit +tgafb_exit(void) +{ + pci_unregister_driver(&tgafb_driver); +} +#endif /* MODULE */ + +#ifndef MODULE +int __init +tgafb_setup(char *arg) +{ + char *this_opt; + + if (arg && *arg) { + while ((this_opt = strsep(&arg, ","))) { + if (!*this_opt) + continue; + if (!strncmp(this_opt, "mode:", 5)) + mode_option = this_opt+5; + else + printk(KERN_ERR + "tgafb: unknown parameter %s\n", + this_opt); + } + } + + return 0; +} +#endif /* !MODULE */ + +int __init +tgafb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("tgafb", &option)) + return -ENODEV; + tgafb_setup(option); +#endif + return pci_register_driver(&tgafb_driver); +} + +/* + * Modularisation + */ + +module_init(tgafb_init); + +#ifdef MODULE +module_exit(tgafb_exit); +#endif + +MODULE_DESCRIPTION("framebuffer driver for TGA chipset"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c new file mode 100644 index 000000000000..da8004e5d03d --- /dev/null +++ b/drivers/video/tridentfb.c @@ -0,0 +1,1294 @@ +/* + * Frame buffer driver for Trident Blade and Image series + * + * Copyright 2001,2002 - Jani Monoses <jani@iv.ro> + * + * + * CREDITS:(in order of appearance) + * skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video + * Special thanks ;) to Mattia Crivellini <tia@mclink.it> + * much inspired by the XFree86 4.x Trident driver sources by Alan Hourihane + * the FreeVGA project + * Francesco Salvestrini <salvestrini@users.sf.net> XP support,code,suggestions + * TODO: + * timing value tweaking so it looks good on every monitor in every mode + * TGUI acceleration + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <linux/delay.h> +#include <video/trident.h> + +#define VERSION "0.7.8-NEWAPI" + +struct tridentfb_par { + int vclk; //in MHz + void __iomem * io_virt; //iospace virtual memory address +}; + +static unsigned char eng_oper; //engine operation... +static struct fb_ops tridentfb_ops; + +static struct tridentfb_par default_par; + +/* FIXME:kmalloc these 3 instead */ +static struct fb_info fb_info; +static u32 pseudo_pal[16]; + + +static struct fb_var_screeninfo default_var; + +static struct fb_fix_screeninfo tridentfb_fix = { + .id = "Trident", + .type = FB_TYPE_PACKED_PIXELS, + .ypanstep = 1, + .visual = FB_VISUAL_PSEUDOCOLOR, + .accel = FB_ACCEL_NONE, +}; + +static int chip_id; + +static int defaultaccel; +static int displaytype; + + +/* defaults which are normally overriden by user values */ + +/* video mode */ +static char * mode = "640x480"; +static int bpp = 8; + +static int noaccel; + +static int center; +static int stretch; + +static int fp; +static int crt; + +static int memsize; +static int memdiff; +static int nativex; + + +module_param(mode, charp, 0); +module_param(bpp, int, 0); +module_param(center, int, 0); +module_param(stretch, int, 0); +module_param(noaccel, int, 0); +module_param(memsize, int, 0); +module_param(memdiff, int, 0); +module_param(nativex, int, 0); +module_param(fp, int, 0); +module_param(crt, int, 0); + + +static int chip3D; +static int chipcyber; + +static int is3Dchip(int id) +{ + return ((id == BLADE3D) || (id == CYBERBLADEE4) || + (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) || + (id == CYBER9397) || (id == CYBER9397DVD) || + (id == CYBER9520) || (id == CYBER9525DVD) || + (id == IMAGE975) || (id == IMAGE985) || + (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) || + (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) || + (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) || + (id == CYBERBLADEXPAi1)); +} + +static int iscyber(int id) +{ + switch (id) { + case CYBER9388: + case CYBER9382: + case CYBER9385: + case CYBER9397: + case CYBER9397DVD: + case CYBER9520: + case CYBER9525DVD: + case CYBERBLADEE4: + case CYBERBLADEi7D: + case CYBERBLADEi1: + case CYBERBLADEi1D: + case CYBERBLADEAi1: + case CYBERBLADEAi1D: + case CYBERBLADEXPAi1: + return 1; + + case CYBER9320: + case TGUI9660: + case IMAGE975: + case IMAGE985: + case BLADE3D: + case CYBERBLADEi7: /* VIA MPV4 integrated version */ + + default: + /* case CYBERBLDAEXPm8: Strange */ + /* case CYBERBLDAEXPm16: Strange */ + return 0; + } +} + +#define CRT 0x3D0 //CRTC registers offset for color display + +#ifndef TRIDENT_MMIO + #define TRIDENT_MMIO 1 +#endif + +#if TRIDENT_MMIO + #define t_outb(val,reg) writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg) + #define t_inb(reg) readb(((struct tridentfb_par*)(fb_info.par))->io_virt + reg) +#else + #define t_outb(val,reg) outb(val,reg) + #define t_inb(reg) inb(reg) +#endif + + +static struct accel_switch { + void (*init_accel)(int,int); + void (*wait_engine)(void); + void (*fill_rect)(__u32,__u32,__u32,__u32,__u32,__u32); + void (*copy_rect)(__u32,__u32,__u32,__u32,__u32,__u32); +} *acc; + +#define writemmr(r,v) writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r) +#define readmmr(r) readl(((struct tridentfb_par *)fb_info.par)->io_virt + r) + + + +/* + * Blade specific acceleration. + */ + +#define point(x,y) ((y)<<16|(x)) +#define STA 0x2120 +#define CMD 0x2144 +#define ROP 0x2148 +#define CLR 0x2160 +#define SR1 0x2100 +#define SR2 0x2104 +#define DR1 0x2108 +#define DR2 0x210C + +#define ROP_S 0xCC + +static void blade_init_accel(int pitch,int bpp) +{ + int v1 = (pitch>>3)<<20; + int tmp = 0,v2; + switch (bpp) { + case 8:tmp = 0;break; + case 15:tmp = 5;break; + case 16:tmp = 1;break; + case 24: + case 32:tmp = 2;break; + } + v2 = v1 | (tmp<<29); + writemmr(0x21C0,v2); + writemmr(0x21C4,v2); + writemmr(0x21B8,v2); + writemmr(0x21BC,v2); + writemmr(0x21D0,v1); + writemmr(0x21D4,v1); + writemmr(0x21C8,v1); + writemmr(0x21CC,v1); + writemmr(0x216C,0); +} + +static void blade_wait_engine(void) +{ + while(readmmr(STA) & 0xFA800000); +} + +static void blade_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop) +{ + writemmr(CLR,c); + writemmr(ROP,rop ? 0x66:ROP_S); + writemmr(CMD,0x20000000|1<<19|1<<4|2<<2); + + writemmr(DR1,point(x,y)); + writemmr(DR2,point(x+w-1,y+h-1)); +} + +static void blade_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h) +{ + __u32 s1,s2,d1,d2; + int direction = 2; + s1 = point(x1,y1); + s2 = point(x1+w-1,y1+h-1); + d1 = point(x2,y2); + d2 = point(x2+w-1,y2+h-1); + + if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) + direction = 0; + + + writemmr(ROP,ROP_S); + writemmr(CMD,0xE0000000|1<<19|1<<4|1<<2|direction); + + writemmr(SR1,direction?s2:s1); + writemmr(SR2,direction?s1:s2); + writemmr(DR1,direction?d2:d1); + writemmr(DR2,direction?d1:d2); +} + +static struct accel_switch accel_blade = { + blade_init_accel, + blade_wait_engine, + blade_fill_rect, + blade_copy_rect, +}; + + +/* + * BladeXP specific acceleration functions + */ + +#define ROP_P 0xF0 +#define masked_point(x,y) ((y & 0xffff)<<16|(x & 0xffff)) + +static void xp_init_accel(int pitch,int bpp) +{ + int tmp = 0,v1; + unsigned char x = 0; + + switch (bpp) { + case 8: x = 0; break; + case 16: x = 1; break; + case 24: x = 3; break; + case 32: x = 2; break; + } + + switch (pitch << (bpp >> 3)) { + case 8192: + case 512: x |= 0x00; break; + case 1024: x |= 0x04; break; + case 2048: x |= 0x08; break; + case 4096: x |= 0x0C; break; + } + + t_outb(x,0x2125); + + eng_oper = x | 0x40; + + switch (bpp) { + case 8: tmp = 18; break; + case 15: + case 16: tmp = 19; break; + case 24: + case 32: tmp = 20; break; + } + + v1 = pitch << tmp; + + writemmr(0x2154,v1); + writemmr(0x2150,v1); + t_outb(3,0x2126); +} + +static void xp_wait_engine(void) +{ + int busy; + int count, timeout; + + count = 0; + timeout = 0; + for (;;) { + busy = t_inb(STA) & 0x80; + if (busy != 0x80) + return; + count++; + if (count == 10000000) { + /* Timeout */ + count = 9990000; + timeout++; + if (timeout == 8) { + /* Reset engine */ + t_outb(0x00, 0x2120); + return; + } + } + } +} + +static void xp_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop) +{ + writemmr(0x2127,ROP_P); + writemmr(0x2158,c); + writemmr(0x2128,0x4000); + writemmr(0x2140,masked_point(h,w)); + writemmr(0x2138,masked_point(y,x)); + t_outb(0x01,0x2124); + t_outb(eng_oper,0x2125); +} + +static void xp_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h) +{ + int direction; + __u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp; + + direction = 0x0004; + + if ((x1 < x2) && (y1 == y2)) { + direction |= 0x0200; + x1_tmp = x1 + w - 1; + x2_tmp = x2 + w - 1; + } else { + x1_tmp = x1; + x2_tmp = x2; + } + + if (y1 < y2) { + direction |= 0x0100; + y1_tmp = y1 + h - 1; + y2_tmp = y2 + h - 1; + } else { + y1_tmp = y1; + y2_tmp = y2; + } + + writemmr(0x2128,direction); + t_outb(ROP_S,0x2127); + writemmr(0x213C,masked_point(y1_tmp,x1_tmp)); + writemmr(0x2138,masked_point(y2_tmp,x2_tmp)); + writemmr(0x2140,masked_point(h,w)); + t_outb(0x01,0x2124); +} + +static struct accel_switch accel_xp = { + xp_init_accel, + xp_wait_engine, + xp_fill_rect, + xp_copy_rect, +}; + + +/* + * Image specific acceleration functions + */ +static void image_init_accel(int pitch,int bpp) +{ + int tmp = 0; + switch (bpp) { + case 8:tmp = 0;break; + case 15:tmp = 5;break; + case 16:tmp = 1;break; + case 24: + case 32:tmp = 2;break; + } + writemmr(0x2120, 0xF0000000); + writemmr(0x2120, 0x40000000|tmp); + writemmr(0x2120, 0x80000000); + writemmr(0x2144, 0x00000000); + writemmr(0x2148, 0x00000000); + writemmr(0x2150, 0x00000000); + writemmr(0x2154, 0x00000000); + writemmr(0x2120, 0x60000000|(pitch<<16) |pitch); + writemmr(0x216C, 0x00000000); + writemmr(0x2170, 0x00000000); + writemmr(0x217C, 0x00000000); + writemmr(0x2120, 0x10000000); + writemmr(0x2130, (2047 << 16) | 2047); +} + +static void image_wait_engine(void) +{ + while(readmmr(0x2164) & 0xF0000000); +} + +static void image_fill_rect(__u32 x, __u32 y, __u32 w, __u32 h, __u32 c, __u32 rop) +{ + writemmr(0x2120,0x80000000); + writemmr(0x2120,0x90000000|ROP_S); + + writemmr(0x2144,c); + + writemmr(DR1,point(x,y)); + writemmr(DR2,point(x+w-1,y+h-1)); + + writemmr(0x2124,0x80000000|3<<22|1<<10|1<<9); +} + +static void image_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h) +{ + __u32 s1,s2,d1,d2; + int direction = 2; + s1 = point(x1,y1); + s2 = point(x1+w-1,y1+h-1); + d1 = point(x2,y2); + d2 = point(x2+w-1,y2+h-1); + + if ((y1 > y2) || ((y1 == y2) && (x1 >x2))) + direction = 0; + + writemmr(0x2120,0x80000000); + writemmr(0x2120,0x90000000|ROP_S); + + writemmr(SR1,direction?s2:s1); + writemmr(SR2,direction?s1:s2); + writemmr(DR1,direction?d2:d1); + writemmr(DR2,direction?d1:d2); + writemmr(0x2124,0x80000000|1<<22|1<<10|1<<7|direction); +} + + +static struct accel_switch accel_image = { + image_init_accel, + image_wait_engine, + image_fill_rect, + image_copy_rect, +}; + +/* + * Accel functions called by the upper layers + */ +#ifdef CONFIG_FB_TRIDENT_ACCEL +static void tridentfb_fillrect(struct fb_info * info, const struct fb_fillrect *fr) +{ + int bpp = info->var.bits_per_pixel; + int col; + + switch (bpp) { + default: + case 8: col = fr->color; + break; + case 16: col = ((u32 *)(info->pseudo_palette))[fr->color]; + break; + case 32: col = ((u32 *)(info->pseudo_palette))[fr->color]; + break; + } + + acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop); + acc->wait_engine(); +} +static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *ca) +{ + acc->copy_rect(ca->sx,ca->sy,ca->dx,ca->dy,ca->width,ca->height); + acc->wait_engine(); +} +#else /* !CONFIG_FB_TRIDENT_ACCEL */ +#define tridentfb_fillrect cfb_fillrect +#define tridentfb_copyarea cfb_copyarea +#endif /* CONFIG_FB_TRIDENT_ACCEL */ + + +/* + * Hardware access functions + */ + +static inline unsigned char read3X4(int reg) +{ + struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par; + writeb(reg, par->io_virt + CRT + 4); + return readb( par->io_virt + CRT + 5); +} + +static inline void write3X4(int reg, unsigned char val) +{ + struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par; + writeb(reg, par->io_virt + CRT + 4); + writeb(val, par->io_virt + CRT + 5); +} + +static inline unsigned char read3C4(int reg) +{ + t_outb(reg, 0x3C4); + return t_inb(0x3C5); +} + +static inline void write3C4(int reg, unsigned char val) +{ + t_outb(reg, 0x3C4); + t_outb(val, 0x3C5); +} + +static inline unsigned char read3CE(int reg) +{ + t_outb(reg, 0x3CE); + return t_inb(0x3CF); +} + +static inline void writeAttr(int reg, unsigned char val) +{ + readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); //flip-flop to index + t_outb(reg, 0x3C0); + t_outb(val, 0x3C0); +} + +static inline void write3CE(int reg, unsigned char val) +{ + t_outb(reg, 0x3CE); + t_outb(val, 0x3CF); +} + +static inline void enable_mmio(void) +{ + /* Goto New Mode */ + outb(0x0B, 0x3C4); + inb(0x3C5); + + /* Unprotect registers */ + outb(NewMode1, 0x3C4); + outb(0x80, 0x3C5); + + /* Enable MMIO */ + outb(PCIReg, 0x3D4); + outb(inb(0x3D5) | 0x01, 0x3D5); +} + + +#define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F) + +/* Return flat panel's maximum x resolution */ +static int __init get_nativex(void) +{ + int x,y,tmp; + + if (nativex) + return nativex; + + tmp = (read3CE(VertStretch) >> 4) & 3; + + switch (tmp) { + case 0: x = 1280; y = 1024; break; + case 2: x = 1024; y = 768; break; + case 3: x = 800; y = 600; break; + case 4: x = 1400; y = 1050; break; + case 1: + default:x = 640; y = 480; break; + } + + output("%dx%d flat panel found\n", x, y); + return x; +} + +/* Set pitch */ +static void set_lwidth(int width) +{ + write3X4(Offset, width & 0xFF); + write3X4(AddColReg, (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >>4)); +} + +/* For resolutions smaller than FP resolution stretch */ +static void screen_stretch(void) +{ + if (chip_id != CYBERBLADEXPAi1) + write3CE(BiosReg,0); + else + write3CE(BiosReg,8); + write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 1); + write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 1); +} + +/* For resolutions smaller than FP resolution center */ +static void screen_center(void) +{ + write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 0x80); + write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 0x80); +} + +/* Address of first shown pixel in display memory */ +static void set_screen_start(int base) +{ + write3X4(StartAddrLow, base & 0xFF); + write3X4(StartAddrHigh, (base & 0xFF00) >> 8); + write3X4(CRTCModuleTest, (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11)); + write3X4(CRTHiOrd, (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17)); +} + +/* Use 20.12 fixed-point for NTSC value and frequency calculation */ +#define calc_freq(n,m,k) ( ((unsigned long)0xE517 * (n+8) / ((m+2)*(1<<k))) >> 12 ) + +/* Set dotclock frequency */ +static void set_vclk(int freq) +{ + int m,n,k; + int f,fi,d,di; + unsigned char lo=0,hi=0; + + d = 20; + for(k = 2;k>=0;k--) + for(m = 0;m<63;m++) + for(n = 0;n<128;n++) { + fi = calc_freq(n,m,k); + if ((di = abs(fi - freq)) < d) { + d = di; + f = fi; + lo = n; + hi = (k<<6) | m; + } + } + if (chip3D) { + write3C4(ClockHigh,hi); + write3C4(ClockLow,lo); + } else { + outb(lo,0x43C8); + outb(hi,0x43C9); + } + debug("VCLK = %X %X\n",hi,lo); +} + +/* Set number of lines for flat panels*/ +static void set_number_of_lines(int lines) +{ + int tmp = read3CE(CyberEnhance) & 0x8F; + if (lines > 1024) + tmp |= 0x50; + else if (lines > 768) + tmp |= 0x30; + else if (lines > 600) + tmp |= 0x20; + else if (lines > 480) + tmp |= 0x10; + write3CE(CyberEnhance, tmp); +} + +/* + * If we see that FP is active we assume we have one. + * Otherwise we have a CRT display.User can override. + */ +static unsigned int __init get_displaytype(void) +{ + if (fp) + return DISPLAY_FP; + if (crt || !chipcyber) + return DISPLAY_CRT; + return (read3CE(FPConfig) & 0x10)?DISPLAY_FP:DISPLAY_CRT; +} + +/* Try detecting the video memory size */ +static unsigned int __init get_memsize(void) +{ + unsigned char tmp, tmp2; + unsigned int k; + + /* If memory size provided by user */ + if (memsize) + k = memsize * Kb; + else + switch (chip_id) { + case CYBER9525DVD: k = 2560 * Kb; break; + default: + tmp = read3X4(SPR) & 0x0F; + switch (tmp) { + + case 0x01: k = 512; break; + case 0x02: k = 6 * Mb; break; /* XP */ + case 0x03: k = 1 * Mb; break; + case 0x04: k = 8 * Mb; break; + case 0x06: k = 10 * Mb; break; /* XP */ + case 0x07: k = 2 * Mb; break; + case 0x08: k = 12 * Mb; break; /* XP */ + case 0x0A: k = 14 * Mb; break; /* XP */ + case 0x0C: k = 16 * Mb; break; /* XP */ + case 0x0E: /* XP */ + + tmp2 = read3C4(0xC1); + switch (tmp2) { + case 0x00: k = 20 * Mb; break; + case 0x01: k = 24 * Mb; break; + case 0x10: k = 28 * Mb; break; + case 0x11: k = 32 * Mb; break; + default: k = 1 * Mb; break; + } + break; + + case 0x0F: k = 4 * Mb; break; + default: k = 1 * Mb; + } + } + + k -= memdiff * Kb; + output("framebuffer size = %d Kb\n", k/Kb); + return k; +} + +/* See if we can handle the video mode described in var */ +static int tridentfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + int bpp = var->bits_per_pixel; + debug("enter\n"); + + /* check color depth */ + if (bpp == 24 ) + bpp = var->bits_per_pixel = 32; + /* check whether resolution fits on panel and in memory*/ + if (flatpanel && nativex && var->xres > nativex) + return -EINVAL; + if (var->xres * var->yres_virtual * bpp/8 > info->fix.smem_len) + return -EINVAL; + + switch (bpp) { + case 8: + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->red.length = 6; + var->green.length = 6; + var->blue.length = 6; + break; + case 16: + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + break; + default: + return -EINVAL; + } + debug("exit\n"); + + return 0; + +} +/* Pan the display */ +static int tridentfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + unsigned int offset; + + debug("enter\n"); + offset = (var->xoffset + (var->yoffset * var->xres)) + * var->bits_per_pixel/32; + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + set_screen_start(offset); + debug("exit\n"); + return 0; +} + +#define shadowmode_on() write3CE(CyberControl,read3CE(CyberControl) | 0x81) +#define shadowmode_off() write3CE(CyberControl,read3CE(CyberControl) & 0x7E) + +/* Set the hardware to the requested video mode */ +static int tridentfb_set_par(struct fb_info *info) +{ + struct tridentfb_par * par = (struct tridentfb_par *)(info->par); + u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend, + vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend; + struct fb_var_screeninfo *var = &info->var; + int bpp = var->bits_per_pixel; + unsigned char tmp; + debug("enter\n"); + htotal = (var->xres + var->left_margin + var->right_margin + var->hsync_len)/8 - 10; + hdispend = var->xres/8 - 1; + hsyncstart = (var->xres + var->right_margin)/8; + hsyncend = var->hsync_len/8; + hblankstart = hdispend + 1; + hblankend = htotal + 5; + + vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len - 2; + vdispend = var->yres - 1; + vsyncstart = var->yres + var->lower_margin; + vsyncend = var->vsync_len; + vblankstart = var->yres; + vblankend = vtotal + 2; + + enable_mmio(); + crtc_unlock(); + write3CE(CyberControl,8); + + if (flatpanel && var->xres < nativex) { + /* + * on flat panels with native size larger + * than requested resolution decide whether + * we stretch or center + */ + t_outb(0xEB,0x3C2); + + shadowmode_on(); + + if (center) + screen_center(); + else if (stretch) + screen_stretch(); + + } else { + t_outb(0x2B,0x3C2); + write3CE(CyberControl,8); + } + + /* vertical timing values */ + write3X4(CRTVTotal, vtotal & 0xFF); + write3X4(CRTVDispEnd, vdispend & 0xFF); + write3X4(CRTVSyncStart, vsyncstart & 0xFF); + write3X4(CRTVSyncEnd, (vsyncend & 0x0F)); + write3X4(CRTVBlankStart, vblankstart & 0xFF); + write3X4(CRTVBlankEnd, 0/*p->vblankend & 0xFF*/); + + /* horizontal timing values */ + write3X4(CRTHTotal, htotal & 0xFF); + write3X4(CRTHDispEnd, hdispend & 0xFF); + write3X4(CRTHSyncStart, hsyncstart & 0xFF); + write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20)<<2)); + write3X4(CRTHBlankStart, hblankstart & 0xFF); + write3X4(CRTHBlankEnd, 0/*(p->hblankend & 0x1F)*/); + + /* higher bits of vertical timing values */ + tmp = 0x10; + if (vtotal & 0x100) tmp |= 0x01; + if (vdispend & 0x100) tmp |= 0x02; + if (vsyncstart & 0x100) tmp |= 0x04; + if (vblankstart & 0x100) tmp |= 0x08; + + if (vtotal & 0x200) tmp |= 0x20; + if (vdispend & 0x200) tmp |= 0x40; + if (vsyncstart & 0x200) tmp |= 0x80; + write3X4(CRTOverflow, tmp); + + tmp = read3X4(CRTHiOrd) | 0x08; //line compare bit 10 + if (vtotal & 0x400) tmp |= 0x80; + if (vblankstart & 0x400) tmp |= 0x40; + if (vsyncstart & 0x400) tmp |= 0x20; + if (vdispend & 0x400) tmp |= 0x10; + write3X4(CRTHiOrd, tmp); + + tmp = 0; + if (htotal & 0x800) tmp |= 0x800 >> 11; + if (hblankstart & 0x800) tmp |= 0x800 >> 7; + write3X4(HorizOverflow, tmp); + + tmp = 0x40; + if (vblankstart & 0x200) tmp |= 0x20; +//FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; //double scan for 200 line modes + write3X4(CRTMaxScanLine, tmp); + + write3X4(CRTLineCompare,0xFF); + write3X4(CRTPRowScan,0); + write3X4(CRTModeControl,0xC3); + + write3X4(LinearAddReg,0x20); //enable linear addressing + + tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84:0x80; + write3X4(CRTCModuleTest,tmp); //enable access extended memory + + write3X4(GraphEngReg, 0x80); //enable GE for text acceleration + +// if (info->var.accel_flags & FB_ACCELF_TEXT) +//FIXME acc->init_accel(info->var.xres,bpp); + + switch (bpp) { + case 8: tmp = 0x00; break; + case 16: tmp = 0x05; break; + case 24: tmp = 0x29; break; + case 32: tmp = 0x09; + } + + write3X4(PixelBusReg, tmp); + + tmp = 0x10; + if (chipcyber) + tmp |= 0x20; + write3X4(DRAMControl, tmp); //both IO,linear enable + + write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40); + write3X4(Performance,0x20); + write3X4(PCIReg,0x07); //MMIO & PCI read and write burst enable + + /* convert from picoseconds to MHz */ + par->vclk = 1000000/info->var.pixclock; + if (bpp == 32) + par->vclk *=2; + set_vclk(par->vclk); + + write3C4(0,3); + write3C4(1,1); //set char clock 8 dots wide + write3C4(2,0x0F); //enable 4 maps because needed in chain4 mode + write3C4(3,0); + write3C4(4,0x0E); //memory mode enable bitmaps ?? + + write3CE(MiscExtFunc,(bpp==32)?0x1A:0x12); //divide clock by 2 if 32bpp + //chain4 mode display and CPU path + write3CE(0x5,0x40); //no CGA compat,allow 256 col + write3CE(0x6,0x05); //graphics mode + write3CE(0x7,0x0F); //planes? + + if (chip_id == CYBERBLADEXPAi1) { + /* This fixes snow-effect in 32 bpp */ + write3X4(CRTHSyncStart,0x84); + } + + writeAttr(0x10,0x41); //graphics mode and support 256 color modes + writeAttr(0x12,0x0F); //planes + writeAttr(0x13,0); //horizontal pel panning + + //colors + for(tmp = 0;tmp < 0x10;tmp++) + writeAttr(tmp,tmp); + readb(par->io_virt + CRT + 0x0A); //flip-flop to index + t_outb(0x20, 0x3C0); //enable attr + + switch (bpp) { + case 8: tmp = 0;break; //256 colors + case 15: tmp = 0x10;break; + case 16: tmp = 0x30;break; //hicolor + case 24: //truecolor + case 32: tmp = 0xD0;break; + } + + t_inb(0x3C8); + t_inb(0x3C6); + t_inb(0x3C6); + t_inb(0x3C6); + t_inb(0x3C6); + t_outb(tmp,0x3C6); + t_inb(0x3C8); + + if (flatpanel) + set_number_of_lines(info->var.yres); + set_lwidth(info->var.xres * bpp/(4*16)); + info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + info->fix.line_length = info->var.xres * (bpp >> 3); + info->cmap.len = (bpp == 8) ? 256: 16; + debug("exit\n"); + return 0; +} + +/* Set one color register */ +static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + int bpp = info->var.bits_per_pixel; + + if (regno >= info->cmap.len) + return 1; + + + if (bpp==8) { + t_outb(0xFF,0x3C6); + t_outb(regno,0x3C8); + + t_outb(red>>10,0x3C9); + t_outb(green>>10,0x3C9); + t_outb(blue>>10,0x3C9); + + } else + if (bpp == 16) /* RGB 565 */ + ((u32*)info->pseudo_palette)[regno] = (red & 0xF800) | + ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); + else + if (bpp == 32) /* ARGB 8888 */ + ((u32*)info->pseudo_palette)[regno] = + ((transp & 0xFF00) <<16) | + ((red & 0xFF00) << 8) | + ((green & 0xFF00)) | + ((blue & 0xFF00)>>8); + +// debug("exit\n"); + return 0; +} + +/* Try blanking the screen.For flat panels it does nothing */ +static int tridentfb_blank(int blank_mode, struct fb_info *info) +{ + unsigned char PMCont,DPMSCont; + + debug("enter\n"); + if (flatpanel) + return 0; + t_outb(0x04,0x83C8); /* Read DPMS Control */ + PMCont = t_inb(0x83C6) & 0xFC; + DPMSCont = read3CE(PowerStatus) & 0xFC; + switch (blank_mode) + { + case FB_BLANK_UNBLANK: + /* Screen: On, HSync: On, VSync: On */ + case FB_BLANK_NORMAL: + /* Screen: Off, HSync: On, VSync: On */ + PMCont |= 0x03; + DPMSCont |= 0x00; + break; + case FB_BLANK_HSYNC_SUSPEND: + /* Screen: Off, HSync: Off, VSync: On */ + PMCont |= 0x02; + DPMSCont |= 0x01; + break; + case FB_BLANK_VSYNC_SUSPEND: + /* Screen: Off, HSync: On, VSync: Off */ + PMCont |= 0x02; + DPMSCont |= 0x02; + break; + case FB_BLANK_POWERDOWN: + /* Screen: Off, HSync: Off, VSync: Off */ + PMCont |= 0x00; + DPMSCont |= 0x03; + break; + } + + write3CE(PowerStatus,DPMSCont); + t_outb(4,0x83C8); + t_outb(PMCont,0x83C6); + + debug("exit\n"); + + /* let fbcon do a softblank for us */ + return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; +} + +static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_device_id * id) +{ + int err; + unsigned char revision; + + err = pci_enable_device(dev); + if (err) + return err; + + chip_id = id->device; + + /* If PCI id is 0x9660 then further detect chip type */ + + if (chip_id == TGUI9660) { + outb(RevisionID,0x3C4); + revision = inb(0x3C5); + + switch (revision) { + case 0x22: + case 0x23: chip_id = CYBER9397;break; + case 0x2A: chip_id = CYBER9397DVD;break; + case 0x30: + case 0x33: + case 0x34: + case 0x35: + case 0x38: + case 0x3A: + case 0xB3: chip_id = CYBER9385;break; + case 0x40 ... 0x43: chip_id = CYBER9382;break; + case 0x4A: chip_id = CYBER9388;break; + default:break; + } + } + + chip3D = is3Dchip(chip_id); + chipcyber = iscyber(chip_id); + + if (is_xp(chip_id)) { + acc = &accel_xp; + } else + if (is_blade(chip_id)) { + acc = &accel_blade; + } else { + acc = &accel_image; + } + + /* acceleration is on by default for 3D chips */ + defaultaccel = chip3D && !noaccel; + + fb_info.par = &default_par; + + /* setup MMIO region */ + tridentfb_fix.mmio_start = pci_resource_start(dev,1); + tridentfb_fix.mmio_len = chip3D ? 0x20000:0x10000; + + if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) { + debug("request_region failed!\n"); + return -1; + } + + default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); + + if (!default_par.io_virt) { + release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); + debug("ioremap failed\n"); + return -1; + } + + enable_mmio(); + + /* setup framebuffer memory */ + tridentfb_fix.smem_start = pci_resource_start(dev,0); + tridentfb_fix.smem_len = get_memsize(); + + if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) { + debug("request_mem_region failed!\n"); + return -1; + } + + fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start, + tridentfb_fix.smem_len); + + if (!fb_info.screen_base) { + release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len); + debug("ioremap failed\n"); + return -1; + } + + output("%s board found\n", pci_name(dev)); +#if 0 + output("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n", + tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt); +#endif + displaytype = get_displaytype(); + + if(flatpanel) + nativex = get_nativex(); + + fb_info.fix = tridentfb_fix; + fb_info.fbops = &tridentfb_ops; + + + fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; +#ifdef CONFIG_FB_TRIDENT_ACCEL + fb_info.flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; +#endif + fb_info.pseudo_palette = pseudo_pal; + + if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp)) + return -EINVAL; + fb_alloc_cmap(&fb_info.cmap,256,0); + if (defaultaccel && acc) + default_var.accel_flags |= FB_ACCELF_TEXT; + else + default_var.accel_flags &= ~FB_ACCELF_TEXT; + default_var.activate |= FB_ACTIVATE_NOW; + fb_info.var = default_var; + fb_info.device = &dev->dev; + if (register_framebuffer(&fb_info) < 0) { + printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n"); + return -EINVAL; + } + output("fb%d: %s frame buffer device %dx%d-%dbpp\n", + fb_info.node, fb_info.fix.id,default_var.xres, + default_var.yres,default_var.bits_per_pixel); + return 0; +} + +static void __devexit trident_pci_remove(struct pci_dev * dev) +{ + struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par; + unregister_framebuffer(&fb_info); + iounmap(par->io_virt); + iounmap(fb_info.screen_base); + release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len); + release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); +} + +/* List of boards that we are trying to support */ +static struct pci_device_id trident_devices[] = { + {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci,trident_devices); + +static struct pci_driver tridentfb_pci_driver = { + .name = "tridentfb", + .id_table = trident_devices, + .probe = trident_pci_probe, + .remove = __devexit_p(trident_pci_remove) +}; + +/* + * Parse user specified options (`video=trident:') + * example: + * video=trident:800x600,bpp=16,noaccel + */ +#ifndef MODULE +static int tridentfb_setup(char *options) +{ + char * opt; + if (!options || !*options) + return 0; + while((opt = strsep(&options,",")) != NULL ) { + if (!*opt) continue; + if (!strncmp(opt,"noaccel",7)) + noaccel = 1; + else if (!strncmp(opt,"fp",2)) + displaytype = DISPLAY_FP; + else if (!strncmp(opt,"crt",3)) + displaytype = DISPLAY_CRT; + else if (!strncmp(opt,"bpp=",4)) + bpp = simple_strtoul(opt+4,NULL,0); + else if (!strncmp(opt,"center",6)) + center = 1; + else if (!strncmp(opt,"stretch",7)) + stretch = 1; + else if (!strncmp(opt,"memsize=",8)) + memsize = simple_strtoul(opt+8,NULL,0); + else if (!strncmp(opt,"memdiff=",8)) + memdiff = simple_strtoul(opt+8,NULL,0); + else if (!strncmp(opt,"nativex=",8)) + nativex = simple_strtoul(opt+8,NULL,0); + else + mode = opt; + } + return 0; +} +#endif + +static int __init tridentfb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("tridentfb", &option)) + return -ENODEV; + tridentfb_setup(option); +#endif + output("Trident framebuffer %s initializing\n", VERSION); + return pci_register_driver(&tridentfb_pci_driver); +} + +static void __exit tridentfb_exit(void) +{ + pci_unregister_driver(&tridentfb_pci_driver); +} + +static struct fb_ops tridentfb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = tridentfb_setcolreg, + .fb_pan_display = tridentfb_pan_display, + .fb_blank = tridentfb_blank, + .fb_check_var = tridentfb_check_var, + .fb_set_par = tridentfb_set_par, + .fb_fillrect = tridentfb_fillrect, + .fb_copyarea= tridentfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +module_init(tridentfb_init); +module_exit(tridentfb_exit); + +MODULE_AUTHOR("Jani Monoses <jani@iv.ro>"); +MODULE_DESCRIPTION("Framebuffer driver for Trident cards"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c new file mode 100644 index 000000000000..39d9ca71856b --- /dev/null +++ b/drivers/video/tx3912fb.c @@ -0,0 +1,328 @@ +/* + * drivers/video/tx3912fb.c + * + * Copyright (C) 1999 Harald Koerfgen + * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.com) + * + * 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. + * + * Framebuffer for LCD controller in TMPR3912/05 and PR31700 processors + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/tty.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/pm.h> +#include <linux/fb.h> +#include <asm/io.h> +#include <asm/bootinfo.h> +#include <asm/uaccess.h> +#include <asm/tx3912.h> +#include <video/tx3912.h> + +/* + * Frame buffer, palette and console structures + */ +static struct fb_info fb_info; +static u32 cfb8[16]; + +static struct fb_fix_screeninfo tx3912fb_fix __initdata = { + .id = "tx3912fb", + .smem_len = ((240 * 320)/2), + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .xpanstep = 1, + .ypanstep = 1, + .ywrapstep = 1, + .accel = FB_ACCEL_NONE, +}; + +static struct fb_var_screeninfo tx3912fb_var = { + .xres = 240, + .yres = 320, + .xres_virtual = 240, + .yres_virtual = 320, + .bits_per_pixel =4, + .red = { 0, 4, 0 }, /* ??? */ + .green = { 0, 4, 0 }, + .blue = { 0, 4, 0 }, + .activate = FB_ACTIVATE_NOW, + .width = -1, + .height = -1, + .pixclock = 20000, + .left_margin = 64, + .right_margin = 64, + .upper_margin = 32, + .lower_margin = 32, + .hsync_len = 64, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED, +}; + +/* + * Interface used by the world + */ +int tx3912fb_init(void); + +static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info); + +/* + * Macros + */ +#define get_line_length(xres_virtual, bpp) \ + (u_long) (((int) xres_virtual * (int) bpp + 7) >> 3) + +/* + * Frame buffer operations structure used by console driver + */ +static struct fb_ops tx3912fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = tx3912fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +static int tx3912fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + /* + * Memory limit + */ + line_length = + get_line_length(var->xres_virtual, var->bits_per_pixel); + if ((line_length * var->yres_virtual) > info->fix.smem_len) + return -ENOMEM; + + return 0; +} + +static int tx3912fb_set_par(struct fb_info *info) +{ + u_long tx3912fb_paddr = 0; + + /* Disable the video logic */ + outl(inl(TX3912_VIDEO_CTRL1) & + ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), + TX3912_VIDEO_CTRL1); + udelay(200); + + /* Set start address for DMA transfer */ + outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3); + + /* Set end address for DMA transfer */ + outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4); + + /* Set the pixel depth */ + switch (info->var.bits_per_pixel) { + case 1: + /* Monochrome */ + outl(inl(TX3912_VIDEO_CTRL1) & + ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); + info->fix.visual = FB_VISUAL_MONO10; + break; + case 4: + /* 4-bit gray */ + outl(inl(TX3912_VIDEO_CTRL1) & + ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); + outl(inl(TX3912_VIDEO_CTRL1) | + TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY, + TX3912_VIDEO_CTRL1); + info->fix.visual = FB_VISUAL_TRUECOLOR; + break; + case 8: + /* 8-bit color */ + outl(inl(TX3912_VIDEO_CTRL1) & + ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); + outl(inl(TX3912_VIDEO_CTRL1) | + TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR, + TX3912_VIDEO_CTRL1); + info->fix.visual = FB_VISUAL_TRUECOLOR; + break; + case 2: + default: + /* 2-bit gray */ + outl(inl(TX3912_VIDEO_CTRL1) & + ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); + outl(inl(TX3912_VIDEO_CTRL1) | + TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY, + TX3912_VIDEO_CTRL1); + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + } + + /* Enable the video clock */ + outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK, + TX3912_CLK_CTRL); + + /* Unfreeze video logic and enable DF toggle */ + outl(inl(TX3912_VIDEO_CTRL1) & + ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | + TX3912_VIDEO_CTRL1_DFMODE) + , TX3912_VIDEO_CTRL1); + udelay(200); + + /* Enable the video logic */ + outl(inl(TX3912_VIDEO_CTRL1) | + (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), + TX3912_VIDEO_CTRL1); + + info->fix.line_length = get_line_length(var->xres_virtual, + var->bits_per_pixel); +} + +/* + * Set a single color register + */ +static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info) +{ + if (regno > 255) + return 1; + + if (regno < 16) + ((u32 *)(info->pseudo_palette))[regno] = ((red & 0xe000) >> 8) + | ((green & 0xe000) >> 11) + | ((blue & 0xc000) >> 14); + return 0; +} + +int __init tx3912fb_setup(char *options); + +/* + * Initialization of the framebuffer + */ +int __init tx3912fb_init(void) +{ + u_long tx3912fb_paddr = 0; + int size = (info->var.bits_per_pixel == 8) ? 256 : 16; + char *option = NULL; + + if (fb_get_options("tx3912fb", &option)) + return -ENODEV; + tx3912fb_setup(option); + + /* Disable the video logic */ + outl(inl(TX3912_VIDEO_CTRL1) & + ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), + TX3912_VIDEO_CTRL1); + udelay(200); + + /* Set start address for DMA transfer */ + outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3); + + /* Set end address for DMA transfer */ + outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4); + + /* Set the pixel depth */ + switch (tx3912fb_var.bits_per_pixel) { + case 1: + /* Monochrome */ + outl(inl(TX3912_VIDEO_CTRL1) & + ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); + tx3912fb_fix.visual = FB_VISUAL_MONO10; + break; + case 4: + /* 4-bit gray */ + outl(inl(TX3912_VIDEO_CTRL1) & + ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); + outl(inl(TX3912_VIDEO_CTRL1) | + TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY, + TX3912_VIDEO_CTRL1); + tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR; + tx3912fb_fix.grayscale = 1; + break; + case 8: + /* 8-bit color */ + outl(inl(TX3912_VIDEO_CTRL1) & + ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); + outl(inl(TX3912_VIDEO_CTRL1) | + TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR, + TX3912_VIDEO_CTRL1); + tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR; + break; + case 2: + default: + /* 2-bit gray */ + outl(inl(TX3912_VIDEO_CTRL1) & + ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); + outl(inl(TX3912_VIDEO_CTRL1) | + TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY, + TX3912_VIDEO_CTRL1); + tx3912fb_fix.visual = FB_VISUAL_PSEUDOCOLOR; + tx3912fb_fix.grayscale = 1; + break; + } + + /* Enable the video clock */ + outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK, + TX3912_CLK_CTRL); + + /* Unfreeze video logic and enable DF toggle */ + outl(inl(TX3912_VIDEO_CTRL1) & + ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | TX3912_VIDEO_CTRL1_DFMODE), + TX3912_VIDEO_CTRL1); + udelay(200); + + /* Clear the framebuffer */ + memset((void *) tx3912fb_fix.smem_start, 0xff, tx3912fb_fix.smem_len); + udelay(200); + + /* Enable the video logic */ + outl(inl(TX3912_VIDEO_CTRL1) | + (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), + TX3912_VIDEO_CTRL1); + + /* + * Memory limit + */ + tx3912fb_fix.line_length = + get_line_length(tx3912fb_var.xres_virtual, tx3912fb_var.bits_per_pixel); + if ((tx3912fb_fix.line_length * tx3912fb_var.yres_virtual) > tx3912fb_fix.smem_len) + return -ENOMEM; + + fb_info.fbops = &tx3912fb_ops; + fb_info.var = tx3912fb_var; + fb_info.fix = tx3912fb_fix; + fb_info.pseudo_palette = pseudo_palette; + fb_info.flags = FBINFO_DEFAULT; + + /* Clear the framebuffer */ + memset((void *) fb_info.fix.smem_start, 0xff, fb_info.fix.smem_len); + udelay(200); + + fb_alloc_cmap(&info->cmap, size, 0); + + if (register_framebuffer(&fb_info) < 0) + return -1; + + printk(KERN_INFO "fb%d: TX3912 frame buffer using %uKB.\n", + fb_info.node, (u_int) (fb_info.fix.smem_len >> 10)); + return 0; +} + +int __init tx3912fb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ","))) { + if (!strncmp(options, "bpp:", 4)) + tx3912fb_var.bits_per_pixel = simple_strtoul(options+4, NULL, 0); + } + return 0; +} + +module_init(tx3912fb_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c new file mode 100644 index 000000000000..31a2bbc53974 --- /dev/null +++ b/drivers/video/valkyriefb.c @@ -0,0 +1,590 @@ +/* + * valkyriefb.c -- frame buffer device for the PowerMac 'valkyrie' display + * + * Created 8 August 1998 by + * Martin Costabel <costabel@wanadoo.fr> and Kevin Schoedel + * + * Vmode-switching changes and vmode 15/17 modifications created 29 August + * 1998 by Barry K. Nathan <barryn@pobox.com>. + * + * Ported to m68k Macintosh by David Huggins-Daines <dhd@debian.org> + * + * Derived directly from: + * + * controlfb.c -- frame buffer device for the PowerMac 'control' display + * Copyright (C) 1998 Dan Jacobowitz <dan@debian.org> + * + * pmc-valkyrie.c -- Console support for PowerMac "valkyrie" display adaptor. + * Copyright (C) 1997 Paul Mackerras. + * + * and indirectly: + * + * Frame buffer structure from: + * drivers/video/chipsfb.c -- frame buffer device for + * Chips & Technologies 65550 chip. + * + * Copyright (C) 1998 Paul Mackerras + * + * This file is derived from the Powermac "chips" driver: + * Copyright (C) 1997 Fabio Riccardi. + * And from the frame buffer device for Open Firmware-initialized devices: + * Copyright (C) 1997 Geert Uytterhoeven. + * + * Hardware information from: + * control.c: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1996 Paul Mackerras + * + * 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/config.h> +#include <linux/module.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/vmalloc.h> +#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 <linux/nvram.h> +#include <linux/adb.h> +#include <linux/cuda.h> +#include <asm/io.h> +#ifdef CONFIG_MAC +#include <asm/bootinfo.h> +#include <asm/macintosh.h> +#else +#include <asm/prom.h> +#endif +#include <asm/pgtable.h> + +#include "macmodes.h" +#include "valkyriefb.h" + +#ifdef CONFIG_MAC +/* We don't yet have functions to read the PRAM... perhaps we can + adapt them from the PPC code? */ +static int default_vmode = VMODE_640_480_67; +static int default_cmode = CMODE_8; +#else +static int default_vmode = VMODE_NVRAM; +static int default_cmode = CMODE_NVRAM; +#endif + +struct fb_par_valkyrie { + int vmode, cmode; + int xres, yres; + int vxres, vyres; + struct valkyrie_regvals *init; +}; + +struct fb_info_valkyrie { + struct fb_info info; + struct fb_par_valkyrie par; + struct cmap_regs __iomem *cmap_regs; + unsigned long cmap_regs_phys; + + struct valkyrie_regs __iomem *valkyrie_regs; + unsigned long valkyrie_regs_phys; + + __u8 __iomem *frame_buffer; + unsigned long frame_buffer_phys; + + int sense; + unsigned long total_vram; + + u32 pseudo_palette[16]; +}; + +/* + * Exported functions + */ +int valkyriefb_init(void); +int valkyriefb_setup(char*); + +static int valkyriefb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int valkyriefb_set_par(struct fb_info *info); +static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int valkyriefb_blank(int blank_mode, struct fb_info *info); + +static int read_valkyrie_sense(struct fb_info_valkyrie *p); +static void set_valkyrie_clock(unsigned char *params); +static int valkyrie_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_valkyrie *par, const struct fb_info *fb_info); + +static void valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p); +static void valkyrie_par_to_fix(struct fb_par_valkyrie *par, struct fb_fix_screeninfo *fix); +static void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p); + +static struct fb_ops valkyriefb_ops = { + .owner = THIS_MODULE, + .fb_check_var = valkyriefb_check_var, + .fb_set_par = valkyriefb_set_par, + .fb_setcolreg = valkyriefb_setcolreg, + .fb_blank = valkyriefb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +/* Sets the video mode according to info->var */ +static int valkyriefb_set_par(struct fb_info *info) +{ + struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) info; + volatile struct valkyrie_regs __iomem *valkyrie_regs = p->valkyrie_regs; + struct fb_par_valkyrie *par = info->par; + struct valkyrie_regvals *init; + int err; + + if ((err = valkyrie_var_to_par(&info->var, par, info))) + return err; + + valkyrie_par_to_fix(par, &info->fix); + + /* Reset the valkyrie */ + out_8(&valkyrie_regs->status.r, 0); + udelay(100); + + /* Initialize display timing registers */ + init = par->init; + out_8(&valkyrie_regs->mode.r, init->mode | 0x80); + out_8(&valkyrie_regs->depth.r, par->cmode + 3); + set_valkyrie_clock(init->clock_params); + udelay(100); + + /* Turn on display */ + out_8(&valkyrie_regs->mode.r, init->mode); + + return 0; +} + +static inline int valkyrie_par_to_var(struct fb_par_valkyrie *par, + struct fb_var_screeninfo *var) +{ + return mac_vmode_to_var(par->vmode, par->cmode, var); +} + +static int +valkyriefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + int err; + struct fb_par_valkyrie par; + + if ((err = valkyrie_var_to_par(var, &par, info))) + return err; + valkyrie_par_to_var(&par, var); + return 0; +} + +/* + * Blank the screen if blank_mode != 0, else unblank. If blank_mode == NULL + * then the caller blanks by setting the CLUT (Color Look Up Table) to all + * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due + * to e.g. a video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + */ +static int valkyriefb_blank(int blank_mode, struct fb_info *info) +{ + struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) info; + struct fb_par_valkyrie *par = info->par; + struct valkyrie_regvals *init = par->init; + + if (init == NULL) + return 1; + + switch (blank_mode) { + case FB_BLANK_UNBLANK: /* unblank */ + out_8(&p->valkyrie_regs->mode.r, init->mode); + break; + case FB_BLANK_NORMAL: + return 1; /* get caller to set CLUT to all black */ + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + /* + * [kps] Value extracted from MacOS. I don't know + * whether this bit disables hsync or vsync, or + * whether the hardware can do the other as well. + */ + out_8(&p->valkyrie_regs->mode.r, init->mode | 0x40); + break; + case FB_BLANK_POWERDOWN: + out_8(&p->valkyrie_regs->mode.r, 0x66); + break; + } + return 0; +} + +static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) info; + volatile struct cmap_regs __iomem *cmap_regs = p->cmap_regs; + struct fb_par_valkyrie *par = info->par; + + if (regno > 255) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + + /* tell clut which address to fill */ + out_8(&p->cmap_regs->addr, regno); + udelay(1); + /* send one color channel at a time */ + out_8(&cmap_regs->lut, red); + out_8(&cmap_regs->lut, green); + out_8(&cmap_regs->lut, blue); + + if (regno < 16 && par->cmode == CMODE_16) + ((u32 *)info->pseudo_palette)[regno] = + (regno << 10) | (regno << 5) | regno; + + return 0; +} + +static inline int valkyrie_vram_reqd(int video_mode, int color_mode) +{ + int pitch; + struct valkyrie_regvals *init = valkyrie_reg_init[video_mode-1]; + + if ((pitch = init->pitch[color_mode]) == 0) + pitch = 2 * init->pitch[0]; + return init->vres * pitch; +} + +static void set_valkyrie_clock(unsigned char *params) +{ + struct adb_request req; + int i; + +#ifdef CONFIG_ADB_CUDA + for (i = 0; i < 3; ++i) { + cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, + 0x50, i + 1, params[i]); + while (!req.complete) + cuda_poll(); + } +#endif +} + +static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p) +{ + p->sense = read_valkyrie_sense(p); + printk(KERN_INFO "Monitor sense value = 0x%x\n", p->sense); + + /* Try to pick a video mode out of NVRAM if we have one. */ +#ifndef CONFIG_MAC + if (default_vmode == VMODE_NVRAM) { + default_vmode = nvram_read_byte(NV_VMODE); + if (default_vmode <= 0 + || default_vmode > VMODE_MAX + || !valkyrie_reg_init[default_vmode - 1]) + default_vmode = VMODE_CHOOSE; + } +#endif + if (default_vmode == VMODE_CHOOSE) + default_vmode = mac_map_monitor_sense(p->sense); + if (!valkyrie_reg_init[default_vmode - 1]) + default_vmode = VMODE_640_480_67; +#ifndef CONFIG_MAC + if (default_cmode == CMODE_NVRAM) + default_cmode = nvram_read_byte(NV_CMODE); +#endif + + /* + * Reduce the pixel size if we don't have enough VRAM or bandwidth. + */ + if (default_cmode < CMODE_8 || default_cmode > CMODE_16 + || valkyrie_reg_init[default_vmode-1]->pitch[default_cmode] == 0 + || valkyrie_vram_reqd(default_vmode, default_cmode) > p->total_vram) + default_cmode = CMODE_8; + + printk(KERN_INFO "using video mode %d and color mode %d.\n", + default_vmode, default_cmode); +} + +int __init valkyriefb_init(void) +{ + struct fb_info_valkyrie *p; + unsigned long frame_buffer_phys, cmap_regs_phys, flags; + int err; + char *option = NULL; + + if (fb_get_options("valkyriefb", &option)) + return -ENODEV; + valkyriefb_setup(option); + +#ifdef CONFIG_MAC + if (!MACH_IS_MAC) + return 0; + if (!(mac_bi_data.id == MAC_MODEL_Q630 + /* I'm not sure about this one */ + || mac_bi_data.id == MAC_MODEL_P588)) + return 0; + + /* Hardcoded addresses... welcome to 68k Macintosh country :-) */ + frame_buffer_phys = 0xf9000000; + cmap_regs_phys = 0x50f24000; + flags = IOMAP_NOCACHE_SER; /* IOMAP_WRITETHROUGH?? */ +#else /* ppc (!CONFIG_MAC) */ + { + struct device_node *dp; + + dp = find_devices("valkyrie"); + if (dp == 0) + return 0; + + if (dp->n_addrs != 1) { + printk(KERN_ERR "expecting 1 address for valkyrie (got %d)\n", + dp->n_addrs); + return 0; + } + + frame_buffer_phys = dp->addrs[0].address; + cmap_regs_phys = dp->addrs[0].address+0x304000; + flags = _PAGE_WRITETHRU; + } +#endif /* ppc (!CONFIG_MAC) */ + + p = kmalloc(sizeof(*p), GFP_ATOMIC); + if (p == 0) + return -ENOMEM; + memset(p, 0, sizeof(*p)); + + /* Map in frame buffer and registers */ + if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) { + kfree(p); + return 0; + } + p->total_vram = 0x100000; + p->frame_buffer_phys = frame_buffer_phys; + p->frame_buffer = __ioremap(frame_buffer_phys, p->total_vram, flags); + p->cmap_regs_phys = cmap_regs_phys; + p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000); + p->valkyrie_regs_phys = cmap_regs_phys+0x6000; + p->valkyrie_regs = ioremap(p->valkyrie_regs_phys, 0x1000); + err = -ENOMEM; + if (p->frame_buffer == NULL || p->cmap_regs == NULL + || p->valkyrie_regs == NULL) { + printk(KERN_ERR "valkyriefb: couldn't map resources\n"); + goto out_free; + } + + valkyrie_choose_mode(p); + mac_vmode_to_var(default_vmode, default_cmode, &p->info.var); + valkyrie_init_info(&p->info, p); + valkyrie_init_fix(&p->info.fix, p); + if (valkyriefb_set_par(&p->info)) + /* "can't happen" */ + printk(KERN_ERR "valkyriefb: can't set default video mode\n"); + + if ((err = register_framebuffer(&p->info)) != 0) + goto out_free; + + printk(KERN_INFO "fb%d: valkyrie frame buffer device\n", p->info.node); + return 0; + + out_free: + if (p->frame_buffer) + iounmap(p->frame_buffer); + if (p->cmap_regs) + iounmap(p->cmap_regs); + if (p->valkyrie_regs) + iounmap(p->valkyrie_regs); + kfree(p); + return err; +} + +/* + * Get the monitor sense value. + */ +static int read_valkyrie_sense(struct fb_info_valkyrie *p) +{ + int sense, in; + + out_8(&p->valkyrie_regs->msense.r, 0); /* release all lines */ + __delay(20000); + sense = ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x70) << 4; + /* drive each sense line low in turn and collect the other 2 */ + out_8(&p->valkyrie_regs->msense.r, 4); /* drive A low */ + __delay(20000); + sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x30); + out_8(&p->valkyrie_regs->msense.r, 2); /* drive B low */ + __delay(20000); + sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x40) >> 3; + sense |= (in & 0x10) >> 2; + out_8(&p->valkyrie_regs->msense.r, 1); /* drive C low */ + __delay(20000); + sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x60) >> 5; + + out_8(&p->valkyrie_regs->msense.r, 7); + + return sense; +} + +/* + * This routine takes a user-supplied var, + * and picks the best vmode/cmode from it. + */ + +/* [bkn] I did a major overhaul of this function. + * + * Much of the old code was "swiped by jonh from atyfb.c". Because + * macmodes has mac_var_to_vmode, I felt that it would be better to + * rework this function to use that, instead of reinventing the wheel to + * add support for vmode 17. This was reinforced by the fact that + * the previously swiped atyfb.c code is no longer there. + * + * So, I swiped and adapted platinum_var_to_par (from platinumfb.c), replacing + * most, but not all, of the old code in the process. One side benefit of + * swiping the platinumfb code is that we now have more comprehensible error + * messages when a vmode/cmode switch fails. (Most of the error messages are + * platinumfb.c, but I added two of my own, and I also changed some commas + * into colons to make the messages more consistent with other Linux error + * messages.) In addition, I think the new code *might* fix some vmode- + * switching oddities, but I'm not sure. + * + * There may be some more opportunities for cleanup in here, but this is a + * good start... + */ + +static int valkyrie_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_valkyrie *par, const struct fb_info *fb_info) +{ + int vmode, cmode; + struct valkyrie_regvals *init; + struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) fb_info; + + if (mac_var_to_vmode(var, &vmode, &cmode) != 0) { + printk(KERN_ERR "valkyriefb: can't do %dx%dx%d.\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + + /* Check if we know about the wanted video mode */ + if (vmode < 1 || vmode > VMODE_MAX || !valkyrie_reg_init[vmode-1]) { + printk(KERN_ERR "valkyriefb: vmode %d not valid.\n", vmode); + return -EINVAL; + } + + if (cmode != CMODE_8 && cmode != CMODE_16) { + printk(KERN_ERR "valkyriefb: cmode %d not valid.\n", cmode); + return -EINVAL; + } + + if (var->xres_virtual > var->xres || var->yres_virtual > var->yres + || var->xoffset != 0 || var->yoffset != 0) { + return -EINVAL; + } + + init = valkyrie_reg_init[vmode-1]; + if (init->pitch[cmode] == 0) { + printk(KERN_ERR "valkyriefb: vmode %d does not support " + "cmode %d.\n", vmode, cmode); + return -EINVAL; + } + + if (valkyrie_vram_reqd(vmode, cmode) > p->total_vram) { + printk(KERN_ERR "valkyriefb: not enough ram for vmode %d, " + "cmode %d.\n", vmode, cmode); + return -EINVAL; + } + + par->vmode = vmode; + par->cmode = cmode; + par->init = init; + par->xres = var->xres; + par->yres = var->yres; + par->vxres = par->xres; + par->vyres = par->yres; + + return 0; +} + +static void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p) +{ + memset(fix, 0, sizeof(*fix)); + strcpy(fix->id, "valkyrie"); + fix->mmio_start = p->valkyrie_regs_phys; + fix->mmio_len = sizeof(struct valkyrie_regs); + fix->type = FB_TYPE_PACKED_PIXELS; + fix->smem_start = p->frame_buffer_phys + 0x1000; + fix->smem_len = p->total_vram; + + fix->type_aux = 0; + fix->ywrapstep = 0; + fix->ypanstep = 0; + fix->xpanstep = 0; + +} + +/* Fix must already be inited above */ +static void valkyrie_par_to_fix(struct fb_par_valkyrie *par, + struct fb_fix_screeninfo *fix) +{ + fix->smem_len = valkyrie_vram_reqd(par->vmode, par->cmode); + fix->visual = (par->cmode == CMODE_8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + fix->line_length = par->vxres << par->cmode; + /* ywrapstep, xpanstep, ypanstep */ +} + +static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p) +{ + info->fbops = &valkyriefb_ops; + info->screen_base = p->frame_buffer + 0x1000; + info->flags = FBINFO_DEFAULT; + info->pseudo_palette = p->pseudo_palette; + fb_alloc_cmap(&info->cmap, 256, 0); + info->par = &p->par; +} + + +/* + * Parse user speficied options (`video=valkyriefb:') + */ +int __init valkyriefb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "vmode:", 6)) { + int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + default_vmode = vmode; + } + else if (!strncmp(this_opt, "cmode:", 6)) { + int depth = simple_strtoul(this_opt+6, NULL, 0); + switch (depth) { + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + } + } + } + return 0; +} + +module_init(valkyriefb_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/valkyriefb.h b/drivers/video/valkyriefb.h new file mode 100644 index 000000000000..97aaf7bb6417 --- /dev/null +++ b/drivers/video/valkyriefb.h @@ -0,0 +1,211 @@ +/* + * valkyriefb.h: Constants of all sorts for valkyriefb + * + * Created 8 August 1998 by + * Martin Costabel <costabel@wanadoo.fr> and Kevin Schoedel + * + * Vmode-switching changes and vmode 15/17 modifications created 29 August + * 1998 by Barry K. Nathan <barryn@pobox.com>. + * + * vmode 10 changed by Steven Borley <sjb@salix.demon.co.uk>, 14 mai 2000 + * + * Ported to 68k Macintosh by David Huggins-Daines <dhd@debian.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Based directly on: + * + * controlfb.h: Constants of all sorts for controlfb + * Copyright (C) 1998 Daniel Jacobowitz <dan@debian.org> + * + * pmc-valkyrie.h: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1997 Paul Mackerras. + * + * pmc-valkyrie.c: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1997 Paul Mackerras. + * + * and indirectly from: + * + * pmc-control.h: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1997 Paul Mackerras. + * + * pmc-control.c: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1996 Paul Mackerras. + * + * platinumfb.c: Console support for PowerMac "platinum" display adaptor. + * Copyright (C) 1998 Jon Howell + */ + +#ifdef CONFIG_MAC +/* Valkyrie registers are word-aligned on m68k */ +#define VALKYRIE_REG_PADSIZE 3 +#else +#define VALKYRIE_REG_PADSIZE 7 +#endif + +/* + * Structure of the registers for the Valkyrie colormap registers. + */ +struct cmap_regs { + unsigned char addr; + char pad1[VALKYRIE_REG_PADSIZE]; + unsigned char lut; +}; + +/* + * Structure of the registers for the "valkyrie" display adaptor. + */ + +struct vpreg { /* padded register */ + unsigned char r; + char pad[VALKYRIE_REG_PADSIZE]; +}; + + +struct valkyrie_regs { + struct vpreg mode; + struct vpreg depth; + struct vpreg status; + struct vpreg reg3; + struct vpreg intr; + struct vpreg reg5; + struct vpreg intr_enb; + struct vpreg msense; +}; + +/* + * Register initialization tables for the valkyrie display. + * + * Dot clock rate is + * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0]. + */ +struct valkyrie_regvals { + unsigned char mode; + unsigned char clock_params[3]; + int pitch[2]; /* bytes/line, indexed by color_mode */ + int hres; + int vres; +}; + +#ifndef CONFIG_MAC +/* Register values for 1024x768, 75Hz mode (17) */ +/* I'm not sure which mode this is (16 or 17), so I'm defining it as 17, + * since the equivalent mode in controlfb (which I adapted this from) is + * also 17. Just because MacOS can't do this on Valkyrie doesn't mean we + * can't! :) + * + * I was going to use 12, 31, 3, which I found by myself, but instead I'm + * using 11, 28, 3 like controlfb, for consistency's sake. + */ + +static struct valkyrie_regvals valkyrie_reg_init_17 = { + 15, + { 11, 28, 3 }, /* pixel clock = 79.55MHz for V=74.50Hz */ + { 1024, 0 }, + 1024, 768 +}; + +/* Register values for 1024x768, 72Hz mode (15) */ +/* This used to be 12, 30, 3 for pixel clock = 78.12MHz for V=72.12Hz, but + * that didn't match MacOS in the same video mode on this chip, and it also + * caused the 15" Apple Studio Display to not work in this mode. While this + * mode still doesn't match MacOS exactly (as far as I can tell), it's a lot + * closer now, and it works with the Apple Studio Display. + * + * Yes, even though MacOS calls it "72Hz", in reality it's about 70Hz. + */ +static struct valkyrie_regvals valkyrie_reg_init_15 = { + 15, + { 12, 29, 3 }, /* pixel clock = 75.52MHz for V=69.71Hz? */ + /* I interpolated the V=69.71 from the vmode 14 and old 15 + * numbers. Is this result correct? + */ + { 1024, 0 }, + 1024, 768 +}; + +/* Register values for 1024x768, 60Hz mode (14) */ +static struct valkyrie_regvals valkyrie_reg_init_14 = { + 14, + { 15, 31, 3 }, /* pixel clock = 64.58MHz for V=59.62Hz */ + { 1024, 0 }, + 1024, 768 +}; + +/* Register values for 800x600, 72Hz mode (11) */ +static struct valkyrie_regvals valkyrie_reg_init_11 = { + 13, + { 17, 27, 3 }, /* pixel clock = 49.63MHz for V=71.66Hz */ + { 800, 0 }, + 800, 600 +}; +#endif /* CONFIG_MAC */ + +/* Register values for 832x624, 75Hz mode (13) */ +static struct valkyrie_regvals valkyrie_reg_init_13 = { + 9, + { 23, 42, 3 }, /* pixel clock = 57.07MHz for V=74.27Hz */ + { 832, 0 }, + 832, 624 +}; + +/* Register values for 800x600, 60Hz mode (10) */ +static struct valkyrie_regvals valkyrie_reg_init_10 = { + 12, + { 25, 32, 3 }, /* pixel clock = 40.0015MHz, + used to be 20,53,2, pixel clock 41.41MHz for V=59.78Hz */ + { 800, 1600 }, + 800, 600 +}; + +/* Register values for 640x480, 67Hz mode (6) */ +static struct valkyrie_regvals valkyrie_reg_init_6 = { + 6, + { 14, 27, 2 }, /* pixel clock = 30.13MHz for V=66.43Hz */ + { 640, 1280 }, + 640, 480 +}; + +/* Register values for 640x480, 60Hz mode (5) */ +static struct valkyrie_regvals valkyrie_reg_init_5 = { + 11, + { 23, 37, 2 }, /* pixel clock = 25.14MHz for V=59.85Hz */ + { 640, 1280 }, + 640, 480 +}; + +static struct valkyrie_regvals *valkyrie_reg_init[VMODE_MAX] = { + NULL, + NULL, + NULL, + NULL, + &valkyrie_reg_init_5, + &valkyrie_reg_init_6, + NULL, + NULL, + NULL, + &valkyrie_reg_init_10, +#ifdef CONFIG_MAC + NULL, + NULL, + &valkyrie_reg_init_13, + NULL, + NULL, + NULL, + NULL, +#else + &valkyrie_reg_init_11, + NULL, + &valkyrie_reg_init_13, + &valkyrie_reg_init_14, + &valkyrie_reg_init_15, + NULL, + &valkyrie_reg_init_17, +#endif + NULL, + NULL, + NULL +}; diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c new file mode 100644 index 000000000000..8fc1278d7fbd --- /dev/null +++ b/drivers/video/vesafb.c @@ -0,0 +1,456 @@ +/* + * framebuffer driver for VBE 2.0 compliant graphic boards + * + * switching to graphics mode happens at boot time (while + * running in real mode, see arch/i386/boot/video.S). + * + * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * + */ + +#include <linux/module.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/delay.h> +#include <linux/fb.h> +#include <linux/ioport.h> +#include <linux/init.h> +#ifdef __i386__ +#include <video/edid.h> +#endif +#include <asm/io.h> +#include <asm/mtrr.h> + +#define dac_reg (0x3c8) +#define dac_val (0x3c9) + +/* --------------------------------------------------------------------- */ + +static struct fb_var_screeninfo vesafb_defined __initdata = { + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .right_margin = 32, + .upper_margin = 16, + .lower_margin = 4, + .vsync_len = 4, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo vesafb_fix __initdata = { + .id = "VESA VGA", + .type = FB_TYPE_PACKED_PIXELS, + .accel = FB_ACCEL_NONE, +}; + +static int inverse = 0; +static int mtrr = 1; +static int vram_remap __initdata = 0; /* Set amount of memory to be used */ +static int vram_total __initdata = 0; /* Set total amount of memory */ +static int pmi_setpal = 0; /* pmi for palette changes ??? */ +static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */ +static unsigned short *pmi_base = NULL; +static void (*pmi_start)(void); +static void (*pmi_pal)(void); +static int depth; + +/* --------------------------------------------------------------------- */ + +static int vesafb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ +#ifdef __i386__ + int offset; + + if (!ypan) + return -EINVAL; + if (var->xoffset) + return -EINVAL; + if (var->yoffset > var->yres_virtual) + return -EINVAL; + if ((ypan==1) && var->yoffset+var->yres > var->yres_virtual) + return -EINVAL; + + offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4; + + __asm__ __volatile__( + "call *(%%edi)" + : /* no return value */ + : "a" (0x4f07), /* EAX */ + "b" (0), /* EBX */ + "c" (offset), /* ECX */ + "d" (offset >> 16), /* EDX */ + "D" (&pmi_start)); /* EDI */ +#endif + return 0; +} + +static void vesa_setpalette(int regno, unsigned red, unsigned green, + unsigned blue) +{ +#ifdef __i386__ + struct { u_char blue, green, red, pad; } entry; + int shift = 16 - depth; + + if (pmi_setpal) { + entry.red = red >> shift; + entry.green = green >> shift; + entry.blue = blue >> shift; + entry.pad = 0; + __asm__ __volatile__( + "call *(%%esi)" + : /* no return value */ + : "a" (0x4f09), /* EAX */ + "b" (0), /* EBX */ + "c" (1), /* ECX */ + "d" (regno), /* EDX */ + "D" (&entry), /* EDI */ + "S" (&pmi_pal)); /* ESI */ + } else { + /* without protected mode interface, try VGA registers... */ + outb_p(regno, dac_reg); + outb_p(red >> shift, dac_val); + outb_p(green >> shift, dac_val); + outb_p(blue >> shift, dac_val); + } +#endif +} + +static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + /* + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return + * != 0 for invalid regno. + */ + + if (regno >= info->cmap.len) + return 1; + + switch (info->var.bits_per_pixel) { + case 8: + vesa_setpalette(regno,red,green,blue); + break; + case 16: + if (info->var.red.offset == 10) { + /* 1:5:5:5 */ + ((u32*) (info->pseudo_palette))[regno] = + ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + } else { + /* 0:5:6:5 */ + ((u32*) (info->pseudo_palette))[regno] = + ((red & 0xf800) ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + } + break; + case 24: + red >>= 8; + green >>= 8; + blue >>= 8; + ((u32 *)(info->pseudo_palette))[regno] = + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + break; + case 32: + red >>= 8; + green >>= 8; + blue >>= 8; + ((u32 *)(info->pseudo_palette))[regno] = + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + break; + } + return 0; +} + +static struct fb_ops vesafb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = vesafb_setcolreg, + .fb_pan_display = vesafb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +static int __init vesafb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) continue; + + if (! strcmp(this_opt, "inverse")) + inverse=1; + else if (! strcmp(this_opt, "redraw")) + ypan=0; + else if (! strcmp(this_opt, "ypan")) + ypan=1; + else if (! strcmp(this_opt, "ywrap")) + ypan=2; + else if (! strcmp(this_opt, "vgapal")) + pmi_setpal=0; + else if (! strcmp(this_opt, "pmipal")) + pmi_setpal=1; + else if (! strcmp(this_opt, "mtrr")) + mtrr=1; + else if (! strcmp(this_opt, "nomtrr")) + mtrr=0; + else if (! strncmp(this_opt, "vtotal:", 7)) + vram_total = simple_strtoul(this_opt+7, NULL, 0); + else if (! strncmp(this_opt, "vremap:", 7)) + vram_remap = simple_strtoul(this_opt+7, NULL, 0); + } + return 0; +} + +static int __init vesafb_probe(struct device *device) +{ + struct platform_device *dev = to_platform_device(device); + struct fb_info *info; + int i, err; + unsigned int size_vmode; + unsigned int size_remap; + unsigned int size_total; + + if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) + return -ENODEV; + + vesafb_fix.smem_start = screen_info.lfb_base; + vesafb_defined.bits_per_pixel = screen_info.lfb_depth; + if (15 == vesafb_defined.bits_per_pixel) + vesafb_defined.bits_per_pixel = 16; + vesafb_defined.xres = screen_info.lfb_width; + vesafb_defined.yres = screen_info.lfb_height; + vesafb_fix.line_length = screen_info.lfb_linelength; + vesafb_fix.visual = (vesafb_defined.bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + + /* size_vmode -- that is the amount of memory needed for the + * used video mode, i.e. the minimum amount of + * memory we need. */ + size_vmode = vesafb_defined.yres * vesafb_fix.line_length; + + /* size_total -- all video memory we have. Used for mtrr + * entries, ressource allocation and bounds + * checking. */ + size_total = screen_info.lfb_size * 65536; + if (vram_total) + size_total = vram_total * 1024 * 1024; + if (size_total < size_vmode) + size_total = size_vmode; + + /* size_remap -- the amount of video memory we are going to + * use for vesafb. With modern cards it is no + * option to simply use size_total as that + * wastes plenty of kernel address space. */ + size_remap = size_vmode * 2; + if (vram_remap) + size_remap = vram_remap * 1024 * 1024; + if (size_remap < size_vmode) + size_remap = size_vmode; + if (size_remap > size_total) + size_remap = size_total; + vesafb_fix.smem_len = size_remap; + +#ifndef __i386__ + screen_info.vesapm_seg = 0; +#endif + + if (!request_mem_region(vesafb_fix.smem_start, size_total, "vesafb")) { + printk(KERN_WARNING + "vesafb: abort, cannot reserve video memory at 0x%lx\n", + vesafb_fix.smem_start); + /* We cannot make this fatal. Sometimes this comes from magic + spaces our resource handlers simply don't know about */ + } + + info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); + if (!info) { + release_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len); + return -ENOMEM; + } + info->pseudo_palette = info->par; + info->par = NULL; + + info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); + if (!info->screen_base) { + printk(KERN_ERR + "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", + vesafb_fix.smem_len, vesafb_fix.smem_start); + err = -EIO; + goto err; + } + + printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, " + "using %dk, total %dk\n", + vesafb_fix.smem_start, info->screen_base, + size_remap/1024, size_total/1024); + printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n", + vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages); + + if (screen_info.vesapm_seg) { + printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n", + screen_info.vesapm_seg,screen_info.vesapm_off); + } + + if (screen_info.vesapm_seg < 0xc000) + ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */ + + if (ypan || pmi_setpal) { + pmi_base = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off); + pmi_start = (void*)((char*)pmi_base + pmi_base[1]); + pmi_pal = (void*)((char*)pmi_base + pmi_base[2]); + printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal); + if (pmi_base[3]) { + printk(KERN_INFO "vesafb: pmi: ports = "); + for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++) + printk("%x ",pmi_base[i]); + printk("\n"); + if (pmi_base[i] != 0xffff) { + /* + * memory areas not supported (yet?) + * + * Rules are: we have to set up a descriptor for the requested + * memory area and pass it in the ES register to the BIOS function. + */ + printk(KERN_INFO "vesafb: can't handle memory requests, pmi disabled\n"); + ypan = pmi_setpal = 0; + } + } + } + + vesafb_defined.xres_virtual = vesafb_defined.xres; + vesafb_defined.yres_virtual = vesafb_fix.smem_len / vesafb_fix.line_length; + if (ypan && vesafb_defined.yres_virtual > vesafb_defined.yres) { + printk(KERN_INFO "vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n", + (ypan > 1) ? "ywrap" : "ypan",vesafb_defined.yres_virtual); + } else { + printk(KERN_INFO "vesafb: scrolling: redraw\n"); + vesafb_defined.yres_virtual = vesafb_defined.yres; + ypan = 0; + } + + /* some dummy values for timing to make fbset happy */ + vesafb_defined.pixclock = 10000000 / vesafb_defined.xres * 1000 / vesafb_defined.yres; + vesafb_defined.left_margin = (vesafb_defined.xres / 8) & 0xf8; + vesafb_defined.hsync_len = (vesafb_defined.xres / 8) & 0xf8; + + vesafb_defined.red.offset = screen_info.red_pos; + vesafb_defined.red.length = screen_info.red_size; + vesafb_defined.green.offset = screen_info.green_pos; + vesafb_defined.green.length = screen_info.green_size; + vesafb_defined.blue.offset = screen_info.blue_pos; + vesafb_defined.blue.length = screen_info.blue_size; + vesafb_defined.transp.offset = screen_info.rsvd_pos; + vesafb_defined.transp.length = screen_info.rsvd_size; + + if (vesafb_defined.bits_per_pixel <= 8) { + depth = vesafb_defined.green.length; + vesafb_defined.red.length = + vesafb_defined.green.length = + vesafb_defined.blue.length = + vesafb_defined.bits_per_pixel; + } + + printk(KERN_INFO "vesafb: %s: " + "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", + (vesafb_defined.bits_per_pixel > 8) ? + "Truecolor" : "Pseudocolor", + screen_info.rsvd_size, + screen_info.red_size, + screen_info.green_size, + screen_info.blue_size, + screen_info.rsvd_pos, + screen_info.red_pos, + screen_info.green_pos, + screen_info.blue_pos); + + vesafb_fix.ypanstep = ypan ? 1 : 0; + vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0; + + /* request failure does not faze us, as vgacon probably has this + * region already (FIXME) */ + request_region(0x3c0, 32, "vesafb"); + + if (mtrr) { + int temp_size = size_total; + /* Find the largest power-of-two */ + while (temp_size & (temp_size - 1)) + temp_size &= (temp_size - 1); + + /* Try and find a power of two to add */ + while (temp_size && mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) { + temp_size >>= 1; + } + } + + info->fbops = &vesafb_ops; + info->var = vesafb_defined; + info->fix = vesafb_fix; + info->flags = FBINFO_FLAG_DEFAULT | + (ypan) ? FBINFO_HWACCEL_YPAN : 0; + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + err = -ENOMEM; + goto err; + } + if (register_framebuffer(info)<0) { + err = -EINVAL; + fb_dealloc_cmap(&info->cmap); + goto err; + } + printk(KERN_INFO "fb%d: %s frame buffer device\n", + info->node, info->fix.id); + return 0; +err: + framebuffer_release(info); + release_mem_region(vesafb_fix.smem_start, size_total); + return err; +} + +static struct device_driver vesafb_driver = { + .name = "vesafb", + .bus = &platform_bus_type, + .probe = vesafb_probe, +}; + +static struct platform_device vesafb_device = { + .name = "vesafb", +}; + +static int __init vesafb_init(void) +{ + int ret; + char *option = NULL; + + /* ignore error return of fb_get_options */ + fb_get_options("vesafb", &option); + vesafb_setup(option); + ret = driver_register(&vesafb_driver); + + if (!ret) { + ret = platform_device_register(&vesafb_device); + if (ret) + driver_unregister(&vesafb_driver); + } + return ret; +} +module_init(vesafb_init); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c new file mode 100644 index 000000000000..b137a3fe0752 --- /dev/null +++ b/drivers/video/vfb.c @@ -0,0 +1,528 @@ +/* + * linux/drivers/video/vfb.c -- Virtual frame buffer device + * + * Copyright (C) 2002 James Simmons + * + * Copyright (C) 1997 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. + */ + +#include <linux/module.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/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <asm/uaccess.h> +#include <linux/fb.h> +#include <linux/init.h> + + /* + * RAM we reserve for the frame buffer. This defines the maximum screen + * size + * + * The default can be overridden if the driver is compiled as a module + */ + +#define VIDEOMEMSIZE (1*1024*1024) /* 1 MB */ + +static void *videomemory; +static u_long videomemorysize = VIDEOMEMSIZE; +module_param(videomemorysize, ulong, 0); + +static struct fb_var_screeninfo vfb_default __initdata = { + .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 }, + .activate = FB_ACTIVATE_TEST, + .height = -1, + .width = -1, + .pixclock = 20000, + .left_margin = 64, + .right_margin = 64, + .upper_margin = 32, + .lower_margin = 32, + .hsync_len = 64, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo vfb_fix __initdata = { + .id = "Virtual FB", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .xpanstep = 1, + .ypanstep = 1, + .ywrapstep = 1, + .accel = FB_ACCEL_NONE, +}; + +static int vfb_enable __initdata = 0; /* disabled by default */ +module_param(vfb_enable, bool, 0); + +static int vfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int vfb_set_par(struct fb_info *info); +static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int vfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +static int vfb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma); + +static struct fb_ops vfb_ops = { + .fb_check_var = vfb_check_var, + .fb_set_par = vfb_set_par, + .fb_setcolreg = vfb_setcolreg, + .fb_pan_display = vfb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + .fb_mmap = vfb_mmap, +}; + + /* + * Internal routines + */ + +static u_long get_line_length(int xres_virtual, int bpp) +{ + u_long length; + + length = xres_virtual * bpp; + length = (length + 31) & ~31; + length >>= 3; + return (length); +} + + /* + * Setting the video mode has been split into two parts. + * First part, xxxfb_check_var, must not write anything + * to hardware, it should only verify and adjust var. + * This means it doesn't alter par but it does use hardware + * data from it to check this var. + */ + +static int vfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + u_long line_length; + + /* + * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! + * as FB_VMODE_SMOOTH_XPAN is only used internally + */ + + if (var->vmode & FB_VMODE_CONUPDATE) { + var->vmode |= FB_VMODE_YWRAP; + var->xoffset = info->var.xoffset; + var->yoffset = info->var.yoffset; + } + + /* + * Some very basic checks + */ + if (!var->xres) + var->xres = 1; + if (!var->yres) + var->yres = 1; + if (var->xres > var->xres_virtual) + var->xres_virtual = var->xres; + if (var->yres > var->yres_virtual) + var->yres_virtual = var->yres; + if (var->bits_per_pixel <= 1) + var->bits_per_pixel = 1; + else if (var->bits_per_pixel <= 8) + var->bits_per_pixel = 8; + else if (var->bits_per_pixel <= 16) + var->bits_per_pixel = 16; + else if (var->bits_per_pixel <= 24) + var->bits_per_pixel = 24; + else if (var->bits_per_pixel <= 32) + var->bits_per_pixel = 32; + else + return -EINVAL; + + if (var->xres_virtual < var->xoffset + var->xres) + var->xres_virtual = var->xoffset + var->xres; + if (var->yres_virtual < var->yoffset + var->yres) + var->yres_virtual = var->yoffset + var->yres; + + /* + * Memory limit + */ + line_length = + get_line_length(var->xres_virtual, var->bits_per_pixel); + if (line_length * var->yres_virtual > videomemorysize) + return -ENOMEM; + + /* + * Now that we checked it we alter var. The reason being is that the video + * mode passed in might not work but slight changes to it might make it + * work. This way we let the user know what is acceptable. + */ + switch (var->bits_per_pixel) { + case 1: + 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: /* RGBA 5551 */ + if (var->transp.length) { + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 10; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + } else { /* RGB 565 */ + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 11; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } + break; + case 24: /* RGB 888 */ + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 32: /* RGBA 8888 */ + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + 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; + + return 0; +} + +/* This routine actually sets the video mode. It's in here where we + * the hardware state info->par and fix which can be affected by the + * change in par. For this driver it doesn't do much. + */ +static int vfb_set_par(struct fb_info *info) +{ + info->fix.line_length = get_line_length(info->var.xres_virtual, + info->var.bits_per_pixel); + return 0; +} + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + if (regno >= 256) /* no. of hw registers */ + return 1; + /* + * Program hardware... do anything you want with transp + */ + + /* grayscale works only partially under directcolor */ + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = + (red * 77 + green * 151 + blue * 28) >> 8; + } + + /* Directcolor: + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * {hardwarespecific} contains width of RAMDAC + * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) + * RAMDAC[X] is programmed to (red, green, blue) + * + * Pseudocolor: + * uses offset = 0 && length = RAMDAC register width. + * var->{color}.offset is 0 + * var->{color}.length contains widht of DAC + * cmap is not used + * RAMDAC[X] is programmed to (red, green, blue) + * Truecolor: + * does not use DAC. Usually 3 are present. + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * cmap is programmed to (red << red.offset) | (green << green.offset) | + * (blue << blue.offset) | (transp << transp.offset) + * RAMDAC does not exist + */ +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + case FB_VISUAL_PSEUDOCOLOR: + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + break; + case FB_VISUAL_DIRECTCOLOR: + red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */ + green = CNVT_TOHW(green, 8); + blue = CNVT_TOHW(blue, 8); + /* hey, there is bug in transp handling... */ + transp = CNVT_TOHW(transp, 8); + break; + } +#undef CNVT_TOHW + /* Truecolor has hardware independent palette */ + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v; + + if (regno >= 16) + return 1; + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + switch (info->var.bits_per_pixel) { + case 8: + break; + case 16: + ((u32 *) (info->pseudo_palette))[regno] = v; + break; + case 24: + case 32: + ((u32 *) (info->pseudo_palette))[regno] = v; + break; + } + return 0; + } + return 0; +} + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int vfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset < 0 + || var->yoffset >= info->var.yres_virtual + || var->xoffset) + return -EINVAL; + } else { + if (var->xoffset + var->xres > info->var.xres_virtual || + var->yoffset + var->yres > info->var.yres_virtual) + return -EINVAL; + } + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; +} + + /* + * Most drivers don't need their own mmap function + */ + +static int vfb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + return -EINVAL; +} + +#ifndef MODULE +static int __init vfb_setup(char *options) +{ + char *this_opt; + + vfb_enable = 1; + + if (!options || !*options) + return 1; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + if (!strncmp(this_opt, "disable", 7)) + vfb_enable = 0; + } + return 1; +} +#endif /* MODULE */ + + /* + * Initialisation + */ + +static void vfb_platform_release(struct device *device) +{ + // This is called when the reference count goes to zero. +} + +static int __init vfb_probe(struct device *device) +{ + struct platform_device *dev = to_platform_device(device); + struct fb_info *info; + int retval = -ENOMEM; + + /* + * For real video cards we use ioremap. + */ + if (!(videomemory = vmalloc(videomemorysize))) + return retval; + + /* + * VFB must clear memory to prevent kernel info + * leakage into userspace + * VGA-based drivers MUST NOT clear memory if + * they want to be able to take over vgacon + */ + memset(videomemory, 0, videomemorysize); + + info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); + if (!info) + goto err; + + info->screen_base = (char __iomem *)videomemory; + info->fbops = &vfb_ops; + + retval = fb_find_mode(&info->var, info, NULL, + NULL, 0, NULL, 8); + + if (!retval || (retval == 4)) + info->var = vfb_default; + info->fix = vfb_fix; + info->pseudo_palette = info->par; + info->par = NULL; + info->flags = FBINFO_FLAG_DEFAULT; + + retval = fb_alloc_cmap(&info->cmap, 256, 0); + if (retval < 0) + goto err1; + + retval = register_framebuffer(info); + if (retval < 0) + goto err2; + dev_set_drvdata(&dev->dev, info); + + printk(KERN_INFO + "fb%d: Virtual frame buffer device, using %ldK of video memory\n", + info->node, videomemorysize >> 10); + return 0; +err2: + fb_dealloc_cmap(&info->cmap); +err1: + framebuffer_release(info); +err: + vfree(videomemory); + return retval; +} + +static int vfb_remove(struct device *device) +{ + struct fb_info *info = dev_get_drvdata(device); + + if (info) { + unregister_framebuffer(info); + vfree(videomemory); + framebuffer_release(info); + } + return 0; +} + +static struct device_driver vfb_driver = { + .name = "vfb", + .bus = &platform_bus_type, + .probe = vfb_probe, + .remove = vfb_remove, +}; + +static struct platform_device vfb_device = { + .name = "vfb", + .id = 0, + .dev = { + .release = vfb_platform_release, + } +}; + +static int __init vfb_init(void) +{ + int ret = 0; + +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("vfb", &option)) + return -ENODEV; + vfb_setup(option); +#endif + + if (!vfb_enable) + return -ENXIO; + + ret = driver_register(&vfb_driver); + + if (!ret) { + ret = platform_device_register(&vfb_device); + if (ret) + driver_unregister(&vfb_driver); + } + return ret; +} + +module_init(vfb_init); + +#ifdef MODULE +static void __exit vfb_exit(void) +{ + platform_device_unregister(&vfb_device); + driver_unregister(&vfb_driver); +} + +module_exit(vfb_exit); + +MODULE_LICENSE("GPL"); +#endif /* MODULE */ diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c new file mode 100644 index 000000000000..b46454c55c91 --- /dev/null +++ b/drivers/video/vga16fb.c @@ -0,0 +1,1444 @@ +/* + * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver + * + * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz> + * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm + * Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * + * 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/kernel.h> +#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/ioport.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <video/vga.h> + +#define GRAPHICS_ADDR_REG VGA_GFX_I /* Graphics address register. */ +#define GRAPHICS_DATA_REG VGA_GFX_D /* Graphics data register. */ + +#define SET_RESET_INDEX VGA_GFX_SR_VALUE /* Set/Reset Register index. */ +#define ENABLE_SET_RESET_INDEX VGA_GFX_SR_ENABLE /* Enable Set/Reset Register index. */ +#define DATA_ROTATE_INDEX VGA_GFX_DATA_ROTATE /* Data Rotate Register index. */ +#define GRAPHICS_MODE_INDEX VGA_GFX_MODE /* Graphics Mode Register index. */ +#define BIT_MASK_INDEX VGA_GFX_BIT_MASK /* Bit Mask Register index. */ + +#define dac_reg (VGA_PEL_IW) +#define dac_val (VGA_PEL_D) + +#define VGA_FB_PHYS 0xA0000 +#define VGA_FB_PHYS_LEN 65536 + +#define MODE_SKIP4 1 +#define MODE_8BPP 2 +#define MODE_CFB 4 +#define MODE_TEXT 8 + +/* --------------------------------------------------------------------- */ + +/* + * card parameters + */ + +static struct fb_info vga16fb; + +static struct vga16fb_par { + /* structure holding original VGA register settings when the + screen is blanked */ + struct { + unsigned char SeqCtrlIndex; /* Sequencer Index reg. */ + unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */ + unsigned char CrtMiscIO; /* Miscellaneous register */ + unsigned char HorizontalTotal; /* CRT-Controller:00h */ + unsigned char HorizDisplayEnd; /* CRT-Controller:01h */ + unsigned char StartHorizRetrace; /* CRT-Controller:04h */ + unsigned char EndHorizRetrace; /* CRT-Controller:05h */ + unsigned char Overflow; /* CRT-Controller:07h */ + unsigned char StartVertRetrace; /* CRT-Controller:10h */ + unsigned char EndVertRetrace; /* CRT-Controller:11h */ + unsigned char ModeControl; /* CRT-Controller:17h */ + unsigned char ClockingMode; /* Seq-Controller:01h */ + } vga_state; + struct vgastate state; + atomic_t ref_count; + int palette_blanked, vesa_blanked, mode, isVGA; + u8 misc, pel_msk, vss, clkdiv; + u8 crtc[VGA_CRT_C]; +} vga16_par; + +/* --------------------------------------------------------------------- */ + +static struct fb_var_screeninfo vga16fb_defined = { + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 480, + .bits_per_pixel = 4, + .activate = FB_ACTIVATE_TEST, + .height = -1, + .width = -1, + .pixclock = 39721, + .left_margin = 48, + .right_margin = 16, + .upper_margin = 33, + .lower_margin = 10, + .hsync_len = 96, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED, +}; + +/* name should not depend on EGA/VGA */ +static struct fb_fix_screeninfo vga16fb_fix __initdata = { + .id = "VGA16 VGA", + .smem_start = VGA_FB_PHYS, + .smem_len = VGA_FB_PHYS_LEN, + .type = FB_TYPE_VGA_PLANES, + .type_aux = FB_AUX_VGA_PLANES_VGA4, + .visual = FB_VISUAL_PSEUDOCOLOR, + .xpanstep = 8, + .ypanstep = 1, + .line_length = 640/8, + .accel = FB_ACCEL_NONE +}; + +/* The VGA's weird architecture often requires that we read a byte and + write a byte to the same location. It doesn't matter *what* byte + we write, however. This is because all the action goes on behind + the scenes in the VGA's 32-bit latch register, and reading and writing + video memory just invokes latch behavior. + + To avoid race conditions (is this necessary?), reading and writing + the memory byte should be done with a single instruction. One + suitable instruction is the x86 bitwise OR. The following + read-modify-write routine should optimize to one such bitwise + OR. */ +static inline void rmw(volatile char __iomem *p) +{ + readb(p); + writeb(1, p); +} + +/* Set the Graphics Mode Register, and return its previous value. + Bits 0-1 are write mode, bit 3 is read mode. */ +static inline int setmode(int mode) +{ + int oldmode; + + vga_io_w(GRAPHICS_ADDR_REG, GRAPHICS_MODE_INDEX); + oldmode = vga_io_r(GRAPHICS_DATA_REG); + vga_io_w(GRAPHICS_DATA_REG, mode); + return oldmode; +} + +/* Select the Bit Mask Register and return its value. */ +static inline int selectmask(void) +{ + return vga_io_rgfx(BIT_MASK_INDEX); +} + +/* Set the value of the Bit Mask Register. It must already have been + selected with selectmask(). */ +static inline void setmask(int mask) +{ + vga_io_w(GRAPHICS_DATA_REG, mask); +} + +/* Set the Data Rotate Register and return its old value. + Bits 0-2 are rotate count, bits 3-4 are logical operation + (0=NOP, 1=AND, 2=OR, 3=XOR). */ +static inline int setop(int op) +{ + int oldop; + + vga_io_w(GRAPHICS_ADDR_REG, DATA_ROTATE_INDEX); + oldop = vga_io_r(GRAPHICS_DATA_REG); + vga_io_w(GRAPHICS_DATA_REG, op); + return oldop; +} + +/* Set the Enable Set/Reset Register and return its old value. + The code here always uses value 0xf for thsi register. */ +static inline int setsr(int sr) +{ + int oldsr; + + vga_io_w(GRAPHICS_ADDR_REG, ENABLE_SET_RESET_INDEX); + oldsr = vga_io_r(GRAPHICS_DATA_REG); + vga_io_w(GRAPHICS_DATA_REG, sr); + return oldsr; +} + +/* Set the Set/Reset Register and return its old value. */ +static inline int setcolor(int color) +{ + int oldcolor; + + vga_io_w(GRAPHICS_ADDR_REG, SET_RESET_INDEX); + oldcolor = vga_io_r(GRAPHICS_DATA_REG); + vga_io_w(GRAPHICS_DATA_REG, color); + return oldcolor; +} + +/* Return the value in the Graphics Address Register. */ +static inline int getindex(void) +{ + return vga_io_r(GRAPHICS_ADDR_REG); +} + +/* Set the value in the Graphics Address Register. */ +static inline void setindex(int index) +{ + vga_io_w(GRAPHICS_ADDR_REG, index); +} + +static void vga16fb_pan_var(struct fb_info *info, + struct fb_var_screeninfo *var) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + u32 xoffset, pos; + + xoffset = var->xoffset; + if (info->var.bits_per_pixel == 8) { + pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2; + } else if (par->mode & MODE_TEXT) { + int fh = 16; // FIXME !!! font height. Fugde for now. + pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3; + } else { + if (info->var.nonstd) + xoffset--; + pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3; + } + vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8); + vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF); + /* if we support CFB4, then we must! support xoffset with pixel + * granularity if someone supports xoffset in bit resolution */ + vga_io_r(VGA_IS1_RC); /* reset flip-flop */ + vga_io_w(VGA_ATT_IW, VGA_ATC_PEL); + if (var->bits_per_pixel == 8) + vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1); + else + vga_io_w(VGA_ATT_IW, xoffset & 7); + vga_io_r(VGA_IS1_RC); + vga_io_w(VGA_ATT_IW, 0x20); +} + +static void vga16fb_update_fix(struct fb_info *info) +{ + if (info->var.bits_per_pixel == 4) { + if (info->var.nonstd) { + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.line_length = info->var.xres_virtual / 2; + } else { + info->fix.type = FB_TYPE_VGA_PLANES; + info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4; + info->fix.line_length = info->var.xres_virtual / 8; + } + } else if (info->var.bits_per_pixel == 0) { + info->fix.type = FB_TYPE_TEXT; + info->fix.type_aux = FB_AUX_TEXT_CGA; + info->fix.line_length = info->var.xres_virtual / 4; + } else { /* 8bpp */ + if (info->var.nonstd) { + info->fix.type = FB_TYPE_VGA_PLANES; + info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8; + info->fix.line_length = info->var.xres_virtual / 4; + } else { + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.line_length = info->var.xres_virtual; + } + } +} + +static void vga16fb_clock_chip(struct vga16fb_par *par, + unsigned int pixclock, + const struct fb_info *info, + int mul, int div) +{ + static struct { + u32 pixclock; + u8 misc; + u8 seq_clock_mode; + } *ptr, *best, vgaclocks[] = { + { 79442 /* 12.587 */, 0x00, 0x08}, + { 70616 /* 14.161 */, 0x04, 0x08}, + { 39721 /* 25.175 */, 0x00, 0x00}, + { 35308 /* 28.322 */, 0x04, 0x00}, + { 0 /* bad */, 0x00, 0x00}}; + int err; + + pixclock = (pixclock * mul) / div; + best = vgaclocks; + err = pixclock - best->pixclock; + if (err < 0) err = -err; + for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) { + int tmp; + + tmp = pixclock - ptr->pixclock; + if (tmp < 0) tmp = -tmp; + if (tmp < err) { + err = tmp; + best = ptr; + } + } + par->misc |= best->misc; + par->clkdiv = best->seq_clock_mode; + pixclock = (best->pixclock * div) / mul; +} + +#define FAIL(X) return -EINVAL + +static int vga16fb_open(struct fb_info *info, int user) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + int cnt = atomic_read(&par->ref_count); + + if (!cnt) { + memset(&par->state, 0, sizeof(struct vgastate)); + par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE | + VGA_SAVE_CMAP; + save_vga(&par->state); + } + atomic_inc(&par->ref_count); + return 0; +} + +static int vga16fb_release(struct fb_info *info, int user) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + int cnt = atomic_read(&par->ref_count); + + if (!cnt) + return -EINVAL; + if (cnt == 1) + restore_vga(&par->state); + atomic_dec(&par->ref_count); + + return 0; +} + +static int vga16fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + u32 xres, right, hslen, left, xtotal; + u32 yres, lower, vslen, upper, ytotal; + u32 vxres, xoffset, vyres, yoffset; + u32 pos; + u8 r7, rMode; + int shift; + int mode; + u32 maxmem; + + par->pel_msk = 0xFF; + + if (var->bits_per_pixel == 4) { + if (var->nonstd) { + if (!par->isVGA) + return -EINVAL; + shift = 3; + mode = MODE_SKIP4 | MODE_CFB; + maxmem = 16384; + par->pel_msk = 0x0F; + } else { + shift = 3; + mode = 0; + maxmem = 65536; + } + } else if (var->bits_per_pixel == 8) { + if (!par->isVGA) + return -EINVAL; /* no support on EGA */ + shift = 2; + if (var->nonstd) { + mode = MODE_8BPP | MODE_CFB; + maxmem = 65536; + } else { + mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB; + maxmem = 16384; + } + } else + return -EINVAL; + + xres = (var->xres + 7) & ~7; + vxres = (var->xres_virtual + 0xF) & ~0xF; + xoffset = (var->xoffset + 7) & ~7; + left = (var->left_margin + 7) & ~7; + right = (var->right_margin + 7) & ~7; + hslen = (var->hsync_len + 7) & ~7; + + if (vxres < xres) + vxres = xres; + if (xres + xoffset > vxres) + xoffset = vxres - xres; + + var->xres = xres; + var->right_margin = right; + var->hsync_len = hslen; + var->left_margin = left; + var->xres_virtual = vxres; + var->xoffset = xoffset; + + xres >>= shift; + right >>= shift; + hslen >>= shift; + left >>= shift; + vxres >>= shift; + xtotal = xres + right + hslen + left; + if (xtotal >= 256) + FAIL("xtotal too big"); + if (hslen > 32) + FAIL("hslen too big"); + if (right + hslen + left > 64) + FAIL("hblank too big"); + par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5; + par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1; + par->crtc[VGA_CRTC_H_DISP] = xres - 1; + pos = xres + right; + par->crtc[VGA_CRTC_H_SYNC_START] = pos; + pos += hslen; + par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F; + pos += left - 2; /* blank_end + 2 <= total + 5 */ + par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80; + if (pos & 0x20) + par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80; + + yres = var->yres; + lower = var->lower_margin; + vslen = var->vsync_len; + upper = var->upper_margin; + vyres = var->yres_virtual; + yoffset = var->yoffset; + + if (yres > vyres) + vyres = yres; + if (vxres * vyres > maxmem) { + vyres = maxmem / vxres; + if (vyres < yres) + return -ENOMEM; + } + if (yoffset + yres > vyres) + yoffset = vyres - yres; + var->yres = yres; + var->lower_margin = lower; + var->vsync_len = vslen; + var->upper_margin = upper; + var->yres_virtual = vyres; + var->yoffset = yoffset; + + if (var->vmode & FB_VMODE_DOUBLE) { + yres <<= 1; + lower <<= 1; + vslen <<= 1; + upper <<= 1; + } + ytotal = yres + lower + vslen + upper; + if (ytotal > 1024) { + ytotal >>= 1; + yres >>= 1; + lower >>= 1; + vslen >>= 1; + upper >>= 1; + rMode = 0x04; + } else + rMode = 0x00; + if (ytotal > 1024) + FAIL("ytotal too big"); + if (vslen > 16) + FAIL("vslen too big"); + par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2; + r7 = 0x10; /* disable linecompare */ + if (ytotal & 0x100) r7 |= 0x01; + if (ytotal & 0x200) r7 |= 0x20; + par->crtc[VGA_CRTC_PRESET_ROW] = 0; + par->crtc[VGA_CRTC_MAX_SCAN] = 0x40; /* 1 scanline, no linecmp */ + if (var->vmode & FB_VMODE_DOUBLE) + par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80; + par->crtc[VGA_CRTC_CURSOR_START] = 0x20; + par->crtc[VGA_CRTC_CURSOR_END] = 0x00; + if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB) + xoffset--; + pos = yoffset * vxres + (xoffset >> shift); + par->crtc[VGA_CRTC_START_HI] = pos >> 8; + par->crtc[VGA_CRTC_START_LO] = pos & 0xFF; + par->crtc[VGA_CRTC_CURSOR_HI] = 0x00; + par->crtc[VGA_CRTC_CURSOR_LO] = 0x00; + pos = yres - 1; + par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF; + par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF; + if (pos & 0x100) + r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */ + if (pos & 0x200) { + r7 |= 0x40; /* 0x40 -> DISP_END */ + par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */ + } + pos += lower; + par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF; + if (pos & 0x100) + r7 |= 0x04; + if (pos & 0x200) + r7 |= 0x80; + pos += vslen; + par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */ + pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */ + par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA, + but some SVGA chips requires all 8 bits to set */ + if (vxres >= 512) + FAIL("vxres too long"); + par->crtc[VGA_CRTC_OFFSET] = vxres >> 1; + if (mode & MODE_SKIP4) + par->crtc[VGA_CRTC_UNDERLINE] = 0x5F; /* 256, cfb8 */ + else + par->crtc[VGA_CRTC_UNDERLINE] = 0x1F; /* 16, vgap */ + par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3); + par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF; + par->crtc[VGA_CRTC_OVERFLOW] = r7; + + par->vss = 0x00; /* 3DA */ + + par->misc = 0xE3; /* enable CPU, ports 0x3Dx, positive sync */ + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + par->misc &= ~0x40; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + par->misc &= ~0x80; + + par->mode = mode; + + if (mode & MODE_8BPP) + /* pixel clock == vga clock / 2 */ + vga16fb_clock_chip(par, var->pixclock, info, 1, 2); + else + /* pixel clock == vga clock */ + vga16fb_clock_chip(par, var->pixclock, info, 1, 1); + + var->red.offset = var->green.offset = var->blue.offset = + var->transp.offset = 0; + var->red.length = var->green.length = var->blue.length = + (par->isVGA) ? 6 : 2; + var->transp.length = 0; + var->activate = FB_ACTIVATE_NOW; + var->height = -1; + var->width = -1; + var->accel_flags = 0; + return 0; +} +#undef FAIL + +static int vga16fb_set_par(struct fb_info *info) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + u8 gdc[VGA_GFX_C]; + u8 seq[VGA_SEQ_C]; + u8 atc[VGA_ATT_C]; + int fh, i; + + seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv; + if (par->mode & MODE_TEXT) + seq[VGA_SEQ_PLANE_WRITE] = 0x03; + else + seq[VGA_SEQ_PLANE_WRITE] = 0x0F; + seq[VGA_SEQ_CHARACTER_MAP] = 0x00; + if (par->mode & MODE_TEXT) + seq[VGA_SEQ_MEMORY_MODE] = 0x03; + else if (par->mode & MODE_SKIP4) + seq[VGA_SEQ_MEMORY_MODE] = 0x0E; + else + seq[VGA_SEQ_MEMORY_MODE] = 0x06; + + gdc[VGA_GFX_SR_VALUE] = 0x00; + gdc[VGA_GFX_SR_ENABLE] = 0x00; + gdc[VGA_GFX_COMPARE_VALUE] = 0x00; + gdc[VGA_GFX_DATA_ROTATE] = 0x00; + gdc[VGA_GFX_PLANE_READ] = 0; + if (par->mode & MODE_TEXT) { + gdc[VGA_GFX_MODE] = 0x10; + gdc[VGA_GFX_MISC] = 0x06; + } else { + if (par->mode & MODE_CFB) + gdc[VGA_GFX_MODE] = 0x40; + else + gdc[VGA_GFX_MODE] = 0x00; + gdc[VGA_GFX_MISC] = 0x05; + } + gdc[VGA_GFX_COMPARE_MASK] = 0x0F; + gdc[VGA_GFX_BIT_MASK] = 0xFF; + + for (i = 0x00; i < 0x10; i++) + atc[i] = i; + if (par->mode & MODE_TEXT) + atc[VGA_ATC_MODE] = 0x04; + else if (par->mode & MODE_8BPP) + atc[VGA_ATC_MODE] = 0x41; + else + atc[VGA_ATC_MODE] = 0x81; + atc[VGA_ATC_OVERSCAN] = 0x00; /* 0 for EGA, 0xFF for VGA */ + atc[VGA_ATC_PLANE_ENABLE] = 0x0F; + if (par->mode & MODE_8BPP) + atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1; + else + atc[VGA_ATC_PEL] = info->var.xoffset & 7; + atc[VGA_ATC_COLOR_PAGE] = 0x00; + + if (par->mode & MODE_TEXT) { + fh = 16; // FIXME !!! Fudge font height. + par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN] + & ~0x1F) | (fh - 1); + } + + vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01); + + /* Enable graphics register modification */ + if (!par->isVGA) { + vga_io_w(EGA_GFX_E0, 0x00); + vga_io_w(EGA_GFX_E1, 0x01); + } + + /* update misc output register */ + vga_io_w(VGA_MIS_W, par->misc); + + /* synchronous reset on */ + vga_io_wseq(0x00, 0x01); + + if (par->isVGA) + vga_io_w(VGA_PEL_MSK, par->pel_msk); + + /* write sequencer registers */ + vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20); + for (i = 2; i < VGA_SEQ_C; i++) { + vga_io_wseq(i, seq[i]); + } + + /* synchronous reset off */ + vga_io_wseq(0x00, 0x03); + + /* deprotect CRT registers 0-7 */ + vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]); + + /* write CRT registers */ + for (i = 0; i < VGA_CRTC_REGS; i++) { + vga_io_wcrt(i, par->crtc[i]); + } + + /* write graphics controller registers */ + for (i = 0; i < VGA_GFX_C; i++) { + vga_io_wgfx(i, gdc[i]); + } + + /* write attribute controller registers */ + for (i = 0; i < VGA_ATT_C; i++) { + vga_io_r(VGA_IS1_RC); /* reset flip-flop */ + vga_io_wattr(i, atc[i]); + } + + /* Wait for screen to stabilize. */ + mdelay(50); + + vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]); + + vga_io_r(VGA_IS1_RC); + vga_io_w(VGA_ATT_IW, 0x20); + + vga16fb_update_fix(info); + return 0; +} + +static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue) +{ + static unsigned char map[] = { 000, 001, 010, 011 }; + int val; + + if (regno >= 16) + return; + val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2); + vga_io_r(VGA_IS1_RC); /* ! 0x3BA */ + vga_io_wattr(regno, val); + vga_io_r(VGA_IS1_RC); /* some clones need it */ + vga_io_w(VGA_ATT_IW, 0x20); /* unblank screen */ +} + +static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue) +{ + outb(regno, dac_reg); + outb(red >> 10, dac_val); + outb(green >> 10, dac_val); + outb(blue >> 10, dac_val); +} + +static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + int gray; + + /* + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return + * != 0 for invalid regno. + */ + + if (regno >= 256) + return 1; + + gray = info->var.grayscale; + + if (gray) { + /* gray = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + if (par->isVGA) + vga16_setpalette(regno,red,green,blue); + else + ega16_setpalette(regno,red,green,blue); + return 0; +} + +static int vga16fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if (var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + + vga16fb_pan_var(info, var); + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; +} + +/* The following VESA blanking code is taken from vgacon.c. The VGA + blanking code was originally by Huang shi chao, and modified by + Christoph Rimek (chrimek@toppoint.de) and todd j. derr + (tjd@barefoot.org) for Linux. */ +#define attrib_port VGA_ATC_IW +#define seq_port_reg VGA_SEQ_I +#define seq_port_val VGA_SEQ_D +#define gr_port_reg VGA_GFX_I +#define gr_port_val VGA_GFX_D +#define video_misc_rd VGA_MIS_R +#define video_misc_wr VGA_MIS_W +#define vga_video_port_reg VGA_CRT_IC +#define vga_video_port_val VGA_CRT_DC + +static void vga_vesa_blank(struct vga16fb_par *par, int mode) +{ + unsigned char SeqCtrlIndex; + unsigned char CrtCtrlIndex; + + //cli(); + SeqCtrlIndex = vga_io_r(seq_port_reg); + CrtCtrlIndex = vga_io_r(vga_video_port_reg); + + /* save original values of VGA controller registers */ + if(!par->vesa_blanked) { + par->vga_state.CrtMiscIO = vga_io_r(video_misc_rd); + //sti(); + + par->vga_state.HorizontalTotal = vga_io_rcrt(0x00); /* HorizontalTotal */ + par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01); /* HorizDisplayEnd */ + par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04); /* StartHorizRetrace */ + par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05); /* EndHorizRetrace */ + par->vga_state.Overflow = vga_io_rcrt(0x07); /* Overflow */ + par->vga_state.StartVertRetrace = vga_io_rcrt(0x10); /* StartVertRetrace */ + par->vga_state.EndVertRetrace = vga_io_rcrt(0x11); /* EndVertRetrace */ + par->vga_state.ModeControl = vga_io_rcrt(0x17); /* ModeControl */ + par->vga_state.ClockingMode = vga_io_rseq(0x01); /* ClockingMode */ + } + + /* assure that video is enabled */ + /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */ + //cli(); + vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20); + + /* test for vertical retrace in process.... */ + if ((par->vga_state.CrtMiscIO & 0x80) == 0x80) + vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO & 0xef); + + /* + * Set <End of vertical retrace> to minimum (0) and + * <Start of vertical Retrace> to maximum (incl. overflow) + * Result: turn off vertical sync (VSync) pulse. + */ + if (mode & FB_BLANK_VSYNC_SUSPEND) { + outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */ + outb_p(0xff,vga_video_port_val); /* maximum value */ + outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */ + outb_p(0x40,vga_video_port_val); /* minimum (bits 0..3) */ + outb_p(0x07,vga_video_port_reg); /* Overflow */ + outb_p(par->vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */ + } + + if (mode & FB_BLANK_HSYNC_SUSPEND) { + /* + * Set <End of horizontal retrace> to minimum (0) and + * <Start of horizontal Retrace> to maximum + * Result: turn off horizontal sync (HSync) pulse. + */ + outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */ + outb_p(0xff,vga_video_port_val); /* maximum */ + outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */ + outb_p(0x00,vga_video_port_val); /* minimum (0) */ + } + + /* restore both index registers */ + outb_p(SeqCtrlIndex,seq_port_reg); + outb_p(CrtCtrlIndex,vga_video_port_reg); + //sti(); +} + +static void vga_vesa_unblank(struct vga16fb_par *par) +{ + unsigned char SeqCtrlIndex; + unsigned char CrtCtrlIndex; + + //cli(); + SeqCtrlIndex = vga_io_r(seq_port_reg); + CrtCtrlIndex = vga_io_r(vga_video_port_reg); + + /* restore original values of VGA controller registers */ + vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO); + + /* HorizontalTotal */ + vga_io_wcrt(0x00, par->vga_state.HorizontalTotal); + /* HorizDisplayEnd */ + vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd); + /* StartHorizRetrace */ + vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace); + /* EndHorizRetrace */ + vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace); + /* Overflow */ + vga_io_wcrt(0x07, par->vga_state.Overflow); + /* StartVertRetrace */ + vga_io_wcrt(0x10, par->vga_state.StartVertRetrace); + /* EndVertRetrace */ + vga_io_wcrt(0x11, par->vga_state.EndVertRetrace); + /* ModeControl */ + vga_io_wcrt(0x17, par->vga_state.ModeControl); + /* ClockingMode */ + vga_io_wseq(0x01, par->vga_state.ClockingMode); + + /* restore index/control registers */ + vga_io_w(seq_port_reg, SeqCtrlIndex); + vga_io_w(vga_video_port_reg, CrtCtrlIndex); + //sti(); +} + +static void vga_pal_blank(void) +{ + int i; + + for (i=0; i<16; i++) { + outb_p (i, dac_reg) ; + outb_p (0, dac_val) ; + outb_p (0, dac_val) ; + outb_p (0, dac_val) ; + } +} + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ +static int vga16fb_blank(int blank, struct fb_info *info) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + + switch (blank) { + case FB_BLANK_UNBLANK: /* Unblank */ + if (par->vesa_blanked) { + vga_vesa_unblank(par); + par->vesa_blanked = 0; + } + if (par->palette_blanked) { + par->palette_blanked = 0; + } + break; + case FB_BLANK_NORMAL: /* blank */ + vga_pal_blank(); + par->palette_blanked = 1; + break; + default: /* VESA blanking */ + vga_vesa_blank(par, blank); + par->vesa_blanked = 1; + break; + } + return 0; +} + +static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + u32 dx = rect->dx, width = rect->width; + char oldindex = getindex(); + char oldmode = setmode(0x40); + char oldmask = selectmask(); + int line_ofs, height; + char oldop, oldsr; + char __iomem *where; + + dx /= 4; + where = info->screen_base + dx + rect->dy * info->fix.line_length; + + if (rect->rop == ROP_COPY) { + oldop = setop(0); + oldsr = setsr(0); + + width /= 4; + line_ofs = info->fix.line_length - width; + setmask(0xff); + + height = rect->height; + + while (height--) { + int x; + + /* we can do memset... */ + for (x = width; x > 0; --x) { + writeb(rect->color, where); + where++; + } + where += line_ofs; + } + } else { + char oldcolor = setcolor(0xf); + int y; + + oldop = setop(0x18); + oldsr = setsr(0xf); + setmask(0x0F); + for (y = 0; y < rect->height; y++) { + rmw(where); + rmw(where+1); + where += info->fix.line_length; + } + setcolor(oldcolor); + } + setmask(oldmask); + setsr(oldsr); + setop(oldop); + setmode(oldmode); + setindex(oldindex); +} + +static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + int x, x2, y2, vxres, vyres, width, height, line_ofs; + char __iomem *dst; + + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + + if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres) + return; + + /* We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. */ + + x2 = rect->dx + rect->width; + y2 = rect->dy + rect->height; + x2 = x2 < vxres ? x2 : vxres; + y2 = y2 < vyres ? y2 : vyres; + width = x2 - rect->dx; + + switch (info->fix.type) { + case FB_TYPE_VGA_PLANES: + if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) { + + height = y2 - rect->dy; + width = rect->width/8; + + line_ofs = info->fix.line_length - width; + dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length; + + switch (rect->rop) { + case ROP_COPY: + setmode(0); + setop(0); + setsr(0xf); + setcolor(rect->color); + selectmask(); + + setmask(0xff); + + while (height--) { + for (x = 0; x < width; x++) { + writeb(0, dst); + dst++; + } + dst += line_ofs; + } + break; + case ROP_XOR: + setmode(0); + setop(0x18); + setsr(0xf); + setcolor(0xf); + selectmask(); + + setmask(0xff); + while (height--) { + for (x = 0; x < width; x++) { + rmw(dst); + dst++; + } + dst += line_ofs; + } + break; + } + } else + vga_8planes_fillrect(info, rect); + break; + case FB_TYPE_PACKED_PIXELS: + default: + cfb_fillrect(info, rect); + break; + } +} + +static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + char oldindex = getindex(); + char oldmode = setmode(0x41); + char oldop = setop(0); + char oldsr = setsr(0xf); + int height, line_ofs, x; + u32 sx, dx, width; + char __iomem *dest; + char __iomem *src; + + height = area->height; + + sx = area->sx / 4; + dx = area->dx / 4; + width = area->width / 4; + + if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) { + line_ofs = info->fix.line_length - width; + dest = info->screen_base + dx + area->dy * info->fix.line_length; + src = info->screen_base + sx + area->sy * info->fix.line_length; + while (height--) { + for (x = 0; x < width; x++) { + readb(src); + writeb(0, dest); + src++; + dest++; + } + src += line_ofs; + dest += line_ofs; + } + } else { + line_ofs = info->fix.line_length - width; + dest = info->screen_base + dx + width + + (area->dy + height - 1) * info->fix.line_length; + src = info->screen_base + sx + width + + (area->sy + height - 1) * info->fix.line_length; + while (height--) { + for (x = 0; x < width; x++) { + --src; + --dest; + readb(src); + writeb(0, dest); + } + src -= line_ofs; + dest -= line_ofs; + } + } + + setsr(oldsr); + setop(oldop); + setmode(oldmode); + setindex(oldindex); +} + +static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; + int x, x2, y2, old_dx, old_dy, vxres, vyres; + int height, width, line_ofs; + char __iomem *dst = NULL; + char __iomem *src = NULL; + + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + + if (area->dx > vxres || area->sx > vxres || area->dy > vyres || + area->sy > vyres) + return; + + /* clip the destination */ + old_dx = area->dx; + old_dy = area->dy; + + /* + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. + */ + x2 = area->dx + area->width; + y2 = area->dy + area->height; + dx = area->dx > 0 ? area->dx : 0; + dy = area->dy > 0 ? area->dy : 0; + x2 = x2 < vxres ? x2 : vxres; + y2 = y2 < vyres ? y2 : vyres; + width = x2 - dx; + height = y2 - dy; + + /* update sx1,sy1 */ + sx += (dx - old_dx); + sy += (dy - old_dy); + + /* the source must be completely inside the virtual screen */ + if (sx < 0 || sy < 0 || (sx + width) > vxres || (sy + height) > vyres) + return; + + switch (info->fix.type) { + case FB_TYPE_VGA_PLANES: + if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) { + width = width/8; + height = height; + line_ofs = info->fix.line_length - width; + + setmode(1); + setop(0); + setsr(0xf); + + if (dy < sy || (dy == sy && dx < sx)) { + dst = info->screen_base + (dx/8) + dy * info->fix.line_length; + src = info->screen_base + (sx/8) + sy * info->fix.line_length; + while (height--) { + for (x = 0; x < width; x++) { + readb(src); + writeb(0, dst); + dst++; + src++; + } + src += line_ofs; + dst += line_ofs; + } + } else { + dst = info->screen_base + (dx/8) + width + + (dy + height - 1) * info->fix.line_length; + src = info->screen_base + (sx/8) + width + + (sy + height - 1) * info->fix.line_length; + while (height--) { + for (x = 0; x < width; x++) { + dst--; + src--; + readb(src); + writeb(0, dst); + } + src -= line_ofs; + dst -= line_ofs; + } + } + } else + vga_8planes_copyarea(info, area); + break; + case FB_TYPE_PACKED_PIXELS: + default: + cfb_copyarea(info, area); + break; + } +} + +#ifdef __LITTLE_ENDIAN +static unsigned int transl_l[] = +{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}; +static unsigned int transl_h[] = +{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, + 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}; +#else +#ifdef __BIG_ENDIAN +static unsigned int transl_h[] = +{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}; +static unsigned int transl_l[] = +{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, + 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}; +#else +#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes" +#endif +#endif + +static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image) +{ + char oldindex = getindex(); + char oldmode = setmode(0x40); + char oldop = setop(0); + char oldsr = setsr(0); + char oldmask = selectmask(); + const char *cdat = image->data; + u32 dx = image->dx; + char __iomem *where; + int y; + + dx /= 4; + where = info->screen_base + dx + image->dy * info->fix.line_length; + + setmask(0xff); + writeb(image->bg_color, where); + readb(where); + selectmask(); + setmask(image->fg_color ^ image->bg_color); + setmode(0x42); + setop(0x18); + for (y = 0; y < image->height; y++, where += info->fix.line_length) + writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where); + setmask(oldmask); + setsr(oldsr); + setop(oldop); + setmode(oldmode); + setindex(oldindex); +} + +static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image) +{ + char __iomem *where = info->screen_base + (image->dx/8) + + image->dy * info->fix.line_length; + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + char *cdat = (char *) image->data; + char __iomem *dst; + int x, y; + + switch (info->fix.type) { + case FB_TYPE_VGA_PLANES: + if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) { + if (par->isVGA) { + setmode(2); + setop(0); + setsr(0xf); + setcolor(image->fg_color); + selectmask(); + + setmask(0xff); + writeb(image->bg_color, where); + rmb(); + readb(where); /* fill latches */ + setmode(3); + wmb(); + for (y = 0; y < image->height; y++) { + dst = where; + for (x = image->width/8; x--;) + writeb(*cdat++, dst++); + where += info->fix.line_length; + } + wmb(); + } else { + setmode(0); + setop(0); + setsr(0xf); + setcolor(image->bg_color); + selectmask(); + + setmask(0xff); + for (y = 0; y < image->height; y++) { + dst = where; + for (x=image->width/8; x--;){ + rmw(dst); + setcolor(image->fg_color); + selectmask(); + if (*cdat) { + setmask(*cdat++); + rmw(dst++); + } + } + where += info->fix.line_length; + } + } + } else + vga_8planes_imageblit(info, image); + break; + case FB_TYPE_PACKED_PIXELS: + default: + cfb_imageblit(info, image); + break; + } +} + +static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image) +{ + /* + * Draw logo + */ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + char __iomem *where = + info->screen_base + image->dy * info->fix.line_length + + image->dx/8; + const char *cdat = image->data; + char __iomem *dst; + int x, y; + + switch (info->fix.type) { + case FB_TYPE_VGA_PLANES: + if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 && + par->isVGA) { + setsr(0xf); + setop(0); + setmode(0); + + for (y = 0; y < image->height; y++) { + for (x = 0; x < image->width; x++) { + dst = where + x/8; + + setcolor(*cdat); + selectmask(); + setmask(1 << (7 - (x % 8))); + fb_readb(dst); + fb_writeb(0, dst); + + cdat++; + } + where += info->fix.line_length; + } + } + break; + case FB_TYPE_PACKED_PIXELS: + cfb_imageblit(info, image); + break; + default: + break; + } +} + +static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + if (image->depth == 1) + vga_imageblit_expand(info, image); + else + vga_imageblit_color(info, image); +} + +static struct fb_ops vga16fb_ops = { + .owner = THIS_MODULE, + .fb_open = vga16fb_open, + .fb_release = vga16fb_release, + .fb_check_var = vga16fb_check_var, + .fb_set_par = vga16fb_set_par, + .fb_setcolreg = vga16fb_setcolreg, + .fb_pan_display = vga16fb_pan_display, + .fb_blank = vga16fb_blank, + .fb_fillrect = vga16fb_fillrect, + .fb_copyarea = vga16fb_copyarea, + .fb_imageblit = vga16fb_imageblit, + .fb_cursor = soft_cursor, +}; + +#ifndef MODULE +static int vga16fb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) continue; + } + return 0; +} +#endif + +static int __init vga16fb_init(void) +{ + int i; + int ret; +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("vga16fb", &option)) + return -ENODEV; + + vga16fb_setup(option); +#endif + printk(KERN_DEBUG "vga16fb: initializing\n"); + + /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ + + vga16fb.screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS); + if (!vga16fb.screen_base) { + printk(KERN_ERR "vga16fb: unable to map device\n"); + ret = -ENOMEM; + goto err_ioremap; + } + printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.screen_base); + + vga16_par.isVGA = ORIG_VIDEO_ISVGA; + vga16_par.palette_blanked = 0; + vga16_par.vesa_blanked = 0; + + i = vga16_par.isVGA? 6 : 2; + + vga16fb_defined.red.length = i; + vga16fb_defined.green.length = i; + vga16fb_defined.blue.length = i; + + /* name should not depend on EGA/VGA */ + vga16fb.fbops = &vga16fb_ops; + vga16fb.var = vga16fb_defined; + vga16fb.fix = vga16fb_fix; + vga16fb.par = &vga16_par; + vga16fb.flags = FBINFO_FLAG_DEFAULT | + FBINFO_HWACCEL_YPAN; + + i = (vga16fb_defined.bits_per_pixel == 8) ? 256 : 16; + ret = fb_alloc_cmap(&vga16fb.cmap, i, 0); + if (ret) { + printk(KERN_ERR "vga16fb: unable to allocate colormap\n"); + ret = -ENOMEM; + goto err_alloc_cmap; + } + + if (vga16fb_check_var(&vga16fb.var, &vga16fb)) { + printk(KERN_ERR "vga16fb: unable to validate variable\n"); + ret = -EINVAL; + goto err_check_var; + } + + vga16fb_update_fix(&vga16fb); + + if (register_framebuffer(&vga16fb) < 0) { + printk(KERN_ERR "vga16fb: unable to register framebuffer\n"); + ret = -EINVAL; + goto err_check_var; + } + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + vga16fb.node, vga16fb.fix.id); + + return 0; + + err_check_var: + fb_dealloc_cmap(&vga16fb.cmap); + err_alloc_cmap: + iounmap(vga16fb.screen_base); + err_ioremap: + return ret; +} + +static void __exit vga16fb_exit(void) +{ + unregister_framebuffer(&vga16fb); + iounmap(vga16fb.screen_base); + fb_dealloc_cmap(&vga16fb.cmap); + /* XXX unshare VGA regions */ +} + +MODULE_LICENSE("GPL"); +module_init(vga16fb_init); +module_exit(vga16fb_exit); + + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff --git a/drivers/video/vgastate.c b/drivers/video/vgastate.c new file mode 100644 index 000000000000..0ea62d8bc703 --- /dev/null +++ b/drivers/video/vgastate.c @@ -0,0 +1,504 @@ +/* + * linux/drivers/video/vgastate.c -- VGA state save/restore + * + * Copyright 2002 James Simmons + * + * Copyright history from vga16fb.c: + * Copyright 1999 Ben Pfaff and Petr Vandrovec + * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm + * Based on VESA framebuffer (c) 1998 Gerd Knorr + * + * 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/config.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/vmalloc.h> +#include <video/vga.h> + +struct regstate { + __u8 *vga_font0; + __u8 *vga_font1; + __u8 *vga_text; + __u8 *vga_cmap; + __u8 *attr; + __u8 *crtc; + __u8 *gfx; + __u8 *seq; + __u8 misc; +}; + +static inline unsigned char vga_rcrtcs(void __iomem *regbase, unsigned short iobase, + unsigned char reg) +{ + vga_w(regbase, iobase + 0x4, reg); + return vga_r(regbase, iobase + 0x5); +} + +static inline void vga_wcrtcs(void __iomem *regbase, unsigned short iobase, + unsigned char reg, unsigned char val) +{ + vga_w(regbase, iobase + 0x4, reg); + vga_w(regbase, iobase + 0x5, val); +} + +static void save_vga_text(struct vgastate *state, void __iomem *fbbase) +{ + struct regstate *saved = (struct regstate *) state->vidstate; + int i; + u8 misc, attr10, gr4, gr5, gr6, seq1, seq2, seq4; + + /* if in graphics mode, no need to save */ + attr10 = vga_rattr(state->vgabase, 0x10); + if (attr10 & 1) + return; + + /* save regs */ + misc = vga_r(state->vgabase, VGA_MIS_R); + gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ); + gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE); + gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC); + seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE); + seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE); + + /* force graphics mode */ + vga_w(state->vgabase, VGA_MIS_W, misc | 1); + + /* blank screen */ + seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE); + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); + vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 | 1 << 5); + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3); + + /* save font at plane 2 */ + if (state->flags & VGA_SAVE_FONT0) { + vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4); + vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); + vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2); + vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); + vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); + for (i = 0; i < 4 * 8192; i++) + saved->vga_font0[i] = vga_r(fbbase, i); + } + + /* save font at plane 3 */ + if (state->flags & VGA_SAVE_FONT1) { + vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x8); + vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); + 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 < state->memsize; i++) + saved->vga_font1[i] = vga_r(fbbase, i); + } + + /* save font at plane 0/1 */ + if (state->flags & VGA_SAVE_TEXT) { + vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1); + vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); + vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0); + 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, i); + + vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2); + vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); + vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1); + 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[8192+i] = vga_r(fbbase + 2 * 8192, i); + } + + /* restore regs */ + vga_wattr(state->vgabase, 0x10, attr10); + + vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2); + vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4); + + vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4); + vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5); + vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6); + vga_w(state->vgabase, VGA_MIS_W, misc); + + /* unblank screen */ + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); + vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 & ~(1 << 5)); + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3); + + vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1); +} + +static void restore_vga_text(struct vgastate *state, void __iomem *fbbase) +{ + struct regstate *saved = (struct regstate *) state->vidstate; + int i; + u8 misc, gr1, gr3, gr4, gr5, gr6, gr8; + u8 seq1, seq2, seq4; + + /* save regs */ + misc = vga_r(state->vgabase, VGA_MIS_R); + gr1 = vga_rgfx(state->vgabase, VGA_GFX_SR_ENABLE); + gr3 = vga_rgfx(state->vgabase, VGA_GFX_DATA_ROTATE); + gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ); + gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE); + gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC); + gr8 = vga_rgfx(state->vgabase, VGA_GFX_BIT_MASK); + seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE); + seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE); + + /* force graphics mode */ + vga_w(state->vgabase, VGA_MIS_W, misc | 1); + + /* blank screen */ + seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE); + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); + vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 | 1 << 5); + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3); + + if (state->depth == 4) { + vga_wgfx(state->vgabase, VGA_GFX_DATA_ROTATE, 0x0); + vga_wgfx(state->vgabase, VGA_GFX_BIT_MASK, 0xff); + vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, 0x00); + } + + /* restore font at plane 2 */ + if (state->flags & VGA_SAVE_FONT0) { + vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4); + vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); + vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2); + vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); + vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); + for (i = 0; i < 4 * 8192; i++) + vga_w(fbbase, i, saved->vga_font0[i]); + } + + /* restore font at plane 3 */ + if (state->flags & VGA_SAVE_FONT1) { + vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x8); + vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); + 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 < state->memsize; i++) + vga_w(fbbase, i, saved->vga_font1[i]); + } + + /* restore font at plane 0/1 */ + if (state->flags & VGA_SAVE_TEXT) { + vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1); + vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); + vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0); + 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, i, saved->vga_text[i]); + + vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2); + vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); + vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1); + 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, i, saved->vga_text[8192+i]); + } + + /* unblank screen */ + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); + vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 & ~(1 << 5)); + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3); + + /* restore regs */ + vga_w(state->vgabase, VGA_MIS_W, misc); + + vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, gr1); + vga_wgfx(state->vgabase, VGA_GFX_DATA_ROTATE, gr3); + vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4); + vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5); + vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6); + vga_wgfx(state->vgabase, VGA_GFX_BIT_MASK, gr8); + + vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1); + vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2); + vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4); +} + +static void save_vga_mode(struct vgastate *state) +{ + struct regstate *saved = (struct regstate *) state->vidstate; + unsigned short iobase; + int i; + + saved->misc = vga_r(state->vgabase, VGA_MIS_R); + if (saved->misc & 1) + iobase = 0x3d0; + else + iobase = 0x3b0; + + for (i = 0; i < state->num_crtc; i++) + saved->crtc[i] = vga_rcrtcs(state->vgabase, iobase, i); + + vga_r(state->vgabase, iobase + 0xa); + vga_w(state->vgabase, VGA_ATT_W, 0x00); + for (i = 0; i < state->num_attr; i++) { + vga_r(state->vgabase, iobase + 0xa); + saved->attr[i] = vga_rattr(state->vgabase, i); + } + vga_r(state->vgabase, iobase + 0xa); + vga_w(state->vgabase, VGA_ATT_W, 0x20); + + for (i = 0; i < state->num_gfx; i++) + saved->gfx[i] = vga_rgfx(state->vgabase, i); + + for (i = 0; i < state->num_seq; i++) + saved->seq[i] = vga_rseq(state->vgabase, i); +} + +static void restore_vga_mode(struct vgastate *state) +{ + struct regstate *saved = (struct regstate *) state->vidstate; + unsigned short iobase; + int i; + + vga_w(state->vgabase, VGA_MIS_W, saved->misc); + + if (saved->misc & 1) + iobase = 0x3d0; + else + iobase = 0x3b0; + + /* turn off display */ + vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, + saved->seq[VGA_SEQ_CLOCK_MODE] | 0x20); + + /* disable sequencer */ + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01); + + /* enable palette addressing */ + vga_r(state->vgabase, iobase + 0xa); + vga_w(state->vgabase, VGA_ATT_W, 0x00); + + for (i = 2; i < state->num_seq; i++) + vga_wseq(state->vgabase, i, saved->seq[i]); + + + /* unprotect vga regs */ + vga_wcrtcs(state->vgabase, iobase, 17, saved->crtc[17] & ~0x80); + for (i = 0; i < state->num_crtc; i++) + vga_wcrtcs(state->vgabase, iobase, i, saved->crtc[i]); + + for (i = 0; i < state->num_gfx; i++) + vga_wgfx(state->vgabase, i, saved->gfx[i]); + + for (i = 0; i < state->num_attr; i++) { + vga_r(state->vgabase, iobase + 0xa); + vga_wattr(state->vgabase, i, saved->attr[i]); + } + + /* reenable sequencer */ + vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03); + /* turn display on */ + vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, + saved->seq[VGA_SEQ_CLOCK_MODE] & ~(1 << 5)); + + /* disable video/palette source */ + vga_r(state->vgabase, iobase + 0xa); + vga_w(state->vgabase, VGA_ATT_W, 0x20); +} + +static void save_vga_cmap(struct vgastate *state) +{ + struct regstate *saved = (struct regstate *) state->vidstate; + int i; + + vga_w(state->vgabase, VGA_PEL_MSK, 0xff); + + /* assumes DAC is readable and writable */ + vga_w(state->vgabase, VGA_PEL_IR, 0x00); + for (i = 0; i < 768; i++) + saved->vga_cmap[i] = vga_r(state->vgabase, VGA_PEL_D); +} + +static void restore_vga_cmap(struct vgastate *state) +{ + struct regstate *saved = (struct regstate *) state->vidstate; + int i; + + vga_w(state->vgabase, VGA_PEL_MSK, 0xff); + + /* assumes DAC is readable and writable */ + vga_w(state->vgabase, VGA_PEL_IW, 0x00); + for (i = 0; i < 768; i++) + vga_w(state->vgabase, VGA_PEL_D, saved->vga_cmap[i]); +} + +static void vga_cleanup(struct vgastate *state) +{ + if (state->vidstate != NULL) { + struct regstate *saved = (struct regstate *) state->vidstate; + + if (saved->vga_font0) + vfree(saved->vga_font0); + if (saved->vga_font1) + vfree(saved->vga_font1); + if (saved->vga_text) + vfree(saved->vga_text); + if (saved->vga_cmap) + vfree(saved->vga_cmap); + if (saved->attr) + vfree(saved->attr); + kfree(saved); + state->vidstate = NULL; + } +} + +int save_vga(struct vgastate *state) +{ + struct regstate *saved; + + saved = kmalloc(sizeof(struct regstate), GFP_KERNEL); + if (saved == NULL) + return 1; + memset (saved, 0, sizeof(struct regstate)); + state->vidstate = (void *)saved; + + if (state->flags & VGA_SAVE_CMAP) { + saved->vga_cmap = vmalloc(768); + if (!saved->vga_cmap) { + vga_cleanup(state); + return 1; + } + save_vga_cmap(state); + } + + if (state->flags & VGA_SAVE_MODE) { + int total; + + if (state->num_attr < 21) + state->num_attr = 21; + if (state->num_crtc < 25) + state->num_crtc = 25; + if (state->num_gfx < 9) + state->num_gfx = 9; + if (state->num_seq < 5) + state->num_seq = 5; + total = state->num_attr + state->num_crtc + + state->num_gfx + state->num_seq; + + saved->attr = vmalloc(total); + if (!saved->attr) { + vga_cleanup(state); + return 1; + } + saved->crtc = saved->attr + state->num_attr; + saved->gfx = saved->crtc + state->num_crtc; + saved->seq = saved->gfx + state->num_gfx; + + save_vga_mode(state); + } + + if (state->flags & VGA_SAVE_FONTS) { + void __iomem *fbbase; + + /* exit if window is less than 32K */ + if (state->memsize && state->memsize < 4 * 8192) { + vga_cleanup(state); + return 1; + } + if (!state->memsize) + state->memsize = 8 * 8192; + + if (!state->membase) + state->membase = 0xA0000; + + fbbase = ioremap(state->membase, state->memsize); + + if (!fbbase) { + vga_cleanup(state); + return 1; + } + + /* + * save only first 32K used by vgacon + */ + if (state->flags & VGA_SAVE_FONT0) { + saved->vga_font0 = vmalloc(4 * 8192); + if (!saved->vga_font0) { + iounmap(fbbase); + vga_cleanup(state); + return 1; + } + } + /* + * largely unused, but if required by the caller + * we'll just save everything. + */ + if (state->flags & VGA_SAVE_FONT1) { + saved->vga_font1 = vmalloc(state->memsize); + if (!saved->vga_font1) { + iounmap(fbbase); + vga_cleanup(state); + return 1; + } + } + /* + * Save 8K at plane0[0], and 8K at plane1[16K] + */ + if (state->flags & VGA_SAVE_TEXT) { + saved->vga_text = vmalloc(8192 * 2); + if (!saved->vga_text) { + iounmap(fbbase); + vga_cleanup(state); + return 1; + } + } + + save_vga_text(state, fbbase); + iounmap(fbbase); + } + return 0; +} + +int restore_vga (struct vgastate *state) +{ + if (state->vidstate == NULL) + return 1; + + if (state->flags & VGA_SAVE_MODE) + restore_vga_mode(state); + + if (state->flags & VGA_SAVE_FONTS) { + void __iomem *fbbase = ioremap(state->membase, state->memsize); + + if (!fbbase) { + vga_cleanup(state); + return 1; + } + restore_vga_text(state, fbbase); + iounmap(fbbase); + } + + if (state->flags & VGA_SAVE_CMAP) + restore_vga_cmap(state); + + vga_cleanup(state); + return 0; +} + +#ifdef MODULE +int init_module(void) { return 0; }; +void cleanup_module(void) {}; +#endif + +EXPORT_SYMBOL(save_vga); +EXPORT_SYMBOL(restore_vga); + +MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); +MODULE_DESCRIPTION("VGA State Save/Restore"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c new file mode 100644 index 000000000000..ed78747487e2 --- /dev/null +++ b/drivers/video/virgefb.c @@ -0,0 +1,2513 @@ +/* + * linux/drivers/video/virgefb.c -- CyberVision64/3D frame buffer device + * + * Copyright (C) 1997 Andr Heynatz + * + * + * This file is based on the CyberVision frame buffer device (cyberfb.c): + * + * Copyright (C) 1996 Martin Apel + * Geert Uytterhoeven + * + * Zorro II additions : + * + * Copyright (C) 1998-2000 Christian T. Steigies + * + * Initialization additions : + * + * Copyright (C) 1998-2000 Ken Tyler + * + * Parts of the Initialization code are based on Cyberfb.c by Allan Bair, + * and on the NetBSD CyberVision64 frame buffer driver by Michael Teske who gave + * permission for its use. + * + * Many thanks to Frank Mariak for his assistance with ZORRO 2 access and other + * mysteries. + * + * + * + * 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. + */ + +#undef VIRGEFBDEBUG +#undef VIRGEFBDUMP + +#include <linux/module.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/delay.h> +#include <linux/zorro.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/amigahw.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb32.h> + +#include "virgefb.h" + +#ifdef VIRGEFBDEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#ifdef VIRGEFBDUMP +static void cv64_dump(void); +#define DUMP cv64_dump() +#else +#define DUMP +#endif + +/* + * Macros for register access and zorro control + */ + +static inline void mb_inline(void) { mb(); } /* for use in comma expressions */ + +/* Set zorro 2 map */ + +#define SelectIO \ + mb(); \ + if (on_zorro2) { \ + (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x01); \ + mb(); \ + } + +#define SelectMMIO \ + mb(); \ + if (on_zorro2) { \ + (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x02); \ + mb(); \ + } + +#define SelectCFG \ + mb(); \ + if (on_zorro2) { \ + (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x03); \ + mb(); \ + } + +/* Set pass through, 0 = amiga, !=0 = cv64/3d */ + +#define SetVSwitch(x) \ + mb(); \ + (*(volatile u16 *)((u8 *)(vcode_switch_base)) = \ + (u16)(x ? 0 : 1)); \ + mb(); + +/* Zorro2 endian 'aperture' */ + +#define ENDIAN_BYTE 2 +#define ENDIAN_WORD 1 +#define ENDIAN_LONG 0 + +#define Select_Zorro2_FrameBuffer(x) \ + do { \ + if (on_zorro2) { \ + mb(); \ + (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x08)) = \ + (x * 0x40)); \ + mb(); \ + } \ + } while (0) + +/* SetPortVal - only used for interrupt enable (not yet implemented) */ + +#if 0 +#define SetPortVal(x) \ + mb(); \ + (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x0c)) = \ + (u16)x); \ + mb(); +#endif + +/* IO access */ + +#define byte_access_io(x) (((x) & 0x3ffc) | (((x) & 3)^3) | (((x) & 3) <<14)) +#define byte_access_mmio(x) (((x) & 0xfffc) | (((x) & 3)^3)) + +/* Write 8 bit VGA register - used once for chip wakeup */ + +#define wb_vgaio(reg, dat) \ + SelectIO; \ + (*(volatile u8 *)(vgaio_regs + ((u32)byte_access_io(reg) & 0xffff)) = \ + (dat & 0xff)); \ + SelectMMIO; + +/* Read 8 bit VGA register - only used in dump (SelectIO not needed on read ?) */ + +#ifdef VIRGEFBDUMP +#define rb_vgaio(reg) \ + ({ \ + u8 __zzyzx; \ + SelectIO; \ + __zzyzx = (*(volatile u8 *)((vgaio_regs)+(u32)byte_access_io(reg))); \ + SelectMMIO; \ + __zzyzx; \ + }) +#endif + +/* MMIO access */ + +/* Read 8 bit MMIO register */ + +#define rb_mmio(reg) \ + (mb_inline(), \ + (*(volatile u8 *)(mmio_regs + 0x8000 + (u32)byte_access_mmio(reg)))) + +/* Write 8 bit MMIO register */ + +#define wb_mmio(reg,dat) \ + mb(); \ + (*(volatile u8 *)(mmio_regs + 0x8000 + (byte_access_mmio((reg) & 0xffff))) = \ + (dat & 0xff)); \ + mb(); + +/* Read 32 bit MMIO register */ + +#define rl_mmio(reg) \ + (mb_inline(), \ + (*((volatile u32 *)((u8 *)((mmio_regs + (on_zorro2 ? 0x20000 : 0)) + (reg)))))) + +/* Write 32 bit MMIO register */ + +#define wl_mmio(reg,dat) \ + mb(); \ + ((*(volatile u32 *)((u8 *)((mmio_regs + (on_zorro2 ? 0x20000 : 0)) + (reg)))) = \ + (u32)(dat)); \ + mb(); + +/* Write to virge graphics register */ + +#define wgfx(reg, dat) do { wb_mmio(GCT_ADDRESS, (reg)); wb_mmio(GCT_ADDRESS_W, (dat)); } while (0) + +/* Write to virge sequencer register */ + +#define wseq(reg, dat) do { wb_mmio(SEQ_ADDRESS, (reg)); wb_mmio(SEQ_ADDRESS_W, (dat)); } while (0) + +/* Write to virge CRT controller register */ + +#define wcrt(reg, dat) do { wb_mmio(CRT_ADDRESS, (reg)); wb_mmio(CRT_ADDRESS_W, (dat)); } while (0) + +/* Write to virge attribute register */ + +#define watr(reg, dat) \ + do { \ + volatile unsigned char watr_tmp; \ + watr_tmp = rb_mmio(ACT_ADDRESS_RESET); \ + wb_mmio(ACT_ADDRESS_W, (reg)); \ + wb_mmio(ACT_ADDRESS_W, (dat)); \ + udelay(10); \ + } while (0) + +/* end of macros */ + +struct virgefb_par { + struct fb_var_screeninfo var; + __u32 type; + __u32 type_aux; + __u32 visual; + __u32 line_length; +}; + +static struct virgefb_par current_par; + +static int current_par_valid = 0; + +static struct display disp; +static struct fb_info fb_info; + +static union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif +} fbcon_cmap; + +/* + * Switch for Chipset Independency + */ + +static struct fb_hwswitch { + + /* Initialisation */ + + int (*init)(void); + + /* Display Control */ + + int (*encode_fix)(struct fb_fix_screeninfo *fix, struct virgefb_par *par); + int (*decode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par); + int (*encode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par); + int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info); + void (*blank)(int blank); +} *fbhw; + +static unsigned char blit_maybe_busy = 0; + +/* + * Frame Buffer Name + */ + +static char virgefb_name[16] = "CyberVision/3D"; + +/* + * CyberVision64/3d Graphics Board + */ + +static unsigned char virgefb_colour_table [256][3]; +static unsigned long v_ram; +static unsigned long v_ram_size; +static volatile unsigned char *mmio_regs; +static volatile unsigned char *vgaio_regs; + +static unsigned long v_ram_phys; +static unsigned long mmio_regs_phys; +static unsigned long vcode_switch_base; +static unsigned char on_zorro2; + +/* + * Offsets from start of video ram to appropriate ZIII aperture + */ + +#ifdef FBCON_HAS_CFB8 +#define CYBMEM_OFFSET_8 0x800000 /* BGRX */ +#endif +#ifdef FBCON_HAS_CFB16 +#define CYBMEM_OFFSET_16 0x400000 /* GBXR */ +#endif +#ifdef FBCON_HAS_CFB32 +#define CYBMEM_OFFSET_32 0x000000 /* XRGB */ +#endif + +/* + * MEMCLOCK was 32MHz, 64MHz works, 72MHz doesn't (on my board) + */ + +#define MEMCLOCK 50000000 + +/* + * Predefined Video Modes + */ + +static struct { + const char *name; + struct fb_var_screeninfo var; +} virgefb_predefined[] __initdata = { +#ifdef FBCON_HAS_CFB8 + { + "640x480-8", { /* Cybervision 8 bpp */ + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 160, 136, 82, 61, 88, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "768x576-8", { /* Cybervision 8 bpp */ + 768, 576, 768, 576, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "800x600-8", { /* Cybervision 8 bpp */ + 800, 600, 800, 600, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + #if 0 + "1024x768-8", { /* Cybervision 8 bpp */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, + 0, FB_VMODE_NONINTERLACED + } + #else + "1024x768-8", { + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + #if 0 + 0, 0, -1, -1, FB_ACCELF_TEXT, 12500, 184, 40, 40, 2, 96, 1, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + #else + 0, 0, -1, -1, FB_ACCELF_TEXT, 12699, 176, 16, 28, 1, 96, 3, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + #endif + #endif + }, { + "1152x886-8", { /* Cybervision 8 bpp */ + 1152, 886, 1152, 886, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1280x1024-8", { /* Cybervision 8 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + #if 0 + 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, + } + #else + 0, 0, -1, -1, FB_ACCELF_TEXT, 7414, 232, 64, 38, 1, 112, 3, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + #endif + }, { + "1600x1200-8", { /* Cybervision 8 bpp */ + 1600, 1200, 1600, 1200, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + #if 0 + 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, + 0, FB_VMODE_NONINTERLACED + } + #else + 0, 0, -1, -1, FB_ACCELF_TEXT, 6411, 256, 32, 52, 10, 160, 8, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + #endif + }, +#endif + +#ifdef FBCON_HAS_CFB16 + { + "640x480-16", { /* Cybervision 16 bpp */ + 640, 480, 640, 480, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 152, 144, 82, 61, 88, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "768x576-16", { /* Cybervision 16 bpp */ + 768, 576, 768, 576, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "800x600-16", { /* Cybervision 16 bpp */ + 800, 600, 800, 600, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { +#if 0 + "1024x768-16", { /* Cybervision 16 bpp */ + 1024, 768, 1024, 768, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, + 0, FB_VMODE_NONINTERLACED + } +#else + "1024x768-16", { + 1024, 768, 1024, 768, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 12500, 184, 40, 40, 2, 96, 1, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } +#endif + }, { + "1152x886-16", { /* Cybervision 16 bpp */ + 1152, 886, 1152, 886, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1280x1024-16", { /* Cybervision 16 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1600x1200-16", { /* Cybervision 16 bpp */ + 1600, 1200, 1600, 1200, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, + 0, FB_VMODE_NONINTERLACED + } + }, +#endif + +#ifdef FBCON_HAS_CFB32 + { + "640x480-32", { /* Cybervision 32 bpp */ + 640, 480, 640, 480, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 160, 136, 82, 61, 88, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "768x576-32", { /* Cybervision 32 bpp */ + 768, 576, 768, 576, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "800x600-32", { /* Cybervision 32 bpp */ + 800, 600, 800, 600, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1024x768-32", { /* Cybervision 32 bpp */ + 1024, 768, 1024, 768, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1152x886-32", { /* Cybervision 32 bpp */ + 1152, 886, 1152, 886, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1280x1024-32", { /* Cybervision 32 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1600x1200-32", { /* Cybervision 32 bpp */ + 1600, 1200, 1600, 1200, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, + 0, FB_VMODE_NONINTERLACED + } + }, +#endif + +/* interlaced modes */ + +#ifdef FBCON_HAS_CFB8 + { + "1024x768-8i", { /* Cybervision 8 bpp */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, + 0, FB_VMODE_INTERLACED + } + }, { + "1280x1024-8i", { /* Cybervision 8 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, + 0, FB_VMODE_INTERLACED + } + }, { + "1600x1200-8i", { /* Cybervision 8 bpp */ + 1600, 1200, 1600, 1200, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, + 0, FB_VMODE_INTERLACED + } + }, +#endif + +#ifdef FBCON_HAS_CFB16 + { + "1024x768-16i", { /* Cybervision 16 bpp */ + 1024, 768, 1024, 768, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, + 0, FB_VMODE_INTERLACED + } + }, { + "1280x1024-16i", { /* Cybervision 16 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, + 0, FB_VMODE_INTERLACED + } + }, { + "1600x1200-16i", { /* Cybervision 16 bpp */ + 1600, 1200, 1600, 1200, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, + 0, FB_VMODE_INTERLACED + } + }, +#endif + +#ifdef FBCON_HAS_CFB32 + { + "1024x768-32i", { /* Cybervision 32 bpp */ + 1024, 768, 1024, 768, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 22222, 216, 144, 39, 2, 72, 1, + 0, FB_VMODE_INTERLACED + } + }, { + "1280x1024-32i", { /* Cybervision 32 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {23, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, + 0, FB_VMODE_INTERLACED + } + }, { + "1600x1200-32i", { /* Cybervision 32 bpp */ + 1600, 1200, 1600, 1200, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, + 0, FB_VMODE_INTERLACED + } + }, +#endif + +/* doublescan modes */ + +#ifdef FBCON_HAS_CFB8 + { + "320x240-8d", { /* Cybervision 8 bpp */ + 320, 240, 320, 240, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1, + 0, FB_VMODE_DOUBLE + } + }, +#endif + +#ifdef FBCON_HAS_CFB16 + { + "320x240-16d", { /* Cybervision 16 bpp */ + 320, 240, 320, 240, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1, + 0, FB_VMODE_DOUBLE + } + }, +#endif + +#ifdef FBCON_HAS_CFB32 + { + "320x240-32d", { /* Cybervision 32 bpp */ + 320, 240, 320, 240, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1, + 0, FB_VMODE_DOUBLE + } + }, +#endif +}; + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) +#define NUM_TOTAL_MODES arraysize(virgefb_predefined) + +/* + * Default to 800x600 for video=virge8:, virge16: or virge32: + */ + +#ifdef FBCON_HAS_CFB8 +#define VIRGE8_DEFMODE (2) +#endif + +#ifdef FBCON_HAS_CFB16 +#define VIRGE16_DEFMODE (9) +#endif + +#ifdef FBCON_HAS_CFB32 +#define VIRGE32_DEFMODE (16) +#endif + +static struct fb_var_screeninfo virgefb_default; +static int virgefb_inverse = 0; + +/* + * Interface used by the world + */ + +int virgefb_setup(char*); +static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int virgefb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int virgefb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int virgefb_blank(int blank, struct fb_info *info); + +/* + * Interface to the low level console driver + */ + +int virgefb_init(void); +static int virgefb_switch(int con, struct fb_info *info); +static int virgefb_updatevar(int con, struct fb_info *info); + +/* + * Text console acceleration + */ + +#ifdef FBCON_HAS_CFB8 +static struct display_switch fbcon_virge8; +#endif + +#ifdef FBCON_HAS_CFB16 +static struct display_switch fbcon_virge16; +#endif + +#ifdef FBCON_HAS_CFB32 +static struct display_switch fbcon_virge32; +#endif + +/* + * Hardware Specific Routines + */ + +static int virge_init(void); +static int virgefb_encode_fix(struct fb_fix_screeninfo *fix, + struct virgefb_par *par); +static int virgefb_decode_var(struct fb_var_screeninfo *var, + struct virgefb_par *par); +static int virgefb_encode_var(struct fb_var_screeninfo *var, + struct virgefb_par *par); +static int virgefb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info); +static void virgefb_gfx_on_off(int blank); +static inline void virgefb_wait_for_idle(void); +static void virgefb_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty, + u_short width, u_short height, u_short stride, u_short depth); +static void virgefb_RectFill(u_short x, u_short y, u_short width, u_short height, + u_short color, u_short stride, u_short depth); + +/* + * Internal routines + */ + +static void virgefb_get_par(struct virgefb_par *par); +static void virgefb_set_par(struct virgefb_par *par); +static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive); +static void virgefb_set_disp(int con, struct fb_info *info); +static int virgefb_get_video_mode(const char *name); +static void virgefb_set_video(struct fb_var_screeninfo *var); + +/* + * Additions for Initialization + */ + +static void virgefb_load_video_mode(struct fb_var_screeninfo *video_mode); +static int cv3d_has_4mb(void); +static unsigned short virgefb_compute_clock(unsigned long freq); +static inline unsigned char rattr(short); +static inline unsigned char rseq(short); +static inline unsigned char rcrt(short); +static inline unsigned char rgfx(short); +static inline void gfx_on_off(int toggle); +static void virgefb_pci_init(void); + +/* -------------------- Hardware specific routines ------------------------- */ + +/* + * Functions for register access + */ + +/* Read attribute controller register */ + +static inline unsigned char rattr(short idx) +{ + volatile unsigned char rattr_tmp; + + rattr_tmp = rb_mmio(ACT_ADDRESS_RESET); + wb_mmio(ACT_ADDRESS_W, idx); + return (rb_mmio(ACT_ADDRESS_R)); +} + +/* Read sequencer register */ + +static inline unsigned char rseq(short idx) +{ + wb_mmio(SEQ_ADDRESS, idx); + return (rb_mmio(SEQ_ADDRESS_R)); +} + +/* Read CRT controller register */ + +static inline unsigned char rcrt(short idx) +{ + wb_mmio(CRT_ADDRESS, idx); + return (rb_mmio(CRT_ADDRESS_R)); +} + +/* Read graphics controller register */ + +static inline unsigned char rgfx(short idx) +{ + wb_mmio(GCT_ADDRESS, idx); + return (rb_mmio(GCT_ADDRESS_R)); +} + + +/* + * Initialization + */ + +/* PCI init */ + +void virgefb_pci_init(void) { + + DPRINTK("ENTER\n"); + + SelectCFG; + + if (on_zorro2) { + *((short *)(vgaio_regs + 0x00000010)) = 0; + *((long *)(vgaio_regs + 0x00000004)) = 0x02000003; + } else { + *((short *)(vgaio_regs + 0x000e0010)) = 0; + *((long *)(vgaio_regs + 0x000e0004)) = 0x02000003; + } + + /* SelectIO is in wb_vgaio macro */ + wb_vgaio(SREG_VIDEO_SUBS_ENABLE, 0x01); + /* SelectMMIO is in wb_vgaio macro */ + + DPRINTK("EXIT\n"); + + return; +} + +/* + * Initalize all mode independent regs, find mem size and clear mem +*/ + +static int virge_init(void) +{ + int i; + unsigned char tmp; + + DPRINTK("ENTER\n"); + + virgefb_pci_init(); + + wb_mmio(GREG_MISC_OUTPUT_W, 0x07); /* colour, ram enable, clk sel */ + + wseq(SEQ_ID_UNLOCK_EXT, 0x06); /* unlock extensions */ + tmp = rb_mmio(GREG_MISC_OUTPUT_R); + wcrt(CRT_ID_REGISTER_LOCK_1, 0x48); /* unlock CR2D to CR3F */ + + wcrt(CRT_ID_BACKWAD_COMP_1, 0x00); /* irq disable */ + + wcrt(CRT_ID_REGISTER_LOCK_2, 0xa5); /* unlock CR40 to CRFF and more */ + wcrt(CRT_ID_REGISTER_LOCK,0x00); /* unlock h and v timing */ + wcrt(CRT_ID_SYSTEM_CONFIG, 0x01); /* unlock enhanced programming registers */ + + wb_mmio(GREG_FEATURE_CONTROL_W, 0x00); + + wcrt(CRT_ID_EXT_MISC_CNTL, 0x00); /* b2 = 0 to allow VDAC mmio access */ +#if 0 + /* write strap options ... ? */ + wcrt(CRT_ID_CONFIG_1, 0x08); + wcrt(CRT_ID_CONFIG_2, 0xff); /* 0x0x2 bit needs to be set ?? */ + wcrt(CRT_ID_CONFIG_3, 0x0f); + wcrt(CRT_ID_CONFIG_4, 0x1a); +#endif + wcrt(CRT_ID_EXT_MISC_CNTL_1, 0x82); /* PCI DE and software reset S3D engine */ + /* EXT_MISC_CNTL_1, CR66 bit 0 should be the same as bit 0 MR_ADVANCED_FUNCTION_CONTROL - check */ + wl_mmio(MR_ADVANCED_FUNCTION_CONTROL, 0x00000011); /* enhanced mode, linear addressing */ + +/* crtc registers */ + + wcrt(CRT_ID_PRESET_ROW_SCAN, 0x00); + + /* Disable h/w cursor */ + + wcrt(CRT_ID_CURSOR_START, 0x00); + wcrt(CRT_ID_CURSOR_END, 0x00); + wcrt(CRT_ID_START_ADDR_HIGH, 0x00); + wcrt(CRT_ID_START_ADDR_LOW, 0x00); + wcrt(CRT_ID_CURSOR_LOC_HIGH, 0x00); + wcrt(CRT_ID_CURSOR_LOC_LOW, 0x00); + wcrt(CRT_ID_EXT_MODE, 0x00); + wcrt(CRT_ID_HWGC_MODE, 0x00); + wcrt(CRT_ID_HWGC_ORIGIN_X_HI, 0x00); + wcrt(CRT_ID_HWGC_ORIGIN_X_LO, 0x00); + wcrt(CRT_ID_HWGC_ORIGIN_Y_HI, 0x00); + wcrt(CRT_ID_HWGC_ORIGIN_Y_LO, 0x00); + i = rcrt(CRT_ID_HWGC_MODE); + wcrt(CRT_ID_HWGC_FG_STACK, 0x00); + wcrt(CRT_ID_HWGC_FG_STACK, 0x00); + wcrt(CRT_ID_HWGC_FG_STACK, 0x00); + wcrt(CRT_ID_HWGC_BG_STACK, 0x00); + wcrt(CRT_ID_HWGC_BG_STACK, 0x00); + wcrt(CRT_ID_HWGC_BG_STACK, 0x00); + wcrt(CRT_ID_HWGC_START_AD_HI, 0x00); + wcrt(CRT_ID_HWGC_START_AD_LO, 0x00); + wcrt(CRT_ID_HWGC_DSTART_X, 0x00); + wcrt(CRT_ID_HWGC_DSTART_Y, 0x00); + + wcrt(CRT_ID_UNDERLINE_LOC, 0x00); + + wcrt(CRT_ID_MODE_CONTROL, 0xe3); + wcrt(CRT_ID_BACKWAD_COMP_2, 0x22); /* blank bdr bit 5 blanking only on 8 bit */ + + wcrt(CRT_ID_EX_SYNC_1, 0x00); + + /* memory */ + + wcrt(CRT_ID_EXT_SYS_CNTL_3, 0x00); + wcrt(CRT_ID_MEMORY_CONF, 0x08); /* config enhanced map */ + wcrt(CRT_ID_EXT_MEM_CNTL_1, 0x08); /* MMIO Select (0x0c works as well)*/ + wcrt(CRT_ID_EXT_MEM_CNTL_2, 0x02); /* why 02 big endian 00 works ? */ + wcrt(CRT_ID_EXT_MEM_CNTL_4, 0x9f); /* config big endian - 0x00 ? */ + wcrt(CRT_ID_LAW_POS_HI, 0x00); + wcrt(CRT_ID_LAW_POS_LO, 0x00); + wcrt(CRT_ID_EXT_MISC_CNTL_1, 0x81); + wcrt(CRT_ID_MISC_1, 0x90); /* must follow CRT_ID_EXT_MISC_CNTL_1 */ + wcrt(CRT_ID_LAW_CNTL, 0x13); /* force 4 Meg for test */ + if (cv3d_has_4mb()) { + v_ram_size = 0x00400000; + wcrt(CRT_ID_LAW_CNTL, 0x13); /* 4 MB */ + } else { + v_ram_size = 0x00200000; + wcrt(CRT_ID_LAW_CNTL, 0x12); /* 2 MB */ + } + + if (on_zorro2) + v_ram_size -= 0x60000; /* we need some space for the registers */ + + wcrt(CRT_ID_EXT_SYS_CNTL_4, 0x00); + wcrt(CRT_ID_EXT_DAC_CNTL, 0x00); /* 0x10 for X11 cursor mode */ + +/* sequencer registers */ + + wseq(SEQ_ID_CLOCKING_MODE, 0x01); /* 8 dot clock */ + wseq(SEQ_ID_MAP_MASK, 0xff); + wseq(SEQ_ID_CHAR_MAP_SELECT, 0x00); + wseq(SEQ_ID_MEMORY_MODE, 0x02); + wseq(SEQ_ID_RAMDAC_CNTL, 0x00); + wseq(SEQ_ID_SIGNAL_SELECT, 0x00); + wseq(SEQ_ID_EXT_SEQ_REG9, 0x00); /* MMIO and PIO reg access enabled */ + wseq(SEQ_ID_EXT_MISC_SEQ, 0x00); + wseq(SEQ_ID_CLKSYN_CNTL_1, 0x00); + wseq(SEQ_ID_EXT_SEQ, 0x00); + +/* graphic registers */ + + wgfx(GCT_ID_SET_RESET, 0x00); + wgfx(GCT_ID_ENABLE_SET_RESET, 0x00); + wgfx(GCT_ID_COLOR_COMPARE, 0x00); + wgfx(GCT_ID_DATA_ROTATE, 0x00); + wgfx(GCT_ID_READ_MAP_SELECT, 0x00); + wgfx(GCT_ID_GRAPHICS_MODE, 0x40); + wgfx(GCT_ID_MISC, 0x01); + wgfx(GCT_ID_COLOR_XCARE, 0x0f); + wgfx(GCT_ID_BITMASK, 0xff); + +/* attribute registers */ + + for(i = 0; i <= 15; i++) + watr(ACT_ID_PALETTE0 + i, i); + watr(ACT_ID_ATTR_MODE_CNTL, 0x41); + watr(ACT_ID_OVERSCAN_COLOR, 0xff); + watr(ACT_ID_COLOR_PLANE_ENA, 0x0f); + watr(ACT_ID_HOR_PEL_PANNING, 0x00); + watr(ACT_ID_COLOR_SELECT, 0x00); + + wb_mmio(VDAC_MASK, 0xff); + +/* init local cmap as greyscale levels */ + + for (i = 0; i < 256; i++) { + virgefb_colour_table [i][0] = i; + virgefb_colour_table [i][1] = i; + virgefb_colour_table [i][2] = i; + } + +/* clear framebuffer memory */ + + memset((char*)v_ram, 0x00, v_ram_size); + + DPRINTK("EXIT\n"); + return 0; +} + + +/* + * This function should fill in the `fix' structure based on the + * values in the `par' structure. + */ + +static int virgefb_encode_fix(struct fb_fix_screeninfo *fix, + struct virgefb_par *par) +{ + DPRINTK("ENTER set video phys addr\n"); + + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, virgefb_name); + if (on_zorro2) + fix->smem_start = v_ram_phys; + switch (par->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + if (on_zorro2) + Select_Zorro2_FrameBuffer(ENDIAN_BYTE); + else + fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_8); + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + if (on_zorro2) + Select_Zorro2_FrameBuffer(ENDIAN_WORD); + else + fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_16); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + if (on_zorro2) + Select_Zorro2_FrameBuffer(ENDIAN_LONG); + else + fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_32); + break; +#endif + } + + fix->smem_len = v_ram_size; + fix->mmio_start = mmio_regs_phys; + fix->mmio_len = 0x10000; /* TODO: verify this for the CV64/3D */ + + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + if (par->var.bits_per_pixel == 8) + fix->visual = FB_VISUAL_PSEUDOCOLOR; + else + fix->visual = FB_VISUAL_TRUECOLOR; + + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = par->var.xres_virtual*par->var.bits_per_pixel/8; + fix->accel = FB_ACCEL_S3_VIRGE; + DPRINTK("EXIT v_ram_phys = 0x%8.8lx\n", (unsigned long)fix->smem_start); + return 0; +} + + +/* + * Fill the `par' structure based on the values in `var'. + * TODO: Verify and adjust values, return -EINVAL if bad. + */ + +static int virgefb_decode_var(struct fb_var_screeninfo *var, + struct virgefb_par *par) +{ + DPRINTK("ENTER\n"); + par->var.xres = var->xres; + par->var.yres = var->yres; + par->var.xres_virtual = var->xres_virtual; + par->var.yres_virtual = var->yres_virtual; + /* roundup and validate */ + par->var.xres = (par->var.xres+7) & ~7; + par->var.xres_virtual = (par->var.xres_virtual+7) & ~7; + if (par->var.xres_virtual < par->var.xres) + par->var.xres_virtual = par->var.xres; + if (par->var.yres_virtual < par->var.yres) + par->var.yres_virtual = par->var.yres; + par->var.xoffset = var->xoffset; + par->var.yoffset = var->yoffset; + par->var.bits_per_pixel = var->bits_per_pixel; + if (par->var.bits_per_pixel <= 8) + par->var.bits_per_pixel = 8; + else if (par->var.bits_per_pixel <= 16) + par->var.bits_per_pixel = 16; + else + par->var.bits_per_pixel = 32; +#ifndef FBCON_HAS_CFB32 + if (par->var.bits_per_pixel == 32) + par->var.bits_per_pixel = 16; +#endif +#ifndef FBCON_HAS_CFB16 + if (par->var.bits_per_pixel == 16) + par->var.bits_per_pixel = 8; +#endif + par->var.grayscale = var->grayscale; + par->var.red = var->red; + par->var.green = var->green; + par->var.blue = var->blue; + par->var.transp = var->transp; + par->var.nonstd = var->nonstd; + par->var.activate = var->activate; + par->var.height = var->height; + par->var.width = var->width; + if (var->accel_flags & FB_ACCELF_TEXT) { + par->var.accel_flags = FB_ACCELF_TEXT; + } else { + par->var.accel_flags = 0; + } + par->var.pixclock = var->pixclock; + par->var.left_margin = var->left_margin; + par->var.right_margin = var->right_margin; + par->var.upper_margin = var->upper_margin; + par->var.lower_margin = var->lower_margin; + par->var.hsync_len = var->hsync_len; + par->var.vsync_len = var->vsync_len; + par->var.sync = var->sync; + par->var.vmode = var->vmode; + DPRINTK("EXIT\n"); + return 0; +} + +/* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static int virgefb_encode_var(struct fb_var_screeninfo *var, + struct virgefb_par *par) +{ + DPRINTK("ENTER\n"); + memset(var, 0, sizeof(struct fb_var_screeninfo)); /* need this ? */ + var->xres = par->var.xres; + var->yres = par->var.yres; + var->xres_virtual = par->var.xres_virtual; + var->yres_virtual = par->var.yres_virtual; + var->xoffset = par->var.xoffset; + var->yoffset = par->var.yoffset; + var->bits_per_pixel = par->var.bits_per_pixel; + var->grayscale = par->var.grayscale; + var->red = par->var.red; + var->green = par->var.green; + var->blue = par->var.blue; + var->transp = par->var.transp; + var->nonstd = par->var.nonstd; + var->activate = par->var.activate; + var->height = par->var.height; + var->width = par->var.width; + var->accel_flags = par->var.accel_flags; + var->pixclock = par->var.pixclock; + var->left_margin = par->var.left_margin; + var->right_margin = par->var.right_margin; + var->upper_margin = par->var.upper_margin; + var->lower_margin = par->var.lower_margin; + var->hsync_len = par->var.hsync_len; + var->vsync_len = par->var.vsync_len; + var->sync = par->var.sync; + var->vmode = par->var.vmode; + DPRINTK("EXIT\n"); + return 0; +} + +/* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + DPRINTK("ENTER\n"); + if (((current_par.var.bits_per_pixel==8) && (regno>255)) || + ((current_par.var.bits_per_pixel!=8) && (regno>15))) { + DPRINTK("EXIT\n"); + return 1; + } + if (((current_par.var.bits_per_pixel==8) && (regno<256)) || + ((current_par.var.bits_per_pixel!=8) && (regno<16))) { + virgefb_colour_table [regno][0] = red >> 10; + virgefb_colour_table [regno][1] = green >> 10; + virgefb_colour_table [regno][2] = blue >> 10; + } + + switch (current_par.var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + wb_mmio(VDAC_ADDRESS_W, (unsigned char)regno); + wb_mmio(VDAC_DATA, ((unsigned char)(red >> 10))); + wb_mmio(VDAC_DATA, ((unsigned char)(green >> 10))); + wb_mmio(VDAC_DATA, ((unsigned char)(blue >> 10))); + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + fbcon_cmap.cfb16[regno] = + ((red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11)); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + fbcon_cmap.cfb32[regno] = + /* transp = 0's or 1's ? */ + (((red & 0xff00) << 8) | + ((green & 0xff00) >> 0) | + ((blue & 0xff00) >> 8)); + break; +#endif + } + DPRINTK("EXIT\n"); + return 0; +} + + +/* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int virgefb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info) +{ + int t; + + DPRINTK("ENTER\n"); + if (regno > 255) { + DPRINTK("EXIT\n"); + return 1; + } + if (((current_par.var.bits_per_pixel==8) && (regno<256)) || + ((current_par.var.bits_per_pixel!=8) && (regno<16))) { + + t = virgefb_colour_table [regno][0]; + *red = (t<<10) | (t<<4) | (t>>2); + t = virgefb_colour_table [regno][1]; + *green = (t<<10) | (t<<4) | (t>>2); + t = virgefb_colour_table [regno][2]; + *blue = (t<<10) | (t<<4) | (t>>2); + } + *transp = 0; + DPRINTK("EXIT\n"); + return 0; +} + + +/* + * (Un)Blank the screen + */ + +static void virgefb_gfx_on_off(int blank) +{ + DPRINTK("ENTER\n"); + gfx_on_off(blank); + DPRINTK("EXIT\n"); +} + +/* + * CV3D low-level support + */ + + +static inline void wait_3d_fifo_slots(int n) /* WaitQueue */ +{ + do { + mb(); + } while (((rl_mmio(MR_SUBSYSTEM_STATUS_R) >> 8) & 0x1f) < (n + 2)); +} + +static inline void virgefb_wait_for_idle(void) /* WaitIdle */ +{ + while(!(rl_mmio(MR_SUBSYSTEM_STATUS_R) & 0x2000)) ; + blit_maybe_busy = 0; +} + + /* + * BitBLT - Through the Plane + */ + +static void virgefb_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty, + u_short width, u_short height, u_short stride, u_short depth) +{ + unsigned int blitcmd = S3V_BITBLT | S3V_DRAW | S3V_BLT_COPY; + + switch (depth) { +#ifdef FBCON_HAS_CFB8 + case 8 : + blitcmd |= S3V_DST_8BPP; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16 : + blitcmd |= S3V_DST_16BPP; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32 : + /* 32 bit uses 2 by 16 bit values, see fbcon_virge32_bmove */ + blitcmd |= S3V_DST_16BPP; + break; +#endif + } + + /* Set drawing direction */ + /* -Y, X maj, -X (default) */ + if (curx > destx) { + blitcmd |= (1 << 25); /* Drawing direction +X */ + } else { + curx += (width - 1); + destx += (width - 1); + } + + if (cury > desty) { + blitcmd |= (1 << 26); /* Drawing direction +Y */ + } else { + cury += (height - 1); + desty += (height - 1); + } + + wait_3d_fifo_slots(8); /* wait on fifo slots for 8 writes */ + + if (blit_maybe_busy) + virgefb_wait_for_idle(); + blit_maybe_busy = 1; + + wl_mmio(BLT_PATTERN_COLOR, 1); /* pattern fb color */ + wl_mmio(BLT_MONO_PATTERN_0, ~0); + wl_mmio(BLT_MONO_PATTERN_1, ~0); + wl_mmio(BLT_SIZE_X_Y, ((width << 16) | height)); + wl_mmio(BLT_SRC_X_Y, ((curx << 16) | cury)); + wl_mmio(BLT_DEST_X_Y, ((destx << 16) | desty)); + wl_mmio(BLT_SRC_DEST_STRIDE, (((stride << 16) | stride) /* & 0x0ff80ff8 */)); /* why is this needed now ? */ + wl_mmio(BLT_COMMAND_SET, blitcmd); +} + +/* + * Rectangle Fill Solid + */ + +static void virgefb_RectFill(u_short x, u_short y, u_short width, u_short height, + u_short color, u_short stride, u_short depth) +{ + unsigned int blitcmd = S3V_RECTFILL | S3V_DRAW | + S3V_BLT_CLEAR | S3V_MONO_PAT | (1 << 26) | (1 << 25); + + switch (depth) { +#ifdef FBCON_HAS_CFB8 + case 8 : + blitcmd |= S3V_DST_8BPP; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16 : + blitcmd |= S3V_DST_16BPP; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32 : + /* 32 bit uses 2 times 16 bit values, see fbcon_virge32_clear */ + blitcmd |= S3V_DST_16BPP; + break; +#endif + } + + wait_3d_fifo_slots(5); /* wait on fifo slots for 5 writes */ + + if (blit_maybe_busy) + virgefb_wait_for_idle(); + blit_maybe_busy = 1; + + wl_mmio(BLT_PATTERN_COLOR, (color & 0xff)); + wl_mmio(BLT_SIZE_X_Y, ((width << 16) | height)); + wl_mmio(BLT_DEST_X_Y, ((x << 16) | y)); + wl_mmio(BLT_SRC_DEST_STRIDE, (((stride << 16) | stride) /* & 0x0ff80ff8 */)); + wl_mmio(BLT_COMMAND_SET, blitcmd); +} + +/* + * Move cursor to x, y + */ + +#if 0 +static void virgefb_move_cursor(u_short x, u_short y) +{ + DPRINTK("Yuck .... MoveCursor on a 3D\n"); + return 0; +} +#endif + +/* -------------------- Interfaces to hardware functions -------------------- */ + +static struct fb_hwswitch virgefb_hw_switch = { + .init = virge_init, + .encode_fix = virgefb_encode_fix, + .decode_var = virgefb_decode_var, + .encode_var = virgefb_encode_var, + .getcolreg = virgefb_getcolreg, + .blank = virgefb_gfx_on_off +}; + + +/* -------------------- Generic routines ------------------------------------ */ + + +/* + * Fill the hardware's `par' structure. + */ + +static void virgefb_get_par(struct virgefb_par *par) +{ + DPRINTK("ENTER\n"); + if (current_par_valid) { + *par = current_par; + } else { + fbhw->decode_var(&virgefb_default, par); + } + DPRINTK("EXIT\n"); +} + + +static void virgefb_set_par(struct virgefb_par *par) +{ + DPRINTK("ENTER\n"); + current_par = *par; + current_par_valid = 1; + DPRINTK("EXIT\n"); +} + + +static void virgefb_set_video(struct fb_var_screeninfo *var) +{ +/* Set clipping rectangle to current screen size */ + + unsigned int clip; + + DPRINTK("ENTER\n"); + wait_3d_fifo_slots(4); + clip = ((0 << 16) | (var->xres - 1)); + wl_mmio(BLT_CLIP_LEFT_RIGHT, clip); + clip = ((0 << 16) | (var->yres - 1)); + wl_mmio(BLT_CLIP_TOP_BOTTOM, clip); + wl_mmio(BLT_SRC_BASE, 0); /* seems we need to clear these two */ + wl_mmio(BLT_DEST_BASE, 0); + +/* Load the video mode defined by the 'var' data */ + + virgefb_load_video_mode(var); + DPRINTK("EXIT\n"); +} + +/* +Merge these two functions, Geert's suggestion. +static int virgefb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info); +static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive); +*/ + +static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +{ + int err, activate; + struct virgefb_par par; + + DPRINTK("ENTER\n"); + if ((err = fbhw->decode_var(var, &par))) { + DPRINTK("EXIT\n"); + return (err); + } + + activate = var->activate; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) + virgefb_set_par(&par); + fbhw->encode_var(var, &par); + var->activate = activate; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) + virgefb_set_video(var); + DPRINTK("EXIT\n"); + return 0; +} + + +/* + * Get the Fixed Part of the Display + */ + +static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct virgefb_par par; + int error = 0; + + DPRINTK("ENTER\n"); + if (con == -1) + virgefb_get_par(&par); + else + error = fbhw->decode_var(&fb_display[con].var, &par); + + if (!error) + error = fbhw->encode_fix(fix, &par); + DPRINTK("EXIT\n"); + return(error); +} + + +/* + * Get the User Defined Part of the Display + */ + +static int virgefb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct virgefb_par par; + int error = 0; + + DPRINTK("ENTER\n"); + if (con == -1) { + virgefb_get_par(&par); + error = fbhw->encode_var(var, &par); + disp.var = *var; /* ++Andre: don't know if this is the right place */ + } else { + *var = fb_display[con].var; + } + DPRINTK("EXIT\n"); + return(error); +} + +static void virgefb_set_disp(int con, struct fb_info *info) +{ + struct fb_fix_screeninfo fix; + struct display *display; + + DPRINTK("ENTER\n"); + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + virgefb_get_fix(&fix, con, info); + if (con == -1) + con = 0; + if(on_zorro2) { + info->screen_base = (char*)v_ram; + } else { + switch (display->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + info->screen_base = (char*)(v_ram + CYBMEM_OFFSET_8); + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + info->screen_base = (char*)(v_ram + CYBMEM_OFFSET_16); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + info->screen_base = (char*)(v_ram + CYBMEM_OFFSET_32); + break; +#endif + } + } + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->can_soft_blank = 1; + display->inverse = virgefb_inverse; + display->line_length = display->var.xres_virtual* + display->var.bits_per_pixel/8; + + switch (display->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + if (display->var.accel_flags & FB_ACCELF_TEXT) { + display->dispsw = &fbcon_virge8; +#warning FIXME: We should reinit the graphics engine here + } else + display->dispsw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + if (display->var.accel_flags & FB_ACCELF_TEXT) { + display->dispsw = &fbcon_virge16; + } else + display->dispsw = &fbcon_cfb16; + display->dispsw_data = &fbcon_cmap.cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + if (display->var.accel_flags & FB_ACCELF_TEXT) { + display->dispsw = &fbcon_virge32; + } else + display->dispsw = &fbcon_cfb32; + display->dispsw_data = &fbcon_cmap.cfb32; + break; +#endif + default: + display->dispsw = &fbcon_dummy; + break; + } + DPRINTK("EXIT v_ram virt = 0x%8.8lx\n",(unsigned long)display->screen_base); +} + + +/* + * Set the User Defined Part of the Display + */ + +static int virgefb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel; + + DPRINTK("ENTER\n"); + + if ((err = virgefb_do_fb_set_var(var, con == info->currcon))) { + DPRINTK("EXIT\n"); + return(err); + } + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres = fb_display[con].var.xres; + oldyres = fb_display[con].var.yres; + oldvxres = fb_display[con].var.xres_virtual; + oldvyres = fb_display[con].var.yres_virtual; + oldbpp = fb_display[con].var.bits_per_pixel; + oldaccel = fb_display[con].var.accel_flags; + fb_display[con].var = *var; + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || + oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel || + oldaccel != var->accel_flags) { + virgefb_set_disp(con, info); + if (fb_info.changevar) + (*fb_info.changevar)(con); + fb_alloc_cmap(&fb_display[con].cmap, 0, 0); + do_install_cmap(con, info); + } + } + var->activate = 0; + DPRINTK("EXIT\n"); + return 0; +} + + +/* + * Get the Colormap + */ + +static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + DPRINTK("ENTER\n"); + if (con == info->currcon) { /* current console? */ + DPRINTK("EXIT - console is current console, fb_get_cmap\n"); + return(fb_get_cmap(cmap, kspc, fbhw->getcolreg, info)); + } else if (fb_display[con].cmap.len) { /* non default colormap? */ + DPRINTK("Use console cmap\n"); + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + } else { + DPRINTK("Use default cmap\n"); + fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel==8 ? 256 : 16), + cmap, kspc ? 0 : 2); + } + DPRINTK("EXIT\n"); + return 0; +} + +static struct fb_ops virgefb_ops = { + .owner = THIS_MODULE, + .fb_get_fix = virgefb_get_fix, + .fb_get_var = virgefb_get_var, + .fb_set_var = virgefb_set_var, + .fb_get_cmap = virgefb_get_cmap, + .fb_set_cmap = gen_set_cmap, + .fb_setcolreg = virgefb_setcolreg, + .fb_blank = virgefb_blank, +}; + +int __init virgefb_setup(char *options) +{ + char *this_opt; + fb_info.fontname[0] = '\0'; + + DPRINTK("ENTER\n"); + if (!options || !*options) { + DPRINTK("EXIT\n"); + return 0; + } + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + if (!strcmp(this_opt, "inverse")) { + virgefb_inverse = 1; + fb_invert_cmaps(); + } else if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt+5); +#ifdef FBCON_HAS_CFB8 + else if (!strcmp (this_opt, "virge8")){ + virgefb_default = virgefb_predefined[VIRGE8_DEFMODE].var; + } +#endif +#ifdef FBCON_HAS_CFB16 + else if (!strcmp (this_opt, "virge16")){ + virgefb_default = virgefb_predefined[VIRGE16_DEFMODE].var; + } +#endif +#ifdef FBCON_HAS_CFB32 + else if (!strcmp (this_opt, "virge32")){ + virgefb_default = virgefb_predefined[VIRGE32_DEFMODE].var; + } +#endif + else + virgefb_get_video_mode(this_opt); + } + + printk(KERN_INFO "mode : xres=%d, yres=%d, bpp=%d\n", virgefb_default.xres, + virgefb_default.yres, virgefb_default.bits_per_pixel); + DPRINTK("EXIT\n"); + return 0; +} + + +/* + * Get a Video Mode + */ + +static int __init virgefb_get_video_mode(const char *name) +{ + int i; + + DPRINTK("ENTER\n"); + for (i = 0; i < NUM_TOTAL_MODES; i++) { + if (!strcmp(name, virgefb_predefined[i].name)) { + virgefb_default = virgefb_predefined[i].var; + DPRINTK("EXIT\n"); + return(i); + } + } + /* ++Andre: set virgefb default mode */ + +/* prefer 16 bit depth, 8 if no 16, if no 8 or 16 use 32 */ + +#ifdef FBCON_HAS_CFB32 + virgefb_default = virgefb_predefined[VIRGE32_DEFMODE].var; +#endif +#ifdef FBCON_HAS_CFB8 + virgefb_default = virgefb_predefined[VIRGE8_DEFMODE].var; +#endif +#ifdef FBCON_HAS_CFB16 + virgefb_default = virgefb_predefined[VIRGE16_DEFMODE].var; +#endif + DPRINTK("EXIT\n"); + return 0; +} + +/* + * Initialization + */ + +int __init virgefb_init(void) +{ + struct virgefb_par par; + unsigned long board_addr, board_size; + struct zorro_dev *z = NULL; + + DPRINTK("ENTER\n"); + + z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERVISION64_3D, NULL); + if (!z) + return -ENODEV; + + board_addr = z->resource.start; + if (board_addr < 0x01000000) { + + /* board running in Z2 space. This includes the video memory + as well as the S3 register set */ + + on_zorro2 = 1; + board_size = 0x00400000; + + if (!request_mem_region(board_addr, board_size, "S3 ViRGE")) + return -ENOMEM; + + v_ram_phys = board_addr; + v_ram = ZTWO_VADDR(v_ram_phys); + mmio_regs_phys = (unsigned long)(board_addr + 0x003c0000); + vgaio_regs = (unsigned char *) ZTWO_VADDR(board_addr + 0x003c0000); + mmio_regs = (unsigned char *)ZTWO_VADDR(mmio_regs_phys); + vcode_switch_base = (unsigned long) ZTWO_VADDR(board_addr + 0x003a0000); + printk(KERN_INFO "CV3D detected running in Z2 mode.\n"); + + } else { + + /* board running in Z3 space. Separate video memory (3 apertures) + and S3 register set */ + + on_zorro2 = 0; + board_size = 0x01000000; + + if (!request_mem_region(board_addr, board_size, "S3 ViRGE")) + return -ENOMEM; + + v_ram_phys = board_addr + 0x04000000; + v_ram = (unsigned long)ioremap(v_ram_phys, 0x01000000); + mmio_regs_phys = board_addr + 0x05000000; + vgaio_regs = (unsigned char *)ioremap(board_addr +0x0c000000, 0x00100000); /* includes PCI regs */ + mmio_regs = ioremap(mmio_regs_phys, 0x00010000); + vcode_switch_base = (unsigned long)ioremap(board_addr + 0x08000000, 0x1000); + printk(KERN_INFO "CV3D detected running in Z3 mode\n"); + } + +#if defined (VIRGEFBDEBUG) + DPRINTK("board_addr : 0x%8.8lx\n",board_addr); + DPRINTK("board_size : 0x%8.8lx\n",board_size); + DPRINTK("mmio_regs_phy : 0x%8.8lx\n",mmio_regs_phys); + DPRINTK("v_ram_phys : 0x%8.8lx\n",v_ram_phys); + DPRINTK("vgaio_regs : 0x%8.8lx\n",(unsigned long)vgaio_regs); + DPRINTK("mmio_regs : 0x%8.8lx\n",(unsigned long)mmio_regs); + DPRINTK("v_ram : 0x%8.8lx\n",v_ram); + DPRINTK("vcode sw base : 0x%8.8lx\n",vcode_switch_base); +#endif + fbhw = &virgefb_hw_switch; + strcpy(fb_info.modename, virgefb_name); + fb_info.changevar = NULL; + fb_info.fbops = &virgefb_ops; + fb_info.disp = &disp; + fb_info.currcon = -1; + fb_info.switch_con = &virgefb_switch; + fb_info.updatevar = &virgefb_updatevar; + fb_info.flags = FBINFO_FLAG_DEFAULT; + fbhw->init(); + fbhw->decode_var(&virgefb_default, &par); + fbhw->encode_var(&virgefb_default, &par); + virgefb_do_fb_set_var(&virgefb_default, 1); + virgefb_get_var(&fb_display[0].var, -1, &fb_info); + virgefb_set_disp(-1, &fb_info); + do_install_cmap(0, &fb_info); + + if (register_framebuffer(&fb_info) < 0) { + #warning release resources + printk(KERN_ERR "virgefb.c: register_framebuffer failed\n"); + DPRINTK("EXIT\n"); + return -EINVAL; + } + + printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of video memory\n", + fb_info.node, fb_info.modename, v_ram_size>>10); + + /* TODO: This driver cannot be unloaded yet */ + + DPRINTK("EXIT\n"); + return 0; +} + + +static int virgefb_switch(int con, struct fb_info *info) +{ + DPRINTK("ENTER\n"); + /* Do we have to save the colormap? */ + if (fb_display[info->currcon].cmap.len) + fb_get_cmap(&fb_display[info->currcon].cmap, 1, + fbhw->getcolreg, info); + virgefb_do_fb_set_var(&fb_display[con].var, 1); + info->currcon = con; + /* Install new colormap */ + do_install_cmap(con, info); + DPRINTK("EXIT\n"); + return 0; +} + + +/* + * Update the `var' structure (called by fbcon.c) + * + * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. + * Since it's called by a kernel driver, no range checking is done. + */ + +static int virgefb_updatevar(int con, struct fb_info *info) +{ + DPRINTK("ENTER\n"); + return 0; + DPRINTK("EXIT\n"); +} + +/* + * Blank the display. + */ + +static int virgefb_blank(int blank, struct fb_info *info) +{ + DPRINTK("ENTER\n"); + fbhw->blank(blank); + DPRINTK("EXIT\n"); + return 0; +} + + +/* + * Text console acceleration + */ + +#ifdef FBCON_HAS_CFB8 +static void fbcon_virge8_bmove(struct display *p, int sy, int sx, int dy, + int dx, int height, int width) +{ + sx *= 8; dx *= 8; width *= 8; + virgefb_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx, + (u_short)(dy*fontheight(p)), (u_short)width, + (u_short)(height*fontheight(p)), (u_short)p->next_line, 8); +} + +static void fbcon_virge8_clear(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + unsigned char bg; + + sx *= 8; width *= 8; + bg = attr_bgcol_ec(p,conp); + virgefb_RectFill((u_short)sx, (u_short)(sy*fontheight(p)), + (u_short)width, (u_short)(height*fontheight(p)), + (u_short)bg, (u_short)p->next_line, 8); +} + +static void fbcon_virge8_putc(struct vc_data *conp, struct display *p, int c, int yy, + int xx) +{ + if (blit_maybe_busy) + virgefb_wait_for_idle(); + fbcon_cfb8_putc(conp, p, c, yy, xx); +} + +static void fbcon_virge8_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, int xx) +{ + if (blit_maybe_busy) + virgefb_wait_for_idle(); + fbcon_cfb8_putcs(conp, p, s, count, yy, xx); +} + +static void fbcon_virge8_revc(struct display *p, int xx, int yy) +{ + if (blit_maybe_busy) + virgefb_wait_for_idle(); + fbcon_cfb8_revc(p, xx, yy); +} + +static void fbcon_virge8_clear_margins(struct vc_data *conp, struct display *p, + int bottom_only) +{ + if (blit_maybe_busy) + virgefb_wait_for_idle(); + fbcon_cfb8_clear_margins(conp, p, bottom_only); +} + +static struct display_switch fbcon_virge8 = { + .setup = fbcon_cfb8_setup, + .bmove = fbcon_virge8_bmove, + .clear = fbcon_virge8_clear, + .putc = fbcon_virge8_putc, + .putcs = fbcon_virge8_putcs, + .revc = fbcon_virge8_revc, + .clear_margins = fbcon_virge8_clear_margins, + .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif + +#ifdef FBCON_HAS_CFB16 +static void fbcon_virge16_bmove(struct display *p, int sy, int sx, int dy, + int dx, int height, int width) +{ + sx *= 8; dx *= 8; width *= 8; + virgefb_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx, + (u_short)(dy*fontheight(p)), (u_short)width, + (u_short)(height*fontheight(p)), (u_short)p->next_line, 16); +} + +static void fbcon_virge16_clear(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + unsigned char bg; + + sx *= 8; width *= 8; + bg = attr_bgcol_ec(p,conp); + virgefb_RectFill((u_short)sx, (u_short)(sy*fontheight(p)), + (u_short)width, (u_short)(height*fontheight(p)), + (u_short)bg, (u_short)p->next_line, 16); +} + +static void fbcon_virge16_putc(struct vc_data *conp, struct display *p, int c, int yy, + int xx) +{ + if (blit_maybe_busy) + virgefb_wait_for_idle(); + fbcon_cfb16_putc(conp, p, c, yy, xx); +} + +static void fbcon_virge16_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, int xx) +{ + if (blit_maybe_busy) + virgefb_wait_for_idle(); + fbcon_cfb16_putcs(conp, p, s, count, yy, xx); +} + +static void fbcon_virge16_revc(struct display *p, int xx, int yy) +{ + if (blit_maybe_busy) + virgefb_wait_for_idle(); + fbcon_cfb16_revc(p, xx, yy); +} + +static void fbcon_virge16_clear_margins(struct vc_data *conp, struct display *p, + int bottom_only) +{ + if (blit_maybe_busy) + virgefb_wait_for_idle(); + fbcon_cfb16_clear_margins(conp, p, bottom_only); +} + +static struct display_switch fbcon_virge16 = { + .setup = fbcon_cfb16_setup, + .bmove = fbcon_virge16_bmove, + .clear = fbcon_virge16_clear, + .putc = fbcon_virge16_putc, + .putcs = fbcon_virge16_putcs, + .revc = fbcon_virge16_revc, + .clear_margins = fbcon_virge16_clear_margins, + .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif + +#ifdef FBCON_HAS_CFB32 +static void fbcon_virge32_bmove(struct display *p, int sy, int sx, int dy, + int dx, int height, int width) +{ + sx *= 16; dx *= 16; width *= 16; /* doubled these values to do 32 bit blit */ + virgefb_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx, + (u_short)(dy*fontheight(p)), (u_short)width, + (u_short)(height*fontheight(p)), (u_short)p->next_line, 16); +} + +static void fbcon_virge32_clear(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + unsigned char bg; + + sx *= 16; width *= 16; /* doubled these values to do 32 bit blit */ + bg = attr_bgcol_ec(p,conp); + virgefb_RectFill((u_short)sx, (u_short)(sy*fontheight(p)), + (u_short)width, (u_short)(height*fontheight(p)), + (u_short)bg, (u_short)p->next_line, 16); +} + +static void fbcon_virge32_putc(struct vc_data *conp, struct display *p, int c, int yy, + int xx) +{ + if (blit_maybe_busy) + virgefb_wait_for_idle(); + fbcon_cfb32_putc(conp, p, c, yy, xx); +} + +static void fbcon_virge32_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, int xx) +{ + if (blit_maybe_busy) + virgefb_wait_for_idle(); + fbcon_cfb32_putcs(conp, p, s, count, yy, xx); +} + +static void fbcon_virge32_revc(struct display *p, int xx, int yy) +{ + if (blit_maybe_busy) + virgefb_wait_for_idle(); + fbcon_cfb32_revc(p, xx, yy); +} + +static void fbcon_virge32_clear_margins(struct vc_data *conp, struct display *p, + int bottom_only) +{ + if (blit_maybe_busy) + virgefb_wait_for_idle(); + fbcon_cfb32_clear_margins(conp, p, bottom_only); +} + +static struct display_switch fbcon_virge32 = { + .setup = fbcon_cfb32_setup, + .bmove = fbcon_virge32_bmove, + .clear = fbcon_virge32_clear, + .putc = fbcon_virge32_putc, + .putcs = fbcon_virge32_putcs, + .revc = fbcon_virge32_revc, + .clear_margins = fbcon_virge32_clear_margins, + .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif + +#ifdef MODULE +MODULE_LICENSE("GPL"); + +int init_module(void) +{ + return virgefb_init(); +} +#endif /* MODULE */ + +static int cv3d_has_4mb(void) +{ + /* cyberfb version didn't work, neither does this (not reliably) + forced to return 4MB */ +#if 0 + volatile unsigned long *t0, *t2; +#endif + DPRINTK("ENTER\n"); +#if 0 + /* write patterns in memory and test if they can be read */ + t0 = (volatile unsigned long *)v_ram; + t2 = (volatile unsigned long *)(v_ram + 0x00200000); + *t0 = 0x87654321; + *t2 = 0x12345678; + + if (*t0 != 0x87654321) { + /* read of first location failed */ + DPRINTK("EXIT - 0MB !\n"); + return 0; + } + + if (*t2 == 0x87654321) { + /* should read 0x12345678 if 4MB */ + DPRINTK("EXIT - 2MB(a) \n"); + return 0; + } + + if (*t2 != 0x12345678) { + /* upper 2MB read back match failed */ + DPRINTK("EXIT - 2MB(b)\n"); + return 0; + } + + /* may have 4MB */ + + *t2 = 0xAAAAAAAA; + + if(*t2 != 0xAAAAAAAA) { + /* upper 2MB read back match failed */ + DPRINTK("EXIT - 2MB(c)\n"); + return 0; + } + + *t2 = 0x55555555; + + if(*t2 != 0x55555555) { + /* upper 2MB read back match failed */ + DPRINTK("EXIT - 2MB(d)\n"); + return 0; + } + +#endif + DPRINTK("EXIT - 4MB\n"); + return 1; +} + + +/* + * Computes M, N, and R pll params for freq arg. + * Returns 16 bits - hi 0MMMMMM lo 0RRNNNNN + */ + +#define REFCLOCK 14318000 + +static unsigned short virgefb_compute_clock(unsigned long freq) +{ + + unsigned char m, n, r, rpwr; + unsigned long diff, ftry, save = ~0UL; + unsigned short mnr; + + DPRINTK("ENTER\n"); + + for (r = 0, rpwr = 1 ; r < 4 ; r++, rpwr *= 2) { + if ((135000000 <= (rpwr * freq)) && ((rpwr * freq) <= 270000000)) { + for (n = 1 ; n < 32 ; n++) { + m = ((freq * (n + 2) * rpwr)/REFCLOCK) - 2; + if (m == 0 || m >127) + break; + ftry = ((REFCLOCK / (n + 2)) * (m + 2)) / rpwr; + if (ftry > freq) + diff = ftry - freq; + else + diff = freq - ftry; + if (diff < save) { + save = diff; + mnr = (m << 8) | (r<<5) | (n & 0x7f); + } + } + } + } + if (save == ~0UL) + printk("Can't compute clock PLL values for %ld Hz clock\n", freq); + DPRINTK("EXIT\n"); + return(mnr); +} + +static void virgefb_load_video_mode(struct fb_var_screeninfo *video_mode) +{ + unsigned char lace, dblscan, tmp; + unsigned short mnr; + unsigned short HT, HDE, HBS, HBW, HSS, HSW; + unsigned short VT, VDE, VBS, VBW, VSS, VSW; + unsigned short SCO; + int cr11; + int cr67; + int hmul; + int xres, xres_virtual, hfront, hsync, hback; + int yres, vfront, vsync, vback; + int bpp; + int i; + long freq; + + DPRINTK("ENTER : %dx%d-%d\n",video_mode->xres, video_mode->yres, + video_mode->bits_per_pixel); + + bpp = video_mode->bits_per_pixel; + xres = video_mode->xres; + xres_virtual = video_mode->xres_virtual; + hfront = video_mode->right_margin; + hsync = video_mode->hsync_len; + hback = video_mode->left_margin; + + lace = 0; + dblscan = 0; + + if (video_mode->vmode & FB_VMODE_DOUBLE) { + yres = video_mode->yres * 2; + vfront = video_mode->lower_margin * 2; + vsync = video_mode->vsync_len * 2; + vback = video_mode->upper_margin * 2; + dblscan = 1; + } else if (video_mode->vmode & FB_VMODE_INTERLACED) { + yres = (video_mode->yres + 1) / 2; + vfront = (video_mode->lower_margin + 1) / 2; + vsync = (video_mode->vsync_len + 1) / 2; + vback = (video_mode->upper_margin + 1) / 2; + lace = 1; + } else { + yres = video_mode->yres; + vfront = video_mode->lower_margin; + vsync = video_mode->vsync_len; + vback = video_mode->upper_margin; + } + + switch (bpp) { + case 8: + video_mode->red.offset = 0; + video_mode->green.offset = 0; + video_mode->blue.offset = 0; + video_mode->transp.offset = 0; + video_mode->red.length = 8; + video_mode->green.length = 8; + video_mode->blue.length = 8; + video_mode->transp.length = 0; + hmul = 1; + cr67 = 0x00; + SCO = xres_virtual / 8; + break; + case 16: + video_mode->red.offset = 11; + video_mode->green.offset = 5; + video_mode->blue.offset = 0; + video_mode->transp.offset = 0; + video_mode->red.length = 5; + video_mode->green.length = 6; + video_mode->blue.length = 5; + video_mode->transp.length = 0; + hmul = 2; + cr67 = 0x50; + SCO = xres_virtual / 4; + break; + case 32: + video_mode->red.offset = 16; + video_mode->green.offset = 8; + video_mode->blue.offset = 0; + video_mode->transp.offset = 24; + video_mode->red.length = 8; + video_mode->green.length = 8; + video_mode->blue.length = 8; + video_mode->transp.length = 8; + hmul = 1; + cr67 = 0xd0; + SCO = xres_virtual / 2; + break; + } + + HT = (((xres + hfront + hsync + hback) / 8) * hmul) - 5; + HDE = ((xres / 8) * hmul) - 1; + HBS = (xres / 8) * hmul; + HSS = ((xres + hfront) / 8) * hmul; + HSW = (hsync / 8) * hmul; + HBW = (((hfront + hsync + hback) / 8) * hmul) - 2; + + VT = yres + vfront + vsync + vback - 2; + VDE = yres - 1; + VBS = yres - 1; + VSS = yres + vfront; + VSW = vsync; + VBW = vfront + vsync + vback - 2; + +#ifdef VIRGEFBDEBUG + DPRINTK("HDE : 0x%4.4x, %4.4d\n", HDE, HDE); + DPRINTK("HBS : 0x%4.4x, %4.4d\n", HBS, HBS); + DPRINTK("HSS : 0x%4.4x, %4.4d\n", HSS, HSS); + DPRINTK("HSW : 0x%4.4x, %4.4d\n", HSW, HSW); + DPRINTK("HBW : 0x%4.4x, %4.4d\n", HBW, HBW); + DPRINTK("HSS + HSW : 0x%4.4x, %4.4d\n", HSS+HSW, HSS+HSW); + DPRINTK("HBS + HBW : 0x%4.4x, %4.4d\n", HBS+HBW, HBS+HBW); + DPRINTK("HT : 0x%4.4x, %4.4d\n", HT, HT); + DPRINTK("VDE : 0x%4.4x, %4.4d\n", VDE, VDE); + DPRINTK("VBS : 0x%4.4x, %4.4d\n", VBS, VBS); + DPRINTK("VSS : 0x%4.4x, %4.4d\n", VSS, VSS); + DPRINTK("VSW : 0x%4.4x, %4.4d\n", VSW, VSW); + DPRINTK("VBW : 0x%4.4x, %4.4d\n", VBW, VBW); + DPRINTK("VT : 0x%4.4x, %4.4d\n", VT, VT); +#endif + +/* turn gfx off, don't mess up the display */ + + gfx_on_off(1); + +/* H and V sync polarity */ + + tmp = rb_mmio(GREG_MISC_OUTPUT_R) & 0x2f; /* colour, ram enable, clk sr12/s13 sel */ + if (!(video_mode->sync & FB_SYNC_HOR_HIGH_ACT)) + tmp |= 0x40; /* neg H sync polarity */ + if (!(video_mode->sync & FB_SYNC_VERT_HIGH_ACT)) + tmp |= 0x80; /* neg V sync polarity */ + tmp |= 0x0c; /* clk from sr12/sr13 */ + wb_mmio(GREG_MISC_OUTPUT_W, tmp); + +/* clocks */ + + wseq(SEQ_ID_BUS_REQ_CNTL, 0xc0); /* 2 clk mem wr and /RAS1 */ + wseq(SEQ_ID_CLKSYN_CNTL_2, 0x80); /* b7 is 2 mem clk wr */ + mnr = virgefb_compute_clock(MEMCLOCK); + DPRINTK("mem clock %d, m %d, n %d, r %d.\n", MEMCLOCK, ((mnr>>8)&0x7f), (mnr&0x1f), ((mnr >> 5)&0x03)); + wseq(SEQ_ID_MCLK_LO, (mnr & 0x7f)); + wseq(SEQ_ID_MCLK_HI, ((mnr & 0x7f00) >> 8)); + freq = (1000000000 / video_mode->pixclock) * 1000; /* pixclock is in ps ... convert to Hz */ + mnr = virgefb_compute_clock(freq); + DPRINTK("dot clock %ld, m %d, n %d, r %d.\n", freq, ((mnr>>8)&0x7f), (mnr&0x1f), ((mnr>>5)&0x03)); + wseq(SEQ_ID_DCLK_LO, (mnr & 0x7f)); + wseq(SEQ_ID_DCLK_HI, ((mnr & 0x7f00) >> 8)); + wseq(SEQ_ID_CLKSYN_CNTL_2, 0xa0); + wseq(SEQ_ID_CLKSYN_CNTL_2, 0x80); + udelay(100); + +/* load display parameters into board */ + + /* not sure about sync and blanking extensions bits in cr5d and cr5 */ + + wcrt(CRT_ID_EXT_HOR_OVF, /* 0x5d */ + ((HT & 0x100) ? 0x01 : 0x00) | + ((HDE & 0x100) ? 0x02 : 0x00) | + ((HBS & 0x100) ? 0x04 : 0x00) | + /* (((HBS + HBW) & 0x40) ? 0x08 : 0x00) | */ + ((HSS & 0x100) ? 0x10 : 0x00) | + /* (((HSS + HSW) & 0x20) ? 0x20 : 0x00) | */ + ((HSW >= 0x20) ? 0x20 : 0x00) | + (((HT-5) & 0x100) ? 0x40 : 0x00)); + + wcrt(CRT_ID_EXT_VER_OVF, /* 0x5e */ + ((VT & 0x400) ? 0x01 : 0x00) | + ((VDE & 0x400) ? 0x02 : 0x00) | + ((VBS & 0x400) ? 0x04 : 0x00) | + ((VSS & 0x400) ? 0x10 : 0x00) | + 0x40); /* line compare */ + + wcrt(CRT_ID_START_VER_RETR, VSS); + cr11 = rcrt(CRT_ID_END_VER_RETR) | 0x20; /* vert interrupt flag */ + wcrt(CRT_ID_END_VER_RETR, ((cr11 & 0x20) | ((VSS + VSW) & 0x0f))); /* keeps vert irq enable state, also has unlock bit cr0 to 7 */ + wcrt(CRT_ID_VER_DISP_ENA_END, VDE); + wcrt(CRT_ID_START_VER_BLANK, VBS); + wcrt(CRT_ID_END_VER_BLANK, VBS + VBW); /* might be +/- 1 out */ + wcrt(CRT_ID_HOR_TOTAL, HT); + wcrt(CRT_ID_DISPLAY_FIFO, HT - 5); + wcrt(CRT_ID_BACKWAD_COMP_3, 0x10); /* enable display fifo */ + wcrt(CRT_ID_HOR_DISP_ENA_END, HDE); + wcrt(CRT_ID_START_HOR_BLANK , HBS); + wcrt(CRT_ID_END_HOR_BLANK, (HBS + HBW) & 0x1f); + wcrt(CRT_ID_START_HOR_RETR, HSS); + wcrt(CRT_ID_END_HOR_RETR, /* cr5 */ + ((HSS + HSW) & 0x1f) | + (((HBS + HBW) & 0x20) ? 0x80 : 0x00)); + wcrt(CRT_ID_VER_TOTAL, VT); + wcrt(CRT_ID_OVERFLOW, + ((VT & 0x100) ? 0x01 : 0x00) | + ((VDE & 0x100) ? 0x02 : 0x00) | + ((VSS & 0x100) ? 0x04 : 0x00) | + ((VBS & 0x100) ? 0x08 : 0x00) | + 0x10 | + ((VT & 0x200) ? 0x20 : 0x00) | + ((VDE & 0x200) ? 0x40 : 0x00) | + ((VSS & 0x200) ? 0x80 : 0x00)); + wcrt(CRT_ID_MAX_SCAN_LINE, + (dblscan ? 0x80 : 0x00) | + 0x40 | + ((VBS & 0x200) ? 0x20 : 0x00)); + wcrt(CRT_ID_LINE_COMPARE, 0xff); + wcrt(CRT_ID_LACE_RETR_START, HT / 2); /* (HT-5)/2 ? */ + wcrt(CRT_ID_LACE_CONTROL, (lace ? 0x20 : 0x00)); + + wcrt(CRT_ID_SCREEN_OFFSET, SCO); + wcrt(CRT_ID_EXT_SYS_CNTL_2, (SCO >> 4) & 0x30 ); + + /* wait for vert sync before cr67 update */ + + for (i=0; i < 10000; i++) { + udelay(10); + mb(); + if (rb_mmio(GREG_INPUT_STATUS1_R) & 0x08) + break; + } + + wl_mmio(0x8200, 0x0000c000); /* fifo control (0x00110400 ?) */ + wcrt(CRT_ID_EXT_MISC_CNTL_2, cr67); + +/* enable video */ + + tmp = rb_mmio(ACT_ADDRESS_RESET); + wb_mmio(ACT_ADDRESS_W, ((bpp == 8) ? 0x20 : 0x00)); /* set b5, ENB PLT in attr idx reg) */ + tmp = rb_mmio(ACT_ADDRESS_RESET); + +/* turn gfx on again */ + + gfx_on_off(0); + +/* pass-through */ + + SetVSwitch(1); /* cv3d */ + + DUMP; + DPRINTK("EXIT\n"); +} + +static inline void gfx_on_off(int toggle) +{ + unsigned char tmp; + + DPRINTK("ENTER gfx %s\n", (toggle ? "off" : "on")); + + toggle = (toggle & 0x01) << 5; + tmp = rseq(SEQ_ID_CLOCKING_MODE) & (~(0x01 << 5)); + wseq(SEQ_ID_CLOCKING_MODE, tmp | toggle); + + DPRINTK("EXIT\n"); +} + +#if defined (VIRGEFBDUMP) + +/* + * Dump board registers + */ + +static void cv64_dump(void) +{ + int i; + u8 c, b; + u16 w; + u32 l; + + /* crt, seq, gfx and atr regs */ + + SelectMMIO; + + printk("\n"); + for (i = 0; i <= 0x6f; i++) { + wb_mmio(CRT_ADDRESS, i); + printk("crt idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(CRT_ADDRESS_R)); + } + for (i = 0; i <= 0x1c; i++) { + wb_mmio(SEQ_ADDRESS, i); + printk("seq idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(SEQ_ADDRESS_R)); + } + for (i = 0; i <= 8; i++) { + wb_mmio(GCT_ADDRESS, i); + printk("gfx idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(GCT_ADDRESS_R)); + } + for (i = 0; i <= 0x14; i++) { + c = rb_mmio(ACT_ADDRESS_RESET); + wb_mmio(ACT_ADDRESS_W, i); + printk("atr idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(ACT_ADDRESS_R)); + } + + /* re-enable video access to palette */ + + c = rb_mmio(ACT_ADDRESS_RESET); + udelay(10); + wb_mmio(ACT_ADDRESS_W, 0x20); + c = rb_mmio(ACT_ADDRESS_RESET); + udelay(10); + + /* general regs */ + + printk("0x3cc(w 0x3c2) : 0x%2.2x\n", rb_mmio(0x3cc)); /* GREG_MISC_OUTPUT READ */ + printk("0x3c2(-------) : 0x%2.2x\n", rb_mmio(0x3c2)); /* GREG_INPUT_STATUS 0 READ */ + printk("0x3c3(w 0x3c3) : 0x%2.2x\n", rb_vgaio(0x3c3)); /* GREG_VIDEO_SUBS_ENABLE */ + printk("0x3ca(w 0x3da) : 0x%2.2x\n", rb_vgaio(0x3ca)); /* GREG_FEATURE_CONTROL read */ + printk("0x3da(-------) : 0x%2.2x\n", rb_mmio(0x3da)); /* GREG_INPUT_STATUS 1 READ */ + + /* engine regs */ + + for (i = 0x8180; i <= 0x8200; i = i + 4) + printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i)); + + i = 0x8504; + printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i)); + i = 0x850c; + printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i)); + for (i = 0xa4d4; i <= 0xa50c; i = i + 4) + printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i)); + + /* PCI regs */ + + SelectCFG; + + for (c = 0; c < 0x08; c = c + 2) { + w = (*((u16 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 2))); + printk("pci 0x%2.2x : 0x%4.4x\n", c, w); + } + c = 8; + l = (*((u32 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000))))); + printk("pci 0x%2.2x : 0x%8.8x\n", c, l); + c = 0x0d; + b = (*((u8 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 3))); + printk("pci 0x%2.2x : 0x%2.2x\n", c, b); + c = 0x10; + l = (*((u32 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000))))); + printk("pci 0x%2.2x : 0x%8.8x\n", c, l); + c = 0x30; + l = (*((u32 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000))))); + printk("pci 0x%2.2x : 0x%8.8x\n", c, l); + c = 0x3c; + b = (*((u8 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 3))); + printk("pci 0x%2.2x : 0x%2.2x\n", c, b); + c = 0x3d; + b = (*((u8 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 3))); + printk("pci 0x%2.2x : 0x%2.2x\n", c, b); + c = 0x3e; + w = (*((u16 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 2))); + printk("pci 0x%2.2x : 0x%4.4x\n", c, w); + SelectMMIO; +} +#endif diff --git a/drivers/video/virgefb.h b/drivers/video/virgefb.h new file mode 100644 index 000000000000..157d66deb244 --- /dev/null +++ b/drivers/video/virgefb.h @@ -0,0 +1,288 @@ +/* + * linux/drivers/video/virgefb.h -- CyberVision64 definitions for the + * text console driver. + * + * Copyright (c) 1998 Alan Bair + * + * This file is based on the initial port to Linux of grf_cvreg.h: + * + * Copyright (c) 1997 Antonio Santos + * + * The original work is from the NetBSD CyberVision 64 framebuffer driver + * and support files (grf_cv.c, grf_cvreg.h, ite_cv.c): + * Permission to use the source of this driver was obtained from the + * author Michael Teske by Alan Bair. + * + * Copyright (c) 1995 Michael Teske + * + * History: + * + * + * + * 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. + */ + +/* Enhanced register mapping (MMIO mode) */ + +#define S3_CRTC_ADR 0x03d4 +#define S3_CRTC_DATA 0x03d5 + +#define S3_REG_LOCK2 0x39 +#define S3_HGC_MODE 0x45 + +#define S3_HWGC_ORGX_H 0x46 +#define S3_HWGC_ORGX_L 0x47 +#define S3_HWGC_ORGY_H 0x48 +#define S3_HWGC_ORGY_L 0x49 +#define S3_HWGC_DX 0x4e +#define S3_HWGC_DY 0x4f + +#define S3_LAW_CTL 0x58 + +/**************************************************/ + +/* + * Defines for the used register addresses (mw) + * + * NOTE: There are some registers that have different addresses when + * in mono or color mode. We only support color mode, and thus + * some addresses won't work in mono-mode! + * + * General and VGA-registers taken from retina driver. Fixed a few + * bugs in it. (SR and GR read address is Port + 1, NOT Port) + * + */ + +/* General Registers: */ +#define GREG_MISC_OUTPUT_R 0x03CC +#define GREG_MISC_OUTPUT_W 0x03C2 +#define GREG_FEATURE_CONTROL_R 0x03CA +#define GREG_FEATURE_CONTROL_W 0x03DA +#define GREG_INPUT_STATUS0_R 0x03C2 +#define GREG_INPUT_STATUS1_R 0x03DA + +/* Setup Registers: */ +#define SREG_VIDEO_SUBS_ENABLE 0x03C3 /* virge */ + +/* Attribute Controller: */ +#define ACT_ADDRESS 0x03C0 +#define ACT_ADDRESS_R 0x03C1 +#define ACT_ADDRESS_W 0x03C0 +#define ACT_ADDRESS_RESET 0x03DA +#define ACT_ID_PALETTE0 0x00 +#define ACT_ID_PALETTE1 0x01 +#define ACT_ID_PALETTE2 0x02 +#define ACT_ID_PALETTE3 0x03 +#define ACT_ID_PALETTE4 0x04 +#define ACT_ID_PALETTE5 0x05 +#define ACT_ID_PALETTE6 0x06 +#define ACT_ID_PALETTE7 0x07 +#define ACT_ID_PALETTE8 0x08 +#define ACT_ID_PALETTE9 0x09 +#define ACT_ID_PALETTE10 0x0A +#define ACT_ID_PALETTE11 0x0B +#define ACT_ID_PALETTE12 0x0C +#define ACT_ID_PALETTE13 0x0D +#define ACT_ID_PALETTE14 0x0E +#define ACT_ID_PALETTE15 0x0F +#define ACT_ID_ATTR_MODE_CNTL 0x10 +#define ACT_ID_OVERSCAN_COLOR 0x11 +#define ACT_ID_COLOR_PLANE_ENA 0x12 +#define ACT_ID_HOR_PEL_PANNING 0x13 +#define ACT_ID_COLOR_SELECT 0x14 /* virge PX_PADD pixel padding register */ + +/* Graphics Controller: */ +#define GCT_ADDRESS 0x03CE +#define GCT_ADDRESS_R 0x03CF +#define GCT_ADDRESS_W 0x03CF +#define GCT_ID_SET_RESET 0x00 +#define GCT_ID_ENABLE_SET_RESET 0x01 +#define GCT_ID_COLOR_COMPARE 0x02 +#define GCT_ID_DATA_ROTATE 0x03 +#define GCT_ID_READ_MAP_SELECT 0x04 +#define GCT_ID_GRAPHICS_MODE 0x05 +#define GCT_ID_MISC 0x06 +#define GCT_ID_COLOR_XCARE 0x07 +#define GCT_ID_BITMASK 0x08 + +/* Sequencer: */ +#define SEQ_ADDRESS 0x03C4 +#define SEQ_ADDRESS_R 0x03C5 +#define SEQ_ADDRESS_W 0x03C5 +#define SEQ_ID_RESET 0x00 +#define SEQ_ID_CLOCKING_MODE 0x01 +#define SEQ_ID_MAP_MASK 0x02 +#define SEQ_ID_CHAR_MAP_SELECT 0x03 +#define SEQ_ID_MEMORY_MODE 0x04 +#define SEQ_ID_UNKNOWN1 0x05 +#define SEQ_ID_UNKNOWN2 0x06 +#define SEQ_ID_UNKNOWN3 0x07 +/* S3 extensions */ +#define SEQ_ID_UNLOCK_EXT 0x08 +#define SEQ_ID_EXT_SEQ_REG9 0x09 /* b7 = 1 extended reg access by MMIO only */ +#define SEQ_ID_BUS_REQ_CNTL 0x0A +#define SEQ_ID_EXT_MISC_SEQ 0x0B +#define SEQ_ID_UNKNOWN4 0x0C +#define SEQ_ID_EXT_SEQ 0x0D +#define SEQ_ID_UNKNOWN5 0x0E +#define SEQ_ID_UNKNOWN6 0x0F +#define SEQ_ID_MCLK_LO 0x10 +#define SEQ_ID_MCLK_HI 0x11 +#define SEQ_ID_DCLK_LO 0x12 +#define SEQ_ID_DCLK_HI 0x13 +#define SEQ_ID_CLKSYN_CNTL_1 0x14 +#define SEQ_ID_CLKSYN_CNTL_2 0x15 +#define SEQ_ID_CLKSYN_TEST_HI 0x16 /* reserved for S3 testing of the */ +#define SEQ_ID_CLKSYN_TEST_LO 0x17 /* internal clock synthesizer */ +#define SEQ_ID_RAMDAC_CNTL 0x18 +#define SEQ_ID_MORE_MAGIC 0x1A +#define SEQ_ID_SIGNAL_SELECT 0x1C /* new for virge */ + +/* CRT Controller: */ +#define CRT_ADDRESS 0x03D4 +#define CRT_ADDRESS_R 0x03D5 +#define CRT_ADDRESS_W 0x03D5 +#define CRT_ID_HOR_TOTAL 0x00 +#define CRT_ID_HOR_DISP_ENA_END 0x01 +#define CRT_ID_START_HOR_BLANK 0x02 +#define CRT_ID_END_HOR_BLANK 0x03 +#define CRT_ID_START_HOR_RETR 0x04 +#define CRT_ID_END_HOR_RETR 0x05 +#define CRT_ID_VER_TOTAL 0x06 +#define CRT_ID_OVERFLOW 0x07 +#define CRT_ID_PRESET_ROW_SCAN 0x08 +#define CRT_ID_MAX_SCAN_LINE 0x09 +#define CRT_ID_CURSOR_START 0x0A +#define CRT_ID_CURSOR_END 0x0B +#define CRT_ID_START_ADDR_HIGH 0x0C +#define CRT_ID_START_ADDR_LOW 0x0D +#define CRT_ID_CURSOR_LOC_HIGH 0x0E +#define CRT_ID_CURSOR_LOC_LOW 0x0F +#define CRT_ID_START_VER_RETR 0x10 +#define CRT_ID_END_VER_RETR 0x11 +#define CRT_ID_VER_DISP_ENA_END 0x12 +#define CRT_ID_SCREEN_OFFSET 0x13 +#define CRT_ID_UNDERLINE_LOC 0x14 +#define CRT_ID_START_VER_BLANK 0x15 +#define CRT_ID_END_VER_BLANK 0x16 +#define CRT_ID_MODE_CONTROL 0x17 +#define CRT_ID_LINE_COMPARE 0x18 +#define CRT_ID_GD_LATCH_RBACK 0x22 +#define CRT_ID_ACT_TOGGLE_RBACK 0x24 +#define CRT_ID_ACT_INDEX_RBACK 0x26 +/* S3 extensions: S3 VGA Registers */ +#define CRT_ID_DEVICE_HIGH 0x2D +#define CRT_ID_DEVICE_LOW 0x2E +#define CRT_ID_REVISION 0x2F +#define CRT_ID_CHIP_ID_REV 0x30 +#define CRT_ID_MEMORY_CONF 0x31 +#define CRT_ID_BACKWAD_COMP_1 0x32 +#define CRT_ID_BACKWAD_COMP_2 0x33 +#define CRT_ID_BACKWAD_COMP_3 0x34 +#define CRT_ID_REGISTER_LOCK 0x35 +#define CRT_ID_CONFIG_1 0x36 +#define CRT_ID_CONFIG_2 0x37 +#define CRT_ID_REGISTER_LOCK_1 0x38 +#define CRT_ID_REGISTER_LOCK_2 0x39 +#define CRT_ID_MISC_1 0x3A +#define CRT_ID_DISPLAY_FIFO 0x3B +#define CRT_ID_LACE_RETR_START 0x3C +/* S3 extensions: System Control Registers */ +#define CRT_ID_SYSTEM_CONFIG 0x40 +#define CRT_ID_BIOS_FLAG 0x41 +#define CRT_ID_LACE_CONTROL 0x42 +#define CRT_ID_EXT_MODE 0x43 +#define CRT_ID_HWGC_MODE 0x45 /* HWGC = Hardware Graphics Cursor */ +#define CRT_ID_HWGC_ORIGIN_X_HI 0x46 +#define CRT_ID_HWGC_ORIGIN_X_LO 0x47 +#define CRT_ID_HWGC_ORIGIN_Y_HI 0x48 +#define CRT_ID_HWGC_ORIGIN_Y_LO 0x49 +#define CRT_ID_HWGC_FG_STACK 0x4A +#define CRT_ID_HWGC_BG_STACK 0x4B +#define CRT_ID_HWGC_START_AD_HI 0x4C +#define CRT_ID_HWGC_START_AD_LO 0x4D +#define CRT_ID_HWGC_DSTART_X 0x4E +#define CRT_ID_HWGC_DSTART_Y 0x4F +/* S3 extensions: System Extension Registers */ +#define CRT_ID_EXT_SYS_CNTL_1 0x50 /* NOT a virge register */ +#define CRT_ID_EXT_SYS_CNTL_2 0x51 +#define CRT_ID_EXT_BIOS_FLAG_1 0x52 +#define CRT_ID_EXT_MEM_CNTL_1 0x53 +#define CRT_ID_EXT_MEM_CNTL_2 0x54 +#define CRT_ID_EXT_DAC_CNTL 0x55 +#define CRT_ID_EX_SYNC_1 0x56 +#define CRT_ID_EX_SYNC_2 0x57 +#define CRT_ID_LAW_CNTL 0x58 /* LAW = Linear Address Window */ +#define CRT_ID_LAW_POS_HI 0x59 +#define CRT_ID_LAW_POS_LO 0x5A +#define CRT_ID_GOUT_PORT 0x5C +#define CRT_ID_EXT_HOR_OVF 0x5D +#define CRT_ID_EXT_VER_OVF 0x5E +#define CRT_ID_EXT_MEM_CNTL_3 0x60 /* NOT a virge register */ +#define CRT_ID_EXT_MEM_CNTL_4 0x61 +#define CRT_ID_EX_SYNC_3 0x63 /* NOT a virge register */ +#define CRT_ID_EXT_MISC_CNTL 0x65 +#define CRT_ID_EXT_MISC_CNTL_1 0x66 +#define CRT_ID_EXT_MISC_CNTL_2 0x67 +#define CRT_ID_CONFIG_3 0x68 +#define CRT_ID_EXT_SYS_CNTL_3 0x69 +#define CRT_ID_EXT_SYS_CNTL_4 0x6A +#define CRT_ID_EXT_BIOS_FLAG_3 0x6B +#define CRT_ID_EXT_BIOS_FLAG_4 0x6C +/* S3 virge extensions: more System Extension Registers */ +#define CRT_ID_EXT_BIOS_FLAG_5 0x6D +#define CRT_ID_EXT_DAC_TEST 0x6E +#define CRT_ID_CONFIG_4 0x6F + +/* Video DAC */ +#define VDAC_ADDRESS 0x03c8 +#define VDAC_ADDRESS_W 0x03c8 +#define VDAC_ADDRESS_R 0x03c7 +#define VDAC_STATE 0x03c7 +#define VDAC_DATA 0x03c9 +#define VDAC_MASK 0x03c6 + +/* Miscellaneous Registers */ +#define MR_SUBSYSTEM_STATUS_R 0x8504 /* new for virge */ +#define MR_SUBSYSTEM_CNTL_W 0x8504 /* new for virge */ +#define MR_ADVANCED_FUNCTION_CONTROL 0x850C /* new for virge */ + +/* Blitter */ +#define BLT_COMMAND_SET 0xA500 +#define BLT_SIZE_X_Y 0xA504 +#define BLT_SRC_X_Y 0xA508 +#define BLT_DEST_X_Y 0xA50C + +#define BLT_SRC_BASE 0xa4d4 +#define BLT_DEST_BASE 0xa4d8 +#define BLT_CLIP_LEFT_RIGHT 0xa4dc +#define BLT_CLIP_TOP_BOTTOM 0xa4e0 +#define BLT_SRC_DEST_STRIDE 0xa4e4 +#define BLT_MONO_PATTERN_0 0xa4e8 +#define BLT_MONO_PATTERN_1 0xa4ec +#define BLT_PATTERN_COLOR 0xa4f4 + +#define L2D_COMMAND_SET 0xA900 +#define L2D_CLIP_LEFT_RIGHT 0xA8DC +#define L2D_CLIP_TOP_BOTTOM 0xA8E0 + +#define P2D_COMMAND_SET 0xAD00 +#define P2D_CLIP_LEFT_RIGHT 0xACDC +#define P2D_CLIP_TOP_BOTTOM 0xACE0 + +#define CMD_NOP (0xf << 27) /* %1111 << 27, was 0x07 */ +#define S3V_BITBLT (0x0 << 27) +#define S3V_RECTFILL (0x2 << 27) +#define S3V_AUTOEXE 0x01 +#define S3V_HWCLIP 0x02 +#define S3V_DRAW 0x20 +#define S3V_DST_8BPP 0x00 +#define S3V_DST_16BPP 0x04 +#define S3V_DST_24BPP 0x08 +#define S3V_MONO_PAT 0x100 + +#define S3V_BLT_COPY (0xcc<<17) +#define S3V_BLT_CLEAR (0x00<<17) +#define S3V_BLT_SET (0xff<<17) diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c new file mode 100644 index 000000000000..057e154c8858 --- /dev/null +++ b/drivers/video/w100fb.c @@ -0,0 +1,1873 @@ +/* + * linux/drivers/video/w100fb.c + * + * Frame Buffer Device for ATI Imageon w100 (Wallaby) + * + * Copyright (C) 2002, ATI Corp. + * Copyright (C) 2004-2005 Richard Purdie + * + * Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/device.h> +#include <linux/string.h> +#include <linux/proc_fs.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <video/w100fb.h> +#include "w100fb.h" + +/* + * Prototypes + */ +static void w100fb_save_buffer(void); +static void w100fb_clear_buffer(void); +static void w100fb_restore_buffer(void); +static void w100fb_clear_screen(u32 mode, long int offset); +static void w100_resume(void); +static void w100_suspend(u32 mode); +static void w100_init_qvga_rotation(u16 deg); +static void w100_init_vga_rotation(u16 deg); +static void w100_vsync(void); +static void w100_init_sharp_lcd(u32 mode); +static void w100_pwm_setup(void); +static void w100_InitExtMem(u32 mode); +static void w100_hw_init(void); +static u16 w100_set_fastsysclk(u16 Freq); + +static void lcdtg_hw_init(u32 mode); +static void lcdtg_lcd_change(u32 mode); +static void lcdtg_resume(void); +static void lcdtg_suspend(void); + + +/* Register offsets & lengths */ +#define REMAPPED_FB_LEN 0x15ffff + +#define BITS_PER_PIXEL 16 + +/* Pseudo palette size */ +#define MAX_PALETTES 16 + +/* for resolution change */ +#define LCD_MODE_INIT (-1) +#define LCD_MODE_480 0 +#define LCD_MODE_320 1 +#define LCD_MODE_240 2 +#define LCD_MODE_640 3 + +#define LCD_SHARP_QVGA 0 +#define LCD_SHARP_VGA 1 + +#define LCD_MODE_PORTRAIT 0 +#define LCD_MODE_LANDSCAPE 1 + +#define W100_SUSPEND_EXTMEM 0 +#define W100_SUSPEND_ALL 1 + +/* General frame buffer data structures */ +struct w100fb_par { + u32 xres; + u32 yres; + int fastsysclk_mode; + int lcdMode; + int rotation_flag; + int blanking_flag; + int comadj; + int phadadj; +}; + +static struct w100fb_par *current_par; + +/* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */ +static void *remapped_base; +static void *remapped_regs; +static void *remapped_fbuf; + +/* External Function */ +static void(*w100fb_ssp_send)(u8 adrs, u8 data); + +/* + * Sysfs functions + */ + +static ssize_t rotation_show(struct device *dev, char *buf) +{ + struct fb_info *info = dev_get_drvdata(dev); + struct w100fb_par *par=info->par; + + return sprintf(buf, "%d\n",par->rotation_flag); +} + +static ssize_t rotation_store(struct device *dev, const char *buf, size_t count) +{ + unsigned int rotate; + struct fb_info *info = dev_get_drvdata(dev); + struct w100fb_par *par=info->par; + + rotate = simple_strtoul(buf, NULL, 10); + + if (rotate > 0) par->rotation_flag = 1; + else par->rotation_flag = 0; + + if (par->lcdMode == LCD_MODE_320) + w100_init_qvga_rotation(par->rotation_flag ? 270 : 90); + else if (par->lcdMode == LCD_MODE_240) + w100_init_qvga_rotation(par->rotation_flag ? 180 : 0); + else if (par->lcdMode == LCD_MODE_640) + w100_init_vga_rotation(par->rotation_flag ? 270 : 90); + else if (par->lcdMode == LCD_MODE_480) + w100_init_vga_rotation(par->rotation_flag ? 180 : 0); + + return count; +} + +static DEVICE_ATTR(rotation, 0644, rotation_show, rotation_store); + +static ssize_t w100fb_reg_read(struct device *dev, const char *buf, size_t count) +{ + unsigned long param; + unsigned long regs; + regs = simple_strtoul(buf, NULL, 16); + param = readl(remapped_regs + regs); + printk("Read Register 0x%08lX: 0x%08lX\n", regs, param); + return count; +} + +static DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read); + +static ssize_t w100fb_reg_write(struct device *dev, const char *buf, size_t count) +{ + unsigned long regs; + unsigned long param; + sscanf(buf, "%lx %lx", ®s, ¶m); + + if (regs <= 0x2000) { + printk("Write Register 0x%08lX: 0x%08lX\n", regs, param); + writel(param, remapped_regs + regs); + } + + return count; +} + +static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write); + + +static ssize_t fastsysclk_show(struct device *dev, char *buf) +{ + struct fb_info *info = dev_get_drvdata(dev); + struct w100fb_par *par=info->par; + + return sprintf(buf, "%d\n",par->fastsysclk_mode); +} + +static ssize_t fastsysclk_store(struct device *dev, const char *buf, size_t count) +{ + int param; + struct fb_info *info = dev_get_drvdata(dev); + struct w100fb_par *par=info->par; + + param = simple_strtoul(buf, NULL, 10); + + if (param == 75) { + printk("Set fastsysclk %d\n", param); + par->fastsysclk_mode = param; + w100_set_fastsysclk(par->fastsysclk_mode); + } else if (param == 100) { + printk("Set fastsysclk %d\n", param); + par->fastsysclk_mode = param; + w100_set_fastsysclk(par->fastsysclk_mode); + } + return count; +} + +static DEVICE_ATTR(fastsysclk, 0644, fastsysclk_show, fastsysclk_store); + +/* + * The touchscreen on this device needs certain information + * from the video driver to function correctly. We export it here. + */ +int w100fb_get_xres(void) { + return current_par->xres; +} + +int w100fb_get_blanking(void) { + return current_par->blanking_flag; +} + +int w100fb_get_fastsysclk(void) { + return current_par->fastsysclk_mode; +} +EXPORT_SYMBOL(w100fb_get_xres); +EXPORT_SYMBOL(w100fb_get_blanking); +EXPORT_SYMBOL(w100fb_get_fastsysclk); + + +/* + * Set a palette value from rgb components + */ +static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int trans, struct fb_info *info) +{ + unsigned int val; + int ret = 1; + + /* + * If greyscale is true, then we convert the RGB value + * to greyscale no matter what visual we are using. + */ + if (info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16; + + /* + * 16-bit True Colour. We encode the RGB value + * according to the RGB bitfield information. + */ + if (regno < MAX_PALETTES) { + + u32 *pal = info->pseudo_palette; + + val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); + pal[regno] = val; + ret = 0; + } + return ret; +} + + +/* + * Blank the display based on value in blank_mode + */ +static int w100fb_blank(int blank_mode, struct fb_info *info) +{ + struct w100fb_par *par; + par=info->par; + + switch(blank_mode) { + + case FB_BLANK_NORMAL: /* Normal blanking */ + case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ + case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ + case FB_BLANK_POWERDOWN: /* Poweroff */ + if (par->blanking_flag == 0) { + w100fb_save_buffer(); + lcdtg_suspend(); + par->blanking_flag = 1; + } + break; + + case FB_BLANK_UNBLANK: /* Unblanking */ + if (par->blanking_flag != 0) { + w100fb_restore_buffer(); + lcdtg_resume(); + par->blanking_flag = 0; + } + break; + } + return 0; +} + +/* + * Change the resolution by calling the appropriate hardware functions + */ +static void w100fb_changeres(int rotate_mode, u32 mode) +{ + u16 rotation=0; + + switch(rotate_mode) { + case LCD_MODE_LANDSCAPE: + rotation=(current_par->rotation_flag ? 270 : 90); + break; + case LCD_MODE_PORTRAIT: + rotation=(current_par->rotation_flag ? 180 : 0); + break; + } + + w100_pwm_setup(); + switch(mode) { + case LCD_SHARP_QVGA: + w100_vsync(); + w100_suspend(W100_SUSPEND_EXTMEM); + w100_init_sharp_lcd(LCD_SHARP_QVGA); + w100_init_qvga_rotation(rotation); + w100_InitExtMem(LCD_SHARP_QVGA); + w100fb_clear_screen(LCD_SHARP_QVGA, 0); + lcdtg_lcd_change(LCD_SHARP_QVGA); + break; + case LCD_SHARP_VGA: + w100fb_clear_screen(LCD_SHARP_QVGA, 0); + writel(0xBFFFA000, remapped_regs + mmMC_EXT_MEM_LOCATION); + w100_InitExtMem(LCD_SHARP_VGA); + w100fb_clear_screen(LCD_SHARP_VGA, 0x200000); + w100_vsync(); + w100_init_sharp_lcd(LCD_SHARP_VGA); + if (rotation != 0) + w100_init_vga_rotation(rotation); + lcdtg_lcd_change(LCD_SHARP_VGA); + break; + } +} + +/* + * Set up the display for the fb subsystem + */ +static void w100fb_activate_var(struct fb_info *info) +{ + u32 temp32; + struct w100fb_par *par=info->par; + struct fb_var_screeninfo *var = &info->var; + + /* Set the hardware to 565 */ + temp32 = readl(remapped_regs + mmDISP_DEBUG2); + temp32 &= 0xff7fffff; + temp32 |= 0x00800000; + writel(temp32, remapped_regs + mmDISP_DEBUG2); + + if (par->lcdMode == LCD_MODE_INIT) { + w100_init_sharp_lcd(LCD_SHARP_VGA); + w100_init_vga_rotation(par->rotation_flag ? 270 : 90); + par->lcdMode = LCD_MODE_640; + lcdtg_hw_init(LCD_SHARP_VGA); + } else if (var->xres == 320 && var->yres == 240) { + if (par->lcdMode != LCD_MODE_320) { + w100fb_changeres(LCD_MODE_LANDSCAPE, LCD_SHARP_QVGA); + par->lcdMode = LCD_MODE_320; + } + } else if (var->xres == 240 && var->yres == 320) { + if (par->lcdMode != LCD_MODE_240) { + w100fb_changeres(LCD_MODE_PORTRAIT, LCD_SHARP_QVGA); + par->lcdMode = LCD_MODE_240; + } + } else if (var->xres == 640 && var->yres == 480) { + if (par->lcdMode != LCD_MODE_640) { + w100fb_changeres(LCD_MODE_LANDSCAPE, LCD_SHARP_VGA); + par->lcdMode = LCD_MODE_640; + } + } else if (var->xres == 480 && var->yres == 640) { + if (par->lcdMode != LCD_MODE_480) { + w100fb_changeres(LCD_MODE_PORTRAIT, LCD_SHARP_VGA); + par->lcdMode = LCD_MODE_480; + } + } else printk(KERN_ERR "W100FB: Resolution error!\n"); +} + + +/* + * w100fb_check_var(): + * Get the video params out of 'var'. If a value doesn't fit, round it up, + * if it's too big, return -EINVAL. + * + */ +static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + if (var->xres < var->yres) { /* Portrait mode */ + if ((var->xres > 480) || (var->yres > 640)) { + return -EINVAL; + } else if ((var->xres > 240) || (var->yres > 320)) { + var->xres = 480; + var->yres = 640; + } else { + var->xres = 240; + var->yres = 320; + } + } else { /* Landscape mode */ + if ((var->xres > 640) || (var->yres > 480)) { + return -EINVAL; + } else if ((var->xres > 320) || (var->yres > 240)) { + var->xres = 640; + var->yres = 480; + } else { + var->xres = 320; + var->yres = 240; + } + } + + var->xres_virtual = max(var->xres_virtual, var->xres); + var->yres_virtual = max(var->yres_virtual, var->yres); + + if (var->bits_per_pixel > BITS_PER_PIXEL) + return -EINVAL; + else + var->bits_per_pixel = BITS_PER_PIXEL; + + 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 = var->transp.length = 0; + + var->nonstd = 0; + + var->height = -1; + var->width = -1; + var->vmode = FB_VMODE_NONINTERLACED; + + var->sync = 0; + var->pixclock = 0x04; /* 171521; */ + + return 0; +} + + +/* + * w100fb_set_par(): + * Set the user defined part of the display for the specified console + * by looking at the values in info.var + */ +static int w100fb_set_par(struct fb_info *info) +{ + struct w100fb_par *par=info->par; + + par->xres = info->var.xres; + par->yres = info->var.yres; + + info->fix.visual = FB_VISUAL_TRUECOLOR; + + info->fix.ypanstep = 0; + info->fix.ywrapstep = 0; + + if (par->blanking_flag) + w100fb_clear_buffer(); + + w100fb_activate_var(info); + + if (par->lcdMode == LCD_MODE_480) { + info->fix.line_length = (480 * BITS_PER_PIXEL) / 8; + info->fix.smem_len = 0x200000; + } else if (par->lcdMode == LCD_MODE_320) { + info->fix.line_length = (320 * BITS_PER_PIXEL) / 8; + info->fix.smem_len = 0x60000; + } else if (par->lcdMode == LCD_MODE_240) { + info->fix.line_length = (240 * BITS_PER_PIXEL) / 8; + info->fix.smem_len = 0x60000; + } else if (par->lcdMode == LCD_MODE_INIT || par->lcdMode == LCD_MODE_640) { + info->fix.line_length = (640 * BITS_PER_PIXEL) / 8; + info->fix.smem_len = 0x200000; + } + + return 0; +} + + +/* + * Frame buffer operations + */ +static struct fb_ops w100fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = w100fb_check_var, + .fb_set_par = w100fb_set_par, + .fb_setcolreg = w100fb_setcolreg, + .fb_blank = w100fb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + + +static void w100fb_clear_screen(u32 mode, long int offset) +{ + int i, numPix = 0; + + if (mode == LCD_SHARP_VGA) + numPix = 640 * 480; + else if (mode == LCD_SHARP_QVGA) + numPix = 320 * 240; + + for (i = 0; i < numPix; i++) + writew(0xffff, remapped_fbuf + offset + (2*i)); +} + + +/* Need to split up the buffers to stay within the limits of kmalloc */ +#define W100_BUF_NUM 6 +static uint32_t *gSaveImagePtr[W100_BUF_NUM] = { NULL }; + +static void w100fb_save_buffer(void) +{ + int i, j, bufsize; + + bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM; + for (i = 0; i < W100_BUF_NUM; i++) { + if (gSaveImagePtr[i] == NULL) + gSaveImagePtr[i] = kmalloc(bufsize, GFP_KERNEL); + if (gSaveImagePtr[i] == NULL) { + w100fb_clear_buffer(); + printk(KERN_WARNING "can't alloc pre-off image buffer %d\n", i); + break; + } + for (j = 0; j < bufsize/4; j++) + *(gSaveImagePtr[i] + j) = readl(remapped_fbuf + (bufsize*i) + j*4); + } +} + + +static void w100fb_restore_buffer(void) +{ + int i, j, bufsize; + + bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM; + for (i = 0; i < W100_BUF_NUM; i++) { + if (gSaveImagePtr[i] == NULL) { + printk(KERN_WARNING "can't find pre-off image buffer %d\n", i); + w100fb_clear_buffer(); + break; + } + for (j = 0; j < (bufsize/4); j++) + writel(*(gSaveImagePtr[i] + j),remapped_fbuf + (bufsize*i) + (j*4)); + kfree(gSaveImagePtr[i]); + gSaveImagePtr[i] = NULL; + } +} + + +static void w100fb_clear_buffer(void) +{ + int i; + for (i = 0; i < W100_BUF_NUM; i++) { + kfree(gSaveImagePtr[i]); + gSaveImagePtr[i] = NULL; + } +} + + +#ifdef CONFIG_PM +static int w100fb_suspend(struct device *dev, u32 state, u32 level) +{ + if (level == SUSPEND_POWER_DOWN) { + struct fb_info *info = dev_get_drvdata(dev); + struct w100fb_par *par=info->par; + + w100fb_save_buffer(); + lcdtg_suspend(); + w100_suspend(W100_SUSPEND_ALL); + par->blanking_flag = 1; + } + return 0; +} + +static int w100fb_resume(struct device *dev, u32 level) +{ + if (level == RESUME_POWER_ON) { + struct fb_info *info = dev_get_drvdata(dev); + struct w100fb_par *par=info->par; + + w100_resume(); + w100fb_restore_buffer(); + lcdtg_resume(); + par->blanking_flag = 0; + } + return 0; +} +#else +#define w100fb_suspend NULL +#define w100fb_resume NULL +#endif + + +int __init w100fb_probe(struct device *dev) +{ + struct w100fb_mach_info *inf; + struct fb_info *info; + struct w100fb_par *par; + struct platform_device *pdev = to_platform_device(dev); + struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!mem) + return -EINVAL; + + /* remap the areas we're going to use */ + remapped_base = ioremap_nocache(mem->start+W100_CFG_BASE, W100_CFG_LEN); + if (remapped_base == NULL) + return -EIO; + + remapped_regs = ioremap_nocache(mem->start+W100_REG_BASE, W100_REG_LEN); + if (remapped_regs == NULL) { + iounmap(remapped_base); + return -EIO; + } + + remapped_fbuf = ioremap_nocache(mem->start+MEM_EXT_BASE_VALUE, REMAPPED_FB_LEN); + if (remapped_fbuf == NULL) { + iounmap(remapped_base); + iounmap(remapped_regs); + return -EIO; + } + + info=framebuffer_alloc(sizeof(struct w100fb_par), dev); + if (!info) { + iounmap(remapped_base); + iounmap(remapped_regs); + iounmap(remapped_fbuf); + return -ENOMEM; + } + + info->device=dev; + par = info->par; + current_par=info->par; + dev_set_drvdata(dev, info); + + inf = dev->platform_data; + par->phadadj = inf->phadadj; + par->comadj = inf->comadj; + par->fastsysclk_mode = 75; + par->lcdMode = LCD_MODE_INIT; + par->rotation_flag=0; + par->blanking_flag=0; + w100fb_ssp_send = inf->w100fb_ssp_send; + + w100_hw_init(); + w100_pwm_setup(); + + info->pseudo_palette = kmalloc(sizeof (u32) * MAX_PALETTES, GFP_KERNEL); + if (!info->pseudo_palette) { + iounmap(remapped_base); + iounmap(remapped_regs); + iounmap(remapped_fbuf); + return -ENOMEM; + } + + info->fbops = &w100fb_ops; + info->flags = FBINFO_DEFAULT; + info->node = -1; + info->screen_base = remapped_fbuf; + info->screen_size = REMAPPED_FB_LEN; + + info->var.xres = 640; + info->var.xres_virtual = info->var.xres; + info->var.yres = 480; + info->var.yres_virtual = info->var.yres; + info->var.pixclock = 0x04; /* 171521; */ + info->var.sync = 0; + info->var.grayscale = 0; + info->var.xoffset = info->var.yoffset = 0; + info->var.accel_flags = 0; + info->var.activate = FB_ACTIVATE_NOW; + + strcpy(info->fix.id, "w100fb"); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + info->fix.accel = FB_ACCEL_NONE; + info->fix.smem_start = mem->start+MEM_EXT_BASE_VALUE; + info->fix.mmio_start = mem->start+W100_REG_BASE; + info->fix.mmio_len = W100_REG_LEN; + + w100fb_check_var(&info->var, info); + w100fb_set_par(info); + + if (register_framebuffer(info) < 0) { + kfree(info->pseudo_palette); + iounmap(remapped_base); + iounmap(remapped_regs); + iounmap(remapped_fbuf); + return -EINVAL; + } + + device_create_file(dev, &dev_attr_fastsysclk); + device_create_file(dev, &dev_attr_reg_read); + device_create_file(dev, &dev_attr_reg_write); + device_create_file(dev, &dev_attr_rotation); + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); + return 0; +} + + +static int w100fb_remove(struct device *dev) +{ + struct fb_info *info = dev_get_drvdata(dev); + + device_remove_file(dev, &dev_attr_fastsysclk); + device_remove_file(dev, &dev_attr_reg_read); + device_remove_file(dev, &dev_attr_reg_write); + device_remove_file(dev, &dev_attr_rotation); + + unregister_framebuffer(info); + + w100fb_clear_buffer(); + kfree(info->pseudo_palette); + + iounmap(remapped_base); + iounmap(remapped_regs); + iounmap(remapped_fbuf); + + framebuffer_release(info); + + return 0; +} + + +/* ------------------- chipset specific functions -------------------------- */ + + +static void w100_soft_reset(void) +{ + u16 val = readw((u16 *) remapped_base + cfgSTATUS); + writew(val | 0x08, (u16 *) remapped_base + cfgSTATUS); + udelay(100); + writew(0x00, (u16 *) remapped_base + cfgSTATUS); + udelay(100); +} + +/* + * Initialization of critical w100 hardware + */ +static void w100_hw_init(void) +{ + u32 temp32; + union cif_cntl_u cif_cntl; + union intf_cntl_u intf_cntl; + union cfgreg_base_u cfgreg_base; + union wrap_top_dir_u wrap_top_dir; + union cif_read_dbg_u cif_read_dbg; + union cpu_defaults_u cpu_default; + union cif_write_dbg_u cif_write_dbg; + union wrap_start_dir_u wrap_start_dir; + union mc_ext_mem_location_u mc_ext_mem_loc; + union cif_io_u cif_io; + + w100_soft_reset(); + + /* This is what the fpga_init code does on reset. May be wrong + but there is little info available */ + writel(0x31, remapped_regs + mmSCRATCH_UMSK); + for (temp32 = 0; temp32 < 10000; temp32++) + readl(remapped_regs + mmSCRATCH_UMSK); + writel(0x30, remapped_regs + mmSCRATCH_UMSK); + + /* Set up CIF */ + cif_io.val = defCIF_IO; + writel((u32)(cif_io.val), remapped_regs + mmCIF_IO); + + cif_write_dbg.val = readl(remapped_regs + mmCIF_WRITE_DBG); + cif_write_dbg.f.dis_packer_ful_during_rbbm_timeout = 0; + cif_write_dbg.f.en_dword_split_to_rbbm = 1; + cif_write_dbg.f.dis_timeout_during_rbbm = 1; + writel((u32) (cif_write_dbg.val), remapped_regs + mmCIF_WRITE_DBG); + + cif_read_dbg.val = readl(remapped_regs + mmCIF_READ_DBG); + cif_read_dbg.f.dis_rd_same_byte_to_trig_fetch = 1; + writel((u32) (cif_read_dbg.val), remapped_regs + mmCIF_READ_DBG); + + cif_cntl.val = readl(remapped_regs + mmCIF_CNTL); + cif_cntl.f.dis_system_bits = 1; + cif_cntl.f.dis_mr = 1; + cif_cntl.f.en_wait_to_compensate_dq_prop_dly = 0; + cif_cntl.f.intb_oe = 1; + cif_cntl.f.interrupt_active_high = 1; + writel((u32) (cif_cntl.val), remapped_regs + mmCIF_CNTL); + + /* Setup cfgINTF_CNTL and cfgCPU defaults */ + intf_cntl.val = defINTF_CNTL; + intf_cntl.f.ad_inc_a = 1; + intf_cntl.f.ad_inc_b = 1; + intf_cntl.f.rd_data_rdy_a = 0; + intf_cntl.f.rd_data_rdy_b = 0; + writeb((u8) (intf_cntl.val), remapped_base + cfgINTF_CNTL); + + cpu_default.val = defCPU_DEFAULTS; + cpu_default.f.access_ind_addr_a = 1; + cpu_default.f.access_ind_addr_b = 1; + cpu_default.f.access_scratch_reg = 1; + cpu_default.f.transition_size = 0; + writeb((u8) (cpu_default.val), remapped_base + cfgCPU_DEFAULTS); + + /* set up the apertures */ + writeb((u8) (W100_REG_BASE >> 16), remapped_base + cfgREG_BASE); + + cfgreg_base.val = defCFGREG_BASE; + cfgreg_base.f.cfgreg_base = W100_CFG_BASE; + writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE); + + /* This location is relative to internal w100 addresses */ + writel(0x15FF1000, remapped_regs + mmMC_FB_LOCATION); + + mc_ext_mem_loc.val = defMC_EXT_MEM_LOCATION; + mc_ext_mem_loc.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8; + mc_ext_mem_loc.f.mc_ext_mem_top = MEM_EXT_TOP_VALUE >> 8; + writel((u32) (mc_ext_mem_loc.val), remapped_regs + mmMC_EXT_MEM_LOCATION); + + if ((current_par->lcdMode == LCD_MODE_240) || (current_par->lcdMode == LCD_MODE_320)) + w100_InitExtMem(LCD_SHARP_QVGA); + else + w100_InitExtMem(LCD_SHARP_VGA); + + wrap_start_dir.val = defWRAP_START_DIR; + wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1; + writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR); + + wrap_top_dir.val = defWRAP_TOP_DIR; + wrap_top_dir.f.top_addr = WRAP_BUF_TOP_VALUE >> 1; + writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR); + + writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL); +} + + +/* + * Types + */ + +struct pll_parm { + u16 freq; /* desired Fout for PLL */ + u8 M; + u8 N_int; + u8 N_fac; + u8 tfgoal; + u8 lock_time; +}; + +struct power_state { + union clk_pin_cntl_u clk_pin_cntl; + union pll_ref_fb_div_u pll_ref_fb_div; + union pll_cntl_u pll_cntl; + union sclk_cntl_u sclk_cntl; + union pclk_cntl_u pclk_cntl; + union clk_test_cntl_u clk_test_cntl; + union pwrmgt_cntl_u pwrmgt_cntl; + u32 freq; /* Fout for PLL calibration */ + u8 tf100; /* for pll calibration */ + u8 tf80; /* for pll calibration */ + u8 tf20; /* for pll calibration */ + u8 M; /* for pll calibration */ + u8 N_int; /* for pll calibration */ + u8 N_fac; /* for pll calibration */ + u8 lock_time; /* for pll calibration */ + u8 tfgoal; /* for pll calibration */ + u8 auto_mode; /* hardware auto switch? */ + u8 pwm_mode; /* 0 fast, 1 normal/slow */ + u16 fast_sclk; /* fast clk freq */ + u16 norm_sclk; /* slow clk freq */ +}; + + +/* + * Global state variables + */ + +static struct power_state w100_pwr_state; + +/* This table is specific for 12.5MHz ref crystal. */ +static struct pll_parm gPLLTable[] = { + /*freq M N_int N_fac tfgoal lock_time */ + { 50, 0, 1, 0, 0xE0, 56}, /* 50.00 MHz */ + { 75, 0, 5, 0, 0xDE, 37}, /* 75.00 MHz */ + {100, 0, 7, 0, 0xE0, 28}, /* 100.00 MHz */ + {125, 0, 9, 0, 0xE0, 22}, /* 125.00 MHz */ + {150, 0, 11, 0, 0xE0, 17}, /* 150.00 MHz */ + { 0, 0, 0, 0, 0, 0} /* Terminator */ +}; + + +static u8 w100_pll_get_testcount(u8 testclk_sel) +{ + udelay(5); + + w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0; + w100_pwr_state.clk_test_cntl.f.testclk_sel = testclk_sel; + w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x1; /*reset test count */ + writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL); + w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x0; + writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL); + + w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x1; + writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL); + + udelay(20); + + w100_pwr_state.clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL); + w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0; + writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL); + + return w100_pwr_state.clk_test_cntl.f.test_count; +} + + +static u8 w100_pll_adjust(void) +{ + do { + /* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V + * therefore, commented out the following lines + * tf80 meant tf100 + * set VCO input = 0.8 * VDD + */ + w100_pwr_state.pll_cntl.f.pll_dactal = 0xd; + writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); + + w100_pwr_state.tf80 = w100_pll_get_testcount(0x1); /* PLLCLK */ + if (w100_pwr_state.tf80 >= (w100_pwr_state.tfgoal)) { + /* set VCO input = 0.2 * VDD */ + w100_pwr_state.pll_cntl.f.pll_dactal = 0x7; + writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); + + w100_pwr_state.tf20 = w100_pll_get_testcount(0x1); /* PLLCLK */ + if (w100_pwr_state.tf20 <= (w100_pwr_state.tfgoal)) + return 1; // Success + + if ((w100_pwr_state.pll_cntl.f.pll_vcofr == 0x0) && + ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) || + (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) { + /* slow VCO config */ + w100_pwr_state.pll_cntl.f.pll_vcofr = 0x1; + w100_pwr_state.pll_cntl.f.pll_pvg = 0x0; + w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; + writel((u32) (w100_pwr_state.pll_cntl.val), + remapped_regs + mmPLL_CNTL); + continue; + } + } + if ((w100_pwr_state.pll_cntl.f.pll_ioffset) < 0x3) { + w100_pwr_state.pll_cntl.f.pll_ioffset += 0x1; + writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); + continue; + } + if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) { + w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; + w100_pwr_state.pll_cntl.f.pll_pvg += 0x1; + writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); + continue; + } + return 0; // error + } while(1); +} + + +/* + * w100_pll_calibration + * freq = target frequency of the PLL + * (note: crystal = 14.3MHz) + */ +static u8 w100_pll_calibration(u32 freq) +{ + u8 status; + + /* initial setting */ + w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0; /* power down */ + w100_pwr_state.pll_cntl.f.pll_reset = 0x0; /* not reset */ + w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1; /* Hi-Z */ + w100_pwr_state.pll_cntl.f.pll_pvg = 0x0; /* VCO gain = 0 */ + w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0; /* VCO frequency range control = off */ + w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; /* current offset inside VCO = 0 */ + w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0; + writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); + + /* check for (tf80 >= tfgoal) && (tf20 =< tfgoal) */ + if ((w100_pwr_state.tf80 < w100_pwr_state.tfgoal) || (w100_pwr_state.tf20 > w100_pwr_state.tfgoal)) { + status=w100_pll_adjust(); + } + /* PLL Reset And Lock */ + + /* set VCO input = 0.5 * VDD */ + w100_pwr_state.pll_cntl.f.pll_dactal = 0xa; + writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); + + /* reset time */ + udelay(1); + + /* enable charge pump */ + w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0; /* normal */ + writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); + + /* set VCO input = Hi-Z */ + /* disable DAC */ + w100_pwr_state.pll_cntl.f.pll_dactal = 0x0; + writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); + + /* lock time */ + udelay(400); /* delay 400 us */ + + /* PLL locked */ + + w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x1; /* PLL clock */ + writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL); + + w100_pwr_state.tf100 = w100_pll_get_testcount(0x1); /* PLLCLK */ + + return status; +} + + +static u8 w100_pll_set_clk(void) +{ + u8 status; + + if (w100_pwr_state.auto_mode == 1) /* auto mode */ + { + w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0; /* disable fast to normal */ + w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0; /* disable normal to fast */ + writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL); + } + + w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0; /* crystal clock */ + writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL); + + w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = w100_pwr_state.M; + w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = w100_pwr_state.N_int; + w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = w100_pwr_state.N_fac; + w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = w100_pwr_state.lock_time; + writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV); + + w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0; + writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL); + + status = w100_pll_calibration (w100_pwr_state.freq); + + if (w100_pwr_state.auto_mode == 1) /* auto mode */ + { + w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1; /* reenable fast to normal */ + w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1; /* reenable normal to fast */ + writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL); + } + return status; +} + + +/* assume reference crystal clk is 12.5MHz, + * and that doubling is not enabled. + * + * Freq = 12 == 12.5MHz. + */ +static u16 w100_set_slowsysclk(u16 freq) +{ + if (w100_pwr_state.norm_sclk == freq) + return freq; + + if (w100_pwr_state.auto_mode == 1) /* auto mode */ + return 0; + + if (freq == 12) { + w100_pwr_state.norm_sclk = freq; + w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0; /* Pslow = 1 */ + w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0; /* crystal src */ + + writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL); + + w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x1; + writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL); + + w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x1; + w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1; + writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL); + w100_pwr_state.pwm_mode = 1; /* normal mode */ + return freq; + } else + return 0; +} + + +static u16 w100_set_fastsysclk(u16 freq) +{ + u16 pll_freq; + int i; + + while(1) { + pll_freq = (u16) (freq * (w100_pwr_state.sclk_cntl.f.sclk_post_div_fast + 1)); + i = 0; + do { + if (pll_freq == gPLLTable[i].freq) { + w100_pwr_state.freq = gPLLTable[i].freq * 1000000; + w100_pwr_state.M = gPLLTable[i].M; + w100_pwr_state.N_int = gPLLTable[i].N_int; + w100_pwr_state.N_fac = gPLLTable[i].N_fac; + w100_pwr_state.tfgoal = gPLLTable[i].tfgoal; + w100_pwr_state.lock_time = gPLLTable[i].lock_time; + w100_pwr_state.tf20 = 0xff; /* set highest */ + w100_pwr_state.tf80 = 0x00; /* set lowest */ + + w100_pll_set_clk(); + w100_pwr_state.pwm_mode = 0; /* fast mode */ + w100_pwr_state.fast_sclk = freq; + return freq; + } + i++; + } while(gPLLTable[i].freq); + + if (w100_pwr_state.auto_mode == 1) + break; + + if (w100_pwr_state.sclk_cntl.f.sclk_post_div_fast == 0) + break; + + w100_pwr_state.sclk_cntl.f.sclk_post_div_fast -= 1; + writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL); + } + return 0; +} + + +/* Set up an initial state. Some values/fields set + here will be overwritten. */ +static void w100_pwm_setup(void) +{ + w100_pwr_state.clk_pin_cntl.f.osc_en = 0x1; + w100_pwr_state.clk_pin_cntl.f.osc_gain = 0x1f; + w100_pwr_state.clk_pin_cntl.f.dont_use_xtalin = 0x0; + w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x0; + w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = 0x0; /* no freq doubling */ + w100_pwr_state.clk_pin_cntl.f.cg_debug = 0x0; + writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL); + + w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0; /* Crystal Clk */ + w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0; /* Pfast = 1 */ + w100_pwr_state.sclk_cntl.f.sclk_clkon_hys = 0x3; + w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0; /* Pslow = 1 */ + w100_pwr_state.sclk_cntl.f.disp_cg_ok2switch_en = 0x0; + w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0; /* Dynamic */ + w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0; /* Dynamic */ + w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0; /* Dynamic */ + w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0; /* Dynamic */ + w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0; /* Dynamic */ + w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0; /* Dynamic */ + w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0; /* Dynamic */ + w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0; /* Dynamic */ + w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0; /* Dynamic */ + w100_pwr_state.sclk_cntl.f.busy_extend_cp = 0x0; + w100_pwr_state.sclk_cntl.f.busy_extend_e2 = 0x0; + w100_pwr_state.sclk_cntl.f.busy_extend_e3 = 0x0; + w100_pwr_state.sclk_cntl.f.busy_extend_idct = 0x0; + writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL); + + w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x0; /* Crystal Clk */ + w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1; /* P = 2 */ + w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0; /* Dynamic */ + writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL); + + w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0; /* M = 1 */ + w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0; /* N = 1.0 */ + w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = 0x0; + w100_pwr_state.pll_ref_fb_div.f.pll_reset_time = 0x5; + w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = 0xff; + writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV); + + w100_pwr_state.pll_cntl.f.pll_pwdn = 0x1; + w100_pwr_state.pll_cntl.f.pll_reset = 0x1; + w100_pwr_state.pll_cntl.f.pll_pm_en = 0x0; + w100_pwr_state.pll_cntl.f.pll_mode = 0x0; /* uses VCO clock */ + w100_pwr_state.pll_cntl.f.pll_refclk_sel = 0x0; + w100_pwr_state.pll_cntl.f.pll_fbclk_sel = 0x0; + w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0; + w100_pwr_state.pll_cntl.f.pll_pcp = 0x4; + w100_pwr_state.pll_cntl.f.pll_pvg = 0x0; + w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0; + w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; + w100_pwr_state.pll_cntl.f.pll_pecc_mode = 0x0; + w100_pwr_state.pll_cntl.f.pll_pecc_scon = 0x0; + w100_pwr_state.pll_cntl.f.pll_dactal = 0x0; /* Hi-Z */ + w100_pwr_state.pll_cntl.f.pll_cp_clip = 0x3; + w100_pwr_state.pll_cntl.f.pll_conf = 0x2; + w100_pwr_state.pll_cntl.f.pll_mbctrl = 0x2; + w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0; + writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); + + w100_pwr_state.clk_test_cntl.f.testclk_sel = 0x1; /* PLLCLK (for testing) */ + w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0; + w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x0; + writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL); + + w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x0; + w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1; /* normal mode (0, 1, 3) */ + w100_pwr_state.pwrmgt_cntl.f.pwm_wakeup_cond = 0x0; + w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0; + w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0; + w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1; /* PM4,ENG */ + w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1; /* PM4,ENG */ + w100_pwr_state.pwrmgt_cntl.f.pwm_idle_timer = 0xFF; + w100_pwr_state.pwrmgt_cntl.f.pwm_busy_timer = 0xFF; + writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL); + + w100_pwr_state.auto_mode = 0; /* manual mode */ + w100_pwr_state.pwm_mode = 1; /* normal mode (0, 1, 2) */ + w100_pwr_state.freq = 50000000; /* 50 MHz */ + w100_pwr_state.M = 3; /* M = 4 */ + w100_pwr_state.N_int = 6; /* N = 7.0 */ + w100_pwr_state.N_fac = 0; + w100_pwr_state.tfgoal = 0xE0; + w100_pwr_state.lock_time = 56; + w100_pwr_state.tf20 = 0xff; /* set highest */ + w100_pwr_state.tf80 = 0x00; /* set lowest */ + w100_pwr_state.tf100 = 0x00; /* set lowest */ + w100_pwr_state.fast_sclk = 50; /* 50.0 MHz */ + w100_pwr_state.norm_sclk = 12; /* 12.5 MHz */ +} + + +static void w100_init_sharp_lcd(u32 mode) +{ + u32 temp32; + union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl; + + /* Prevent display updates */ + disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e; + disp_db_buf_wr_cntl.f.update_db_buf = 0; + disp_db_buf_wr_cntl.f.en_db_buf = 0; + writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL); + + switch(mode) { + case LCD_SHARP_QVGA: + w100_set_slowsysclk(12); /* use crystal -- 12.5MHz */ + /* not use PLL */ + + writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION); + writel(0x85FF8000, remapped_regs + mmMC_FB_LOCATION); + writel(0x00000003, remapped_regs + mmLCD_FORMAT); + writel(0x00CF1C06, remapped_regs + mmGRAPHIC_CTRL); + writel(0x01410145, remapped_regs + mmCRTC_TOTAL); + writel(0x01170027, remapped_regs + mmACTIVE_H_DISP); + writel(0x01410001, remapped_regs + mmACTIVE_V_DISP); + writel(0x01170027, remapped_regs + mmGRAPHIC_H_DISP); + writel(0x01410001, remapped_regs + mmGRAPHIC_V_DISP); + writel(0x81170027, remapped_regs + mmCRTC_SS); + writel(0xA0140000, remapped_regs + mmCRTC_LS); + writel(0x00400008, remapped_regs + mmCRTC_REV); + writel(0xA0000000, remapped_regs + mmCRTC_DCLK); + writel(0xC0140014, remapped_regs + mmCRTC_GS); + writel(0x00010141, remapped_regs + mmCRTC_VPOS_GS); + writel(0x8015010F, remapped_regs + mmCRTC_GCLK); + writel(0x80100110, remapped_regs + mmCRTC_GOE); + writel(0x00000000, remapped_regs + mmCRTC_FRAME); + writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS); + writel(0x01CC0000, remapped_regs + mmLCDD_CNTL1); + writel(0x0003FFFF, remapped_regs + mmLCDD_CNTL2); + writel(0x00FFFF0D, remapped_regs + mmGENLCD_CNTL1); + writel(0x003F3003, remapped_regs + mmGENLCD_CNTL2); + writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT); + writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR); + writel(0x000102aa, remapped_regs + mmGENLCD_CNTL3); + writel(0x00800000, remapped_regs + mmGRAPHIC_OFFSET); + writel(0x000001e0, remapped_regs + mmGRAPHIC_PITCH); + writel(0x000000bf, remapped_regs + mmGPIO_DATA); + writel(0x03c0feff, remapped_regs + mmGPIO_CNTL2); + writel(0x00000000, remapped_regs + mmGPIO_CNTL1); + writel(0x41060010, remapped_regs + mmCRTC_PS1_ACTIVE); + break; + case LCD_SHARP_VGA: + w100_set_slowsysclk(12); /* use crystal -- 12.5MHz */ + w100_set_fastsysclk(current_par->fastsysclk_mode); /* use PLL -- 75.0MHz */ + w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x1; + w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x2; + writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL); + writel(0x15FF1000, remapped_regs + mmMC_FB_LOCATION); + writel(0x9FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION); + writel(0x00000003, remapped_regs + mmLCD_FORMAT); + writel(0x00DE1D66, remapped_regs + mmGRAPHIC_CTRL); + + writel(0x0283028B, remapped_regs + mmCRTC_TOTAL); + writel(0x02360056, remapped_regs + mmACTIVE_H_DISP); + writel(0x02830003, remapped_regs + mmACTIVE_V_DISP); + writel(0x02360056, remapped_regs + mmGRAPHIC_H_DISP); + writel(0x02830003, remapped_regs + mmGRAPHIC_V_DISP); + writel(0x82360056, remapped_regs + mmCRTC_SS); + writel(0xA0280000, remapped_regs + mmCRTC_LS); + writel(0x00400008, remapped_regs + mmCRTC_REV); + writel(0xA0000000, remapped_regs + mmCRTC_DCLK); + writel(0x80280028, remapped_regs + mmCRTC_GS); + writel(0x02830002, remapped_regs + mmCRTC_VPOS_GS); + writel(0x8015010F, remapped_regs + mmCRTC_GCLK); + writel(0x80100110, remapped_regs + mmCRTC_GOE); + writel(0x00000000, remapped_regs + mmCRTC_FRAME); + writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS); + writel(0x01CC0000, remapped_regs + mmLCDD_CNTL1); + writel(0x0003FFFF, remapped_regs + mmLCDD_CNTL2); + writel(0x00FFFF0D, remapped_regs + mmGENLCD_CNTL1); + writel(0x003F3003, remapped_regs + mmGENLCD_CNTL2); + writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT); + writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR); + writel(0x000102aa, remapped_regs + mmGENLCD_CNTL3); + writel(0x00800000, remapped_regs + mmGRAPHIC_OFFSET); + writel(0x000003C0, remapped_regs + mmGRAPHIC_PITCH); + writel(0x000000bf, remapped_regs + mmGPIO_DATA); + writel(0x03c0feff, remapped_regs + mmGPIO_CNTL2); + writel(0x00000000, remapped_regs + mmGPIO_CNTL1); + writel(0x41060010, remapped_regs + mmCRTC_PS1_ACTIVE); + break; + default: + break; + } + + /* Hack for overlay in ext memory */ + temp32 = readl(remapped_regs + mmDISP_DEBUG2); + temp32 |= 0xc0000000; + writel(temp32, remapped_regs + mmDISP_DEBUG2); + + /* Re-enable display updates */ + disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e; + disp_db_buf_wr_cntl.f.update_db_buf = 1; + disp_db_buf_wr_cntl.f.en_db_buf = 1; + writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL); +} + + +static void w100_set_vga_rotation_regs(u16 divider, unsigned long ctrl, unsigned long offset, unsigned long pitch) +{ + w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x1; + w100_pwr_state.pclk_cntl.f.pclk_post_div = divider; + writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL); + + writel(ctrl, remapped_regs + mmGRAPHIC_CTRL); + writel(offset, remapped_regs + mmGRAPHIC_OFFSET); + writel(pitch, remapped_regs + mmGRAPHIC_PITCH); + + /* Re-enable display updates */ + writel(0x0000007b, remapped_regs + mmDISP_DB_BUF_CNTL); +} + + +static void w100_init_vga_rotation(u16 deg) +{ + switch(deg) { + case 0: + w100_set_vga_rotation_regs(0x02, 0x00DE1D66, 0x00800000, 0x000003c0); + break; + case 90: + w100_set_vga_rotation_regs(0x06, 0x00DE1D0e, 0x00895b00, 0x00000500); + break; + case 180: + w100_set_vga_rotation_regs(0x02, 0x00DE1D7e, 0x00895ffc, 0x000003c0); + break; + case 270: + w100_set_vga_rotation_regs(0x06, 0x00DE1D16, 0x008004fc, 0x00000500); + break; + default: + /* not-support */ + break; + } +} + + +static void w100_set_qvga_rotation_regs(unsigned long ctrl, unsigned long offset, unsigned long pitch) +{ + writel(ctrl, remapped_regs + mmGRAPHIC_CTRL); + writel(offset, remapped_regs + mmGRAPHIC_OFFSET); + writel(pitch, remapped_regs + mmGRAPHIC_PITCH); + + /* Re-enable display updates */ + writel(0x0000007b, remapped_regs + mmDISP_DB_BUF_CNTL); +} + + +static void w100_init_qvga_rotation(u16 deg) +{ + switch(deg) { + case 0: + w100_set_qvga_rotation_regs(0x00d41c06, 0x00800000, 0x000001e0); + break; + case 90: + w100_set_qvga_rotation_regs(0x00d41c0E, 0x00825580, 0x00000280); + break; + case 180: + w100_set_qvga_rotation_regs(0x00d41c1e, 0x008257fc, 0x000001e0); + break; + case 270: + w100_set_qvga_rotation_regs(0x00d41c16, 0x0080027c, 0x00000280); + break; + default: + /* not-support */ + break; + } +} + + +static void w100_suspend(u32 mode) +{ + u32 val; + + writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION); + writel(0x00FF0000, remapped_regs + mmMC_PERF_MON_CNTL); + + val = readl(remapped_regs + mmMEM_EXT_TIMING_CNTL); + val &= ~(0x00100000); /* bit20=0 */ + val |= 0xFF000000; /* bit31:24=0xff */ + writel(val, remapped_regs + mmMEM_EXT_TIMING_CNTL); + + val = readl(remapped_regs + mmMEM_EXT_CNTL); + val &= ~(0x00040000); /* bit18=0 */ + val |= 0x00080000; /* bit19=1 */ + writel(val, remapped_regs + mmMEM_EXT_CNTL); + + udelay(1); /* wait 1us */ + + if (mode == W100_SUSPEND_EXTMEM) { + + /* CKE: Tri-State */ + val = readl(remapped_regs + mmMEM_EXT_CNTL); + val |= 0x40000000; /* bit30=1 */ + writel(val, remapped_regs + mmMEM_EXT_CNTL); + + /* CLK: Stop */ + val = readl(remapped_regs + mmMEM_EXT_CNTL); + val &= ~(0x00000001); /* bit0=0 */ + writel(val, remapped_regs + mmMEM_EXT_CNTL); + } else { + + writel(0x00000000, remapped_regs + mmSCLK_CNTL); + writel(0x000000BF, remapped_regs + mmCLK_PIN_CNTL); + writel(0x00000015, remapped_regs + mmPWRMGT_CNTL); + + udelay(5); + + val = readl(remapped_regs + mmPLL_CNTL); + val |= 0x00000004; /* bit2=1 */ + writel(val, remapped_regs + mmPLL_CNTL); + writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL); + } +} + + +static void w100_resume(void) +{ + u32 temp32; + + w100_hw_init(); + w100_pwm_setup(); + + temp32 = readl(remapped_regs + mmDISP_DEBUG2); + temp32 &= 0xff7fffff; + temp32 |= 0x00800000; + writel(temp32, remapped_regs + mmDISP_DEBUG2); + + if (current_par->lcdMode == LCD_MODE_480 || current_par->lcdMode == LCD_MODE_640) { + w100_init_sharp_lcd(LCD_SHARP_VGA); + if (current_par->lcdMode == LCD_MODE_640) { + w100_init_vga_rotation(current_par->rotation_flag ? 270 : 90); + } + } else { + w100_init_sharp_lcd(LCD_SHARP_QVGA); + if (current_par->lcdMode == LCD_MODE_320) { + w100_init_qvga_rotation(current_par->rotation_flag ? 270 : 90); + } + } +} + + +static void w100_vsync(void) +{ + u32 tmp; + int timeout = 30000; /* VSync timeout = 30[ms] > 16.8[ms] */ + + tmp = readl(remapped_regs + mmACTIVE_V_DISP); + + /* set vline pos */ + writel((tmp >> 16) & 0x3ff, remapped_regs + mmDISP_INT_CNTL); + + /* disable vline irq */ + tmp = readl(remapped_regs + mmGEN_INT_CNTL); + + tmp &= ~0x00000002; + writel(tmp, remapped_regs + mmGEN_INT_CNTL); + + /* clear vline irq status */ + writel(0x00000002, remapped_regs + mmGEN_INT_STATUS); + + /* enable vline irq */ + writel((tmp | 0x00000002), remapped_regs + mmGEN_INT_CNTL); + + /* clear vline irq status */ + writel(0x00000002, remapped_regs + mmGEN_INT_STATUS); + + while(timeout > 0) { + if (readl(remapped_regs + mmGEN_INT_STATUS) & 0x00000002) + break; + udelay(1); + timeout--; + } + + /* disable vline irq */ + writel(tmp, remapped_regs + mmGEN_INT_CNTL); + + /* clear vline irq status */ + writel(0x00000002, remapped_regs + mmGEN_INT_STATUS); +} + + +static void w100_InitExtMem(u32 mode) +{ + switch(mode) { + case LCD_SHARP_QVGA: + /* QVGA doesn't use external memory + nothing to do, really. */ + break; + case LCD_SHARP_VGA: + writel(0x00007800, remapped_regs + mmMC_BIST_CTRL); + writel(0x00040003, remapped_regs + mmMEM_EXT_CNTL); + writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG); + udelay(100); + writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG); + udelay(100); + writel(0x00650021, remapped_regs + mmMEM_SDRAM_MODE_REG); + udelay(100); + writel(0x10002a4a, remapped_regs + mmMEM_EXT_TIMING_CNTL); + writel(0x7ff87012, remapped_regs + mmMEM_IO_CNTL); + break; + default: + break; + } +} + + +#define RESCTL_ADRS 0x00 +#define PHACTRL_ADRS 0x01 +#define DUTYCTRL_ADRS 0x02 +#define POWERREG0_ADRS 0x03 +#define POWERREG1_ADRS 0x04 +#define GPOR3_ADRS 0x05 +#define PICTRL_ADRS 0x06 +#define POLCTRL_ADRS 0x07 + +#define RESCTL_QVGA 0x01 +#define RESCTL_VGA 0x00 + +#define POWER1_VW_ON 0x01 /* VW Supply FET ON */ +#define POWER1_GVSS_ON 0x02 /* GVSS(-8V) Power Supply ON */ +#define POWER1_VDD_ON 0x04 /* VDD(8V),SVSS(-4V) Power Supply ON */ + +#define POWER1_VW_OFF 0x00 /* VW Supply FET OFF */ +#define POWER1_GVSS_OFF 0x00 /* GVSS(-8V) Power Supply OFF */ +#define POWER1_VDD_OFF 0x00 /* VDD(8V),SVSS(-4V) Power Supply OFF */ + +#define POWER0_COM_DCLK 0x01 /* COM Voltage DC Bias DAC Serial Data Clock */ +#define POWER0_COM_DOUT 0x02 /* COM Voltage DC Bias DAC Serial Data Out */ +#define POWER0_DAC_ON 0x04 /* DAC Power Supply ON */ +#define POWER0_COM_ON 0x08 /* COM Powewr Supply ON */ +#define POWER0_VCC5_ON 0x10 /* VCC5 Power Supply ON */ + +#define POWER0_DAC_OFF 0x00 /* DAC Power Supply OFF */ +#define POWER0_COM_OFF 0x00 /* COM Powewr Supply OFF */ +#define POWER0_VCC5_OFF 0x00 /* VCC5 Power Supply OFF */ + +#define PICTRL_INIT_STATE 0x01 +#define PICTRL_INIOFF 0x02 +#define PICTRL_POWER_DOWN 0x04 +#define PICTRL_COM_SIGNAL_OFF 0x08 +#define PICTRL_DAC_SIGNAL_OFF 0x10 + +#define PICTRL_POWER_ACTIVE (0) + +#define POLCTRL_SYNC_POL_FALL 0x01 +#define POLCTRL_EN_POL_FALL 0x02 +#define POLCTRL_DATA_POL_FALL 0x04 +#define POLCTRL_SYNC_ACT_H 0x08 +#define POLCTRL_EN_ACT_L 0x10 + +#define POLCTRL_SYNC_POL_RISE 0x00 +#define POLCTRL_EN_POL_RISE 0x00 +#define POLCTRL_DATA_POL_RISE 0x00 +#define POLCTRL_SYNC_ACT_L 0x00 +#define POLCTRL_EN_ACT_H 0x00 + +#define PHACTRL_PHASE_MANUAL 0x01 + +#define PHAD_QVGA_DEFAULT_VAL (9) +#define COMADJ_DEFAULT (125) + +static void lcdtg_ssp_send(u8 adrs, u8 data) +{ + w100fb_ssp_send(adrs,data); +} + +/* + * This is only a psuedo I2C interface. We can't use the standard kernel + * routines as the interface is write only. We just assume the data is acked... + */ +static void lcdtg_ssp_i2c_send(u8 data) +{ + lcdtg_ssp_send(POWERREG0_ADRS, data); + udelay(10); +} + +static void lcdtg_i2c_send_bit(u8 data) +{ + lcdtg_ssp_i2c_send(data); + lcdtg_ssp_i2c_send(data | POWER0_COM_DCLK); + lcdtg_ssp_i2c_send(data); +} + +static void lcdtg_i2c_send_start(u8 base) +{ + lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT); + lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK); + lcdtg_ssp_i2c_send(base); +} + +static void lcdtg_i2c_send_stop(u8 base) +{ + lcdtg_ssp_i2c_send(base); + lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK); + lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT); +} + +static void lcdtg_i2c_send_byte(u8 base, u8 data) +{ + int i; + for (i = 0; i < 8; i++) { + if (data & 0x80) + lcdtg_i2c_send_bit(base | POWER0_COM_DOUT); + else + lcdtg_i2c_send_bit(base); + data <<= 1; + } +} + +static void lcdtg_i2c_wait_ack(u8 base) +{ + lcdtg_i2c_send_bit(base); +} + +static void lcdtg_set_common_voltage(u8 base_data, u8 data) +{ + /* Set Common Voltage to M62332FP via I2C */ + lcdtg_i2c_send_start(base_data); + lcdtg_i2c_send_byte(base_data, 0x9c); + lcdtg_i2c_wait_ack(base_data); + lcdtg_i2c_send_byte(base_data, 0x00); + lcdtg_i2c_wait_ack(base_data); + lcdtg_i2c_send_byte(base_data, data); + lcdtg_i2c_wait_ack(base_data); + lcdtg_i2c_send_stop(base_data); +} + +static struct lcdtg_register_setting { + u8 adrs; + u8 data; + u32 wait; +} lcdtg_power_on_table[] = { + + /* Initialize Internal Logic & Port */ + { PICTRL_ADRS, + PICTRL_POWER_DOWN | PICTRL_INIOFF | PICTRL_INIT_STATE | + PICTRL_COM_SIGNAL_OFF | PICTRL_DAC_SIGNAL_OFF, + 0 }, + + { POWERREG0_ADRS, + POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF | POWER0_COM_OFF | + POWER0_VCC5_OFF, + 0 }, + + { POWERREG1_ADRS, + POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF, + 0 }, + + /* VDD(+8V),SVSS(-4V) ON */ + { POWERREG1_ADRS, + POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON /* VDD ON */, + 3000 }, + + /* DAC ON */ + { POWERREG0_ADRS, + POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ | + POWER0_COM_OFF | POWER0_VCC5_OFF, + 0 }, + + /* INIB = H, INI = L */ + { PICTRL_ADRS, + /* PICTL[0] = H , PICTL[1] = PICTL[2] = PICTL[4] = L */ + PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF, + 0 }, + + /* Set Common Voltage */ + { 0xfe, 0, 0 }, + + /* VCC5 ON */ + { POWERREG0_ADRS, + POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ | + POWER0_COM_OFF | POWER0_VCC5_ON /* VCC5 ON */, + 0 }, + + /* GVSS(-8V) ON */ + { POWERREG1_ADRS, + POWER1_VW_OFF | POWER1_GVSS_ON /* GVSS ON */ | + POWER1_VDD_ON /* VDD ON */, + 2000 }, + + /* COM SIGNAL ON (PICTL[3] = L) */ + { PICTRL_ADRS, + PICTRL_INIT_STATE, + 0 }, + + /* COM ON */ + { POWERREG0_ADRS, + POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ | + POWER0_COM_ON /* COM ON */ | POWER0_VCC5_ON /* VCC5_ON */, + 0 }, + + /* VW ON */ + { POWERREG1_ADRS, + POWER1_VW_ON /* VW ON */ | POWER1_GVSS_ON /* GVSS ON */ | + POWER1_VDD_ON /* VDD ON */, + 0 /* Wait 100ms */ }, + + /* Signals output enable */ + { PICTRL_ADRS, + 0 /* Signals output enable */, + 0 }, + + { PHACTRL_ADRS, + PHACTRL_PHASE_MANUAL, + 0 }, + + /* Initialize for Input Signals from ATI */ + { POLCTRL_ADRS, + POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE | POLCTRL_DATA_POL_RISE | + POLCTRL_SYNC_ACT_L | POLCTRL_EN_ACT_H, + 1000 /*100000*/ /* Wait 100ms */ }, + + /* end mark */ + { 0xff, 0, 0 } +}; + +static void lcdtg_resume(void) +{ + if (current_par->lcdMode == LCD_MODE_480 || current_par->lcdMode == LCD_MODE_640) { + lcdtg_hw_init(LCD_SHARP_VGA); + } else { + lcdtg_hw_init(LCD_SHARP_QVGA); + } +} + +static void lcdtg_suspend(void) +{ + int i; + + for (i = 0; i < (current_par->xres * current_par->yres); i++) { + writew(0xffff, remapped_fbuf + (2*i)); + } + + /* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */ + mdelay(34); + + /* (1)VW OFF */ + lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON); + + /* (2)COM OFF */ + lcdtg_ssp_send(PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF); + lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON); + + /* (3)Set Common Voltage Bias 0V */ + lcdtg_set_common_voltage(POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON, 0); + + /* (4)GVSS OFF */ + lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON); + + /* (5)VCC5 OFF */ + lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF); + + /* (6)Set PDWN, INIOFF, DACOFF */ + lcdtg_ssp_send(PICTRL_ADRS, PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF | + PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF); + + /* (7)DAC OFF */ + lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF); + + /* (8)VDD OFF */ + lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF); + +} + +static void lcdtg_set_phadadj(u32 mode) +{ + int adj; + + if (mode == LCD_SHARP_VGA) { + /* Setting for VGA */ + adj = current_par->phadadj; + if (adj < 0) { + adj = PHACTRL_PHASE_MANUAL; + } else { + adj = ((adj & 0x0f) << 1) | PHACTRL_PHASE_MANUAL; + } + } else { + /* Setting for QVGA */ + adj = (PHAD_QVGA_DEFAULT_VAL << 1) | PHACTRL_PHASE_MANUAL; + } + lcdtg_ssp_send(PHACTRL_ADRS, adj); +} + +static void lcdtg_hw_init(u32 mode) +{ + int i; + int comadj; + + i = 0; + while(lcdtg_power_on_table[i].adrs != 0xff) { + if (lcdtg_power_on_table[i].adrs == 0xfe) { + /* Set Common Voltage */ + comadj = current_par->comadj; + if (comadj < 0) { + comadj = COMADJ_DEFAULT; + } + lcdtg_set_common_voltage((POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF), comadj); + } else if (lcdtg_power_on_table[i].adrs == PHACTRL_ADRS) { + /* Set Phase Adjuct */ + lcdtg_set_phadadj(mode); + } else { + /* Other */ + lcdtg_ssp_send(lcdtg_power_on_table[i].adrs, lcdtg_power_on_table[i].data); + } + if (lcdtg_power_on_table[i].wait != 0) + udelay(lcdtg_power_on_table[i].wait); + i++; + } + + switch(mode) { + case LCD_SHARP_QVGA: + /* Set Lcd Resolution (QVGA) */ + lcdtg_ssp_send(RESCTL_ADRS, RESCTL_QVGA); + break; + case LCD_SHARP_VGA: + /* Set Lcd Resolution (VGA) */ + lcdtg_ssp_send(RESCTL_ADRS, RESCTL_VGA); + break; + default: + break; + } +} + +static void lcdtg_lcd_change(u32 mode) +{ + /* Set Phase Adjuct */ + lcdtg_set_phadadj(mode); + + if (mode == LCD_SHARP_VGA) + /* Set Lcd Resolution (VGA) */ + lcdtg_ssp_send(RESCTL_ADRS, RESCTL_VGA); + else if (mode == LCD_SHARP_QVGA) + /* Set Lcd Resolution (QVGA) */ + lcdtg_ssp_send(RESCTL_ADRS, RESCTL_QVGA); +} + + +static struct device_driver w100fb_driver = { + .name = "w100fb", + .bus = &platform_bus_type, + .probe = w100fb_probe, + .remove = w100fb_remove, + .suspend = w100fb_suspend, + .resume = w100fb_resume, +}; + +int __devinit w100fb_init(void) +{ + return driver_register(&w100fb_driver); +} + +void __exit w100fb_cleanup(void) +{ + driver_unregister(&w100fb_driver); +} + +module_init(w100fb_init); +module_exit(w100fb_cleanup); + +MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver"); +MODULE_LICENSE("GPLv2"); diff --git a/drivers/video/w100fb.h b/drivers/video/w100fb.h new file mode 100644 index 000000000000..41624f961237 --- /dev/null +++ b/drivers/video/w100fb.h @@ -0,0 +1,615 @@ +/* + * linux/drivers/video/w100fb.h + * + * Frame Buffer Device for ATI w100 (Wallaby) + * + * Copyright (C) 2002, ATI Corp. + * Copyright (C) 2004-2005 Richard Purdie + * + * Modified to work with 2.6 by Richard Purdie <rpurdie@rpsys.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#if !defined (_W100FB_H) +#define _W100FB_H + +/* Block CIF Start: */ +#define mmCHIP_ID 0x0000 +#define mmREVISION_ID 0x0004 +#define mmWRAP_BUF_A 0x0008 +#define mmWRAP_BUF_B 0x000C +#define mmWRAP_TOP_DIR 0x0010 +#define mmWRAP_START_DIR 0x0014 +#define mmCIF_CNTL 0x0018 +#define mmCFGREG_BASE 0x001C +#define mmCIF_IO 0x0020 +#define mmCIF_READ_DBG 0x0024 +#define mmCIF_WRITE_DBG 0x0028 +#define cfgIND_ADDR_A_0 0x0000 +#define cfgIND_ADDR_A_1 0x0001 +#define cfgIND_ADDR_A_2 0x0002 +#define cfgIND_DATA_A 0x0003 +#define cfgREG_BASE 0x0004 +#define cfgINTF_CNTL 0x0005 +#define cfgSTATUS 0x0006 +#define cfgCPU_DEFAULTS 0x0007 +#define cfgIND_ADDR_B_0 0x0008 +#define cfgIND_ADDR_B_1 0x0009 +#define cfgIND_ADDR_B_2 0x000A +#define cfgIND_DATA_B 0x000B +#define cfgPM4_RPTR 0x000C +#define cfgSCRATCH 0x000D +#define cfgPM4_WRPTR_0 0x000E +#define cfgPM4_WRPTR_1 0x000F +/* Block CIF End: */ + +/* Block CP Start: */ +#define mmSCRATCH_UMSK 0x0280 +#define mmSCRATCH_ADDR 0x0284 +#define mmGEN_INT_CNTL 0x0200 +#define mmGEN_INT_STATUS 0x0204 +/* Block CP End: */ + +/* Block DISPLAY Start: */ +#define mmLCD_FORMAT 0x0410 +#define mmGRAPHIC_CTRL 0x0414 +#define mmGRAPHIC_OFFSET 0x0418 +#define mmGRAPHIC_PITCH 0x041C +#define mmCRTC_TOTAL 0x0420 +#define mmACTIVE_H_DISP 0x0424 +#define mmACTIVE_V_DISP 0x0428 +#define mmGRAPHIC_H_DISP 0x042C +#define mmGRAPHIC_V_DISP 0x0430 +#define mmVIDEO_CTRL 0x0434 +#define mmGRAPHIC_KEY 0x0438 +#define mmBRIGHTNESS_CNTL 0x045C +#define mmDISP_INT_CNTL 0x0488 +#define mmCRTC_SS 0x048C +#define mmCRTC_LS 0x0490 +#define mmCRTC_REV 0x0494 +#define mmCRTC_DCLK 0x049C +#define mmCRTC_GS 0x04A0 +#define mmCRTC_VPOS_GS 0x04A4 +#define mmCRTC_GCLK 0x04A8 +#define mmCRTC_GOE 0x04AC +#define mmCRTC_FRAME 0x04B0 +#define mmCRTC_FRAME_VPOS 0x04B4 +#define mmGPIO_DATA 0x04B8 +#define mmGPIO_CNTL1 0x04BC +#define mmGPIO_CNTL2 0x04C0 +#define mmLCDD_CNTL1 0x04C4 +#define mmLCDD_CNTL2 0x04C8 +#define mmGENLCD_CNTL1 0x04CC +#define mmGENLCD_CNTL2 0x04D0 +#define mmDISP_DEBUG 0x04D4 +#define mmDISP_DB_BUF_CNTL 0x04D8 +#define mmDISP_CRC_SIG 0x04DC +#define mmCRTC_DEFAULT_COUNT 0x04E0 +#define mmLCD_BACKGROUND_COLOR 0x04E4 +#define mmCRTC_PS2 0x04E8 +#define mmCRTC_PS2_VPOS 0x04EC +#define mmCRTC_PS1_ACTIVE 0x04F0 +#define mmCRTC_PS1_NACTIVE 0x04F4 +#define mmCRTC_GCLK_EXT 0x04F8 +#define mmCRTC_ALW 0x04FC +#define mmCRTC_ALW_VPOS 0x0500 +#define mmCRTC_PSK 0x0504 +#define mmCRTC_PSK_HPOS 0x0508 +#define mmCRTC_CV4_START 0x050C +#define mmCRTC_CV4_END 0x0510 +#define mmCRTC_CV4_HPOS 0x0514 +#define mmCRTC_ECK 0x051C +#define mmREFRESH_CNTL 0x0520 +#define mmGENLCD_CNTL3 0x0524 +#define mmGPIO_DATA2 0x0528 +#define mmGPIO_CNTL3 0x052C +#define mmGPIO_CNTL4 0x0530 +#define mmCHIP_STRAP 0x0534 +#define mmDISP_DEBUG2 0x0538 +#define mmDEBUG_BUS_CNTL 0x053C +#define mmGAMMA_VALUE1 0x0540 +#define mmGAMMA_VALUE2 0x0544 +#define mmGAMMA_SLOPE 0x0548 +#define mmGEN_STATUS 0x054C +#define mmHW_INT 0x0550 +/* Block DISPLAY End: */ + +/* Block GFX Start: */ +#define mmBRUSH_OFFSET 0x108C +#define mmBRUSH_Y_X 0x1074 +#define mmDEFAULT_PITCH_OFFSET 0x10A0 +#define mmDEFAULT_SC_BOTTOM_RIGHT 0x10A8 +#define mmDEFAULT2_SC_BOTTOM_RIGHT 0x10AC +#define mmGLOBAL_ALPHA 0x1210 +#define mmFILTER_COEF 0x1214 +#define mmMVC_CNTL_START 0x11E0 +#define mmE2_ARITHMETIC_CNTL 0x1220 +#define mmENG_CNTL 0x13E8 +#define mmENG_PERF_CNT 0x13F0 +/* Block GFX End: */ + +/* Block IDCT Start: */ +#define mmIDCT_RUNS 0x0C00 +#define mmIDCT_LEVELS 0x0C04 +#define mmIDCT_CONTROL 0x0C3C +#define mmIDCT_AUTH_CONTROL 0x0C08 +#define mmIDCT_AUTH 0x0C0C +/* Block IDCT End: */ + +/* Block MC Start: */ +#define mmMEM_CNTL 0x0180 +#define mmMEM_ARB 0x0184 +#define mmMC_FB_LOCATION 0x0188 +#define mmMEM_EXT_CNTL 0x018C +#define mmMC_EXT_MEM_LOCATION 0x0190 +#define mmMEM_EXT_TIMING_CNTL 0x0194 +#define mmMEM_SDRAM_MODE_REG 0x0198 +#define mmMEM_IO_CNTL 0x019C +#define mmMC_DEBUG 0x01A0 +#define mmMC_BIST_CTRL 0x01A4 +#define mmMC_BIST_COLLAR_READ 0x01A8 +#define mmTC_MISMATCH 0x01AC +#define mmMC_PERF_MON_CNTL 0x01B0 +#define mmMC_PERF_COUNTERS 0x01B4 +/* Block MC End: */ + +/* Block RBBM Start: */ +#define mmWAIT_UNTIL 0x1400 +#define mmISYNC_CNTL 0x1404 +#define mmRBBM_CNTL 0x0144 +#define mmNQWAIT_UNTIL 0x0150 +/* Block RBBM End: */ + +/* Block CG Start: */ +#define mmCLK_PIN_CNTL 0x0080 +#define mmPLL_REF_FB_DIV 0x0084 +#define mmPLL_CNTL 0x0088 +#define mmSCLK_CNTL 0x008C +#define mmPCLK_CNTL 0x0090 +#define mmCLK_TEST_CNTL 0x0094 +#define mmPWRMGT_CNTL 0x0098 +#define mmPWRMGT_STATUS 0x009C +/* Block CG End: */ + +/* default value definitions */ +#define defWRAP_TOP_DIR 0x00000000 +#define defWRAP_START_DIR 0x00000000 +#define defCFGREG_BASE 0x00000000 +#define defCIF_IO 0x000C0902 +#define defINTF_CNTL 0x00000011 +#define defCPU_DEFAULTS 0x00000006 +#define defHW_INT 0x00000000 +#define defMC_EXT_MEM_LOCATION 0x07ff0000 +#define defTC_MISMATCH 0x00000000 + +#define W100_CFG_BASE 0x0 +#define W100_CFG_LEN 0x10 +#define W100_REG_BASE 0x10000 +#define W100_REG_LEN 0x2000 +#define MEM_INT_BASE_VALUE 0x100000 +#define MEM_INT_TOP_VALUE_W100 0x15ffff +#define MEM_EXT_BASE_VALUE 0x800000 +#define MEM_EXT_TOP_VALUE 0x9fffff +#define WRAP_BUF_BASE_VALUE 0x80000 +#define WRAP_BUF_TOP_VALUE 0xbffff + + +/* data structure definitions */ + +struct wrap_top_dir_t { + unsigned long top_addr : 23; + unsigned long : 9; +} __attribute__((packed)); + +union wrap_top_dir_u { + unsigned long val : 32; + struct wrap_top_dir_t f; +} __attribute__((packed)); + +struct wrap_start_dir_t { + unsigned long start_addr : 23; + unsigned long : 9; +} __attribute__((packed)); + +union wrap_start_dir_u { + unsigned long val : 32; + struct wrap_start_dir_t f; +} __attribute__((packed)); + +struct cif_cntl_t { + unsigned long swap_reg : 2; + unsigned long swap_fbuf_1 : 2; + unsigned long swap_fbuf_2 : 2; + unsigned long swap_fbuf_3 : 2; + unsigned long pmi_int_disable : 1; + unsigned long pmi_schmen_disable : 1; + unsigned long intb_oe : 1; + unsigned long en_wait_to_compensate_dq_prop_dly : 1; + unsigned long compensate_wait_rd_size : 2; + unsigned long wait_asserted_timeout_val : 2; + unsigned long wait_masked_val : 2; + unsigned long en_wait_timeout : 1; + unsigned long en_one_clk_setup_before_wait : 1; + unsigned long interrupt_active_high : 1; + unsigned long en_overwrite_straps : 1; + unsigned long strap_wait_active_hi : 1; + unsigned long lat_busy_count : 2; + unsigned long lat_rd_pm4_sclk_busy : 1; + unsigned long dis_system_bits : 1; + unsigned long dis_mr : 1; + unsigned long cif_spare_1 : 4; +} __attribute__((packed)); + +union cif_cntl_u { + unsigned long val : 32; + struct cif_cntl_t f; +} __attribute__((packed)); + +struct cfgreg_base_t { + unsigned long cfgreg_base : 24; + unsigned long : 8; +} __attribute__((packed)); + +union cfgreg_base_u { + unsigned long val : 32; + struct cfgreg_base_t f; +} __attribute__((packed)); + +struct cif_io_t { + unsigned long dq_srp : 1; + unsigned long dq_srn : 1; + unsigned long dq_sp : 4; + unsigned long dq_sn : 4; + unsigned long waitb_srp : 1; + unsigned long waitb_srn : 1; + unsigned long waitb_sp : 4; + unsigned long waitb_sn : 4; + unsigned long intb_srp : 1; + unsigned long intb_srn : 1; + unsigned long intb_sp : 4; + unsigned long intb_sn : 4; + unsigned long : 2; +} __attribute__((packed)); + +union cif_io_u { + unsigned long val : 32; + struct cif_io_t f; +} __attribute__((packed)); + +struct cif_read_dbg_t { + unsigned long unpacker_pre_fetch_trig_gen : 2; + unsigned long dly_second_rd_fetch_trig : 1; + unsigned long rst_rd_burst_id : 1; + unsigned long dis_rd_burst_id : 1; + unsigned long en_block_rd_when_packer_is_not_emp : 1; + unsigned long dis_pre_fetch_cntl_sm : 1; + unsigned long rbbm_chrncy_dis : 1; + unsigned long rbbm_rd_after_wr_lat : 2; + unsigned long dis_be_during_rd : 1; + unsigned long one_clk_invalidate_pulse : 1; + unsigned long dis_chnl_priority : 1; + unsigned long rst_read_path_a_pls : 1; + unsigned long rst_read_path_b_pls : 1; + unsigned long dis_reg_rd_fetch_trig : 1; + unsigned long dis_rd_fetch_trig_from_ind_addr : 1; + unsigned long dis_rd_same_byte_to_trig_fetch : 1; + unsigned long dis_dir_wrap : 1; + unsigned long dis_ring_buf_to_force_dec : 1; + unsigned long dis_addr_comp_in_16bit : 1; + unsigned long clr_w : 1; + unsigned long err_rd_tag_is_3 : 1; + unsigned long err_load_when_ful_a : 1; + unsigned long err_load_when_ful_b : 1; + unsigned long : 7; +} __attribute__((packed)); + +union cif_read_dbg_u { + unsigned long val : 32; + struct cif_read_dbg_t f; +} __attribute__((packed)); + +struct cif_write_dbg_t { + unsigned long packer_timeout_count : 2; + unsigned long en_upper_load_cond : 1; + unsigned long en_chnl_change_cond : 1; + unsigned long dis_addr_comp_cond : 1; + unsigned long dis_load_same_byte_addr_cond : 1; + unsigned long dis_timeout_cond : 1; + unsigned long dis_timeout_during_rbbm : 1; + unsigned long dis_packer_ful_during_rbbm_timeout : 1; + unsigned long en_dword_split_to_rbbm : 1; + unsigned long en_dummy_val : 1; + unsigned long dummy_val_sel : 1; + unsigned long mask_pm4_wrptr_dec : 1; + unsigned long dis_mc_clean_cond : 1; + unsigned long err_two_reqi_during_ful : 1; + unsigned long err_reqi_during_idle_clk : 1; + unsigned long err_global : 1; + unsigned long en_wr_buf_dbg_load : 1; + unsigned long en_wr_buf_dbg_path : 1; + unsigned long sel_wr_buf_byte : 3; + unsigned long dis_rd_flush_wr : 1; + unsigned long dis_packer_ful_cond : 1; + unsigned long dis_invalidate_by_ops_chnl : 1; + unsigned long en_halt_when_reqi_err : 1; + unsigned long cif_spare_2 : 5; + unsigned long : 1; +} __attribute__((packed)); + +union cif_write_dbg_u { + unsigned long val : 32; + struct cif_write_dbg_t f; +} __attribute__((packed)); + + +struct intf_cntl_t { + unsigned char ad_inc_a : 1; + unsigned char ring_buf_a : 1; + unsigned char rd_fetch_trigger_a : 1; + unsigned char rd_data_rdy_a : 1; + unsigned char ad_inc_b : 1; + unsigned char ring_buf_b : 1; + unsigned char rd_fetch_trigger_b : 1; + unsigned char rd_data_rdy_b : 1; +} __attribute__((packed)); + +union intf_cntl_u { + unsigned char val : 8; + struct intf_cntl_t f; +} __attribute__((packed)); + +struct cpu_defaults_t { + unsigned char unpack_rd_data : 1; + unsigned char access_ind_addr_a: 1; + unsigned char access_ind_addr_b: 1; + unsigned char access_scratch_reg : 1; + unsigned char pack_wr_data : 1; + unsigned char transition_size : 1; + unsigned char en_read_buf_mode : 1; + unsigned char rd_fetch_scratch : 1; +} __attribute__((packed)); + +union cpu_defaults_u { + unsigned char val : 8; + struct cpu_defaults_t f; +} __attribute__((packed)); + +struct video_ctrl_t { + unsigned long video_mode : 1; + unsigned long keyer_en : 1; + unsigned long en_video_req : 1; + unsigned long en_graphic_req_video : 1; + unsigned long en_video_crtc : 1; + unsigned long video_hor_exp : 2; + unsigned long video_ver_exp : 2; + unsigned long uv_combine : 1; + unsigned long total_req_video : 9; + unsigned long video_ch_sel : 1; + unsigned long video_portrait : 2; + unsigned long yuv2rgb_en : 1; + unsigned long yuv2rgb_option : 1; + unsigned long video_inv_hor : 1; + unsigned long video_inv_ver : 1; + unsigned long gamma_sel : 2; + unsigned long dis_limit : 1; + unsigned long en_uv_hblend : 1; + unsigned long rgb_gamma_sel : 2; +} __attribute__((packed)); + +union video_ctrl_u { + unsigned long val : 32; + struct video_ctrl_t f; +} __attribute__((packed)); + +struct disp_db_buf_cntl_rd_t { + unsigned long en_db_buf : 1; + unsigned long update_db_buf_done : 1; + unsigned long db_buf_cntl : 6; + unsigned long : 24; +} __attribute__((packed)); + +union disp_db_buf_cntl_rd_u { + unsigned long val : 32; + struct disp_db_buf_cntl_rd_t f; +} __attribute__((packed)); + +struct disp_db_buf_cntl_wr_t { + unsigned long en_db_buf : 1; + unsigned long update_db_buf : 1; + unsigned long db_buf_cntl : 6; + unsigned long : 24; +} __attribute__((packed)); + +union disp_db_buf_cntl_wr_u { + unsigned long val : 32; + struct disp_db_buf_cntl_wr_t f; +} __attribute__((packed)); + +struct gamma_value1_t { + unsigned long gamma1 : 8; + unsigned long gamma2 : 8; + unsigned long gamma3 : 8; + unsigned long gamma4 : 8; +} __attribute__((packed)); + +union gamma_value1_u { + unsigned long val : 32; + struct gamma_value1_t f; +} __attribute__((packed)); + +struct gamma_value2_t { + unsigned long gamma5 : 8; + unsigned long gamma6 : 8; + unsigned long gamma7 : 8; + unsigned long gamma8 : 8; +} __attribute__((packed)); + +union gamma_value2_u { + unsigned long val : 32; + struct gamma_value2_t f; +} __attribute__((packed)); + +struct gamma_slope_t { + unsigned long slope1 : 3; + unsigned long slope2 : 3; + unsigned long slope3 : 3; + unsigned long slope4 : 3; + unsigned long slope5 : 3; + unsigned long slope6 : 3; + unsigned long slope7 : 3; + unsigned long slope8 : 3; + unsigned long : 8; +} __attribute__((packed)); + +union gamma_slope_u { + unsigned long val : 32; + struct gamma_slope_t f; +} __attribute__((packed)); + +struct mc_ext_mem_location_t { + unsigned long mc_ext_mem_start : 16; + unsigned long mc_ext_mem_top : 16; +} __attribute__((packed)); + +union mc_ext_mem_location_u { + unsigned long val : 32; + struct mc_ext_mem_location_t f; +} __attribute__((packed)); + +struct clk_pin_cntl_t { + unsigned long osc_en : 1; + unsigned long osc_gain : 5; + unsigned long dont_use_xtalin : 1; + unsigned long xtalin_pm_en : 1; + unsigned long xtalin_dbl_en : 1; + unsigned long : 7; + unsigned long cg_debug : 16; +} __attribute__((packed)); + +union clk_pin_cntl_u { + unsigned long val : 32; + struct clk_pin_cntl_t f; +} __attribute__((packed)); + +struct pll_ref_fb_div_t { + unsigned long pll_ref_div : 4; + unsigned long : 4; + unsigned long pll_fb_div_int : 6; + unsigned long : 2; + unsigned long pll_fb_div_frac : 3; + unsigned long : 1; + unsigned long pll_reset_time : 4; + unsigned long pll_lock_time : 8; +} __attribute__((packed)); + +union pll_ref_fb_div_u { + unsigned long val : 32; + struct pll_ref_fb_div_t f; +} __attribute__((packed)); + +struct pll_cntl_t { + unsigned long pll_pwdn : 1; + unsigned long pll_reset : 1; + unsigned long pll_pm_en : 1; + unsigned long pll_mode : 1; + unsigned long pll_refclk_sel : 1; + unsigned long pll_fbclk_sel : 1; + unsigned long pll_tcpoff : 1; + unsigned long pll_pcp : 3; + unsigned long pll_pvg : 3; + unsigned long pll_vcofr : 1; + unsigned long pll_ioffset : 2; + unsigned long pll_pecc_mode : 2; + unsigned long pll_pecc_scon : 2; + unsigned long pll_dactal : 4; + unsigned long pll_cp_clip : 2; + unsigned long pll_conf : 3; + unsigned long pll_mbctrl : 2; + unsigned long pll_ring_off : 1; +} __attribute__((packed)); + +union pll_cntl_u { + unsigned long val : 32; + struct pll_cntl_t f; +} __attribute__((packed)); + +struct sclk_cntl_t { + unsigned long sclk_src_sel : 2; + unsigned long : 2; + unsigned long sclk_post_div_fast : 4; + unsigned long sclk_clkon_hys : 3; + unsigned long sclk_post_div_slow : 4; + unsigned long disp_cg_ok2switch_en : 1; + unsigned long sclk_force_reg : 1; + unsigned long sclk_force_disp : 1; + unsigned long sclk_force_mc : 1; + unsigned long sclk_force_extmc : 1; + unsigned long sclk_force_cp : 1; + unsigned long sclk_force_e2 : 1; + unsigned long sclk_force_e3 : 1; + unsigned long sclk_force_idct : 1; + unsigned long sclk_force_bist : 1; + unsigned long busy_extend_cp : 1; + unsigned long busy_extend_e2 : 1; + unsigned long busy_extend_e3 : 1; + unsigned long busy_extend_idct : 1; + unsigned long : 3; +} __attribute__((packed)); + +union sclk_cntl_u { + unsigned long val : 32; + struct sclk_cntl_t f; +} __attribute__((packed)); + +struct pclk_cntl_t { + unsigned long pclk_src_sel : 2; + unsigned long : 2; + unsigned long pclk_post_div : 4; + unsigned long : 8; + unsigned long pclk_force_disp : 1; + unsigned long : 15; +} __attribute__((packed)); + +union pclk_cntl_u { + unsigned long val : 32; + struct pclk_cntl_t f; +} __attribute__((packed)); + +struct clk_test_cntl_t { + unsigned long testclk_sel : 4; + unsigned long : 3; + unsigned long start_check_freq : 1; + unsigned long tstcount_rst : 1; + unsigned long : 15; + unsigned long test_count : 8; +} __attribute__((packed)); + +union clk_test_cntl_u { + unsigned long val : 32; + struct clk_test_cntl_t f; +} __attribute__((packed)); + +struct pwrmgt_cntl_t { + unsigned long pwm_enable : 1; + unsigned long : 1; + unsigned long pwm_mode_req : 2; + unsigned long pwm_wakeup_cond : 2; + unsigned long pwm_fast_noml_hw_en : 1; + unsigned long pwm_noml_fast_hw_en : 1; + unsigned long pwm_fast_noml_cond : 4; + unsigned long pwm_noml_fast_cond : 4; + unsigned long pwm_idle_timer : 8; + unsigned long pwm_busy_timer : 8; +} __attribute__((packed)); + +union pwrmgt_cntl_u { + unsigned long val : 32; + struct pwrmgt_cntl_t f; +} __attribute__((packed)); + +#endif + |