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