]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/vgas3.c
pc/vga*: use 64-bit physical addresses and check pci membar types and sizes
[plan9front.git] / sys / src / 9 / pc / vgas3.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8
9 #define Image   IMAGE
10 #include <draw.h>
11 #include <memdraw.h>
12 #include <cursor.h>
13 #include "screen.h"
14
15 enum {
16         PCIS3           = 0x5333,               /* PCI VID */
17
18         SAVAGE3D        = 0x8A20,               /* PCI DID */
19         SAVAGE3DMV      = 0x8A21,
20         SAVAGE4         = 0x8A22,
21         PROSAVAGEP      = 0x8A25,
22         PROSAVAGEK      = 0x8A26,
23         PROSAVAGE8      = 0x8D04,
24         SAVAGEMXMV      = 0x8C10,
25         SAVAGEMX        = 0x8C11,
26         SAVAGEIXMV      = 0x8C12,
27         SAVAGEIX        = 0x8C13,
28         SUPERSAVAGEIXC16 = 0x8C2E,
29         SAVAGE2000      = 0x9102,
30
31         VIRGE           = 0x5631,
32         VIRGEGX2        = 0x8A10,
33         VIRGEDXGX       = 0x8A01,
34         VIRGEVX         = 0x883D,
35         VIRGEMX         = 0x8C01,
36         VIRGEMXP        = 0x8C03,
37
38         VIRTUALPC2004   = 0x8810,
39         AURORA64VPLUS   = 0x8812,
40 };
41
42 static int
43 s3pageset(VGAscr* scr, int page)
44 {
45         uchar crt35, crt51;
46         int opage;
47
48         crt35 = vgaxi(Crtx, 0x35);
49         if(scr->gscreen->depth >= 8){
50                 /*
51                  * The S3 registers need to be unlocked for this.
52                  * Let's hope they are already:
53                  *      vgaxo(Crtx, 0x38, 0x48);
54                  *      vgaxo(Crtx, 0x39, 0xA0);
55                  *
56                  * The page is 6 bits, the lower 4 bits in Crt35<3:0>,
57                  * the upper 2 in Crt51<3:2>.
58                  */
59                 vgaxo(Crtx, 0x35, page & 0x0F);
60                 crt51 = vgaxi(Crtx, 0x51);
61                 vgaxo(Crtx, 0x51, (crt51 & ~0x0C)|((page & 0x30)>>2));
62                 opage = ((crt51 & 0x0C)<<2)|(crt35 & 0x0F);
63         }
64         else{
65                 vgaxo(Crtx, 0x35, (page<<2) & 0x0C);
66                 opage = (crt35>>2) & 0x03;
67         }
68
69         return opage;
70 }
71
72 static void
73 s3page(VGAscr* scr, int page)
74 {
75         int id;
76
77         id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
78         switch(id){
79
80         case VIRGEGX2:
81                 break;
82
83         default:
84                 lock(&scr->devlock);
85                 s3pageset(scr, page);
86                 unlock(&scr->devlock);
87                 break;
88         }
89 }
90
91 static void
92 s3linear(VGAscr* scr, int, int)
93 {
94         uvlong mmiobase;
95         ulong mmiosize;
96         int id, j;
97         Pcidev *p;
98         
99         p = scr->pci;
100         if(p == nil)
101                 return;
102         vgalinearpci(scr);
103
104         if(scr->paddr)
105                 addvgaseg("s3screen", scr->paddr, scr->apsize);
106         
107         id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
108         switch(id){                     /* find mmio */
109         case SAVAGE4:
110         case PROSAVAGEP:
111         case PROSAVAGEK:
112         case PROSAVAGE8:
113         case SUPERSAVAGEIXC16:
114                 /*
115                  * We could assume that the MMIO registers
116                  * will be in the screen segment and just use
117                  * that, but PCI software is allowed to move them
118                  * if it feels like it, so we look for an aperture of
119                  * the right size; only the first 512k actually means
120                  * anything.  The S3 engineers overestimated how
121                  * much space they would need in the first design.
122                  */
123                 for(j=0; j<nelem(p->mem); j++){
124                         if((p->mem[j].bar&1) == 0)
125                         if((p->mem[j].bar&~0x0F) != scr->paddr)
126                         if(p->mem[j].size==512*1024 || p->mem[j].size==16*1024*1024){
127                                 mmiobase = p->mem[j].bar & ~0x0F;
128                                 mmiosize = 512*1024;
129                                 scr->mmio = vmap(mmiobase, mmiosize);
130                                 if(scr->mmio == nil)
131                                         return;
132                                 addvgaseg("savagemmio", mmiobase, mmiosize);
133                                 break;
134                         }
135                 }
136         }
137 }
138
139 static void
140 s3vsyncactive(void)
141 {
142         /*
143          * Hardware cursor information is fetched from display memory
144          * during the horizontal blank active time. The 80x chips may hang
145          * if the cursor is turned on or off during this period.
146          */
147         while((vgai(Status1) & 0x08) == 0)
148                 ;
149 }
150
151 static void
152 s3disable(VGAscr*)
153 {
154         uchar crt45;
155
156         /*
157          * Turn cursor off.
158          */
159         crt45 = vgaxi(Crtx, 0x45) & 0xFE;
160         s3vsyncactive();
161         vgaxo(Crtx, 0x45, crt45);
162 }
163
164 static void
165 s3load(VGAscr* scr, Cursor* curs)
166 {
167         uchar *p;
168         int id, dolock, opage, x, y;
169
170         /*
171          * Disable the cursor and
172          * set the pointer to the two planes.
173          */
174         s3disable(scr);
175
176         opage = 0;
177         p = scr->vaddr;
178         id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
179         switch(id){
180
181         case VIRTUALPC2004:
182         case VIRGE:
183         case VIRGEDXGX:
184         case VIRGEGX2:
185         case VIRGEVX:   
186         case SAVAGEMXMV:
187         case SAVAGEIXMV:
188         case SAVAGE4:
189         case PROSAVAGEP:
190         case PROSAVAGEK:
191         case PROSAVAGE8:
192         case SUPERSAVAGEIXC16:
193                 dolock = 0;
194                 p += scr->storage;
195                 break;
196
197         default:
198                 dolock = 1;
199                 lock(&scr->devlock);
200                 opage = s3pageset(scr, scr->storage>>16);
201                 p += (scr->storage & 0xFFFF);
202                 break;
203         }
204
205         /*
206          * The cursor is set in Microsoft Windows format (the ViRGE/GX2 doesn't
207          * support the X11 format) which gives the following truth table:
208          *      and xor colour
209          *       0   0  background colour
210          *       0   1  foreground colour
211          *       1   0  current screen pixel
212          *       1   1  NOT current screen pixel
213          * Put the cursor into the top-left of the 64x64 array.
214          *
215          * The cursor pattern in memory is interleaved words of
216          * AND and XOR patterns.
217          */
218         for(y = 0; y < 64; y++){
219                 for(x = 0; x < 64/8; x += 2){
220                         if(x < 16/8 && y < 16){
221                                 *p++ = ~(curs->clr[2*y + x]|curs->set[2*y + x]);
222                                 *p++ = ~(curs->clr[2*y + x+1]|curs->set[2*y + x+1]);
223                                 *p++ = curs->set[2*y + x];
224                                 *p++ = curs->set[2*y + x+1];
225                         }
226                         else {
227                                 *p++ = 0xFF;
228                                 *p++ = 0xFF;
229                                 *p++ = 0x00;
230                                 *p++ = 0x00;
231                         }
232                 }
233         }
234
235         if(dolock){
236                 s3pageset(scr, opage);
237                 unlock(&scr->devlock);
238         }
239
240         /*
241          * Save the cursor hotpoint and enable the cursor.
242          */
243         scr->offset = curs->offset;
244         s3vsyncactive();
245         vgaxo(Crtx, 0x45, 0x01);
246 }
247
248 static int
249 s3move(VGAscr* scr, Point p)
250 {
251         int x, xo, y, yo;
252
253         /*
254          * Mustn't position the cursor offscreen even partially,
255          * or it disappears. Therefore, if x or y is -ve, adjust the
256          * cursor offset instead.
257          * There seems to be a bug in that if the offset is 1, the
258          * cursor doesn't disappear off the left edge properly, so
259          * round it up to be even.
260          */
261         if((x = p.x+scr->offset.x) < 0){
262                 xo = -x;
263                 xo = ((xo+1)/2)*2;
264                 x = 0;
265         }
266         else
267                 xo = 0;
268         if((y = p.y+scr->offset.y) < 0){
269                 yo = -y;
270                 y = 0;
271         }
272         else
273                 yo = 0;
274
275         vgaxo(Crtx, 0x46, (x>>8) & 0x07);
276         vgaxo(Crtx, 0x47, x & 0xFF);
277         vgaxo(Crtx, 0x49, y & 0xFF);
278         vgaxo(Crtx, 0x4E, xo);
279         vgaxo(Crtx, 0x4F, yo);
280         vgaxo(Crtx, 0x48, (y>>8) & 0x07);
281
282         return 0;
283 }
284
285 static void
286 s3enable(VGAscr* scr)
287 {
288         int i;
289         ulong storage;
290
291         s3disable(scr);
292
293         /*
294          * Cursor colours. Set both the CR0[EF] and the colour
295          * stack in case we are using a 16-bit RAMDAC.
296          */
297         vgaxo(Crtx, 0x0E, Pwhite);
298         vgaxo(Crtx, 0x0F, Pblack);
299         vgaxi(Crtx, 0x45);
300
301         for(i = 0; i < 3; i++)
302                 vgaxo(Crtx, 0x4A, Pblack);
303         vgaxi(Crtx, 0x45);
304         for(i = 0; i < 3; i++)
305                 vgaxo(Crtx, 0x4B, Pwhite);
306
307         /*
308          * Find a place for the cursor data in display memory.
309          * Must be on a 1024-byte boundary.
310          */
311         storage = (scr->gscreen->width*sizeof(ulong)*scr->gscreen->r.max.y+1023)/1024;
312         vgaxo(Crtx, 0x4C, storage>>8);
313         vgaxo(Crtx, 0x4D, storage & 0xFF);
314         storage *= 1024;
315         scr->storage = storage;
316
317         /*
318          * Load, locate and enable the cursor
319          * in Microsoft Windows format.
320          */
321         s3load(scr, &cursor);
322         s3move(scr, ZP);
323         vgaxo(Crtx, 0x55, vgaxi(Crtx, 0x55) & ~0x10);
324         s3vsyncactive();
325         vgaxo(Crtx, 0x45, 0x01);
326 }
327
328 /*
329  * The manual gives byte offsets, but we want ulong offsets, hence /4.
330  */
331 enum {
332         SrcBase = 0xA4D4/4,
333         DstBase = 0xA4D8/4,
334         Stride = 0xA4E4/4,
335         FgrdData = 0xA4F4/4,
336         WidthHeight = 0xA504/4,
337         SrcXY = 0xA508/4,
338         DestXY = 0xA50C/4,
339         Command = 0xA500/4,
340         SubStat = 0x8504/4,
341         FifoStat = 0x850C/4,
342 };
343
344 /*
345  * Wait for writes to VGA memory via linear aperture to flush.
346  */
347 enum {Maxloop = 1<<24};
348 struct {
349         ulong linear;
350         ulong fifo;
351         ulong idle;
352         ulong lineartimeout;
353         ulong fifotimeout;
354         ulong idletimeout;
355 } waitcount;
356
357 static void
358 waitforlinearfifo(VGAscr *scr)
359 {
360         ulong *mmio;
361         long x;
362         static ulong nwaitforlinearfifo;
363         ulong mask, val;
364
365         switch(scr->id){
366         default:
367                 panic("unknown scr->id in s3 waitforlinearfifo");
368         case 0x8A01:    /* ViRGE/[DG]X.  XFree86 says no waiting necessary */
369                 return;
370         case 0x5631:    /* ViRGE */
371         case 0x883D:    /* ViRGE/VX */
372                 mask = 0x0F<<6;
373                 val = 0x08<<6;
374                 break;
375         case 0x8A10:    /* ViRGE/GX2 */
376                 mask = 0x1F<<6;
377                 val = 0x10<<6;
378                 break;
379         }
380         mmio = scr->mmio;
381         x = 0;
382         while((mmio[FifoStat]&mask) != val && x++ < Maxloop)
383                 waitcount.linear++;
384         if(x >= Maxloop)
385                 waitcount.lineartimeout++;
386 }
387
388 static void
389 waitforfifo(VGAscr *scr, int entries)
390 {
391         ulong *mmio;
392         long x;
393         static ulong nwaitforfifo;
394
395         mmio = scr->mmio;
396         x = 0;
397         while((mmio[SubStat]&0x1F00) < ((entries+2)<<8) && x++ < Maxloop)
398                 waitcount.fifo++;
399         if(x >= Maxloop)
400                 waitcount.fifotimeout++;
401 }
402
403 static void
404 waitforidle(VGAscr *scr)
405 {
406         ulong *mmio;
407         long x;
408
409         mmio = scr->mmio;
410         x = 0;
411         while((mmio[SubStat]&0x3F00) != 0x3000 && x++ < Maxloop)
412                 waitcount.idle++;
413         if(x >= Maxloop)
414                 waitcount.idletimeout++;
415 }
416
417 static int
418 hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
419 {
420         enum { Bitbltop = 0xCC };       /* copy source */
421         ulong *mmio;
422         ulong cmd, stride;
423         Point dp, sp;
424         int did, d;
425
426         d = scr->gscreen->depth;
427         did = (d-8)/8;
428         cmd = 0x00000020|(Bitbltop<<17)|(did<<2);
429         stride = Dx(scr->gscreen->r)*d/8;
430
431         if(r.min.x <= sr.min.x){
432                 cmd |= 1<<25;
433                 dp.x = r.min.x;
434                 sp.x = sr.min.x;
435         }else{
436                 dp.x = r.max.x-1;
437                 sp.x = sr.max.x-1;
438         }
439
440         if(r.min.y <= sr.min.y){
441                 cmd |= 1<<26;
442                 dp.y = r.min.y;
443                 sp.y = sr.min.y;
444         }else{
445                 dp.y = r.max.y-1;
446                 sp.y = sr.max.y-1;
447         }
448
449         mmio = scr->mmio;
450         waitforlinearfifo(scr);
451         waitforfifo(scr, 7);
452         mmio[SrcBase] = scr->paddr;
453         mmio[DstBase] = scr->paddr;
454         mmio[Stride] = (stride<<16)|stride;
455         mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r);
456         mmio[SrcXY] = (sp.x<<16)|sp.y;
457         mmio[DestXY] = (dp.x<<16)|dp.y;
458         mmio[Command] = cmd;
459         waitforidle(scr);
460         return 1;
461 }
462
463 static int
464 hwfill(VGAscr *scr, Rectangle r, ulong sval)
465 {
466         enum { Bitbltop = 0xCC };       /* copy source */
467         ulong *mmio;
468         ulong cmd, stride;
469         int did, d;
470
471         d = scr->gscreen->depth;
472         did = (d-8)/8;
473         cmd = 0x16000120|(Bitbltop<<17)|(did<<2);
474         stride = Dx(scr->gscreen->r)*d/8;
475         mmio = scr->mmio;
476         waitforlinearfifo(scr);
477         waitforfifo(scr, 8);
478         mmio[SrcBase] = scr->paddr;
479         mmio[DstBase] = scr->paddr;
480         mmio[DstBase] = scr->paddr;
481         mmio[Stride] = (stride<<16)|stride;
482         mmio[FgrdData] = sval;
483         mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r);
484         mmio[DestXY] = (r.min.x<<16)|r.min.y;
485         mmio[Command] = cmd;
486         waitforidle(scr);
487         return 1;
488 }
489
490 enum {
491         CursorSyncCtl = 0x0D,   /* in Seqx */
492         VsyncHi = 0x80,
493         VsyncLo = 0x40,
494         HsyncHi = 0x20,
495         HsyncLo = 0x10,
496 };
497
498 static void
499 s3blank(VGAscr*, int blank)
500 {
501         uchar x;
502
503         x = vgaxi(Seqx, CursorSyncCtl);
504         x &= ~0xF0;
505         if(blank)
506                 x |= VsyncLo | HsyncLo;
507         vgaxo(Seqx, CursorSyncCtl, x);
508 }
509
510 static void
511 s3drawinit(VGAscr *scr)
512 {
513         extern void savageinit(VGAscr*);        /* vgasavage.c */
514         ulong id;
515
516         id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
517         scr->id = id;
518
519         /*
520          * It's highly likely that other ViRGEs will work without
521          * change to the driver, with the exception of the size of
522          * the linear aperture memory write FIFO.  Since we don't
523          * know that size, I'm not turning them on.  See waitforlinearfifo
524          * above.
525          */
526         scr->blank = s3blank;
527
528         switch(id){
529         case VIRGE:
530         case VIRGEVX:
531         case VIRGEGX2:
532                 scr->mmio = (ulong*)((char*)scr->vaddr+0x1000000);
533                 scr->fill = hwfill;
534                 scr->scroll = hwscroll;
535                 break;
536         case SAVAGEMXMV:
537         case SAVAGEIXMV:
538                 scr->mmio = (ulong*)((char*)scr->vaddr+0x1000000);
539                 savageinit(scr);        
540                 break;
541         case SUPERSAVAGEIXC16:
542         case SAVAGE4:
543         case PROSAVAGEP:
544         case PROSAVAGE8:
545         case PROSAVAGEK:
546                 /* scr->mmio is set by s3linear */
547                 savageinit(scr);
548                 break;
549         }
550 }
551
552 VGAdev vgas3dev = {
553         "s3",
554
555         0,
556         0,
557         s3page,
558         s3linear,
559         s3drawinit,
560 };
561
562 VGAcur vgas3cur = {
563         "s3hwgc",
564
565         s3enable,
566         s3disable,
567         s3load,
568         s3move,
569 };
570