From: "Antonino A. Daplas" Because nVidia keeps pumping out new graphics chipsets, it is becoming harder to add support for these with the old rivafb code. Currently, rivafb can properly support NV_ARCH_20 chipsets and older. Instead of rewriting rivafb to support the latest chipsets, I've decided to write a new driver, called nvidiafb. The aim is to closely follow Xorg development. Currently, this driver is based on the most recent CVS Xorg nv driver. Main - console acceleration for all chipsets - uses DMA instead of PIO - better LCD/digital output support - better monitor detection - support for Riva128 will be dropped as it cannot do DMA, rivafb will remain as the driver for this chipset It should work with Xorg/XFree86 nv driver, but as with rivafb, is not compatible with the proprietary nvidia driver. Once the code becomes stable, rivafb code will be trimmed to only support the Riva128 and perhaps some of the older chipsets. The code has been tested on several nVidia graphics card on x86 and x86_64. I'm still waiting for feedback from Guido Guenther regarding ppc. This need not go to mainline immediately, as I would prefer the code to receive rigorous testing in the mm tree. Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton --- 25-akpm/drivers/video/Kconfig | 32 25-akpm/drivers/video/Makefile | 1 25-akpm/drivers/video/nvidia/Makefile | 12 25-akpm/drivers/video/nvidia/nv_accel.c | 367 ++++++ 25-akpm/drivers/video/nvidia/nv_dma.h | 178 +++ 25-akpm/drivers/video/nvidia/nv_hw.c | 1582 +++++++++++++++++++++++++++++ 25-akpm/drivers/video/nvidia/nv_i2c.c | 209 +++ 25-akpm/drivers/video/nvidia/nv_local.h | 98 + 25-akpm/drivers/video/nvidia/nv_of.c | 59 + 25-akpm/drivers/video/nvidia/nv_proto.h | 61 + 25-akpm/drivers/video/nvidia/nv_setup.c | 622 +++++++++++ 25-akpm/drivers/video/nvidia/nv_type.h | 174 +++ 25-akpm/drivers/video/nvidia/nvidia.c | 1725 ++++++++++++++++++++++++++++++++ 25-akpm/include/linux/fb.h | 5 25-akpm/include/linux/pci_ids.h | 84 + 15 files changed, 5207 insertions(+), 2 deletions(-) diff -puN drivers/video/Kconfig~nvidiafb-add-update-framebuffer-driver-for-nvidia-chipsets drivers/video/Kconfig --- 25/drivers/video/Kconfig~nvidiafb-add-update-framebuffer-driver-for-nvidia-chipsets 2005-02-24 23:15:31.000000000 -0800 +++ 25-akpm/drivers/video/Kconfig 2005-02-24 23:15:31.000000000 -0800 @@ -606,6 +606,38 @@ config FB_EPSON1355 framebuffer. Product specs at . +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 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. + none yet + +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 diff -puN drivers/video/Makefile~nvidiafb-add-update-framebuffer-driver-for-nvidia-chipsets drivers/video/Makefile --- 25/drivers/video/Makefile~nvidiafb-add-update-framebuffer-driver-for-nvidia-chipsets 2005-02-24 23:15:31.000000000 -0800 +++ 25-akpm/drivers/video/Makefile 2005-02-24 23:15:31.000000000 -0800 @@ -30,6 +30,7 @@ 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/ obj-$(CONFIG_FB_ATY128) += aty/ obj-$(CONFIG_FB_RADEON) += aty/ diff -puN /dev/null drivers/video/nvidia/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/video/nvidia/Makefile 2005-02-24 23:15:31.000000000 -0800 @@ -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 -puN /dev/null drivers/video/nvidia/nv_accel.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/video/nvidia/nv_accel.c 2005-02-24 23:15:31.000000000 -0800 @@ -0,0 +1,367 @@ +/* + * linux/drivers/video/nvidia/nv_accel.c - nVidia Hardware Acceleration + * + * Copyright 2004 Antonino Daplas + * + * 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 +#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; + } +} + +void NVDmaKickoff(struct nvidia_par *par) +{ + if (par->dmaCurrent != par->dmaPut) { + par->dmaPut = par->dmaCurrent; + WRITE_PUT(par, par->dmaPut); + } +} + +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 i, j, k = 0; + + width = (image->width + 31) & ~31; + dsize = width >> 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)); + + for (i = image->height; i--;) { + 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 -puN /dev/null drivers/video/nvidia/nv_dma.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/video/nvidia/nv_dma.h 2005-02-24 23:15:31.000000000 -0800 @@ -0,0 +1,178 @@ + + /***************************************************************************\ +|* *| +|* 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. *| +|* *| + \***************************************************************************/ + +#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 -puN /dev/null drivers/video/nvidia/nv_hw.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/video/nvidia/nv_hw.c 2005-02-24 23:15:31.000000000 -0800 @@ -0,0 +1,1582 @@ + /***************************************************************************\ +|* *| +|* 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. *| +|* *| + \***************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_hw.c,v 1.4 2003/11/03 05:11:25 tsi Exp $ */ + +#include +#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 -puN /dev/null drivers/video/nvidia/nv_i2c.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/video/nvidia/nv_i2c.c 2005-02-24 23:15:31.000000000 -0800 @@ -0,0 +1,209 @@ +/* + * linux/drivers/video/nvidia/nvidia-i2c.c - nVidia i2c + * + * Copyright 2004 Antonino A. Daplas + * + * 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 +#include +#include +#include +#include +#include +#include + +#include + +#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); + 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; + + 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 -puN /dev/null drivers/video/nvidia/nvidia.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/video/nvidia/nvidia.c 2005-02-24 23:15:31.000000000 -0800 @@ -0,0 +1,1725 @@ +/* + * linux/drivers/video/nvidia/nvidia.c - nVidia fb driver + * + * Copyright 2004 Antonino Daplas + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MTRR +#include +#endif +#ifdef CONFIG_PPC_OF +#include +#include +#endif +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#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 __initdata = -1; /* Autodetect later */ +static int forceCRTC __initdata = -1; +static int hwcur __initdata = 0; +static int noaccel __initdata = 0; +static int noscale __initdata = 0; +static int paneltweak __initdata = 0; +#ifdef CONFIG_MTRR +static int nomtrr __initdata = 0; +#endif + +static char *mode_option __initdata = NULL; + +static struct fb_fix_screeninfo __initdata nvidiafb_fix = { + .type = FB_TYPE_PACKED_PIXELS, + .xpanstep = 8, + .ypanstep = 1, +}; + +static struct fb_var_screeninfo __initdata 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); + 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; + var->xres_virtual &= ~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; + + 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; + 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 &= ~8; + + 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 | FBINFO_MISC_MODESWITCHLATE; + + 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); + par->FpScale = (!noscale); + par->paneltweak = paneltweak; + + 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; + + /* 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); + err_out_free_base1: + fb_destroy_modedb(info->monspecs.modedb); + 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 */ + + fb_destroy_modedb(info->monspecs.modedb); + iounmap(par->REGS); + iounmap(info->screen_base); + 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 +int __init 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 + * + * ------------------------------------------------------------------------- */ + +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 -puN /dev/null drivers/video/nvidia/nv_local.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/video/nvidia/nv_local.h 2005-02-24 23:15:31.000000000 -0800 @@ -0,0 +1,98 @@ +/***************************************************************************\ +|* *| +|* 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. *| +|* *| + \***************************************************************************/ + +#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) { \ + volatile u8 scratch; \ + _NV_FENCE() \ + scratch = 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 -puN /dev/null drivers/video/nvidia/nv_of.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/video/nvidia/nv_of.c 2005-02-24 23:15:31.000000000 -0800 @@ -0,0 +1,59 @@ +/* + * linux/drivers/video/nvidia/nv_of.c + * + * Copyright 2004 Antonino A. Daplas + * + * 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 +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#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 -puN /dev/null drivers/video/nvidia/nv_proto.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/video/nvidia/nv_proto.h 2005-02-24 23:15:31.000000000 -0800 @@ -0,0 +1,61 @@ +/* $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 NVEnablePalette(struct nvidia_par *par); +void NVDisablePalette(struct nvidia_par *par); +void NVWriteDacMask(struct nvidia_par *par, u8 value); +u8 NVReadDacMask(struct nvidia_par *par); +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 -puN /dev/null drivers/video/nvidia/nv_setup.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/video/nvidia/nv_setup.c 2005-02-24 23:15:31.000000000 -0800 @@ -0,0 +1,622 @@ + /***************************************************************************\ +|* *| +|* 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. *| +|* *| + \***************************************************************************/ + +#include