]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/vgasavage.c
pc, pc64: clear debug watchpoint registers on exec and exit
[plan9front.git] / sys / src / 9 / 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 }