1/*
2 * Copyright (c) 1993-1999 NVIDIA, Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "riva_local.h"
29#include "compiler.h"
30#include "riva_include.h"
31#include "riva_hw.h"
32#include "riva_tbl.h"
33
34/*
35 * This file is an OS-agnostic file used to make RIVA 128 and RIVA TNT
36 * operate identically (except TNT has more memory and better 3D quality.
37 */
38static int nv3Busy
39(
40    RIVA_HW_INST *chip
41)
42{
43    return ((chip->Rop->FifoFree < chip->FifoEmptyCount) || (chip->PGRAPH[0x000006B0/4] & 0x01));
44}
45static void vgaLockUnlock
46(
47    RIVA_HW_INST *chip,
48    Bool           Lock
49)
50{
51    CARD8 cr11;
52    VGA_WR08(chip->PCIO, 0x3D4, 0x11);
53    cr11 = VGA_RD08(chip->PCIO, 0x3D5);
54    if(Lock) cr11 |= 0x80;
55    else cr11 &= ~0x80;
56    VGA_WR08(chip->PCIO, 0x3D5, cr11);
57}
58
59static void nv3LockUnlock
60(
61    RIVA_HW_INST *chip,
62    Bool           Lock
63)
64{
65    VGA_WR08(chip->PVIO, 0x3C4, 0x06);
66    VGA_WR08(chip->PVIO, 0x3C5, Lock ? 0x99 : 0x57);
67    vgaLockUnlock(chip, Lock);
68}
69static int ShowHideCursor
70(
71    RIVA_HW_INST *chip,
72    int           ShowHide
73)
74{
75    int current;
76    current                     =  chip->CurrentState->cursor1;
77    chip->CurrentState->cursor1 = (chip->CurrentState->cursor1 & 0xFE) |
78	                          (ShowHide & 0x01);
79    VGA_WR08(chip->PCIO, 0x3D4, 0x31);
80    VGA_WR08(chip->PCIO, 0x3D5, chip->CurrentState->cursor1);
81    return (current & 0x01);
82}
83
84/****************************************************************************\
85*                                                                            *
86* The video arbitration routines calculate some "magic" numbers.  Fixes      *
87* the snow seen when accessing the framebuffer without it.                   *
88* It just works (I hope).                                                    *
89*                                                                            *
90\****************************************************************************/
91
92#define DEFAULT_GR_LWM 100
93#define DEFAULT_VID_LWM 100
94#define DEFAULT_GR_BURST_SIZE 256
95#define DEFAULT_VID_BURST_SIZE 128
96#define VIDEO		0
97#define GRAPHICS	1
98#define MPORT		2
99#define ENGINE		3
100#define GFIFO_SIZE	320
101#define GFIFO_SIZE_128	256
102#define MFIFO_SIZE	120
103#define VFIFO_SIZE	256
104#define	ABS(a)	((a) > 0 ? (a) : -(a))
105typedef struct {
106  int gdrain_rate;
107  int vdrain_rate;
108  int mdrain_rate;
109  int gburst_size;
110  int vburst_size;
111  char vid_en;
112  char gr_en;
113  int wcmocc, wcgocc, wcvocc, wcvlwm, wcglwm;
114  int by_gfacc;
115  char vid_only_once;
116  char gr_only_once;
117  char first_vacc;
118  char first_gacc;
119  char first_macc;
120  int vocc;
121  int gocc;
122  int mocc;
123  char cur;
124  char engine_en;
125  char converged;
126  int priority;
127} nv3_arb_info;
128typedef struct {
129  int graphics_lwm;
130  int video_lwm;
131  int graphics_burst_size;
132  int video_burst_size;
133  int graphics_hi_priority;
134  int media_hi_priority;
135  int rtl_values;
136  int valid;
137} nv3_fifo_info;
138typedef struct {
139  char pix_bpp;
140  char enable_video;
141  char gr_during_vid;
142  char enable_mp;
143  int memory_width;
144  int video_scale;
145  int pclk_khz;
146  int mclk_khz;
147  int mem_page_miss;
148  int mem_latency;
149  char mem_aligned;
150} nv3_sim_state;
151static int nv3_iterate(nv3_fifo_info *res_info, nv3_sim_state * state, nv3_arb_info *ainfo)
152{
153    int iter = 0;
154    int tmp;
155    int vfsize, mfsize, gfsize;
156    int mburst_size = 32;
157    int mmisses, gmisses, vmisses;
158    int misses;
159    int vlwm, glwm;
160    int last, next, cur;
161    int max_gfsize ;
162    long ns;
163
164    vlwm = 0;
165    glwm = 0;
166    vfsize = 0;
167    gfsize = 0;
168    cur = ainfo->cur;
169    mmisses = 2;
170    gmisses = 2;
171    vmisses = 2;
172    if (ainfo->gburst_size == 128) max_gfsize = GFIFO_SIZE_128;
173    else  max_gfsize = GFIFO_SIZE;
174    max_gfsize = GFIFO_SIZE;
175    while (1)
176    {
177        if (ainfo->vid_en)
178        {
179            if (ainfo->wcvocc > ainfo->vocc) ainfo->wcvocc = ainfo->vocc;
180            if (ainfo->wcvlwm > vlwm) ainfo->wcvlwm = vlwm ;
181            ns = 1000000 * ainfo->vburst_size/(state->memory_width/8)/state->mclk_khz;
182            vfsize = ns * ainfo->vdrain_rate / 1000000;
183            vfsize =  ainfo->wcvlwm - ainfo->vburst_size + vfsize;
184        }
185        if (state->enable_mp)
186        {
187            if (ainfo->wcmocc > ainfo->mocc) ainfo->wcmocc = ainfo->mocc;
188        }
189        if (ainfo->gr_en)
190        {
191            if (ainfo->wcglwm > glwm) ainfo->wcglwm = glwm ;
192            if (ainfo->wcgocc > ainfo->gocc) ainfo->wcgocc = ainfo->gocc;
193            ns = 1000000 * (ainfo->gburst_size/(state->memory_width/8))/state->mclk_khz;
194            gfsize = (ns * (long) ainfo->gdrain_rate)/1000000;
195            gfsize = ainfo->wcglwm - ainfo->gburst_size + gfsize;
196        }
197        mfsize = 0;
198        if (!state->gr_during_vid && ainfo->vid_en)
199            if (ainfo->vid_en && (ainfo->vocc < 0) && !ainfo->vid_only_once)
200                next = VIDEO;
201            else if (ainfo->mocc < 0)
202                next = MPORT;
203            else if (ainfo->gocc< ainfo->by_gfacc)
204                next = GRAPHICS;
205            else return (0);
206        else switch (ainfo->priority)
207            {
208                case VIDEO:
209                    if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
210                        next = VIDEO;
211                    else if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
212                        next = GRAPHICS;
213                    else if (ainfo->mocc<0)
214                        next = MPORT;
215                    else    return (0);
216                    break;
217                case GRAPHICS:
218                    if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
219                        next = GRAPHICS;
220                    else if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
221                        next = VIDEO;
222                    else if (ainfo->mocc<0)
223                        next = MPORT;
224                    else    return (0);
225                    break;
226                default:
227                    if (ainfo->mocc<0)
228                        next = MPORT;
229                    else if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
230                        next = GRAPHICS;
231                    else if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
232                        next = VIDEO;
233                    else    return (0);
234                    break;
235            }
236        last = cur;
237        cur = next;
238        iter++;
239        switch (cur)
240        {
241            case VIDEO:
242                if (last==cur)    misses = 0;
243                else if (ainfo->first_vacc)   misses = vmisses;
244                else    misses = 1;
245                ainfo->first_vacc = 0;
246                if (last!=cur)
247                {
248                    ns =  1000000 * (vmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz;
249                    vlwm = ns * ainfo->vdrain_rate/ 1000000;
250                    vlwm = ainfo->vocc - vlwm;
251                }
252                ns = 1000000*(misses*state->mem_page_miss + ainfo->vburst_size)/(state->memory_width/8)/state->mclk_khz;
253                ainfo->vocc = ainfo->vocc + ainfo->vburst_size - ns*ainfo->vdrain_rate/1000000;
254                ainfo->gocc = ainfo->gocc - ns*ainfo->gdrain_rate/1000000;
255                ainfo->mocc = ainfo->mocc - ns*ainfo->mdrain_rate/1000000;
256                break;
257            case GRAPHICS:
258                if (last==cur)    misses = 0;
259                else if (ainfo->first_gacc)   misses = gmisses;
260                else    misses = 1;
261                ainfo->first_gacc = 0;
262                if (last!=cur)
263                {
264                    ns = 1000000*(gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz ;
265                    glwm = ns * ainfo->gdrain_rate/1000000;
266                    glwm = ainfo->gocc - glwm;
267                }
268                ns = 1000000*(misses*state->mem_page_miss + ainfo->gburst_size/(state->memory_width/8))/state->mclk_khz;
269                ainfo->vocc = ainfo->vocc + 0 - ns*ainfo->vdrain_rate/1000000;
270                ainfo->gocc = ainfo->gocc + ainfo->gburst_size - ns*ainfo->gdrain_rate/1000000;
271                ainfo->mocc = ainfo->mocc + 0 - ns*ainfo->mdrain_rate/1000000;
272                break;
273            default:
274                if (last==cur)    misses = 0;
275                else if (ainfo->first_macc)   misses = mmisses;
276                else    misses = 1;
277                ainfo->first_macc = 0;
278                ns = 1000000*(misses*state->mem_page_miss + mburst_size/(state->memory_width/8))/state->mclk_khz;
279                ainfo->vocc = ainfo->vocc + 0 - ns*ainfo->vdrain_rate/1000000;
280                ainfo->gocc = ainfo->gocc + 0 - ns*ainfo->gdrain_rate/1000000;
281                ainfo->mocc = ainfo->mocc + mburst_size - ns*ainfo->mdrain_rate/1000000;
282                break;
283        }
284        if (iter>100)
285        {
286            ainfo->converged = 0;
287            return (1);
288        }
289        ns = 1000000*ainfo->gburst_size/(state->memory_width/8)/state->mclk_khz;
290        tmp = ns * ainfo->gdrain_rate/1000000;
291        if (ABS(ainfo->gburst_size) + ((ABS(ainfo->wcglwm) + 16 ) & ~0x7) - tmp > max_gfsize)
292        {
293            ainfo->converged = 0;
294            return (1);
295        }
296        ns = 1000000*ainfo->vburst_size/(state->memory_width/8)/state->mclk_khz;
297        tmp = ns * ainfo->vdrain_rate/1000000;
298        if (ABS(ainfo->vburst_size) + (ABS(ainfo->wcvlwm + 32) & ~0xf)  - tmp> VFIFO_SIZE)
299        {
300            ainfo->converged = 0;
301            return (1);
302        }
303        if (ABS(ainfo->gocc) > max_gfsize)
304        {
305            ainfo->converged = 0;
306            return (1);
307        }
308        if (ABS(ainfo->vocc) > VFIFO_SIZE)
309        {
310            ainfo->converged = 0;
311            return (1);
312        }
313        if (ABS(ainfo->mocc) > MFIFO_SIZE)
314        {
315            ainfo->converged = 0;
316            return (1);
317        }
318        if (ABS(vfsize) > VFIFO_SIZE)
319        {
320            ainfo->converged = 0;
321            return (1);
322        }
323        if (ABS(gfsize) > max_gfsize)
324        {
325            ainfo->converged = 0;
326            return (1);
327        }
328        if (ABS(mfsize) > MFIFO_SIZE)
329        {
330            ainfo->converged = 0;
331            return (1);
332        }
333    }
334}
335static char nv3_arb(nv3_fifo_info * res_info, nv3_sim_state * state,  nv3_arb_info *ainfo)
336{
337    long ens, vns, mns, gns;
338    int mmisses, gmisses, vmisses, eburst_size, mburst_size;
339    int refresh_cycle;
340
341    refresh_cycle = 0;
342    refresh_cycle = 2*(state->mclk_khz/state->pclk_khz) + 5;
343    mmisses = 2;
344    if (state->mem_aligned) gmisses = 2;
345    else    gmisses = 3;
346    vmisses = 2;
347    eburst_size = state->memory_width * 1;
348    mburst_size = 32;
349    gns = 1000000 * (gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz;
350    ainfo->by_gfacc = gns*ainfo->gdrain_rate/1000000;
351    ainfo->wcmocc = 0;
352    ainfo->wcgocc = 0;
353    ainfo->wcvocc = 0;
354    ainfo->wcvlwm = 0;
355    ainfo->wcglwm = 0;
356    ainfo->engine_en = 1;
357    ainfo->converged = 1;
358    if (ainfo->engine_en)
359    {
360        ens =  1000000*(state->mem_page_miss + eburst_size/(state->memory_width/8) +refresh_cycle)/state->mclk_khz;
361        ainfo->mocc = state->enable_mp ? 0-ens*ainfo->mdrain_rate/1000000 : 0;
362        ainfo->vocc = ainfo->vid_en ? 0-ens*ainfo->vdrain_rate/1000000 : 0;
363        ainfo->gocc = ainfo->gr_en ? 0-ens*ainfo->gdrain_rate/1000000 : 0;
364        ainfo->cur = ENGINE;
365        ainfo->first_vacc = 1;
366        ainfo->first_gacc = 1;
367        ainfo->first_macc = 1;
368        nv3_iterate(res_info, state,ainfo);
369    }
370    if (state->enable_mp)
371    {
372        mns = 1000000 * (mmisses*state->mem_page_miss + mburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
373        ainfo->mocc = state->enable_mp ? 0 : mburst_size - mns*ainfo->mdrain_rate/1000000;
374        ainfo->vocc = ainfo->vid_en ? 0 : 0- mns*ainfo->vdrain_rate/1000000;
375        ainfo->gocc = ainfo->gr_en ? 0: 0- mns*ainfo->gdrain_rate/1000000;
376        ainfo->cur = MPORT;
377        ainfo->first_vacc = 1;
378        ainfo->first_gacc = 1;
379        ainfo->first_macc = 0;
380        nv3_iterate(res_info, state,ainfo);
381    }
382    if (ainfo->gr_en)
383    {
384        ainfo->first_vacc = 1;
385        ainfo->first_gacc = 0;
386        ainfo->first_macc = 1;
387        gns = 1000000*(gmisses*state->mem_page_miss + ainfo->gburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
388        ainfo->gocc = ainfo->gburst_size - gns*ainfo->gdrain_rate/1000000;
389        ainfo->vocc = ainfo->vid_en? 0-gns*ainfo->vdrain_rate/1000000 : 0;
390        ainfo->mocc = state->enable_mp ?  0-gns*ainfo->mdrain_rate/1000000: 0;
391        ainfo->cur = GRAPHICS;
392        nv3_iterate(res_info, state,ainfo);
393    }
394    if (ainfo->vid_en)
395    {
396        ainfo->first_vacc = 0;
397        ainfo->first_gacc = 1;
398        ainfo->first_macc = 1;
399        vns = 1000000*(vmisses*state->mem_page_miss + ainfo->vburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
400        ainfo->vocc = ainfo->vburst_size - vns*ainfo->vdrain_rate/1000000;
401        ainfo->gocc = ainfo->gr_en? (0-vns*ainfo->gdrain_rate/1000000) : 0;
402        ainfo->mocc = state->enable_mp? 0-vns*ainfo->mdrain_rate/1000000 :0 ;
403        ainfo->cur = VIDEO;
404        nv3_iterate(res_info, state, ainfo);
405    }
406    if (ainfo->converged)
407    {
408        res_info->graphics_lwm = (int)ABS(ainfo->wcglwm) + 16;
409        res_info->video_lwm = (int)ABS(ainfo->wcvlwm) + 32;
410        res_info->graphics_burst_size = ainfo->gburst_size;
411        res_info->video_burst_size = ainfo->vburst_size;
412        res_info->graphics_hi_priority = (ainfo->priority == GRAPHICS);
413        res_info->media_hi_priority = (ainfo->priority == MPORT);
414        if (res_info->video_lwm > 160)
415        {
416            res_info->graphics_lwm = 256;
417            res_info->video_lwm = 128;
418            res_info->graphics_burst_size = 64;
419            res_info->video_burst_size = 64;
420            res_info->graphics_hi_priority = 0;
421            res_info->media_hi_priority = 0;
422            ainfo->converged = 0;
423            return (0);
424        }
425        if (res_info->video_lwm > 128)
426        {
427            res_info->video_lwm = 128;
428        }
429        return (1);
430    }
431    else
432    {
433        res_info->graphics_lwm = 256;
434        res_info->video_lwm = 128;
435        res_info->graphics_burst_size = 64;
436        res_info->video_burst_size = 64;
437        res_info->graphics_hi_priority = 0;
438        res_info->media_hi_priority = 0;
439        return (0);
440    }
441}
442static char nv3_get_param(nv3_fifo_info *res_info, nv3_sim_state * state, nv3_arb_info *ainfo)
443{
444    int done, g,v, p;
445
446    done = 0;
447    for (p=0; p < 2; p++)
448    {
449        for (g=128 ; g > 32; g= g>> 1)
450        {
451            for (v=128; v >=32; v = v>> 1)
452            {
453                ainfo->priority = p;
454                ainfo->gburst_size = g;
455                ainfo->vburst_size = v;
456                done = nv3_arb(res_info, state,ainfo);
457                if (done && (g==128))
458                    if ((res_info->graphics_lwm + g) > 256)
459                        done = 0;
460                if (done)
461                    goto Done;
462            }
463        }
464    }
465
466 Done:
467    return done;
468}
469static void nv3CalcArbitration
470(
471    nv3_fifo_info * res_info,
472    nv3_sim_state * state
473)
474{
475    nv3_fifo_info save_info;
476    nv3_arb_info ainfo;
477    char   res_gr, res_vid;
478
479    ainfo.gr_en = 1;
480    ainfo.vid_en = state->enable_video;
481    ainfo.vid_only_once = 0;
482    ainfo.gr_only_once = 0;
483    ainfo.gdrain_rate = (int) state->pclk_khz * (state->pix_bpp/8);
484    ainfo.vdrain_rate = (int) state->pclk_khz * 2;
485    if (state->video_scale != 0)
486        ainfo.vdrain_rate = ainfo.vdrain_rate/state->video_scale;
487    ainfo.mdrain_rate = 33000;
488    res_info->rtl_values = 0;
489    if (!state->gr_during_vid && state->enable_video)
490    {
491        ainfo.gr_only_once = 1;
492        ainfo.gr_en = 1;
493        ainfo.gdrain_rate = 0;
494        res_vid = nv3_get_param(res_info, state,  &ainfo);
495        res_vid = ainfo.converged;
496        save_info.video_lwm = res_info->video_lwm;
497        save_info.video_burst_size = res_info->video_burst_size;
498        ainfo.vid_en = 1;
499        ainfo.vid_only_once = 1;
500        ainfo.gr_en = 1;
501        ainfo.gdrain_rate = (int) state->pclk_khz * (state->pix_bpp/8);
502        ainfo.vdrain_rate = 0;
503        res_gr = nv3_get_param(res_info, state,  &ainfo);
504        res_gr = ainfo.converged;
505        res_info->video_lwm = save_info.video_lwm;
506        res_info->video_burst_size = save_info.video_burst_size;
507        res_info->valid = res_gr & res_vid;
508    }
509    else
510    {
511        if (!ainfo.gr_en) ainfo.gdrain_rate = 0;
512        if (!ainfo.vid_en) ainfo.vdrain_rate = 0;
513        res_gr = nv3_get_param(res_info, state,  &ainfo);
514        res_info->valid = ainfo.converged;
515    }
516}
517static void nv3UpdateArbitrationSettings
518(
519    unsigned      VClk,
520    unsigned      pixelDepth,
521    unsigned     *burst,
522    unsigned     *lwm,
523    RIVA_HW_INST *chip
524)
525{
526    nv3_fifo_info fifo_data;
527    nv3_sim_state sim_data;
528    unsigned int M, N, P, pll, MClk;
529
530    pll = chip->PRAMDAC[0x00000504/4];
531    M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F;
532    MClk = (N * chip->CrystalFreqKHz / M) >> P;
533    sim_data.pix_bpp        = (char)pixelDepth;
534    sim_data.enable_video   = 0;
535    sim_data.enable_mp      = 0;
536    sim_data.video_scale    = 1;
537    sim_data.memory_width   = (chip->PEXTDEV[0x00000000/4] & 0x10) ? 128 : 64;
538    sim_data.memory_width   = 128;
539
540    sim_data.mem_latency    = 9;
541    sim_data.mem_aligned    = 1;
542    sim_data.mem_page_miss  = 11;
543    sim_data.gr_during_vid  = 0;
544    sim_data.pclk_khz       = VClk;
545    sim_data.mclk_khz       = MClk;
546    nv3CalcArbitration(&fifo_data, &sim_data);
547    if (fifo_data.valid)
548    {
549        int  b = fifo_data.graphics_burst_size >> 4;
550        *burst = 0;
551        while (b >>= 1) (*burst)++;
552        *lwm   = fifo_data.graphics_lwm >> 3;
553    }
554    else
555    {
556        *lwm   = 0x24;
557        *burst = 0x2;
558    }
559}
560
561/****************************************************************************\
562*                                                                            *
563*                          RIVA Mode State Routines                          *
564*                                                                            *
565\****************************************************************************/
566
567/*
568 * Calculate the Video Clock parameters for the PLL.
569 */
570static int CalcVClock
571(
572    int           clockIn,
573    int          *clockOut,
574    int          *mOut,
575    int          *nOut,
576    int          *pOut,
577    RIVA_HW_INST *chip
578)
579{
580    unsigned lowM, highM, highP;
581    unsigned DeltaNew, DeltaOld;
582    unsigned VClk, Freq;
583    unsigned M, N, P;
584
585    DeltaOld = 0xFFFFFFFF;
586
587    VClk     = (unsigned)clockIn;
588
589    if (chip->CrystalFreqKHz == 13500)
590    {
591        lowM  = 7;
592        highM = 12;
593    }
594    else
595    {
596        lowM  = 8;
597        highM = 13;
598    }
599
600    highP = 3;
601    for (P = 0; P <= highP; P ++)
602    {
603        Freq = VClk << P;
604        if ((Freq >= 128000) && (Freq <= chip->MaxVClockFreqKHz))
605        {
606            for (M = lowM; M <= highM; M++)
607            {
608                N    = (VClk << P) * M / chip->CrystalFreqKHz;
609                if(N <= 255) {
610                    Freq = (chip->CrystalFreqKHz * N / M) >> P;
611                    if (Freq > VClk)
612                        DeltaNew = Freq - VClk;
613                    else
614                        DeltaNew = VClk - Freq;
615                    if (DeltaNew < DeltaOld)
616                    {
617                        *mOut     = M;
618                        *nOut     = N;
619                        *pOut     = P;
620                        *clockOut = Freq;
621                        DeltaOld  = DeltaNew;
622                    }
623                }
624            }
625        }
626    }
627    return (DeltaOld != 0xFFFFFFFF);
628}
629/*
630 * Calculate extended mode parameters (SVGA) and save in a
631 * mode state structure.
632 */
633static void CalcStateExt
634(
635    RIVA_HW_INST  *chip,
636    RIVA_HW_STATE *state,
637    int            bpp,
638    int            width,
639    int            hDisplaySize,
640    int            height,
641    int            dotClock,
642    int		   flags
643)
644{
645    int pixelDepth, VClk = 0, m = 0, n = 0, p = 0;
646    /*
647     * Save mode parameters.
648     */
649    state->bpp    = bpp;    /* this is not bitsPerPixel, it's 8,15,16,32 */
650    state->width  = width;
651    state->height = height;
652    /*
653     * Extended RIVA registers.
654     */
655    pixelDepth = (bpp + 1)/8;
656    CalcVClock(dotClock, &VClk, &m, &n, &p, chip);
657
658    nv3UpdateArbitrationSettings(VClk,
659                                 pixelDepth * 8,
660                                 &(state->arbitration0),
661                                 &(state->arbitration1),
662                                 chip);
663    state->cursor0  = 0x00;
664    state->cursor1  = 0x78;
665    if (flags & V_DBLSCAN)
666       state->cursor1 |= 2;
667    state->cursor2  = 0x00000000;
668    state->pllsel   = 0x10010100;
669    state->config   = ((width + 31)/32)
670                      | (((pixelDepth > 2) ? 3 : pixelDepth) << 8)
671                      | 0x1000;
672    state->general  = 0x00100100;
673    state->repaint1 = hDisplaySize < 1280 ? 0x06 : 0x02;
674
675
676    state->vpll     = (p << 16) | (n << 8) | m;
677    state->repaint0 = (((width/8)*pixelDepth) & 0x700) >> 3;
678    state->pixel    = pixelDepth > 2   ? 3    : pixelDepth;
679    state->offset   = 0;
680    state->pitch    = pixelDepth * width;
681}
682/*
683 * Load fixed function state and pre-calculated/stored state.
684 */
685#define LOAD_FIXED_STATE(tbl,dev)                                       \
686    for (i = 0; i < sizeof(tbl##Table##dev)/8; i++)                 \
687        chip->dev[tbl##Table##dev[i][0]] = tbl##Table##dev[i][1]
688#define LOAD_FIXED_STATE_8BPP(tbl,dev)                                  \
689    for (i = 0; i < sizeof(tbl##Table##dev##_8BPP)/8; i++)            \
690        chip->dev[tbl##Table##dev##_8BPP[i][0]] = tbl##Table##dev##_8BPP[i][1]
691#define LOAD_FIXED_STATE_15BPP(tbl,dev)                                 \
692    for (i = 0; i < sizeof(tbl##Table##dev##_15BPP)/8; i++)           \
693        chip->dev[tbl##Table##dev##_15BPP[i][0]] = tbl##Table##dev##_15BPP[i][1]
694#define LOAD_FIXED_STATE_16BPP(tbl,dev)                                 \
695    for (i = 0; i < sizeof(tbl##Table##dev##_16BPP)/8; i++)           \
696        chip->dev[tbl##Table##dev##_16BPP[i][0]] = tbl##Table##dev##_16BPP[i][1]
697#define LOAD_FIXED_STATE_32BPP(tbl,dev)                                 \
698    for (i = 0; i < sizeof(tbl##Table##dev##_32BPP)/8; i++)           \
699        chip->dev[tbl##Table##dev##_32BPP[i][0]] = tbl##Table##dev##_32BPP[i][1]
700static void UpdateFifoState
701(
702    RIVA_HW_INST  *chip
703)
704{
705}
706static void LoadStateExt
707(
708    RIVA_HW_INST  *chip,
709    RIVA_HW_STATE *state
710)
711{
712    int i;
713
714    /*
715     * Load HW fixed function state.
716     */
717    LOAD_FIXED_STATE(Riva,PMC);
718    LOAD_FIXED_STATE(Riva,PTIMER);
719     /*
720      * Make sure frame buffer config gets set before loading PRAMIN.
721      */
722    chip->PFB[0x00000200/4] = state->config;
723    LOAD_FIXED_STATE(nv3,PFIFO);
724    LOAD_FIXED_STATE(nv3,PRAMIN);
725    LOAD_FIXED_STATE(nv3,PGRAPH);
726    switch (state->bpp)
727    {
728     case 15:
729     case 16:
730         LOAD_FIXED_STATE_15BPP(nv3,PRAMIN);
731         LOAD_FIXED_STATE_15BPP(nv3,PGRAPH);
732         break;
733     case 24:
734     case 32:
735         LOAD_FIXED_STATE_32BPP(nv3,PRAMIN);
736         LOAD_FIXED_STATE_32BPP(nv3,PGRAPH);
737         break;
738     case 8:
739     default:
740         LOAD_FIXED_STATE_8BPP(nv3,PRAMIN);
741        LOAD_FIXED_STATE_8BPP(nv3,PGRAPH);
742        break;
743    }
744    for (i = 0x00000; i < 0x00800; i++)
745        chip->PRAMIN[0x00000502 + i] = (i << 12) | 0x03;
746    chip->PGRAPH[0x00000630/4] = state->offset;
747    chip->PGRAPH[0x00000634/4] = state->offset;
748    chip->PGRAPH[0x00000638/4] = state->offset;
749    chip->PGRAPH[0x0000063C/4] = state->offset;
750    chip->PGRAPH[0x00000650/4] = state->pitch;
751    chip->PGRAPH[0x00000654/4] = state->pitch;
752    chip->PGRAPH[0x00000658/4] = state->pitch;
753    chip->PGRAPH[0x0000065C/4] = state->pitch;
754
755    LOAD_FIXED_STATE(Riva,FIFO);
756    UpdateFifoState(chip);
757
758    /*
759     * Load HW mode state.
760     */
761    VGA_WR08(chip->PCIO, 0x03D4, 0x19);
762    VGA_WR08(chip->PCIO, 0x03D5, state->repaint0);
763    VGA_WR08(chip->PCIO, 0x03D4, 0x1A);
764    VGA_WR08(chip->PCIO, 0x03D5, state->repaint1);
765    VGA_WR08(chip->PCIO, 0x03D4, 0x25);
766    VGA_WR08(chip->PCIO, 0x03D5, state->screen);
767    VGA_WR08(chip->PCIO, 0x03D4, 0x28);
768    VGA_WR08(chip->PCIO, 0x03D5, state->pixel);
769    VGA_WR08(chip->PCIO, 0x03D4, 0x2D);
770    VGA_WR08(chip->PCIO, 0x03D5, state->horiz);
771    VGA_WR08(chip->PCIO, 0x03D4, 0x1B);
772    VGA_WR08(chip->PCIO, 0x03D5, state->arbitration0);
773    VGA_WR08(chip->PCIO, 0x03D4, 0x20);
774    VGA_WR08(chip->PCIO, 0x03D5, state->arbitration1);
775    VGA_WR08(chip->PCIO, 0x03D4, 0x30);
776    VGA_WR08(chip->PCIO, 0x03D5, state->cursor0);
777    VGA_WR08(chip->PCIO, 0x03D4, 0x31);
778    VGA_WR08(chip->PCIO, 0x03D5, state->cursor1);
779    VGA_WR08(chip->PCIO, 0x03D4, 0x2F);
780    VGA_WR08(chip->PCIO, 0x03D5, state->cursor2);
781    VGA_WR08(chip->PCIO, 0x03D4, 0x39);
782    VGA_WR08(chip->PCIO, 0x03D5, state->interlace);
783
784    chip->PRAMDAC[0x00000508/4] = state->vpll;
785    chip->PRAMDAC[0x0000050C/4] = state->pllsel;
786    chip->PRAMDAC[0x00000600/4]  = state->general;
787
788    /*
789     * Turn off VBlank enable and reset.
790     */
791    chip->PCRTC[0x00000140/4] = 0;
792    chip->PCRTC[0x00000100/4] = chip->VBlankBit;
793    /*
794     * Set interrupt enable.
795     */
796    chip->PMC[0x00000140/4]  = chip->EnableIRQ & 0x01;
797    /*
798     * Set current state pointer.
799     */
800    chip->CurrentState = state;
801    /*
802     * Reset FIFO free and empty counts.
803     */
804    chip->FifoFreeCount  = 0;
805    /* Free count from first subchannel */
806    chip->FifoEmptyCount = chip->Rop->FifoFree;
807}
808
809static void UnloadStateExt
810(
811    RIVA_HW_INST  *chip,
812    RIVA_HW_STATE *state
813)
814{
815    /*
816     * Save current HW state.
817     */
818    VGA_WR08(chip->PCIO, 0x03D4, 0x19);
819    state->repaint0     = VGA_RD08(chip->PCIO, 0x03D5);
820    VGA_WR08(chip->PCIO, 0x03D4, 0x1A);
821    state->repaint1     = VGA_RD08(chip->PCIO, 0x03D5);
822    VGA_WR08(chip->PCIO, 0x03D4, 0x25);
823    state->screen       = VGA_RD08(chip->PCIO, 0x03D5);
824    VGA_WR08(chip->PCIO, 0x03D4, 0x28);
825    state->pixel        = VGA_RD08(chip->PCIO, 0x03D5);
826    VGA_WR08(chip->PCIO, 0x03D4, 0x2D);
827    state->horiz        = VGA_RD08(chip->PCIO, 0x03D5);
828    VGA_WR08(chip->PCIO, 0x03D4, 0x1B);
829    state->arbitration0 = VGA_RD08(chip->PCIO, 0x03D5);
830    VGA_WR08(chip->PCIO, 0x03D4, 0x20);
831    state->arbitration1 = VGA_RD08(chip->PCIO, 0x03D5);
832    VGA_WR08(chip->PCIO, 0x03D4, 0x30);
833    state->cursor0      = VGA_RD08(chip->PCIO, 0x03D5);
834    VGA_WR08(chip->PCIO, 0x03D4, 0x31);
835    state->cursor1      = VGA_RD08(chip->PCIO, 0x03D5);
836    VGA_WR08(chip->PCIO, 0x03D4, 0x2F);
837    state->cursor2      = VGA_RD08(chip->PCIO, 0x03D5);
838    VGA_WR08(chip->PCIO, 0x03D4, 0x39);
839    state->interlace    = VGA_RD08(chip->PCIO, 0x03D5);
840    state->vpll         = chip->PRAMDAC[0x00000508/4];
841    state->pllsel       = chip->PRAMDAC[0x0000050C/4];
842    state->general      = chip->PRAMDAC[0x00000600/4];
843    state->config       = chip->PFB[0x00000200/4];
844    state->offset       = chip->PGRAPH[0x00000630/4];
845    state->pitch        = chip->PGRAPH[0x00000650/4];
846}
847
848static void SetStartAddress
849(
850    RIVA_HW_INST *chip,
851    unsigned      start
852)
853{
854    int offset = start >> 2;
855    int pan    = (start & 3) << 1;
856    unsigned char tmp;
857
858    /*
859     * Unlock extended registers.
860     */
861    chip->LockUnlock(chip, 0);
862    /*
863     * Set start address.
864     */
865    VGA_WR08(chip->PCIO, 0x3D4, 0x0D); VGA_WR08(chip->PCIO, 0x3D5, offset);
866    offset >>= 8;
867    VGA_WR08(chip->PCIO, 0x3D4, 0x0C); VGA_WR08(chip->PCIO, 0x3D5, offset);
868    offset >>= 8;
869    VGA_WR08(chip->PCIO, 0x3D4, 0x19); tmp = VGA_RD08(chip->PCIO, 0x3D5);
870    VGA_WR08(chip->PCIO, 0x3D5, (offset & 0x01F) | (tmp & ~0x1F));
871    VGA_WR08(chip->PCIO, 0x3D4, 0x2D); tmp = VGA_RD08(chip->PCIO, 0x3D5);
872    VGA_WR08(chip->PCIO, 0x3D5, (offset & 0x60) | (tmp & ~0x60));
873    /*
874     * 4 pixel pan register.
875     */
876    offset = VGA_RD08(chip->PCIO, chip->IO + 0x0A);
877    VGA_WR08(chip->PCIO, 0x3C0, 0x13);
878    VGA_WR08(chip->PCIO, 0x3C0, pan);
879}
880/****************************************************************************\
881*                                                                            *
882*                      Probe RIVA Chip Configuration                         *
883*                                                                            *
884\****************************************************************************/
885
886static void nv3GetConfig
887(
888    RIVA_HW_INST *chip
889)
890{
891    /*
892     * Fill in chip configuration.
893     */
894    if (chip->PFB[0x00000000/4] & 0x00000020)
895    {
896        if (((chip->PMC[0x00000000/4] & 0xF0) == 0x20)
897         && ((chip->PMC[0x00000000/4] & 0x0F) >= 0x02))
898        {
899            /*
900             * SDRAM 128 ZX.
901             */
902            chip->RamBandwidthKBytesPerSec = 800000;
903            switch (chip->PFB[0x00000000/4] & 0x03)
904            {
905                case 2:
906                    chip->RamAmountKBytes = 1024 * 4;
907                    break;
908                case 1:
909                    chip->RamAmountKBytes = 1024 * 2;
910                    break;
911                default:
912                    chip->RamAmountKBytes = 1024 * 8;
913                    break;
914            }
915        }
916        else
917        {
918            chip->RamBandwidthKBytesPerSec = 1000000;
919            chip->RamAmountKBytes          = 1024 * 8;
920        }
921    }
922    else
923    {
924        /*
925         * SGRAM 128.
926         */
927        chip->RamBandwidthKBytesPerSec = 1000000;
928        switch (chip->PFB[0x00000000/4] & 0x00000003)
929        {
930            case 0:
931                chip->RamAmountKBytes = 1024 * 8;
932                break;
933            case 2:
934                chip->RamAmountKBytes = 1024 * 4;
935                break;
936            default:
937                chip->RamAmountKBytes = 1024 * 2;
938                break;
939        }
940    }
941    chip->CrystalFreqKHz   = (chip->PEXTDEV[0x00000000/4] & 0x00000040) ? 14318 : 13500;
942    chip->CURSOR           = &(chip->PRAMIN[0x00008000/4 - 0x0800/4]);
943    chip->VBlankBit        = 0x00000100;
944    chip->MaxVClockFreqKHz = 256000;
945    /*
946     * Set chip functions.
947     */
948    chip->Busy            = nv3Busy;
949    chip->ShowHideCursor  = ShowHideCursor;
950    chip->CalcStateExt    = CalcStateExt;
951    chip->LoadStateExt    = LoadStateExt;
952    chip->UnloadStateExt  = UnloadStateExt;
953    chip->SetStartAddress = SetStartAddress;
954    chip->LockUnlock      = nv3LockUnlock;
955}
956int RivaGetConfig
957(
958    RivaPtr pRiva
959)
960{
961    RIVA_HW_INST *chip = &pRiva->riva;
962
963    nv3GetConfig(chip);
964    /*
965     * Fill in FIFO pointers.
966     */
967    chip->Rop    = (RivaRop                 *)&(chip->FIFO[0x00000000/4]);
968    chip->Clip   = (RivaClip                *)&(chip->FIFO[0x00002000/4]);
969    chip->Patt   = (RivaPattern             *)&(chip->FIFO[0x00004000/4]);
970    chip->Pixmap = (RivaPixmap              *)&(chip->FIFO[0x00006000/4]);
971    chip->Blt    = (RivaScreenBlt           *)&(chip->FIFO[0x00008000/4]);
972    chip->Bitmap = (RivaBitmap              *)&(chip->FIFO[0x0000A000/4]);
973    chip->Line   = (RivaLine                *)&(chip->FIFO[0x0000C000/4]);
974    return (0);
975}
976