FreeBSD/Linux Kernel Cross Reference
sys/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/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 char Eunsupportedformat[] = "unsupported video format";
16 char Enotconfigured[] = "device not configured";
17
18 #define SCALE_ZERO_EXTEND 0x0
19 #define SCALE_DYNAMIC 0x1
20 #define SCALE_RED_TEMP_6500K 0x0
21 #define SCALE_RED_TEMP_9800K 0x2
22 #define SCALE_HORZ_BLEND 0x0
23 #define SCALE_HORZ_REP 0x4
24 #define SCALE_VERT_BLEND 0x0
25 #define SCALE_VERT_REP 0x8
26 #define SCALE_BANDWIDTH_NORMAL 0x0
27 #define SCALE_BANDWIDTH_EXCEEDED 0x4000000
28 #define SCALE_BANDWIDTH_RESET 0x4000000
29 #define SCALE_CLK_ACTIVITY 0x0
30 #define SCALE_CLK_CONTINUOUS 0x20000000
31 #define OVERLAY_DISABLE 0x0
32 #define OVERLAY_ENABLE 0x40000000
33 #define SCALE_DISABLE 0x0
34 #define SCALE_ENABLE 0x80000000
35
36 #define SCALER_FRAME_READ_MODE_FULL 0x0
37 #define SCALER_BUF_MODE_SINGLE 0x0
38 #define SCALER_BUF_MODE_DOUBLE 0x40000
39 #define SCALER_BUF_NEXT_0 0x0
40 #define SCALER_BUF_NEXT_1 0x80000
41 #define SCALER_BUF_STATUS_0 0x0
42 #define SCALER_BUF_STATUS_1 0x100000
43
44 #define OVERLAY_MIX_G_CMP 0x0
45 #define OVERLAY_MIX_ALWAYS_G 0x100
46 #define OVERLAY_MIX_ALWAYS_V 0x200
47 #define OVERLAY_MIX_NOT_G 0x300
48 #define OVERLAY_MIX_NOT_V 0x400
49 #define OVERLAY_MIX_G_XOR_V 0x500
50 #define OVERLAY_MIX_NOT_G_XOR_V 0x600
51 #define OVERLAY_MIX_V_CMP 0x700
52 #define OVERLAY_MIX_NOT_G_OR_NOT_V 0x800
53 #define OVERLAY_MIX_G_OR_NOT_V 0x900
54 #define OVERLAY_MIX_NOT_G_OR_V 0xA00
55 #define OVERLAY_MIX_G_OR_V 0xB00
56 #define OVERLAY_MIX_G_AND_V 0xC00
57 #define OVERLAY_MIX_NOT_G_AND_V 0xD00
58 #define OVERLAY_MIX_G_AND_NOT_V 0xE00
59 #define OVERLAY_MIX_NOT_G_AND_NOT_V 0xF00
60 #define OVERLAY_EXCLUSIVE_NORMAL 0x0
61 #define OVERLAY_EXCLUSIVE_V_ONLY 0x80000000
62
63 #define VIDEO_IN_8BPP 0x2
64 #define VIDEO_IN_16BPP 0x4
65 #define VIDEO_IN_32BPP 0x6
66 #define VIDEO_IN_VYUY422 0xB /*16 bpp */
67 #define VIDEO_IN_YVYU422 0xC /* 16 bpp */
68 #define SCALE_IN_15BPP 0x30000 /* aRGB 1555 */
69 #define SCALE_IN_16BPP 0x40000 /* RGB 565 */
70 #define SCALE_IN_32BPP 0x60000 /* aRGB 8888 */
71 #define SCALE_IN_YUV9 0x90000 /* planar */
72 #define SCALE_IN_YUV12 0xA0000 /* planar */
73 #define SCALE_IN_VYUY422 0xB0000 /* 16 bpp */
74 #define SCALE_IN_YVYU422 0xC0000 /* 16 bpp */
75 #define HOST_YUV_APERTURE_UPPER 0x0
76 #define HOST_YUV_APERTURE_LOWER 0x20000000
77 #define HOST_MEM_MODE_Y 0x40000000
78 #define HOST_MEM_MODE_U 0x80000000
79 #define HOST_MEM_MODE_V 0xC0000000
80 #define HOST_MEM_MODE_NORMAL HOST_YUV_APERTURE_UPPER
81
82 static Chan *ovl_chan; /* Channel of controlling process */
83 static int ovl_width; /* Width of input overlay buffer */
84 static int ovl_height; /* Height of input overlay buffer */
85 static int ovl_format; /* Overlay format */
86 static ulong ovl_fib; /* Frame in bytes */
87
88 enum {
89 VTGTB1S1 = 0x01, /* Asic description for VTB1S1 and GTB1S1. */
90 VT4GTIIC = 0x3A, /* asic descr for VT4 and RAGE IIC */
91 GTB1U1 = 0x19, /* Asic description for GTB1U1. */
92 GTB1S2 = 0x41, /* Asic description for GTB1S2. */
93 GTB2U1 = 0x1A,
94 GTB2U2 = 0x5A,
95 GTB2U3 = 0x9A,
96 GTIIIC1U1 = 0x1B, /* 3D RAGE PRO asic descrp. */
97 GTIIIC1U2 = 0x5B, /* 3D RAGE PRO asic descrp. */
98 GTIIIC2U1 = 0x1C, /* 3D RAGE PRO asic descrp. */
99 GTIIIC2U2 = 0x5C, /* 3D RAGE PRO asic descrp. */
100 GTIIIC2U3 = 0x7C, /* 3D RAGE PRO asic descrp. */
101 GTBC = 0x3A, /* 3D RAGE IIC asic descrp. */
102 LTPRO = 0x9C, /* 3D RAGE LT PRO */
103 };
104
105 /*
106 * ATI Mach64(CT|ET|G*|V*|L*).
107 */
108 typedef struct Mach64types Mach64types;
109 struct Mach64types {
110 ushort m64_id; /* Chip ID */
111 int m64_vtgt; /* Is this a VT or GT chipset? */
112 ulong m64_ovlclock; /* Max. overlay clock frequency */
113 int m64_pro; /* Is this a PRO? */
114 };
115
116 static ulong mach64refclock;
117 static Mach64types *mach64type;
118 static int mach64revb; /* Revision B or greater? */
119 static ulong mach64overlay; /* Overlay buffer */
120
121 static Mach64types mach64s[] = {
122 ('C'<<8)|'T', 0, 1350000, /*?*/ 0, /* 4354: CT */
123 ('E'<<8)|'T', 0, 1350000, /*?*/ 0, /* 4554: ET */
124 ('G'<<8)|'B', 1, 1250000, 1, /* 4742: 264GT PRO */
125 ('G'<<8)|'D', 1, 1250000, 1, /* 4744: 264GT PRO */
126 ('G'<<8)|'I', 1, 1250000, 1, /* 4749: 264GT PRO */
127 ('G'<<8)|'M', 0, 1350000, 0, /* 474D: Rage XL */
128 ('G'<<8)|'P', 1, 1250000, 1, /* 4750: 264GT PRO */
129 ('G'<<8)|'Q', 1, 1250000, 1, /* 4751: 264GT PRO */
130 ('G'<<8)|'R', 1, 1250000, 1, /* 4752: */
131 ('G'<<8)|'T', 1, 800000, 0, /* 4754: 264GT[B] */
132 ('G'<<8)|'U', 1, 1000000, 0, /* 4755: 264GT DVD */
133 ('G'<<8)|'V', 1, 1000000, 0, /* 4756: Rage2C */
134 ('G'<<8)|'Z', 1, 1000000, 0, /* 475A: Rage2C */
135 ('V'<<8)|'T', 1, 800000, 0, /* 5654: 264VT/GT/VTB */
136 ('V'<<8)|'U', 1, 800000, 0, /* 5655: 264VT3 */
137 ('V'<<8)|'V', 1, 1000000, 0, /* 5656: 264VT4 */
138 ('L'<<8)|'B', 0, 1350000, 1, /* 4C42: Rage LTPro AGP */
139 ('L'<<8)|'I', 0, 1350000, 0, /* 4C49: Rage LTPro AGP */
140 ('L'<<8)|'M', 0, 1350000, 0, /* 4C4D: Rage Mobility */
141 ('L'<<8)|'P', 0, 1350000, 1, /* 4C50: 264LT PRO */
142 };
143
144
145 static int hwfill(VGAscr*, Rectangle, ulong);
146 static int hwscroll(VGAscr*, Rectangle, Rectangle);
147 static void initengine(VGAscr*);
148
149 static Pcidev*
150 mach64xxpci(void)
151 {
152 Pcidev *p;
153 int i;
154
155 if((p = pcimatch(nil, 0x1002, 0)) == nil)
156 return nil;
157
158 for (i = 0; i != nelem(mach64s); i++)
159 if (mach64s[i].m64_id == p->did) {
160 mach64type = &mach64s[i];
161 return p;
162 }
163 return nil;
164 }
165
166 static void
167 mach64xxenable(VGAscr* scr)
168 {
169 Pcidev *p;
170
171 if(scr->io)
172 return;
173 if(p = mach64xxpci()){
174 scr->id = p->did;
175 scr->pci = p;
176
177 /*
178 * The CT doesn't always have the I/O base address
179 * in the PCI base registers. There is a way to find
180 * it via the vendor-specific PCI config space but
181 * this will do for now.
182 */
183 scr->io = p->mem[1].bar & ~0x03;
184
185 if(scr->io == 0)
186 scr->io = 0x2EC;
187 }
188 }
189
190 static void
191 mach64xxlinear(VGAscr* scr, int size, int)
192 {
193 vgalinearpci(scr);
194 if(scr->paddr == 0)
195 return;
196 scr->mmio = (ulong*)((uchar*)scr->vaddr+size-1024);
197 addvgaseg("mach64mmio", scr->paddr+size-BY2PG, BY2PG);
198 addvgaseg("mach64screen", scr->paddr, scr->apsize);
199 }
200
201 enum {
202 CrtcOffPitch = 0x05,
203 CrtcGenCtl = 0x07,
204 CurClr0 = 0x0B, /* I/O Select */
205 CurClr1 = 0x0C,
206 CurOffset = 0x0D,
207 CurHVposn = 0x0E,
208 CurHVoff = 0x0F,
209 BusCntl = 0x13,
210 GenTestCntl = 0x19,
211
212 CrtcHsyncDis = 0x04,
213 CrtcVsyncDis = 0x08,
214
215 ContextMask = 0x100, /* not accessible via I/O */
216 FifoStat,
217 GuiStat,
218 DpFrgdClr,
219 DpBkgdClr,
220 DpWriteMask,
221 DpMix,
222 DpPixWidth,
223 DpSrc,
224 ClrCmpCntl,
225 GuiTrajCntl,
226 ScLeftRight,
227 ScTopBottom,
228 DstOffPitch,
229 DstYX,
230 DstHeightWidth,
231 DstCntl,
232 DstHeight,
233 DstBresErr,
234 DstBresInc,
235 DstBresDec,
236 SrcCntl,
237 SrcHeight1Width1,
238 SrcHeight2Width2,
239 SrcYX,
240 SrcWidth1,
241 SrcYXstart,
242 HostCntl,
243 PatReg0,
244 PatReg1,
245 PatCntl,
246 ScBottom,
247 ScLeft,
248 ScRight,
249 ScTop,
250 ClrCmpClr,
251 ClrCmpMask,
252 DpChainMask,
253 SrcOffPitch,
254 LcdIndex,
255 LcdData,
256 ClockCntl,
257 OverlayScaleCntl,
258 ConfigChipId,
259 Buf0Pitch,
260 ScalerBuf0Pitch,
261 CaptureConfig,
262 OverlayKeyCntl,
263 ScalerColourCntl,
264 ScalerHCoef0,
265 ScalerHCoef1,
266 ScalerHCoef2,
267 ScalerHCoef3,
268 ScalerHCoef4,
269 VideoFormat,
270 Buf0Offset,
271 ScalerBuf0Offset,
272 CrtcGenCntl,
273 OverlayScaleInc,
274 OverlayYX,
275 OverlayYXEnd,
276 ScalerHeightWidth,
277 HTotalDisp,
278 VTotalDisp,
279 };
280
281 enum {
282 LCD_ConfigPanel = 0,
283 LCD_GenCtrl,
284 LCD_DstnCntl,
285 LCD_HfbPitchAddr,
286 LCD_HorzStretch,
287 LCD_VertStretch,
288 LCD_ExtVertStretch,
289 LCD_LtGio,
290 LCD_PowerMngmnt,
291 LCD_ZvgPio,
292 Nlcd,
293 };
294
295 #define Bank1 (-0x100) /* 1KB */
296
297 static int mmoffset[] = {
298 [HTotalDisp] 0x00,
299 [VTotalDisp] 0x02,
300 [CrtcOffPitch] 0x05,
301 [CrtcGenCntl] 0x07,
302 [CurClr0] 0x18,
303 [CurClr1] 0x19,
304 [CurOffset] 0x1A,
305 [CurHVposn] 0x1B,
306 [CurHVoff] 0x1C,
307 [ClockCntl] 0x24,
308 [BusCntl] 0x28,
309 [LcdIndex] 0x29,
310 [LcdData] 0x2A,
311 [GenTestCntl] 0x34,
312 [ConfigChipId] 0x38,
313 [DstOffPitch] 0x40,
314 [DstYX] 0x43,
315 [DstHeight] 0x45,
316 [DstHeightWidth] 0x46,
317 [DstBresErr] 0x49,
318 [DstBresInc] 0x4A,
319 [DstBresDec] 0x4B,
320 [DstCntl] 0x4C,
321 [SrcOffPitch] 0x60,
322 [SrcYX] 0x63,
323 [SrcWidth1] 0x64,
324 [SrcYXstart] 0x69,
325 [SrcHeight1Width1] 0x66,
326 [SrcHeight2Width2] 0x6C,
327 [SrcCntl] 0x6D,
328 [HostCntl] 0x90,
329 [PatReg0] 0xA0,
330 [PatReg1] 0xA1,
331 [PatCntl] 0xA2,
332 [ScLeft] 0xA8,
333 [ScRight] 0xA9,
334 [ScLeftRight] 0xAA,
335 [ScTop] 0xAB,
336 [ScBottom] 0xAC,
337 [ScTopBottom] 0xAD,
338 [DpBkgdClr] 0xB0,
339 [DpFrgdClr] 0xB1,
340 [DpWriteMask] 0xB2,
341 [DpChainMask] 0xB3,
342 [DpPixWidth] 0xB4,
343 [DpMix] 0xB5,
344 [DpSrc] 0xB6,
345 [ClrCmpClr] 0xC0,
346 [ClrCmpMask] 0xC1,
347 [ClrCmpCntl] 0xC2,
348 [FifoStat] 0xC4,
349 [ContextMask] 0xC8,
350 [GuiTrajCntl] 0xCC,
351 [GuiStat] 0xCE,
352
353 /* Bank1 */
354 [OverlayYX] Bank1 + 0x00,
355 [OverlayYXEnd] Bank1 + 0x01,
356 [OverlayKeyCntl] Bank1 + 0x06,
357 [OverlayScaleInc] Bank1 + 0x08,
358 [OverlayScaleCntl] Bank1 + 0x09,
359 [ScalerHeightWidth] Bank1 + 0x0A,
360 [ScalerBuf0Offset] Bank1 + 0x0D,
361 [ScalerBuf0Pitch] Bank1 + 0x0F,
362 [VideoFormat] Bank1 + 0x12,
363 [CaptureConfig] Bank1 + 0x14,
364 [Buf0Offset] Bank1 + 0x20,
365 [Buf0Pitch] Bank1 + 0x23,
366 [ScalerColourCntl] Bank1 + 0x54,
367 [ScalerHCoef0] Bank1 + 0x55,
368 [ScalerHCoef1] Bank1 + 0x56,
369 [ScalerHCoef2] Bank1 + 0x57,
370 [ScalerHCoef3] Bank1 + 0x58,
371 [ScalerHCoef4] Bank1 + 0x59,
372 };
373
374 static ulong
375 ior32(VGAscr* scr, int r)
376 {
377 if(scr->io == 0x2EC || scr->io == 0x1C8)
378 return inl((r<<10)+scr->io);
379 if(r >= 0x100 && scr->mmio != nil)
380 return scr->mmio[mmoffset[r]];
381 return inl((mmoffset[r]<<2)+scr->io);
382 }
383
384 static void
385 iow32(VGAscr* scr, int r, ulong l)
386 {
387 if(scr->io == 0x2EC || scr->io == 0x1C8)
388 outl(((r)<<10)+scr->io, l);
389 else if(r >= 0x100 && scr->mmio != nil)
390 scr->mmio[mmoffset[r]] = l;
391 else
392 outl((mmoffset[r]<<2)+scr->io, l);
393 }
394
395 static ulong
396 lcdr32(VGAscr *scr, ulong r)
397 {
398 ulong or;
399
400 or = ior32(scr, LcdIndex);
401 iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
402 return ior32(scr, LcdData);
403 }
404
405 static void
406 lcdw32(VGAscr *scr, ulong r, ulong v)
407 {
408 ulong or;
409
410 or = ior32(scr, LcdIndex);
411 iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
412 iow32(scr, LcdData, v);
413 }
414
415 static void
416 mach64xxcurdisable(VGAscr* scr)
417 {
418 ulong r;
419
420 r = ior32(scr, GenTestCntl);
421 iow32(scr, GenTestCntl, r & ~0x80);
422 }
423
424 static void
425 mach64xxcurload(VGAscr* scr, Cursor* curs)
426 {
427 uchar *p;
428 int i, y;
429 ulong c, s, m, r;
430
431 /*
432 * Disable the cursor.
433 */
434 r = ior32(scr, GenTestCntl);
435 iow32(scr, GenTestCntl, r & ~0x80);
436
437 p = scr->vaddr;
438 p += scr->storage;
439
440 /*
441 * Initialise the 64x64 cursor RAM array.
442 * The cursor mode gives the following truth table:
443 * p1 p0 colour
444 * 0 0 Cursor Colour 0
445 * 0 1 Cursor Colour 1
446 * 1 0 Transparent
447 * 1 1 Complement
448 * Put the cursor into the top-right of the 64x64 array.
449 */
450 for(y = 0; y < 16; y++){
451 for(i = 0; i < (64-16)/8; i++){
452 *p++ = 0xAA;
453 *p++ = 0xAA;
454 }
455
456 c = (curs->clr[2*y]<<8)|curs->clr[y*2 + 1];
457 s = (curs->set[2*y]<<8)|curs->set[y*2 + 1];
458
459 m = 0x00000000;
460 for(i = 0; i < 16; i++){
461 if(s & (1<<(15-i)))
462 m |= 0x01<<(2*i);
463 else if(c & (1<<(15-i))){
464 /* nothing to do */
465 }
466 else
467 m |= 0x02<<(2*i);
468 }
469 *p++ = m;
470 *p++ = m>>8;
471 *p++ = m>>16;
472 *p++ = m>>24;
473 }
474 memset(p, 0xAA, (64-16)*16);
475
476 /*
477 * Set the cursor hotpoint and enable the cursor.
478 */
479 scr->offset = curs->offset;
480 iow32(scr, GenTestCntl, 0x80|r);
481 }
482
483 static int
484 ptalmostinrect(Point p, Rectangle r)
485 {
486 return p.x>=r.min.x && p.x<=r.max.x &&
487 p.y>=r.min.y && p.y<=r.max.y;
488 }
489
490 /*
491 * If necessary, translate the rectangle physr
492 * some multiple of [dx dy] so that it includes p.
493 * Return 1 if the rectangle changed.
494 */
495 static int
496 screenpan(Point p, Rectangle *physr, int dx, int dy)
497 {
498 int d;
499
500 if(ptalmostinrect(p, *physr))
501 return 0;
502
503 if(p.y < physr->min.y){
504 d = physr->min.y - (p.y&~(dy-1));
505 physr->min.y -= d;
506 physr->max.y -= d;
507 }
508 if(p.y > physr->max.y){
509 d = ((p.y+dy-1)&~(dy-1)) - physr->max.y;
510 physr->min.y += d;
511 physr->max.y += d;
512 }
513
514 if(p.x < physr->min.x){
515 d = physr->min.x - (p.x&~(dx-1));
516 physr->min.x -= d;
517 physr->max.x -= d;
518 }
519 if(p.x > physr->max.x){
520 d = ((p.x+dx-1)&~(dx-1)) - physr->max.x;
521 physr->min.x += d;
522 physr->max.x += d;
523 }
524 return 1;
525 }
526
527 static int
528 mach64xxcurmove(VGAscr* scr, Point p)
529 {
530 int x, xo, y, yo;
531 int dx;
532 ulong off, pitch;
533
534 /*
535 * If the point we want to display is outside the current
536 * screen rectangle, pan the screen to display it.
537 *
538 * We have to move in 64-bit chunks.
539 */
540 if(scr->gscreen->depth == 24)
541 dx = (64*3)/24;
542 else
543 dx = 64 / scr->gscreen->depth;
544
545 if(panning && screenpan(p, &physgscreenr, dx, 1)){
546 off = (physgscreenr.min.y*Dx(scr->gscreen->r)+physgscreenr.min.x)/dx;
547 pitch = Dx(scr->gscreen->r)/8;
548 iow32(scr, CrtcOffPitch, (pitch<<22)|off);
549 }
550
551 p.x -= physgscreenr.min.x;
552 p.y -= physgscreenr.min.y;
553
554 /*
555 * Mustn't position the cursor offscreen even partially,
556 * or it disappears. Therefore, if x or y is -ve, adjust the
557 * cursor presets instead. If y is negative also have to
558 * adjust the starting offset.
559 */
560 if((x = p.x+scr->offset.x) < 0){
561 xo = x;
562 x = 0;
563 }
564 else
565 xo = 0;
566 if((y = p.y+scr->offset.y) < 0){
567 yo = y;
568 y = 0;
569 }
570 else
571 yo = 0;
572
573 iow32(scr, CurHVoff, ((64-16-yo)<<16)|(64-16-xo));
574 iow32(scr, CurOffset, scr->storage/8 + (-yo*2));
575 iow32(scr, CurHVposn, (y<<16)|x);
576
577 return 0;
578 }
579
580 static void
581 mach64xxcurenable(VGAscr* scr)
582 {
583 ulong r, storage;
584
585 mach64xxenable(scr);
586 if(scr->io == 0)
587 return;
588
589 r = ior32(scr, GenTestCntl);
590 iow32(scr, GenTestCntl, r & ~0x80);
591
592 iow32(scr, CurClr0, (Pwhite<<24)|(Pwhite<<16)|(Pwhite<<8)|Pwhite);
593 iow32(scr, CurClr1, (Pblack<<24)|(Pblack<<16)|(Pblack<<8)|Pblack);
594
595 /*
596 * Find a place for the cursor data in display memory.
597 * Must be 64-bit aligned.
598 */
599 storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+7)/8;
600 iow32(scr, CurOffset, storage);
601 scr->storage = storage*8;
602
603 /*
604 * Cursor goes in the top right corner of the 64x64 array
605 * so the horizontal and vertical presets are 64-16.
606 */
607 iow32(scr, CurHVposn, (0<<16)|0);
608 iow32(scr, CurHVoff, ((64-16)<<16)|(64-16));
609
610 /*
611 * Load, locate and enable the 64x64 cursor.
612 */
613 mach64xxcurload(scr, &arrow);
614 mach64xxcurmove(scr, ZP);
615 iow32(scr, GenTestCntl, 0x80|r);
616 }
617
618 static void
619 waitforfifo(VGAscr *scr, int entries)
620 {
621 int x;
622
623 x = 0;
624 while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && x++ < 1000000)
625 ;
626 if(x >= 1000000)
627 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));
628 }
629
630 static void
631 waitforidle(VGAscr *scr)
632 {
633 int x;
634
635 waitforfifo(scr, 16);
636 x = 0;
637 while((ior32(scr, GuiStat)&1) && x++ < 1000000)
638 ;
639 if(x >= 1000000)
640 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));
641 }
642
643 static void
644 resetengine(VGAscr *scr)
645 {
646 ulong x;
647 x = ior32(scr, GenTestCntl);
648 iow32(scr, GenTestCntl, x&~0x100);
649 iow32(scr, GenTestCntl, x|0x100);
650 iow32(scr, BusCntl, ior32(scr, BusCntl)|0x00A00000);
651 }
652
653 static void
654 init_overlayclock(VGAscr *scr)
655 {
656 uchar *cc, save, pll_ref_div, pll_vclk_cntl, vclk_post_div,
657 vclk_fb_div, ecp_div;
658 int i;
659 ulong dotclock;
660
661 /* Taken from GLX */
662 /* Get monitor dotclock, check for Overlay Scaler clock limit */
663 cc = (uchar *)&scr->mmio[mmoffset[ClockCntl]];
664 save = cc[1]; i = cc[0] & 3;
665 cc[1] = 2<<2; pll_ref_div = cc[2];
666 cc[1] = 5<<2; pll_vclk_cntl = cc[2];
667 cc[1] = 6<<2; vclk_post_div = (cc[2]>>(i+i)) & 3;
668 cc[1] = (7+i)<<2; vclk_fb_div = cc[2];
669
670 dotclock = 2 * mach64refclock * vclk_fb_div /
671 (pll_ref_div * (1 << vclk_post_div));
672 /* ecp_div: 0=dotclock, 1=dotclock/2, 2=dotclock/4 */
673 ecp_div = dotclock / mach64type->m64_ovlclock;
674 if (ecp_div>2) ecp_div = 2;
675
676 /* Force a scaler clock factor of 1 if refclock *
677 * is unknown (VCLK_SRC not PLLVCLK) */
678 if ((pll_vclk_cntl & 0x03) != 0x03)
679 ecp_div = 0;
680 if ((pll_vclk_cntl & 0x30) != ecp_div<<4) {
681 cc[1] = (5<<2)|2;
682 cc[2] = (pll_vclk_cntl&0xCF) | (ecp_div<<4);
683 }
684
685 /* Restore PLL Register Index */
686 cc[1] = save;
687 }
688
689 static void
690 initengine(VGAscr *scr)
691 {
692 ulong pitch;
693 uchar *bios;
694 ushort table;
695
696 pitch = Dx(scr->gscreen->r)/8;
697 if(scr->gscreen->depth == 24)
698 pitch *= 3;
699
700 resetengine(scr);
701 waitforfifo(scr, 14);
702 iow32(scr, ContextMask, ~0);
703 iow32(scr, DstOffPitch, pitch<<22);
704 iow32(scr, DstYX, 0);
705 iow32(scr, DstHeight, 0);
706 iow32(scr, DstBresErr, 0);
707 iow32(scr, DstBresInc, 0);
708 iow32(scr, DstBresDec, 0);
709 iow32(scr, DstCntl, 0x23);
710 iow32(scr, SrcOffPitch, pitch<<22);
711 iow32(scr, SrcYX, 0);
712 iow32(scr, SrcHeight1Width1, 1);
713 iow32(scr, SrcYXstart, 0);
714 iow32(scr, SrcHeight2Width2, 1);
715 iow32(scr, SrcCntl, 0x01);
716
717 waitforfifo(scr, 13);
718 iow32(scr, HostCntl, 0);
719 iow32(scr, PatReg0, 0);
720 iow32(scr, PatReg1, 0);
721 iow32(scr, PatCntl, 0);
722 iow32(scr, ScLeft, 0);
723 iow32(scr, ScTop, 0);
724 iow32(scr, ScBottom, 0xFFFF);
725 iow32(scr, ScRight, 0xFFFF);
726 iow32(scr, DpBkgdClr, 0);
727 iow32(scr, DpFrgdClr, ~0);
728 iow32(scr, DpWriteMask, ~0);
729 iow32(scr, DpMix, 0x70003);
730 iow32(scr, DpSrc, 0x00010100);
731
732 waitforfifo(scr, 3);
733 iow32(scr, ClrCmpClr, 0);
734 iow32(scr, ClrCmpMask, ~0);
735 iow32(scr, ClrCmpCntl, 0);
736
737 waitforfifo(scr, 2);
738 switch(scr->gscreen->depth){
739 case 8:
740 case 24: /* [sic] */
741 iow32(scr, DpPixWidth, 0x00020202);
742 iow32(scr, DpChainMask, 0x8080);
743 break;
744 case 16:
745 iow32(scr, DpPixWidth, 0x00040404);
746 iow32(scr, DpChainMask, 0x8410);
747 break;
748 case 32:
749 iow32(scr, DpPixWidth, 0x00060606);
750 iow32(scr, DpChainMask, 0x8080);
751 break;
752 }
753
754 /* Get the base freq from the BIOS */
755 bios = kaddr(0xC000);
756 table = *(ushort *)(bios + 0x48);
757 table = *(ushort *)(bios + table + 0x10);
758 switch (*(ushort *)(bios + table + 0x08)) {
759 case 2700:
760 mach64refclock = 270000;
761 break;
762 case 2863:
763 case 2864:
764 mach64refclock = 286363;
765 break;
766 case 2950:
767 mach64refclock = 294989;
768 break;
769 case 1432:
770 default:
771 mach64refclock = 143181;
772 break ;
773 }
774
775 /* Figure out which revision this chip is */
776 switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) {
777 case VTGTB1S1:
778 case GTB1U1:
779 case GTB1S2:
780 case GTB2U1:
781 case GTB2U2:
782 case GTB2U3:
783 case GTBC:
784 case GTIIIC1U1:
785 case GTIIIC1U2:
786 case GTIIIC2U1:
787 case GTIIIC2U2:
788 case GTIIIC2U3:
789 case LTPRO:
790 mach64revb = 1;
791 break;
792 default:
793 mach64revb = 0;
794 break;
795 }
796
797 waitforidle(scr);
798 }
799
800 static int
801 mach64hwfill(VGAscr *scr, Rectangle r, ulong sval)
802 {
803 ulong pitch;
804 ulong ctl;
805
806 if(drawdebug)
807 iprint("hwfill %R val %lux...\n", r, sval);
808
809 /* shouldn't happen */
810 if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0)
811 return 0;
812
813 pitch = Dx(scr->gscreen->r)/8;
814 ctl = 1|2; /* left-to-right, top-to-bottom */
815 if(scr->gscreen->depth == 24){
816 r.min.x *= 3;
817 r.max.x *= 3;
818 pitch *= 3;
819 ctl |= (1<<7)|(((r.min.x/4)%6)<<8);
820 }
821
822 waitforfifo(scr, 11);
823 iow32(scr, DpFrgdClr, sval);
824 iow32(scr, DpWriteMask, 0xFFFFFFFF);
825 iow32(scr, DpMix, 0x00070003);
826 iow32(scr, DpSrc, 0x00000111);
827 iow32(scr, ClrCmpCntl, 0x00000000);
828 iow32(scr, ScLeftRight, 0x1FFF0000);
829 iow32(scr, ScTopBottom, 0x1FFF0000);
830 iow32(scr, DstOffPitch, pitch<<22);
831 iow32(scr, DstCntl, ctl);
832 iow32(scr, DstYX, (r.min.x<<16)|r.min.y);
833 iow32(scr, DstHeightWidth, (Dx(r)<<16)|Dy(r));
834
835 waitforidle(scr);
836 return 1;
837 }
838
839 static int
840 mach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
841 {
842 ulong pitch;
843 Point dp, sp;
844 ulong ctl;
845 int dx, dy;
846
847 dx = Dx(r);
848 dy = Dy(r);
849 pitch = Dx(scr->gscreen->r)/8;
850 if(scr->gscreen->depth == 24){
851 dx *= 3;
852 pitch *= 3;
853 r.min.x *= 3;
854 sr.min.x *= 3;
855 }
856
857 ctl = 0;
858 if(r.min.x <= sr.min.x){
859 ctl |= 1;
860 dp.x = r.min.x;
861 sp.x = sr.min.x;
862 }else{
863 dp.x = r.min.x+dx-1;
864 sp.x = sr.min.x+dx-1;
865 }
866
867 if(r.min.y <= sr.min.y){
868 ctl |= 2;
869 dp.y = r.min.y;
870 sp.y = sr.min.y;
871 }else{
872 dp.y = r.min.y+dy-1;
873 sp.y = sr.min.y+dy-1;
874 }
875
876 if(scr->gscreen->depth == 24)
877 ctl |= (1<<7)|(((dp.x/4)%6)<<8);
878
879 waitforfifo(scr, 6);
880 iow32(scr, ScLeftRight, 0x1FFF0000);
881 iow32(scr, ScTopBottom, 0x1FFF0000);
882 iow32(scr, DpWriteMask, 0xFFFFFFFF);
883 iow32(scr, DpMix, 0x00070003);
884 iow32(scr, DpSrc, 0x00000300);
885 iow32(scr, ClrCmpCntl, 0x00000000);
886
887 waitforfifo(scr, 8);
888 iow32(scr, SrcOffPitch, pitch<<22);
889 iow32(scr, SrcCntl, 0x00000000);
890 iow32(scr, SrcYX, (sp.x<<16)|sp.y);
891 iow32(scr, SrcWidth1, dx);
892 iow32(scr, DstOffPitch, pitch<<22);
893 iow32(scr, DstCntl, ctl);
894
895 iow32(scr, DstYX, (dp.x<<16)|dp.y);
896 iow32(scr, DstHeightWidth, (dx<<16)|dy);
897
898 waitforidle(scr);
899
900 return 1;
901 }
902
903 /*
904 * This should work, but doesn't.
905 * It messes up the screen timings for some reason.
906 */
907 static void
908 mach64blank(VGAscr *scr, int blank)
909 {
910 ulong ctl;
911
912 ctl = ior32(scr, CrtcGenCtl) & ~(CrtcHsyncDis|CrtcVsyncDis);
913 if(blank)
914 ctl |= CrtcHsyncDis|CrtcVsyncDis;
915 iow32(scr, CrtcGenCtl, ctl);
916 }
917
918 /*
919 * We squirrel away whether the LCD and/or CRT were
920 * on when we were called to blank the screen, and
921 * restore the old state. If we are called to blank the
922 * screen when it is already blank, we don't update the state.
923 * Such a call sequence should not happen, though.
924 *
925 * We could try forcing the chip into power management
926 * mode instead, but I'm not sure how that would interact
927 * with screen updates going on while the screen is blanked.
928 */
929 static void
930 mach64lcdblank(VGAscr *scr, int blank)
931 {
932 static int crtlcd;
933 ulong x;
934
935 if(blank) {
936 x = lcdr32(scr, LCD_GenCtrl);
937 if(x & 3) {
938 crtlcd = x & 3;
939 lcdw32(scr, LCD_GenCtrl, x&~3);
940 }
941 } else {
942 if(crtlcd == 0)
943 crtlcd = 2; /* lcd only */
944 x = lcdr32(scr, LCD_GenCtrl);
945 lcdw32(scr, LCD_GenCtrl, x | crtlcd);
946 }
947 }
948
949 static void
950 mach64xxdrawinit(VGAscr *scr)
951 {
952 if(scr->io > 0x2FF){
953 initengine(scr);
954 scr->fill = mach64hwfill;
955 scr->scroll = mach64hwscroll;
956 }
957 /* scr->blank = mach64blank; */
958 switch(scr->id){
959 default:
960 break;
961 case ('L'<<8)|'B': /* 4C42: Rage 3D LTPro */
962 case ('L'<<8)|'I': /* 4C49: Rage 3D LTPro */
963 case ('L'<<8)|'M': /* 4C4D: Rage Mobility */
964 case ('L'<<8)|'P': /* 4C50: Rage 3D LTPro */
965 scr->blank = mach64lcdblank;
966 hwblank = 1;
967 break;
968 }
969 }
970
971 static void
972 ovl_configure(VGAscr *scr, Chan *c, char **field)
973 {
974 int w, h;
975 char *format;
976
977 w = (int)strtol(field[1], nil, 0);
978 h = (int)strtol(field[2], nil, 0);
979 format = field[3];
980
981 if (c != ovl_chan)
982 error(Einuse);
983 if (strcmp(format, "YUYV"))
984 error(Eunsupportedformat);
985
986 ovl_width = w;
987 ovl_height = h;
988 ovl_fib = w * h * sizeof(ushort);
989
990 waitforidle(scr);
991 scr->mmio[mmoffset[BusCntl]] |= 0x08000000; /* Enable regblock 1 */
992 scr->mmio[mmoffset[OverlayScaleCntl]] =
993 SCALE_ZERO_EXTEND|SCALE_RED_TEMP_6500K|
994 SCALE_HORZ_BLEND|SCALE_VERT_BLEND;
995 scr->mmio[mmoffset[!mach64revb? Buf0Pitch: ScalerBuf0Pitch]] = w;
996 scr->mmio[mmoffset[CaptureConfig]] =
997 SCALER_FRAME_READ_MODE_FULL|
998 SCALER_BUF_MODE_SINGLE|
999 SCALER_BUF_NEXT_0;
1000 scr->mmio[mmoffset[OverlayKeyCntl]] = !mach64revb?
1001 OVERLAY_MIX_ALWAYS_V|(OVERLAY_EXCLUSIVE_NORMAL << 28):
1002 0x011;
1003
1004 if (mach64type->m64_pro) {
1005 waitforfifo(scr, 6);
1006
1007 /* set the scaler co-efficient registers */
1008 scr->mmio[mmoffset[ScalerColourCntl]] =
1009 (0x00) | (0x10 << 8) | (0x10 << 16);
1010 scr->mmio[mmoffset[ScalerHCoef0]] =
1011 (0x00) | (0x20 << 8);
1012 scr->mmio[mmoffset[ScalerHCoef1]] =
1013 (0x0D) | (0x20 << 8) | (0x06 << 16) | (0x0D << 24);
1014 scr->mmio[mmoffset[ScalerHCoef2]] =
1015 (0x0D) | (0x1C << 8) | (0x0A << 16) | (0x0D << 24);
1016 scr->mmio[mmoffset[ScalerHCoef3]] =
1017 (0x0C) | (0x1A << 8) | (0x0E << 16) | (0x0C << 24);
1018 scr->mmio[mmoffset[ScalerHCoef4]] =
1019 (0x0C) | (0x14 << 8) | (0x14 << 16) | (0x0C << 24);
1020 }
1021
1022 waitforfifo(scr, 3);
1023 scr->mmio[mmoffset[VideoFormat]] = SCALE_IN_YVYU422 |
1024 (!mach64revb? 0xC: 0);
1025
1026 if (mach64overlay == 0)
1027 mach64overlay = scr->storage + 64 * 64 * sizeof(uchar);
1028 scr->mmio[mmoffset[!mach64revb? Buf0Offset: ScalerBuf0Offset]] =
1029 mach64overlay;
1030 }
1031
1032 static void
1033 ovl_enable(VGAscr *scr, Chan *c, char **field)
1034 {
1035 int x, y, w, h;
1036 long h_inc, v_inc;
1037
1038 x = (int)strtol(field[1], nil, 0);
1039 y = (int)strtol(field[2], nil, 0);
1040 w = (int)strtol(field[3], nil, 0);
1041 h = (int)strtol(field[4], nil, 0);
1042
1043 if (x < 0 || x + w > physgscreenr.max.x ||
1044 y < 0 || y + h > physgscreenr.max.y)
1045 error(Ebadarg);
1046
1047 if (c != ovl_chan)
1048 error(Einuse);
1049 if (scr->mmio[mmoffset[CrtcGenCntl]] & 1) { /* double scan enable */
1050 y *= 2;
1051 h *= 2;
1052 }
1053
1054 waitforfifo(scr, 2);
1055 scr->mmio[mmoffset[OverlayYX]] =
1056 ((x & 0xFFFF) << 16) | (y & 0xFFFF);
1057 scr->mmio[mmoffset[OverlayYXEnd]] =
1058 (((x + w) & 0xFFFF) << 16) | ((y + h) & 0xFFFF);
1059
1060 h_inc = (ovl_width << 12) / (w >> 1); /* ??? */
1061 v_inc = (ovl_height << 12) / h;
1062 waitforfifo(scr, 2);
1063 scr->mmio[mmoffset[OverlayScaleInc]] =
1064 ((h_inc & 0xFFFF) << 16) | (v_inc & 0xFFFF);
1065 scr->mmio[mmoffset[ScalerHeightWidth]] =
1066 ((ovl_width & 0xFFFF) << 16) | (ovl_height & 0xFFFF);
1067 waitforidle(scr);
1068 scr->mmio[mmoffset[OverlayScaleCntl]] |=
1069 (SCALE_ENABLE|OVERLAY_ENABLE);
1070 }
1071
1072 static void
1073 ovl_status(VGAscr *scr, Chan *, char **field)
1074 {
1075 pprint("%s: %s %.4uX, VT/GT %s, PRO %s, ovlclock %d, rev B %s, refclock %ld\n",
1076 scr->dev->name, field[0], mach64type->m64_id,
1077 mach64type->m64_vtgt? "yes": "no",
1078 mach64type->m64_pro? "yes": "no",
1079 mach64type->m64_ovlclock,
1080 mach64revb? "yes": "no",
1081 mach64refclock);
1082 pprint("%s: storage @%.8luX, aperture @%8.ulX, ovl buf @%.8ulX\n",
1083 scr->dev->name, scr->storage, scr->paddr,
1084 mach64overlay);
1085 }
1086
1087 static void
1088 ovl_openctl(VGAscr *, Chan *c, char **)
1089 {
1090 if (ovl_chan)
1091 error(Einuse);
1092 ovl_chan = c;
1093 }
1094
1095 static void
1096 ovl_closectl(VGAscr *scr, Chan *c, char **)
1097 {
1098 if (c != ovl_chan) return;
1099
1100 waitforidle(scr);
1101 scr->mmio[mmoffset[OverlayScaleCntl]] &=
1102 ~(SCALE_ENABLE|OVERLAY_ENABLE);
1103 ovl_chan = nil;
1104 ovl_width = ovl_height = ovl_fib = 0;
1105 }
1106
1107 enum
1108 {
1109 CMclosectl,
1110 CMconfigure,
1111 CMenable,
1112 CMopenctl,
1113 CMstatus,
1114 };
1115
1116 static void (*ovl_cmds[])(VGAscr *, Chan *, char **) =
1117 {
1118 [CMclosectl] ovl_closectl,
1119 [CMconfigure] ovl_configure,
1120 [CMenable] ovl_enable,
1121 [CMopenctl] ovl_openctl,
1122 [CMstatus] ovl_status,
1123 };
1124
1125 static Cmdtab mach64xxcmd[] =
1126 {
1127 CMclosectl, "closectl", 1,
1128 CMconfigure, "configure", 4,
1129 CMenable, "enable", 5,
1130 CMopenctl, "openctl", 1,
1131 CMstatus, "status", 1,
1132 };
1133
1134 static void
1135 mach64xxovlctl(VGAscr *scr, Chan *c, void *a, int n)
1136 {
1137 Cmdbuf *cb;
1138 Cmdtab *ct;
1139
1140 if(!mach64type->m64_vtgt)
1141 error(Enodev);
1142
1143 if(!scr->overlayinit){
1144 scr->overlayinit = 1;
1145 init_overlayclock(scr);
1146 }
1147 cb = parsecmd(a, n);
1148 if(waserror()){
1149 free(cb);
1150 nexterror();
1151 }
1152
1153 ct = lookupcmd(cb, mach64xxcmd, nelem(mach64xxcmd));
1154
1155 ovl_cmds[ct->index](scr, c, cb->f);
1156
1157 poperror();
1158 free(cb);
1159 }
1160
1161 static int
1162 mach64xxovlwrite(VGAscr *scr, void *a, int len, vlong offs)
1163 {
1164 uchar *src;
1165 int _len;
1166
1167 if (ovl_chan == nil) return len; /* Acts as a /dev/null */
1168
1169 /* Calculate the destination address */
1170 _len = len;
1171 src = (uchar *)a;
1172 while (len > 0) {
1173 ulong _offs;
1174 int nb;
1175
1176 _offs = (ulong)(offs % ovl_fib);
1177 nb = (_offs + len > ovl_fib)? ovl_fib - _offs: len;
1178 memmove((uchar *)scr->vaddr + mach64overlay + _offs,
1179 src, nb);
1180 offs += nb;
1181 src += nb;
1182 len -= nb;
1183 }
1184 return _len;
1185 }
1186
1187 VGAdev vgamach64xxdev = {
1188 "mach64xx",
1189
1190 mach64xxenable, /* enable */
1191 0, /* disable */
1192 0, /* page */
1193 mach64xxlinear, /* linear */
1194 mach64xxdrawinit, /* drawinit */
1195 0,
1196 mach64xxovlctl, /* overlay control */
1197 mach64xxovlwrite, /* write the overlay */
1198 };
1199
1200 VGAcur vgamach64xxcur = {
1201 "mach64xxhwgc",
1202
1203 mach64xxcurenable, /* enable */
1204 mach64xxcurdisable, /* disable */
1205 mach64xxcurload, /* load */
1206 mach64xxcurmove, /* move */
1207
1208 1 /* doespanning */
1209 };
1210
Cache object: 5c1b65112363855ea9a0334cebe6effc
|