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