add RAMDAC register read/write
[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_local.h"
42 #include "compiler.h"
43 #include "nv_include.h"
44
45 uint8_t nvReadVGA(NVPtr pNv, uint8_t index)
46 {
47   volatile const uint8_t *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
48   VGA_WR08(ptr, 0x03D4, index);
49   return VGA_RD08(ptr, 0x03D5);
50 }
51
52 void nvWriteVGA(NVPtr pNv, uint8_t index, uint8_t data)
53 {
54   volatile const uint8_t *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
55   VGA_WR08(ptr, 0x03D4, index);
56   VGA_WR08(ptr, 0x03D5, data);
57 }
58
59 CARD32 nvReadRAMDAC(NVPtr pNv, uint8_t head, uint32_t ramdac_reg)
60 {
61   volatile const void *ptr = head ? pNv->PRAMDAC1 : pNv->PRAMDAC0;
62   return MMIO_IN32(ptr, ramdac_reg);
63 }
64
65 void nvWriteRAMDAC(NVPtr pNv, uint8_t head, uint32_t ramdac_reg, CARD32 val)
66 {
67   volatile const void *ptr = head ? pNv->PRAMDAC1 : pNv->PRAMDAC0;
68   MMIO_OUT32(ptr, ramdac_reg, val);
69 }
70
71 #define nvReadRAMDAC0(pNv, reg) nvReadRAMDAC(pNv, 0, reg)
72 #define nvWriteRAMDAC0(pNv, reg, val) nvWriteRAMDAC(pNv, 0, reg, val)
73
74 #define nvReadCurRAMDAC(pNv, reg) nvReadRAMDAC(pNv, pNv->cur_head, reg)
75
76 #define nvWriteCurRAMDAC(pNv, reg, val) nvWriteRAMDAC(pNv, pNv->cur_head, reg, val)
77
78 void NVLockUnlock (
79     NVPtr pNv,
80     Bool  Lock
81 )
82 {
83     CARD8 cr11;
84
85     nvWriteVGA(pNv, 0x1f, Lock ? 0x99 : 0x57 );
86
87     cr11 = nvReadVGA(pNv, 0x11);
88     if(Lock) cr11 |= 0x80;
89     else cr11 &= ~0x80;
90     nvWriteVGA(pNv, 0x11, cr11);
91 }
92
93 int NVShowHideCursor (
94     NVPtr pNv,
95     int   ShowHide
96 )
97 {
98     int current = pNv->CurrentState->cursor1;
99
100     pNv->CurrentState->cursor1 = (pNv->CurrentState->cursor1 & 0xFE) |
101                                  (ShowHide & 0x01);
102
103     nvWriteVGA(pNv, 0x31, pNv->CurrentState->cursor1);
104
105     if(pNv->Architecture == NV_ARCH_40) {  /* HW bug */
106        volatile CARD32 curpos = nvReadCurRAMDAC(pNv, 0x300);
107        nvWriteCurRAMDAC(pNv, 0x0300, curpos);
108     }
109
110     return (current & 0x01);
111 }
112
113 /****************************************************************************\
114 *                                                                            *
115 * The video arbitration routines calculate some "magic" numbers.  Fixes      *
116 * the snow seen when accessing the framebuffer without it.                   *
117 * It just works (I hope).                                                    *
118 *                                                                            *
119 \****************************************************************************/
120
121 typedef struct {
122   int graphics_lwm;
123   int video_lwm;
124   int graphics_burst_size;
125   int video_burst_size;
126   int valid;
127 } nv4_fifo_info;
128
129 typedef struct {
130   int pclk_khz;
131   int mclk_khz;
132   int nvclk_khz;
133   char mem_page_miss;
134   char mem_latency;
135   int memory_width;
136   char enable_video;
137   char gr_during_vid;
138   char pix_bpp;
139   char mem_aligned;
140   char enable_mp;
141 } nv4_sim_state;
142
143 typedef struct {
144   int graphics_lwm;
145   int video_lwm;
146   int graphics_burst_size;
147   int video_burst_size;
148   int valid;
149 } nv10_fifo_info;
150
151 typedef struct {
152   int pclk_khz;
153   int mclk_khz;
154   int nvclk_khz;
155   char mem_page_miss;
156   char mem_latency;
157   int memory_type;
158   int memory_width;
159   char enable_video;
160   char gr_during_vid;
161   char pix_bpp;
162   char mem_aligned;
163   char enable_mp;
164 } nv10_sim_state;
165
166
167 static void nvGetClocks(NVPtr pNv, unsigned int *MClk, unsigned int *NVClk)
168 {
169     unsigned int pll, N, M, MB, NB, P;
170
171     if(pNv->Architecture >= NV_ARCH_40) {
172        pll = pNv->PMC[0x4020/4];
173        P = (pll >> 16) & 0x07;
174        pll = pNv->PMC[0x4024/4];
175        M = pll & 0xFF;
176        N = (pll >> 8) & 0xFF;
177        if(((pNv->Chipset & 0xfff0) == CHIPSET_G71) ||
178           ((pNv->Chipset & 0xfff0) == CHIPSET_G73))
179        {
180           MB = 1;
181           NB = 1;
182        } else {
183           MB = (pll >> 16) & 0xFF;
184           NB = (pll >> 24) & 0xFF;
185        }
186        *MClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P;
187
188        pll = pNv->PMC[0x4000/4];
189        P = (pll >> 16) & 0x07;  
190        pll = pNv->PMC[0x4004/4];
191        M = pll & 0xFF;
192        N = (pll >> 8) & 0xFF;
193        MB = (pll >> 16) & 0xFF;
194        NB = (pll >> 24) & 0xFF;
195
196        *NVClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P;
197     } else
198     if(pNv->twoStagePLL) {
199        pll = nvReadRAMDAC0(pNv, 0x0504);
200        M = pll & 0xFF; 
201        N = (pll >> 8) & 0xFF; 
202        P = (pll >> 16) & 0x0F;
203        pll = nvReadRAMDAC0(pNv, 0x0574);
204        if(pll & 0x80000000) {
205            MB = pll & 0xFF; 
206            NB = (pll >> 8) & 0xFF;
207        } else {
208            MB = 1;
209            NB = 1;
210        }
211        *MClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P;
212
213        pll = nvReadRAMDAC0(pNv, 0x0500);
214        M = pll & 0xFF; 
215        N = (pll >> 8) & 0xFF; 
216        P = (pll >> 16) & 0x0F;
217        pll = nvReadRAMDAC0(pNv, 0x0570);
218        if(pll & 0x80000000) {
219            MB = pll & 0xFF;
220            NB = (pll >> 8) & 0xFF;
221        } else {
222            MB = 1;
223            NB = 1;
224        }
225        *NVClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P;
226     } else 
227     if(((pNv->Chipset & 0x0ff0) == CHIPSET_NV30) ||
228        ((pNv->Chipset & 0x0ff0) == CHIPSET_NV35))
229     {
230        pll = nvReadRAMDAC0(pNv, 0x504);
231        M = pll & 0x0F; 
232        N = (pll >> 8) & 0xFF;
233        P = (pll >> 16) & 0x07;
234        if(pll & 0x00000080) {
235            MB = (pll >> 4) & 0x07;     
236            NB = (pll >> 19) & 0x1f;
237        } else {
238            MB = 1;
239            NB = 1;
240        }
241        *MClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P;
242
243        pll = nvReadRAMDAC0(pNv, 0x500);
244        M = pll & 0x0F;
245        N = (pll >> 8) & 0xFF;
246        P = (pll >> 16) & 0x07;
247        if(pll & 0x00000080) {
248            MB = (pll >> 4) & 0x07;
249            NB = (pll >> 19) & 0x1f;
250        } else {
251            MB = 1;
252            NB = 1;
253        }
254        *NVClk = ((N * NB * pNv->CrystalFreqKHz) / (M * MB)) >> P;
255     } else {
256        pll = nvReadRAMDAC0(pNv, 0x504);
257        M = pll & 0xFF; 
258        N = (pll >> 8) & 0xFF; 
259        P = (pll >> 16) & 0x0F;
260        *MClk = (N * pNv->CrystalFreqKHz / M) >> P;
261
262        pll = nvReadRAMDAC0(pNv, 0x500);
263        M = pll & 0xFF; 
264        N = (pll >> 8) & 0xFF; 
265        P = (pll >> 16) & 0x0F;
266        *NVClk = (N * pNv->CrystalFreqKHz / M) >> P;
267     }
268
269 #if 0
270     ErrorF("NVClock = %i MHz, MEMClock = %i MHz\n", *NVClk/1000, *MClk/1000);
271 #endif
272 }
273
274
275 static void nv4CalcArbitration (
276     nv4_fifo_info *fifo,
277     nv4_sim_state *arb
278 )
279 {
280     int data, pagemiss, cas,width, video_enable, bpp;
281     int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs;
282     int found, mclk_extra, mclk_loop, cbs, m1, p1;
283     int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
284     int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate;
285     int vpm_us, us_video, vlwm, video_fill_us, cpm_us, us_crt,clwm;
286
287     fifo->valid = 1;
288     pclk_freq = arb->pclk_khz;
289     mclk_freq = arb->mclk_khz;
290     nvclk_freq = arb->nvclk_khz;
291     pagemiss = arb->mem_page_miss;
292     cas = arb->mem_latency;
293     width = arb->memory_width >> 6;
294     video_enable = arb->enable_video;
295     bpp = arb->pix_bpp;
296     mp_enable = arb->enable_mp;
297     clwm = 0;
298     vlwm = 0;
299     cbs = 128;
300     pclks = 2;
301     nvclks = 2;
302     nvclks += 2;
303     nvclks += 1;
304     mclks = 5;
305     mclks += 3;
306     mclks += 1;
307     mclks += cas;
308     mclks += 1;
309     mclks += 1;
310     mclks += 1;
311     mclks += 1;
312     mclk_extra = 3;
313     nvclks += 2;
314     nvclks += 1;
315     nvclks += 1;
316     nvclks += 1;
317     if (mp_enable)
318         mclks+=4;
319     nvclks += 0;
320     pclks += 0;
321     found = 0;
322     vbs = 0;
323     while (found != 1)
324     {
325         fifo->valid = 1;
326         found = 1;
327         mclk_loop = mclks+mclk_extra;
328         us_m = mclk_loop *1000*1000 / mclk_freq;
329         us_n = nvclks*1000*1000 / nvclk_freq;
330         us_p = nvclks*1000*1000 / pclk_freq;
331         if (video_enable)
332         {
333             video_drain_rate = pclk_freq * 2;
334             crtc_drain_rate = pclk_freq * bpp/8;
335             vpagemiss = 2;
336             vpagemiss += 1;
337             crtpagemiss = 2;
338             vpm_us = (vpagemiss * pagemiss)*1000*1000/mclk_freq;
339             if (nvclk_freq * 2 > mclk_freq * width)
340                 video_fill_us = cbs*1000*1000 / 16 / nvclk_freq ;
341             else
342                 video_fill_us = cbs*1000*1000 / (8 * width) / mclk_freq;
343             us_video = vpm_us + us_m + us_n + us_p + video_fill_us;
344             vlwm = us_video * video_drain_rate/(1000*1000);
345             vlwm++;
346             vbs = 128;
347             if (vlwm > 128) vbs = 64;
348             if (vlwm > (256-64)) vbs = 32;
349             if (nvclk_freq * 2 > mclk_freq * width)
350                 video_fill_us = vbs *1000*1000/ 16 / nvclk_freq ;
351             else
352                 video_fill_us = vbs*1000*1000 / (8 * width) / mclk_freq;
353             cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
354             us_crt =
355             us_video
356             +video_fill_us
357             +cpm_us
358             +us_m + us_n +us_p
359             ;
360             clwm = us_crt * crtc_drain_rate/(1000*1000);
361             clwm++;
362         }
363         else
364         {
365             crtc_drain_rate = pclk_freq * bpp/8;
366             crtpagemiss = 2;
367             crtpagemiss += 1;
368             cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
369             us_crt =  cpm_us + us_m + us_n + us_p ;
370             clwm = us_crt * crtc_drain_rate/(1000*1000);
371             clwm++;
372         }
373         m1 = clwm + cbs - 512;
374         p1 = m1 * pclk_freq / mclk_freq;
375         p1 = p1 * bpp / 8;
376         if ((p1 < m1) && (m1 > 0))
377         {
378             fifo->valid = 0;
379             found = 0;
380             if (mclk_extra ==0)   found = 1;
381             mclk_extra--;
382         }
383         else if (video_enable)
384         {
385             if ((clwm > 511) || (vlwm > 255))
386             {
387                 fifo->valid = 0;
388                 found = 0;
389                 if (mclk_extra ==0)   found = 1;
390                 mclk_extra--;
391             }
392         }
393         else
394         {
395             if (clwm > 519)
396             {
397                 fifo->valid = 0;
398                 found = 0;
399                 if (mclk_extra ==0)   found = 1;
400                 mclk_extra--;
401             }
402         }
403         if (clwm < 384) clwm = 384;
404         if (vlwm < 128) vlwm = 128;
405         data = (int)(clwm);
406         fifo->graphics_lwm = data;
407         fifo->graphics_burst_size = 128;
408         data = (int)((vlwm+15));
409         fifo->video_lwm = data;
410         fifo->video_burst_size = vbs;
411     }
412 }
413
414 static void nv4UpdateArbitrationSettings (
415     unsigned      VClk, 
416     unsigned      pixelDepth, 
417     unsigned     *burst,
418     unsigned     *lwm,
419     NVPtr        pNv
420 )
421 {
422     nv4_fifo_info fifo_data;
423     nv4_sim_state sim_data;
424     unsigned int MClk, NVClk, cfg1;
425
426     nvGetClocks(pNv, &MClk, &NVClk);
427
428     cfg1 = pNv->PFB[0x00000204/4];
429     sim_data.pix_bpp        = (char)pixelDepth;
430     sim_data.enable_video   = 0;
431     sim_data.enable_mp      = 0;
432     sim_data.memory_width   = (pNv->PEXTDEV[0x0000/4] & 0x10) ? 128 : 64;
433     sim_data.mem_latency    = (char)cfg1 & 0x0F;
434     sim_data.mem_aligned    = 1;
435     sim_data.mem_page_miss  = (char)(((cfg1 >> 4) &0x0F) + ((cfg1 >> 31) & 0x01));
436     sim_data.gr_during_vid  = 0;
437     sim_data.pclk_khz       = VClk;
438     sim_data.mclk_khz       = MClk;
439     sim_data.nvclk_khz      = NVClk;
440     nv4CalcArbitration(&fifo_data, &sim_data);
441     if (fifo_data.valid)
442     {
443         int  b = fifo_data.graphics_burst_size >> 4;
444         *burst = 0;
445         while (b >>= 1) (*burst)++;
446         *lwm   = fifo_data.graphics_lwm >> 3;
447     }
448 }
449
450 static void nv10CalcArbitration (
451     nv10_fifo_info *fifo,
452     nv10_sim_state *arb
453 )
454 {
455     int data, pagemiss, width, video_enable, bpp;
456     int nvclks, mclks, pclks, vpagemiss, crtpagemiss;
457     int nvclk_fill;
458     int found, mclk_extra, mclk_loop, cbs, m1;
459     int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
460     int us_m, us_m_min, us_n, us_p, crtc_drain_rate;
461     int vus_m;
462     int vpm_us, us_video, cpm_us, us_crt,clwm;
463     int clwm_rnd_down;
464     int m2us, us_pipe_min, p1clk, p2;
465     int min_mclk_extra;
466     int us_min_mclk_extra;
467
468     fifo->valid = 1;
469     pclk_freq = arb->pclk_khz; /* freq in KHz */
470     mclk_freq = arb->mclk_khz;
471     nvclk_freq = arb->nvclk_khz;
472     pagemiss = arb->mem_page_miss;
473     width = arb->memory_width/64;
474     video_enable = arb->enable_video;
475     bpp = arb->pix_bpp;
476     mp_enable = arb->enable_mp;
477     clwm = 0;
478
479     cbs = 512;
480
481     pclks = 4; /* lwm detect. */
482
483     nvclks = 3; /* lwm -> sync. */
484     nvclks += 2; /* fbi bus cycles (1 req + 1 busy) */
485
486     mclks  = 1;   /* 2 edge sync.  may be very close to edge so just put one. */
487
488     mclks += 1;   /* arb_hp_req */
489     mclks += 5;   /* ap_hp_req   tiling pipeline */
490
491     mclks += 2;    /* tc_req     latency fifo */
492     mclks += 2;    /* fb_cas_n_  memory request to fbio block */
493     mclks += 7;    /* sm_d_rdv   data returned from fbio block */
494
495     /* fb.rd.d.Put_gc   need to accumulate 256 bits for read */
496     if (arb->memory_type == 0)
497       if (arb->memory_width == 64) /* 64 bit bus */
498         mclks += 4;
499       else
500         mclks += 2;
501     else
502       if (arb->memory_width == 64) /* 64 bit bus */
503         mclks += 2;
504       else
505         mclks += 1;
506
507     if ((!video_enable) && (arb->memory_width == 128))
508     {  
509       mclk_extra = (bpp == 32) ? 31 : 42; /* Margin of error */
510       min_mclk_extra = 17;
511     }
512     else
513     {
514       mclk_extra = (bpp == 32) ? 8 : 4; /* Margin of error */
515       /* mclk_extra = 4; */ /* Margin of error */
516       min_mclk_extra = 18;
517     }
518
519     nvclks += 1; /* 2 edge sync.  may be very close to edge so just put one. */
520     nvclks += 1; /* fbi_d_rdv_n */
521     nvclks += 1; /* Fbi_d_rdata */
522     nvclks += 1; /* crtfifo load */
523
524     if(mp_enable)
525       mclks+=4; /* Mp can get in with a burst of 8. */
526     /* Extra clocks determined by heuristics */
527
528     nvclks += 0;
529     pclks += 0;
530     found = 0;
531     while(found != 1) {
532       fifo->valid = 1;
533       found = 1;
534       mclk_loop = mclks+mclk_extra;
535       us_m = mclk_loop *1000*1000 / mclk_freq; /* Mclk latency in us */
536       us_m_min = mclks * 1000*1000 / mclk_freq; /* Minimum Mclk latency in us */
537       us_min_mclk_extra = min_mclk_extra *1000*1000 / mclk_freq;
538       us_n = nvclks*1000*1000 / nvclk_freq;/* nvclk latency in us */
539       us_p = pclks*1000*1000 / pclk_freq;/* nvclk latency in us */
540       us_pipe_min = us_m_min + us_n + us_p;
541
542       vus_m = mclk_loop *1000*1000 / mclk_freq; /* Mclk latency in us */
543
544       if(video_enable) {
545         crtc_drain_rate = pclk_freq * bpp/8; /* MB/s */
546
547         vpagemiss = 1; /* self generating page miss */
548         vpagemiss += 1; /* One higher priority before */
549
550         crtpagemiss = 2; /* self generating page miss */
551         if(mp_enable)
552             crtpagemiss += 1; /* if MA0 conflict */
553
554         vpm_us = (vpagemiss * pagemiss)*1000*1000/mclk_freq;
555
556         us_video = vpm_us + vus_m; /* Video has separate read return path */
557
558         cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
559         us_crt =
560           us_video  /* Wait for video */
561           +cpm_us /* CRT Page miss */
562           +us_m + us_n +us_p /* other latency */
563           ;
564
565         clwm = us_crt * crtc_drain_rate/(1000*1000);
566         clwm++; /* fixed point <= float_point - 1.  Fixes that */
567       } else {
568         crtc_drain_rate = pclk_freq * bpp/8; /* bpp * pclk/8 */
569
570         crtpagemiss = 1; /* self generating page miss */
571         crtpagemiss += 1; /* MA0 page miss */
572         if(mp_enable)
573             crtpagemiss += 1; /* if MA0 conflict */
574         cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
575         us_crt =  cpm_us + us_m + us_n + us_p ;
576         clwm = us_crt * crtc_drain_rate/(1000*1000);
577         clwm++; /* fixed point <= float_point - 1.  Fixes that */
578
579           /* Finally, a heuristic check when width == 64 bits */
580           if(width == 1){
581               nvclk_fill = nvclk_freq * 8;
582               if(crtc_drain_rate * 100 >= nvclk_fill * 102)
583                       clwm = 0xfff; /*Large number to fail */
584
585               else if(crtc_drain_rate * 100  >= nvclk_fill * 98) {
586                   clwm = 1024;
587                   cbs = 512;
588               }
589           }
590       }
591
592
593       /*
594         Overfill check:
595
596         */
597
598       clwm_rnd_down = ((int)clwm/8)*8;
599       if (clwm_rnd_down < clwm)
600           clwm += 8;
601
602       m1 = clwm + cbs -  1024; /* Amount of overfill */
603       m2us = us_pipe_min + us_min_mclk_extra;
604
605       /* pclk cycles to drain */
606       p1clk = m2us * pclk_freq/(1000*1000); 
607       p2 = p1clk * bpp / 8; /* bytes drained. */
608
609       if((p2 < m1) && (m1 > 0)) {
610           fifo->valid = 0;
611           found = 0;
612           if(min_mclk_extra == 0)   {
613             if(cbs <= 32) {
614               found = 1; /* Can't adjust anymore! */
615             } else {
616               cbs = cbs/2;  /* reduce the burst size */
617             }
618           } else {
619             min_mclk_extra--;
620           }
621       } else {
622         if (clwm > 1023){ /* Have some margin */
623           fifo->valid = 0;
624           found = 0;
625           if(min_mclk_extra == 0)   
626               found = 1; /* Can't adjust anymore! */
627           else 
628               min_mclk_extra--;
629         }
630       }
631
632       if(clwm < (1024-cbs+8)) clwm = 1024-cbs+8;
633       data = (int)(clwm);
634       /*  printf("CRT LWM: %f bytes, prog: 0x%x, bs: 256\n", clwm, data ); */
635       fifo->graphics_lwm = data;   fifo->graphics_burst_size = cbs;
636
637       fifo->video_lwm = 1024;  fifo->video_burst_size = 512;
638     }
639 }
640
641 static void nv10UpdateArbitrationSettings (
642     unsigned      VClk, 
643     unsigned      pixelDepth, 
644     unsigned     *burst,
645     unsigned     *lwm,
646     NVPtr        pNv
647 )
648 {
649     nv10_fifo_info fifo_data;
650     nv10_sim_state sim_data;
651     unsigned int MClk, NVClk, cfg1;
652
653     nvGetClocks(pNv, &MClk, &NVClk);
654
655     cfg1 = pNv->PFB[0x0204/4];
656     sim_data.pix_bpp        = (char)pixelDepth;
657     sim_data.enable_video   = 1;
658     sim_data.enable_mp      = 0;
659     sim_data.memory_type    = (pNv->PFB[0x0200/4] & 0x01) ? 1 : 0;
660     sim_data.memory_width   = (pNv->PEXTDEV[0x0000/4] & 0x10) ? 128 : 64;
661     sim_data.mem_latency    = (char)cfg1 & 0x0F;
662     sim_data.mem_aligned    = 1;
663     sim_data.mem_page_miss  = (char)(((cfg1>>4) &0x0F) + ((cfg1>>31) & 0x01));
664     sim_data.gr_during_vid  = 0;
665     sim_data.pclk_khz       = VClk;
666     sim_data.mclk_khz       = MClk;
667     sim_data.nvclk_khz      = NVClk;
668     nv10CalcArbitration(&fifo_data, &sim_data);
669     if (fifo_data.valid) {
670         int  b = fifo_data.graphics_burst_size >> 4;
671         *burst = 0;
672         while (b >>= 1) (*burst)++;
673         *lwm   = fifo_data.graphics_lwm >> 3;
674     }
675 }
676
677
678 static void nv30UpdateArbitrationSettings (
679     NVPtr        pNv,
680     unsigned     *burst,
681     unsigned     *lwm
682 )   
683 {
684     unsigned int MClk, NVClk;
685     unsigned int fifo_size, burst_size, graphics_lwm;
686
687     fifo_size = 2048;
688     burst_size = 512;
689     graphics_lwm = fifo_size - burst_size;
690
691     nvGetClocks(pNv, &MClk, &NVClk);
692     
693     *burst = 0;
694     burst_size >>= 5;
695     while(burst_size >>= 1) (*burst)++;
696     *lwm = graphics_lwm >> 3;
697 }
698
699 static void nForceUpdateArbitrationSettings (
700     unsigned      VClk,
701     unsigned      pixelDepth,
702     unsigned     *burst,
703     unsigned     *lwm,
704     NVPtr        pNv
705 )
706 {
707     nv10_fifo_info fifo_data;
708     nv10_sim_state sim_data;
709     unsigned int M, N, P, pll, MClk, NVClk, memctrl;
710
711     if((pNv->Chipset & 0x0FF0) == CHIPSET_NFORCE) {
712        unsigned int uMClkPostDiv;
713
714        uMClkPostDiv = (pciReadLong(pciTag(0, 0, 3), 0x6C) >> 8) & 0xf;
715        if(!uMClkPostDiv) uMClkPostDiv = 4; 
716        MClk = 400000 / uMClkPostDiv;
717     } else {
718        MClk = pciReadLong(pciTag(0, 0, 5), 0x4C) / 1000;
719     }
720
721     pll = nvReadRAMDAC0(pNv, 0x500);
722     M = (pll >> 0)  & 0xFF; N = (pll >> 8)  & 0xFF; P = (pll >> 16) & 0x0F;
723     NVClk  = (N * pNv->CrystalFreqKHz / M) >> P;
724     sim_data.pix_bpp        = (char)pixelDepth;
725     sim_data.enable_video   = 0;
726     sim_data.enable_mp      = 0;
727     sim_data.memory_type    = (pciReadLong(pciTag(0, 0, 1), 0x7C) >> 12) & 1;
728     sim_data.memory_width   = 64;
729
730     memctrl = pciReadLong(pciTag(0, 0, 3), 0x00) >> 16;
731
732     if((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) {
733         int dimm[3];
734
735         dimm[0] = (pciReadLong(pciTag(0, 0, 2), 0x40) >> 8) & 0x4F;
736         dimm[1] = (pciReadLong(pciTag(0, 0, 2), 0x44) >> 8) & 0x4F;
737         dimm[2] = (pciReadLong(pciTag(0, 0, 2), 0x48) >> 8) & 0x4F;
738
739         if((dimm[0] + dimm[1]) != dimm[2]) {
740              ErrorF("WARNING: "
741               "your nForce DIMMs are not arranged in optimal banks!\n");
742         } 
743     }
744
745     sim_data.mem_latency    = 3;
746     sim_data.mem_aligned    = 1;
747     sim_data.mem_page_miss  = 10;
748     sim_data.gr_during_vid  = 0;
749     sim_data.pclk_khz       = VClk;
750     sim_data.mclk_khz       = MClk;
751     sim_data.nvclk_khz      = NVClk;
752     nv10CalcArbitration(&fifo_data, &sim_data);
753     if (fifo_data.valid)
754     {
755         int  b = fifo_data.graphics_burst_size >> 4;
756         *burst = 0;
757         while (b >>= 1) (*burst)++;
758         *lwm   = fifo_data.graphics_lwm >> 3;
759     }
760 }
761
762
763 /****************************************************************************\
764 *                                                                            *
765 *                          RIVA Mode State Routines                          *
766 *                                                                            *
767 \****************************************************************************/
768
769 /*
770  * Calculate the Video Clock parameters for the PLL.
771  */
772 static void CalcVClock (
773     int           clockIn,
774     int          *clockOut,
775     CARD32         *pllOut,
776     NVPtr        pNv
777 )
778 {
779     unsigned lowM, highM;
780     unsigned DeltaNew, DeltaOld;
781     unsigned VClk, Freq;
782     unsigned M, N, P;
783     
784     DeltaOld = 0xFFFFFFFF;
785
786     VClk = (unsigned)clockIn;
787     
788     if (pNv->CrystalFreqKHz == 13500) {
789         lowM  = 7;
790         highM = 13;
791     } else {
792         lowM  = 8;
793         highM = 14;
794     }
795
796     for (P = 0; P <= 4; P++) {
797         Freq = VClk << P;
798         if ((Freq >= 128000) && (Freq <= 350000)) {
799             for (M = lowM; M <= highM; M++) {
800                 N = ((VClk << P) * M) / pNv->CrystalFreqKHz;
801                 if(N <= 255) {
802                     Freq = ((pNv->CrystalFreqKHz * N) / M) >> P;
803                     if (Freq > VClk)
804                         DeltaNew = Freq - VClk;
805                     else
806                         DeltaNew = VClk - Freq;
807                     if (DeltaNew < DeltaOld) {
808                         *pllOut   = (P << 16) | (N << 8) | M;
809                         *clockOut = Freq;
810                         DeltaOld  = DeltaNew;
811                     }
812                 }
813             }
814         }
815     }
816 }
817
818 static void CalcVClock2Stage (
819     int           clockIn,
820     int          *clockOut,
821     CARD32         *pllOut,
822     CARD32         *pllBOut,
823     NVPtr        pNv
824 )
825 {
826     unsigned DeltaNew, DeltaOld;
827     unsigned VClk, Freq;
828     unsigned M, N, P;
829
830     DeltaOld = 0xFFFFFFFF;
831
832     *pllBOut = 0x80000401;  /* fixed at x4 for now */
833
834     VClk = (unsigned)clockIn;
835
836     for (P = 0; P <= 6; P++) {
837         Freq = VClk << P;
838         if ((Freq >= 400000) && (Freq <= 1000000)) {
839             for (M = 1; M <= 13; M++) {
840                 N = ((VClk << P) * M) / (pNv->CrystalFreqKHz << 2);
841                 if((N >= 5) && (N <= 255)) {
842                     Freq = (((pNv->CrystalFreqKHz << 2) * N) / M) >> P;
843                     if (Freq > VClk)
844                         DeltaNew = Freq - VClk;
845                     else
846                         DeltaNew = VClk - Freq;
847                     if (DeltaNew < DeltaOld) {
848                         *pllOut   = (P << 16) | (N << 8) | M;
849                         *clockOut = Freq;
850                         DeltaOld  = DeltaNew;
851                     }
852                 }
853             }
854         }
855     }
856 }
857
858 /*
859  * Calculate extended mode parameters (SVGA) and save in a 
860  * mode state structure.
861  */
862 void NVCalcStateExt (
863     NVPtr pNv,
864     RIVA_HW_STATE *state,
865     int            bpp,
866     int            width,
867     int            hDisplaySize,
868     int            height,
869     int            dotClock,
870     int            flags 
871 )
872 {
873     int pixelDepth, VClk;
874         CARD32 CursorStart;
875
876     /*
877      * Save mode parameters.
878      */
879     state->bpp    = bpp;    /* this is not bitsPerPixel, it's 8,15,16,32 */
880     state->width  = width;
881     state->height = height;
882     /*
883      * Extended RIVA registers.
884      */
885     pixelDepth = (bpp + 1)/8;
886     if(pNv->twoStagePLL)
887         CalcVClock2Stage(dotClock, &VClk, &state->pll, &state->pllB, pNv);
888     else
889         CalcVClock(dotClock, &VClk, &state->pll, pNv);
890
891     switch (pNv->Architecture)
892     {
893         case NV_ARCH_04:
894             nv4UpdateArbitrationSettings(VClk, 
895                                          pixelDepth * 8, 
896                                         &(state->arbitration0),
897                                         &(state->arbitration1),
898                                          pNv);
899             state->cursor0  = 0x00;
900             state->cursor1  = 0xbC;
901             if (flags & V_DBLSCAN)
902                 state->cursor1 |= 2;
903             state->cursor2  = 0x00000000;
904             state->pllsel   = 0x10000700;
905             state->config   = 0x00001114;
906             state->general  = bpp == 16 ? 0x00101100 : 0x00100100;
907             state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
908             break;
909         case NV_ARCH_10:
910         case NV_ARCH_20:
911         case NV_ARCH_30:
912         default:
913             if(((pNv->Chipset & 0xfff0) == CHIPSET_C51) ||
914                ((pNv->Chipset & 0xfff0) == CHIPSET_C512))
915             {
916                 state->arbitration0 = 128; 
917                 state->arbitration1 = 0x0480; 
918             } else
919             if(((pNv->Chipset & 0xffff) == CHIPSET_NFORCE) ||
920                ((pNv->Chipset & 0xffff) == CHIPSET_NFORCE2))
921             {
922                 nForceUpdateArbitrationSettings(VClk,
923                                           pixelDepth * 8,
924                                          &(state->arbitration0),
925                                          &(state->arbitration1),
926                                           pNv);
927             } else if(pNv->Architecture < NV_ARCH_30) {
928                 nv10UpdateArbitrationSettings(VClk, 
929                                           pixelDepth * 8, 
930                                          &(state->arbitration0),
931                                          &(state->arbitration1),
932                                           pNv);
933             } else {
934                 nv30UpdateArbitrationSettings(pNv,
935                                          &(state->arbitration0),
936                                          &(state->arbitration1));
937             }
938                         CursorStart = pNv->Cursor->offset - pNv->VRAMPhysical;
939             state->cursor0  = 0x80 | (CursorStart >> 17);
940             state->cursor1  = (CursorStart >> 11) << 2;
941             state->cursor2  = CursorStart >> 24;
942             if (flags & V_DBLSCAN) 
943                 state->cursor1 |= 2;
944             state->pllsel   = 0x10000700;
945             state->config   = pNv->PFB[0x00000200/4];
946             state->general  = bpp == 16 ? 0x00101100 : 0x00100100;
947             state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
948             break;
949     }
950
951     if(bpp != 8) /* DirectColor */
952         state->general |= 0x00000030;
953
954     state->repaint0 = (((width / 8) * pixelDepth) & 0x700) >> 3;
955     state->pixel    = (pixelDepth > 2) ? 3 : pixelDepth;
956 }
957
958
959 void NVLoadStateExt (
960     ScrnInfoPtr pScrn,
961     RIVA_HW_STATE *state
962 )
963 {
964     NVPtr pNv = NVPTR(pScrn);
965     int i, j;
966     CARD32 temp;
967
968     if (!pNv->IRQ)
969         pNv->PMC[0x0140/4] = 0x00000000;
970     pNv->PMC[0x0200/4] = 0xFFFF00FF;
971     pNv->PMC[0x0200/4] = 0xFFFFFFFF;
972
973     pNv->PTIMER[0x0200] = 0x00000008;
974     pNv->PTIMER[0x0210] = 0x00000003;
975     /*TODO: DRM handle PTIMER interrupts */
976     pNv->PTIMER[0x0140] = 0x00000000;
977     pNv->PTIMER[0x0100] = 0xFFFFFFFF;
978
979     /* begin surfaces */
980     /* it seems those regions are equivalent to the radeon's SURFACEs. needs to go in-kernel just like the SURFACEs */
981     if(pNv->Architecture == NV_ARCH_04) {
982         pNv->PFB[0x0200/4] = state->config;
983     } else 
984     if((pNv->Architecture < NV_ARCH_40) ||
985        ((pNv->Chipset & 0xfff0) == CHIPSET_NV40))
986     {
987         for(i = 0; i < 8; i++) {
988            pNv->PFB[(0x0240 + (i * 0x10))/4] = 0;
989            pNv->PFB[(0x0244 + (i * 0x10))/4] = pNv->VRAMPhysicalSize - 1;
990         }
991     } else {
992         int regions = 12;
993
994         if(((pNv->Chipset & 0xfff0) == CHIPSET_G70) ||
995            ((pNv->Chipset & 0xfff0) == CHIPSET_G71) ||
996            ((pNv->Chipset & 0xfff0) == CHIPSET_G72) ||
997            ((pNv->Chipset & 0xfff0) == CHIPSET_G73) ||
998            ((pNv->Chipset & 0xfff0) == CHIPSET_C512))
999         {
1000            regions = 15;
1001         }
1002  
1003        for(i = 0; i < regions; i++) {
1004           pNv->PFB[(0x0600 + (i * 0x10))/4] = 0;
1005           pNv->PFB[(0x0604 + (i * 0x10))/4] = pNv->VRAMPhysicalSize - 1;
1006        }
1007     }
1008     /* end of surfaces */
1009
1010     if(pNv->Architecture < NV_ARCH_10) {
1011        if((pNv->Chipset & 0x0fff) == CHIPSET_NV04) {
1012                    /*XXX: RAMIN access here, find out what it's for.
1013                         *     The DRM is handling RAMIN now
1014                         */
1015            pNv->PRAMIN[0x0824] |= 0x00020000;
1016            pNv->PRAMIN[0x0826] += pNv->VRAMPhysical;
1017        }
1018        pNv->PGRAPH[0x0080/4] = 0x000001FF;
1019        pNv->PGRAPH[0x0080/4] = 0x1230C000;
1020        pNv->PGRAPH[0x0084/4] = 0x72111101;
1021        pNv->PGRAPH[0x0088/4] = 0x11D5F071;
1022        pNv->PGRAPH[0x008C/4] = 0x0004FF31;
1023        pNv->PGRAPH[0x008C/4] = 0x4004FF31;
1024
1025        if (!pNv->IRQ) {
1026            pNv->PGRAPH[0x0140/4] = 0x00000000;
1027            pNv->PGRAPH[0x0100/4] = 0xFFFFFFFF;
1028        }
1029        pNv->PGRAPH[0x0170/4] = 0x10010100;
1030        pNv->PGRAPH[0x0710/4] = 0xFFFFFFFF;
1031        pNv->PGRAPH[0x0720/4] = 0x00000001;
1032
1033        pNv->PGRAPH[0x0810/4] = 0x00000000;
1034        pNv->PGRAPH[0x0608/4] = 0xFFFFFFFF; 
1035     } else {
1036        pNv->PGRAPH[0x0080/4] = 0xFFFFFFFF;
1037        pNv->PGRAPH[0x0080/4] = 0x00000000;
1038
1039        if (!pNv->IRQ) {
1040            pNv->PGRAPH[0x0140/4] = 0x00000000;
1041            pNv->PGRAPH[0x0100/4] = 0xFFFFFFFF;
1042        }
1043        pNv->PGRAPH[0x0144/4] = 0x10010100;
1044        pNv->PGRAPH[0x0714/4] = 0xFFFFFFFF;
1045        pNv->PGRAPH[0x0720/4] = 0x00000001;
1046        pNv->PGRAPH[0x0710/4] &= 0x0007ff00;
1047        pNv->PGRAPH[0x0710/4] |= 0x00020100;
1048
1049        if(pNv->Architecture == NV_ARCH_10) {
1050            pNv->PGRAPH[0x0084/4] = 0x00118700;
1051            pNv->PGRAPH[0x0088/4] = 0x24E00810;
1052            pNv->PGRAPH[0x008C/4] = 0x55DE0030;
1053
1054            /* nv10 second surfaces */
1055            /* this is a copy of the surfaces. What is it for ? */
1056            for(i = 0; i < 32; i++)
1057              pNv->PGRAPH[(0x0B00/4) + i] = pNv->PFB[(0x0240/4) + i];
1058            /* end of nv10 second surfaces */
1059
1060            pNv->PGRAPH[0x640/4] = 0;
1061            pNv->PGRAPH[0x644/4] = 0;
1062            pNv->PGRAPH[0x684/4] = pNv->VRAMPhysicalSize - 1;
1063            pNv->PGRAPH[0x688/4] = pNv->VRAMPhysicalSize - 1;
1064
1065            pNv->PGRAPH[0x0810/4] = 0x00000000;
1066            pNv->PGRAPH[0x0608/4] = 0xFFFFFFFF;
1067        } else {
1068            if(pNv->Architecture >= NV_ARCH_40) {
1069               pNv->PGRAPH[0x0084/4] = 0x401287c0;
1070               pNv->PGRAPH[0x008C/4] = 0x60de8051;
1071               pNv->PGRAPH[0x0090/4] = 0x00008000;
1072               pNv->PGRAPH[0x0610/4] = 0x00be3c5f;
1073
1074               j = pNv->REGS[0x1540/4] & 0xff;
1075               if(j) {
1076                   for(i = 0; !(j & 1); j >>= 1, i++);
1077                   pNv->PGRAPH[0x5000/4] = i;
1078               }
1079
1080               if((pNv->Chipset & 0xfff0) == CHIPSET_NV40) {
1081                  pNv->PGRAPH[0x09b0/4] = 0x83280fff;
1082                  pNv->PGRAPH[0x09b4/4] = 0x000000a0;
1083               } else {
1084                  pNv->PGRAPH[0x0820/4] = 0x83280eff;
1085                  pNv->PGRAPH[0x0824/4] = 0x000000a0;
1086               }
1087
1088               switch(pNv->Chipset & 0xfff0) {
1089               case CHIPSET_NV40:
1090               case CHIPSET_NV45:
1091                  pNv->PGRAPH[0x09b8/4] = 0x0078e366;
1092                  pNv->PGRAPH[0x09bc/4] = 0x0000014c;
1093                  pNv->PFB[0x033C/4] &= 0xffff7fff;
1094                  break;
1095               case CHIPSET_NV41:
1096               case 0x0120:
1097                  pNv->PGRAPH[0x0828/4] = 0x007596ff;
1098                  pNv->PGRAPH[0x082C/4] = 0x00000108;
1099                  break;
1100               case CHIPSET_NV44:
1101               case CHIPSET_G72:
1102               case CHIPSET_C51:
1103               case CHIPSET_C512:
1104                  pNv->PMC[0x1700/4] = pNv->PFB[0x020C/4];
1105                  pNv->PMC[0x1704/4] = 0;
1106                  pNv->PMC[0x1708/4] = 0;
1107                  pNv->PMC[0x170C/4] = pNv->PFB[0x020C/4];
1108                  pNv->PGRAPH[0x0860/4] = 0;
1109                  pNv->PGRAPH[0x0864/4] = 0;
1110                  temp = nvReadCurRAMDAC(pNv, 0x608);
1111                  nvWriteCurRAMDAC(pNv, 0x608, temp | 0x00100000);
1112                  break;
1113               case CHIPSET_NV43:
1114                  pNv->PGRAPH[0x0828/4] = 0x0072cb77;
1115                  pNv->PGRAPH[0x082C/4] = 0x00000108;
1116                  break;
1117               case CHIPSET_NV44A:
1118                  pNv->PGRAPH[0x0860/4] = 0;
1119                  pNv->PGRAPH[0x0864/4] = 0;
1120                  temp = nvReadCurRAMDAC(pNv, 0x608);
1121                  nvWriteCurRAMDAC(pNv, 0x608, temp | 0x00100000);
1122                  break;
1123               case CHIPSET_G70:
1124               case CHIPSET_G71:
1125               case CHIPSET_G73:
1126                  temp = nvReadCurRAMDAC(pNv, 0x608);
1127                  nvWriteCurRAMDAC(pNv, 0x608, temp | 0x00100000);
1128                  pNv->PGRAPH[0x0828/4] = 0x07830610;
1129                  pNv->PGRAPH[0x082C/4] = 0x0000016A;
1130                  break;
1131               default:
1132                  break;
1133               };
1134
1135               pNv->PGRAPH[0x0b38/4] = 0x2ffff800;
1136               pNv->PGRAPH[0x0b3c/4] = 0x00006000;
1137               pNv->PGRAPH[0x032C/4] = 0x01000000; 
1138            } else
1139            if(pNv->Architecture == NV_ARCH_30) {
1140               pNv->PGRAPH[0x0084/4] = 0x40108700;
1141               pNv->PGRAPH[0x0890/4] = 0x00140000;
1142               pNv->PGRAPH[0x008C/4] = 0xf00e0431;
1143               pNv->PGRAPH[0x0090/4] = 0x00008000;
1144               pNv->PGRAPH[0x0610/4] = 0xf04b1f36;
1145               pNv->PGRAPH[0x0B80/4] = 0x1002d888;
1146               pNv->PGRAPH[0x0B88/4] = 0x62ff007f;
1147            } else {
1148               pNv->PGRAPH[0x0084/4] = 0x00118700;
1149               pNv->PGRAPH[0x008C/4] = 0xF20E0431;
1150               pNv->PGRAPH[0x0090/4] = 0x00000000;
1151               pNv->PGRAPH[0x009C/4] = 0x00000040;
1152
1153               if((pNv->Chipset & 0x0ff0) >= CHIPSET_NV25) {
1154                  pNv->PGRAPH[0x0890/4] = 0x00080000;
1155                  pNv->PGRAPH[0x0610/4] = 0x304B1FB6; 
1156                  pNv->PGRAPH[0x0B80/4] = 0x18B82880; 
1157                  pNv->PGRAPH[0x0B84/4] = 0x44000000; 
1158                  pNv->PGRAPH[0x0098/4] = 0x40000080; 
1159                  pNv->PGRAPH[0x0B88/4] = 0x000000ff; 
1160               } else {
1161                  pNv->PGRAPH[0x0880/4] = 0x00080000;
1162                  pNv->PGRAPH[0x0094/4] = 0x00000005;
1163                  pNv->PGRAPH[0x0B80/4] = 0x45CAA208; 
1164                  pNv->PGRAPH[0x0B84/4] = 0x24000000;
1165                  pNv->PGRAPH[0x0098/4] = 0x00000040;
1166                  pNv->PGRAPH[0x0750/4] = 0x00E00038;
1167                  pNv->PGRAPH[0x0754/4] = 0x00000030;
1168                  pNv->PGRAPH[0x0750/4] = 0x00E10038;
1169                  pNv->PGRAPH[0x0754/4] = 0x00000030;
1170               }
1171            }
1172
1173            /* begin nv20+ secondr surfaces */
1174            /* again, a copy of the surfaces. */
1175            if((pNv->Architecture < NV_ARCH_40) ||
1176               ((pNv->Chipset & 0xfff0) == CHIPSET_NV40)) 
1177            {
1178               for(i = 0; i < 32; i++) {
1179                 pNv->PGRAPH[(0x0900/4) + i] = pNv->PFB[(0x0240/4) + i];
1180                 pNv->PGRAPH[(0x6900/4) + i] = pNv->PFB[(0x0240/4) + i];
1181               }
1182            } else {
1183               if(((pNv->Chipset & 0xfff0) == CHIPSET_G70) ||
1184                  ((pNv->Chipset & 0xfff0) == CHIPSET_G71) ||
1185                  ((pNv->Chipset & 0xfff0) == CHIPSET_G72) ||
1186                  ((pNv->Chipset & 0xfff0) == CHIPSET_G73) ||
1187                  ((pNv->Chipset & 0xfff0) == CHIPSET_C512))
1188               {
1189                  for(i = 0; i < 60; i++) {
1190                    pNv->PGRAPH[(0x0D00/4) + i] = pNv->PFB[(0x0600/4) + i];
1191                    pNv->PGRAPH[(0x6900/4) + i] = pNv->PFB[(0x0600/4) + i];
1192                  }
1193               } else {
1194                  for(i = 0; i < 48; i++) {
1195                    pNv->PGRAPH[(0x0900/4) + i] = pNv->PFB[(0x0600/4) + i];
1196                    if(((pNv->Chipset & 0xfff0) != CHIPSET_NV44) &&
1197                       ((pNv->Chipset & 0xfff0) != CHIPSET_NV44A) &&
1198                       ((pNv->Chipset & 0xfff0) != CHIPSET_C51))
1199                    {
1200                       pNv->PGRAPH[(0x6900/4) + i] = pNv->PFB[(0x0600/4) + i];
1201                    }
1202                  }
1203               }
1204            }
1205            /* end nv20+ second surfaces */
1206
1207            /* begin RAM config */
1208            if(pNv->Architecture >= NV_ARCH_40) {
1209               if((pNv->Chipset & 0xfff0) == CHIPSET_NV40) {
1210                  pNv->PGRAPH[0x09A4/4] = pNv->PFB[0x0200/4];
1211                  pNv->PGRAPH[0x09A8/4] = pNv->PFB[0x0204/4];
1212                  pNv->PGRAPH[0x69A4/4] = pNv->PFB[0x0200/4];
1213                  pNv->PGRAPH[0x69A8/4] = pNv->PFB[0x0204/4];
1214
1215                  pNv->PGRAPH[0x0820/4] = 0;
1216                  pNv->PGRAPH[0x0824/4] = 0;
1217                  pNv->PGRAPH[0x0864/4] = pNv->VRAMPhysicalSize - 1;
1218                  pNv->PGRAPH[0x0868/4] = pNv->VRAMPhysicalSize - 1;
1219               } else {
1220                  if(((pNv->Chipset & 0xfff0) == CHIPSET_G70) ||
1221                     ((pNv->Chipset & 0xfff0) == CHIPSET_G71) ||
1222                     ((pNv->Chipset & 0xfff0) == CHIPSET_G72) ||
1223                     ((pNv->Chipset & 0xfff0) == CHIPSET_G73)) 
1224                  {
1225                     pNv->PGRAPH[0x0DF0/4] = pNv->PFB[0x0200/4];
1226                     pNv->PGRAPH[0x0DF4/4] = pNv->PFB[0x0204/4];
1227                  } else {
1228                     pNv->PGRAPH[0x09F0/4] = pNv->PFB[0x0200/4];
1229                     pNv->PGRAPH[0x09F4/4] = pNv->PFB[0x0204/4];
1230                  }
1231                  pNv->PGRAPH[0x69F0/4] = pNv->PFB[0x0200/4];
1232                  pNv->PGRAPH[0x69F4/4] = pNv->PFB[0x0204/4];
1233
1234                  pNv->PGRAPH[0x0840/4] = 0;
1235                  pNv->PGRAPH[0x0844/4] = 0;
1236                  pNv->PGRAPH[0x08a0/4] = pNv->VRAMPhysicalSize - 1;
1237                  pNv->PGRAPH[0x08a4/4] = pNv->VRAMPhysicalSize - 1;
1238               }
1239            } else {
1240               pNv->PGRAPH[0x09A4/4] = pNv->PFB[0x0200/4];
1241               pNv->PGRAPH[0x09A8/4] = pNv->PFB[0x0204/4];
1242               pNv->PGRAPH[0x0750/4] = 0x00EA0000;
1243               pNv->PGRAPH[0x0754/4] = pNv->PFB[0x0200/4];
1244               pNv->PGRAPH[0x0750/4] = 0x00EA0004;
1245               pNv->PGRAPH[0x0754/4] = pNv->PFB[0x0204/4];
1246
1247               pNv->PGRAPH[0x0820/4] = 0;
1248               pNv->PGRAPH[0x0824/4] = 0;
1249               pNv->PGRAPH[0x0864/4] = pNv->VRAMPhysicalSize - 1;
1250               pNv->PGRAPH[0x0868/4] = pNv->VRAMPhysicalSize - 1;
1251            }
1252            /* end of RAM config */
1253
1254            pNv->PGRAPH[0x0B20/4] = 0x00000000;
1255            pNv->PGRAPH[0x0B04/4] = 0xFFFFFFFF;
1256        }
1257     }
1258
1259     /* begin clipping values */
1260     pNv->PGRAPH[0x053C/4] = 0;
1261     pNv->PGRAPH[0x0540/4] = 0;
1262     pNv->PGRAPH[0x0544/4] = 0x00007FFF;
1263     pNv->PGRAPH[0x0548/4] = 0x00007FFF;
1264     /* end of clipping values */
1265
1266     /* Seems we have to reinit some/all of the FIFO regs on a mode switch */
1267     drmCommandNone(pNv->drm_fd, DRM_NOUVEAU_PFIFO_REINIT);
1268
1269     if(pNv->Architecture >= NV_ARCH_10) {
1270         if(pNv->twoHeads) {
1271            pNv->PCRTC0[0x0860/4] = state->head;
1272            pNv->PCRTC0[0x2860/4] = state->head2;
1273         }
1274         temp = nvReadCurRAMDAC(pNv, 0x404);
1275         nvWriteCurRAMDAC(pNv, 0x404, temp | (1 << 25));
1276     
1277         pNv->PMC[0x8704/4] = 1;
1278         pNv->PMC[0x8140/4] = 0;
1279         pNv->PMC[0x8920/4] = 0;
1280         pNv->PMC[0x8924/4] = 0;
1281         pNv->PMC[0x8908/4] = pNv->VRAMPhysicalSize - 1;
1282         pNv->PMC[0x890C/4] = pNv->VRAMPhysicalSize - 1;
1283         pNv->PMC[0x1588/4] = 0;
1284
1285         pNv->PCRTC[0x0810/4] = state->cursorConfig;
1286         pNv->PCRTC[0x0830/4] = state->displayV - 3;
1287         pNv->PCRTC[0x0834/4] = state->displayV - 1;
1288     
1289         if(pNv->FlatPanel) {
1290            if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
1291                nvWriteCurRAMDAC(pNv, 0x528, state->dither);
1292            } else 
1293            if(pNv->twoHeads) {
1294                nvWriteCurRAMDAC(pNv, 0x83C, state->dither);
1295            }
1296     
1297            nvWriteVGA(pNv, 0x53, state->timingH);
1298            nvWriteVGA(pNv, 0x54, state->timingV);
1299            nvWriteVGA(pNv, 0x21, 0xfa);
1300         }
1301
1302         nvWriteVGA(pNv, 0x41, state->extra);
1303     }
1304
1305     nvWriteVGA(pNv, 0x19, state->repaint0);
1306     nvWriteVGA(pNv, 0x1A, state->repaint1);
1307     nvWriteVGA(pNv, 0x25, state->screen);
1308     nvWriteVGA(pNv, 0x28, state->pixel);
1309     nvWriteVGA(pNv, 0x2D, state->horiz);
1310     nvWriteVGA(pNv, 0x1C, state->fifo);
1311     nvWriteVGA(pNv, 0x1B, state->arbitration0);
1312     nvWriteVGA(pNv, 0x20, state->arbitration1);
1313     if(pNv->Architecture >= NV_ARCH_30) {
1314       nvWriteVGA(pNv, 0x47, state->arbitration1 >> 8);
1315     }
1316
1317     nvWriteVGA(pNv, 0x30, state->cursor0);
1318     nvWriteVGA(pNv, 0x31, state->cursor1);
1319     nvWriteVGA(pNv, 0x2F, state->cursor2);
1320     nvWriteVGA(pNv, 0x39, state->interlace);
1321
1322     if(!pNv->FlatPanel) {
1323        nvWriteRAMDAC0(pNv, 0x50C, state->pllsel);
1324        nvWriteRAMDAC0(pNv, 0x508, state->vpll);
1325        if(pNv->twoHeads)
1326           nvWriteRAMDAC0(pNv, 0x520, state->vpll2);
1327        if(pNv->twoStagePLL) {
1328           nvWriteRAMDAC0(pNv, 0x578, state->vpllB);
1329           nvWriteRAMDAC0(pNv, 0x57C, state->vpll2B);
1330        }
1331     } else {
1332        nvWriteCurRAMDAC(pNv, 0x848, state->scale);
1333        nvWriteCurRAMDAC(pNv, 0x828, state->crtcSync);
1334     }
1335     nvWriteCurRAMDAC(pNv, 0x600, state->general);
1336
1337     pNv->PCRTC[0x0140/4] = 0;
1338     pNv->PCRTC[0x0100/4] = 1;
1339
1340     pNv->CurrentState = state;
1341 }
1342
1343 void NVUnloadStateExt
1344 (
1345     NVPtr pNv,
1346     RIVA_HW_STATE *state
1347 )
1348 {
1349     state->repaint0     = nvReadVGA(pNv, 0x19);
1350     state->repaint1     = nvReadVGA(pNv, 0x1A);
1351     state->screen       = nvReadVGA(pNv, 0x25);
1352     state->pixel        = nvReadVGA(pNv, 0x28);
1353     state->horiz        = nvReadVGA(pNv, 0x2D);
1354     state->fifo         = nvReadVGA(pNv, 0x1C);
1355     state->arbitration0 = nvReadVGA(pNv, 0x1B);
1356     state->arbitration1 = nvReadVGA(pNv, 0x20);
1357     if(pNv->Architecture >= NV_ARCH_30) {
1358        state->arbitration1 |= (nvReadVGA(pNv, 0x47) & 1) << 8;
1359     }
1360     state->cursor0      = nvReadVGA(pNv, 0x30);
1361     state->cursor1      = nvReadVGA(pNv, 0x31);
1362     state->cursor2      = nvReadVGA(pNv, 0x2F);
1363     state->interlace    = nvReadVGA(pNv, 0x39);
1364
1365     state->vpll         = nvReadRAMDAC0(pNv, 0x0508);
1366     if(pNv->twoHeads)
1367        state->vpll2     = nvReadRAMDAC0(pNv, 0x0520);
1368     if(pNv->twoStagePLL) {
1369         state->vpllB    = nvReadRAMDAC0(pNv, 0x0578);
1370         state->vpll2B   = nvReadRAMDAC0(pNv, 0x057C);
1371     }
1372     state->pllsel       = nvReadRAMDAC0(pNv, 0x050C);
1373     state->general      = nvReadCurRAMDAC(pNv, 0x0600);
1374     state->scale        = nvReadCurRAMDAC(pNv, 0x0848);
1375     state->config       = pNv->PFB[0x0200/4];
1376
1377     if(pNv->Architecture >= NV_ARCH_10) {
1378         if(pNv->twoHeads) {
1379            state->head     = pNv->PCRTC0[0x0860/4];
1380            state->head2    = pNv->PCRTC0[0x2860/4];
1381            state->crtcOwner = nvReadVGA(pNv, 0x44);
1382         }
1383         state->extra = nvReadVGA(pNv, 0x41);
1384
1385         state->cursorConfig = pNv->PCRTC[0x0810/4];
1386
1387         if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
1388            state->dither = nvReadCurRAMDAC(pNv, 0x0528);
1389         } else 
1390         if(pNv->twoHeads) {
1391             state->dither = nvReadCurRAMDAC(pNv, 0x083C);
1392         }
1393
1394         if(pNv->FlatPanel) {
1395            state->timingH = nvReadVGA(pNv, 0x53);
1396            state->timingV = nvReadVGA(pNv, 0x54);
1397         }
1398     }
1399
1400     if(pNv->FlatPanel) {
1401        state->crtcSync = nvReadCurRAMDAC(pNv, 0x0828);
1402     }
1403 }
1404
1405 void NVSetStartAddress (
1406     NVPtr   pNv,
1407     CARD32 start
1408 )
1409 {
1410     pNv->PCRTC[0x800/4] = start;
1411 }
1412
1413