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