]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/vga/mga4xx.c
vga: make kernel vga drivers more stupid
[plan9front.git] / sys / src / cmd / aux / vga / mga4xx.c
1 /* Philippe Anel <philippe.anel@noos.fr> 
2         - 2001-08-12 : First release.
3         - 2001-08-15 : Added G450, with source code "adapted from" from Xfree86 4.1.0
4         - 2001-08-23 : Added 'palettedepth 8' and a few 'ultradebug' ...
5         - 2001-08-24 : Removed a possible lock in initialization.
6         - 2001-08-30 : Hey ! The 32 bits mode is PALETIZED (Gamma Control I presume) !
7                                   And it seems plan9 assume the frame buffer is organized in
8                                   Big Endian format ! (+ Fix for the palette init. )
9         - 2001-09-06 : Added Full 2D Accel ! (see drivers in /sys/src/9/pc)
10         - 2001-10-01 : Rid Fix.
11         - 2006-04-01 : Add MGA550 support.
12         - 2006-08-07 : Add support for 16 and 24bits modes.
13                                 HW accel now works for the G200 cards too (see kernel).
14                                 by Leonardo Valencia <leoval@anixcorp.com>
15
16      Greets and Acknowledgements go to :
17         - Sylvain Chipaux <a.k.a. asle>.
18         - Nigel Roles.
19         - Jean Mehat (the man who introduced me into the world of plan9).
20         - Nicolas Stojanovic.
21                 ... and for those who wrote plan9 of course ... :)
22 */      
23
24 #include <u.h>
25 #include <libc.h>
26 #include <bio.h>
27
28 #include "pci.h"
29 #include "vga.h"
30
31 static int       ultradebug = 0;
32
33 /*
34  * Matrox G4xx 3D graphics accelerators
35  */
36 enum {
37         Kilo                    = 1024,
38         Meg                     = 1024*1024,
39         
40         MATROX                  = 0x102B,       /* pci chip manufacturer */
41         MGA550                  = 0x2527, /* pci chip device ids */
42         MGA4XX                  = 0x0525,
43         MGA200                  = 0x0521,
44
45         /* Pci configuration space mapping */
46         PCfgMgaFBAA             = 0x10,         /* Frame buffer Aperture Address */
47         PCfgMgaCAA              = 0x14,         /* Control Aperture Address base */
48         PCfgMgaIAA              = 0x18,         /* ILOAD Aperture base Address */
49         PCfgMgaOption1          = 0x40,         /* Option Register 1 */
50         PCfgMgaOption2          = 0x50,         /* Option Register 2 */
51         PCfgMgaOption3          = 0x54,         /* Option Register 3 */
52         PCfgMgaDevCtrl          = 0x04,         /* Device Control */
53
54         /* control aperture offsets */
55         DMAWIN                  = 0x0000,       /* 7KByte Pseudo-DMA Window */
56
57         STATUS0                 = 0x1FC2,       /* Input Status 0 */
58         STATUS1                 = 0x1FDA,       /* Input Status 1 */
59         
60         SEQIDX                  = 0x1FC4,       /* Sequencer Index */
61         SEQDATA                 = 0x1FC5,       /* Sequencer Data */
62
63         MISC_W                  = 0x1FC2,       /* Misc. WO */
64         MISC_R                  = 0x1FCC,       /* Misc. RO */
65
66         GCTLIDX                 = 0x1FCE,       /* Graphic Controler Index */
67         GCTLDATA                = 0x1FCF,       /* Graphic Controler Data */
68
69         CRTCIDX                 = 0x1FD4,       /* CRTC Index */
70         CRTCDATA                = 0x1FD5,       /* CRTC Data */
71
72         CRTCEXTIDX              = 0x1FDE,       /* CRTC Extension Index */
73         CRTCEXTDATA             = 0x1FDF,       /* CRTC Extension Data */
74         
75         RAMDACIDX               = 0x3C00,       /* RAMDAC registers Index */
76         RAMDACDATA              = 0x3C0A,       /* RAMDAC Indexed Data */
77         RAMDACPALDATA           = 0x3C01,
78
79         ATTRIDX                 = 0x1FC0,       /* Attribute Index */
80         ATTRDATA                = 0x1FC1,       /* Attribute Data */
81
82         CACHEFLUSH              = 0x1FFF,
83
84         C2_CTL                  = 0X3C10,
85         MGA_STATUS              = 0X1E14,
86         Z_DEPTH_ORG             = 0X1C0C,
87         
88         /* ... */
89         Seq_ClockingMode =      0x01,
90                 Dotmode =               (1<<0),
91                 Shftldrt =              (1<<2),
92                 Dotclkrt =              (1<<3),
93                 Shiftfour =             (1<<4),
94                 Scroff =                (1<<5),
95
96         CrtcExt_Horizontcount = 0x01,
97                 Htotal =                (1<<0),
98                 Hblkstr =               (1<<1),
99                 Hsyncstr =              (1<<2),
100                 Hrsten =                (1<<3),
101                 Hsyncoff =              (1<<4),
102                 Vsyncoff =              (1<<5),
103                 Hblkend =               (1<<6),
104                 Vrsten =                (1<<7),
105
106         CrtcExt_Miscellaneous = 0x03,
107                 Mgamode =               (1<<7),
108
109         Dac_Xpixclkctrl =       0x1a,
110                 Pixclksl =              (3<<0),
111                 Pixclkdis =             (1<<2),
112                 Pixpllpdn =             (1<<3),
113
114         Dac_Xpixpllstat =       0x4f,
115                 Pixlock =               (1<<6),
116         
117         Dac_Xpixpllan =         0x45,
118         Dac_Xpixpllbn =         0x49,
119         Dac_Xpixpllcn  =        0x4d,
120
121         Dac_Xpixpllam =         0x44, 
122         Dac_Xpixpllbm =         0x48,
123         Dac_Xpixpllcm =         0x4c,
124
125         Dac_Xpixpllap =         0x46,
126         Dac_Xpixpllbp =         0x4a,
127         Dac_Xpixpllcp =         0x4e,
128
129         Dac_Xmulctrl =          0x19,
130                 ColorDepth =            (7<<0),
131                         _8bitsPerPixel =                0,
132                         _15bitsPerPixel =               1,
133                         _16bitsPerPixel =               2,
134                         _24bitsPerPixel =               3,
135                         _32bitsPerPixelWithOv =         4,
136                         _32bitsPerPixel =               7,
137
138         Dac_Xpanelmode =        0x1f,
139
140         Dac_Xmiscctrl =         0x1e,
141                 Dacpdn =                (1<<0),
142                 Mfcsel =                (3<<1),
143                 Vga8dac =               (1<<3),
144                 Ramcs =                 (1<<4),
145                 Vdoutsel =              (7<<5),
146
147         Dac_Xcurctrl =          0x06,
148                 CursorDis =             0,
149                 Cursor3Color =          1,
150                 CursorXGA =             2,
151                 CursorX11 =             3,
152                 Cursor16Color =         4,
153
154         Dac_Xzoomctrl =         0x38,
155
156         Misc_loaddsel =                 (1<<0),
157         Misc_rammapen =                 (1<<1),
158         Misc_clksel =                   (3<<2),
159         Misc_videodis =                 (1<<4),
160         Misc_hpgoddev =                 (1<<5),
161         Misc_hsyncpol =                 (1<<6),
162         Misc_vsyncpol =                 (1<<7),
163
164         MNP_TABLE_SIZE =        64,
165
166         TRUE =  (1 == 1),
167         FALSE = (1 == 0),
168 };
169
170 typedef struct {
171         Pcidev* pci;
172         int     devid;
173         int     revid;
174         
175         uchar*  mmio;
176         uchar*  mmfb;
177         int     fbsize;
178         ulong   iload;
179
180         uchar   syspll_m;
181         uchar   syspll_n;
182         uchar   syspll_p;
183         uchar   syspll_s;
184
185         uchar   pixpll_m;
186         uchar   pixpll_n;
187         uchar   pixpll_p;
188         uchar   pixpll_s;
189
190         ulong   option1;
191         ulong   option2;
192         ulong   option3;
193
194         ulong   Fneeded;
195
196         /* From plan9.ini ... later */
197         uchar   sdram;
198         uchar   colorkey;
199         uchar   maskkey;
200         ulong   maxpclk;
201
202         uchar   graphics[9];    
203         uchar   attribute[0x14];        
204         uchar   sequencer[5];
205         uchar   crtc[0x19];
206         uchar   crtcext[9];
207
208         ulong   htotal;
209         ulong   hdispend;
210         ulong   hblkstr;
211         ulong   hblkend;
212         ulong   hsyncstr;
213         ulong   hsyncend;
214         ulong   vtotal;
215         ulong   vdispend;
216         ulong   vblkstr;
217         ulong   vblkend;
218         ulong   vsyncstr;
219         ulong   vsyncend;
220         ulong   linecomp;
221         ulong   hsyncsel;
222         ulong   startadd;
223         ulong   offset;
224         ulong   maxscan;
225         ulong   curloc;
226         ulong   prowscan;
227         ulong   currowstr;
228         ulong   currowend;
229         ulong   curoff;
230         ulong   undrow;
231         ulong   curskew;
232         ulong   conv2t4;
233         ulong   interlace;
234         ulong   hsyncdel;
235         ulong   hdispskew;
236         ulong   bytepan;
237         ulong   dotclkrt;
238         ulong   dword;
239         ulong   wbmode;
240         ulong   addwrap;
241         ulong   selrowscan;
242         ulong   cms;
243         ulong   csynccen;
244         ulong   hrsten;
245         ulong   vrsten;
246         ulong   vinten;
247         ulong   vintclr;
248         ulong   hsyncoff;
249         ulong   vsyncoff;
250         ulong   crtcrstN;
251         ulong   mgamode;
252         ulong   scale;
253         ulong   hiprilvl;
254         ulong   maxhipri;
255         ulong   c2hiprilvl;
256         ulong   c2maxhipri;
257         ulong   misc;
258         ulong   crtcprotect;
259         ulong   winsize;
260         ulong   winfreq;
261         
262         ulong   mgaapsize;
263 } Mga;
264
265 static void
266 mgawrite32(Mga* mga, int index, ulong val)
267 {
268         ((ulong*)mga->mmio)[index] = val;
269 }
270
271 static ulong
272 mgaread32(Mga* mga, int index)
273 {
274         return ((ulong*)mga->mmio)[index];
275 }
276
277 static void
278 mgawrite8(Mga* mga, int index, uchar val)
279 {
280         mga->mmio[index] = val;
281 }
282
283 static uchar
284 mgaread8(Mga* mga, int index)
285 {
286         return mga->mmio[index];
287 }
288
289 static uchar
290 seqget(Mga* mga, int index)
291 {
292         mgawrite8(mga, SEQIDX, index);
293         return mgaread8(mga, SEQDATA);
294 }
295
296 static uchar
297 seqset(Mga* mga, int index, uchar set, uchar clr)
298 {
299         uchar   tmp;
300
301         mgawrite8(mga, SEQIDX, index);
302         tmp = mgaread8(mga, SEQDATA);
303         mgawrite8(mga, SEQIDX, index);
304         mgawrite8(mga, SEQDATA, (tmp & ~clr) | set);
305         return tmp;
306 }
307
308 static uchar
309 crtcget(Mga* mga, int index)
310 {
311         mgawrite8(mga, CRTCIDX, index);
312         return mgaread8(mga, CRTCDATA);
313 }
314
315 static uchar
316 crtcset(Mga* mga, int index, uchar set, uchar clr)
317 {
318         uchar   tmp;
319
320         mgawrite8(mga, CRTCIDX, index);
321         tmp = mgaread8(mga, CRTCDATA);
322         mgawrite8(mga, CRTCIDX, index);
323         mgawrite8(mga, CRTCDATA, (tmp & ~clr) | set);
324         return tmp;
325 }
326
327 static uchar
328 crtcextget(Mga* mga, int index)
329 {
330         mgawrite8(mga, CRTCEXTIDX, index);
331         return mgaread8(mga, CRTCEXTDATA);
332 }
333
334 static uchar
335 crtcextset(Mga* mga, int index, uchar set, uchar clr)
336 {
337         uchar   tmp;
338
339         mgawrite8(mga, CRTCEXTIDX, index);
340         tmp = mgaread8(mga, CRTCEXTDATA);
341         mgawrite8(mga, CRTCEXTIDX, index);
342         mgawrite8(mga, CRTCEXTDATA, (tmp & ~clr) | set);
343         return tmp;
344 }
345
346 static uchar
347 dacget(Mga* mga, int index)
348 {
349         mgawrite8(mga, RAMDACIDX, index);
350         return mgaread8(mga, RAMDACDATA);
351 }
352
353 static uchar
354 dacset(Mga* mga, int index, uchar set, uchar clr)
355 {
356         uchar   tmp;
357
358         mgawrite8(mga, RAMDACIDX, index);
359         tmp = mgaread8(mga, RAMDACDATA);
360         mgawrite8(mga, RAMDACIDX, index);
361         mgawrite8(mga, RAMDACDATA, (tmp & ~clr) | set);
362         return  tmp;
363 }
364
365 static uchar
366 gctlget(Mga* mga, int index)
367 {
368         mgawrite8(mga, GCTLIDX, index);
369         return mgaread8(mga, GCTLDATA);
370 }
371
372 static uchar
373 gctlset(Mga* mga, int index, uchar set, uchar clr)
374 {
375         uchar   tmp;
376
377         mgawrite8(mga, GCTLIDX, index);
378         tmp = mgaread8(mga, GCTLDATA);
379         mgawrite8(mga, GCTLIDX, index);
380         mgawrite8(mga, GCTLDATA, (tmp & ~clr) | set);
381         return  tmp;
382 }
383
384 static uchar
385 attrget(Mga* mga, int index)
386 {
387         mgawrite8(mga, ATTRIDX, index);
388         return mgaread8(mga, ATTRDATA);
389 }
390
391 static uchar
392 attrset(Mga* mga, int index, uchar set, uchar clr)
393 {
394         uchar   tmp;
395
396         mgawrite8(mga, ATTRIDX, index);
397         tmp = mgaread8(mga, ATTRDATA);
398         mgawrite8(mga, ATTRIDX, index);
399         mgawrite8(mga, ATTRDATA, (tmp & ~clr) | set);
400         return  tmp;
401 }
402
403 static uchar
404 miscget(Mga* mga)
405 {
406         return mgaread8(mga, MISC_R);
407 }
408
409 static uchar
410 miscset(Mga* mga, uchar set, uchar clr)
411 {
412         uchar   tmp;
413
414         tmp = mgaread8(mga, MISC_R);
415         mgawrite8(mga, MISC_W, (tmp & ~clr) | set);
416         return  tmp;
417 }
418
419 /* ************************************************************ */
420
421 static void
422 dump_all_regs(Mga* mga)
423 {
424         int     i;
425
426         for (i = 0; i < 25; i++)
427                 trace("crtc[%d] = 0x%x\n", i, crtcget(mga, i));
428         for (i = 0; i < 9; i++)
429                 trace("crtcext[%d] = 0x%x\n", i, crtcextget(mga, i));
430         for (i = 0; i < 5; i++)
431                 trace("seq[%d] = 0x%x\n", i, seqget(mga, i));
432         for (i = 0; i < 9; i++)
433                 trace("gctl[%d] = 0x%x\n", i, gctlget(mga, i));
434         trace("misc = 0x%x\n", mgaread8(mga, MISC_R));
435         for (i = 0; i < 0x87; i++)
436                 trace("dac[%d] = 0x%x\n", i, dacget(mga, i));
437 }
438
439 /* ************************************************************ */
440
441 static void
442 dump(Vga* vga, Ctlr* ctlr)
443 {
444         dump_all_regs(vga->private);
445         ctlr->flag |= Fdump;
446 }
447
448 static void
449 setpalettedepth(int depth)
450 {
451         char buf[12];
452
453         if ((depth != 8) && (depth != 6) && (depth != 16))
454                 error("mga: invalid palette depth %d\n", depth);
455
456         snprint(buf, sizeof(buf), "%d", depth);
457         vgactlw("palettedepth", buf);
458 }
459
460 static void
461 mapmga4xx(Vga* vga, Ctlr* ctlr)
462 {
463         uchar*  m;
464         Mga *   mga;
465
466         if(vga->private == nil)
467                 error("%s: g4xxio: no *mga4xx\n", ctlr->name);
468         mga = vga->private;
469
470         vgactlpci(vga->pci);
471         vgactlw("type", "mga4xx");
472         
473         m = segattach(0, "mga4xxmmio", 0, 16*Kilo);
474         if(m == (void*)-1)
475                 error("%s: can't attach mga4xxmmio segment\n", ctlr->name);
476         mga->mmio = m;
477         trace("%s: mmio at %#p\n", ctlr->name, mga->mmio);
478
479         m = segattach(0, "mga4xxscreen", 0, 32*Meg);
480         if(m == (void*)-1) {
481                 mga->mgaapsize = 8*Meg;
482                 m = segattach(0, "mga4xxscreen", 0, 8*Meg);
483                 if(m == (void*)-1)
484                         error("%s: can't attach mga4xxscreen segment\n", ctlr->name);
485         } else {
486                 mga->mgaapsize = 32*Meg;
487         }
488         mga->mmfb = m;
489         trace("%s: frame buffer at %#p\n", ctlr->name, mga->mmfb);
490 }
491
492 static void
493 snarf(Vga* vga, Ctlr* ctlr)
494 {
495         int     i, k, n;
496         uchar * p;
497         uchar   x[16];
498         Pcidev *        pci;
499         Mga *   mga;
500         uchar   crtcext3;
501         uchar   rid;
502
503         trace("%s->snarf\n", ctlr->name);
504         if(vga->private == nil) {
505                 pci = pcimatch(nil, MATROX, MGA4XX);
506                 if(pci == nil)
507                         pci = pcimatch(nil, MATROX, MGA550);
508                 if(pci == nil)
509                         pci = pcimatch(nil, MATROX, MGA200);
510                 if(pci == nil)
511                         error("%s: cannot find matrox adapter\n", ctlr->name);
512
513                 rid = pcicfgr8(pci, PciRID); // PciRID = 0x08
514
515                 trace("%s: G%d%d0 rev %d\n", ctlr->name, 
516                         2*(pci->did==MGA200)
517                         +4*(pci->did==MGA4XX)
518                         +5*(pci->did==MGA550),
519                         rid&0x80 ? 5 : 0,
520                         rid&~0x80);
521                 i = pcicfgr32(pci, PCfgMgaDevCtrl);
522                 if ((i & 2) != 2)
523                         error("%s: Memory Space not enabled ... Aborting ...\n", ctlr->name);   
524
525                 vga->private = alloc(sizeof(Mga));
526                 mga = (Mga*)vga->private;
527                 mga->devid =    pci->did;
528                 mga->revid =    rid;    
529                 mga->pci =      pci;
530
531                 mapmga4xx(vga, ctlr);
532         }
533         else {
534                 mga = (Mga*)vga->private;
535         }
536
537         /* Find out how much memory is here, some multiple of 2Meg */
538
539         /* First Set MGA Mode ... */
540         crtcext3 = crtcextset(mga, 3, 0x80, 0x00);
541
542         p = mga->mmfb;
543         n = (mga->mgaapsize / Meg) / 2;
544         for (i = 0; i < n; i++) {
545                 k = (2*i+1)*Meg;
546                 p[k] = 0;
547                 p[k] = i+1;
548                 *(mga->mmio + CACHEFLUSH) = 0;
549                 x[i] = p[k];
550                 trace("x[%d]=%d\n", i, x[i]);
551         }
552         for(i = 1; i < n; i++)
553                 if(x[i] != i+1)
554                         break;
555         vga->vmz = mga->fbsize = 2*i*Meg;
556         trace("probe found %d megabytes\n", 2*i);
557
558         crtcextset(mga, 3, crtcext3, 0xff);
559
560         ctlr->flag |= Fsnarf;
561 }
562
563 static void
564 options(Vga* vga, Ctlr* ctlr)
565 {
566         if(vga->virtx & 127)
567                 vga->virtx = (vga->virtx+127)&~127;
568         ctlr->flag |= Foptions;
569 }
570
571 /* ************************************************************ */
572
573 static void 
574 G450ApplyPFactor(Mga*, uchar ucP, ulong *pulFIn)
575 {
576         if(!(ucP & 0x40))
577         {
578                 *pulFIn = *pulFIn / (2L << (ucP & 3));
579         }
580 }
581
582
583 static void 
584 G450RemovePFactor(Mga*, uchar ucP, ulong *pulFIn)
585 {
586         if(!(ucP & 0x40))
587         {
588                 *pulFIn = *pulFIn * (2L << (ucP & 3));
589         }
590 }
591
592 static void 
593 G450CalculVCO(Mga*, ulong ulMNP, ulong *pulF)
594 {
595         uchar ucM, ucN;
596
597         ucM = (uchar)((ulMNP >> 16) & 0xff);
598         ucN = (uchar)((ulMNP >>  8) & 0xff);
599
600         *pulF = (27000 * (2 * (ucN + 2)) + ((ucM + 1) >> 1)) / (ucM + 1);
601         trace("G450CalculVCO: ulMNP %lx, pulF %ld\n", ulMNP, *pulF);
602 }
603
604
605 static void 
606 G450CalculDeltaFreq(Mga*, ulong ulF1, ulong ulF2, ulong *pulDelta)
607 {
608         if(ulF2 < ulF1)
609         {
610                 *pulDelta = ((ulF1 - ulF2) * 1000) / ulF1;
611         }
612         else
613         {
614                 *pulDelta = ((ulF2 - ulF1) * 1000) / ulF1;
615         }
616         trace("G450CalculDeltaFreq: ulF1 %ld, ulF2 %ld, pulDelta %ld\n", ulF1, ulF2, *pulDelta);
617 }
618
619 static void 
620 G450FindNextPLLParam(Mga* mga, ulong ulFout, ulong *pulPLLMNP)
621 {
622         uchar ucM, ucN, ucP, ucS;
623         ulong ulVCO, ulVCOMin;
624
625         ucM = (uchar)((*pulPLLMNP >> 16) & 0xff);
626         /* ucN = (uchar)((*pulPLLMNP >>  8) & 0xff); */
627         ucP = (uchar)(*pulPLLMNP &  0x43);
628
629         ulVCOMin = 256000;
630
631         if(ulVCOMin >= (255L * 8000))
632         {
633                 ulVCOMin = 230000;
634         }
635
636         if((ucM == 9) && (ucP & 0x40))
637         {
638                 *pulPLLMNP = 0xffffffff;
639         } else if (ucM == 9)
640         {
641                 if(ucP)
642                 {
643                         ucP--;
644                 }
645                 else
646                 {
647                         ucP = 0x40;
648                 }
649                 ucM = 0;
650         }
651         else
652         {
653                 ucM++;
654         }
655
656         ulVCO = ulFout;
657
658         G450RemovePFactor(mga, ucP, &ulVCO);
659
660         if(ulVCO < ulVCOMin)
661         {
662                 *pulPLLMNP = 0xffffffff;
663         }
664
665         if(*pulPLLMNP != 0xffffffff)
666         {
667                 ucN = (uchar)(((ulVCO * (ucM+1) + 27000)/(27000 * 2)) - 2);
668
669                 ucS = 5;
670                 if(ulVCO < 1300000) ucS = 4;
671                 if(ulVCO < 1100000) ucS = 3;
672                 if(ulVCO <  900000) ucS = 2;
673                 if(ulVCO <  700000) ucS = 1;
674                 if(ulVCO <  550000) ucS = 0;
675
676                 ucP |= (uchar)(ucS << 3);
677
678                 *pulPLLMNP &= 0xff000000;
679                 *pulPLLMNP |= (ulong)ucM << 16;
680                 *pulPLLMNP |= (ulong)ucN << 8;
681                 *pulPLLMNP |= (ulong)ucP;
682         }
683 }
684
685 static void 
686 G450FindFirstPLLParam(Mga* mga, ulong ulFout, ulong *pulPLLMNP)
687 {
688         uchar ucP;
689         ulong ulVCO;
690         ulong ulVCOMax;
691
692         /* Default value */
693         ulVCOMax = 1300000;
694
695         if(ulFout > (ulVCOMax/2))
696         {
697                 ucP = 0x40;
698                 ulVCO = ulFout;
699         }
700         else
701         {
702                 ucP = 3;
703                 ulVCO = ulFout;
704                 G450RemovePFactor(mga, ucP, &ulVCO);
705                 while(ucP && (ulVCO > ulVCOMax))
706                 {
707                         ucP--;
708                         ulVCO = ulFout;
709                         G450RemovePFactor(mga, ucP, &ulVCO);
710                 }
711         }
712
713         if(ulVCO > ulVCOMax)
714         {
715                 *pulPLLMNP = 0xffffffff;
716         }
717         else
718         {
719                 /* Pixel clock: 1 */
720                 *pulPLLMNP = (1 << 24) + 0xff0000 + ucP;
721                 G450FindNextPLLParam(mga, ulFout, pulPLLMNP);
722         }
723 }
724
725
726 static void 
727 G450WriteMNP(Mga* mga, ulong ulMNP)
728 {
729         if (0) trace("G450WriteMNP : 0x%lx\n", ulMNP);
730         dacset(mga, Dac_Xpixpllcm, (uchar)(ulMNP >> 16), 0xff);
731         dacset(mga, Dac_Xpixpllcn, (uchar)(ulMNP >>  8), 0xff);   
732         dacset(mga, Dac_Xpixpllcp, (uchar)ulMNP, 0xff);   
733 }
734
735
736 static void 
737 G450CompareMNP(Mga* mga, ulong ulFout, ulong ulMNP1,
738                             ulong ulMNP2, long *pulResult)
739 {
740         ulong ulFreq, ulDelta1, ulDelta2;
741
742         G450CalculVCO(mga, ulMNP1, &ulFreq);
743         G450ApplyPFactor(mga, (uchar) ulMNP1, &ulFreq);
744         G450CalculDeltaFreq(mga, ulFout, ulFreq, &ulDelta1);
745
746         G450CalculVCO(mga, ulMNP2, &ulFreq);
747         G450ApplyPFactor(mga, (uchar) ulMNP2, &ulFreq);
748         G450CalculDeltaFreq(mga, ulFout, ulFreq, &ulDelta2);
749
750         if(ulDelta1 < ulDelta2)
751         {
752                 *pulResult = -1;
753         }
754         else if(ulDelta1 > ulDelta2)
755         {
756                 *pulResult = 1;
757         }
758         else
759         {
760                 *pulResult = 0;
761         }
762
763         if((ulDelta1 <= 5) && (ulDelta2 <= 5))
764         {
765                 if((ulMNP1 & 0xff0000) < (ulMNP2 & 0xff0000))
766                 {
767                         *pulResult = -1;
768                 }
769                 else if((ulMNP1 & 0xff0000) > (ulMNP2 & 0xff0000))
770                 {
771                         *pulResult = 1;
772                 }
773         }
774 }
775
776
777 static void 
778 G450IsPllLocked(Mga* mga, int *lpbLocked)
779 {
780         ulong ulFallBackCounter, ulLockCount, ulCount;
781         uchar  ucPLLStatus;
782
783         /* Pixel PLL */
784         mgawrite8(mga, 0x3c00, 0x4f);    
785         ulFallBackCounter = 0;
786
787         do 
788         {
789                 ucPLLStatus = mgaread8(mga, 0x3c0a);
790                 if (0) trace("ucPLLStatus[1] : 0x%x\n", ucPLLStatus);
791                 ulFallBackCounter++;
792         } while(!(ucPLLStatus & 0x40) && (ulFallBackCounter < 1000));
793
794         ulLockCount = 0;
795         if(ulFallBackCounter < 1000)
796         {
797                 for(ulCount = 0; ulCount < 100; ulCount++)
798                 {
799                         ucPLLStatus = mgaread8(mga, 0x3c0a);
800                         if (0) trace("ucPLLStatus[2] : 0x%x\n", ucPLLStatus);
801                         if(ucPLLStatus & 0x40)
802                         {
803                                 ulLockCount++;
804                         }
805                 }
806         }
807
808         *lpbLocked = ulLockCount >= 90;
809 }
810
811 static void 
812 G450SetPLLFreq(Mga* mga, long f_out) 
813 {
814         int bFoundValidPLL;
815         int bLocked;
816         ulong ulMaxIndex;
817         ulong ulMNP;
818         ulong ulMNPTable[MNP_TABLE_SIZE];
819         ulong ulIndex;
820         ulong ulTryMNP;
821         long lCompareResult;
822
823         trace("f_out : %ld\n", f_out);
824
825         G450FindFirstPLLParam(mga, f_out, &ulMNP);
826         ulMNPTable[0] = ulMNP;
827         G450FindNextPLLParam(mga, f_out, &ulMNP);
828         ulMaxIndex = 1;
829         while(ulMNP != 0xffffffff)
830         {
831                 int ulIndex;
832                 int bSkipValue;
833
834                 bSkipValue = FALSE;
835                 if(ulMaxIndex == MNP_TABLE_SIZE)
836                 {
837                         G450CompareMNP(mga, f_out, ulMNP, ulMNPTable[MNP_TABLE_SIZE - 1],
838                                        &lCompareResult);
839
840                         if(lCompareResult > 0)
841                         {
842                                 bSkipValue = TRUE;
843                         }
844                         else
845                         {
846                                 ulMaxIndex--;
847                         }
848                 }
849
850                 if(!bSkipValue)
851                 {
852                         for(ulIndex = ulMaxIndex; !bSkipValue && (ulIndex > 0); ulIndex--)
853                         {
854                                 G450CompareMNP(mga, f_out, ulMNP, ulMNPTable[ulIndex - 1],
855                                                &lCompareResult);
856
857                                 if(lCompareResult < 0)
858                                 {
859                                         ulMNPTable[ulIndex] = ulMNPTable[ulIndex - 1];
860                                 }
861                                 else
862                                 {
863                                         break;
864                                 }
865                         }
866                         ulMNPTable[ulIndex] = ulMNP;
867                         ulMaxIndex++;
868                 }
869
870                 G450FindNextPLLParam(mga, f_out, &ulMNP);
871         }
872
873         bFoundValidPLL = FALSE;
874         ulMNP = 0;
875
876         for(ulIndex = 0; !bFoundValidPLL && (ulIndex < ulMaxIndex); ulIndex++)
877         {
878                 ulTryMNP = ulMNPTable[ulIndex];
879
880                 {
881                         bLocked = TRUE;
882                         if((ulMNPTable[ulIndex] & 0xff00) < 0x300 ||
883                            (ulMNPTable[ulIndex] & 0xff00) > 0x7a00)
884                         {
885                                 bLocked = FALSE;
886                         }
887
888                         if(bLocked)
889                         {
890                                 G450WriteMNP(mga, ulTryMNP - 0x300);
891                                 G450IsPllLocked(mga, &bLocked);
892                         }     
893
894                         if(bLocked)
895                         {
896                                 G450WriteMNP(mga, ulTryMNP + 0x300);
897                                 G450IsPllLocked(mga, &bLocked);
898                         }     
899
900                         if(bLocked)
901                         {
902                                 G450WriteMNP(mga, ulTryMNP - 0x200);
903                                 G450IsPllLocked(mga, &bLocked);
904                         }     
905
906                         if(bLocked)
907                         {
908                                 G450WriteMNP(mga, ulTryMNP + 0x200);
909                                 G450IsPllLocked(mga, &bLocked);
910                         }     
911
912                         if(bLocked)
913                         {
914                                 G450WriteMNP(mga, ulTryMNP - 0x100);
915                                 G450IsPllLocked(mga, &bLocked);
916                         }     
917
918                         if(bLocked)
919                         {
920                                 G450WriteMNP(mga, ulTryMNP + 0x100);
921                                 G450IsPllLocked(mga, &bLocked);
922                         }     
923
924                         if(bLocked)
925                         {
926                                 G450WriteMNP(mga, ulTryMNP);
927                                 G450IsPllLocked(mga, &bLocked);
928                         }     
929                         else if(!ulMNP)
930                         {
931                                 G450WriteMNP(mga, ulTryMNP);
932                                 G450IsPllLocked(mga, &bLocked);
933                                 if(bLocked)
934                                 {
935                                         ulMNP = ulMNPTable[ulIndex]; 
936                                 }
937                                 bLocked = FALSE;
938                         }
939
940                         if(bLocked)
941                         {
942                                 bFoundValidPLL = TRUE;
943                         }
944                 }
945         }
946
947         if(!bFoundValidPLL)
948         {
949                 if(ulMNP)
950                 {
951                         G450WriteMNP(mga, ulMNP);
952                 }
953                 else
954                 {
955                         G450WriteMNP(mga, ulMNPTable[0]);
956                 }
957         }
958 }
959
960
961 /* ************************************************************ */
962
963 /*
964         calcclock - Calculate the PLL settings (m, n, p, s).
965 */
966 static double
967 g400_calcclock(Mga* mga, long Fneeded)
968 {
969         double  Fpll;
970         double  Fvco;
971         double  Fref;
972         int             pixpll_m_min;
973         int             pixpll_m_max;
974         int             pixpll_n_min;
975         int             pixpll_n_max;
976         int             pixpll_p_max;
977         double  Ferr, Fcalc;
978         int             m, n, p;
979         
980         if (mga->devid == MGA4XX || mga->devid == MGA550) {
981                 /* These values are taken from Matrox G400 Specification - p 4-91 */
982                 Fref                    = 27000000.0;
983                 pixpll_n_min    = 7;
984                 pixpll_n_max    = 127;
985                 pixpll_m_min    = 1;
986                 pixpll_m_max    = 31;
987                 pixpll_p_max    = 7;
988         } else {                                /* MGA200 */
989                 /* These values are taken from Matrox G200 Specification - p 4-77 */
990                 //Fref                  = 14318180.0;
991                 Fref                    = 27050500.0;
992                 pixpll_n_min    = 7;
993                 pixpll_n_max    = 127;
994                 pixpll_m_min    = 1;
995                 pixpll_m_max    = 6;
996                 pixpll_p_max    = 7;
997         }
998
999         Fvco = ( double ) Fneeded;
1000         for (p = 0;  p <= pixpll_p_max && Fvco < mga->maxpclk; p = p * 2 + 1, Fvco *= 2.0)
1001                 ;
1002         mga->pixpll_p = p;
1003
1004         Ferr = Fneeded;
1005         for ( m = pixpll_m_min ; m <= pixpll_m_max ; m++ )
1006                 for ( n = pixpll_n_min; n <= pixpll_n_max; n++ )
1007                 { 
1008                         Fcalc = Fref * (n + 1) / (m + 1) ;
1009
1010                         /*
1011                          * Pick the closest frequency.
1012                          */
1013                         if ( labs(Fcalc - Fvco) < Ferr ) {
1014                                 Ferr = abs(Fcalc - Fvco);
1015                                 mga->pixpll_m = m;
1016                                 mga->pixpll_n = n;
1017                         }
1018                 }
1019         
1020         Fvco = Fref * (mga->pixpll_n + 1) / (mga->pixpll_m + 1);
1021
1022         if (mga->devid == MGA4XX || mga->devid == MGA550) {
1023                 if ( (50000000.0 <= Fvco) && (Fvco < 110000000.0) )
1024                         mga->pixpll_p |= 0;     
1025                 if ( (110000000.0 <= Fvco) && (Fvco < 170000000.0) )
1026                         mga->pixpll_p |= (1<<3);        
1027                 if ( (170000000.0 <= Fvco) && (Fvco < 240000000.0) )
1028                         mga->pixpll_p |= (2<<3);        
1029                 if ( (300000000.0 <= Fvco) )
1030                         mga->pixpll_p |= (3<<3);        
1031         } else {
1032                 if ( (50000000.0 <= Fvco) && (Fvco < 100000000.0) )
1033                         mga->pixpll_p |= 0;     
1034                 if ( (100000000.0 <= Fvco) && (Fvco < 140000000.0) )
1035                         mga->pixpll_p |= (1<<3);        
1036                 if ( (140000000.0 <= Fvco) && (Fvco < 180000000.0) )
1037                         mga->pixpll_p |= (2<<3);        
1038                 if ( (250000000.0 <= Fvco) )
1039                         mga->pixpll_p |= (3<<3);        
1040         }
1041         
1042         Fpll = Fvco / (p + 1);
1043
1044         return Fpll;
1045 }
1046
1047 /* ************************************************************ */
1048
1049 static void
1050 init(Vga* vga, Ctlr* ctlr)
1051 {
1052         Mode*   mode;
1053         Mga*    mga;
1054         double  Fpll;
1055         Ctlr*   c;
1056         int     i;
1057         ulong   t;
1058         int     bppShift;
1059
1060         mga = vga->private;
1061         mode = vga->mode;
1062
1063         trace("mga mmio at %#p\n", mga->mmio);
1064
1065         ctlr->flag |= Ulinear;
1066
1067         /*
1068          * Set the right bppShitf based on depth
1069          */
1070
1071         switch(mode->z) {
1072         case 8: 
1073                 bppShift = 0;
1074                 break;
1075         case 16:
1076                 bppShift = 1;
1077                 break;
1078         case 24:
1079                 bppShift = 0;
1080                 break;
1081         case 32:
1082                 bppShift = 2;
1083                 break;
1084         default:
1085                 bppShift = 0;
1086                 error("depth %d not supported !\n", mode->z);
1087         }
1088
1089         if (mode->interlace)
1090                 error("interlaced mode not supported !\n");
1091
1092         trace("%s: Initializing mode %dx%dx%d on %s\n", ctlr->name, mode->x, mode->y, mode->z, mode->type);
1093         trace("%s: Suggested Dot Clock : %d\n",         ctlr->name, mode->frequency);
1094         trace("%s: Horizontal Total = %d\n",            ctlr->name, mode->ht);
1095         trace("%s: Start Horizontal Blank = %d\n", ctlr->name, mode->shb);
1096         trace("%s: End Horizontal Blank = %d\n",        ctlr->name, mode->ehb);
1097         trace("%s: Vertical Total = %d\n",              ctlr->name, mode->vt);
1098         trace("%s: Vertical Retrace Start = %d\n",      ctlr->name, mode->vrs);
1099         trace("%s: Vertical Retrace End = %d\n",        ctlr->name, mode->vre);
1100         trace("%s: Start Horizontal Sync = %d\n",       ctlr->name, mode->shs);
1101         trace("%s: End Horizontal Sync = %d\n",         ctlr->name, mode->ehs);
1102         trace("%s: HSync = %c\n",                       ctlr->name, mode->hsync);
1103         trace("%s: VSync = %c\n",                               ctlr->name, mode->vsync);
1104         trace("%s: Interlace = %d\n",                   ctlr->name, mode->interlace);
1105
1106         /* TODO : G400 Max : 360000000 */
1107         if (mga->devid == MGA4XX || mga->devid == MGA550)
1108                 mga->maxpclk    = 300000000;
1109         else
1110                 mga->maxpclk    = 250000000;
1111
1112         if (mode->frequency < 50000)
1113                 error("mga: Too little Frequency %d : Minimum supported by PLL is %d\n", 
1114                         mode->frequency, 50000);
1115
1116         if (mode->frequency > mga->maxpclk)
1117                 error("mga: Too big Frequency %d : Maximum supported by PLL is %ld\n",
1118                         mode->frequency, mga->maxpclk);
1119         
1120         trace("mga: revision ID is %x\n", mga->revid);
1121         if ((mga->devid == MGA200) || ((mga->devid == MGA4XX) && (mga->revid & 0x80) == 0x00)) {
1122                 /* Is it G200/G400 or G450 ? */
1123                 Fpll = g400_calcclock(mga, mode->frequency);
1124                 trace("Fpll set to %f\n", Fpll);
1125                 trace("pixclks : n = %d m = %d p = %d\n", mga->pixpll_n, mga->pixpll_m, mga->pixpll_p & 0x7);
1126         } else
1127                 mga->Fneeded = mode->frequency;
1128
1129         trace("PCI Option1 = 0x%x\n", pcicfgr32(mga->pci, PCfgMgaOption1));
1130         trace("PCI Option2 = 0x%x\n", pcicfgr32(mga->pci, PCfgMgaOption2));
1131         trace("PCI Option3 = 0x%x\n", pcicfgr32(mga->pci, PCfgMgaOption3));
1132
1133         mga->htotal =                   (mode->ht >> 3) - 5;
1134         mga->hdispend =         (mode->x >> 3) - 1;
1135         mga->hblkstr =          mga->hdispend;          /* (mode->shb >> 3); */
1136         mga->hblkend =          mga->htotal + 4;                /* (mode->ehb >> 3); */
1137         mga->hsyncstr =         (mode->shs >> 3) - 1;   // Was (mode->shs >> 3);
1138         mga->hsyncend =         (mode->ehs >> 3) - 1;   // Was (mode->ehs >> 3);
1139         mga->hsyncdel =                 0;
1140         mga->vtotal =                   mode->vt - 2;
1141         mga->vdispend =                 mode->y - 1;
1142         mga->vblkstr =          mode->y - 1;
1143         mga->vblkend =          mode->vt - 1;
1144         mga->vsyncstr =                 mode->vrs;
1145         mga->vsyncend =                 mode->vre;
1146         mga->linecomp =         mode->y;
1147         mga->hsyncsel =                 0;                                      /* Do not double lines ... */
1148         mga->startadd =         0;
1149         mga->offset =           (mode->z==24) ? (vga->virtx * 3) >> (4 - bppShift) : vga->virtx >> (4-bppShift);
1150         /* No Zoom */
1151         mga->maxscan =          0;
1152         /* Not used in Power Graphic mode */
1153         mga->curloc =                   0;
1154         mga->prowscan =                 0;
1155         mga->currowstr =                0;
1156         mga->currowend =                0;
1157         mga->curoff =           1;
1158         mga->undrow =           0;
1159         mga->curskew =          0;
1160         mga->conv2t4 =          0;
1161         mga->interlace =                0;
1162         mga->hdispskew =                0;
1163         mga->bytepan =          0;
1164         mga->dotclkrt =                 0;
1165         mga->dword =                    0;
1166         mga->wbmode =           1;
1167         mga->addwrap =          0;      /* Not Used ! */
1168         mga->selrowscan =               1;
1169         mga->cms =                      1;
1170         mga->csynccen =         0;      /* Disable composite sync */
1171
1172         /* VIDRST Pin */
1173         mga->hrsten =                   0;      // Was 1;
1174         mga->vrsten =                   0;      // Was 1;
1175
1176         /* vertical interrupt control ... disabled */
1177         mga->vinten =           1;
1178         mga->vintclr =          0;
1179
1180         /* Let [hv]sync run freely */
1181         mga->hsyncoff =         0;
1182         mga->vsyncoff =         0;
1183
1184         mga->crtcrstN =         1;
1185
1186         mga->mgamode =          1;
1187         mga->scale   =          (mode->z == 24) ? ((1 << bppShift)*3)-1 : (1 << bppShift)-1;
1188         
1189         mga->crtcprotect =      1;
1190         mga->winsize =          0;
1191         mga->winfreq =          0;
1192
1193         if ((mga->htotal == 0)
1194             || (mga->hblkend <= (mga->hblkstr + 1))
1195             || ((mga->htotal - mga->hdispend) == 0)
1196             || ((mga->htotal - mga->bytepan + 2) <= mga->hdispend)
1197             || (mga->hsyncstr <= (mga->hdispend + 2))
1198             || (mga->vtotal == 0))
1199         {
1200                 error("Invalid Power Graphic Mode :\n"
1201                       "mga->htotal = %ld\n"
1202                       "mga->hdispend = %ld\n"
1203                       "mga->hblkstr = %ld\n"
1204                       "mga->hblkend = %ld\n"
1205                       "mga->hsyncstr = %ld\n"
1206                       "mga->hsyncend = %ld\n"
1207                       "mga->hsyncdel = %ld\n"
1208                       "mga->vtotal = %ld\n"
1209                       "mga->vdispend = %ld\n"
1210                       "mga->vblkstr = %ld\n"
1211                       "mga->vblkend = %ld\n"
1212                       "mga->vsyncstr = %ld\n"
1213                       "mga->vsyncend = %ld\n"
1214                       "mga->linecomp = %ld\n",
1215                       mga->htotal,
1216                       mga->hdispend,
1217                       mga->hblkstr,
1218                       mga->hblkend,
1219                       mga->hsyncstr,
1220                       mga->hsyncend,
1221                       mga->hsyncdel,
1222                       mga->vtotal,
1223                       mga->vdispend,
1224                       mga->vblkstr,
1225                       mga->vblkend,
1226                       mga->vsyncstr,
1227                       mga->vsyncend,
1228                       mga->linecomp
1229                       );
1230         }
1231
1232         mga->hiprilvl = 0;
1233         mga->maxhipri = 0;
1234         mga->c2hiprilvl = 0;
1235         mga->c2maxhipri = 0;
1236
1237         mga->misc = ((mode->hsync != '-')?0:(1<<6)) | ((mode->vsync != '-')?0:(1<<7));
1238
1239         trace("mga->htotal = %ld\n"
1240                       "mga->hdispend = %ld\n"
1241                       "mga->hblkstr = %ld\n"
1242                       "mga->hblkend = %ld\n"
1243                       "mga->hsyncstr = %ld\n"
1244                       "mga->hsyncend = %ld\n"
1245                       "mga->hsyncdel = %ld\n"
1246                       "mga->vtotal = %ld\n"
1247                       "mga->vdispend = %ld\n"
1248                       "mga->vblkstr = %ld\n"
1249                       "mga->vblkend = %ld\n"
1250                       "mga->vsyncstr = %ld\n"
1251                       "mga->vsyncend = %ld\n"
1252                       "mga->linecomp = %ld\n",
1253                       mga->htotal,
1254                       mga->hdispend,
1255                       mga->hblkstr,
1256                       mga->hblkend,
1257                       mga->hsyncstr,
1258                       mga->hsyncend,
1259                       mga->hsyncdel,
1260                       mga->vtotal,
1261                       mga->vdispend,
1262                       mga->vblkstr,
1263                       mga->vblkend,
1264                       mga->vsyncstr,
1265                       mga->vsyncend,
1266                       mga->linecomp
1267                       );        
1268
1269         mga->crtc[0x00] = 0xff & mga->htotal;
1270
1271         mga->crtc[0x01] = 0xff & mga->hdispend;
1272
1273         mga->crtc[0x02] = 0xff & mga->hblkstr;
1274
1275         mga->crtc[0x03] = (0x1f & mga->hblkend) 
1276                 | ((0x03 & mga->hdispskew) << 5)
1277                 | 0x80  /* cf 3-304 */
1278                 ;
1279
1280         mga->crtc[0x04] = 0xff & mga->hsyncstr;
1281
1282         mga->crtc[0x05] = (0x1f & mga->hsyncend) 
1283                 | ((0x03 & mga->hsyncdel) << 5) 
1284                 | ((0x01 & (mga->hblkend >> 5)) << 7)
1285                 ;
1286
1287         mga->crtc[0x06] = 0xff & mga->vtotal;
1288
1289         t = ((0x01 & (mga->vtotal >> 8)) << 0)
1290           | ((0x01 & (mga->vdispend >> 8)) << 1)
1291           | ((0x01 & (mga->vsyncstr >> 8)) << 2)
1292           | ((0x01 & (mga->vblkstr >> 8)) << 3)
1293           | ((0x01 & (mga->linecomp >> 8)) << 4)
1294           | ((0x01 & (mga->vtotal >> 9)) << 5)
1295           | ((0x01 & (mga->vdispend >> 9)) << 6)
1296           | ((0x01 & (mga->vsyncstr >> 9)) << 7)
1297           ;
1298         mga->crtc[0x07] = 0xff & t;
1299
1300         mga->crtc[0x08] = (0x1f & mga->prowscan) 
1301                 | ((0x03 & mga->bytepan) << 5)
1302                 ;
1303
1304         mga->crtc[0x09] = (0x1f & mga->maxscan) 
1305                 | ((0x01 & (mga->vblkstr >> 9)) << 5)
1306                 | ((0x01 & (mga->linecomp >> 9)) << 6)
1307                 | ((0x01 & mga->conv2t4) << 7)
1308                 ;
1309
1310         mga->crtc[0x0a] = (0x1f & mga->currowstr)
1311                 | ((0x01 & mga->curoff) << 5)
1312                 ;
1313
1314         mga->crtc[0x0b] = (0x1f & mga->currowend)
1315                 | ((0x03 & mga->curskew) << 5)
1316                 ;
1317
1318         mga->crtc[0x0c] = 0xff & (mga->startadd >> 8);
1319
1320         mga->crtc[0x0d] = 0xff & mga->startadd;
1321
1322         mga->crtc[0x0e] = 0xff & (mga->curloc >> 8);
1323
1324         mga->crtc[0x0f] = 0xff & mga->curloc;
1325
1326         mga->crtc[0x10] = 0xff & mga->vsyncstr;
1327
1328         mga->crtc[0x11] = (0x0f & mga->vsyncend)
1329                 | ((0x01 & mga->vintclr) << 4)
1330                 | ((0x01 & mga->vinten) << 5)
1331                 | ((0x01 & mga->crtcprotect) << 7)
1332                 ;
1333
1334         mga->crtc[0x12] = 0xff & mga->vdispend;
1335
1336         mga->crtc[0x13] = 0xff & mga->offset;
1337
1338         mga->crtc[0x14] = 0x1f & mga->undrow;   /* vga only */
1339
1340         mga->crtc[0x15] = 0xff & mga->vblkstr;
1341
1342         mga->crtc[0x16] = 0xff & mga->vblkend;
1343
1344         mga->crtc[0x17] = ((0x01 & mga->cms) << 0)
1345                 | ((0x01 & mga->selrowscan) << 1)
1346                 | ((0x01 & mga->hsyncsel) << 2)
1347                 | ((0x01 & mga->addwrap) << 5)
1348                 | ((0x01 & mga->wbmode) << 6)
1349                 | ((0x01 & mga->crtcrstN) << 7)
1350                 ;
1351
1352         mga->crtc[0x18] = 0xff & mga->linecomp;
1353         
1354         mga->crtcext[0] = (0x0f & (mga->startadd >> 16))
1355                 | ((0x03 & (mga->offset >> 8)) << 4)
1356                 | ((0x01 & (mga->startadd >> 20)) << 6)
1357                 | ((0x01 & mga->interlace) << 7)
1358                 ;
1359
1360         mga->crtcext[1] = ((0x01 & (mga->htotal >> 8)) << 0)
1361                 | ((0x01 & (mga->hblkstr >> 8)) << 1)
1362                 | ((0x01 & (mga->hsyncstr >> 8)) << 2)
1363                 | ((0x01 & mga->hrsten) << 3)
1364                 | ((0x01 & mga->hsyncoff) << 4)
1365                 | ((0x01 & mga->vsyncoff) << 5)
1366                 | ((0x01 & (mga->hblkend >> 6)) << 6)
1367                 | ((0x01 & mga->vrsten) << 7)
1368                 ;
1369
1370         mga->crtcext[2] = ((0x03 & (mga->vtotal >> 10)) << 0)
1371                 | ((0x01 & (mga->vdispend >> 10)) << 2)
1372                 | ((0x03 & (mga->vblkstr >> 10)) << 3)
1373                 | ((0x03 & (mga->vsyncstr >> 10)) << 5)
1374                 | ((0x01 & (mga->linecomp >> 10)) << 7)
1375                 ;
1376
1377         mga->crtcext[3] = ((0x07 & mga->scale) << 0)
1378                 | ((0x01 & mga->csynccen) << 6)
1379                 | ((0x01 & mga->mgamode) << 7)
1380                 ;
1381
1382         mga->crtcext[4] = 0;    /* memory page ... not used in Power Graphic Mode */
1383
1384         mga->crtcext[5] = 0;    /* Not used in non-interlaced mode */
1385
1386         mga->crtcext[6] = ((0x07 & mga->hiprilvl) << 0)
1387                 | ((0x07 & mga->maxhipri) << 4)
1388                 ;
1389
1390         mga->crtcext[7] = ((0x07 & mga->winsize) << 1)
1391                 | ((0x07 & mga->winfreq) << 5)
1392                 ;
1393
1394         mga->crtcext[8] = (0x01 & (mga->startadd >> 21)) << 0;
1395
1396         /* Initialize Sequencer */
1397         mga->sequencer[0] = 0;
1398         mga->sequencer[1] = 0;
1399         mga->sequencer[2] = 0x03;
1400         mga->sequencer[3] = 0;
1401         mga->sequencer[4] = 0x02;
1402
1403         /* Graphic Control registers are ignored when not using 0xA0000 aperture */     
1404         for (i = 0; i < 9; i++)
1405                 mga->graphics[i] = 0;   
1406
1407         /* The Attribute Controler is not available in Power Graphics mode */
1408         for (i = 0; i < 0x15; i++)
1409                 mga->attribute[i] = i;  
1410
1411         /* disable vga load (want to do fields in different order) */
1412         for(c = vga->link; c; c = c->link)
1413                 if (strncmp(c->name, "vga", 3) == 0)
1414                         c->load = nil;
1415 }
1416
1417 static void
1418 load(Vga* vga, Ctlr* ctlr)
1419 {
1420         Mga*    mga;
1421         int     i;
1422         uchar*  p;
1423         Mode*   mode;
1424         uchar   cursor;
1425
1426         mga = vga->private;
1427         mode = vga->mode;
1428
1429         trace("mga: Loading ...\n");
1430         dump_all_regs(mga);
1431
1432         if (mode->z == 8)
1433                 setpalettedepth(mode->z);
1434
1435         trace("mga mmio at %#p\n", mga->mmio);
1436         trace("mga: loading vga registers ...\n" );
1437         if (ultradebug) Bflush(&stdout);
1438
1439         /* Initialize Sequencer registers */
1440         for(i = 0; i < 5; i++)
1441                 seqset(mga, i, mga->sequencer[i], 0xff);
1442
1443         /* Initialize Attribute register */
1444         for(i = 0; i < 0x15; i++)
1445                 attrset(mga, i, mga->attribute[i], 0xff);
1446
1447         /* Initialize Graphic Control registers */
1448         for(i = 0; i < 9; i++)
1449                 gctlset(mga, i, mga->graphics[i], 0xff);
1450
1451         /* Wait VSYNC */
1452         while (mgaread8(mga, STATUS1) & 0x08);
1453         while (! (mgaread8(mga, STATUS1) & ~0x08));
1454
1455         /* Turn off the video. */
1456         seqset(mga, Seq_ClockingMode, Scroff, 0);
1457
1458         /* Crtc2 Off */
1459         mgawrite32(mga, C2_CTL, 0);
1460
1461         /* Disable Cursor */
1462         cursor = dacset(mga, Dac_Xcurctrl, CursorDis, 0xff);
1463
1464         /* Pixel Pll UP and set Pixel clock source to Pixel Clock PLL */
1465         dacset(mga, Dac_Xpixclkctrl, 0x01 | 0x08, 0x0f);
1466
1467         trace("mga: waiting for the clock source becomes stable ...\n");
1468         while ((dacget(mga, Dac_Xpixpllstat) & Pixlock) != Pixlock)
1469                 ;
1470         trace("mga: pixpll locked !\n");
1471         if (ultradebug) Bflush(&stdout);
1472
1473         /* Enable LUT, Disable MAFC */
1474         dacset(mga, Dac_Xmiscctrl, Ramcs | Mfcsel, Vdoutsel);
1475
1476         /* Disable Dac */
1477         dacset(mga, Dac_Xmiscctrl, 0, Dacpdn);
1478
1479         /* Initialize Panel Mode */
1480         dacset(mga, Dac_Xpanelmode, 0, 0xff);
1481
1482         /* Disable the PIXCLK and set Pixel clock source to Pixel Clock PLL */
1483         dacset(mga, Dac_Xpixclkctrl, Pixclkdis | 0x01, 0x3);
1484
1485         /* Disable mapping of the memory */ 
1486         miscset(mga, 0, Misc_rammapen);
1487
1488         /* Enable 8 bit palette */
1489         dacset(mga, Dac_Xmiscctrl, Vga8dac, 0);
1490
1491         /* Select MGA Pixel Clock */
1492         miscset(mga, Misc_clksel, 0);
1493
1494         /* Initialize Z Buffer ... (useful?) */
1495         mgawrite32(mga, Z_DEPTH_ORG, 0);
1496
1497         /* Wait */
1498         for (i = 0; i < 50; i++)
1499                 mgaread32(mga, MGA_STATUS);
1500
1501         if ((mga->devid == MGA200) || ((mga->devid == MGA4XX) && (mga->revid & 0x80) == 0x00)) { 
1502                 dacset(mga, Dac_Xpixpllcm, mga->pixpll_m, 0xff);
1503                 dacset(mga, Dac_Xpixpllcn, mga->pixpll_n, 0xff);
1504                 dacset(mga, Dac_Xpixpllcp, mga->pixpll_p, 0xff);
1505
1506                 /* Wait until new clock becomes stable */
1507                 trace("mga: waiting for the clock source becomes stable ...\n");
1508                 while ((dacget(mga, Dac_Xpixpllstat) & Pixlock) != Pixlock)
1509                         ;
1510                 trace("mga: pixpll locked !\n");
1511         } else {
1512         /* MGA450 and MGA550 */
1513                 /* Wait until new clock becomes stable */
1514                 trace("mga450: waiting for the clock source becomes stable ...\n");
1515                 while ((dacget(mga, Dac_Xpixpllstat) & Pixlock) != Pixlock)
1516                         ;
1517                 trace("mga: pixpll locked !\n");
1518
1519                 G450SetPLLFreq(mga, (long) mga->Fneeded / 1000);
1520         }
1521
1522         /* Enable Pixel Clock Oscillation */
1523         dacset(mga, Dac_Xpixclkctrl, 0, Pixclkdis);
1524         if (ultradebug) Bflush(&stdout);
1525
1526         /* Enable Dac */
1527         dacset(mga, Dac_Xmiscctrl, Dacpdn, 0);
1528
1529         /* Set Video Mode */
1530         switch (mode->z) {
1531         case 8:
1532                 dacset(mga, Dac_Xmulctrl, _8bitsPerPixel, ColorDepth);  
1533                 break;
1534         case 16:
1535                 dacset(mga, Dac_Xmulctrl, _16bitsPerPixel, ColorDepth); 
1536                 break;
1537         case 24:
1538                 dacset(mga, Dac_Xmulctrl, _24bitsPerPixel, ColorDepth); 
1539                 break;
1540         case 32:
1541                 dacset(mga, Dac_Xmulctrl, _32bitsPerPixel, ColorDepth);
1542                 break;
1543         default: 
1544                 error("Unsupported depth %d\n", mode->z);
1545         }
1546
1547         /* Wait */
1548         for (i = 0; i < 50; i++)
1549                 mgaread32(mga, MGA_STATUS);
1550
1551         /* Wait until new clock becomes stable */
1552         trace("mga: waiting for the clock source becomes stable ...\n");
1553         if (ultradebug) Bflush(&stdout);
1554         while ((dacget(mga, Dac_Xpixpllstat) & Pixlock) != Pixlock)
1555                 ;
1556         trace("mga: pixpll locked !\n");
1557         if (ultradebug) Bflush(&stdout);
1558
1559         /* Initialize CRTC registers and remove irq */
1560         crtcset(mga, 0x11, (1<<4), (1<<5)|0x80);
1561         for (i = 0; i < 25; i++)
1562                 crtcset(mga, i, mga->crtc[i], 0xff);
1563
1564         trace("mga: crtc loaded !\n");
1565         if (ultradebug) Bflush(&stdout);
1566
1567         /* Initialize CRTC Extension registers */
1568         for (i = 0; i < 9; i++)
1569                 crtcextset(mga, i, mga->crtcext[i], 0xff);
1570
1571         trace("mga: ext loaded !\n");
1572         if (ultradebug) Bflush(&stdout);
1573
1574         /* Disable Zoom */
1575         dacset(mga, Dac_Xzoomctrl, 0, 0xff);
1576
1577         trace("mga: XzoomCtrl Loaded !\n");
1578         if (ultradebug) Bflush(&stdout);
1579
1580         /* Enable mga mode again ... Just in case :) */
1581         crtcextset(mga, CrtcExt_Miscellaneous, Mgamode, 0);
1582
1583         trace("mga: crtcext MgaMode loaded !\n");
1584         if (ultradebug) Bflush(&stdout);
1585
1586         if (mode->z == 32 || mode->z == 24 ) {
1587                 /* Initialize Big Endian Mode ! */
1588                 mgawrite32(mga, 0x1e54, 0x02 << 16);
1589         }
1590
1591
1592         /* Set final misc ... enable mapping ... */
1593         miscset(mga, mga->misc | Misc_rammapen, 0);
1594
1595         trace("mga: mapping enabled !\n");
1596         if (ultradebug) Bflush(&stdout);
1597
1598         /* Enable Screen */
1599         seqset(mga, 1, 0, 0xff);
1600
1601         trace("screen enabled ...\n");
1602
1603         if (0) {
1604                 p = mga->mmfb;
1605                 for (i = 0; i < mga->fbsize; i++)
1606                         *p++ = (0xff & i);
1607         }
1608
1609         trace("mga: Loaded !\n" );
1610         dump_all_regs(mga);
1611         if (ultradebug) Bflush(&stdout);
1612
1613         trace("mga: Loaded [bis]!\n" );
1614
1615         /*
1616          * TODO: In 16bpp mode, what is the correct palette ?
1617          *       in the meantime lets use the default one,
1618          *       which has a weird color combination.
1619          */
1620
1621         if (mode->z != 8 && mode ->z != 16) {
1622                 /* Initialize Palette */
1623                 mgawrite8(mga, RAMDACIDX, 0);
1624                 for (i = 0; i < 0x100; i++) {
1625                         mgawrite8(mga, RAMDACPALDATA, i);
1626                         mgawrite8(mga, RAMDACPALDATA, i);
1627                         mgawrite8(mga, RAMDACPALDATA, i);
1628                 }
1629         }
1630
1631         trace("mga: Palette initialised !\n");
1632
1633         /* Enable Cursor */
1634         dacset(mga, Dac_Xcurctrl, cursor, 0xff);
1635
1636         ctlr->flag |= Fload;
1637         if (ultradebug) Bflush(&stdout);
1638 }
1639
1640 Ctlr mga4xx = {
1641         "mga4xx",                       /* name */
1642         snarf,                          /* snarf */
1643         options,                                /* options */
1644         init,                                   /* init */
1645         load,                                   /* load */
1646         dump,                           /* dump */
1647 };
1648
1649 Ctlr mga4xxhwgc = {
1650         "mga4xxhwgc",           /* name */
1651         0,                                      /* snarf */
1652         0,                                      /* options */
1653         0,                                      /* init */
1654         0,                                      /* load */
1655         dump,                           /* dump */
1656 };