]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/vgamach64xx.c
audiohda: fix syntax error
[plan9front.git] / sys / src / 9 / pc / vgamach64xx.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/pci.h"
8 #include "../port/error.h"
9
10 #define Image   IMAGE
11 #include <draw.h>
12 #include <memdraw.h>
13 #include <cursor.h>
14 #include "screen.h"
15
16 char Eunsupportedformat[] = "unsupported video format";
17 char Enotconfigured[] = "device not configured";
18
19 #define SCALE_ZERO_EXTEND               0x0
20 #define SCALE_DYNAMIC                           0x1
21 #define SCALE_RED_TEMP_6500K            0x0
22 #define SCALE_RED_TEMP_9800K            0x2
23 #define SCALE_HORZ_BLEND                0x0
24 #define SCALE_HORZ_REP                          0x4
25 #define SCALE_VERT_BLEND                        0x0
26 #define SCALE_VERT_REP                          0x8
27 #define SCALE_BANDWIDTH_NORMAL     0x0
28 #define SCALE_BANDWIDTH_EXCEEDED  0x4000000
29 #define SCALE_BANDWIDTH_RESET           0x4000000
30 #define SCALE_CLK_ACTIVITY              0x0
31 #define SCALE_CLK_CONTINUOUS            0x20000000
32 #define OVERLAY_DISABLE                         0x0
33 #define OVERLAY_ENABLE                          0x40000000
34 #define SCALE_DISABLE                           0x0
35 #define SCALE_ENABLE                            0x80000000
36
37 #define SCALER_FRAME_READ_MODE_FULL     0x0
38 #define SCALER_BUF_MODE_SINGLE                  0x0
39 #define SCALER_BUF_MODE_DOUBLE                  0x40000
40 #define SCALER_BUF_NEXT_0                       0x0
41 #define SCALER_BUF_NEXT_1                       0x80000
42 #define SCALER_BUF_STATUS_0                     0x0
43 #define SCALER_BUF_STATUS_1                     0x100000
44
45 #define OVERLAY_MIX_G_CMP                       0x0
46 #define OVERLAY_MIX_ALWAYS_G                    0x100
47 #define OVERLAY_MIX_ALWAYS_V                    0x200
48 #define OVERLAY_MIX_NOT_G                       0x300
49 #define OVERLAY_MIX_NOT_V                       0x400
50 #define OVERLAY_MIX_G_XOR_V                     0x500
51 #define OVERLAY_MIX_NOT_G_XOR_V         0x600
52 #define OVERLAY_MIX_V_CMP                       0x700
53 #define OVERLAY_MIX_NOT_G_OR_NOT_V      0x800
54 #define OVERLAY_MIX_G_OR_NOT_V          0x900
55 #define OVERLAY_MIX_NOT_G_OR_V          0xA00
56 #define OVERLAY_MIX_G_OR_V                      0xB00
57 #define OVERLAY_MIX_G_AND_V                     0xC00
58 #define OVERLAY_MIX_NOT_G_AND_V         0xD00
59 #define OVERLAY_MIX_G_AND_NOT_V         0xE00
60 #define OVERLAY_MIX_NOT_G_AND_NOT_V     0xF00
61 #define OVERLAY_EXCLUSIVE_NORMAL        0x0
62 #define OVERLAY_EXCLUSIVE_V_ONLY        0x80000000
63
64 #define VIDEO_IN_8BPP                                   0x2
65 #define VIDEO_IN_16BPP                                  0x4
66 #define VIDEO_IN_32BPP                                  0x6
67 #define VIDEO_IN_VYUY422                                0xB                     /*16 bpp */
68 #define VIDEO_IN_YVYU422                                0xC                     /* 16 bpp */
69 #define SCALE_IN_15BPP                                  0x30000         /* aRGB 1555 */
70 #define SCALE_IN_16BPP                                  0x40000         /* RGB 565 */
71 #define SCALE_IN_32BPP                                  0x60000         /* aRGB 8888 */
72 #define SCALE_IN_YUV9                                   0x90000         /* planar */
73 #define SCALE_IN_YUV12                                  0xA0000         /* planar */
74 #define SCALE_IN_VYUY422                                0xB0000         /* 16 bpp */
75 #define SCALE_IN_YVYU422                                0xC0000         /* 16 bpp */
76 #define HOST_YUV_APERTURE_UPPER                 0x0
77 #define HOST_YUV_APERTURE_LOWER         0x20000000
78 #define HOST_MEM_MODE_Y                         0x40000000
79 #define HOST_MEM_MODE_U                         0x80000000
80 #define HOST_MEM_MODE_V                         0xC0000000
81 #define HOST_MEM_MODE_NORMAL                    HOST_YUV_APERTURE_UPPER 
82
83 enum {
84          VTGTB1S1       = 0x01, /* Asic description for VTB1S1 and GTB1S1. */
85          VT4GTIIC       = 0x3A,         /* asic descr for VT4 and RAGE IIC */
86          GTB1U1         = 0x19,         /* Asic description for GTB1U1. */
87          GTB1S2         = 0x41,         /* Asic description for GTB1S2. */
88          GTB2U1         = 0x1A,
89          GTB2U2         = 0x5A,
90          GTB2U3         = 0x9A,
91          GTIIIC1U1      = 0x1B,         /* 3D RAGE PRO asic descrp. */
92          GTIIIC1U2      = 0x5B,         /* 3D RAGE PRO asic descrp. */
93          GTIIIC2U1      = 0x1C,         /* 3D RAGE PRO asic descrp. */
94          GTIIIC2U2      = 0x5C,         /* 3D RAGE PRO asic descrp. */
95          GTIIIC2U3      = 0x7C,         /* 3D RAGE PRO asic descrp. */
96          GTBC           = 0x3A,         /* 3D RAGE IIC asic descrp. */
97          LTPRO          = 0x9C,         /* 3D RAGE LT PRO */
98 };
99
100 /*
101  * ATI Mach64(CT|ET|G*|V*|L*).
102  */
103 typedef struct Mach64types Mach64types;
104 struct Mach64types {
105         ushort  m64_id;                 /* Chip ID */
106         int     m64_vtgt;               /* Is this a VT or GT chipset? */
107         ulong   m64_ovlclock;           /* Max. overlay clock frequency */
108         int     m64_pro;                /* Is this a PRO? */
109 };
110
111 static ulong mach64refclock;
112 static Mach64types *mach64type;
113 static int mach64revb;                  /* Revision B or greater? */
114
115 static Mach64types mach64s[] = {
116         ('C'<<8)|'T',   0,      1350000, /*?*/  0,      /* 4354: CT */
117         ('E'<<8)|'T',   0,      1350000, /*?*/  0,      /* 4554: ET */
118         ('G'<<8)|'B',   1,      1250000,        1,      /* 4742: 264GT PRO */
119         ('G'<<8)|'D',   1,      1250000,        1,      /* 4744: 264GT PRO */
120         ('G'<<8)|'I',   1,      1250000,        1,      /* 4749: 264GT PRO */
121         ('G'<<8)|'M',   0,      1350000,        0,      /* 474D: Rage XL */
122         ('G'<<8)|'P',   1,      1250000,        1,      /* 4750: 264GT PRO */
123         ('G'<<8)|'Q',   1,      1250000,        1,      /* 4751: 264GT PRO */
124         ('G'<<8)|'R',   1,      1250000,        1,      /* 4752: */
125         ('G'<<8)|'T',   1,      800000,         0,      /* 4754: 264GT[B] */
126         ('G'<<8)|'U',   1,      1000000,        0,      /* 4755: 264GT DVD */
127         ('G'<<8)|'V',   1,      1000000,        0,      /* 4756: Rage2C */
128         ('G'<<8)|'Z',   1,      1000000,        0,      /* 475A: Rage2C */
129         ('V'<<8)|'T',   1,      800000,         0,      /* 5654: 264VT/GT/VTB */
130         ('V'<<8)|'U',   1,      800000,         0,      /* 5655: 264VT3 */
131         ('V'<<8)|'V',   1,      1000000,        0,      /* 5656: 264VT4 */
132         ('L'<<8)|'B',   0,      1350000,        1,      /* 4C42: Rage LTPro AGP */
133         ('L'<<8)|'I',   0,      1350000,        0,      /* 4C49: Rage LTPro AGP */
134         ('L'<<8)|'M',   0,      1350000,        0,      /* 4C4D: Rage Mobility */
135         ('L'<<8)|'P',   0,      1350000,        1,      /* 4C50: 264LT PRO */
136 };
137
138
139 static int hwfill(VGAscr*, Rectangle, ulong);
140 static int hwscroll(VGAscr*, Rectangle, Rectangle);
141 static void initengine(VGAscr*);
142
143 static void
144 mach64xxenable(VGAscr* scr)
145 {
146         Pcidev *p;
147         int i;
148
149         if(scr->io)
150                 return;
151         p = scr->pci;
152         if(p == nil || p->vid != 0x1002)
153                 return;
154
155         mach64type = nil;
156         for (i = 0; i != nelem(mach64s); i++)
157                 if (mach64s[i].m64_id == p->did) {
158                         scr->id = p->did;
159                         mach64type = &mach64s[i];
160                         break;                  
161                 }
162
163         if(mach64type != nil){
164                 /*
165                  * The CT doesn't always have the I/O base address
166                  * in the PCI base registers. There is a way to find
167                  * it via the vendor-specific PCI config space but
168                  * this will do for now.
169                  */
170                 scr->io = p->mem[1].bar & ~0x03;
171                 if(scr->io == 0)
172                         scr->io = 0x2EC;
173         }
174 }
175
176 static void
177 mach64xxlinear(VGAscr* scr, int size, int)
178 {
179         vgalinearpci(scr);
180         if(scr->paddr == 0)
181                 return;
182         scr->mmio = (ulong*)((uchar*)scr->vaddr+size-1024);
183         addvgaseg("mach64mmio", scr->paddr+size-BY2PG, BY2PG);
184         addvgaseg("mach64screen", scr->paddr, scr->apsize);
185 }
186
187 enum {
188         CrtcOffPitch    = 0x05,
189         CrtcGenCtl      = 0x07,
190         CurClr0         = 0x0B,         /* I/O Select */
191         CurClr1         = 0x0C,
192         CurOffset       = 0x0D,
193         CurHVposn       = 0x0E,
194         CurHVoff        = 0x0F,
195         BusCntl = 0x13,
196         GenTestCntl     = 0x19,
197
198         CrtcHsyncDis    = 0x04,
199         CrtcVsyncDis    = 0x08,
200
201         ContextMask     = 0x100,        /* not accessible via I/O */
202         FifoStat,
203         GuiStat,
204         DpFrgdClr,
205         DpBkgdClr,
206         DpWriteMask,
207         DpMix,
208         DpPixWidth,
209         DpSrc,
210         ClrCmpCntl,
211         GuiTrajCntl,
212         ScLeftRight,
213         ScTopBottom,
214         DstOffPitch,
215         DstYX,
216         DstHeightWidth,
217         DstCntl,
218         DstHeight,
219         DstBresErr,
220         DstBresInc,
221         DstBresDec,
222         SrcCntl,
223         SrcHeight1Width1,
224         SrcHeight2Width2,
225         SrcYX,
226         SrcWidth1,
227         SrcYXstart,
228         HostCntl,
229         PatReg0,
230         PatReg1,
231         PatCntl,
232         ScBottom,
233         ScLeft,
234         ScRight,
235         ScTop,
236         ClrCmpClr,
237         ClrCmpMask,
238         DpChainMask,
239         SrcOffPitch,    
240         LcdIndex,
241         LcdData,
242         ClockCntl,
243         OverlayScaleCntl,
244         ConfigChipId,
245         Buf0Pitch,
246         ScalerBuf0Pitch,
247         CaptureConfig,
248         OverlayKeyCntl,
249         ScalerColourCntl,
250         ScalerHCoef0,
251         ScalerHCoef1,
252         ScalerHCoef2,
253         ScalerHCoef3,
254         ScalerHCoef4,
255         VideoFormat,
256         Buf0Offset,
257         ScalerBuf0Offset,
258         CrtcGenCntl,
259         OverlayScaleInc,
260         OverlayYX,
261         OverlayYXEnd,
262         ScalerHeightWidth,
263         HTotalDisp,
264         VTotalDisp,
265 };
266
267 enum {
268         LCD_ConfigPanel = 0,
269         LCD_GenCtrl,
270         LCD_DstnCntl,
271         LCD_HfbPitchAddr,
272         LCD_HorzStretch,
273         LCD_VertStretch,
274         LCD_ExtVertStretch,
275         LCD_LtGio,
276         LCD_PowerMngmnt,
277         LCD_ZvgPio,
278         Nlcd,
279 };
280
281 #define Bank1                   (-0x100)                /* 1KB */
282
283 static int mmoffset[] = {
284         [HTotalDisp]            0x00,
285         [VTotalDisp]            0x02,
286         [CrtcOffPitch]          0x05,
287         [CrtcGenCntl]           0x07,
288         [CurClr0]                       0x18,
289         [CurClr1]                       0x19,
290         [CurOffset]             0x1A,
291         [CurHVposn]             0x1B,
292         [CurHVoff]              0x1C,
293         [ClockCntl]             0x24,
294         [BusCntl]                       0x28,
295         [LcdIndex]              0x29,
296         [LcdData]                       0x2A,
297         [GenTestCntl]           0x34,
298         [ConfigChipId]          0x38,
299         [DstOffPitch]           0x40,
300         [DstYX]                 0x43,
301         [DstHeight]             0x45,
302         [DstHeightWidth]        0x46,
303         [DstBresErr]            0x49,
304         [DstBresInc]            0x4A,
305         [DstBresDec]            0x4B,
306         [DstCntl]                       0x4C,
307         [SrcOffPitch]           0x60,
308         [SrcYX]                 0x63,
309         [SrcWidth1]             0x64,
310         [SrcYXstart]            0x69,
311         [SrcHeight1Width1]      0x66,
312         [SrcHeight2Width2]      0x6C,
313         [SrcCntl]                       0x6D,
314         [HostCntl]                      0x90,
315         [PatReg0]                       0xA0,
316         [PatReg1]                       0xA1,
317         [PatCntl]                       0xA2,
318         [ScLeft]                        0xA8,
319         [ScRight]                       0xA9,
320         [ScLeftRight]           0xAA,
321         [ScTop]                 0xAB,
322         [ScBottom]              0xAC,
323         [ScTopBottom]           0xAD,
324         [DpBkgdClr]             0xB0,
325         [DpFrgdClr]             0xB1,
326         [DpWriteMask]           0xB2,
327         [DpChainMask]           0xB3,
328         [DpPixWidth]            0xB4,
329         [DpMix]                 0xB5,
330         [DpSrc]                 0xB6,
331         [ClrCmpClr]             0xC0,
332         [ClrCmpMask]            0xC1,
333         [ClrCmpCntl]            0xC2,
334         [FifoStat]                      0xC4,
335         [ContextMask]           0xC8,
336         [GuiTrajCntl]           0xCC,
337         [GuiStat]                       0xCE,
338
339         /* Bank1 */
340         [OverlayYX]             Bank1 + 0x00,
341         [OverlayYXEnd]          Bank1 + 0x01,
342         [OverlayKeyCntl]        Bank1 + 0x06,
343         [OverlayScaleInc]       Bank1 + 0x08,
344         [OverlayScaleCntl]      Bank1 + 0x09,
345         [ScalerHeightWidth]     Bank1 + 0x0A,
346         [ScalerBuf0Offset]      Bank1 + 0x0D,
347         [ScalerBuf0Pitch]       Bank1 + 0x0F,
348         [VideoFormat]           Bank1 + 0x12,
349         [CaptureConfig] Bank1 + 0x14,
350         [Buf0Offset]            Bank1 + 0x20,
351         [Buf0Pitch]             Bank1 + 0x23,
352         [ScalerColourCntl]      Bank1 + 0x54,
353         [ScalerHCoef0]          Bank1 + 0x55,
354         [ScalerHCoef1]          Bank1 + 0x56,
355         [ScalerHCoef2]          Bank1 + 0x57,
356         [ScalerHCoef3]          Bank1 + 0x58,
357         [ScalerHCoef4]          Bank1 + 0x59,
358 };
359
360 static ulong
361 ior32(VGAscr* scr, int r)
362 {
363         if(scr->io == 0x2EC || scr->io == 0x1C8)
364                 return inl((r<<10)+scr->io);
365         if(r >= 0x100 && scr->mmio != nil)
366                 return scr->mmio[mmoffset[r]];
367         return inl((mmoffset[r]<<2)+scr->io);
368 }
369
370 static void
371 iow32(VGAscr* scr, int r, ulong l)
372 {
373         if(scr->io == 0x2EC || scr->io == 0x1C8)
374                 outl(((r)<<10)+scr->io, l);
375         else if(r >= 0x100 && scr->mmio != nil)
376                 scr->mmio[mmoffset[r]] = l;
377         else
378                 outl((mmoffset[r]<<2)+scr->io, l);
379 }
380
381 static ulong
382 lcdr32(VGAscr *scr, ulong r)
383 {
384         ulong or;
385
386         or = ior32(scr, LcdIndex);
387         iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
388         return ior32(scr, LcdData);
389 }
390
391 static void
392 lcdw32(VGAscr *scr, ulong r, ulong v)
393 {
394         ulong or;
395
396         or = ior32(scr, LcdIndex);
397         iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
398         iow32(scr, LcdData, v);
399 }
400
401 static void
402 mach64xxcurdisable(VGAscr* scr)
403 {
404         ulong r;
405
406         r = ior32(scr, GenTestCntl);
407         iow32(scr, GenTestCntl, r & ~0x80);
408 }
409
410 static void
411 mach64xxcurload(VGAscr* scr, Cursor* curs)
412 {
413         uchar *p;
414         int i, y;
415         ulong c, s, m, r;
416
417         /*
418          * Disable the cursor.
419          */
420         r = ior32(scr, GenTestCntl);
421         iow32(scr, GenTestCntl, r & ~0x80);
422
423         p = scr->vaddr;
424         p += scr->storage;
425
426         /*
427          * Initialise the 64x64 cursor RAM array.
428          * The cursor mode gives the following truth table:
429          *      p1 p0   colour
430          *       0  0   Cursor Colour 0
431          *       0  1   Cursor Colour 1
432          *       1  0   Transparent
433          *       1  1   Complement
434          * Put the cursor into the top-right of the 64x64 array.
435          */
436         for(y = 0; y < 16; y++){
437                 for(i = 0; i < (64-16)/8; i++){
438                         *p++ = 0xAA;
439                         *p++ = 0xAA;
440                 }
441
442                 c = (curs->clr[2*y]<<8)|curs->clr[y*2 + 1];
443                 s = (curs->set[2*y]<<8)|curs->set[y*2 + 1];
444
445                 m = 0x00000000;
446                 for(i = 0; i < 16; i++){
447                         if(s & (1<<(15-i)))
448                                 m |= 0x01<<(2*i);
449                         else if(c & (1<<(15-i))){
450                                 /* nothing to do */
451                         }
452                         else
453                                 m |= 0x02<<(2*i);
454                 }
455                 *p++ = m;
456                 *p++ = m>>8;
457                 *p++ = m>>16;
458                 *p++ = m>>24;
459         }
460         memset(p, 0xAA, (64-16)*16);
461
462         /*
463          * Set the cursor hotpoint and enable the cursor.
464          */
465         scr->offset = curs->offset;
466         iow32(scr, GenTestCntl, 0x80|r);
467 }
468
469 static int
470 ptalmostinrect(Point p, Rectangle r)
471 {
472         return p.x>=r.min.x && p.x<=r.max.x &&
473                p.y>=r.min.y && p.y<=r.max.y;
474 }
475
476 static int
477 mach64xxcurmove(VGAscr* scr, Point p)
478 {
479         int x, xo, y, yo;
480
481         /*
482          * Mustn't position the cursor offscreen even partially,
483          * or it disappears. Therefore, if x or y is -ve, adjust the
484          * cursor presets instead. If y is negative also have to
485          * adjust the starting offset.
486          */
487         if((x = p.x+scr->offset.x) < 0){
488                 xo = x;
489                 x = 0;
490         }
491         else
492                 xo = 0;
493         if((y = p.y+scr->offset.y) < 0){
494                 yo = y;
495                 y = 0;
496         }
497         else
498                 yo = 0;
499
500         iow32(scr, CurHVoff, ((64-16-yo)<<16)|(64-16-xo));
501         iow32(scr, CurOffset, scr->storage/8 + (-yo*2));
502         iow32(scr, CurHVposn, (y<<16)|x);
503
504         return 0;
505 }
506
507 static void
508 mach64xxcurenable(VGAscr* scr)
509 {
510         ulong r, storage;
511
512         mach64xxenable(scr);
513         if(scr->io == 0)
514                 return;
515
516         r = ior32(scr, GenTestCntl);
517         iow32(scr, GenTestCntl, r & ~0x80);
518
519         iow32(scr, CurClr0, (Pwhite<<24)|(Pwhite<<16)|(Pwhite<<8)|Pwhite);
520         iow32(scr, CurClr1, (Pblack<<24)|(Pblack<<16)|(Pblack<<8)|Pblack);
521
522         /*
523          * Find a place for the cursor data in display memory.
524          * Must be 64-bit aligned.
525          */
526         storage = (scr->pitch*scr->height+7)/8;
527         iow32(scr, CurOffset, storage);
528         scr->storage = storage*8;
529
530         /*
531          * Cursor goes in the top right corner of the 64x64 array
532          * so the horizontal and vertical presets are 64-16.
533          */
534         iow32(scr, CurHVposn, (0<<16)|0);
535         iow32(scr, CurHVoff, ((64-16)<<16)|(64-16));
536
537         /*
538          * Load, locate and enable the 64x64 cursor.
539          */
540         mach64xxcurload(scr, &cursor);
541         mach64xxcurmove(scr, ZP);
542         iow32(scr, GenTestCntl, 0x80|r);
543 }
544
545 static void
546 waitforfifo(VGAscr *scr, int entries)
547 {
548         int x;
549
550         x = 0;
551         while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && x++ < 1000000)
552                 ;
553         if(x >= 1000000)
554                 iprint("fifo %d stat %#.8lux %#.8lux scrio %#.8lux mmio %#p scr %#p pc %#p\n", entries, ior32(scr, FifoStat), scr->mmio[mmoffset[FifoStat]], scr->io, scr->mmio, scr, getcallerpc(&scr));
555 }
556
557 static void
558 waitforidle(VGAscr *scr)
559 {
560         int x;
561
562         waitforfifo(scr, 16);
563         x = 0;
564         while((ior32(scr, GuiStat)&1) && x++ < 1000000)
565                 ;
566         if(x >= 1000000)
567                 iprint("idle stat %#.8lux %#.8lux scrio %#.8lux mmio %#p scr %#p pc %#p\n", ior32(scr, GuiStat), scr->mmio[mmoffset[GuiStat]], scr->io, scr->mmio, scr, getcallerpc(&scr));
568 }
569
570 static void
571 resetengine(VGAscr *scr)
572 {
573         ulong x;
574         x = ior32(scr, GenTestCntl);
575         iow32(scr, GenTestCntl, x&~0x100);
576         iow32(scr, GenTestCntl, x|0x100);
577         iow32(scr, BusCntl, ior32(scr, BusCntl)|0x00A00000);
578 }
579
580 static void
581 initengine(VGAscr *scr)
582 {
583         uchar *bios;
584         ushort table;
585
586         resetengine(scr);
587         waitforfifo(scr, 14);
588         iow32(scr, ContextMask, ~0);
589         iow32(scr, DstOffPitch, scr->pitch<<22);
590         iow32(scr, DstYX, 0);
591         iow32(scr, DstHeight, 0);
592         iow32(scr, DstBresErr, 0);
593         iow32(scr, DstBresInc, 0);
594         iow32(scr, DstBresDec, 0);
595         iow32(scr, DstCntl, 0x23);
596         iow32(scr, SrcOffPitch, scr->pitch<<22);
597         iow32(scr, SrcYX, 0);
598         iow32(scr, SrcHeight1Width1, 1);
599         iow32(scr, SrcYXstart, 0);
600         iow32(scr, SrcHeight2Width2, 1);
601         iow32(scr, SrcCntl, 0x01);
602
603         waitforfifo(scr, 13);
604         iow32(scr, HostCntl, 0);
605         iow32(scr, PatReg0, 0);
606         iow32(scr, PatReg1, 0);
607         iow32(scr, PatCntl, 0);
608         iow32(scr, ScLeft, 0);
609         iow32(scr, ScTop, 0);
610         iow32(scr, ScBottom, 0xFFFF);
611         iow32(scr, ScRight, 0xFFFF);
612         iow32(scr, DpBkgdClr, 0);
613         iow32(scr, DpFrgdClr, ~0);
614         iow32(scr, DpWriteMask, ~0);
615         iow32(scr, DpMix, 0x70003);
616         iow32(scr, DpSrc, 0x00010100);
617
618         waitforfifo(scr, 3);
619         iow32(scr, ClrCmpClr, 0);
620         iow32(scr, ClrCmpMask, ~0);
621         iow32(scr, ClrCmpCntl, 0);
622
623         waitforfifo(scr, 2);
624         switch(scr->gscreen->depth){
625         case 8:
626         case 24:        /* [sic] */
627                 iow32(scr, DpPixWidth, 0x00020202);
628                 iow32(scr, DpChainMask, 0x8080);
629                 break;
630         case 16:
631                 iow32(scr, DpPixWidth, 0x00040404);
632                 iow32(scr, DpChainMask, 0x8410);
633                 break;
634         case 32:
635                 iow32(scr, DpPixWidth, 0x00060606);
636                 iow32(scr, DpChainMask, 0x8080);
637                 break;
638         }
639
640         /* Get the base freq from the BIOS */
641         bios  = kaddr(0xC000);
642         table = *(ushort *)(bios + 0x48);
643         table = *(ushort *)(bios + table + 0x10);
644         switch (*(ushort *)(bios + table + 0x08)) {
645         case 2700: 
646                 mach64refclock = 270000; 
647                 break;
648         case 2863: 
649         case 2864: 
650                 mach64refclock = 286363; 
651                 break;
652         case 2950: 
653                 mach64refclock = 294989; 
654                 break;
655         case 1432: 
656         default:
657                 mach64refclock = 143181; 
658                 break ; 
659         }
660         
661         /* Figure out which revision this chip is */
662         switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) {
663         case VTGTB1S1:
664         case GTB1U1:
665         case GTB1S2:
666         case GTB2U1:
667         case GTB2U2:
668         case GTB2U3:
669         case GTBC:
670         case GTIIIC1U1:
671         case GTIIIC1U2:
672         case GTIIIC2U1:
673         case GTIIIC2U2: 
674         case GTIIIC2U3: 
675         case LTPRO:
676                         mach64revb = 1;
677                         break;
678         default: 
679                         mach64revb = 0;
680                         break;
681         }
682
683         waitforidle(scr);
684 }
685
686 static int
687 mach64hwfill(VGAscr *scr, Rectangle r, ulong sval)
688 {
689         ulong ctl;
690
691         /* shouldn't happen */
692         if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0)
693                 return 0;
694
695         ctl = 1|2;      /* left-to-right, top-to-bottom */
696         if(scr->gscreen->depth == 24){
697                 r.min.x *= 3;
698                 r.max.x *= 3;
699                 ctl |= (1<<7)|(((r.min.x/4)%6)<<8);
700         }
701
702         waitforfifo(scr, 11);
703         iow32(scr, DpFrgdClr, sval);
704         iow32(scr, DpWriteMask, 0xFFFFFFFF);
705         iow32(scr, DpMix, 0x00070003);
706         iow32(scr, DpSrc, 0x00000111);
707         iow32(scr, ClrCmpCntl, 0x00000000);
708         iow32(scr, ScLeftRight, 0x1FFF0000);
709         iow32(scr, ScTopBottom, 0x1FFF0000);
710         iow32(scr, DstOffPitch, scr->pitch<<22);
711         iow32(scr, DstCntl, ctl);
712         iow32(scr, DstYX, (r.min.x<<16)|r.min.y);
713         iow32(scr, DstHeightWidth, (Dx(r)<<16)|Dy(r));
714
715         waitforidle(scr);
716         return 1;
717 }
718
719 static int
720 mach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
721 {
722         Point dp, sp;
723         ulong ctl;
724         int dx, dy;
725
726         dx = Dx(r);
727         dy = Dy(r);
728         if(scr->gscreen->depth == 24){
729                 dx *= 3;
730                 r.min.x *= 3;
731                 sr.min.x *= 3;
732         }
733
734         ctl = 0;
735         if(r.min.x <= sr.min.x){
736                 ctl |= 1;
737                 dp.x = r.min.x;
738                 sp.x = sr.min.x;
739         }else{
740                 dp.x = r.min.x+dx-1;
741                 sp.x = sr.min.x+dx-1;
742         }
743
744         if(r.min.y <= sr.min.y){
745                 ctl |= 2;
746                 dp.y = r.min.y;
747                 sp.y = sr.min.y;
748         }else{
749                 dp.y = r.min.y+dy-1;
750                 sp.y = sr.min.y+dy-1;
751         }
752
753         if(scr->gscreen->depth == 24)
754                 ctl |= (1<<7)|(((dp.x/4)%6)<<8);
755
756         waitforfifo(scr, 6);
757         iow32(scr, ScLeftRight, 0x1FFF0000);
758         iow32(scr, ScTopBottom, 0x1FFF0000);
759         iow32(scr, DpWriteMask, 0xFFFFFFFF);
760         iow32(scr, DpMix, 0x00070003);
761         iow32(scr, DpSrc, 0x00000300);
762         iow32(scr, ClrCmpCntl, 0x00000000);
763
764         waitforfifo(scr, 8);
765         iow32(scr, SrcOffPitch, scr->pitch<<22);
766         iow32(scr, SrcCntl, 0x00000000);
767         iow32(scr, SrcYX, (sp.x<<16)|sp.y);
768         iow32(scr, SrcWidth1, dx);
769         iow32(scr, DstOffPitch, scr->pitch<<22);
770         iow32(scr, DstCntl, ctl);
771
772         iow32(scr, DstYX, (dp.x<<16)|dp.y);
773         iow32(scr, DstHeightWidth, (dx<<16)|dy);
774
775         waitforidle(scr);
776
777         return 1;
778 }
779
780 /*
781  * This should work, but doesn't.
782  * It messes up the screen timings for some reason.
783  */
784 static void
785 mach64blank(VGAscr *scr, int blank)
786 {
787         ulong ctl;
788
789         ctl = ior32(scr, CrtcGenCtl) & ~(CrtcHsyncDis|CrtcVsyncDis);
790         if(blank)
791                 ctl |= CrtcHsyncDis|CrtcVsyncDis;
792         iow32(scr, CrtcGenCtl, ctl);
793 }
794
795 /*
796  * We squirrel away whether the LCD and/or CRT were
797  * on when we were called to blank the screen, and
798  * restore the old state.  If we are called to blank the
799  * screen when it is already blank, we don't update the state.
800  * Such a call sequence should not happen, though.
801  *
802  * We could try forcing the chip into power management
803  * mode instead, but I'm not sure how that would interact
804  * with screen updates going on while the screen is blanked.
805  */
806 static void
807 mach64lcdblank(VGAscr *scr, int blank)
808 {
809         static int crtlcd;
810         ulong x;
811
812         if(blank) {
813                 x = lcdr32(scr, LCD_GenCtrl);
814                 if(x & 3) {
815                         crtlcd = x & 3;
816                         lcdw32(scr, LCD_GenCtrl,  x&~3);
817                 }
818         } else {
819                 if(crtlcd == 0)
820                         crtlcd = 2;     /* lcd only */
821                 x = lcdr32(scr, LCD_GenCtrl);
822                 lcdw32(scr, LCD_GenCtrl, x | crtlcd);
823         }
824 }
825
826 static void
827 mach64xxdrawinit(VGAscr *scr)
828 {
829         if(scr->io > 0x2FF){
830                 initengine(scr);
831                 scr->fill = mach64hwfill;
832                 scr->scroll = mach64hwscroll;
833         }
834 /*      scr->blank = mach64blank; */
835         switch(scr->id){
836         default:
837                 break;
838         case ('L'<<8)|'B':              /* 4C42: Rage 3D LTPro */
839         case ('L'<<8)|'I':              /* 4C49: Rage 3D LTPro */
840         case ('L'<<8)|'M':              /* 4C4D: Rage Mobility */
841         case ('L'<<8)|'P':              /* 4C50: Rage 3D LTPro */
842                 scr->blank = mach64lcdblank;
843                 break;
844         }
845 }
846
847 VGAdev vgamach64xxdev = {
848         "mach64xx",
849
850         mach64xxenable,                 /* enable */
851         0,                              /* disable */
852         0,                              /* page */
853         mach64xxlinear,                 /* linear */
854         mach64xxdrawinit,               /* drawinit */
855 };
856
857 VGAcur vgamach64xxcur = {
858         "mach64xxhwgc",
859
860         mach64xxcurenable,              /* enable */
861         mach64xxcurdisable,             /* disable */
862         mach64xxcurload,                /* load */
863         mach64xxcurmove,                /* move */
864 };
865