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