2 #include "../port/lib.h"
7 #include "../port/pci.h"
8 #include "../port/error.h"
16 char Eunsupportedformat[] = "unsupported video format";
17 char Enotconfigured[] = "device not configured";
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
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
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
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
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. */
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 */
101 * ATI Mach64(CT|ET|G*|V*|L*).
103 typedef struct Mach64types 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? */
111 static ulong mach64refclock;
112 static Mach64types *mach64type;
113 static int mach64revb; /* Revision B or greater? */
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 */
139 static int hwfill(VGAscr*, Rectangle, ulong);
140 static int hwscroll(VGAscr*, Rectangle, Rectangle);
141 static void initengine(VGAscr*);
144 mach64xxenable(VGAscr* scr)
152 if(p == nil || p->vid != 0x1002)
156 for (i = 0; i != nelem(mach64s); i++)
157 if (mach64s[i].m64_id == p->did) {
159 mach64type = &mach64s[i];
163 if(mach64type != nil){
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.
170 scr->io = p->mem[1].bar & ~0x03;
177 mach64xxlinear(VGAscr* scr, int size, int)
182 scr->mmio = (ulong*)((uchar*)scr->vaddr+size-1024);
183 addvgaseg("mach64mmio", scr->paddr+size-BY2PG, BY2PG);
184 addvgaseg("mach64screen", scr->paddr, scr->apsize);
190 CurClr0 = 0x0B, /* I/O Select */
201 ContextMask = 0x100, /* not accessible via I/O */
281 #define Bank1 (-0x100) /* 1KB */
283 static int mmoffset[] = {
302 [DstHeightWidth] 0x46,
311 [SrcHeight1Width1] 0x66,
312 [SrcHeight2Width2] 0x6C,
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,
361 ior32(VGAscr* scr, int r)
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);
371 iow32(VGAscr* scr, int r, ulong l)
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;
378 outl((mmoffset[r]<<2)+scr->io, l);
382 lcdr32(VGAscr *scr, ulong r)
386 or = ior32(scr, LcdIndex);
387 iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
388 return ior32(scr, LcdData);
392 lcdw32(VGAscr *scr, ulong r, ulong v)
396 or = ior32(scr, LcdIndex);
397 iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
398 iow32(scr, LcdData, v);
402 mach64xxcurdisable(VGAscr* scr)
406 r = ior32(scr, GenTestCntl);
407 iow32(scr, GenTestCntl, r & ~0x80);
411 mach64xxcurload(VGAscr* scr, Cursor* curs)
418 * Disable the cursor.
420 r = ior32(scr, GenTestCntl);
421 iow32(scr, GenTestCntl, r & ~0x80);
427 * Initialise the 64x64 cursor RAM array.
428 * The cursor mode gives the following truth table:
430 * 0 0 Cursor Colour 0
431 * 0 1 Cursor Colour 1
434 * Put the cursor into the top-right of the 64x64 array.
436 for(y = 0; y < 16; y++){
437 for(i = 0; i < (64-16)/8; i++){
442 c = (curs->clr[2*y]<<8)|curs->clr[y*2 + 1];
443 s = (curs->set[2*y]<<8)|curs->set[y*2 + 1];
446 for(i = 0; i < 16; i++){
449 else if(c & (1<<(15-i))){
460 memset(p, 0xAA, (64-16)*16);
463 * Set the cursor hotpoint and enable the cursor.
465 scr->offset = curs->offset;
466 iow32(scr, GenTestCntl, 0x80|r);
470 ptalmostinrect(Point p, Rectangle r)
472 return p.x>=r.min.x && p.x<=r.max.x &&
473 p.y>=r.min.y && p.y<=r.max.y;
477 mach64xxcurmove(VGAscr* scr, Point p)
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.
487 if((x = p.x+scr->offset.x) < 0){
493 if((y = p.y+scr->offset.y) < 0){
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);
508 mach64xxcurenable(VGAscr* scr)
516 r = ior32(scr, GenTestCntl);
517 iow32(scr, GenTestCntl, r & ~0x80);
519 iow32(scr, CurClr0, (Pwhite<<24)|(Pwhite<<16)|(Pwhite<<8)|Pwhite);
520 iow32(scr, CurClr1, (Pblack<<24)|(Pblack<<16)|(Pblack<<8)|Pblack);
523 * Find a place for the cursor data in display memory.
524 * Must be 64-bit aligned.
526 storage = (scr->pitch*scr->height+7)/8;
527 iow32(scr, CurOffset, storage);
528 scr->storage = storage*8;
531 * Cursor goes in the top right corner of the 64x64 array
532 * so the horizontal and vertical presets are 64-16.
534 iow32(scr, CurHVposn, (0<<16)|0);
535 iow32(scr, CurHVoff, ((64-16)<<16)|(64-16));
538 * Load, locate and enable the 64x64 cursor.
540 mach64xxcurload(scr, &cursor);
541 mach64xxcurmove(scr, ZP);
542 iow32(scr, GenTestCntl, 0x80|r);
546 waitforfifo(VGAscr *scr, int entries)
551 while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && 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));
558 waitforidle(VGAscr *scr)
562 waitforfifo(scr, 16);
564 while((ior32(scr, GuiStat)&1) && 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));
571 resetengine(VGAscr *scr)
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);
581 initengine(VGAscr *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);
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);
619 iow32(scr, ClrCmpClr, 0);
620 iow32(scr, ClrCmpMask, ~0);
621 iow32(scr, ClrCmpCntl, 0);
624 switch(scr->gscreen->depth){
627 iow32(scr, DpPixWidth, 0x00020202);
628 iow32(scr, DpChainMask, 0x8080);
631 iow32(scr, DpPixWidth, 0x00040404);
632 iow32(scr, DpChainMask, 0x8410);
635 iow32(scr, DpPixWidth, 0x00060606);
636 iow32(scr, DpChainMask, 0x8080);
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)) {
646 mach64refclock = 270000;
650 mach64refclock = 286363;
653 mach64refclock = 294989;
657 mach64refclock = 143181;
661 /* Figure out which revision this chip is */
662 switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) {
687 mach64hwfill(VGAscr *scr, Rectangle r, ulong sval)
691 /* shouldn't happen */
692 if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0)
695 ctl = 1|2; /* left-to-right, top-to-bottom */
696 if(scr->gscreen->depth == 24){
699 ctl |= (1<<7)|(((r.min.x/4)%6)<<8);
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));
720 mach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
728 if(scr->gscreen->depth == 24){
735 if(r.min.x <= sr.min.x){
741 sp.x = sr.min.x+dx-1;
744 if(r.min.y <= sr.min.y){
750 sp.y = sr.min.y+dy-1;
753 if(scr->gscreen->depth == 24)
754 ctl |= (1<<7)|(((dp.x/4)%6)<<8);
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);
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);
772 iow32(scr, DstYX, (dp.x<<16)|dp.y);
773 iow32(scr, DstHeightWidth, (dx<<16)|dy);
781 * This should work, but doesn't.
782 * It messes up the screen timings for some reason.
785 mach64blank(VGAscr *scr, int blank)
789 ctl = ior32(scr, CrtcGenCtl) & ~(CrtcHsyncDis|CrtcVsyncDis);
791 ctl |= CrtcHsyncDis|CrtcVsyncDis;
792 iow32(scr, CrtcGenCtl, ctl);
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.
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.
807 mach64lcdblank(VGAscr *scr, int blank)
813 x = lcdr32(scr, LCD_GenCtrl);
816 lcdw32(scr, LCD_GenCtrl, x&~3);
820 crtlcd = 2; /* lcd only */
821 x = lcdr32(scr, LCD_GenCtrl);
822 lcdw32(scr, LCD_GenCtrl, x | crtlcd);
827 mach64xxdrawinit(VGAscr *scr)
831 scr->fill = mach64hwfill;
832 scr->scroll = mach64hwscroll;
834 /* scr->blank = mach64blank; */
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;
847 VGAdev vgamach64xxdev = {
850 mach64xxenable, /* enable */
853 mach64xxlinear, /* linear */
854 mach64xxdrawinit, /* drawinit */
857 VGAcur vgamach64xxcur = {
860 mach64xxcurenable, /* enable */
861 mach64xxcurdisable, /* disable */
862 mach64xxcurload, /* load */
863 mach64xxcurmove, /* move */