FreeBSD/Linux Kernel Cross Reference
sys/pc/vgasavage.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 AURORA64VPLUS = 0x8812,
39 };
40
41 /*
42 * Savage4 et al. acceleration.
43 *
44 * This is based only on the Savage4 documentation.
45 * It is expected to work on other Savage cards as well,
46 * but has not been tried.
47 *
48 * There are five ways to access the 2D graphics engine registers:
49 * - Old MMIO non-packed format
50 * - Old MMIO packed format
51 * - New MMIO non-packed format
52 * - New MMIO packed format
53 * - Burst Command Interface (BCI)
54 *
55 * Of these, the manual hints that the first three are deprecated,
56 * and it does not document any of those three well enough to use.
57 *
58 * I have tried for many hours with no success to understand the BCI
59 * interface well enough to use it. It is not well documented, and the
60 * XFree86 driver seems to completely contradict what little documentation
61 * there is.
62 *
63 * This leaves the packed new MMIO.
64 * The manual contradicts itself here, claming that the registers
65 * start at 0x2008100 as well as at 0x0008100 from the base of the
66 * mmio segment. Since the segment is only 512k, we assume that
67 * the latter is the correct offset.
68 *
69 * According to the manual, only 16-bit reads of the 2D registers
70 * are supported: 32-bit reads will return garbage in the upper word.
71 * 32-bit writes must be enabled explicitly.
72 *
73 * 32-bit reads of the status registers seem just fine.
74 */
75
76 /* 2D graphics engine registers for Savage4; others appear to be mostly the same */
77 enum {
78 SubsystemStatus = 0x8504, /* Subsystem Status: read only */
79 /* read only: whether we get interrupts on various events */
80 VsyncInt = 1<<0, /* vertical sync */
81 GeBusyInt = 1<<1, /* 2D graphics engine busy */
82 BfifoFullInt = 1<<2, /* BIU FIFO full */
83 BfifoEmptyInt = 1<<3, /* BIU FIFO empty */
84 CfifoFullInt = 1<<4, /* command FIFO full */
85 CfifoEmptyInt = 1<<5, /* command FIFO empty */
86 BciInt = 1<<6, /* BCI */
87 LpbInt = 1<<7, /* LPB */
88 CbHiInt = 1<<16, /* COB upper threshold */
89 CbLoInt = 1<<17, /* COB lower threshold */
90
91 SubsystemCtl = 0x8504, /* Subsystem Control: write only */
92 /* clear interrupts for various events */
93 VsyncClr = 1<<0,
94 GeBusyClr = 1<<1,
95 BfifoFullClr = 1<<2,
96 BfifoEmptyClr = 1<<3,
97 CfifoFullClr = 1<<4,
98 CfifoEmptyClr = 1<<5,
99 BciClr = 1<<6,
100 LpbClr = 1<<7,
101 CbHiClr = 1<<16,
102 CbLoClr = 1<<17,
103
104 /* enable interrupts for various events */
105 VsyncEna = 1<<8,
106 Busy2DEna = 1<<9,
107 BfifoFullEna = 1<<10,
108 BfifoEmptyEna = 1<<11,
109 CfifoFullEna = 1<<12,
110 CfifoEmptyEna = 1<<13,
111 SubsysBciEna = 1<<14,
112 CbHiEna = 1<<24,
113 CbLoEna = 1<<25,
114
115 /* 2D graphics engine software reset */
116 GeSoftReset = 1<<15,
117
118 FifoStatus = 0x8508, /* FIFO status: read only */
119 CwbEmpty = 1<<0, /* command write buffer empty */
120 CrbEmpty = 1<<1, /* command read buffer empty */
121 CobEmpty = 1<<2, /* command overflow buffer empty */
122 CfifoEmpty = 1<<3, /* command FIFO empty */
123 CwbFull = 1<<8, /* command write buffer full */
124 CrbFull = 1<<9, /* command read buffer full */
125 CobFull = 1<<10, /* command overflow buffer full */
126 CfifoFull = 1<<11, /* command FIFO full */
127
128 AdvFunCtl = 0x850C, /* Advanced Function Control: read/write */
129 GeEna = 1<<0, /* enable 2D/3D engine */
130 /*
131 * according to the manual, BigPixel should be
132 * set when bpp >= 8 (bpp != 4), and then CR50_5-4 are
133 * used to figure out bpp example. however, it does bad things
134 * to the screen in 8bpp mode.
135 */
136 BigPixel = 1<<2, /* 8 or more bpp enhanced mode */
137 LaEna = 1<<3, /* linear addressing ena: or'ed with CR58_4 */
138 Mclk_2 = 0<<8, /* 2D engine clock divide: MCLK/2 */
139 Mclk_4 = 1<<8, /* " MCLK/4 */
140 Mclk = 2<<8, /* " MCLK */
141 /* Mclk = 3<<8, /* " MCLK */
142 Ic33mhz = 1<<16, /* Internal clock 33 MHz (instead of 66) */
143
144 WakeupReg = 0x8510, /* Wakeup: read/write */
145 WakeupBit = 1<<0, /* wake up: or'ed with 3C3_0 */
146
147 SourceY = 0x8100, /* UL corner of bitblt source */
148 SourceX = 0x8102, /* " */
149 RectY = 0x8100, /* UL corner of rectangle fill */
150 RectX = 0x8102, /* " */
151 DestY = 0x8108, /* UL corner of bitblt dest */
152 DestX = 0x810A, /* " */
153 Height = 0x8148, /* bitblt, image xfer rectangle height */
154 Width = 0x814A, /* bitblt, image xfer rectangle width */
155
156 StartY = 0x8100, /* Line draw: first point*/
157 StartX = 0x8102, /* " */
158 /*
159 * For line draws, the following must be programmed:
160 * axial step constant = 2*min(|dx|,|dy|)
161 * diagonal step constant = 2*[min(|dx|,|dy|) - max(|dx|,|dy|)]
162 * error term = 2*min(|dx|,|dy|) - max(|dx|,|dy| - 1
163 * [sic] when start X < end X
164 * error term = 2*min(|dx|,|dy|) - max(|dx|,|dy|
165 * [sic] when start X >= end X
166 */
167 AxialStep = 0x8108,
168 DiagonalStep = 0x810A,
169 LineError = 0x8110,
170 MinorLength = 0x8148, /* pixel count along minor axis */
171 MajorLength = 0x814A, /* pixel count along major axis */
172
173 DrawCmd = 0x8118, /* Drawing Command: write only */
174 CmdMagic = 0<<1,
175 AcrossPlane = 1<<1, /* across the plane mode */
176 LastPixelOff = 1<<2, /* last pixel of line or vector draw not drawn */
177 Radial = 1<<3, /* enable radial direction (else axial) */
178 DoDraw = 1<<4, /* draw pixels (else only move current pos) */
179
180 DrawRight = 1<<5, /* axial drawing direction: left to right */
181 /* DrawLeft = 0<<5, */
182 MajorY = 1<<6,
183 /* MajorX = 0<<6, */
184 DrawDown = 1<<7,
185 /* DrawUp = 0<<7, */
186 Degree0 = 0<<5, /* drawing direction when Radial */
187 Degree45 = 1<<5,
188 /* ... */
189 Degree315 = 7<<5,
190
191 UseCPUData = 1<<8,
192
193 /* image write bus transfer width */
194 Bus8 = 0<<9,
195 Bus16 = 1<<9,
196 /*
197 * in Bus32 mode, doubleword bits beyond the image rect width are
198 * discarded. each line starts on a new doubleword.
199 * Bus32AP is intended for across-the-plane mode and
200 * rounds to byte boundaries instead.
201 */
202 Bus32 = 2<<9,
203 Bus32AP = 3<<9,
204
205 CmdNop = 0<<13, /* nop */
206 CmdLine = 1<<13, /* draw line */
207 CmdFill = 2<<13, /* fill rectangle */
208 CmdBitblt = 6<<13, /* bitblt */
209 CmdPatblt = 7<<13, /* 8x8 pattern blt */
210
211 SrcGBD = 0<<16,
212 SrcPBD = 1<<16,
213 SrcSBD = 2<<16,
214
215 DstGBD = 0<<18,
216 DstPBD = 1<<18,
217 DstSBD = 2<<18,
218
219 /* color sources, controls */
220 BgColor = 0x8120, /* Background Color: read/write */
221 FgColor = 0x8124, /* Foreground Color: read/write */
222 BitplaneWmask = 0x8128, /* Bitplane Write Mask: read/write */
223 BitplaneRmask = 0x812C, /* Bitplane Read Mask: read/write */
224 CmpColor = 0x8130, /* Color Compare: read/write */
225 BgMix = 0x8134,
226 FgMix = 0x8136,
227 MixNew = 7,
228 SrcBg = 0<<5,
229 SrcFg = 1<<5,
230 SrcCPU = 2<<5,
231 SrcDisp = 3<<5,
232
233 /* clipping rectangle */
234 TopScissors = 0x8138, /* Top Scissors: write only */
235 LeftScissors = 0x813A, /* Left Scissors: write only */
236 BottomScissors = 0x813C, /* Bottom Scissors: write only */
237 RightScissors = 0x813E, /* Right Scissors: write only */
238
239 /*
240 * Registers with Magic were indirectly accessed in older modes.
241 * It is not clear whether the Magic is necessary.
242 * In the older modes, writes to these registers were pipelined,
243 * so that you had to issue an engine command and wait for engine
244 * idle before reading a write back. It is not clear if this is
245 * still the case either.
246 */
247 PixCtl = 0x8140, /* Pixel Control: write only */
248 PixMagic = 0xA<<12,
249 PixMixFg = 0<<6, /* foreground mix register always */
250 PixMixCPU = 2<<6, /* CPU data determines mix register */
251 PixMixDisp = 3<<6, /* display data determines mix register */
252
253 MfMisc2Ctl = 0x8142, /* Multifunction Control Misc. 2: write only */
254 MfMisc2Magic = 0xD<<12,
255 DstShift = 0, /* 3 bits: destination base address in MB */
256 SrcShift = 4, /* 3 bits: source base address in MB */
257 WaitFifoEmpty = 2<<8, /* wait for write FIFO empty between draws */
258
259 MfMiscCtl = 0x8144, /* Multifunction Control Misc: write only */
260 MfMiscMagic = 0xE<<12,
261 UseHighBits = 1<<4, /* select upper 16 bits for 32-bit reg access */
262 ClipInvert = 1<<5, /* only touch pixels outside clip rectangle */
263 SkipSame = 0<<6, /* ignore pixels with color CmpColor */
264 SkipDifferent = 1<<7, /* ignore pixels not color CmpColor */
265 CmpEna = 1<<8, /* enable color compare */
266 W32Ena = 1<<9, /* enable 32-bit register write */
267 ClipDis = 1<<11, /* disable clipping */
268
269 /*
270 * The bitmap descriptor 1 registers contain the starting
271 * address of the bitmap (in bytes).
272 * The bitmap descriptor 2 registesr contain stride (in pixels)
273 * in the lower 16 bits, depth (in bits) in the next 8 bits,
274 * and whether block write is disabled.
275 */
276 GBD1 = 0x8168, /* Global Bitmap Descriptor 1: read/write */
277 GBD2 = 0x816C, /* Global Bitmap Descriptor 2: read/write */
278 /* GBD2-only bits */
279 BDS64 = 1<<0, /* bitmap descriptor size 64 bits */
280 GBDBciEna = 1<<3, /* BCI enable */
281 /* generic BD2 bits */
282 BlockWriteDis = 1<<28,
283 StrideShift = 0,
284 DepthShift = 16,
285
286 PBD1 = 0x8170, /* Primary Bitmap Descriptor: read/write */
287 PBD2 = 0x8174,
288 SBD1 = 0x8178, /* Secondary Bitmap Descriptor: read/write */
289 SBD2 = 0x817C,
290 };
291
292 /* mastered data transfer registers */
293
294 /* configuration/status registers */
295 enum {
296 XStatus0 = 0x48C00, /* Status Word 0: read only */
297 /* rev. A silicon differs from rev. B; use AltStatus0 */
298 CBEMaskA = 0x1FFFF, /* filled command buffer entries */
299 CBEShiftA = 0,
300 BciIdleA = 1<<17, /* BCI idle */
301 Ge3IdleA = 1<<18, /* 3D engine idle */
302 Ge2IdleA = 1<<19, /* 2D engine idle */
303 McpIdleA = 1<<20, /* motion compensation processor idle */
304 MeIdleA = 1<<22, /* master engine idle */
305 PfPendA = 1<<23, /* page flip pending */
306
307 CBEMaskB = 0x1FFFFF,
308 CBEShiftB = 0,
309 BciIdleB = 1<<25,
310 Ge3IdleB = 1<<26,
311 Ge2IdleB = 1<<27,
312 McpIdleB = 1<<28,
313 MeIdleB = 1<<30,
314 PfPendB = 1<<31,
315
316 AltStatus0 = 0x48C60, /* Alternate Status Word 0: read only */
317 CBEMask = 0x1FFFF,
318 CBEShift = 0,
319 /* the Savage4 manual says bits 17..23 for these, like Status0 */
320 /* empirically, they are bits 21..26 */
321 BciIdle = 1<<21,
322 Ge3Idle = 1<<22,
323 Ge2Idle = 1<<23,
324 McpIdle = 1<<24,
325 MeIdle = 1<<25,
326 PfPend = 1<<26,
327
328 XStatus1 = 0x48C04, /* Status Word 1: read only */
329 /* contains event tag 1, event tag 0, both 16 bits */
330
331 XStatus2 = 0x48C08, /* Status Word 2: read only */
332 ScanMask = 0x3FF, /* current scan line */
333 ScanShift = 0,
334 VRTMask = 0x7F100, /* vert retrace count */
335 VRTShift = 11,
336
337 CbThresh = 0x48C10, /* Command Buffer Thresholds: read/write */
338 CobOff = 0x48C14, /* Command Overflow Buffer: read/write */
339
340 CobPtr = 0x48C18, /* Command Overflow Buffer Pointers: read/write */
341 CobEna = 1<<2, /* command overflow buffer enable */
342 CobBciEna = 1<<3, /* BCI function enable */
343 CbeMask = 0xFFFF8000, /* no. of entries in command buffer */
344 CbeShift = 15,
345
346 AltStatus1 = 0x48C64, /* Alternate Status Word 1: read onnly */
347 /* contains current texture surface tag, vertex buffer tag */
348
349 };
350
351 struct {
352 ulong idletimeout;
353 ulong tostatw[16];
354 } savagestats;
355
356 enum {
357 Maxloop = 1<<20
358 };
359
360 static void
361 savagewaitidle(VGAscr *scr)
362 {
363 long x;
364 ulong *statw, mask, goal;
365
366 switch(scr->id){
367 case SAVAGE4:
368 case PROSAVAGEP:
369 case PROSAVAGEK:
370 case PROSAVAGE8:
371 /* wait for engine idle and FIFO empty */
372 statw = (ulong*)((uchar*)scr->mmio+AltStatus0);
373 mask = CBEMask | Ge2Idle;
374 goal = Ge2Idle;
375 break;
376 /* case SAVAGEMXMV: ? */
377 /* case SAVAGEMX: ? */
378 /* case SAVAGEIX: ? */
379 case SUPERSAVAGEIXC16:
380 case SAVAGEIXMV:
381 case SAVAGEMXMV:
382 /* wait for engine idle and FIFO empty */
383 statw = (ulong*)((uchar*)scr->mmio+XStatus0);
384 mask = CBEMaskA | Ge2IdleA;
385 goal = Ge2IdleA;
386 break;
387 default:
388 /*
389 * best we can do: can't print or we'll call ourselves.
390 * savageinit is supposed to not let this happen.
391 */
392 return;
393 }
394
395 for(x=0; x<Maxloop; x++)
396 if((*statw & mask) == goal)
397 return;
398
399 savagestats.tostatw[savagestats.idletimeout++&15] = *statw;
400 savagestats.tostatw[savagestats.idletimeout++&15] = (ulong)statw;
401 }
402
403 static int
404 savagefill(VGAscr *scr, Rectangle r, ulong sval)
405 {
406 uchar *mmio;
407
408 mmio = (uchar*)scr->mmio;
409
410 *(ulong*)(mmio+FgColor) = sval;
411 *(ulong*)(mmio+BgColor) = sval;
412 *(ulong*)(mmio+BgMix) = SrcFg|MixNew;
413 *(ulong*)(mmio+FgMix) = SrcFg|MixNew;
414 *(ushort*)(mmio+RectY) = r.min.y;
415 *(ushort*)(mmio+RectX) = r.min.x;
416 *(ushort*)(mmio+Width) = Dx(r)-1;
417 *(ushort*)(mmio+Height) = Dy(r)-1;
418 *(ulong*)(mmio+DrawCmd) = CmdMagic | DoDraw | CmdFill | DrawRight | DrawDown;
419 savagewaitidle(scr);
420 return 1;
421 }
422
423 static int
424 savagescroll(VGAscr *scr, Rectangle r, Rectangle sr)
425 {
426 uchar *mmio;
427 ulong cmd;
428 Point dp, sp;
429
430 cmd = CmdMagic | DoDraw | CmdBitblt | SrcPBD | DstGBD;
431
432 if(r.min.x <= sr.min.x){
433 cmd |= DrawRight;
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 |= DrawDown;
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 = (uchar*)scr->mmio;
451
452 *(ushort*)(mmio+SourceX) = sp.x;
453 *(ushort*)(mmio+SourceY) = sp.y;
454 *(ushort*)(mmio+DestX) = dp.x;
455 *(ushort*)(mmio+DestY) = dp.y;
456 *(ushort*)(mmio+Width) = Dx(r)-1;
457 *(ushort*)(mmio+Height) = Dy(r)-1;
458 *(ulong*)(mmio+BgMix) = SrcDisp|MixNew;
459 *(ulong*)(mmio+FgMix) = SrcDisp|MixNew;
460 *(ulong*)(mmio+DrawCmd) = cmd;
461 savagewaitidle(scr);
462 return 1;
463 }
464
465 static void
466 savageblank(VGAscr*, int blank)
467 {
468 uchar seqD;
469
470 /*
471 * Will handle DPMS to monitor
472 */
473 vgaxo(Seqx, 8, vgaxi(Seqx,8)|0x06);
474 seqD = vgaxi(Seqx, 0xD);
475 seqD &= 0x03;
476 if(blank)
477 seqD |= 0x50;
478 vgaxo(Seqx, 0xD, seqD);
479
480 /*
481 * Will handle LCD
482 */
483 if(blank)
484 vgaxo(Seqx, 0x31, vgaxi(Seqx, 0x31) & ~0x10);
485 else
486 vgaxo(Seqx, 0x31, vgaxi(Seqx, 0x31) | 0x10);
487 }
488
489
490 void
491 savageinit(VGAscr *scr)
492 {
493 uchar *mmio;
494 ulong bd;
495
496 /* if you add chip IDs here be sure to update savagewaitidle */
497 switch(scr->id){
498 case SAVAGE4:
499 case PROSAVAGEP:
500 case PROSAVAGEK:
501 case PROSAVAGE8:
502 case SAVAGEIXMV:
503 case SUPERSAVAGEIXC16:
504 case SAVAGEMXMV:
505 break;
506 default:
507 print("unknown savage %.4lux\n", scr->id);
508 return;
509 }
510
511 mmio = (uchar*)scr->mmio;
512 if(mmio == nil) {
513 print("savageinit: no mmio\n");
514 return;
515 }
516
517 /* 2D graphics engine software reset */
518 *(ushort*)(mmio+SubsystemCtl) = GeSoftReset;
519 delay(2);
520 *(ushort*)(mmio+SubsystemCtl) = 0;
521 savagewaitidle(scr);
522
523 /* disable BCI as much as possible */
524 *(ushort*)(mmio+CobPtr) &= ~CobBciEna;
525 *(ushort*)(mmio+GBD2) &= ~GBDBciEna;
526 savagewaitidle(scr);
527
528 /* enable 32-bit writes, disable clipping */
529 *(ushort*)(mmio+MfMiscCtl) = MfMiscMagic|W32Ena|ClipDis;
530 savagewaitidle(scr);
531
532 /* enable all read, write planes */
533 *(ulong*)(mmio+BitplaneRmask) = ~0;
534 *(ulong*)(mmio+BitplaneWmask) = ~0;
535 savagewaitidle(scr);
536
537 /* turn on linear access, 2D engine */
538 *(ulong*)(mmio+AdvFunCtl) |= GeEna|LaEna;
539 savagewaitidle(scr);
540
541 /* set bitmap descriptors */
542 bd = (scr->gscreen->depth<<DepthShift) |
543 (Dx(scr->gscreen->r)<<StrideShift) | BlockWriteDis
544 | BDS64;
545
546 *(ulong*)(mmio+GBD1) = 0;
547 *(ulong*)(mmio+GBD2) = bd;
548
549 *(ulong*)(mmio+PBD1) = 0;
550 *(ulong*)(mmio+PBD2) = bd;
551
552 *(ulong*)(mmio+SBD1) = 0;
553 *(ulong*)(mmio+SBD2) = bd;
554
555 /*
556 * For some reason, the GBD needs to get programmed twice,
557 * once before the PBD, SBD, and once after.
558 * This empirically makes it get set right.
559 * I would like to better understand the ugliness
560 * going on here.
561 */
562 *(ulong*)(mmio+GBD1) = 0;
563 *(ulong*)(mmio+GBD2) = bd;
564 *(ushort*)(mmio+GBD2+2) = bd>>16;
565 savagewaitidle(scr);
566
567 scr->fill = savagefill;
568 scr->scroll = savagescroll;
569 scr->blank = savageblank;
570 hwblank = 0;
571 }
Cache object: 935824bf7cb6de008e2fe05626bec368
|