Tighten bios reg checks a little
[nouveau] / src / nv_hw.c
1 /***************************************************************************\
2 |*                                                                           *|
3 |*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
4 |*                                                                           *|
5 |*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
6 |*     international laws.  Users and possessors of this source code are     *|
7 |*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
8 |*     use this code in individual and commercial software.                  *|
9 |*                                                                           *|
10 |*     Any use of this source code must include,  in the user documenta-     *|
11 |*     tion and  internal comments to the code,  notices to the end user     *|
12 |*     as follows:                                                           *|
13 |*                                                                           *|
14 |*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
15 |*                                                                           *|
16 |*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
17 |*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
18 |*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
19 |*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
20 |*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
21 |*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
22 |*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
23 |*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
24 |*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
25 |*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
26 |*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
27 |*                                                                           *|
28 |*     U.S. Government  End  Users.   This source code  is a "commercial     *|
29 |*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
30 |*     consisting  of "commercial  computer  software"  and  "commercial     *|
31 |*     computer  software  documentation,"  as such  terms  are  used in     *|
32 |*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
33 |*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
34 |*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
35 |*     all U.S. Government End Users  acquire the source code  with only     *|
36 |*     those rights set forth herein.                                        *|
37 |*                                                                           *|
38  \***************************************************************************/
39 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_hw.c,v 1.21 2006/06/16 00:19:33 mvojkovi Exp $ */
40
41 #include "nv_include.h"
42 #include "nv_local.h"
43 #include "compiler.h"
44
45 /* Reminder: Do NOT use these functions for the randr-1.2 codepath. */
46 uint8_t nvReadVGA(NVPtr pNv, uint8_t index)
47 {
48         volatile const uint8_t *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
49         assert(pNv->randr12_enable == FALSE);
50         VGA_WR08(ptr, 0x03D4, index);
51         return VGA_RD08(ptr, 0x03D5);
52 }
53 void nvWriteVGA(NVPtr pNv, uint8_t index, uint8_t data)
54 {
55         volatile const uint8_t *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
56         assert(pNv->randr12_enable == FALSE);
57         VGA_WR08(ptr, 0x03D4, index);
58         VGA_WR08(ptr, 0x03D5, data);
59 }
60
61 uint32_t nvReadRAMDAC(NVPtr pNv, uint8_t head, uint32_t reg)
62 {
63         if (head)
64                 reg += NV_PRAMDAC0_SIZE;
65         assert(pNv->randr12_enable == FALSE);
66         DDXMMIOH("nvReadRamdac: head %d reg %08x val %08x\n", head, reg, (uint32_t)MMIO_IN32(pNv->REGS, reg));
67         return MMIO_IN32(pNv->REGS, reg);
68 }
69
70 void nvWriteRAMDAC(NVPtr pNv, uint8_t head, uint32_t reg, uint32_t val)
71 {
72         if (head)
73                 reg += NV_PRAMDAC0_SIZE;
74         assert(pNv->randr12_enable == FALSE);
75         DDXMMIOH("nvWriteRamdac: head %d reg %08x val %08x\n", head, reg, val);
76         MMIO_OUT32(pNv->REGS, reg, val);
77 }
78
79 uint32_t nvReadCRTC(NVPtr pNv, uint8_t head, uint32_t reg)
80 {
81         if (head)
82                 reg += NV_PCRTC0_SIZE;
83         assert(pNv->randr12_enable == FALSE);
84         DDXMMIOH("nvReadCRTC: head %d reg %08x val %08x\n", head, reg, (uint32_t)MMIO_IN32(pNv->REGS, reg));
85         return MMIO_IN32(pNv->REGS, reg);
86 }
87
88 void nvWriteCRTC(NVPtr pNv, uint8_t head, uint32_t reg, uint32_t val)
89 {
90         if (head)
91                 reg += NV_PCRTC0_SIZE;
92         assert(pNv->randr12_enable == FALSE);
93         DDXMMIOH("nvWriteCRTC: head %d reg %08x val %08x\n", head, reg, val);
94         MMIO_OUT32(pNv->REGS, reg, val);
95 }
96
97 void NVLockUnlock (
98     NVPtr pNv,
99     Bool  Lock
100 )
101 {
102     CARD8 cr11;
103
104     nvWriteVGA(pNv, NV_VGA_CRTCX_LOCK, Lock ? 0x99 : 0x57 );
105
106     cr11 = nvReadVGA(pNv, NV_VGA_CRTCX_VSYNCE);
107     if(Lock) cr11 |= 0x80;
108     else cr11 &= ~0x80;
109     nvWriteVGA(pNv, NV_VGA_CRTCX_VSYNCE, cr11);
110 }
111
112 int NVShowHideCursor (
113     NVPtr pNv,
114     int   ShowHide
115 )
116 {
117     int current = pNv->CurrentState->cursor1;
118
119     pNv->CurrentState->cursor1 = (pNv->CurrentState->cursor1 & 0xFE) |
120                                  (ShowHide & 0x01);
121
122     nvWriteVGA(pNv, NV_VGA_CRTCX_CURCTL1, pNv->CurrentState->cursor1);
123
124     if(pNv->Architecture == NV_ARCH_40) {  /* HW bug */
125        volatile CARD32 curpos = nvReadCurRAMDAC(pNv, NV_RAMDAC_CURSOR_POS);
126        nvWriteCurRAMDAC(pNv, NV_RAMDAC_CURSOR_POS, curpos);
127     }
128
129     return (current & 0x01);
130 }
131
132 /****************************************************************************\
133 *                                                                            *
134 * The video arbitration routines calculate some "magic" numbers.  Fixes      *
135 * the snow seen when accessing the framebuffer without it.                   *
136 * It just works (I hope).                                                    *
137 *                                                                            *
138 \****************************************************************************/
139
140 typedef struct {
141   int graphics_lwm;
142   int video_lwm;
143   int graphics_burst_size;
144   int video_burst_size;
145   int valid;
146 } nv4_fifo_info;
147
148 typedef struct {
149   int pclk_khz;
150   int mclk_khz;
151   int nvclk_khz;
152   char mem_page_miss;
153   char mem_latency;
154   int memory_width;
155   char enable_video;
156   char gr_during_vid;
157   char pix_bpp;
158   char mem_aligned;
159   char enable_mp;
160 } nv4_sim_state;
161
162 typedef struct {
163   int graphics_lwm;
164   int video_lwm;
165   int graphics_burst_size;
166   int video_burst_size;
167   int valid;
168 } nv10_fifo_info;
169
170 typedef struct {
171   uint32_t pclk_khz;
172   uint32_t mclk_khz;
173   uint32_t nvclk_khz;
174   uint8_t mem_page_miss;
175   uint8_t mem_latency;
176   uint32_t memory_type;
177   uint32_t memory_width;
178   uint8_t enable_video;
179   uint8_t gr_during_vid;
180   uint8_t pix_bpp;
181   uint8_t mem_aligned;
182   uint8_t enable_mp;
183 } nv10_sim_state;
184
185
186 static void nvGetClocks(NVPtr pNv, unsigned int *MClk, unsigned int *NVClk)
187 {
188         unsigned int pll, N, M, MB, NB, P;
189
190     if(pNv->Architecture >= NV_ARCH_40) {
191         Bool VCO2_off = FALSE;
192        pll = nvReadMC(pNv, 0x4020);
193        P = (pll >> 16) & 0x07;
194         /* There seem to be 2 (redundant?) switches to turn VCO2 off. */
195         if (pll & (1 << 8))
196                 VCO2_off = TRUE;
197         if (!(pll & (1 << 30))) 
198                 VCO2_off = TRUE;
199        pll = nvReadMC(pNv, 0x4024);
200        M = pll & 0xFF;
201        N = (pll >> 8) & 0xFF;
202         if (VCO2_off) {
203                 MB = 1;
204                 NB = 1;
205         } else {
206                 MB = (pll >> 16) & 0xFF;
207                 NB = (pll >> 24) & 0xFF;
208         }
209         if (!MB || !NB) {
210                 ErrorF("Something wrong with MPLL VCO2 settings, ignoring VCO2.\n");
211                 MB = 1;
212                 NB = 1;
213         }
214
215        *MClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P;
216
217         VCO2_off = FALSE; /* reset */
218
219        pll = nvReadMC(pNv, 0x4000);
220        P = (pll >> 16) & 0x07;
221         /* There seem to be 2 (redundant?) switches to turn VCO2 off. */
222         if (pll & (1 << 8))
223                 VCO2_off = TRUE;
224         if (!(pll & (1 << 30))) 
225                 VCO2_off = TRUE;
226        pll = nvReadMC(pNv, 0x4004);
227        M = pll & 0xFF;
228        N = (pll >> 8) & 0xFF;
229         if (VCO2_off) {
230                 MB = 1;
231                 NB = 1;
232         } else {
233                 MB = (pll >> 16) & 0xFF;
234                 NB = (pll >> 24) & 0xFF;
235         }
236         if (!MB || !NB) {
237                 ErrorF("Something wrong with NVPLL VCO2 settings, ignoring VCO2\n");
238                 MB = 1;
239                 NB = 1;
240         }
241
242        *NVClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P;
243     } else
244     if(pNv->twoStagePLL) {
245        pll = nvReadRAMDAC0(pNv, NV_RAMDAC_MPLL);
246        M = pll & 0xFF;
247        N = (pll >> 8) & 0xFF; 
248        P = (pll >> 16) & 0x0F;
249        pll = nvReadRAMDAC0(pNv, NV_RAMDAC_MPLL_B);
250        if(pll & 0x80000000) {
251            MB = pll & 0xFF; 
252            NB = (pll >> 8) & 0xFF;
253        } else {
254            MB = 1;
255            NB = 1;
256        }
257        *MClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P;
258
259        pll = nvReadRAMDAC0(pNv, NV_RAMDAC_NVPLL);
260        M = pll & 0xFF; 
261        N = (pll >> 8) & 0xFF; 
262        P = (pll >> 16) & 0x0F;
263        pll = nvReadRAMDAC0(pNv, NV_RAMDAC_NVPLL_B);
264        if(pll & 0x80000000) {
265            MB = pll & 0xFF;
266            NB = (pll >> 8) & 0xFF;
267        } else {
268            MB = 1;
269            NB = 1;
270        }
271        *NVClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P;
272     } else 
273     if(((pNv->Chipset & 0x0ff0) == CHIPSET_NV30) ||
274        ((pNv->Chipset & 0x0ff0) == CHIPSET_NV35))
275     {
276        pll = nvReadRAMDAC0(pNv, NV_RAMDAC_MPLL);
277        M = pll & 0x0F; 
278        N = (pll >> 8) & 0xFF;
279        P = (pll >> 16) & 0x07;
280        if(pll & 0x00000080) {
281            MB = (pll >> 4) & 0x07;     
282            NB = (pll >> 19) & 0x1f;
283        } else {
284            MB = 1;
285            NB = 1;
286        }
287        *MClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P;
288
289        pll = nvReadRAMDAC0(pNv, NV_RAMDAC_NVPLL);
290        M = pll & 0x0F;
291        N = (pll >> 8) & 0xFF;
292        P = (pll >> 16) & 0x07;
293        if(pll & 0x00000080) {
294            MB = (pll >> 4) & 0x07;
295            NB = (pll >> 19) & 0x1f;
296        } else {
297            MB = 1;
298            NB = 1;
299        }
300        *NVClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P;
301     } else {
302        pll = nvReadRAMDAC0(pNv, NV_RAMDAC_MPLL);
303        M = pll & 0xFF; 
304        N = (pll >> 8) & 0xFF; 
305        P = (pll >> 16) & 0x0F;
306        *MClk = (N * pNv->CrystalFreqKHz / M) >> P;
307
308        pll = nvReadRAMDAC0(pNv, NV_RAMDAC_NVPLL);
309        M = pll & 0xFF; 
310        N = (pll >> 8) & 0xFF; 
311        P = (pll >> 16) & 0x0F;
312        *NVClk = (N * pNv->CrystalFreqKHz / M) >> P;
313     }
314
315 #if 0
316     ErrorF("NVClock = %i MHz, MEMClock = %i MHz\n", *NVClk/1000, *MClk/1000);
317 #endif
318 }
319
320
321 void nv4CalcArbitration (
322     nv4_fifo_info *fifo,
323     nv4_sim_state *arb
324 )
325 {
326     int data, pagemiss, cas,width, video_enable, bpp;
327     int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs;
328     int found, mclk_extra, mclk_loop, cbs, m1, p1;
329     int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
330     int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate;
331     int vpm_us, us_video, vlwm, video_fill_us, cpm_us, us_crt,clwm;
332
333     fifo->valid = 1;
334     pclk_freq = arb->pclk_khz;
335     mclk_freq = arb->mclk_khz;
336     nvclk_freq = arb->nvclk_khz;
337     pagemiss = arb->mem_page_miss;
338     cas = arb->mem_latency;
339     width = arb->memory_width >> 6;
340     video_enable = arb->enable_video;
341     bpp = arb->pix_bpp;
342     mp_enable = arb->enable_mp;
343     clwm = 0;
344     vlwm = 0;
345     cbs = 128;
346     pclks = 2;
347     nvclks = 2;
348     nvclks += 2;
349     nvclks += 1;
350     mclks = 5;
351     mclks += 3;
352     mclks += 1;
353     mclks += cas;
354     mclks += 1;
355     mclks += 1;
356     mclks += 1;
357     mclks += 1;
358     mclk_extra = 3;
359     nvclks += 2;
360     nvclks += 1;
361     nvclks += 1;
362     nvclks += 1;
363     if (mp_enable)
364         mclks+=4;
365     nvclks += 0;
366     pclks += 0;
367     found = 0;
368     vbs = 0;
369     while (found != 1)
370     {
371         fifo->valid = 1;
372         found = 1;
373         mclk_loop = mclks+mclk_extra;
374         us_m = mclk_loop *1000*1000 / mclk_freq;
375         us_n = nvclks*1000*1000 / nvclk_freq;
376         us_p = nvclks*1000*1000 / pclk_freq;
377         if (video_enable)
378         {
379             video_drain_rate = pclk_freq * 2;
380             crtc_drain_rate = pclk_freq * bpp/8;
381             vpagemiss = 2;
382             vpagemiss += 1;
383             crtpagemiss = 2;
384             vpm_us = (vpagemiss * pagemiss)*1000*1000/mclk_freq;
385             if (nvclk_freq * 2 > mclk_freq * width)
386                 video_fill_us = cbs*1000*1000 / 16 / nvclk_freq ;
387             else
388                 video_fill_us = cbs*1000*1000 / (8 * width) / mclk_freq;
389             us_video = vpm_us + us_m + us_n + us_p + video_fill_us;
390             vlwm = us_video * video_drain_rate/(1000*1000);
391             vlwm++;
392             vbs = 128;
393             if (vlwm > 128) vbs = 64;
394             if (vlwm > (256-64)) vbs = 32;
395             if (nvclk_freq * 2 > mclk_freq * width)
396                 video_fill_us = vbs *1000*1000/ 16 / nvclk_freq ;
397             else
398                 video_fill_us = vbs*1000*1000 / (8 * width) / mclk_freq;
399             cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
400             us_crt =
401             us_video
402             +video_fill_us
403             +cpm_us
404             +us_m + us_n +us_p
405             ;
406             clwm = us_crt * crtc_drain_rate/(1000*1000);
407             clwm++;
408         }
409         else
410         {
411             crtc_drain_rate = pclk_freq * bpp/8;
412             crtpagemiss = 2;
413             crtpagemiss += 1;
414             cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
415             us_crt =  cpm_us + us_m + us_n + us_p ;
416             clwm = us_crt * crtc_drain_rate/(1000*1000);
417             clwm++;
418         }
419         m1 = clwm + cbs - 512;
420         p1 = m1 * pclk_freq / mclk_freq;
421         p1 = p1 * bpp / 8;
422         if ((p1 < m1) && (m1 > 0))
423         {
424             fifo->valid = 0;
425             found = 0;
426             if (mclk_extra ==0)   found = 1;
427             mclk_extra--;
428         }
429         else if (video_enable)
430         {
431             if ((clwm > 511) || (vlwm > 255))
432             {
433                 fifo->valid = 0;
434                 found = 0;
435                 if (mclk_extra ==0)   found = 1;
436                 mclk_extra--;
437             }
438         }
439         else
440         {
441             if (clwm > 519)
442             {
443                 fifo->valid = 0;
444                 found = 0;
445                 if (mclk_extra ==0)   found = 1;
446                 mclk_extra--;
447             }
448         }
449         if (clwm < 384) clwm = 384;
450         if (vlwm < 128) vlwm = 128;
451         data = (int)(clwm);
452         fifo->graphics_lwm = data;
453         fifo->graphics_burst_size = 128;
454         data = (int)((vlwm+15));
455         fifo->video_lwm = data;
456         fifo->video_burst_size = vbs;
457     }
458 }
459
460 void nv4UpdateArbitrationSettings (
461     unsigned      VClk, 
462     unsigned      pixelDepth, 
463     unsigned     *burst,
464     unsigned     *lwm,
465     NVPtr        pNv
466 )
467 {
468     nv4_fifo_info fifo_data;
469     nv4_sim_state sim_data;
470     unsigned int MClk, NVClk, cfg1;
471
472     nvGetClocks(pNv, &MClk, &NVClk);
473
474     cfg1 = nvReadFB(pNv, NV_PFB_CFG1);
475     sim_data.pix_bpp        = (char)pixelDepth;
476     sim_data.enable_video   = 0;
477     sim_data.enable_mp      = 0;
478     sim_data.memory_width   = (nvReadEXTDEV(pNv, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64;
479     sim_data.mem_latency    = (char)cfg1 & 0x0F;
480     sim_data.mem_aligned    = 1;
481     sim_data.mem_page_miss  = (char)(((cfg1 >> 4) &0x0F) + ((cfg1 >> 31) & 0x01));
482     sim_data.gr_during_vid  = 0;
483     sim_data.pclk_khz       = VClk;
484     sim_data.mclk_khz       = MClk;
485     sim_data.nvclk_khz      = NVClk;
486     nv4CalcArbitration(&fifo_data, &sim_data);
487     if (fifo_data.valid)
488     {
489         int  b = fifo_data.graphics_burst_size >> 4;
490         *burst = 0;
491         while (b >>= 1) (*burst)++;
492         *lwm   = fifo_data.graphics_lwm >> 3;
493     }
494 }
495
496 void nv10CalcArbitration (
497     nv10_fifo_info *fifo,
498     nv10_sim_state *arb
499 )
500 {
501     int data, pagemiss, width, video_enable, bpp;
502     int nvclks, mclks, pclks, vpagemiss, crtpagemiss;
503     int nvclk_fill;
504     int found, mclk_extra, mclk_loop, cbs, m1;
505     int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
506     int us_m, us_m_min, us_n, us_p, crtc_drain_rate;
507     int vus_m;
508     int vpm_us, us_video, cpm_us, us_crt,clwm;
509     int clwm_rnd_down;
510     int m2us, us_pipe_min, p1clk, p2;
511     int min_mclk_extra;
512     int us_min_mclk_extra;
513
514     fifo->valid = 1;
515     pclk_freq = arb->pclk_khz; /* freq in KHz */
516     mclk_freq = arb->mclk_khz;
517     nvclk_freq = arb->nvclk_khz;
518     pagemiss = arb->mem_page_miss;
519     width = arb->memory_width/64;
520     video_enable = arb->enable_video;
521     bpp = arb->pix_bpp;
522     mp_enable = arb->enable_mp;
523     clwm = 0;
524
525     cbs = 512;
526
527     pclks = 4; /* lwm detect. */
528
529     nvclks = 3; /* lwm -> sync. */
530     nvclks += 2; /* fbi bus cycles (1 req + 1 busy) */
531
532     mclks  = 1;   /* 2 edge sync.  may be very close to edge so just put one. */
533
534     mclks += 1;   /* arb_hp_req */
535     mclks += 5;   /* ap_hp_req   tiling pipeline */
536
537     mclks += 2;    /* tc_req     latency fifo */
538     mclks += 2;    /* fb_cas_n_  memory request to fbio block */
539     mclks += 7;    /* sm_d_rdv   data returned from fbio block */
540
541     /* fb.rd.d.Put_gc   need to accumulate 256 bits for read */
542     if (arb->memory_type == 0)
543       if (arb->memory_width == 64) /* 64 bit bus */
544         mclks += 4;
545       else
546         mclks += 2;
547     else
548       if (arb->memory_width == 64) /* 64 bit bus */
549         mclks += 2;
550       else
551         mclks += 1;
552
553     if ((!video_enable) && (arb->memory_width == 128))
554     {  
555       mclk_extra = (bpp == 32) ? 31 : 42; /* Margin of error */
556       min_mclk_extra = 17;
557     }
558     else
559     {
560       mclk_extra = (bpp == 32) ? 8 : 4; /* Margin of error */
561       /* mclk_extra = 4; */ /* Margin of error */
562       min_mclk_extra = 18;
563     }
564
565     nvclks += 1; /* 2 edge sync.  may be very close to edge so just put one. */
566     nvclks += 1; /* fbi_d_rdv_n */
567     nvclks += 1; /* Fbi_d_rdata */
568     nvclks += 1; /* crtfifo load */
569
570     if(mp_enable)
571       mclks+=4; /* Mp can get in with a burst of 8. */
572     /* Extra clocks determined by heuristics */
573
574     nvclks += 0;
575     pclks += 0;
576     found = 0;
577     while(found != 1) {
578       fifo->valid = 1;
579       found = 1;
580       mclk_loop = mclks+mclk_extra;
581       us_m = mclk_loop *1000*1000 / mclk_freq; /* Mclk latency in us */
582       us_m_min = mclks * 1000*1000 / mclk_freq; /* Minimum Mclk latency in us */
583       us_min_mclk_extra = min_mclk_extra *1000*1000 / mclk_freq;
584       us_n = nvclks*1000*1000 / nvclk_freq;/* nvclk latency in us */
585       us_p = pclks*1000*1000 / pclk_freq;/* nvclk latency in us */
586       us_pipe_min = us_m_min + us_n + us_p;
587
588       vus_m = mclk_loop *1000*1000 / mclk_freq; /* Mclk latency in us */
589
590       if(video_enable) {
591         crtc_drain_rate = pclk_freq * bpp/8; /* MB/s */
592
593         vpagemiss = 1; /* self generating page miss */
594         vpagemiss += 1; /* One higher priority before */
595
596         crtpagemiss = 2; /* self generating page miss */
597         if(mp_enable)
598             crtpagemiss += 1; /* if MA0 conflict */
599
600         vpm_us = (vpagemiss * pagemiss)*1000*1000/mclk_freq;
601
602         us_video = vpm_us + vus_m; /* Video has separate read return path */
603
604         cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
605         us_crt =
606           us_video  /* Wait for video */
607           +cpm_us /* CRT Page miss */
608           +us_m + us_n +us_p /* other latency */
609           ;
610
611         clwm = us_crt * crtc_drain_rate/(1000*1000);
612         clwm++; /* fixed point <= float_point - 1.  Fixes that */
613       } else {
614         crtc_drain_rate = pclk_freq * bpp/8; /* bpp * pclk/8 */
615
616         crtpagemiss = 1; /* self generating page miss */
617         crtpagemiss += 1; /* MA0 page miss */
618         if(mp_enable)
619             crtpagemiss += 1; /* if MA0 conflict */
620         cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
621         us_crt =  cpm_us + us_m + us_n + us_p ;
622         clwm = us_crt * crtc_drain_rate/(1000*1000);
623         clwm++; /* fixed point <= float_point - 1.  Fixes that */
624
625           /* Finally, a heuristic check when width == 64 bits */
626           if(width == 1){
627               nvclk_fill = nvclk_freq * 8;
628               if(crtc_drain_rate * 100 >= nvclk_fill * 102)
629                       clwm = 0xfff; /*Large number to fail */
630
631               else if(crtc_drain_rate * 100  >= nvclk_fill * 98) {
632                   clwm = 1024;
633                   cbs = 512;
634               }
635           }
636       }
637
638
639       /*
640         Overfill check:
641
642         */
643
644       clwm_rnd_down = ((int)clwm/8)*8;
645       if (clwm_rnd_down < clwm)
646           clwm += 8;
647
648       m1 = clwm + cbs -  1024; /* Amount of overfill */
649       m2us = us_pipe_min + us_min_mclk_extra;
650
651       /* pclk cycles to drain */
652       p1clk = m2us * pclk_freq/(1000*1000); 
653       p2 = p1clk * bpp / 8; /* bytes drained. */
654
655       if((p2 < m1) && (m1 > 0)) {
656           fifo->valid = 0;
657           found = 0;
658           if(min_mclk_extra == 0)   {
659             if(cbs <= 32) {
660               found = 1; /* Can't adjust anymore! */
661             } else {
662               cbs = cbs/2;  /* reduce the burst size */
663             }
664           } else {
665             min_mclk_extra--;
666           }
667       } else {
668         if (clwm > 1023){ /* Have some margin */
669           fifo->valid = 0;
670           found = 0;
671           if(min_mclk_extra == 0)   
672               found = 1; /* Can't adjust anymore! */
673           else 
674               min_mclk_extra--;
675         }
676       }
677
678       if(clwm < (1024-cbs+8)) clwm = 1024-cbs+8;
679       data = (int)(clwm);
680       /*  printf("CRT LWM: %f bytes, prog: 0x%x, bs: 256\n", clwm, data ); */
681       fifo->graphics_lwm = data;   fifo->graphics_burst_size = cbs;
682
683       fifo->video_lwm = 1024;  fifo->video_burst_size = 512;
684     }
685 }
686
687 void nv10UpdateArbitrationSettings (
688     unsigned      VClk, 
689     unsigned      pixelDepth, 
690     unsigned     *burst,
691     unsigned     *lwm,
692     NVPtr        pNv
693 )
694 {
695     nv10_fifo_info fifo_data;
696     nv10_sim_state sim_data;
697     unsigned int MClk, NVClk, cfg1;
698
699     nvGetClocks(pNv, &MClk, &NVClk);
700
701     cfg1 = nvReadFB(pNv, NV_PFB_CFG1);
702     sim_data.pix_bpp        = (char)pixelDepth;
703     sim_data.enable_video   = 1;
704     sim_data.enable_mp      = 0;
705     sim_data.memory_type    = (nvReadFB(pNv, NV_PFB_CFG0) & 0x01) ? 1 : 0;
706     sim_data.memory_width   = (nvReadEXTDEV(pNv, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64;
707     sim_data.mem_latency    = (char)cfg1 & 0x0F;
708     sim_data.mem_aligned    = 1;
709     sim_data.mem_page_miss  = (char)(((cfg1>>4) &0x0F) + ((cfg1>>31) & 0x01));
710     sim_data.gr_during_vid  = 0;
711     sim_data.pclk_khz       = VClk;
712     sim_data.mclk_khz       = MClk;
713     sim_data.nvclk_khz      = NVClk;
714     nv10CalcArbitration(&fifo_data, &sim_data);
715     if (fifo_data.valid) {
716         int  b = fifo_data.graphics_burst_size >> 4;
717         *burst = 0;
718         while (b >>= 1) (*burst)++;
719         *lwm   = fifo_data.graphics_lwm >> 3;
720     }
721 }
722
723
724 void nv30UpdateArbitrationSettings (NVPtr pNv,
725                                     unsigned     *burst,
726                                     unsigned     *lwm)   
727 {
728     unsigned int MClk, NVClk;
729     unsigned int fifo_size, burst_size, graphics_lwm;
730
731     fifo_size = 2048;
732     burst_size = 512;
733     graphics_lwm = fifo_size - burst_size;
734
735     nvGetClocks(pNv, &MClk, &NVClk);
736     
737     *burst = 0;
738     burst_size >>= 5;
739     while(burst_size >>= 1) (*burst)++;
740     *lwm = graphics_lwm >> 3;
741 }
742
743 #ifdef XSERVER_LIBPCIACCESS
744
745 struct pci_device GetDeviceByPCITAG(uint32_t bus, uint32_t dev, uint32_t func)
746 {
747         const struct pci_slot_match match[] = { {0, bus, dev, func, 0} };
748         struct pci_device_iterator *iterator;
749         struct pci_device *device;
750         
751         /* assume one device to exist */
752         iterator = pci_slot_match_iterator_create(match);
753         device = pci_device_next(iterator);
754
755         return *device;
756 }
757
758 #endif /* XSERVER_LIBPCIACCESS */
759
760 void nForceUpdateArbitrationSettings (unsigned VClk,
761                                       unsigned      pixelDepth,
762                                       unsigned     *burst,
763                                       unsigned     *lwm,
764                                       NVPtr        pNv
765 )
766 {
767     nv10_fifo_info fifo_data;
768     nv10_sim_state sim_data;
769     unsigned int M, N, P, pll, MClk, NVClk, memctrl;
770
771 #ifdef XSERVER_LIBPCIACCESS
772         struct pci_device tmp;
773 #endif /* XSERVER_LIBPCIACCESS */
774
775     if((pNv->Chipset & 0x0FF0) == CHIPSET_NFORCE) {
776        unsigned int uMClkPostDiv;
777
778 #ifdef XSERVER_LIBPCIACCESS
779         tmp = GetDeviceByPCITAG(0, 0, 3);
780         PCI_DEV_READ_LONG(&tmp, 0x6C, &(uMClkPostDiv));
781         uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf;
782 #else
783         uMClkPostDiv = (pciReadLong(pciTag(0, 0, 3), 0x6C) >> 8) & 0xf;
784 #endif /* XSERVER_LIBPCIACCESS */
785        if(!uMClkPostDiv) uMClkPostDiv = 4; 
786        MClk = 400000 / uMClkPostDiv;
787     } else {
788 #ifdef XSERVER_LIBPCIACCESS
789         tmp = GetDeviceByPCITAG(0, 0, 5);
790         PCI_DEV_READ_LONG(&tmp, 0x4C, &(MClk));
791         MClk /= 1000;
792 #else
793         MClk = pciReadLong(pciTag(0, 0, 5), 0x4C) / 1000;
794 #endif /* XSERVER_LIBPCIACCESS */
795     }
796
797     pll = nvReadRAMDAC0(pNv, NV_RAMDAC_NVPLL);
798     M = (pll >> 0)  & 0xFF; N = (pll >> 8)  & 0xFF; P = (pll >> 16) & 0x0F;
799     NVClk  = (N * pNv->CrystalFreqKHz / M) >> P;
800     sim_data.pix_bpp        = (char)pixelDepth;
801     sim_data.enable_video   = 0;
802     sim_data.enable_mp      = 0;
803 #ifdef XSERVER_LIBPCIACCESS
804         tmp = GetDeviceByPCITAG(0, 0, 1);
805         PCI_DEV_READ_LONG(&tmp, 0x7C, &(sim_data.memory_type));
806         sim_data.memory_type = (sim_data.memory_type >> 12) & 1;
807 #else
808         sim_data.memory_type = (pciReadLong(pciTag(0, 0, 1), 0x7C) >> 12) & 1;
809 #endif /* XSERVER_LIBPCIACCESS */
810     sim_data.memory_width   = 64;
811
812 #ifdef XSERVER_LIBPCIACCESS
813         /* This offset is 0, is this even usefull? */
814         tmp = GetDeviceByPCITAG(0, 0, 3);
815         PCI_DEV_READ_LONG(&tmp, 0x00, &(memctrl));
816         memctrl >>= 16;
817 #else
818         memctrl = pciReadLong(pciTag(0, 0, 3), 0x00) >> 16;
819 #endif /* XSERVER_LIBPCIACCESS */
820
821     if((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) {
822         uint32_t dimm[3];
823 #ifdef XSERVER_LIBPCIACCESS
824         tmp = GetDeviceByPCITAG(0, 0, 2);
825         PCI_DEV_READ_LONG(&tmp, 0x40, &(dimm[0]));
826         PCI_DEV_READ_LONG(&tmp, 0x44, &(dimm[1]));
827         PCI_DEV_READ_LONG(&tmp, 0x48, &(dimm[2]));
828         int i;
829         for (i = 0; i < 3; i++) {
830                 dimm[i] = (dimm[i] >> 8) & 0x4F;
831         }
832 #else
833         dimm[0] = (pciReadLong(pciTag(0, 0, 2), 0x40) >> 8) & 0x4F;
834         dimm[1] = (pciReadLong(pciTag(0, 0, 2), 0x44) >> 8) & 0x4F;
835         dimm[2] = (pciReadLong(pciTag(0, 0, 2), 0x48) >> 8) & 0x4F;
836 #endif
837
838         if((dimm[0] + dimm[1]) != dimm[2]) {
839              ErrorF("WARNING: "
840               "your nForce DIMMs are not arranged in optimal banks!\n");
841         } 
842     }
843
844     sim_data.mem_latency    = 3;
845     sim_data.mem_aligned    = 1;
846     sim_data.mem_page_miss  = 10;
847     sim_data.gr_during_vid  = 0;
848     sim_data.pclk_khz       = VClk;
849     sim_data.mclk_khz       = MClk;
850     sim_data.nvclk_khz      = NVClk;
851     nv10CalcArbitration(&fifo_data, &sim_data);
852     if (fifo_data.valid)
853     {
854         int  b = fifo_data.graphics_burst_size >> 4;
855         *burst = 0;
856         while (b >>= 1) (*burst)++;
857         *lwm   = fifo_data.graphics_lwm >> 3;
858     }
859 }
860
861
862 /****************************************************************************\
863 *                                                                            *
864 *                          RIVA Mode State Routines                          *
865 *                                                                            *
866 \****************************************************************************/
867
868 /*
869  * Calculate the Video Clock parameters for the PLL.
870  */
871 static void CalcVClock (
872     int           clockIn,
873     int          *clockOut,
874     CARD32         *pllOut,
875     NVPtr        pNv
876 )
877 {
878     unsigned lowM, highM;
879     unsigned DeltaNew, DeltaOld;
880     unsigned VClk, Freq;
881     unsigned M, N, P;
882     
883     DeltaOld = 0xFFFFFFFF;
884
885     VClk = (unsigned)clockIn;
886     
887     if (pNv->CrystalFreqKHz == 13500) {
888         lowM  = 7;
889         highM = 13;
890     } else {
891         lowM  = 8;
892         highM = 14;
893     }
894
895     for (P = 0; P <= 4; P++) {
896         Freq = VClk << P;
897         if ((Freq >= 128000) && (Freq <= 350000)) {
898             for (M = lowM; M <= highM; M++) {
899                 N = ((VClk << P) * M) / pNv->CrystalFreqKHz;
900                 if(N <= 255) {
901                     Freq = ((pNv->CrystalFreqKHz * N) / M) >> P;
902                     if (Freq > VClk)
903                         DeltaNew = Freq - VClk;
904                     else
905                         DeltaNew = VClk - Freq;
906                     if (DeltaNew < DeltaOld) {
907                         *pllOut   = (P << 16) | (N << 8) | M;
908                         *clockOut = Freq;
909                         DeltaOld  = DeltaNew;
910                     }
911                 }
912             }
913         }
914     }
915 }
916
917 static void CalcVClock2Stage (
918     int           clockIn,
919     int          *clockOut,
920     CARD32         *pllOut,
921     CARD32         *pllBOut,
922     NVPtr        pNv
923 )
924 {
925     unsigned DeltaNew, DeltaOld;
926     unsigned VClk, Freq;
927     unsigned M, N, P;
928
929     DeltaOld = 0xFFFFFFFF;
930
931     *pllBOut = 0x80000401;  /* fixed at x4 for now */
932
933     VClk = (unsigned)clockIn;
934
935     for (P = 0; P <= 6; P++) {
936         Freq = VClk << P;
937         if ((Freq >= 400000) && (Freq <= 1000000)) {
938             for (M = 1; M <= 13; M++) {
939                 N = ((VClk << P) * M) / (pNv->CrystalFreqKHz << 2);
940                 if((N >= 5) && (N <= 255)) {
941                     Freq = (((pNv->CrystalFreqKHz << 2) * N) / M) >> P;
942                     if (Freq > VClk)
943                         DeltaNew = Freq - VClk;
944                     else
945                         DeltaNew = VClk - Freq;
946                     if (DeltaNew < DeltaOld) {
947                         *pllOut   = (P << 16) | (N << 8) | M;
948                         *clockOut = Freq;
949                         DeltaOld  = DeltaNew;
950                     }
951                 }
952             }
953         }
954     }
955 }
956
957 /*
958  * Calculate extended mode parameters (SVGA) and save in a 
959  * mode state structure.
960  */
961 void NVCalcStateExt (
962     NVPtr pNv,
963     RIVA_HW_STATE *state,
964     int            bpp,
965     int            width,
966     int            hDisplaySize,
967     int            height,
968     int            dotClock,
969     int            flags 
970 )
971 {
972     int pixelDepth, VClk = 0;
973         CARD32 CursorStart;
974
975     /*
976      * Save mode parameters.
977      */
978     state->bpp    = bpp;    /* this is not bitsPerPixel, it's 8,15,16,32 */
979     state->width  = width;
980     state->height = height;
981     /*
982      * Extended RIVA registers.
983      */
984     pixelDepth = (bpp + 1)/8;
985     if(pNv->twoStagePLL)
986         CalcVClock2Stage(dotClock, &VClk, &state->pll, &state->pllB, pNv);
987     else
988         CalcVClock(dotClock, &VClk, &state->pll, pNv);
989
990     switch (pNv->Architecture)
991     {
992         case NV_ARCH_04:
993             nv4UpdateArbitrationSettings(VClk, 
994                                          pixelDepth * 8, 
995                                         &(state->arbitration0),
996                                         &(state->arbitration1),
997                                          pNv);
998             state->cursor0  = 0x00;
999             state->cursor1  = 0xbC;
1000             if (flags & V_DBLSCAN)
1001                 state->cursor1 |= 2;
1002             state->cursor2  = 0x00000000;
1003             state->pllsel   = 0x10000700;
1004             state->config   = 0x00001114;
1005             state->general  = bpp == 16 ? 0x00101100 : 0x00100100;
1006             state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
1007             break;
1008         case NV_ARCH_10:
1009         case NV_ARCH_20:
1010         case NV_ARCH_30:
1011         default:
1012             if(((pNv->Chipset & 0xfff0) == CHIPSET_C51) ||
1013                ((pNv->Chipset & 0xfff0) == CHIPSET_C512))
1014             {
1015                 state->arbitration0 = 128; 
1016                 state->arbitration1 = 0x0480; 
1017             } else
1018             if(((pNv->Chipset & 0xffff) == CHIPSET_NFORCE) ||
1019                ((pNv->Chipset & 0xffff) == CHIPSET_NFORCE2))
1020             {
1021                 nForceUpdateArbitrationSettings(VClk,
1022                                           pixelDepth * 8,
1023                                          &(state->arbitration0),
1024                                          &(state->arbitration1),
1025                                           pNv);
1026             } else if(pNv->Architecture < NV_ARCH_30) {
1027                 nv10UpdateArbitrationSettings(VClk, 
1028                                           pixelDepth * 8, 
1029                                          &(state->arbitration0),
1030                                          &(state->arbitration1),
1031                                           pNv);
1032             } else {
1033                 nv30UpdateArbitrationSettings(pNv,
1034                                          &(state->arbitration0),
1035                                          &(state->arbitration1));
1036             }
1037             CursorStart = pNv->Cursor->offset;
1038             state->cursor0  = 0x80 | (CursorStart >> 17);
1039             state->cursor1  = (CursorStart >> 11) << 2;
1040             state->cursor2  = CursorStart >> 24;
1041             if (flags & V_DBLSCAN) 
1042                 state->cursor1 |= 2;
1043             state->pllsel   = 0x10000700;
1044             state->config   = nvReadFB(pNv, NV_PFB_CFG0);
1045             state->general  = bpp == 16 ? 0x00101100 : 0x00100100;
1046             state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
1047             break;
1048     }
1049
1050     if(bpp != 8) /* DirectColor */
1051         state->general |= 0x00000030;
1052
1053     state->repaint0 = (((width / 8) * pixelDepth) & 0x700) >> 3;
1054     state->pixel    = (pixelDepth > 2) ? 3 : pixelDepth;
1055 }
1056
1057
1058 void NVLoadStateExt (
1059     ScrnInfoPtr pScrn,
1060     RIVA_HW_STATE *state
1061 )
1062 {
1063     NVPtr pNv = NVPTR(pScrn);
1064     CARD32 temp;
1065
1066     if(pNv->Architecture >= NV_ARCH_40) {
1067         switch(pNv->Chipset & 0xfff0) {
1068         case CHIPSET_NV44:
1069         case CHIPSET_NV44A:
1070         case CHIPSET_C51:
1071         case CHIPSET_G70:
1072         case CHIPSET_G71:
1073         case CHIPSET_G72:
1074         case CHIPSET_G73:
1075         case CHIPSET_C512:
1076              temp = nvReadCurRAMDAC(pNv, NV_RAMDAC_TEST_CONTROL);
1077              nvWriteCurRAMDAC(pNv, NV_RAMDAC_TEST_CONTROL, temp | 0x00100000);
1078              break;
1079         default:
1080              break;
1081         };
1082     }
1083
1084     if(pNv->Architecture >= NV_ARCH_10) {
1085         if(pNv->twoHeads) {
1086            nvWriteCRTC(pNv, 0, NV_CRTC_FSEL, state->head);
1087            nvWriteCRTC(pNv, 1, NV_CRTC_FSEL, state->head2);
1088         }
1089         temp = nvReadCurRAMDAC(pNv, NV_RAMDAC_NV10_CURSYNC);
1090         nvWriteCurRAMDAC(pNv, NV_RAMDAC_NV10_CURSYNC, temp | (1 << 25));
1091     
1092         nvWriteVIDEO(pNv, NV_PVIDEO_STOP, 1);
1093         nvWriteVIDEO(pNv, NV_PVIDEO_INTR_EN, 0);
1094         nvWriteVIDEO(pNv, NV_PVIDEO_OFFSET_BUFF(0), 0);
1095         nvWriteVIDEO(pNv, NV_PVIDEO_OFFSET_BUFF(1), 0);
1096         nvWriteVIDEO(pNv, NV_PVIDEO_LIMIT(0), pNv->VRAMPhysicalSize - 1);
1097         nvWriteVIDEO(pNv, NV_PVIDEO_LIMIT(1), pNv->VRAMPhysicalSize - 1);
1098         nvWriteVIDEO(pNv, NV_PVIDEO_UVPLANE_LIMIT(0), pNv->VRAMPhysicalSize - 1);
1099         nvWriteVIDEO(pNv, NV_PVIDEO_UVPLANE_LIMIT(1), pNv->VRAMPhysicalSize - 1);
1100         nvWriteMC(pNv, 0x1588, 0);
1101
1102         nvWriteCurCRTC(pNv, NV_CRTC_CURSOR_CONFIG, state->cursorConfig);
1103         nvWriteCurCRTC(pNv, NV_CRTC_0830, state->displayV - 3);
1104         nvWriteCurCRTC(pNv, NV_CRTC_0834, state->displayV - 1);
1105     
1106         if(pNv->FlatPanel) {
1107            if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
1108                nvWriteCurRAMDAC(pNv, NV_RAMDAC_DITHER_NV11, state->dither);
1109            } else 
1110            if(pNv->twoHeads) {
1111                nvWriteCurRAMDAC(pNv, NV_RAMDAC_FP_DITHER, state->dither);
1112            }
1113     
1114            nvWriteVGA(pNv, NV_VGA_CRTCX_FP_HTIMING, state->timingH);
1115            nvWriteVGA(pNv, NV_VGA_CRTCX_FP_VTIMING, state->timingV);
1116            nvWriteVGA(pNv, NV_VGA_CRTCX_BUFFER, 0xfa);
1117         }
1118
1119         nvWriteVGA(pNv, NV_VGA_CRTCX_EXTRA, state->extra);
1120     }
1121
1122     nvWriteVGA(pNv, NV_VGA_CRTCX_REPAINT0, state->repaint0);
1123     nvWriteVGA(pNv, NV_VGA_CRTCX_REPAINT1, state->repaint1);
1124     nvWriteVGA(pNv, NV_VGA_CRTCX_LSR, state->screen);
1125     nvWriteVGA(pNv, NV_VGA_CRTCX_PIXEL, state->pixel);
1126     nvWriteVGA(pNv, NV_VGA_CRTCX_HEB, state->horiz);
1127     nvWriteVGA(pNv, NV_VGA_CRTCX_FIFO1, state->fifo);
1128     nvWriteVGA(pNv, NV_VGA_CRTCX_FIFO0, state->arbitration0);
1129     nvWriteVGA(pNv, NV_VGA_CRTCX_FIFO_LWM, state->arbitration1);
1130     if(pNv->Architecture >= NV_ARCH_30) {
1131       nvWriteVGA(pNv, NV_VGA_CRTCX_FIFO_LWM_NV30, state->arbitration1 >> 8);
1132     }
1133
1134     nvWriteVGA(pNv, NV_VGA_CRTCX_CURCTL0, state->cursor0);
1135     nvWriteVGA(pNv, NV_VGA_CRTCX_CURCTL1, state->cursor1);
1136     if(pNv->Architecture == NV_ARCH_40) {  /* HW bug */
1137        volatile CARD32 curpos = nvReadCurRAMDAC(pNv, NV_RAMDAC_CURSOR_POS);
1138        nvWriteCurRAMDAC(pNv, NV_RAMDAC_CURSOR_POS, curpos);
1139     }
1140     nvWriteVGA(pNv, NV_VGA_CRTCX_CURCTL2, state->cursor2);
1141     nvWriteVGA(pNv, NV_VGA_CRTCX_INTERLACE, state->interlace);
1142
1143     if(!pNv->FlatPanel) {
1144        nvWriteRAMDAC0(pNv, NV_RAMDAC_PLL_SELECT, state->pllsel);
1145        nvWriteRAMDAC0(pNv, NV_RAMDAC_VPLL, state->vpll);
1146        if(pNv->twoHeads)
1147           nvWriteRAMDAC0(pNv, NV_RAMDAC_VPLL2, state->vpll2);
1148        if(pNv->twoStagePLL) {
1149           nvWriteRAMDAC0(pNv, NV_RAMDAC_VPLL_B, state->vpllB);
1150           nvWriteRAMDAC0(pNv, NV_RAMDAC_VPLL2_B, state->vpll2B);
1151        }
1152     } else {
1153        nvWriteCurRAMDAC(pNv, NV_RAMDAC_FP_CONTROL, state->scale);
1154        nvWriteCurRAMDAC(pNv, NV_RAMDAC_FP_HCRTC, state->crtcSync);
1155     }
1156     nvWriteCurRAMDAC(pNv, NV_RAMDAC_GENERAL_CONTROL, state->general);
1157
1158     nvWriteCurCRTC(pNv, NV_CRTC_INTR_EN_0, 0);
1159     nvWriteCurCRTC(pNv, NV_CRTC_INTR_0, NV_CRTC_INTR_VBLANK);
1160
1161     pNv->CurrentState = state;
1162 }
1163
1164 void NVUnloadStateExt
1165 (
1166     NVPtr pNv,
1167     RIVA_HW_STATE *state
1168 )
1169 {
1170     state->repaint0     = nvReadVGA(pNv, NV_VGA_CRTCX_REPAINT0);
1171     state->repaint1     = nvReadVGA(pNv, NV_VGA_CRTCX_REPAINT1);
1172     state->screen       = nvReadVGA(pNv, NV_VGA_CRTCX_LSR);
1173     state->pixel        = nvReadVGA(pNv, NV_VGA_CRTCX_PIXEL);
1174     state->horiz        = nvReadVGA(pNv, NV_VGA_CRTCX_HEB);
1175     state->fifo         = nvReadVGA(pNv, NV_VGA_CRTCX_FIFO1);
1176     state->arbitration0 = nvReadVGA(pNv, NV_VGA_CRTCX_FIFO0);
1177     state->arbitration1 = nvReadVGA(pNv, NV_VGA_CRTCX_FIFO_LWM);
1178     if(pNv->Architecture >= NV_ARCH_30) {
1179        state->arbitration1 |= (nvReadVGA(pNv, NV_VGA_CRTCX_FIFO_LWM_NV30) & 1) << 8;
1180     }
1181     state->cursor0      = nvReadVGA(pNv, NV_VGA_CRTCX_CURCTL0);
1182     state->cursor1      = nvReadVGA(pNv, NV_VGA_CRTCX_CURCTL1);
1183     state->cursor2      = nvReadVGA(pNv, NV_VGA_CRTCX_CURCTL2);
1184     state->interlace    = nvReadVGA(pNv, NV_VGA_CRTCX_INTERLACE);
1185
1186     state->vpll         = nvReadRAMDAC0(pNv, NV_RAMDAC_VPLL);
1187     if(pNv->twoHeads)
1188        state->vpll2     = nvReadRAMDAC0(pNv, NV_RAMDAC_VPLL2);
1189     if(pNv->twoStagePLL) {
1190         state->vpllB    = nvReadRAMDAC0(pNv, NV_RAMDAC_VPLL_B);
1191         state->vpll2B   = nvReadRAMDAC0(pNv, NV_RAMDAC_VPLL2_B);
1192     }
1193     state->pllsel       = nvReadRAMDAC0(pNv, NV_RAMDAC_PLL_SELECT);
1194     state->general      = nvReadCurRAMDAC(pNv, NV_RAMDAC_GENERAL_CONTROL);
1195     state->scale        = nvReadCurRAMDAC(pNv, NV_RAMDAC_FP_CONTROL);
1196     state->config       = nvReadFB(pNv, NV_PFB_CFG0);
1197
1198     if(pNv->Architecture >= NV_ARCH_10) {
1199         if(pNv->twoHeads) {
1200            state->head     = nvReadCRTC(pNv, 0, NV_CRTC_FSEL);
1201            state->head2    = nvReadCRTC(pNv, 1, NV_CRTC_FSEL);
1202            state->crtcOwner = nvReadVGA(pNv, NV_VGA_CRTCX_OWNER);
1203         }
1204         state->extra = nvReadVGA(pNv, NV_VGA_CRTCX_EXTRA);
1205
1206         state->cursorConfig = nvReadCurCRTC(pNv, NV_CRTC_CURSOR_CONFIG);
1207
1208         if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
1209            state->dither = nvReadCurRAMDAC(pNv, NV_RAMDAC_DITHER_NV11);
1210         } else 
1211         if(pNv->twoHeads) {
1212             state->dither = nvReadCurRAMDAC(pNv, NV_RAMDAC_FP_DITHER);
1213         }
1214
1215         if(pNv->FlatPanel) {
1216            state->timingH = nvReadVGA(pNv, NV_VGA_CRTCX_FP_HTIMING);
1217            state->timingV = nvReadVGA(pNv, NV_VGA_CRTCX_FP_VTIMING);
1218         }
1219     }
1220
1221     if(pNv->FlatPanel) {
1222        state->crtcSync = nvReadCurRAMDAC(pNv, NV_RAMDAC_FP_HCRTC);
1223     }
1224 }
1225
1226 void NVSetStartAddress (
1227     NVPtr   pNv,
1228     CARD32 start
1229 )
1230 {
1231     nvWriteCurCRTC(pNv, NV_CRTC_START, start);
1232 }
1233
1234