diff options
Diffstat (limited to 'src/nv_hw.c')
-rw-r--r-- | src/nv_hw.c | 1257 |
1 files changed, 1257 insertions, 0 deletions
diff --git a/src/nv_hw.c b/src/nv_hw.c new file mode 100644 index 0000000..b5bb015 --- /dev/null +++ b/src/nv_hw.c @@ -0,0 +1,1257 @@ + /***************************************************************************\ +|* *| +|* 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 "nv_local.h" +#include "compiler.h" +#include "nv_include.h" + + +void NVLockUnlock ( + NVPtr pNv, + Bool Lock +) +{ + CARD8 cr11; + + VGA_WR08(pNv->PCIO, 0x3D4, 0x1F); + VGA_WR08(pNv->PCIO, 0x3D5, Lock ? 0x99 : 0x57); + + VGA_WR08(pNv->PCIO, 0x3D4, 0x11); + cr11 = VGA_RD08(pNv->PCIO, 0x3D5); + if(Lock) cr11 |= 0x80; + else cr11 &= ~0x80; + VGA_WR08(pNv->PCIO, 0x3D5, cr11); +} + +int NVShowHideCursor ( + NVPtr pNv, + int ShowHide +) +{ + int current = pNv->CurrentState->cursor1; + + pNv->CurrentState->cursor1 = (pNv->CurrentState->cursor1 & 0xFE) | + (ShowHide & 0x01); + VGA_WR08(pNv->PCIO, 0x3D4, 0x31); + VGA_WR08(pNv->PCIO, 0x3D5, pNv->CurrentState->cursor1); + return (current & 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(NVPtr pNv, unsigned int *MClk, unsigned int *NVClk) +{ + unsigned int pll, N, M, MB, NB, P; + + if(pNv->twoStagePLL) { + pll = pNv->PRAMDAC0[0x0504/4]; + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + pll = pNv->PRAMDAC0[0x0574/4]; + if(pll & 0x80000000) { + MB = pll & 0xFF; + NB = (pll >> 8) & 0xFF; + } else { + MB = 1; + NB = 1; + } + *MClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P; + + pll = pNv->PRAMDAC0[0x0500/4]; + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + pll = pNv->PRAMDAC0[0x0570/4]; + if(pll & 0x80000000) { + MB = pll & 0xFF; + NB = (pll >> 8) & 0xFF; + } else { + MB = 1; + NB = 1; + } + *NVClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P; + } else + if(((pNv->Chipset & 0x0ff0) == 0x0300) || + ((pNv->Chipset & 0x0ff0) == 0x0330)) + { + pll = pNv->PRAMDAC0[0x0504/4]; + 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 * pNv->CrystalFreqKHz) / (M * MB)) >> P; + + pll = pNv->PRAMDAC0[0x0500/4]; + 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 * pNv->CrystalFreqKHz) / (M * MB)) >> P; + } else { + pll = pNv->PRAMDAC0[0x0504/4]; + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + *MClk = (N * pNv->CrystalFreqKHz / M) >> P; + + pll = pNv->PRAMDAC0[0x0500/4]; + M = pll & 0xFF; + N = (pll >> 8) & 0xFF; + P = (pll >> 16) & 0x0F; + *NVClk = (N * pNv->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, + NVPtr pNv +) +{ + nv4_fifo_info fifo_data; + nv4_sim_state sim_data; + unsigned int MClk, NVClk, cfg1; + + nvGetClocks(pNv, &MClk, &NVClk); + + cfg1 = pNv->PFB[0x00000204/4]; + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 0; + sim_data.enable_mp = 0; + sim_data.memory_width = (pNv->PEXTDEV[0x0000/4] & 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) */ + + mclks = 1; /* 2 edge sync. may be very close to edge so just put one. */ + + mclks += 1; /* arb_hp_req */ + mclks += 5; /* ap_hp_req tiling pipeline */ + + mclks += 2; /* tc_req latency fifo */ + mclks += 2; /* fb_cas_n_ memory request to fbio block */ + mclks += 7; /* sm_d_rdv data returned from fbio block */ + + /* fb.rd.d.Put_gc need to accumulate 256 bits for read */ + if (arb->memory_type == 0) + if (arb->memory_width == 64) /* 64 bit bus */ + mclks += 4; + else + mclks += 2; + else + if (arb->memory_width == 64) /* 64 bit bus */ + mclks += 2; + else + mclks += 1; + + if ((!video_enable) && (arb->memory_width == 128)) + { + mclk_extra = (bpp == 32) ? 31 : 42; /* Margin of error */ + min_mclk_extra = 17; + } + else + { + mclk_extra = (bpp == 32) ? 8 : 4; /* Margin of error */ + /* mclk_extra = 4; */ /* Margin of error */ + min_mclk_extra = 18; + } + + nvclks += 1; /* 2 edge sync. may be very close to edge so just put one. */ + nvclks += 1; /* fbi_d_rdv_n */ + nvclks += 1; /* Fbi_d_rdata */ + nvclks += 1; /* crtfifo load */ + + if(mp_enable) + mclks+=4; /* Mp can get in with a burst of 8. */ + /* Extra clocks determined by heuristics */ + + nvclks += 0; + pclks += 0; + found = 0; + while(found != 1) { + fifo->valid = 1; + found = 1; + mclk_loop = mclks+mclk_extra; + us_m = mclk_loop *1000*1000 / mclk_freq; /* Mclk latency in us */ + us_m_min = mclks * 1000*1000 / mclk_freq; /* Minimum Mclk latency in us */ + us_min_mclk_extra = min_mclk_extra *1000*1000 / mclk_freq; + us_n = nvclks*1000*1000 / nvclk_freq;/* nvclk latency in us */ + us_p = pclks*1000*1000 / pclk_freq;/* nvclk latency in us */ + us_pipe_min = us_m_min + us_n + us_p; + + vus_m = mclk_loop *1000*1000 / mclk_freq; /* Mclk latency in us */ + + 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; + + us_video = vpm_us + vus_m; /* Video has separate read return path */ + + cpm_us = crtpagemiss * pagemiss *1000*1000/ mclk_freq; + us_crt = + us_video /* Wait for video */ + +cpm_us /* CRT Page miss */ + +us_m + us_n +us_p /* other latency */ + ; + + clwm = us_crt * crtc_drain_rate/(1000*1000); + clwm++; /* fixed point <= float_point - 1. Fixes that */ + } else { + crtc_drain_rate = pclk_freq * bpp/8; /* bpp * pclk/8 */ + + crtpagemiss = 1; /* self generating page miss */ + crtpagemiss += 1; /* MA0 page miss */ + if(mp_enable) + crtpagemiss += 1; /* if MA0 conflict */ + cpm_us = crtpagemiss * pagemiss *1000*1000/ mclk_freq; + us_crt = cpm_us + us_m + us_n + us_p ; + clwm = us_crt * crtc_drain_rate/(1000*1000); + clwm++; /* fixed point <= float_point - 1. Fixes that */ + + /* + // + // Another concern, only for high pclks so don't do this + // with video: + // What happens if the latency to fetch the cbs is so large that + // fifo empties. In that case we need to have an alternate clwm value + // based off the total burst fetch + // + us_crt = (cbs * 1000 * 1000)/ (8*width)/mclk_freq ; + us_crt = us_crt + us_m + us_n + us_p + (4 * 1000 * 1000)/mclk_freq; + clwm_mt = us_crt * crtc_drain_rate/(1000*1000); + clwm_mt ++; + if(clwm_mt > clwm) + clwm = clwm_mt; + */ + /* Finally, a heuristic check when width == 64 bits */ + if(width == 1){ + nvclk_fill = nvclk_freq * 8; + if(crtc_drain_rate * 100 >= nvclk_fill * 102) + clwm = 0xfff; /*Large number to fail */ + + else if(crtc_drain_rate * 100 >= nvclk_fill * 98) { + clwm = 1024; + cbs = 512; + } + } + } + + + /* + 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) { + found = 1; /* Can't adjust anymore! */ + } else { + cbs = cbs/2; /* reduce the burst size */ + } + } else { + min_mclk_extra--; + } + } else { + if (clwm > 1023){ /* Have some margin */ + fifo->valid = 0; + found = 0; + if(min_mclk_extra == 0) + found = 1; /* Can't adjust anymore! */ + else + min_mclk_extra--; + } + } + + 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, + NVPtr pNv +) +{ + nv10_fifo_info fifo_data; + nv10_sim_state sim_data; + unsigned int MClk, NVClk, cfg1; + + nvGetClocks(pNv, &MClk, &NVClk); + + cfg1 = pNv->PFB[0x0204/4]; + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 1; + sim_data.enable_mp = 0; + sim_data.memory_type = (pNv->PFB[0x0200/4] & 0x01) ? 1 : 0; + sim_data.memory_width = (pNv->PEXTDEV[0x0000/4] & 0x10) ? 128 : 64; + sim_data.mem_latency = (char)cfg1 & 0x0F; + sim_data.mem_aligned = 1; + sim_data.mem_page_miss = (char)(((cfg1>>4) &0x0F) + ((cfg1>>31) & 0x01)); + sim_data.gr_during_vid = 0; + sim_data.pclk_khz = VClk; + sim_data.mclk_khz = MClk; + sim_data.nvclk_khz = NVClk; + nv10CalcArbitration(&fifo_data, &sim_data); + if (fifo_data.valid) { + int b = fifo_data.graphics_burst_size >> 4; + *burst = 0; + while (b >>= 1) (*burst)++; + *lwm = fifo_data.graphics_lwm >> 3; + } +} + +static void nForceUpdateArbitrationSettings ( + unsigned VClk, + unsigned pixelDepth, + unsigned *burst, + unsigned *lwm, + NVPtr pNv +) +{ + nv10_fifo_info fifo_data; + nv10_sim_state sim_data; + unsigned int M, N, P, pll, MClk, NVClk; + unsigned int uMClkPostDiv, memctrl; + + uMClkPostDiv = (pciReadLong(pciTag(0, 0, 3), 0x6C) >> 8) & 0xf; + if(!uMClkPostDiv) uMClkPostDiv = 4; + MClk = 400000 / uMClkPostDiv; + + pll = pNv->PRAMDAC0[0x0500/4]; + M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; + NVClk = (N * pNv->CrystalFreqKHz / M) >> P; + sim_data.pix_bpp = (char)pixelDepth; + sim_data.enable_video = 0; + sim_data.enable_mp = 0; + sim_data.memory_type = (pciReadLong(pciTag(0, 0, 1), 0x7C) >> 12) & 1; + sim_data.memory_width = 64; + + memctrl = pciReadLong(pciTag(0, 0, 3), 0x00) >> 16; + + if((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) { + int dimm[3]; + + dimm[0] = (pciReadLong(pciTag(0, 0, 2), 0x40) >> 8) & 0x4F; + dimm[1] = (pciReadLong(pciTag(0, 0, 2), 0x44) >> 8) & 0x4F; + dimm[2] = (pciReadLong(pciTag(0, 0, 2), 0x48) >> 8) & 0x4F; + + if((dimm[0] + dimm[1]) != dimm[2]) { + ErrorF("WARNING: " + "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, + U032 *pllOut, + NVPtr pNv +) +{ + unsigned lowM, highM; + unsigned DeltaNew, DeltaOld; + unsigned VClk, Freq; + unsigned M, N, P; + + DeltaOld = 0xFFFFFFFF; + + VClk = (unsigned)clockIn; + + if (pNv->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) / pNv->CrystalFreqKHz; + if(N <= 255) { + Freq = ((pNv->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, + U032 *pllOut, + U032 *pllBOut, + NVPtr pNv +) +{ + 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) / (pNv->CrystalFreqKHz << 2); + if((N >= 5) && (N <= 255)) { + Freq = (((pNv->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 ( + NVPtr pNv, + 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(pNv->twoStagePLL) + CalcVClock2Stage(dotClock, &VClk, &state->pll, &state->pllB, pNv); + else + CalcVClock(dotClock, &VClk, &state->pll, pNv); + + switch (pNv->Architecture) + { + case NV_ARCH_04: + nv4UpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), + pNv); + state->cursor0 = 0x00; + state->cursor1 = 0xbC; + if (flags & V_DBLSCAN) + 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(((pNv->Chipset & 0xffff) == 0x01A0) || + ((pNv->Chipset & 0xffff) == 0x01f0)) + { + nForceUpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), + pNv); + } else { + nv10UpdateArbitrationSettings(VClk, + pixelDepth * 8, + &(state->arbitration0), + &(state->arbitration1), + pNv); + } + state->cursor0 = 0x80 | (pNv->CursorStart >> 17); + state->cursor1 = (pNv->CursorStart >> 11) << 2; + state->cursor2 = pNv->CursorStart >> 24; + if (flags & V_DBLSCAN) + state->cursor1 |= 2; + state->pllsel = 0x10000700; + state->config = pNv->PFB[0x00000200/4]; + 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 ( + NVPtr pNv, + RIVA_HW_STATE *state +) +{ + int i; + + pNv->PMC[0x0140/4] = 0x00000000; + pNv->PMC[0x0200/4] = 0xFFFF00FF; + pNv->PMC[0x0200/4] = 0xFFFFFFFF; + + pNv->PTIMER[0x0200] = 0x00000008; + pNv->PTIMER[0x0210] = 0x00000003; + pNv->PTIMER[0x0140] = 0x00000000; + pNv->PTIMER[0x0100] = 0xFFFFFFFF; + + if(pNv->Architecture == NV_ARCH_04) { + pNv->PFB[0x0200/4] = state->config; + } else { + pNv->PFB[0x0240/4] = 0; + pNv->PFB[0x0244/4] = pNv->FbMapSize - 1; + pNv->PFB[0x0250/4] = 0; + pNv->PFB[0x0254/4] = pNv->FbMapSize - 1; + pNv->PFB[0x0260/4] = 0; + pNv->PFB[0x0264/4] = pNv->FbMapSize - 1; + pNv->PFB[0x0270/4] = 0; + pNv->PFB[0x0274/4] = pNv->FbMapSize - 1; + pNv->PFB[0x0280/4] = 0; + pNv->PFB[0x0284/4] = pNv->FbMapSize - 1; + pNv->PFB[0x0290/4] = 0; + pNv->PFB[0x0294/4] = pNv->FbMapSize - 1; + pNv->PFB[0x02A0/4] = 0; + pNv->PFB[0x02A4/4] = pNv->FbMapSize - 1; + pNv->PFB[0x02B0/4] = 0; + pNv->PFB[0x02B4/4] = pNv->FbMapSize - 1; + } + + pNv->PRAMIN[0x0000] = 0x80000010; + pNv->PRAMIN[0x0001] = 0x80011201; + pNv->PRAMIN[0x0002] = 0x80000011; + pNv->PRAMIN[0x0003] = 0x80011202; + pNv->PRAMIN[0x0004] = 0x80000012; + pNv->PRAMIN[0x0005] = 0x80011203; + pNv->PRAMIN[0x0006] = 0x80000013; + pNv->PRAMIN[0x0007] = 0x80011204; + pNv->PRAMIN[0x0008] = 0x80000014; + pNv->PRAMIN[0x0009] = 0x80011205; + pNv->PRAMIN[0x000A] = 0x80000015; + pNv->PRAMIN[0x000B] = 0x80011206; + pNv->PRAMIN[0x000C] = 0x80000016; + pNv->PRAMIN[0x000D] = 0x80011207; + pNv->PRAMIN[0x000E] = 0x80000017; + pNv->PRAMIN[0x000F] = 0x80011208; + pNv->PRAMIN[0x0800] = 0x00003000; + pNv->PRAMIN[0x0801] = pNv->FbMapSize - 1; + pNv->PRAMIN[0x0802] = 0x00000002; + pNv->PRAMIN[0x0803] = 0x00000002; + if(pNv->Architecture >= NV_ARCH_10) + pNv->PRAMIN[0x0804] = 0x01008062; + else + pNv->PRAMIN[0x0804] = 0x01008042; + pNv->PRAMIN[0x0805] = 0x00000000; + pNv->PRAMIN[0x0806] = 0x12001200; + pNv->PRAMIN[0x0807] = 0x00000000; + pNv->PRAMIN[0x0808] = 0x01008043; + pNv->PRAMIN[0x0809] = 0x00000000; + pNv->PRAMIN[0x080A] = 0x00000000; + pNv->PRAMIN[0x080B] = 0x00000000; + pNv->PRAMIN[0x080C] = 0x01008044; + pNv->PRAMIN[0x080D] = 0x00000002; + pNv->PRAMIN[0x080E] = 0x00000000; + pNv->PRAMIN[0x080F] = 0x00000000; + pNv->PRAMIN[0x0810] = 0x01008019; + pNv->PRAMIN[0x0811] = 0x00000000; + pNv->PRAMIN[0x0812] = 0x00000000; + pNv->PRAMIN[0x0813] = 0x00000000; + pNv->PRAMIN[0x0814] = 0x0100A05C; + pNv->PRAMIN[0x0815] = 0x00000000; + pNv->PRAMIN[0x0816] = 0x00000000; + pNv->PRAMIN[0x0817] = 0x00000000; + pNv->PRAMIN[0x0818] = 0x0100805F; + pNv->PRAMIN[0x0819] = 0x00000000; + pNv->PRAMIN[0x081A] = 0x12001200; + pNv->PRAMIN[0x081B] = 0x00000000; + pNv->PRAMIN[0x081C] = 0x0100804A; + pNv->PRAMIN[0x081D] = 0x00000002; + pNv->PRAMIN[0x081E] = 0x00000000; + pNv->PRAMIN[0x081F] = 0x00000000; + pNv->PRAMIN[0x0820] = 0x01018077; + pNv->PRAMIN[0x0821] = 0x00000000; + pNv->PRAMIN[0x0822] = 0x01201200; + pNv->PRAMIN[0x0823] = 0x00000000; + pNv->PRAMIN[0x0824] = 0x00003002; + pNv->PRAMIN[0x0825] = 0x00007FFF; + pNv->PRAMIN[0x0826] = pNv->FbUsableSize | 0x00000002; + pNv->PRAMIN[0x0827] = 0x00000002; + +#if X_BYTE_ORDER == X_BIG_ENDIAN + pNv->PRAMIN[0x0804] |= 0x00080000; + pNv->PRAMIN[0x0808] |= 0x00080000; + pNv->PRAMIN[0x080C] |= 0x00080000; + pNv->PRAMIN[0x0810] |= 0x00080000; + pNv->PRAMIN[0x0814] |= 0x00080000; + pNv->PRAMIN[0x0818] |= 0x00080000; + pNv->PRAMIN[0x081C] |= 0x00080000; + pNv->PRAMIN[0x0820] |= 0x00080000; + + pNv->PRAMIN[0x080D] = 0x00000001; + pNv->PRAMIN[0x081D] = 0x00000001; +#endif + + if(pNv->Architecture < NV_ARCH_10) { + if((pNv->Chipset & 0x0fff) == 0x0020) { + pNv->PRAMIN[0x0824] |= 0x00020000; + pNv->PRAMIN[0x0826] += pNv->FbAddress; + } + pNv->PGRAPH[0x0080/4] = 0x000001FF; + pNv->PGRAPH[0x0080/4] = 0x1230C000; + pNv->PGRAPH[0x0084/4] = 0x72111101; + pNv->PGRAPH[0x0088/4] = 0x11D5F071; + pNv->PGRAPH[0x008C/4] = 0x0004FF31; + + pNv->PGRAPH[0x0140/4] = 0x00000000; + pNv->PGRAPH[0x0100/4] = 0xFFFFFFFF; + pNv->PGRAPH[0x0170/4] = 0x10010100; + pNv->PGRAPH[0x0710/4] = 0xFFFFFFFF; + pNv->PGRAPH[0x0720/4] = 0x00000001; + + pNv->PGRAPH[0x0810/4] = 0x00000000; + } else { + pNv->PGRAPH[0x0080/4] = 0xFFFFFFFF; + pNv->PGRAPH[0x0080/4] = 0x00000000; + + pNv->PGRAPH[0x0140/4] = 0x00000000; + pNv->PGRAPH[0x0100/4] = 0xFFFFFFFF; + pNv->PGRAPH[0x0144/4] = 0x10010100; + pNv->PGRAPH[0x0714/4] = 0xFFFFFFFF; + pNv->PGRAPH[0x0720/4] = 0x00000001; + + if(pNv->Architecture == NV_ARCH_10) { + pNv->PGRAPH[0x0084/4] = 0x00118700; + pNv->PGRAPH[0x0088/4] = 0x24E00810; + pNv->PGRAPH[0x008C/4] = 0x55DE0030; + + for(i = 0; i < 32; i++) + pNv->PGRAPH[(0x0B00/4) + i] = pNv->PFB[(0x0240/4) + i]; + + pNv->PGRAPH[0x640/4] = 0; + pNv->PGRAPH[0x644/4] = 0; + pNv->PGRAPH[0x684/4] = pNv->FbMapSize - 1; + pNv->PGRAPH[0x688/4] = pNv->FbMapSize - 1; + + pNv->PGRAPH[0x0810/4] = 0x00000000; + } else { + if(pNv->Architecture >= NV_ARCH_30) { + pNv->PGRAPH[0x0084/4] = 0x40108700; + pNv->PGRAPH[0x0890/4] = 0x00140000; + pNv->PGRAPH[0x008C/4] = 0xf00e0431; + pNv->PGRAPH[0x0090/4] = 0x00008000; + pNv->PGRAPH[0x0610/4] = 0xf04b1f36; + pNv->PGRAPH[0x0B80/4] = 0x1002d888; + pNv->PGRAPH[0x0B88/4] = 0x62ff007f; + } else { + pNv->PGRAPH[0x0084/4] = 0x00118700; + pNv->PGRAPH[0x008C/4] = 0xF20E0431; + pNv->PGRAPH[0x0090/4] = 0x00000000; + pNv->PGRAPH[0x009C/4] = 0x00000040; + + if((pNv->Chipset & 0x0ff0) >= 0x0250) { + pNv->PGRAPH[0x0890/4] = 0x00080000; + pNv->PGRAPH[0x0610/4] = 0x304B1FB6; + pNv->PGRAPH[0x0B80/4] = 0x18B82880; + pNv->PGRAPH[0x0B84/4] = 0x44000000; + pNv->PGRAPH[0x0098/4] = 0x40000080; + pNv->PGRAPH[0x0B88/4] = 0x000000ff; + } else { + pNv->PGRAPH[0x0880/4] = 0x00080000; + pNv->PGRAPH[0x0094/4] = 0x00000005; + pNv->PGRAPH[0x0B80/4] = 0x45CAA208; + pNv->PGRAPH[0x0B84/4] = 0x24000000; + pNv->PGRAPH[0x0098/4] = 0x00000040; + pNv->PGRAPH[0x0750/4] = 0x00E00038; + pNv->PGRAPH[0x0754/4] = 0x00000030; + pNv->PGRAPH[0x0750/4] = 0x00E10038; + pNv->PGRAPH[0x0754/4] = 0x00000030; + } + } + + for(i = 0; i < 32; i++) + pNv->PGRAPH[(0x0900/4) + i] = pNv->PFB[(0x0240/4) + i]; + + pNv->PGRAPH[0x09A4/4] = pNv->PFB[0x0200/4]; + pNv->PGRAPH[0x09A8/4] = pNv->PFB[0x0204/4]; + pNv->PGRAPH[0x0750/4] = 0x00EA0000; + pNv->PGRAPH[0x0754/4] = pNv->PFB[0x0200/4]; + pNv->PGRAPH[0x0750/4] = 0x00EA0004; + pNv->PGRAPH[0x0754/4] = pNv->PFB[0x0204/4]; + + pNv->PGRAPH[0x0820/4] = 0; + pNv->PGRAPH[0x0824/4] = 0; + pNv->PGRAPH[0x0864/4] = pNv->FbMapSize - 1; + pNv->PGRAPH[0x0868/4] = pNv->FbMapSize - 1; + + pNv->PGRAPH[0x0B20/4] = 0x00000000; + } + } + pNv->PGRAPH[0x053C/4] = 0; + pNv->PGRAPH[0x0540/4] = 0; + pNv->PGRAPH[0x0544/4] = 0x00007FFF; + pNv->PGRAPH[0x0548/4] = 0x00007FFF; + + pNv->PFIFO[0x0140] = 0x00000000; + pNv->PFIFO[0x0141] = 0x00000001; + pNv->PFIFO[0x0480] = 0x00000000; + pNv->PFIFO[0x0494] = 0x00000000; + pNv->PFIFO[0x0481] = 0x00000100; + pNv->PFIFO[0x0490] = 0x00000000; + pNv->PFIFO[0x0491] = 0x00000000; + pNv->PFIFO[0x048B] = 0x00001209; + pNv->PFIFO[0x0400] = 0x00000000; + pNv->PFIFO[0x0414] = 0x00000000; + pNv->PFIFO[0x0084] = 0x03000100; + pNv->PFIFO[0x0085] = 0x00000110; + pNv->PFIFO[0x0086] = 0x00000112; + pNv->PFIFO[0x0143] = 0x0000FFFF; + pNv->PFIFO[0x0496] = 0x0000FFFF; + pNv->PFIFO[0x0050] = 0x00000000; + pNv->PFIFO[0x0040] = 0xFFFFFFFF; + pNv->PFIFO[0x0415] = 0x00000001; + pNv->PFIFO[0x048C] = 0x00000000; + pNv->PFIFO[0x04A0] = 0x00000000; +#if X_BYTE_ORDER == X_BIG_ENDIAN + pNv->PFIFO[0x0489] = 0x800F0078; +#else + pNv->PFIFO[0x0489] = 0x000F0078; +#endif + pNv->PFIFO[0x0488] = 0x00000001; + pNv->PFIFO[0x0480] = 0x00000001; + pNv->PFIFO[0x0494] = 0x00000001; + pNv->PFIFO[0x0495] = 0x00000001; + pNv->PFIFO[0x0140] = 0x00000001; + + if(pNv->Architecture >= NV_ARCH_10) { + if(pNv->twoHeads) { + pNv->PCRTC0[0x0860/4] = state->head; + pNv->PCRTC0[0x2860/4] = state->head2; + } + pNv->PRAMDAC[0x0404/4] |= (1 << 25); + + pNv->PMC[0x8704/4] = 1; + pNv->PMC[0x8140/4] = 0; + pNv->PMC[0x8920/4] = 0; + pNv->PMC[0x8924/4] = 0; + pNv->PMC[0x8908/4] = pNv->FbMapSize - 1; + pNv->PMC[0x890C/4] = pNv->FbMapSize - 1; + pNv->PMC[0x1588/4] = 0; + + pNv->PCRTC[0x0810/4] = state->cursorConfig; + + if(pNv->FlatPanel) { + if((pNv->Chipset & 0x0ff0) == 0x0110) { + pNv->PRAMDAC[0x0528/4] = state->dither; + } else + if((pNv->Chipset & 0x0ff0) >= 0x0170) { + pNv->PRAMDAC[0x083C/4] = state->dither; + } + + VGA_WR08(pNv->PCIO, 0x03D4, 0x53); + VGA_WR08(pNv->PCIO, 0x03D5, 0); + VGA_WR08(pNv->PCIO, 0x03D4, 0x54); + VGA_WR08(pNv->PCIO, 0x03D5, 0); + VGA_WR08(pNv->PCIO, 0x03D4, 0x21); + VGA_WR08(pNv->PCIO, 0x03D5, 0xfa); + } + + VGA_WR08(pNv->PCIO, 0x03D4, 0x41); + VGA_WR08(pNv->PCIO, 0x03D5, state->extra); + } + + VGA_WR08(pNv->PCIO, 0x03D4, 0x19); + VGA_WR08(pNv->PCIO, 0x03D5, state->repaint0); + VGA_WR08(pNv->PCIO, 0x03D4, 0x1A); + VGA_WR08(pNv->PCIO, 0x03D5, state->repaint1); + VGA_WR08(pNv->PCIO, 0x03D4, 0x25); + VGA_WR08(pNv->PCIO, 0x03D5, state->screen); + VGA_WR08(pNv->PCIO, 0x03D4, 0x28); + VGA_WR08(pNv->PCIO, 0x03D5, state->pixel); + VGA_WR08(pNv->PCIO, 0x03D4, 0x2D); + VGA_WR08(pNv->PCIO, 0x03D5, state->horiz); + VGA_WR08(pNv->PCIO, 0x03D4, 0x1B); + VGA_WR08(pNv->PCIO, 0x03D5, state->arbitration0); + VGA_WR08(pNv->PCIO, 0x03D4, 0x20); + VGA_WR08(pNv->PCIO, 0x03D5, state->arbitration1); + VGA_WR08(pNv->PCIO, 0x03D4, 0x30); + VGA_WR08(pNv->PCIO, 0x03D5, state->cursor0); + VGA_WR08(pNv->PCIO, 0x03D4, 0x31); + VGA_WR08(pNv->PCIO, 0x03D5, state->cursor1); + VGA_WR08(pNv->PCIO, 0x03D4, 0x2F); + VGA_WR08(pNv->PCIO, 0x03D5, state->cursor2); + VGA_WR08(pNv->PCIO, 0x03D4, 0x39); + VGA_WR08(pNv->PCIO, 0x03D5, state->interlace); + + if(!pNv->FlatPanel) { + pNv->PRAMDAC0[0x050C/4] = state->pllsel; + pNv->PRAMDAC0[0x0508/4] = state->vpll; + if(pNv->twoHeads) + pNv->PRAMDAC0[0x0520/4] = state->vpll2; + if(pNv->twoStagePLL) { + pNv->PRAMDAC0[0x0578/4] = state->vpllB; + pNv->PRAMDAC0[0x057C/4] = state->vpll2B; + } + } else { + pNv->PRAMDAC[0x0848/4] = state->scale; + } + pNv->PRAMDAC[0x0600/4] = state->general; + + pNv->PCRTC[0x0140/4] = 0; + pNv->PCRTC[0x0100/4] = 1; + + pNv->CurrentState = state; +} + +void NVUnloadStateExt +( + NVPtr pNv, + RIVA_HW_STATE *state +) +{ + VGA_WR08(pNv->PCIO, 0x03D4, 0x19); + state->repaint0 = VGA_RD08(pNv->PCIO, 0x03D5); + VGA_WR08(pNv->PCIO, 0x03D4, 0x1A); + state->repaint1 = VGA_RD08(pNv->PCIO, 0x03D5); + VGA_WR08(pNv->PCIO, 0x03D4, 0x25); + state->screen = VGA_RD08(pNv->PCIO, 0x03D5); + VGA_WR08(pNv->PCIO, 0x03D4, 0x28); + state->pixel = VGA_RD08(pNv->PCIO, 0x03D5); + VGA_WR08(pNv->PCIO, 0x03D4, 0x2D); + state->horiz = VGA_RD08(pNv->PCIO, 0x03D5); + VGA_WR08(pNv->PCIO, 0x03D4, 0x1B); + state->arbitration0 = VGA_RD08(pNv->PCIO, 0x03D5); + VGA_WR08(pNv->PCIO, 0x03D4, 0x20); + state->arbitration1 = VGA_RD08(pNv->PCIO, 0x03D5); + VGA_WR08(pNv->PCIO, 0x03D4, 0x30); + state->cursor0 = VGA_RD08(pNv->PCIO, 0x03D5); + VGA_WR08(pNv->PCIO, 0x03D4, 0x31); + state->cursor1 = VGA_RD08(pNv->PCIO, 0x03D5); + VGA_WR08(pNv->PCIO, 0x03D4, 0x2F); + state->cursor2 = VGA_RD08(pNv->PCIO, 0x03D5); + VGA_WR08(pNv->PCIO, 0x03D4, 0x39); + state->interlace = VGA_RD08(pNv->PCIO, 0x03D5); + state->vpll = pNv->PRAMDAC0[0x0508/4]; + if(pNv->twoHeads) + state->vpll2 = pNv->PRAMDAC0[0x0520/4]; + if(pNv->twoStagePLL) { + state->vpllB = pNv->PRAMDAC0[0x0578/4]; + state->vpll2B = pNv->PRAMDAC0[0x057C/4]; + } + state->pllsel = pNv->PRAMDAC0[0x050C/4]; + state->general = pNv->PRAMDAC[0x0600/4]; + state->scale = pNv->PRAMDAC[0x0848/4]; + state->config = pNv->PFB[0x0200/4]; + + if(pNv->Architecture >= NV_ARCH_10) { + if(pNv->twoHeads) { + state->head = pNv->PCRTC0[0x0860/4]; + state->head2 = pNv->PCRTC0[0x2860/4]; + VGA_WR08(pNv->PCIO, 0x03D4, 0x44); + state->crtcOwner = VGA_RD08(pNv->PCIO, 0x03D5); + } + VGA_WR08(pNv->PCIO, 0x03D4, 0x41); + state->extra = VGA_RD08(pNv->PCIO, 0x03D5); + state->cursorConfig = pNv->PCRTC[0x0810/4]; + + if((pNv->Chipset & 0x0ff0) == 0x0110) { + state->dither = pNv->PRAMDAC[0x0528/4]; + } else + if((pNv->Chipset & 0x0ff0) >= 0x0170) { + state->dither = pNv->PRAMDAC[0x083C/4]; + } + } +} + +void NVSetStartAddress ( + NVPtr pNv, + CARD32 start +) +{ + pNv->PCRTC[0x800/4] = start; +} + + |