FreeBSD/Linux Kernel Cross Reference
sys/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
Cache object: 2be58fc334fc2336aec72b124d72761d
|