Linux-2.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!
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c
new file mode 100644
index 0000000..6a3cfbd
--- /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 0000000..2a1c596
--- /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 0000000..92265b7
--- /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 0000000..455fda9
--- /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 0000000..f02965f
--- /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 0000000..fb2a7ff
--- /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 0000000..acdba0c
--- /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 0000000..cf8bb67
--- /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 0000000..f4729f4
--- /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 0000000..15ec129
--- /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 0000000..9dec962
--- /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 0000000..13321c6
--- /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 0000000..8a4ba3b
--- /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 0000000..09de173
--- /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 0000000..8c42538
--- /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 Syrjälä 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 0000000..c98f4a4
--- /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 0000000..9bdb2aa
--- /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 0000000..ad8b749
--- /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 0000000..01fdff7
--- /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 0000000..3ca27cb
--- /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 0000000..e8eb124
--- /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 0000000..7622441
--- /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 0000000..ea7c863
--- /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 0000000..23c677e
--- /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 0000000..659bc9f
--- /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 0000000..92643af
--- /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 0000000..cacd88c
--- /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 0000000..657c560
--- /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 0000000..996d543
--- /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 0000000..9aae884
--- /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 0000000..acc81cb
--- /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 0000000..3c026b0
--- /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 0000000..470e6f0
--- /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 0000000..c826f27
--- /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 0000000..b7591fe
--- /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 0000000..3d20b2d
--- /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 0000000..5c30bbd
--- /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 0000000..c77cbf1
--- /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 0000000..67711f7
--- /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 0000000..e4fc42b
--- /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 0000000..4c123ab
--- /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 0000000..18e60b9
--- /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 0000000..6e7d8d4
--- /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 0000000..49a2545
--- /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 0000000..ab98f22
--- /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 0000000..a304042
--- /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 0000000..8692e00
--- /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 0000000..ccf5581
--- /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 0000000..3351644
--- /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 0000000..b28a4b0
--- /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 0000000..1ecda91
--- /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 0000000..59e3b4b
--- /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 0000000..5d37786
--- /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 0000000..c52f129
--- /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 0000000..e6f8dba
--- /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 0000000..57fbe26
--- /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 0000000..d565505
--- /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 0000000..593b955
--- /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 0000000..5fa95f1
--- /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 0000000..05215d0
--- /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 0000000..2af3ab3
--- /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 0000000..465d678
--- /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 0000000..989e4d4
--- /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 0000000..e793ffd
--- /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 0000000..58f9c04
--- /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 0000000..04f42fc
--- /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 0000000..fd5940f
--- /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 0000000..d940f60
--- /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 0000000..7f76e2c
--- /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 0000000..7d1ae06
--- /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 0000000..989e700
--- /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 0000000..6026c60
--- /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 0000000..8b1b7c6
--- /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 0000000..bd7e1c0
--- /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 0000000..a3e189f
--- /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 0000000..8435c43
--- /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 0000000..1dbb82d
--- /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 0000000..bd89fb3
--- /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 0000000..116e808
--- /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 0000000..c51f8fb
--- /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 0000000..25f460c
--- /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 0000000..978def0
--- /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 0000000..2bdda40
--- /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 0000000..10cd050
--- /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 0000000..a076328
--- /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 0000000..605d1a1
--- /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 0000000..2a02328
--- /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 0000000..b075fd0
--- /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 0000000..13ad501e
--- /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 0000000..f498387
--- /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 0000000..671c055
--- /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 0000000..b7bac0a
--- /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 0000000..83830d2
--- /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 0000000..d3764ac
--- /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 0000000..56cecca
--- /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 0000000..b37cea7
--- /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 0000000..0d376ba
--- /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 0000000..e97fe84
--- /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 0000000..794ae76
--- /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 0000000..fe3b757
--- /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 0000000..64cd1c8
--- /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 0000000..27fa703
--- /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 0000000..64f087a
--- /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 0000000..9ec8781
--- /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 0000000..43b4297
--- /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 0000000..6e4b9af
--- /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 0000000..e326f44
--- /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 0000000..5a72ca3
--- /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 0000000..722d21d
--- /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 0000000..6680ec9
--- /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 0000000..6a05b70
--- /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 0000000..cc30581
--- /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 0000000..f5bed58
--- /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 0000000..ba19201
--- /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 0000000..2fd66f5
--- /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 0000000..7e33cd30
--- /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 0000000..e75b3b4
--- /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 0000000..2ae9baf
--- /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 0000000..e6ad037
--- /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 0000000..244549e
--- /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 0000000..3690b04
--- /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 0000000..d8bac9e
--- /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 0000000..7e1e7fb
--- /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 0000000..849b47b
--- /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 0000000..b0d9950
--- /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 0000000..aaf7c38
--- /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 0000000..77b6220
--- /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 0000000..fd921ad
--- /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 0000000..3c14e43
--- /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 0000000..2f14d9f
--- /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 0000000..1850c15
--- /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 0000000..4dad34b
--- /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 0000000..9bf89ef
--- /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 0000000..6fe4697
--- /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 0000000..40e6339
--- /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 0000000..0241aac
--- /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 0000000..6cd378e
--- /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 0000000..a8ffcd7
--- /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 0000000..4945a4c
--- /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 0000000..de5a0f3
--- /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 0000000..232f5a09
--- /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 0000000..f9c00eb
--- /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 0000000..8073a73
--- /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 0000000..c17ed74
--- /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 0000000..57abbae
--- /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 0000000..149680f
--- /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 0000000..a6a4701
--- /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 0000000..537ade5
--- /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 0000000..541933d
--- /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 0000000..c7f3e13
--- /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 0000000..f40c314
--- /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 0000000..98e00d8
--- /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 0000000..85a0b25
--- /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 0000000..429047a
--- /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 0000000..608e40b
--- /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 0000000..35008af
--- /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 0000000..a0822a6
--- /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 0000000..e529841
--- /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 0000000..99eddec
--- /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 0000000..76fd3a5
--- /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 0000000..cb62cc0
--- /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 0000000..f192d99
--- /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 0000000..fbf659b
--- /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 0000000..5d424a3
--- /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 0000000..690d37e
--- /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 0000000..f377a29
--- /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 0000000..a7ed1c0
--- /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 0000000..b989358
--- /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 0000000..3757c14
--- /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 0000000..9da3209
--- /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 0000000..7d12eb85
--- /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 0000000..42847ce
--- /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 0000000..0bbdca2
--- /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 0000000..e4a5b1d
--- /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 0000000..3a6555a
--- /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 0000000..42a6591
--- /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 0000000..7808a01
--- /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 0000000..3dd1de1
--- /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 0000000..2834fc1
--- /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 0000000..5dcedde
--- /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 0000000..8e024aa
--- /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 0000000..3e00ad7
--- /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 0000000..f809558
--- /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 0000000..d14eaee
--- /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 0000000..31c547f
--- /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 0000000..483ad9b
--- /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 0000000..de15fec
--- /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 0000000..71b69da
--- /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 0000000..d9a084e
--- /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 0000000..5e2c64f
--- /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 0000000..5cc7510
--- /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 0000000..8898c99
--- /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 0000000..b0c886d
--- /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 0000000..3b5f911
--- /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 0000000..be630a0
--- /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 0000000..a69480c
--- /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 0000000..abfc167
--- /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 0000000..b6f8690
--- /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 0000000..a1e71a6
--- /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 0000000..7ee7d72
--- /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 0000000..da1334d
--- /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 0000000..440ff44
--- /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 0000000..b637c38
--- /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 0000000..4f8043a
--- /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 0000000..0b07f6a
--- /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 0000000..e09770f
--- /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 0000000..024a0ce
--- /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 0000000..8594b1e
--- /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 0000000..bac8ea3
--- /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 0000000..e1c9c94
--- /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 0000000..34f72ed
--- /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 0000000..a6aa33b
--- /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 0000000..8413907
--- /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 0000000..b6d5c71
--- /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 0000000..2c71d04
--- /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 0000000..aaed8c2
--- /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 0000000..1994054
--- /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 0000000..35030d3
--- /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 0000000..2bc5b80
--- /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 0000000..f05aebc
--- /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 0000000..55a82d6
--- /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 0000000..b1358b7
--- /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 0000000..2b7db91
--- /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 0000000..15939b0
--- /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 0000000..d0103c1
--- /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 0000000..30e90a5
--- /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 0000000..bb28f33
--- /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 0000000..b773c98
--- /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 0000000..a6678a7
--- /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 0000000..507bba1
--- /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 0000000..d4d55c9
--- /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 0000000..7b43716
--- /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 0000000..13a4511
--- /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 0000000..663d536
--- /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 0000000..dc93336
--- /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 0000000..9e52794
--- /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 0000000..9b36b9d
--- /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 0000000..e2fa9e1
--- /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 0000000..c34ba39
--- /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 0000000..3099630
--- /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 0000000..da8004e
--- /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 0000000..39d9ca7
--- /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 0000000..31a2bbc
--- /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 0000000..97aaf7b
--- /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 0000000..8fc1278
--- /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 0000000..b137a3f
--- /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 0000000..b46454c
--- /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 0000000..0ea62d8
--- /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 0000000..ed78747
--- /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 0000000..157d66d
--- /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 0000000..057e154
--- /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 0000000..41624f9
--- /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
+