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