From 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 16 Apr 2005 15:20:36 -0700 Subject: Linux-2.6.12-rc2 Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip! --- drivers/video/nvidia/Makefile | 12 + drivers/video/nvidia/nv_accel.c | 419 ++++++++++ drivers/video/nvidia/nv_dma.h | 188 +++++ drivers/video/nvidia/nv_hw.c | 1593 ++++++++++++++++++++++++++++++++++++ drivers/video/nvidia/nv_i2c.c | 215 +++++ drivers/video/nvidia/nv_local.h | 107 +++ drivers/video/nvidia/nv_of.c | 59 ++ drivers/video/nvidia/nv_proto.h | 58 ++ drivers/video/nvidia/nv_setup.c | 636 ++++++++++++++ drivers/video/nvidia/nv_type.h | 174 ++++ drivers/video/nvidia/nvidia.c | 1729 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 5190 insertions(+) create mode 100644 drivers/video/nvidia/Makefile create mode 100644 drivers/video/nvidia/nv_accel.c create mode 100644 drivers/video/nvidia/nv_dma.h create mode 100644 drivers/video/nvidia/nv_hw.c create mode 100644 drivers/video/nvidia/nv_i2c.c create mode 100644 drivers/video/nvidia/nv_local.h create mode 100644 drivers/video/nvidia/nv_of.c create mode 100644 drivers/video/nvidia/nv_proto.h create mode 100644 drivers/video/nvidia/nv_setup.c create mode 100644 drivers/video/nvidia/nv_type.h create mode 100644 drivers/video/nvidia/nvidia.c (limited to 'drivers/video/nvidia') diff --git a/drivers/video/nvidia/Makefile b/drivers/video/nvidia/Makefile new file mode 100644 index 00000000000..690d37e8de5 --- /dev/null +++ b/drivers/video/nvidia/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the nVidia framebuffer driver +# + +obj-$(CONFIG_FB_NVIDIA) += nvidiafb.o + +nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \ + nv_accel.o +nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o +nvidiafb-$(CONFIG_PPC_OF) += nv_of.o + +nvidiafb-objs := $(nvidiafb-y) \ No newline at end of file diff --git a/drivers/video/nvidia/nv_accel.c b/drivers/video/nvidia/nv_accel.c new file mode 100644 index 00000000000..f377a29ec97 --- /dev/null +++ b/drivers/video/nvidia/nv_accel.c @@ -0,0 +1,419 @@ + /***************************************************************************\ +|* *| +|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/ + * XFree86 'nv' driver, this source code is provided under MIT-style licensing + * where the source code is provided "as is" without warranty of any kind. + * The only usage restriction is for the copyright notices to be retained + * whenever code is used. + * + * Antonino Daplas 2005-03-11 + */ + +#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; + } +} + +static void NVDmaKickoff(struct nvidia_par *par) +{ + if (par->dmaCurrent != par->dmaPut) { + par->dmaPut = par->dmaCurrent; + WRITE_PUT(par, par->dmaPut); + } +} + +static void NVDmaWait(struct nvidia_par *par, int size) +{ + int dmaGet; + int count = 1000000000, cnt; + size++; + + while (par->dmaFree < size && --count && !par->lockup) { + dmaGet = READ_GET(par); + + if (par->dmaPut >= dmaGet) { + par->dmaFree = par->dmaMax - par->dmaCurrent; + if (par->dmaFree < size) { + NVDmaNext(par, 0x20000000); + if (dmaGet <= SKIPS) { + if (par->dmaPut <= SKIPS) + WRITE_PUT(par, SKIPS + 1); + cnt = 1000000000; + do { + dmaGet = READ_GET(par); + } while (--cnt && dmaGet <= SKIPS); + if (!cnt) { + printk("DMA Get lockup\n"); + par->lockup = 1; + } + } + WRITE_PUT(par, SKIPS); + par->dmaCurrent = par->dmaPut = SKIPS; + par->dmaFree = dmaGet - (SKIPS + 1); + } + } else + par->dmaFree = dmaGet - par->dmaCurrent - 1; + } + + if (!count) { + printk("DMA Wait Lockup\n"); + par->lockup = 1; + } +} + +static void NVSetPattern(struct nvidia_par *par, u32 clr0, u32 clr1, + u32 pat0, u32 pat1) +{ + NVDmaStart(par, PATTERN_COLOR_0, 4); + NVDmaNext(par, clr0); + NVDmaNext(par, clr1); + NVDmaNext(par, pat0); + NVDmaNext(par, pat1); +} + +static void NVSetRopSolid(struct nvidia_par *par, u32 rop, u32 planemask) +{ + if (planemask != ~0) { + NVSetPattern(par, 0, planemask, ~0, ~0); + if (par->currentRop != (rop + 32)) { + NVDmaStart(par, ROP_SET, 1); + NVDmaNext(par, NVCopyROP_PM[rop]); + par->currentRop = rop + 32; + } + } else if (par->currentRop != rop) { + if (par->currentRop >= 16) + NVSetPattern(par, ~0, ~0, ~0, ~0); + NVDmaStart(par, ROP_SET, 1); + NVDmaNext(par, NVCopyROP[rop]); + par->currentRop = rop; + } +} + +static void NVSetClippingRectangle(struct fb_info *info, int x1, int y1, + int x2, int y2) +{ + struct nvidia_par *par = info->par; + int h = y2 - y1 + 1; + int w = x2 - x1 + 1; + + NVDmaStart(par, CLIP_POINT, 2); + NVDmaNext(par, (y1 << 16) | x1); + NVDmaNext(par, (h << 16) | w); +} + +void NVResetGraphics(struct fb_info *info) +{ + struct nvidia_par *par = info->par; + u32 surfaceFormat, patternFormat, rectFormat, lineFormat; + int pitch, i; + + pitch = info->fix.line_length; + + par->dmaBase = (u32 __iomem *) (&par->FbStart[par->FbUsableSize]); + + for (i = 0; i < SKIPS; i++) + NV_WR32(&par->dmaBase[i], 0, 0x00000000); + + NV_WR32(&par->dmaBase[0x0 + SKIPS], 0, 0x00040000); + NV_WR32(&par->dmaBase[0x1 + SKIPS], 0, 0x80000010); + NV_WR32(&par->dmaBase[0x2 + SKIPS], 0, 0x00042000); + NV_WR32(&par->dmaBase[0x3 + SKIPS], 0, 0x80000011); + NV_WR32(&par->dmaBase[0x4 + SKIPS], 0, 0x00044000); + NV_WR32(&par->dmaBase[0x5 + SKIPS], 0, 0x80000012); + NV_WR32(&par->dmaBase[0x6 + SKIPS], 0, 0x00046000); + NV_WR32(&par->dmaBase[0x7 + SKIPS], 0, 0x80000013); + NV_WR32(&par->dmaBase[0x8 + SKIPS], 0, 0x00048000); + NV_WR32(&par->dmaBase[0x9 + SKIPS], 0, 0x80000014); + NV_WR32(&par->dmaBase[0xA + SKIPS], 0, 0x0004A000); + NV_WR32(&par->dmaBase[0xB + SKIPS], 0, 0x80000015); + NV_WR32(&par->dmaBase[0xC + SKIPS], 0, 0x0004C000); + NV_WR32(&par->dmaBase[0xD + SKIPS], 0, 0x80000016); + NV_WR32(&par->dmaBase[0xE + SKIPS], 0, 0x0004E000); + NV_WR32(&par->dmaBase[0xF + SKIPS], 0, 0x80000017); + + par->dmaPut = 0; + par->dmaCurrent = 16 + SKIPS; + par->dmaMax = 8191; + par->dmaFree = par->dmaMax - par->dmaCurrent; + + switch (info->var.bits_per_pixel) { + case 32: + case 24: + surfaceFormat = SURFACE_FORMAT_DEPTH24; + patternFormat = PATTERN_FORMAT_DEPTH24; + rectFormat = RECT_FORMAT_DEPTH24; + lineFormat = LINE_FORMAT_DEPTH24; + break; + case 16: + surfaceFormat = SURFACE_FORMAT_DEPTH16; + patternFormat = PATTERN_FORMAT_DEPTH16; + rectFormat = RECT_FORMAT_DEPTH16; + lineFormat = LINE_FORMAT_DEPTH16; + break; + default: + surfaceFormat = SURFACE_FORMAT_DEPTH8; + patternFormat = PATTERN_FORMAT_DEPTH8; + rectFormat = RECT_FORMAT_DEPTH8; + lineFormat = LINE_FORMAT_DEPTH8; + break; + } + + NVDmaStart(par, SURFACE_FORMAT, 4); + NVDmaNext(par, surfaceFormat); + NVDmaNext(par, pitch | (pitch << 16)); + NVDmaNext(par, 0); + NVDmaNext(par, 0); + + NVDmaStart(par, PATTERN_FORMAT, 1); + NVDmaNext(par, patternFormat); + + NVDmaStart(par, RECT_FORMAT, 1); + NVDmaNext(par, rectFormat); + + NVDmaStart(par, LINE_FORMAT, 1); + NVDmaNext(par, lineFormat); + + par->currentRop = ~0; /* set to something invalid */ + NVSetRopSolid(par, ROP_COPY, ~0); + + NVSetClippingRectangle(info, 0, 0, info->var.xres_virtual, + info->var.yres_virtual); + + NVDmaKickoff(par); +} + +u8 byte_rev[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + +int nvidiafb_sync(struct fb_info *info) +{ + struct nvidia_par *par = info->par; + + if (!par->lockup) + NVFlush(par); + + if (!par->lockup) + NVSync(par); + + return 0; +} + +void nvidiafb_copyarea(struct fb_info *info, const struct fb_copyarea *region) +{ + struct nvidia_par *par = info->par; + + if (par->lockup) + return cfb_copyarea(info, region); + + NVDmaStart(par, BLIT_POINT_SRC, 3); + NVDmaNext(par, (region->sy << 16) | region->sx); + NVDmaNext(par, (region->dy << 16) | region->dx); + NVDmaNext(par, (region->height << 16) | region->width); + + NVDmaKickoff(par); +} + +void nvidiafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct nvidia_par *par = info->par; + u32 color; + + if (par->lockup) + return cfb_fillrect(info, rect); + + if (info->var.bits_per_pixel == 8) + color = rect->color; + else + color = ((u32 *) info->pseudo_palette)[rect->color]; + + if (rect->rop != ROP_COPY) + NVSetRopSolid(par, rect->rop, ~0); + + NVDmaStart(par, RECT_SOLID_COLOR, 1); + NVDmaNext(par, color); + + NVDmaStart(par, RECT_SOLID_RECTS(0), 2); + NVDmaNext(par, (rect->dx << 16) | rect->dy); + NVDmaNext(par, (rect->width << 16) | rect->height); + + NVDmaKickoff(par); + + if (rect->rop != ROP_COPY) + NVSetRopSolid(par, ROP_COPY, ~0); +} + +static void nvidiafb_mono_color_expand(struct fb_info *info, + const struct fb_image *image) +{ + struct nvidia_par *par = info->par; + u32 fg, bg, mask = ~(~0 >> (32 - info->var.bits_per_pixel)); + u32 dsize, width, *data = (u32 *) image->data, tmp; + int j, k = 0; + + width = (image->width + 31) & ~31; + dsize = (width * image->height) >> 5; + + if (info->var.bits_per_pixel == 8) { + fg = image->fg_color | mask; + bg = image->bg_color | mask; + } else { + fg = ((u32 *) info->pseudo_palette)[image->fg_color] | mask; + bg = ((u32 *) info->pseudo_palette)[image->bg_color] | mask; + } + + NVDmaStart(par, RECT_EXPAND_TWO_COLOR_CLIP, 7); + NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff)); + NVDmaNext(par, ((image->dy + image->height) << 16) | + ((image->dx + image->width) & 0xffff)); + NVDmaNext(par, bg); + NVDmaNext(par, fg); + NVDmaNext(par, (image->height << 16) | width); + NVDmaNext(par, (image->height << 16) | width); + NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff)); + + while (dsize >= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS) { + NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0), + RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS); + + for (j = RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS; j--;) { + tmp = data[k++]; + reverse_order(&tmp); + NVDmaNext(par, tmp); + } + + dsize -= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS; + } + + if (dsize) { + NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0), dsize); + + for (j = dsize; j--;) { + tmp = data[k++]; + reverse_order(&tmp); + NVDmaNext(par, tmp); + } + } + + NVDmaKickoff(par); +} + +void nvidiafb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct nvidia_par *par = info->par; + + if (image->depth == 1 && !par->lockup) + nvidiafb_mono_color_expand(info, image); + else + cfb_imageblit(info, image); +} diff --git a/drivers/video/nvidia/nv_dma.h b/drivers/video/nvidia/nv_dma.h new file mode 100644 index 00000000000..a7ed1c0acbb --- /dev/null +++ b/drivers/video/nvidia/nv_dma.h @@ -0,0 +1,188 @@ + + /***************************************************************************\ +|* *| +|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/ + * XFree86 'nv' driver, this source code is provided under MIT-style licensing + * where the source code is provided "as is" without warranty of any kind. + * The only usage restriction is for the copyright notices to be retained + * whenever code is used. + * + * Antonino Daplas 2005-03-11 + */ + +#define SURFACE_FORMAT 0x00000300 +#define SURFACE_FORMAT_DEPTH8 0x00000001 +#define SURFACE_FORMAT_DEPTH15 0x00000002 +#define SURFACE_FORMAT_DEPTH16 0x00000004 +#define SURFACE_FORMAT_DEPTH24 0x00000006 +#define SURFACE_PITCH 0x00000304 +#define SURFACE_PITCH_SRC 15:0 +#define SURFACE_PITCH_DST 31:16 +#define SURFACE_OFFSET_SRC 0x00000308 +#define SURFACE_OFFSET_DST 0x0000030C + +#define ROP_SET 0x00002300 + +#define PATTERN_FORMAT 0x00004300 +#define PATTERN_FORMAT_DEPTH8 0x00000003 +#define PATTERN_FORMAT_DEPTH16 0x00000001 +#define PATTERN_FORMAT_DEPTH24 0x00000003 +#define PATTERN_COLOR_0 0x00004310 +#define PATTERN_COLOR_1 0x00004314 +#define PATTERN_PATTERN_0 0x00004318 +#define PATTERN_PATTERN_1 0x0000431C + +#define CLIP_POINT 0x00006300 +#define CLIP_POINT_X 15:0 +#define CLIP_POINT_Y 31:16 +#define CLIP_SIZE 0x00006304 +#define CLIP_SIZE_WIDTH 15:0 +#define CLIP_SIZE_HEIGHT 31:16 + +#define LINE_FORMAT 0x00008300 +#define LINE_FORMAT_DEPTH8 0x00000003 +#define LINE_FORMAT_DEPTH16 0x00000001 +#define LINE_FORMAT_DEPTH24 0x00000003 +#define LINE_COLOR 0x00008304 +#define LINE_MAX_LINES 16 +#define LINE_LINES(i) 0x00008400\ + +(i)*8 +#define LINE_LINES_POINT0_X 15:0 +#define LINE_LINES_POINT0_Y 31:16 +#define LINE_LINES_POINT1_X 47:32 +#define LINE_LINES_POINT1_Y 63:48 + +#define BLIT_POINT_SRC 0x0000A300 +#define BLIT_POINT_SRC_X 15:0 +#define BLIT_POINT_SRC_Y 31:16 +#define BLIT_POINT_DST 0x0000A304 +#define BLIT_POINT_DST_X 15:0 +#define BLIT_POINT_DST_Y 31:16 +#define BLIT_SIZE 0x0000A308 +#define BLIT_SIZE_WIDTH 15:0 +#define BLIT_SIZE_HEIGHT 31:16 + +#define RECT_FORMAT 0x0000C300 +#define RECT_FORMAT_DEPTH8 0x00000003 +#define RECT_FORMAT_DEPTH16 0x00000001 +#define RECT_FORMAT_DEPTH24 0x00000003 +#define RECT_SOLID_COLOR 0x0000C3FC +#define RECT_SOLID_RECTS_MAX_RECTS 32 +#define RECT_SOLID_RECTS(i) 0x0000C400\ + +(i)*8 +#define RECT_SOLID_RECTS_Y 15:0 +#define RECT_SOLID_RECTS_X 31:16 +#define RECT_SOLID_RECTS_HEIGHT 47:32 +#define RECT_SOLID_RECTS_WIDTH 63:48 + +#define RECT_EXPAND_ONE_COLOR_CLIP 0x0000C7EC +#define RECT_EXPAND_ONE_COLOR_CLIP_POINT0_X 15:0 +#define RECT_EXPAND_ONE_COLOR_CLIP_POINT0_Y 31:16 +#define RECT_EXPAND_ONE_COLOR_CLIP_POINT1_X 47:32 +#define RECT_EXPAND_ONE_COLOR_CLIP_POINT1_Y 63:48 +#define RECT_EXPAND_ONE_COLOR_COLOR 0x0000C7F4 +#define RECT_EXPAND_ONE_COLOR_SIZE 0x0000C7F8 +#define RECT_EXPAND_ONE_COLOR_SIZE_WIDTH 15:0 +#define RECT_EXPAND_ONE_COLOR_SIZE_HEIGHT 31:16 +#define RECT_EXPAND_ONE_COLOR_POINT 0x0000C7FC +#define RECT_EXPAND_ONE_COLOR_POINT_X 15:0 +#define RECT_EXPAND_ONE_COLOR_POINT_Y 31:16 +#define RECT_EXPAND_ONE_COLOR_DATA_MAX_DWORDS 128 +#define RECT_EXPAND_ONE_COLOR_DATA(i) 0x0000C800\ + +(i)*4 + +#define RECT_EXPAND_TWO_COLOR_CLIP 0x0000CBE4 +#define RECT_EXPAND_TWO_COLOR_CLIP_POINT0_X 15:0 +#define RECT_EXPAND_TWO_COLOR_CLIP_POINT0_Y 31:16 +#define RECT_EXPAND_TWO_COLOR_CLIP_POINT1_X 47:32 +#define RECT_EXPAND_TWO_COLOR_CLIP_POINT1_Y 63:48 +#define RECT_EXPAND_TWO_COLOR_COLOR_0 0x0000CBEC +#define RECT_EXPAND_TWO_COLOR_COLOR_1 0x0000CBF0 +#define RECT_EXPAND_TWO_COLOR_SIZE_IN 0x0000CBF4 +#define RECT_EXPAND_TWO_COLOR_SIZE_IN_WIDTH 15:0 +#define RECT_EXPAND_TWO_COLOR_SIZE_IN_HEIGHT 31:16 +#define RECT_EXPAND_TWO_COLOR_SIZE_OUT 0x0000CBF8 +#define RECT_EXPAND_TWO_COLOR_SIZE_OUT_WIDTH 15:0 +#define RECT_EXPAND_TWO_COLOR_SIZE_OUT_HEIGHT 31:16 +#define RECT_EXPAND_TWO_COLOR_POINT 0x0000CBFC +#define RECT_EXPAND_TWO_COLOR_POINT_X 15:0 +#define RECT_EXPAND_TWO_COLOR_POINT_Y 31:16 +#define RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS 128 +#define RECT_EXPAND_TWO_COLOR_DATA(i) 0x0000CC00\ + +(i)*4 + +#define STRETCH_BLIT_FORMAT 0x0000E300 +#define STRETCH_BLIT_FORMAT_DEPTH8 0x00000004 +#define STRETCH_BLIT_FORMAT_DEPTH16 0x00000007 +#define STRETCH_BLIT_FORMAT_DEPTH24 0x00000004 +#define STRETCH_BLIT_FORMAT_X8R8G8B8 0x00000004 +#define STRETCH_BLIT_FORMAT_YUYV 0x00000005 +#define STRETCH_BLIT_FORMAT_UYVY 0x00000006 +#define STRETCH_BLIT_CLIP_POINT 0x0000E308 +#define STRETCH_BLIT_CLIP_POINT_X 15:0 +#define STRETCH_BLIT_CLIP_POINT_Y 31:16 +#define STRETCH_BLIT_CLIP_POINT 0x0000E308 +#define STRETCH_BLIT_CLIP_SIZE 0x0000E30C +#define STRETCH_BLIT_CLIP_SIZE_WIDTH 15:0 +#define STRETCH_BLIT_CLIP_SIZE_HEIGHT 31:16 +#define STRETCH_BLIT_DST_POINT 0x0000E310 +#define STRETCH_BLIT_DST_POINT_X 15:0 +#define STRETCH_BLIT_DST_POINT_Y 31:16 +#define STRETCH_BLIT_DST_SIZE 0x0000E314 +#define STRETCH_BLIT_DST_SIZE_WIDTH 15:0 +#define STRETCH_BLIT_DST_SIZE_HEIGHT 31:16 +#define STRETCH_BLIT_DU_DX 0x0000E318 +#define STRETCH_BLIT_DV_DY 0x0000E31C +#define STRETCH_BLIT_SRC_SIZE 0x0000E400 +#define STRETCH_BLIT_SRC_SIZE_WIDTH 15:0 +#define STRETCH_BLIT_SRC_SIZE_HEIGHT 31:16 +#define STRETCH_BLIT_SRC_FORMAT 0x0000E404 +#define STRETCH_BLIT_SRC_FORMAT_PITCH 15:0 +#define STRETCH_BLIT_SRC_FORMAT_ORIGIN 23:16 +#define STRETCH_BLIT_SRC_FORMAT_ORIGIN_CENTER 0x00000001 +#define STRETCH_BLIT_SRC_FORMAT_ORIGIN_CORNER 0x00000002 +#define STRETCH_BLIT_SRC_FORMAT_FILTER 31:24 +#define STRETCH_BLIT_SRC_FORMAT_FILTER_POINT_SAMPLE 0x00000000 +#define STRETCH_BLIT_SRC_FORMAT_FILTER_BILINEAR 0x00000001 +#define STRETCH_BLIT_SRC_OFFSET 0x0000E408 +#define STRETCH_BLIT_SRC_POINT 0x0000E40C +#define STRETCH_BLIT_SRC_POINT_U 15:0 +#define STRETCH_BLIT_SRC_POINT_V 31:16 diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c new file mode 100644 index 00000000000..b989358437b --- /dev/null +++ b/drivers/video/nvidia/nv_hw.c @@ -0,0 +1,1593 @@ + /***************************************************************************\ +|* *| +|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/ + * XFree86 'nv' driver, this source code is provided under MIT-style licensing + * where the source code is provided "as is" without warranty of any kind. + * The only usage restriction is for the copyright notices to be retained + * whenever code is used. + * + * Antonino Daplas 2005-03-11 + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_hw.c,v 1.4 2003/11/03 05:11:25 tsi Exp $ */ + +#include +#include "nv_type.h" +#include "nv_local.h" + +void NVLockUnlock(struct nvidia_par *par, int Lock) +{ + u8 cr11; + + VGA_WR08(par->PCIO, 0x3D4, 0x1F); + VGA_WR08(par->PCIO, 0x3D5, Lock ? 0x99 : 0x57); + + VGA_WR08(par->PCIO, 0x3D4, 0x11); + cr11 = VGA_RD08(par->PCIO, 0x3D5); + if (Lock) + cr11 |= 0x80; + else + cr11 &= ~0x80; + VGA_WR08(par->PCIO, 0x3D5, cr11); +} + +int NVShowHideCursor(struct nvidia_par *par, int ShowHide) +{ + int cur = par->CurrentState->cursor1; + + par->CurrentState->cursor1 = (par->CurrentState->cursor1 & 0xFE) | + (ShowHide & 0x01); + VGA_WR08(par->PCIO, 0x3D4, 0x31); + VGA_WR08(par->PCIO, 0x3D5, par->CurrentState->cursor1); + + if (par->Architecture == NV_ARCH_40) + NV_WR32(par->PRAMDAC, 0x0300, NV_RD32(par->PRAMDAC, 0x0300)); + + return (cur & 0x01); +} + +/****************************************************************************\ +* * +* The video arbitration routines calculate some "magic" numbers. Fixes * +* the snow seen when accessing the framebuffer without it. * +* It just works (I hope). * +* * +\****************************************************************************/ + +typedef struct { + int graphics_lwm; + int video_lwm; + int graphics_burst_size; + int video_burst_size; + int valid; +} nv4_fifo_info; + +typedef struct { + int pclk_khz; + int mclk_khz; + int nvclk_khz; + char mem_page_miss; + char mem_latency; + int memory_width; + char enable_video; + char gr_during_vid; + char pix_bpp; + char mem_aligned; + char enable_mp; +} nv4_sim_state; + +typedef struct { + int graphics_lwm; + int video_lwm; + int graphics_burst_size; + int video_burst_size; + int valid; +} nv10_fifo_info; + +typedef struct { + int pclk_khz; + int mclk_khz; + int nvclk_khz; + char mem_page_miss; + char mem_latency; + int memory_type; + int memory_width; + char enable_video; + char gr_during_vid; + char pix_bpp; + char mem_aligned; + char enable_mp; +} nv10_sim_state; + +static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk, + unsigned int *NVClk) +{ + unsigned int pll, N, M, MB, NB, P; + + if (par->Architecture >= NV_ARCH_40) { + pll = NV_RD32(par->PMC, 0x4020); + P = (pll >> 16) & 0x03; + pll = NV_RD32(par->PMC, 0x4024); + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + MB = (pll >> 16) & 0xFF; + NB = (pll >> 24) & 0xFF; + *MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; + + pll = NV_RD32(par->PMC, 0x4000); + P = (pll >> 16) & 0x03; + pll = NV_RD32(par->PMC, 0x4004); + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + MB = (pll >> 16) & 0xFF; + NB = (pll >> 24) & 0xFF; + + *NVClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; + } else if (par->twoStagePLL) { + pll = NV_RD32(par->PRAMDAC0, 0x0504); + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + pll = NV_RD32(par->PRAMDAC0, 0x0574); + if (pll & 0x80000000) { + MB = pll & 0xFF; + NB = (pll >> 8) & 0xFF; + } else { + MB = 1; + NB = 1; + } + *MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; + + pll = NV_RD32(par->PRAMDAC0, 0x0500); + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + pll = NV_RD32(par->PRAMDAC0, 0x0570); + if (pll & 0x80000000) { + MB = pll & 0xFF; + NB = (pll >> 8) & 0xFF; + } else { + MB = 1; + NB = 1; + } + *NVClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; + } else + if (((par->Chipset & 0x0ff0) == 0x0300) || + ((par->Chipset & 0x0ff0) == 0x0330)) { + pll = NV_RD32(par->PRAMDAC0, 0x0504); + M = pll & 0x0F; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x07; + if (pll & 0x00000080) { + MB = (pll >> 4) & 0x07; + NB = (pll >> 19) & 0x1f; + } else { + MB = 1; + NB = 1; + } + *MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; + + pll = NV_RD32(par->PRAMDAC0, 0x0500); + M = pll & 0x0F; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x07; + if (pll & 0x00000080) { + MB = (pll >> 4) & 0x07; + NB = (pll >> 19) & 0x1f; + } else { + MB = 1; + NB = 1; + } + *NVClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; + } else { + pll = NV_RD32(par->PRAMDAC0, 0x0504); + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + *MClk = (N * par->CrystalFreqKHz / M) >> P; + + pll = NV_RD32(par->PRAMDAC0, 0x0500); + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + *NVClk = (N * par->CrystalFreqKHz / M) >> P; + } +} + +static void nv4CalcArbitration(nv4_fifo_info * fifo, nv4_sim_state * arb) +{ + int data, pagemiss, cas, width, video_enable, bpp; + int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs; + int found, mclk_extra, mclk_loop, cbs, m1, p1; + int mclk_freq, pclk_freq, nvclk_freq, mp_enable; + int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate; + int vpm_us, us_video, vlwm, video_fill_us, cpm_us, us_crt, clwm; + + fifo->valid = 1; + pclk_freq = arb->pclk_khz; + mclk_freq = arb->mclk_khz; + nvclk_freq = arb->nvclk_khz; + pagemiss = arb->mem_page_miss; + cas = arb->mem_latency; + width = arb->memory_width >> 6; + video_enable = arb->enable_video; + bpp = arb->pix_bpp; + mp_enable = arb->enable_mp; + clwm = 0; + vlwm = 0; + cbs = 128; + pclks = 2; + nvclks = 2; + nvclks += 2; + nvclks += 1; + mclks = 5; + mclks += 3; + mclks += 1; + mclks += cas; + mclks += 1; + mclks += 1; + mclks += 1; + mclks += 1; + mclk_extra = 3; + nvclks += 2; + nvclks += 1; + nvclks += 1; + nvclks += 1; + if (mp_enable) + mclks += 4; + nvclks += 0; + pclks += 0; + found = 0; + vbs = 0; + while (found != 1) { + fifo->valid = 1; + found = 1; + mclk_loop = mclks + mclk_extra; + us_m = mclk_loop * 1000 * 1000 / mclk_freq; + us_n = nvclks * 1000 * 1000 / nvclk_freq; + us_p = nvclks * 1000 * 1000 / pclk_freq; + if (video_enable) { + video_drain_rate = pclk_freq * 2; + crtc_drain_rate = pclk_freq * bpp / 8; + vpagemiss = 2; + vpagemiss += 1; + crtpagemiss = 2; + vpm_us = + (vpagemiss * pagemiss) * 1000 * 1000 / mclk_freq; + if (nvclk_freq * 2 > mclk_freq * width) + video_fill_us = + cbs * 1000 * 1000 / 16 / nvclk_freq; + else + video_fill_us = + cbs * 1000 * 1000 / (8 * width) / + mclk_freq; + us_video = vpm_us + us_m + us_n + us_p + video_fill_us; + vlwm = us_video * video_drain_rate / (1000 * 1000); + vlwm++; + vbs = 128; + if (vlwm > 128) + vbs = 64; + if (vlwm > (256 - 64)) + vbs = 32; + if (nvclk_freq * 2 > mclk_freq * width) + video_fill_us = + vbs * 1000 * 1000 / 16 / nvclk_freq; + else + video_fill_us = + vbs * 1000 * 1000 / (8 * width) / + mclk_freq; + cpm_us = + crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq; + us_crt = + us_video + video_fill_us + cpm_us + us_m + us_n + + us_p; + clwm = us_crt * crtc_drain_rate / (1000 * 1000); + clwm++; + } else { + crtc_drain_rate = pclk_freq * bpp / 8; + crtpagemiss = 2; + crtpagemiss += 1; + cpm_us = + crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq; + us_crt = cpm_us + us_m + us_n + us_p; + clwm = us_crt * crtc_drain_rate / (1000 * 1000); + clwm++; + } + m1 = clwm + cbs - 512; + p1 = m1 * pclk_freq / mclk_freq; + p1 = p1 * bpp / 8; + if ((p1 < m1) && (m1 > 0)) { + fifo->valid = 0; + found = 0; + if (mclk_extra == 0) + found = 1; + mclk_extra--; + } else if (video_enable) { + if ((clwm > 511) || (vlwm > 255)) { + fifo->valid = 0; + found = 0; + if (mclk_extra == 0) + found = 1; + mclk_extra--; + } + } else { + if (clwm > 519) { + fifo->valid = 0; + found = 0; + if (mclk_extra == 0) + found = 1; + mclk_extra--; + } + } + if (clwm < 384) + clwm = 384; + if (vlwm < 128) + vlwm = 128; + data = (int)(clwm); + fifo->graphics_lwm = data; + fifo->graphics_burst_size = 128; + data = (int)((vlwm + 15)); + fifo->video_lwm = data; + fifo->video_burst_size = vbs; + } +} + +static void nv4UpdateArbitrationSettings(unsigned VClk, + unsigned pixelDepth, + unsigned *burst, + unsigned *lwm, struct nvidia_par *par) +{ + nv4_fifo_info fifo_data; + nv4_sim_state sim_data; + unsigned int MClk, NVClk, cfg1; + + nvGetClocks(par, &MClk, &NVClk); + + cfg1 = NV_RD32(par->PFB, 0x00000204); + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 0; + sim_data.enable_mp = 0; + sim_data.memory_width = (NV_RD32(par->PEXTDEV, 0x0000) & 0x10) ? + 128 : 64; + sim_data.mem_latency = (char)cfg1 & 0x0F; + sim_data.mem_aligned = 1; + sim_data.mem_page_miss = + (char)(((cfg1 >> 4) & 0x0F) + ((cfg1 >> 31) & 0x01)); + sim_data.gr_during_vid = 0; + sim_data.pclk_khz = VClk; + sim_data.mclk_khz = MClk; + sim_data.nvclk_khz = NVClk; + nv4CalcArbitration(&fifo_data, &sim_data); + if (fifo_data.valid) { + int b = fifo_data.graphics_burst_size >> 4; + *burst = 0; + while (b >>= 1) + (*burst)++; + *lwm = fifo_data.graphics_lwm >> 3; + } +} + +static void nv10CalcArbitration(nv10_fifo_info * fifo, nv10_sim_state * arb) +{ + int data, pagemiss, width, video_enable, bpp; + int nvclks, mclks, pclks, vpagemiss, crtpagemiss; + int nvclk_fill; + int found, mclk_extra, mclk_loop, cbs, m1; + int mclk_freq, pclk_freq, nvclk_freq, mp_enable; + int us_m, us_m_min, us_n, us_p, crtc_drain_rate; + int vus_m; + int vpm_us, us_video, cpm_us, us_crt, clwm; + int clwm_rnd_down; + int m2us, us_pipe_min, p1clk, p2; + int min_mclk_extra; + int us_min_mclk_extra; + + fifo->valid = 1; + pclk_freq = arb->pclk_khz; /* freq in KHz */ + mclk_freq = arb->mclk_khz; + nvclk_freq = arb->nvclk_khz; + pagemiss = arb->mem_page_miss; + width = arb->memory_width / 64; + video_enable = arb->enable_video; + bpp = arb->pix_bpp; + mp_enable = arb->enable_mp; + clwm = 0; + + cbs = 512; + + pclks = 4; /* lwm detect. */ + + nvclks = 3; /* lwm -> sync. */ + nvclks += 2; /* fbi bus cycles (1 req + 1 busy) */ + /* 2 edge sync. may be very close to edge so just put one. */ + mclks = 1; + mclks += 1; /* arb_hp_req */ + mclks += 5; /* ap_hp_req tiling pipeline */ + + mclks += 2; /* tc_req latency fifo */ + mclks += 2; /* fb_cas_n_ memory request to fbio block */ + mclks += 7; /* sm_d_rdv data returned from fbio block */ + + /* fb.rd.d.Put_gc need to accumulate 256 bits for read */ + if (arb->memory_type == 0) + if (arb->memory_width == 64) /* 64 bit bus */ + mclks += 4; + else + mclks += 2; + else if (arb->memory_width == 64) /* 64 bit bus */ + mclks += 2; + else + mclks += 1; + + if ((!video_enable) && (arb->memory_width == 128)) { + mclk_extra = (bpp == 32) ? 31 : 42; /* Margin of error */ + min_mclk_extra = 17; + } else { + mclk_extra = (bpp == 32) ? 8 : 4; /* Margin of error */ + /* mclk_extra = 4; *//* Margin of error */ + min_mclk_extra = 18; + } + + /* 2 edge sync. may be very close to edge so just put one. */ + nvclks += 1; + nvclks += 1; /* fbi_d_rdv_n */ + nvclks += 1; /* Fbi_d_rdata */ + nvclks += 1; /* crtfifo load */ + + if (mp_enable) + mclks += 4; /* Mp can get in with a burst of 8. */ + /* Extra clocks determined by heuristics */ + + nvclks += 0; + pclks += 0; + found = 0; + while (found != 1) { + fifo->valid = 1; + found = 1; + mclk_loop = mclks + mclk_extra; + /* Mclk latency in us */ + us_m = mclk_loop * 1000 * 1000 / mclk_freq; + /* Minimum Mclk latency in us */ + us_m_min = mclks * 1000 * 1000 / mclk_freq; + us_min_mclk_extra = min_mclk_extra * 1000 * 1000 / mclk_freq; + /* nvclk latency in us */ + us_n = nvclks * 1000 * 1000 / nvclk_freq; + /* nvclk latency in us */ + us_p = pclks * 1000 * 1000 / pclk_freq; + us_pipe_min = us_m_min + us_n + us_p; + + /* Mclk latency in us */ + vus_m = mclk_loop * 1000 * 1000 / mclk_freq; + + if (video_enable) { + crtc_drain_rate = pclk_freq * bpp / 8; /* MB/s */ + + vpagemiss = 1; /* self generating page miss */ + vpagemiss += 1; /* One higher priority before */ + + crtpagemiss = 2; /* self generating page miss */ + if (mp_enable) + crtpagemiss += 1; /* if MA0 conflict */ + + vpm_us = + (vpagemiss * pagemiss) * 1000 * 1000 / mclk_freq; + + /* Video has separate read return path */ + us_video = vpm_us + vus_m; + + cpm_us = + crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq; + /* Wait for video */ + us_crt = us_video + + cpm_us /* CRT Page miss */ + + us_m + us_n + us_p /* other latency */ + ; + + clwm = us_crt * crtc_drain_rate / (1000 * 1000); + /* fixed point <= float_point - 1. Fixes that */ + clwm++; + } else { + /* bpp * pclk/8 */ + crtc_drain_rate = pclk_freq * bpp / 8; + + crtpagemiss = 1; /* self generating page miss */ + crtpagemiss += 1; /* MA0 page miss */ + if (mp_enable) + crtpagemiss += 1; /* if MA0 conflict */ + cpm_us = + crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq; + us_crt = cpm_us + us_m + us_n + us_p; + clwm = us_crt * crtc_drain_rate / (1000 * 1000); + /* fixed point <= float_point - 1. Fixes that */ + clwm++; + + /* Finally, a heuristic check when width == 64 bits */ + if (width == 1) { + nvclk_fill = nvclk_freq * 8; + if (crtc_drain_rate * 100 >= nvclk_fill * 102) + /*Large number to fail */ + clwm = 0xfff; + + else if (crtc_drain_rate * 100 >= + nvclk_fill * 98) { + clwm = 1024; + cbs = 512; + } + } + } + + /* + Overfill check: + */ + + clwm_rnd_down = ((int)clwm / 8) * 8; + if (clwm_rnd_down < clwm) + clwm += 8; + + m1 = clwm + cbs - 1024; /* Amount of overfill */ + m2us = us_pipe_min + us_min_mclk_extra; + + /* pclk cycles to drain */ + p1clk = m2us * pclk_freq / (1000 * 1000); + p2 = p1clk * bpp / 8; /* bytes drained. */ + + if ((p2 < m1) && (m1 > 0)) { + fifo->valid = 0; + found = 0; + if (min_mclk_extra == 0) { + if (cbs <= 32) { + /* Can't adjust anymore! */ + found = 1; + } else { + /* reduce the burst size */ + cbs = cbs / 2; + } + } else { + min_mclk_extra--; + } + } else { + if (clwm > 1023) { /* Have some margin */ + fifo->valid = 0; + found = 0; + if (min_mclk_extra == 0) + /* Can't adjust anymore! */ + found = 1; + else + min_mclk_extra--; + } + } + + if (clwm < (1024 - cbs + 8)) + clwm = 1024 - cbs + 8; + data = (int)(clwm); + /* printf("CRT LWM: %f bytes, prog: 0x%x, bs: 256\n", + clwm, data ); */ + fifo->graphics_lwm = data; + fifo->graphics_burst_size = cbs; + + fifo->video_lwm = 1024; + fifo->video_burst_size = 512; + } +} + +static void nv10UpdateArbitrationSettings(unsigned VClk, + unsigned pixelDepth, + unsigned *burst, + unsigned *lwm, + struct nvidia_par *par) +{ + nv10_fifo_info fifo_data; + nv10_sim_state sim_data; + unsigned int MClk, NVClk, cfg1; + + nvGetClocks(par, &MClk, &NVClk); + + cfg1 = NV_RD32(par->PFB, 0x0204); + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 1; + sim_data.enable_mp = 0; + sim_data.memory_type = (NV_RD32(par->PFB, 0x0200) & 0x01) ? 1 : 0; + sim_data.memory_width = (NV_RD32(par->PEXTDEV, 0x0000) & 0x10) ? + 128 : 64; + sim_data.mem_latency = (char)cfg1 & 0x0F; + sim_data.mem_aligned = 1; + sim_data.mem_page_miss = + (char)(((cfg1 >> 4) & 0x0F) + ((cfg1 >> 31) & 0x01)); + sim_data.gr_during_vid = 0; + sim_data.pclk_khz = VClk; + sim_data.mclk_khz = MClk; + sim_data.nvclk_khz = NVClk; + nv10CalcArbitration(&fifo_data, &sim_data); + if (fifo_data.valid) { + int b = fifo_data.graphics_burst_size >> 4; + *burst = 0; + while (b >>= 1) + (*burst)++; + *lwm = fifo_data.graphics_lwm >> 3; + } +} + +static void nv30UpdateArbitrationSettings ( + struct nvidia_par *par, + unsigned int *burst, + unsigned int *lwm +) +{ + unsigned int MClk, NVClk; + unsigned int fifo_size, burst_size, graphics_lwm; + + fifo_size = 2048; + burst_size = 512; + graphics_lwm = fifo_size - burst_size; + + nvGetClocks(par, &MClk, &NVClk); + + *burst = 0; + burst_size >>= 5; + while(burst_size >>= 1) (*burst)++; + *lwm = graphics_lwm >> 3; +} + +static void nForceUpdateArbitrationSettings(unsigned VClk, + unsigned pixelDepth, + unsigned *burst, + unsigned *lwm, + struct nvidia_par *par) +{ + nv10_fifo_info fifo_data; + nv10_sim_state sim_data; + unsigned int M, N, P, pll, MClk, NVClk, memctrl; + struct pci_dev *dev; + + if ((par->Chipset & 0x0FF0) == 0x01A0) { + unsigned int uMClkPostDiv; + dev = pci_find_slot(0, 3); + pci_read_config_dword(dev, 0x6C, &uMClkPostDiv); + uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf; + + if (!uMClkPostDiv) + uMClkPostDiv = 4; + MClk = 400000 / uMClkPostDiv; + } else { + dev = pci_find_slot(0, 5); + pci_read_config_dword(dev, 0x4c, &MClk); + MClk /= 1000; + } + + pll = NV_RD32(par->PRAMDAC0, 0x0500); + M = (pll >> 0) & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + NVClk = (N * par->CrystalFreqKHz / M) >> P; + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 0; + sim_data.enable_mp = 0; + pci_find_slot(0, 1); + pci_read_config_dword(dev, 0x7C, &sim_data.memory_type); + sim_data.memory_type = (sim_data.memory_type >> 12) & 1; + sim_data.memory_width = 64; + + dev = pci_find_slot(0, 3); + pci_read_config_dword(dev, 0, &memctrl); + memctrl >>= 16; + + if ((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) { + int dimm[3]; + + pci_find_slot(0, 2); + pci_read_config_dword(dev, 0x40, &dimm[0]); + dimm[0] = (dimm[0] >> 8) & 0x4f; + pci_read_config_dword(dev, 0x44, &dimm[1]); + dimm[1] = (dimm[1] >> 8) & 0x4f; + pci_read_config_dword(dev, 0x48, &dimm[2]); + dimm[2] = (dimm[2] >> 8) & 0x4f; + + if ((dimm[0] + dimm[1]) != dimm[2]) { + printk("nvidiafb: your nForce DIMMs are not arranged " + "in optimal banks!\n"); + } + } + + sim_data.mem_latency = 3; + sim_data.mem_aligned = 1; + sim_data.mem_page_miss = 10; + sim_data.gr_during_vid = 0; + sim_data.pclk_khz = VClk; + sim_data.mclk_khz = MClk; + sim_data.nvclk_khz = NVClk; + nv10CalcArbitration(&fifo_data, &sim_data); + if (fifo_data.valid) { + int b = fifo_data.graphics_burst_size >> 4; + *burst = 0; + while (b >>= 1) + (*burst)++; + *lwm = fifo_data.graphics_lwm >> 3; + } +} + +/****************************************************************************\ +* * +* RIVA Mode State Routines * +* * +\****************************************************************************/ + +/* + * Calculate the Video Clock parameters for the PLL. + */ +static void CalcVClock(int clockIn, + int *clockOut, u32 * pllOut, struct nvidia_par *par) +{ + unsigned lowM, highM; + unsigned DeltaNew, DeltaOld; + unsigned VClk, Freq; + unsigned M, N, P; + + DeltaOld = 0xFFFFFFFF; + + VClk = (unsigned)clockIn; + + if (par->CrystalFreqKHz == 13500) { + lowM = 7; + highM = 13; + } else { + lowM = 8; + highM = 14; + } + + for (P = 0; P <= 4; P++) { + Freq = VClk << P; + if ((Freq >= 128000) && (Freq <= 350000)) { + for (M = lowM; M <= highM; M++) { + N = ((VClk << P) * M) / par->CrystalFreqKHz; + if (N <= 255) { + Freq = + ((par->CrystalFreqKHz * N) / + M) >> P; + if (Freq > VClk) + DeltaNew = Freq - VClk; + else + DeltaNew = VClk - Freq; + if (DeltaNew < DeltaOld) { + *pllOut = + (P << 16) | (N << 8) | M; + *clockOut = Freq; + DeltaOld = DeltaNew; + } + } + } + } + } +} + +static void CalcVClock2Stage(int clockIn, + int *clockOut, + u32 * pllOut, + u32 * pllBOut, struct nvidia_par *par) +{ + unsigned DeltaNew, DeltaOld; + unsigned VClk, Freq; + unsigned M, N, P; + + DeltaOld = 0xFFFFFFFF; + + *pllBOut = 0x80000401; /* fixed at x4 for now */ + + VClk = (unsigned)clockIn; + + for (P = 0; P <= 6; P++) { + Freq = VClk << P; + if ((Freq >= 400000) && (Freq <= 1000000)) { + for (M = 1; M <= 13; M++) { + N = ((VClk << P) * M) / + (par->CrystalFreqKHz << 2); + if ((N >= 5) && (N <= 255)) { + Freq = + (((par->CrystalFreqKHz << 2) * N) / + M) >> P; + if (Freq > VClk) + DeltaNew = Freq - VClk; + else + DeltaNew = VClk - Freq; + if (DeltaNew < DeltaOld) { + *pllOut = + (P << 16) | (N << 8) | M; + *clockOut = Freq; + DeltaOld = DeltaNew; + } + } + } + } + } +} + +/* + * Calculate extended mode parameters (SVGA) and save in a + * mode state structure. + */ +void NVCalcStateExt(struct nvidia_par *par, + RIVA_HW_STATE * state, + int bpp, + int width, + int hDisplaySize, int height, int dotClock, int flags) +{ + int pixelDepth, VClk; + /* + * Save mode parameters. + */ + state->bpp = bpp; /* this is not bitsPerPixel, it's 8,15,16,32 */ + state->width = width; + state->height = height; + /* + * Extended RIVA registers. + */ + pixelDepth = (bpp + 1) / 8; + if (par->twoStagePLL) + CalcVClock2Stage(dotClock, &VClk, &state->pll, &state->pllB, + par); + else + CalcVClock(dotClock, &VClk, &state->pll, par); + + switch (par->Architecture) { + case NV_ARCH_04: + nv4UpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), par); + state->cursor0 = 0x00; + state->cursor1 = 0xbC; + if (flags & FB_VMODE_DOUBLE) + state->cursor1 |= 2; + state->cursor2 = 0x00000000; + state->pllsel = 0x10000700; + state->config = 0x00001114; + state->general = bpp == 16 ? 0x00101100 : 0x00100100; + state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; + break; + case NV_ARCH_10: + case NV_ARCH_20: + case NV_ARCH_30: + default: + if (((par->Chipset & 0xffff) == 0x01A0) || + ((par->Chipset & 0xffff) == 0x01f0)) { + nForceUpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), + par); + } else if (par->Architecture < NV_ARCH_30) { + nv10UpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), + par); + } else { + nv30UpdateArbitrationSettings(par, + &(state->arbitration0), + &(state->arbitration1)); + } + + state->cursor0 = 0x80 | (par->CursorStart >> 17); + state->cursor1 = (par->CursorStart >> 11) << 2; + state->cursor2 = par->CursorStart >> 24; + if (flags & FB_VMODE_DOUBLE) + state->cursor1 |= 2; + state->pllsel = 0x10000700; + state->config = NV_RD32(par->PFB, 0x00000200); + state->general = bpp == 16 ? 0x00101100 : 0x00100100; + state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; + break; + } + + if (bpp != 8) /* DirectColor */ + state->general |= 0x00000030; + + state->repaint0 = (((width / 8) * pixelDepth) & 0x700) >> 3; + state->pixel = (pixelDepth > 2) ? 3 : pixelDepth; +} + +void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) +{ + int i; + + NV_WR32(par->PMC, 0x0140, 0x00000000); + NV_WR32(par->PMC, 0x0200, 0xFFFF00FF); + NV_WR32(par->PMC, 0x0200, 0xFFFFFFFF); + + NV_WR32(par->PTIMER, 0x0200 * 4, 0x00000008); + NV_WR32(par->PTIMER, 0x0210 * 4, 0x00000003); + NV_WR32(par->PTIMER, 0x0140 * 4, 0x00000000); + NV_WR32(par->PTIMER, 0x0100 * 4, 0xFFFFFFFF); + + if (par->Architecture == NV_ARCH_04) { + NV_WR32(par->PFB, 0x0200, state->config); + } else if ((par->Chipset & 0xfff0) == 0x0090) { + for (i = 0; i < 15; i++) { + NV_WR32(par->PFB, 0x0600 + (i * 0x10), 0); + NV_WR32(par->PFB, 0x0604 + (i * 0x10), par->FbMapSize - 1); + } + } else { + for (i = 0; i < 8; i++) { + NV_WR32(par->PFB, 0x0240 + (i * 0x10), 0); + NV_WR32(par->PFB, 0x0244 + (i * 0x10), par->FbMapSize - 1); + } + } + + if (par->Architecture >= NV_ARCH_40) { + NV_WR32(par->PRAMIN, 0x0000 * 4, 0x80000010); + NV_WR32(par->PRAMIN, 0x0001 * 4, 0x00101202); + NV_WR32(par->PRAMIN, 0x0002 * 4, 0x80000011); + NV_WR32(par->PRAMIN, 0x0003 * 4, 0x00101204); + NV_WR32(par->PRAMIN, 0x0004 * 4, 0x80000012); + NV_WR32(par->PRAMIN, 0x0005 * 4, 0x00101206); + NV_WR32(par->PRAMIN, 0x0006 * 4, 0x80000013); + NV_WR32(par->PRAMIN, 0x0007 * 4, 0x00101208); + NV_WR32(par->PRAMIN, 0x0008 * 4, 0x80000014); + NV_WR32(par->PRAMIN, 0x0009 * 4, 0x0010120A); + NV_WR32(par->PRAMIN, 0x000A * 4, 0x80000015); + NV_WR32(par->PRAMIN, 0x000B * 4, 0x0010120C); + NV_WR32(par->PRAMIN, 0x000C * 4, 0x80000016); + NV_WR32(par->PRAMIN, 0x000D * 4, 0x0010120E); + NV_WR32(par->PRAMIN, 0x000E * 4, 0x80000017); + NV_WR32(par->PRAMIN, 0x000F * 4, 0x00101210); + NV_WR32(par->PRAMIN, 0x0800 * 4, 0x00003000); + NV_WR32(par->PRAMIN, 0x0801 * 4, par->FbMapSize - 1); + NV_WR32(par->PRAMIN, 0x0802 * 4, 0x00000002); + NV_WR32(par->PRAMIN, 0x0808 * 4, 0x02080062); + NV_WR32(par->PRAMIN, 0x0809 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x080A * 4, 0x00001200); + NV_WR32(par->PRAMIN, 0x080B * 4, 0x00001200); + NV_WR32(par->PRAMIN, 0x080C * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x080D * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0810 * 4, 0x02080043); + NV_WR32(par->PRAMIN, 0x0811 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0812 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0813 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0814 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0815 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0818 * 4, 0x02080044); + NV_WR32(par->PRAMIN, 0x0819 * 4, 0x02000000); + NV_WR32(par->PRAMIN, 0x081A * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x081B * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x081C * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x081D * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0820 * 4, 0x02080019); + NV_WR32(par->PRAMIN, 0x0821 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0822 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0823 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0824 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0825 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0828 * 4, 0x020A005C); + NV_WR32(par->PRAMIN, 0x0829 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x082A * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x082B * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x082C * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x082D * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0830 * 4, 0x0208009F); + NV_WR32(par->PRAMIN, 0x0831 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0832 * 4, 0x00001200); + NV_WR32(par->PRAMIN, 0x0833 * 4, 0x00001200); + NV_WR32(par->PRAMIN, 0x0834 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0835 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0838 * 4, 0x0208004A); + NV_WR32(par->PRAMIN, 0x0839 * 4, 0x02000000); + NV_WR32(par->PRAMIN, 0x083A * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x083B * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x083C * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x083D * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0840 * 4, 0x02080077); + NV_WR32(par->PRAMIN, 0x0841 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0842 * 4, 0x00001200); + NV_WR32(par->PRAMIN, 0x0843 * 4, 0x00001200); + NV_WR32(par->PRAMIN, 0x0844 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0845 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x084C * 4, 0x00003002); + NV_WR32(par->PRAMIN, 0x084D * 4, 0x00007FFF); + NV_WR32(par->PRAMIN, 0x084E * 4, + par->FbUsableSize | 0x00000002); + +#ifdef __BIG_ENDIAN + NV_WR32(par->PRAMIN, 0x080A * 4, + NV_RD32(par->PRAMIN, 0x080A * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x0812 * 4, + NV_RD32(par->PRAMIN, 0x0812 * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x081A * 4, + NV_RD32(par->PRAMIN, 0x081A * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x0822 * 4, + NV_RD32(par->PRAMIN, 0x0822 * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x082A * 4, + NV_RD32(par->PRAMIN, 0x082A * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x0832 * 4, + NV_RD32(par->PRAMIN, 0x0832 * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x083A * 4, + NV_RD32(par->PRAMIN, 0x083A * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x0842 * 4, + NV_RD32(par->PRAMIN, 0x0842 * 4) | 0x01000000); + NV_WR32(par->PRAMIN, 0x0819 * 4, 0x01000000); + NV_WR32(par->PRAMIN, 0x0839 * 4, 0x01000000); +#endif + } else { + NV_WR32(par->PRAMIN, 0x0000 * 4, 0x80000010); + NV_WR32(par->PRAMIN, 0x0001 * 4, 0x80011201); + NV_WR32(par->PRAMIN, 0x0002 * 4, 0x80000011); + NV_WR32(par->PRAMIN, 0x0003 * 4, 0x80011202); + NV_WR32(par->PRAMIN, 0x0004 * 4, 0x80000012); + NV_WR32(par->PRAMIN, 0x0005 * 4, 0x80011203); + NV_WR32(par->PRAMIN, 0x0006 * 4, 0x80000013); + NV_WR32(par->PRAMIN, 0x0007 * 4, 0x80011204); + NV_WR32(par->PRAMIN, 0x0008 * 4, 0x80000014); + NV_WR32(par->PRAMIN, 0x0009 * 4, 0x80011205); + NV_WR32(par->PRAMIN, 0x000A * 4, 0x80000015); + NV_WR32(par->PRAMIN, 0x000B * 4, 0x80011206); + NV_WR32(par->PRAMIN, 0x000C * 4, 0x80000016); + NV_WR32(par->PRAMIN, 0x000D * 4, 0x80011207); + NV_WR32(par->PRAMIN, 0x000E * 4, 0x80000017); + NV_WR32(par->PRAMIN, 0x000F * 4, 0x80011208); + NV_WR32(par->PRAMIN, 0x0800 * 4, 0x00003000); + NV_WR32(par->PRAMIN, 0x0801 * 4, par->FbMapSize - 1); + NV_WR32(par->PRAMIN, 0x0802 * 4, 0x00000002); + NV_WR32(par->PRAMIN, 0x0803 * 4, 0x00000002); + if (par->Architecture >= NV_ARCH_10) + NV_WR32(par->PRAMIN, 0x0804 * 4, 0x01008062); + else + NV_WR32(par->PRAMIN, 0x0804 * 4, 0x01008042); + NV_WR32(par->PRAMIN, 0x0805 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0806 * 4, 0x12001200); + NV_WR32(par->PRAMIN, 0x0807 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0808 * 4, 0x01008043); + NV_WR32(par->PRAMIN, 0x0809 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x080A * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x080B * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x080C * 4, 0x01008044); + NV_WR32(par->PRAMIN, 0x080D * 4, 0x00000002); + NV_WR32(par->PRAMIN, 0x080E * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x080F * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0810 * 4, 0x01008019); + NV_WR32(par->PRAMIN, 0x0811 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0812 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0813 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0814 * 4, 0x0100A05C); + NV_WR32(par->PRAMIN, 0x0815 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0816 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0817 * 4, 0x00000000); + if (par->WaitVSyncPossible) + NV_WR32(par->PRAMIN, 0x0818 * 4, 0x0100809F); + else + NV_WR32(par->PRAMIN, 0x0818 * 4, 0x0100805F); + NV_WR32(par->PRAMIN, 0x0819 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x081A * 4, 0x12001200); + NV_WR32(par->PRAMIN, 0x081B * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x081C * 4, 0x0100804A); + NV_WR32(par->PRAMIN, 0x081D * 4, 0x00000002); + NV_WR32(par->PRAMIN, 0x081E * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x081F * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0820 * 4, 0x01018077); + NV_WR32(par->PRAMIN, 0x0821 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0822 * 4, 0x12001200); + NV_WR32(par->PRAMIN, 0x0823 * 4, 0x00000000); + NV_WR32(par->PRAMIN, 0x0824 * 4, 0x00003002); + NV_WR32(par->PRAMIN, 0x0825 * 4, 0x00007FFF); + NV_WR32(par->PRAMIN, 0x0826 * 4, + par->FbUsableSize | 0x00000002); + NV_WR32(par->PRAMIN, 0x0827 * 4, 0x00000002); +#ifdef __BIG_ENDIAN + NV_WR32(par->PRAMIN, 0x0804 * 4, + NV_RD32(par->PRAMIN, 0x0804 * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x0808 * 4, + NV_RD32(par->PRAMIN, 0x0808 * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x080C * 4, + NV_RD32(par->PRAMIN, 0x080C * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x0810 * 4, + NV_RD32(par->PRAMIN, 0x0810 * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x0814 * 4, + NV_RD32(par->PRAMIN, 0x0814 * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x0818 * 4, + NV_RD32(par->PRAMIN, 0x0818 * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x081C * 4, + NV_RD32(par->PRAMIN, 0x081C * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x0820 * 4, + NV_RD32(par->PRAMIN, 0x0820 * 4) | 0x00080000); + NV_WR32(par->PRAMIN, 0x080D * 4, 0x00000001); + NV_WR32(par->PRAMIN, 0x081D * 4, 0x00000001); +#endif + } + if (par->Architecture < NV_ARCH_10) { + if ((par->Chipset & 0x0fff) == 0x0020) { + NV_WR32(par->PRAMIN, 0x0824 * 4, + NV_RD32(par->PRAMIN, 0x0824 * 4) | 0x00020000); + NV_WR32(par->PRAMIN, 0x0826 * 4, + NV_RD32(par->PRAMIN, + 0x0826 * 4) + par->FbAddress); + } + NV_WR32(par->PGRAPH, 0x0080, 0x000001FF); + NV_WR32(par->PGRAPH, 0x0080, 0x1230C000); + NV_WR32(par->PGRAPH, 0x0084, 0x72111101); + NV_WR32(par->PGRAPH, 0x0088, 0x11D5F071); + NV_WR32(par->PGRAPH, 0x008C, 0x0004FF31); + NV_WR32(par->PGRAPH, 0x008C, 0x4004FF31); + NV_WR32(par->PGRAPH, 0x0140, 0x00000000); + NV_WR32(par->PGRAPH, 0x0100, 0xFFFFFFFF); + NV_WR32(par->PGRAPH, 0x0170, 0x10010100); + NV_WR32(par->PGRAPH, 0x0710, 0xFFFFFFFF); + NV_WR32(par->PGRAPH, 0x0720, 0x00000001); + NV_WR32(par->PGRAPH, 0x0810, 0x00000000); + NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF); + } else { + NV_WR32(par->PGRAPH, 0x0080, 0xFFFFFFFF); + NV_WR32(par->PGRAPH, 0x0080, 0x00000000); + + NV_WR32(par->PGRAPH, 0x0140, 0x00000000); + NV_WR32(par->PGRAPH, 0x0100, 0xFFFFFFFF); + NV_WR32(par->PGRAPH, 0x0144, 0x10010100); + NV_WR32(par->PGRAPH, 0x0714, 0xFFFFFFFF); + NV_WR32(par->PGRAPH, 0x0720, 0x00000001); + NV_WR32(par->PGRAPH, 0x0710, + NV_RD32(par->PGRAPH, 0x0710) & 0x0007ff00); + NV_WR32(par->PGRAPH, 0x0710, + NV_RD32(par->PGRAPH, 0x0710) | 0x00020100); + + if (par->Architecture == NV_ARCH_10) { + NV_WR32(par->PGRAPH, 0x0084, 0x00118700); + NV_WR32(par->PGRAPH, 0x0088, 0x24E00810); + NV_WR32(par->PGRAPH, 0x008C, 0x55DE0030); + + for (i = 0; i < 32; i++) + NV_WR32(&par->PGRAPH[(0x0B00 / 4) + i], 0, + NV_RD32(&par->PFB[(0x0240 / 4) + i], + 0)); + + NV_WR32(par->PGRAPH, 0x640, 0); + NV_WR32(par->PGRAPH, 0x644, 0); + NV_WR32(par->PGRAPH, 0x684, par->FbMapSize - 1); + NV_WR32(par->PGRAPH, 0x688, par->FbMapSize - 1); + + NV_WR32(par->PGRAPH, 0x0810, 0x00000000); + NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF); + } else { + if (par->Architecture >= NV_ARCH_40) { + NV_WR32(par->PGRAPH, 0x0084, 0x401287c0); + NV_WR32(par->PGRAPH, 0x008C, 0x60de8051); + NV_WR32(par->PGRAPH, 0x0090, 0x00008000); + NV_WR32(par->PGRAPH, 0x0610, 0x00be3c5f); + + if ((par->Chipset & 0xfff0) == 0x0040) { + NV_WR32(par->PGRAPH, 0x09b0, + 0x83280fff); + NV_WR32(par->PGRAPH, 0x09b4, + 0x000000a0); + } else { + NV_WR32(par->PGRAPH, 0x0820, + 0x83280eff); + NV_WR32(par->PGRAPH, 0x0824, + 0x000000a0); + } + + switch (par->Chipset & 0xfff0) { + case 0x0040: + case 0x0210: + NV_WR32(par->PGRAPH, 0x09b8, + 0x0078e366); + NV_WR32(par->PGRAPH, 0x09bc, + 0x0000014c); + NV_WR32(par->PFB, 0x033C, + NV_RD32(par->PFB, 0x33C) & + 0xffff7fff); + break; + case 0x00C0: + NV_WR32(par->PGRAPH, 0x0828, + 0x007596ff); + NV_WR32(par->PGRAPH, 0x082C, + 0x00000108); + break; + case 0x0160: + case 0x01D0: + NV_WR32(par->PMC, 0x1700, + NV_RD32(par->PFB, 0x020C)); + NV_WR32(par->PMC, 0x1704, 0); + NV_WR32(par->PMC, 0x1708, 0); + NV_WR32(par->PMC, 0x170C, + NV_RD32(par->PFB, 0x020C)); + NV_WR32(par->PGRAPH, 0x0860, 0); + NV_WR32(par->PGRAPH, 0x0864, 0); + NV_WR32(par->PRAMDAC, 0x0608, + NV_RD32(par->PRAMDAC, + 0x0608) | 0x00100000); + break; + case 0x0140: + NV_WR32(par->PGRAPH, 0x0828, + 0x0072cb77); + NV_WR32(par->PGRAPH, 0x082C, + 0x00000108); + break; + case 0x0220: + case 0x0230: + NV_WR32(par->PGRAPH, 0x0860, 0); + NV_WR32(par->PGRAPH, 0x0864, 0); + NV_WR32(par->PRAMDAC, 0x0608, + NV_RD32(par->PRAMDAC, 0x0608) | + 0x00100000); + break; + case 0x0090: + NV_WR32(par->PRAMDAC, 0x0608, + NV_RD32(par->PRAMDAC, 0x0608) | + 0x00100000); + NV_WR32(par->PGRAPH, 0x0828, + 0x07830610); + NV_WR32(par->PGRAPH, 0x082C, + 0x0000016A); + break; + default: + break; + }; + + NV_WR32(par->PGRAPH, 0x0b38, 0x2ffff800); + NV_WR32(par->PGRAPH, 0x0b3c, 0x00006000); + NV_WR32(par->PGRAPH, 0x032C, 0x01000000); + NV_WR32(par->PGRAPH, 0x0220, 0x00001200); + } else if (par->Architecture == NV_ARCH_30) { + NV_WR32(par->PGRAPH, 0x0084, 0x40108700); + NV_WR32(par->PGRAPH, 0x0890, 0x00140000); + NV_WR32(par->PGRAPH, 0x008C, 0xf00e0431); + NV_WR32(par->PGRAPH, 0x0090, 0x00008000); + NV_WR32(par->PGRAPH, 0x0610, 0xf04b1f36); + NV_WR32(par->PGRAPH, 0x0B80, 0x1002d888); + NV_WR32(par->PGRAPH, 0x0B88, 0x62ff007f); + } else { + NV_WR32(par->PGRAPH, 0x0084, 0x00118700); + NV_WR32(par->PGRAPH, 0x008C, 0xF20E0431); + NV_WR32(par->PGRAPH, 0x0090, 0x00000000); + NV_WR32(par->PGRAPH, 0x009C, 0x00000040); + + if ((par->Chipset & 0x0ff0) >= 0x0250) { + NV_WR32(par->PGRAPH, 0x0890, + 0x00080000); + NV_WR32(par->PGRAPH, 0x0610, + 0x304B1FB6); + NV_WR32(par->PGRAPH, 0x0B80, + 0x18B82880); + NV_WR32(par->PGRAPH, 0x0B84, + 0x44000000); + NV_WR32(par->PGRAPH, 0x0098, + 0x40000080); + NV_WR32(par->PGRAPH, 0x0B88, + 0x000000ff); + } else { + NV_WR32(par->PGRAPH, 0x0880, + 0x00080000); + NV_WR32(par->PGRAPH, 0x0094, + 0x00000005); + NV_WR32(par->PGRAPH, 0x0B80, + 0x45CAA208); + NV_WR32(par->PGRAPH, 0x0B84, + 0x24000000); + NV_WR32(par->PGRAPH, 0x0098, + 0x00000040); + NV_WR32(par->PGRAPH, 0x0750, + 0x00E00038); + NV_WR32(par->PGRAPH, 0x0754, + 0x00000030); + NV_WR32(par->PGRAPH, 0x0750, + 0x00E10038); + NV_WR32(par->PGRAPH, 0x0754, + 0x00000030); + } + } + + if ((par->Chipset & 0xfff0) == 0x0090) { + for (i = 0; i < 60; i++) + NV_WR32(par->PGRAPH, 0x0D00 + i, + NV_RD32(par->PFB, 0x0600 + i)); + } else { + for (i = 0; i < 32; i++) + NV_WR32(par->PGRAPH, 0x0900 + i, + NV_RD32(par->PFB, 0x0240 + i)); + } + + if (par->Architecture >= NV_ARCH_40) { + if ((par->Chipset & 0xfff0) == 0x0040) { + NV_WR32(par->PGRAPH, 0x09A4, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x09A8, + NV_RD32(par->PFB, 0x0204)); + NV_WR32(par->PGRAPH, 0x69A4, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x69A8, + NV_RD32(par->PFB, 0x0204)); + + NV_WR32(par->PGRAPH, 0x0820, 0); + NV_WR32(par->PGRAPH, 0x0824, 0); + NV_WR32(par->PGRAPH, 0x0864, + par->FbMapSize - 1); + NV_WR32(par->PGRAPH, 0x0868, + par->FbMapSize - 1); + } else { + if((par->Chipset & 0xfff0) == 0x0090) { + NV_WR32(par->PGRAPH, 0x0DF0, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x0DF4, + NV_RD32(par->PFB, 0x0204)); + } else { + NV_WR32(par->PGRAPH, 0x09F0, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x09F4, + NV_RD32(par->PFB, 0x0204)); + } + NV_WR32(par->PGRAPH, 0x69F0, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x69F4, + NV_RD32(par->PFB, 0x0204)); + + NV_WR32(par->PGRAPH, 0x0840, 0); + NV_WR32(par->PGRAPH, 0x0844, 0); + NV_WR32(par->PGRAPH, 0x08a0, + par->FbMapSize - 1); + NV_WR32(par->PGRAPH, 0x08a4, + par->FbMapSize - 1); + } + } else { + NV_WR32(par->PGRAPH, 0x09A4, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x09A8, + NV_RD32(par->PFB, 0x0204)); + NV_WR32(par->PGRAPH, 0x0750, 0x00EA0000); + NV_WR32(par->PGRAPH, 0x0754, + NV_RD32(par->PFB, 0x0200)); + NV_WR32(par->PGRAPH, 0x0750, 0x00EA0004); + NV_WR32(par->PGRAPH, 0x0754, + NV_RD32(par->PFB, 0x0204)); + + NV_WR32(par->PGRAPH, 0x0820, 0); + NV_WR32(par->PGRAPH, 0x0824, 0); + NV_WR32(par->PGRAPH, 0x0864, + par->FbMapSize - 1); + NV_WR32(par->PGRAPH, 0x0868, + par->FbMapSize - 1); + } + NV_WR32(par->PGRAPH, 0x0B20, 0x00000000); + NV_WR32(par->PGRAPH, 0x0B04, 0xFFFFFFFF); + } + } + NV_WR32(par->PGRAPH, 0x053C, 0); + NV_WR32(par->PGRAPH, 0x0540, 0); + NV_WR32(par->PGRAPH, 0x0544, 0x00007FFF); + NV_WR32(par->PGRAPH, 0x0548, 0x00007FFF); + + NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x0141 * 4, 0x00000001); + NV_WR32(par->PFIFO, 0x0480 * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000000); + if (par->Architecture >= NV_ARCH_40) + NV_WR32(par->PFIFO, 0x0481 * 4, 0x00010000); + else + NV_WR32(par->PFIFO, 0x0481 * 4, 0x00000100); + NV_WR32(par->PFIFO, 0x0490 * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x0491 * 4, 0x00000000); + if (par->Architecture >= NV_ARCH_40) + NV_WR32(par->PFIFO, 0x048B * 4, 0x00001213); + else + NV_WR32(par->PFIFO, 0x048B * 4, 0x00001209); + NV_WR32(par->PFIFO, 0x0400 * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x0414 * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x0084 * 4, 0x03000100); + NV_WR32(par->PFIFO, 0x0085 * 4, 0x00000110); + NV_WR32(par->PFIFO, 0x0086 * 4, 0x00000112); + NV_WR32(par->PFIFO, 0x0143 * 4, 0x0000FFFF); + NV_WR32(par->PFIFO, 0x0496 * 4, 0x0000FFFF); + NV_WR32(par->PFIFO, 0x0050 * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x0040 * 4, 0xFFFFFFFF); + NV_WR32(par->PFIFO, 0x0415 * 4, 0x00000001); + NV_WR32(par->PFIFO, 0x048C * 4, 0x00000000); + NV_WR32(par->PFIFO, 0x04A0 * 4, 0x00000000); +#ifdef __BIG_ENDIAN + NV_WR32(par->PFIFO, 0x0489 * 4, 0x800F0078); +#else + NV_WR32(par->PFIFO, 0x0489 * 4, 0x000F0078); +#endif + NV_WR32(par->PFIFO, 0x0488 * 4, 0x00000001); + NV_WR32(par->PFIFO, 0x0480 * 4, 0x00000001); + NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000001); + NV_WR32(par->PFIFO, 0x0495 * 4, 0x00000001); + NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000001); + if (par->Architecture >= NV_ARCH_10) { + if (par->twoHeads) { + NV_WR32(par->PCRTC0, 0x0860, state->head); + NV_WR32(par->PCRTC0, 0x2860, state->head2); + } + NV_WR32(par->PRAMDAC, 0x0404, NV_RD32(par->PRAMDAC, 0x0404) | + (1 << 25)); + + NV_WR32(par->PMC, 0x8704, 1); + NV_WR32(par->PMC, 0x8140, 0); + NV_WR32(par->PMC, 0x8920, 0); + NV_WR32(par->PMC, 0x8924, 0); + NV_WR32(par->PMC, 0x8908, par->FbMapSize - 1); + NV_WR32(par->PMC, 0x890C, par->FbMapSize - 1); + NV_WR32(par->PMC, 0x1588, 0); + + NV_WR32(par->PCRTC, 0x0810, state->cursorConfig); + NV_WR32(par->PCRTC, 0x0830, state->displayV - 3); + NV_WR32(par->PCRTC, 0x0834, state->displayV - 1); + + if (par->FlatPanel) { + if ((par->Chipset & 0x0ff0) == 0x0110) { + NV_WR32(par->PRAMDAC, 0x0528, state->dither); + } else if (par->twoHeads) { + NV_WR32(par->PRAMDAC, 0x083C, state->dither); + } + + VGA_WR08(par->PCIO, 0x03D4, 0x53); + VGA_WR08(par->PCIO, 0x03D5, state->timingH); + VGA_WR08(par->PCIO, 0x03D4, 0x54); + VGA_WR08(par->PCIO, 0x03D5, state->timingV); + VGA_WR08(par->PCIO, 0x03D4, 0x21); + VGA_WR08(par->PCIO, 0x03D5, 0xfa); + } + + VGA_WR08(par->PCIO, 0x03D4, 0x41); + VGA_WR08(par->PCIO, 0x03D5, state->extra); + } + + VGA_WR08(par->PCIO, 0x03D4, 0x19); + VGA_WR08(par->PCIO, 0x03D5, state->repaint0); + VGA_WR08(par->PCIO, 0x03D4, 0x1A); + VGA_WR08(par->PCIO, 0x03D5, state->repaint1); + VGA_WR08(par->PCIO, 0x03D4, 0x25); + VGA_WR08(par->PCIO, 0x03D5, state->screen); + VGA_WR08(par->PCIO, 0x03D4, 0x28); + VGA_WR08(par->PCIO, 0x03D5, state->pixel); + VGA_WR08(par->PCIO, 0x03D4, 0x2D); + VGA_WR08(par->PCIO, 0x03D5, state->horiz); + VGA_WR08(par->PCIO, 0x03D4, 0x1C); + VGA_WR08(par->PCIO, 0x03D5, state->fifo); + VGA_WR08(par->PCIO, 0x03D4, 0x1B); + VGA_WR08(par->PCIO, 0x03D5, state->arbitration0); + VGA_WR08(par->PCIO, 0x03D4, 0x20); + VGA_WR08(par->PCIO, 0x03D5, state->arbitration1); + + if(par->Architecture >= NV_ARCH_30) { + VGA_WR08(par->PCIO, 0x03D4, 0x47); + VGA_WR08(par->PCIO, 0x03D5, state->arbitration1 >> 8); + } + + VGA_WR08(par->PCIO, 0x03D4, 0x30); + VGA_WR08(par->PCIO, 0x03D5, state->cursor0); + VGA_WR08(par->PCIO, 0x03D4, 0x31); + VGA_WR08(par->PCIO, 0x03D5, state->cursor1); + VGA_WR08(par->PCIO, 0x03D4, 0x2F); + VGA_WR08(par->PCIO, 0x03D5, state->cursor2); + VGA_WR08(par->PCIO, 0x03D4, 0x39); + VGA_WR08(par->PCIO, 0x03D5, state->interlace); + + if (!par->FlatPanel) { + NV_WR32(par->PRAMDAC0, 0x050C, state->pllsel); + NV_WR32(par->PRAMDAC0, 0x0508, state->vpll); + if (par->twoHeads) + NV_WR32(par->PRAMDAC0, 0x0520, state->vpll2); + if (par->twoStagePLL) { + NV_WR32(par->PRAMDAC0, 0x0578, state->vpllB); + NV_WR32(par->PRAMDAC0, 0x057C, state->vpll2B); + } + } else { + NV_WR32(par->PRAMDAC, 0x0848, state->scale); + NV_WR32(par->PRAMDAC, 0x0828, state->crtcSync + + par->PanelTweak); + } + + NV_WR32(par->PRAMDAC, 0x0600, state->general); + + NV_WR32(par->PCRTC, 0x0140, 0); + NV_WR32(par->PCRTC, 0x0100, 1); + + par->CurrentState = state; +} + +void NVUnloadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) { + VGA_WR08(par->PCIO, 0x03D4, 0x19); + state->repaint0 = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x1A); + state->repaint1 = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x25); + state->screen = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x28); + state->pixel = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x2D); + state->horiz = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x1C); + state->fifo = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x1B); + state->arbitration0 = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x20); + state->arbitration1 = VGA_RD08(par->PCIO, 0x03D5); + + if(par->Architecture >= NV_ARCH_30) { + VGA_WR08(par->PCIO, 0x03D4, 0x47); + state->arbitration1 |= (VGA_RD08(par->PCIO, 0x03D5) & 1) << 8; + } + + VGA_WR08(par->PCIO, 0x03D4, 0x30); + state->cursor0 = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x31); + state->cursor1 = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x2F); + state->cursor2 = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x39); + state->interlace = VGA_RD08(par->PCIO, 0x03D5); + state->vpll = NV_RD32(par->PRAMDAC0, 0x0508); + if (par->twoHeads) + state->vpll2 = NV_RD32(par->PRAMDAC0, 0x0520); + if (par->twoStagePLL) { + state->vpllB = NV_RD32(par->PRAMDAC0, 0x0578); + state->vpll2B = NV_RD32(par->PRAMDAC0, 0x057C); + } + state->pllsel = NV_RD32(par->PRAMDAC0, 0x050C); + state->general = NV_RD32(par->PRAMDAC, 0x0600); + state->scale = NV_RD32(par->PRAMDAC, 0x0848); + state->config = NV_RD32(par->PFB, 0x0200); + + if (par->Architecture >= NV_ARCH_10) { + if (par->twoHeads) { + state->head = NV_RD32(par->PCRTC0, 0x0860); + state->head2 = NV_RD32(par->PCRTC0, 0x2860); + VGA_WR08(par->PCIO, 0x03D4, 0x44); + state->crtcOwner = VGA_RD08(par->PCIO, 0x03D5); + } + VGA_WR08(par->PCIO, 0x03D4, 0x41); + state->extra = VGA_RD08(par->PCIO, 0x03D5); + state->cursorConfig = NV_RD32(par->PCRTC, 0x0810); + + if ((par->Chipset & 0x0ff0) == 0x0110) { + state->dither = NV_RD32(par->PRAMDAC, 0x0528); + } else if (par->twoHeads) { + state->dither = NV_RD32(par->PRAMDAC, 0x083C); + } + + if (par->FlatPanel) { + VGA_WR08(par->PCIO, 0x03D4, 0x53); + state->timingH = VGA_RD08(par->PCIO, 0x03D5); + VGA_WR08(par->PCIO, 0x03D4, 0x54); + state->timingV = VGA_RD08(par->PCIO, 0x03D5); + } + } +} + +void NVSetStartAddress(struct nvidia_par *par, u32 start) +{ + NV_WR32(par->PCRTC, 0x800, start); +} diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c new file mode 100644 index 00000000000..3757c1407c1 --- /dev/null +++ b/drivers/video/nvidia/nv_i2c.c @@ -0,0 +1,215 @@ +/* + * linux/drivers/video/nvidia/nvidia-i2c.c - nVidia i2c + * + * Copyright 2004 Antonino A. Daplas + * + * 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); + chan->par = NULL; + } + + return rc; +} + +void nvidia_create_i2c_busses(struct nvidia_par *par) +{ + par->bus = 3; + + par->chan[0].par = par; + par->chan[1].par = par; + par->chan[2].par = par; + + par->chan[0].ddc_base = 0x3e; + nvidia_setup_i2c_bus(&par->chan[0], "BUS1"); + + par->chan[1].ddc_base = 0x36; + nvidia_setup_i2c_bus(&par->chan[1], "BUS2"); + + par->chan[2].ddc_base = 0x50; + nvidia_setup_i2c_bus(&par->chan[2], "BUS3"); +} + +void nvidia_delete_i2c_busses(struct nvidia_par *par) +{ + if (par->chan[0].par) + i2c_bit_del_bus(&par->chan[0].adapter); + par->chan[0].par = NULL; + + if (par->chan[1].par) + i2c_bit_del_bus(&par->chan[1].adapter); + par->chan[1].par = NULL; + + if (par->chan[2].par) + i2c_bit_del_bus(&par->chan[2].adapter); + par->chan[2].par = NULL; + +} + +static u8 *nvidia_do_probe_i2c_edid(struct nvidia_i2c_chan *chan) +{ + u8 start = 0x0; + struct i2c_msg msgs[] = { + { + .addr = 0x50, + .len = 1, + .buf = &start, + }, { + .addr = 0x50, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + }, + }; + u8 *buf; + + if (!chan->par) + return NULL; + + buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!buf) { + dev_warn(&chan->par->pci_dev->dev, "Out of memory!\n"); + return NULL; + } + msgs[1].buf = buf; + + if (i2c_transfer(&chan->adapter, msgs, 2) == 2) + return buf; + dev_dbg(&chan->par->pci_dev->dev, "Unable to read EDID block.\n"); + kfree(buf); + return NULL; +} + +int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, u8 **out_edid) +{ + u8 *edid = NULL; + int i; + + for (i = 0; i < 3; i++) { + /* Do the real work */ + edid = nvidia_do_probe_i2c_edid(&par->chan[conn - 1]); + if (edid) + break; + } + if (out_edid) + *out_edid = edid; + if (!edid) + return 1; + + return 0; +} diff --git a/drivers/video/nvidia/nv_local.h b/drivers/video/nvidia/nv_local.h new file mode 100644 index 00000000000..9da320986f4 --- /dev/null +++ b/drivers/video/nvidia/nv_local.h @@ -0,0 +1,107 @@ +/***************************************************************************\ +|* *| +|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 1993-1999 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/ + * XFree86 'nv' driver, this source code is provided under MIT-style licensing + * where the source code is provided "as is" without warranty of any kind. + * The only usage restriction is for the copyright notices to be retained + * whenever code is used. + * + * Antonino Daplas 2005-03-11 + */ + +#ifndef __NV_LOCAL_H__ +#define __NV_LOCAL_H__ + +/* + * This file includes any environment or machine specific values to access the + * HW. Put all affected includes, typdefs, etc. here so the riva_hw.* files + * can stay generic in nature. + */ + +/* + * HW access macros. These assume memory-mapped I/O, and not normal I/O space. + */ +#define NV_WR08(p,i,d) (__raw_writeb((d), (void __iomem *)(p) + (i))) +#define NV_RD08(p,i) (__raw_readb((void __iomem *)(p) + (i))) +#define NV_WR16(p,i,d) (__raw_writew((d), (void __iomem *)(p) + (i))) +#define NV_RD16(p,i) (__raw_readw((void __iomem *)(p) + (i))) +#define NV_WR32(p,i,d) (__raw_writel((d), (void __iomem *)(p) + (i))) +#define NV_RD32(p,i) (__raw_readl((void __iomem *)(p) + (i))) + +/* VGA I/O is now always done through MMIO */ +#define VGA_WR08(p,i,d) (writeb((d), (void __iomem *)(p) + (i))) +#define VGA_RD08(p,i) (readb((void __iomem *)(p) + (i))) + +#define NVDmaNext(par, data) \ + NV_WR32(&(par)->dmaBase[(par)->dmaCurrent++], 0, (data)) + +#define NVDmaStart(par, tag, size) { \ + if((par)->dmaFree <= (size)) \ + NVDmaWait(par, size); \ + NVDmaNext(par, ((size) << 18) | (tag)); \ + (par)->dmaFree -= ((size) + 1); \ +} + +#if defined(__i386__) +#define _NV_FENCE() outb(0, 0x3D0); +#else +#define _NV_FENCE() mb(); +#endif + +#define WRITE_PUT(par, data) { \ + _NV_FENCE() \ + NV_RD08((par)->FbStart, 0); \ + NV_WR32(&(par)->FIFO[0x0010], 0, (data) << 2); \ + mb(); \ +} + +#define READ_GET(par) (NV_RD32(&(par)->FIFO[0x0011], 0) >> 2) + +#define reverse_order(l) \ +do { \ + u8 *a = (u8 *)(l); \ + *a = byte_rev[*a], a++; \ + *a = byte_rev[*a], a++; \ + *a = byte_rev[*a], a++; \ + *a = byte_rev[*a]; \ +} while(0) + +#endif /* __NV_LOCAL_H__ */ diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c new file mode 100644 index 00000000000..7d12eb85310 --- /dev/null +++ b/drivers/video/nvidia/nv_of.c @@ -0,0 +1,59 @@ +/* + * linux/drivers/video/nvidia/nv_of.c + * + * Copyright 2004 Antonino A. Daplas + * + * 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 --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h new file mode 100644 index 00000000000..42847ce1b8d --- /dev/null +++ b/drivers/video/nvidia/nv_proto.h @@ -0,0 +1,58 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_proto.h,v 1.10 2003/07/31 20:24:29 mvojkovi Exp $ */ + +#ifndef __NV_PROTO_H__ +#define __NV_PROTO_H__ + +/* in nv_setup.c */ +void NVCommonSetup(struct fb_info *info); +void NVWriteCrtc(struct nvidia_par *par, u8 index, u8 value); +u8 NVReadCrtc(struct nvidia_par *par, u8 index); +void NVWriteGr(struct nvidia_par *par, u8 index, u8 value); +u8 NVReadGr(struct nvidia_par *par, u8 index); +void NVWriteSeq(struct nvidia_par *par, u8 index, u8 value); +u8 NVReadSeq(struct nvidia_par *par, u8 index); +void NVWriteAttr(struct nvidia_par *par, u8 index, u8 value); +u8 NVReadAttr(struct nvidia_par *par, u8 index); +void NVWriteMiscOut(struct nvidia_par *par, u8 value); +u8 NVReadMiscOut(struct nvidia_par *par); +void NVWriteDacMask(struct nvidia_par *par, u8 value); +void NVWriteDacReadAddr(struct nvidia_par *par, u8 value); +void NVWriteDacWriteAddr(struct nvidia_par *par, u8 value); +void NVWriteDacData(struct nvidia_par *par, u8 value); +u8 NVReadDacData(struct nvidia_par *par); + +/* in nv_hw.c */ +void NVCalcStateExt(struct nvidia_par *par, struct _riva_hw_state *, + int, int, int, int, int, int); +void NVLoadStateExt(struct nvidia_par *par, struct _riva_hw_state *); +void NVUnloadStateExt(struct nvidia_par *par, struct _riva_hw_state *); +void NVSetStartAddress(struct nvidia_par *par, u32); +int NVShowHideCursor(struct nvidia_par *par, int); +void NVLockUnlock(struct nvidia_par *par, int); + +/* in nvidia-i2c.c */ +#if defined(CONFIG_FB_NVIDIA_I2C) || defined (CONFIG_PPC_OF) +void nvidia_create_i2c_busses(struct nvidia_par *par); +void nvidia_delete_i2c_busses(struct nvidia_par *par); +int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, + u8 ** out_edid); +#else +#define nvidia_create_i2c_busses(...) +#define nvidia_delete_i2c_busses(...) +#define nvidia_probe_i2c_connector(p, c, edid) \ +do { \ + *(edid) = NULL; \ +} while(0) +#endif + +/* in nv_accel.c */ +extern void NVResetGraphics(struct fb_info *info); +extern void nvidiafb_copyarea(struct fb_info *info, + const struct fb_copyarea *region); +extern void nvidiafb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect); +extern void nvidiafb_imageblit(struct fb_info *info, + const struct fb_image *image); +extern int nvidiafb_sync(struct fb_info *info); +extern u8 byte_rev[256]; +#endif /* __NV_PROTO_H__ */ diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c new file mode 100644 index 00000000000..0bbdca2e0f9 --- /dev/null +++ b/drivers/video/nvidia/nv_setup.c @@ -0,0 +1,636 @@ + /***************************************************************************\ +|* *| +|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/ + * XFree86 'nv' driver, this source code is provided under MIT-style licensing + * where the source code is provided "as is" without warranty of any kind. + * The only usage restriction is for the copyright notices to be retained + * whenever code is used. + * + * Antonino Daplas 2005-03-11 + */ + +#include