2 #include "../port/lib.h"
7 #include "../port/error.h"
15 char Eunsupportedformat[] = "unsupported video format";
16 char Enotconfigured[] = "device not configured";
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
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
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
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
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 */
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. */
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 */
106 * ATI Mach64(CT|ET|G*|V*|L*).
108 typedef struct Mach64types 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? */
116 static ulong mach64refclock;
117 static Mach64types *mach64type;
118 static int mach64revb; /* Revision B or greater? */
119 static ulong mach64overlay; /* Overlay buffer */
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 */
145 static int hwfill(VGAscr*, Rectangle, ulong);
146 static int hwscroll(VGAscr*, Rectangle, Rectangle);
147 static void initengine(VGAscr*);
150 mach64xxenable(VGAscr* scr)
158 if(p == nil || p->vid != 0x1002)
162 for (i = 0; i != nelem(mach64s); i++)
163 if (mach64s[i].m64_id == p->did) {
165 mach64type = &mach64s[i];
169 if(mach64type != nil){
171 * The CT doesn't always have the I/O base address
172 * in the PCI base registers. There is a way to find
173 * it via the vendor-specific PCI config space but
174 * this will do for now.
176 scr->io = p->mem[1].bar & ~0x03;
184 mach64xxlinear(VGAscr* scr, int size, int)
189 scr->mmio = (ulong*)((uchar*)scr->vaddr+size-1024);
190 addvgaseg("mach64mmio", scr->paddr+size-BY2PG, BY2PG);
191 addvgaseg("mach64screen", scr->paddr, scr->apsize);
197 CurClr0 = 0x0B, /* I/O Select */
208 ContextMask = 0x100, /* not accessible via I/O */
288 #define Bank1 (-0x100) /* 1KB */
290 static int mmoffset[] = {
309 [DstHeightWidth] 0x46,
318 [SrcHeight1Width1] 0x66,
319 [SrcHeight2Width2] 0x6C,
347 [OverlayYX] Bank1 + 0x00,
348 [OverlayYXEnd] Bank1 + 0x01,
349 [OverlayKeyCntl] Bank1 + 0x06,
350 [OverlayScaleInc] Bank1 + 0x08,
351 [OverlayScaleCntl] Bank1 + 0x09,
352 [ScalerHeightWidth] Bank1 + 0x0A,
353 [ScalerBuf0Offset] Bank1 + 0x0D,
354 [ScalerBuf0Pitch] Bank1 + 0x0F,
355 [VideoFormat] Bank1 + 0x12,
356 [CaptureConfig] Bank1 + 0x14,
357 [Buf0Offset] Bank1 + 0x20,
358 [Buf0Pitch] Bank1 + 0x23,
359 [ScalerColourCntl] Bank1 + 0x54,
360 [ScalerHCoef0] Bank1 + 0x55,
361 [ScalerHCoef1] Bank1 + 0x56,
362 [ScalerHCoef2] Bank1 + 0x57,
363 [ScalerHCoef3] Bank1 + 0x58,
364 [ScalerHCoef4] Bank1 + 0x59,
368 ior32(VGAscr* scr, int r)
370 if(scr->io == 0x2EC || scr->io == 0x1C8)
371 return inl((r<<10)+scr->io);
372 if(r >= 0x100 && scr->mmio != nil)
373 return scr->mmio[mmoffset[r]];
374 return inl((mmoffset[r]<<2)+scr->io);
378 iow32(VGAscr* scr, int r, ulong l)
380 if(scr->io == 0x2EC || scr->io == 0x1C8)
381 outl(((r)<<10)+scr->io, l);
382 else if(r >= 0x100 && scr->mmio != nil)
383 scr->mmio[mmoffset[r]] = l;
385 outl((mmoffset[r]<<2)+scr->io, l);
389 lcdr32(VGAscr *scr, ulong r)
393 or = ior32(scr, LcdIndex);
394 iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
395 return ior32(scr, LcdData);
399 lcdw32(VGAscr *scr, ulong r, ulong v)
403 or = ior32(scr, LcdIndex);
404 iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
405 iow32(scr, LcdData, v);
409 mach64xxcurdisable(VGAscr* scr)
413 r = ior32(scr, GenTestCntl);
414 iow32(scr, GenTestCntl, r & ~0x80);
418 mach64xxcurload(VGAscr* scr, Cursor* curs)
425 * Disable the cursor.
427 r = ior32(scr, GenTestCntl);
428 iow32(scr, GenTestCntl, r & ~0x80);
434 * Initialise the 64x64 cursor RAM array.
435 * The cursor mode gives the following truth table:
437 * 0 0 Cursor Colour 0
438 * 0 1 Cursor Colour 1
441 * Put the cursor into the top-right of the 64x64 array.
443 for(y = 0; y < 16; y++){
444 for(i = 0; i < (64-16)/8; i++){
449 c = (curs->clr[2*y]<<8)|curs->clr[y*2 + 1];
450 s = (curs->set[2*y]<<8)|curs->set[y*2 + 1];
453 for(i = 0; i < 16; i++){
456 else if(c & (1<<(15-i))){
467 memset(p, 0xAA, (64-16)*16);
470 * Set the cursor hotpoint and enable the cursor.
472 scr->offset = curs->offset;
473 iow32(scr, GenTestCntl, 0x80|r);
477 ptalmostinrect(Point p, Rectangle r)
479 return p.x>=r.min.x && p.x<=r.max.x &&
480 p.y>=r.min.y && p.y<=r.max.y;
484 * If necessary, translate the rectangle physr
485 * some multiple of [dx dy] so that it includes p.
486 * Return 1 if the rectangle changed.
489 screenpan(Point p, Rectangle *physr, int dx, int dy)
493 if(ptalmostinrect(p, *physr))
496 if(p.y < physr->min.y){
497 d = physr->min.y - (p.y&~(dy-1));
501 if(p.y > physr->max.y){
502 d = ((p.y+dy-1)&~(dy-1)) - physr->max.y;
507 if(p.x < physr->min.x){
508 d = physr->min.x - (p.x&~(dx-1));
512 if(p.x > physr->max.x){
513 d = ((p.x+dx-1)&~(dx-1)) - physr->max.x;
521 mach64xxcurmove(VGAscr* scr, Point p)
528 * If the point we want to display is outside the current
529 * screen rectangle, pan the screen to display it.
531 * We have to move in 64-bit chunks.
533 if(scr->gscreen->depth == 24)
536 dx = 64 / scr->gscreen->depth;
538 if(panning && screenpan(p, &physgscreenr, dx, 1)){
539 off = (physgscreenr.min.y*Dx(scr->gscreen->r)+physgscreenr.min.x)/dx;
540 pitch = Dx(scr->gscreen->r)/8;
541 iow32(scr, CrtcOffPitch, (pitch<<22)|off);
544 p.x -= physgscreenr.min.x;
545 p.y -= physgscreenr.min.y;
548 * Mustn't position the cursor offscreen even partially,
549 * or it disappears. Therefore, if x or y is -ve, adjust the
550 * cursor presets instead. If y is negative also have to
551 * adjust the starting offset.
553 if((x = p.x+scr->offset.x) < 0){
559 if((y = p.y+scr->offset.y) < 0){
566 iow32(scr, CurHVoff, ((64-16-yo)<<16)|(64-16-xo));
567 iow32(scr, CurOffset, scr->storage/8 + (-yo*2));
568 iow32(scr, CurHVposn, (y<<16)|x);
574 mach64xxcurenable(VGAscr* scr)
582 r = ior32(scr, GenTestCntl);
583 iow32(scr, GenTestCntl, r & ~0x80);
585 iow32(scr, CurClr0, (Pwhite<<24)|(Pwhite<<16)|(Pwhite<<8)|Pwhite);
586 iow32(scr, CurClr1, (Pblack<<24)|(Pblack<<16)|(Pblack<<8)|Pblack);
589 * Find a place for the cursor data in display memory.
590 * Must be 64-bit aligned.
592 storage = (scr->gscreen->width*sizeof(ulong)*scr->gscreen->r.max.y+7)/8;
593 iow32(scr, CurOffset, storage);
594 scr->storage = storage*8;
597 * Cursor goes in the top right corner of the 64x64 array
598 * so the horizontal and vertical presets are 64-16.
600 iow32(scr, CurHVposn, (0<<16)|0);
601 iow32(scr, CurHVoff, ((64-16)<<16)|(64-16));
604 * Load, locate and enable the 64x64 cursor.
606 mach64xxcurload(scr, &cursor);
607 mach64xxcurmove(scr, ZP);
608 iow32(scr, GenTestCntl, 0x80|r);
612 waitforfifo(VGAscr *scr, int entries)
617 while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && x++ < 1000000)
620 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));
624 waitforidle(VGAscr *scr)
628 waitforfifo(scr, 16);
630 while((ior32(scr, GuiStat)&1) && x++ < 1000000)
633 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));
637 resetengine(VGAscr *scr)
640 x = ior32(scr, GenTestCntl);
641 iow32(scr, GenTestCntl, x&~0x100);
642 iow32(scr, GenTestCntl, x|0x100);
643 iow32(scr, BusCntl, ior32(scr, BusCntl)|0x00A00000);
647 init_overlayclock(VGAscr *scr)
649 uchar *cc, save, pll_ref_div, pll_vclk_cntl, vclk_post_div,
650 vclk_fb_div, ecp_div;
655 /* Get monitor dotclock, check for Overlay Scaler clock limit */
656 cc = (uchar *)&scr->mmio[mmoffset[ClockCntl]];
657 save = cc[1]; i = cc[0] & 3;
658 cc[1] = 2<<2; pll_ref_div = cc[2];
659 cc[1] = 5<<2; pll_vclk_cntl = cc[2];
660 cc[1] = 6<<2; vclk_post_div = (cc[2]>>(i+i)) & 3;
661 cc[1] = (7+i)<<2; vclk_fb_div = cc[2];
663 dotclock = 2 * mach64refclock * vclk_fb_div /
664 (pll_ref_div * (1 << vclk_post_div));
665 /* ecp_div: 0=dotclock, 1=dotclock/2, 2=dotclock/4 */
666 ecp_div = dotclock / mach64type->m64_ovlclock;
667 if (ecp_div>2) ecp_div = 2;
669 /* Force a scaler clock factor of 1 if refclock *
670 * is unknown (VCLK_SRC not PLLVCLK) */
671 if ((pll_vclk_cntl & 0x03) != 0x03)
673 if ((pll_vclk_cntl & 0x30) != ecp_div<<4) {
675 cc[2] = (pll_vclk_cntl&0xCF) | (ecp_div<<4);
678 /* Restore PLL Register Index */
683 initengine(VGAscr *scr)
689 pitch = Dx(scr->gscreen->r)/8;
690 if(scr->gscreen->depth == 24)
694 waitforfifo(scr, 14);
695 iow32(scr, ContextMask, ~0);
696 iow32(scr, DstOffPitch, pitch<<22);
697 iow32(scr, DstYX, 0);
698 iow32(scr, DstHeight, 0);
699 iow32(scr, DstBresErr, 0);
700 iow32(scr, DstBresInc, 0);
701 iow32(scr, DstBresDec, 0);
702 iow32(scr, DstCntl, 0x23);
703 iow32(scr, SrcOffPitch, pitch<<22);
704 iow32(scr, SrcYX, 0);
705 iow32(scr, SrcHeight1Width1, 1);
706 iow32(scr, SrcYXstart, 0);
707 iow32(scr, SrcHeight2Width2, 1);
708 iow32(scr, SrcCntl, 0x01);
710 waitforfifo(scr, 13);
711 iow32(scr, HostCntl, 0);
712 iow32(scr, PatReg0, 0);
713 iow32(scr, PatReg1, 0);
714 iow32(scr, PatCntl, 0);
715 iow32(scr, ScLeft, 0);
716 iow32(scr, ScTop, 0);
717 iow32(scr, ScBottom, 0xFFFF);
718 iow32(scr, ScRight, 0xFFFF);
719 iow32(scr, DpBkgdClr, 0);
720 iow32(scr, DpFrgdClr, ~0);
721 iow32(scr, DpWriteMask, ~0);
722 iow32(scr, DpMix, 0x70003);
723 iow32(scr, DpSrc, 0x00010100);
726 iow32(scr, ClrCmpClr, 0);
727 iow32(scr, ClrCmpMask, ~0);
728 iow32(scr, ClrCmpCntl, 0);
731 switch(scr->gscreen->depth){
734 iow32(scr, DpPixWidth, 0x00020202);
735 iow32(scr, DpChainMask, 0x8080);
738 iow32(scr, DpPixWidth, 0x00040404);
739 iow32(scr, DpChainMask, 0x8410);
742 iow32(scr, DpPixWidth, 0x00060606);
743 iow32(scr, DpChainMask, 0x8080);
747 /* Get the base freq from the BIOS */
748 bios = kaddr(0xC000);
749 table = *(ushort *)(bios + 0x48);
750 table = *(ushort *)(bios + table + 0x10);
751 switch (*(ushort *)(bios + table + 0x08)) {
753 mach64refclock = 270000;
757 mach64refclock = 286363;
760 mach64refclock = 294989;
764 mach64refclock = 143181;
768 /* Figure out which revision this chip is */
769 switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) {
794 mach64hwfill(VGAscr *scr, Rectangle r, ulong sval)
799 /* shouldn't happen */
800 if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0)
803 pitch = Dx(scr->gscreen->r)/8;
804 ctl = 1|2; /* left-to-right, top-to-bottom */
805 if(scr->gscreen->depth == 24){
809 ctl |= (1<<7)|(((r.min.x/4)%6)<<8);
812 waitforfifo(scr, 11);
813 iow32(scr, DpFrgdClr, sval);
814 iow32(scr, DpWriteMask, 0xFFFFFFFF);
815 iow32(scr, DpMix, 0x00070003);
816 iow32(scr, DpSrc, 0x00000111);
817 iow32(scr, ClrCmpCntl, 0x00000000);
818 iow32(scr, ScLeftRight, 0x1FFF0000);
819 iow32(scr, ScTopBottom, 0x1FFF0000);
820 iow32(scr, DstOffPitch, pitch<<22);
821 iow32(scr, DstCntl, ctl);
822 iow32(scr, DstYX, (r.min.x<<16)|r.min.y);
823 iow32(scr, DstHeightWidth, (Dx(r)<<16)|Dy(r));
830 mach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
839 pitch = Dx(scr->gscreen->r)/8;
840 if(scr->gscreen->depth == 24){
848 if(r.min.x <= sr.min.x){
854 sp.x = sr.min.x+dx-1;
857 if(r.min.y <= sr.min.y){
863 sp.y = sr.min.y+dy-1;
866 if(scr->gscreen->depth == 24)
867 ctl |= (1<<7)|(((dp.x/4)%6)<<8);
870 iow32(scr, ScLeftRight, 0x1FFF0000);
871 iow32(scr, ScTopBottom, 0x1FFF0000);
872 iow32(scr, DpWriteMask, 0xFFFFFFFF);
873 iow32(scr, DpMix, 0x00070003);
874 iow32(scr, DpSrc, 0x00000300);
875 iow32(scr, ClrCmpCntl, 0x00000000);
878 iow32(scr, SrcOffPitch, pitch<<22);
879 iow32(scr, SrcCntl, 0x00000000);
880 iow32(scr, SrcYX, (sp.x<<16)|sp.y);
881 iow32(scr, SrcWidth1, dx);
882 iow32(scr, DstOffPitch, pitch<<22);
883 iow32(scr, DstCntl, ctl);
885 iow32(scr, DstYX, (dp.x<<16)|dp.y);
886 iow32(scr, DstHeightWidth, (dx<<16)|dy);
894 * This should work, but doesn't.
895 * It messes up the screen timings for some reason.
898 mach64blank(VGAscr *scr, int blank)
902 ctl = ior32(scr, CrtcGenCtl) & ~(CrtcHsyncDis|CrtcVsyncDis);
904 ctl |= CrtcHsyncDis|CrtcVsyncDis;
905 iow32(scr, CrtcGenCtl, ctl);
909 * We squirrel away whether the LCD and/or CRT were
910 * on when we were called to blank the screen, and
911 * restore the old state. If we are called to blank the
912 * screen when it is already blank, we don't update the state.
913 * Such a call sequence should not happen, though.
915 * We could try forcing the chip into power management
916 * mode instead, but I'm not sure how that would interact
917 * with screen updates going on while the screen is blanked.
920 mach64lcdblank(VGAscr *scr, int blank)
926 x = lcdr32(scr, LCD_GenCtrl);
929 lcdw32(scr, LCD_GenCtrl, x&~3);
933 crtlcd = 2; /* lcd only */
934 x = lcdr32(scr, LCD_GenCtrl);
935 lcdw32(scr, LCD_GenCtrl, x | crtlcd);
940 mach64xxdrawinit(VGAscr *scr)
944 scr->fill = mach64hwfill;
945 scr->scroll = mach64hwscroll;
947 /* scr->blank = mach64blank; */
951 case ('L'<<8)|'B': /* 4C42: Rage 3D LTPro */
952 case ('L'<<8)|'I': /* 4C49: Rage 3D LTPro */
953 case ('L'<<8)|'M': /* 4C4D: Rage Mobility */
954 case ('L'<<8)|'P': /* 4C50: Rage 3D LTPro */
955 scr->blank = mach64lcdblank;
961 ovl_configure(VGAscr *scr, Chan *c, char **field)
966 w = (int)strtol(field[1], nil, 0);
967 h = (int)strtol(field[2], nil, 0);
972 if (strcmp(format, "YUYV"))
973 error(Eunsupportedformat);
977 ovl_fib = w * h * sizeof(ushort);
980 scr->mmio[mmoffset[BusCntl]] |= 0x08000000; /* Enable regblock 1 */
981 scr->mmio[mmoffset[OverlayScaleCntl]] =
982 SCALE_ZERO_EXTEND|SCALE_RED_TEMP_6500K|
983 SCALE_HORZ_BLEND|SCALE_VERT_BLEND;
984 scr->mmio[mmoffset[!mach64revb? Buf0Pitch: ScalerBuf0Pitch]] = w;
985 scr->mmio[mmoffset[CaptureConfig]] =
986 SCALER_FRAME_READ_MODE_FULL|
987 SCALER_BUF_MODE_SINGLE|
989 scr->mmio[mmoffset[OverlayKeyCntl]] = !mach64revb?
990 OVERLAY_MIX_ALWAYS_V|(OVERLAY_EXCLUSIVE_NORMAL << 28):
993 if (mach64type->m64_pro) {
996 /* set the scaler co-efficient registers */
997 scr->mmio[mmoffset[ScalerColourCntl]] =
998 (0x00) | (0x10 << 8) | (0x10 << 16);
999 scr->mmio[mmoffset[ScalerHCoef0]] =
1000 (0x00) | (0x20 << 8);
1001 scr->mmio[mmoffset[ScalerHCoef1]] =
1002 (0x0D) | (0x20 << 8) | (0x06 << 16) | (0x0D << 24);
1003 scr->mmio[mmoffset[ScalerHCoef2]] =
1004 (0x0D) | (0x1C << 8) | (0x0A << 16) | (0x0D << 24);
1005 scr->mmio[mmoffset[ScalerHCoef3]] =
1006 (0x0C) | (0x1A << 8) | (0x0E << 16) | (0x0C << 24);
1007 scr->mmio[mmoffset[ScalerHCoef4]] =
1008 (0x0C) | (0x14 << 8) | (0x14 << 16) | (0x0C << 24);
1011 waitforfifo(scr, 3);
1012 scr->mmio[mmoffset[VideoFormat]] = SCALE_IN_YVYU422 |
1013 (!mach64revb? 0xC: 0);
1015 if (mach64overlay == 0)
1016 mach64overlay = scr->storage + 64 * 64 * sizeof(uchar);
1017 scr->mmio[mmoffset[!mach64revb? Buf0Offset: ScalerBuf0Offset]] =
1022 ovl_enable(VGAscr *scr, Chan *c, char **field)
1027 x = (int)strtol(field[1], nil, 0);
1028 y = (int)strtol(field[2], nil, 0);
1029 w = (int)strtol(field[3], nil, 0);
1030 h = (int)strtol(field[4], nil, 0);
1032 if (x < 0 || x + w > physgscreenr.max.x ||
1033 y < 0 || y + h > physgscreenr.max.y)
1038 if (scr->mmio[mmoffset[CrtcGenCntl]] & 1) { /* double scan enable */
1043 waitforfifo(scr, 2);
1044 scr->mmio[mmoffset[OverlayYX]] =
1045 ((x & 0xFFFF) << 16) | (y & 0xFFFF);
1046 scr->mmio[mmoffset[OverlayYXEnd]] =
1047 (((x + w) & 0xFFFF) << 16) | ((y + h) & 0xFFFF);
1049 h_inc = (ovl_width << 12) / (w >> 1); /* ??? */
1050 v_inc = (ovl_height << 12) / h;
1051 waitforfifo(scr, 2);
1052 scr->mmio[mmoffset[OverlayScaleInc]] =
1053 ((h_inc & 0xFFFF) << 16) | (v_inc & 0xFFFF);
1054 scr->mmio[mmoffset[ScalerHeightWidth]] =
1055 ((ovl_width & 0xFFFF) << 16) | (ovl_height & 0xFFFF);
1057 scr->mmio[mmoffset[OverlayScaleCntl]] |=
1058 (SCALE_ENABLE|OVERLAY_ENABLE);
1062 ovl_status(VGAscr *scr, Chan *, char **field)
1064 pprint("%s: %s %.4uX, VT/GT %s, PRO %s, ovlclock %lud, rev B %s, refclock %ld\n",
1065 scr->dev->name, field[0], mach64type->m64_id,
1066 mach64type->m64_vtgt? "yes": "no",
1067 mach64type->m64_pro? "yes": "no",
1068 mach64type->m64_ovlclock,
1069 mach64revb? "yes": "no",
1071 pprint("%s: storage @%.8luX, aperture @%8.ulX, ovl buf @%.8ulX\n",
1072 scr->dev->name, scr->storage, scr->paddr,
1077 ovl_openctl(VGAscr *, Chan *c, char **)
1085 ovl_closectl(VGAscr *scr, Chan *c, char **)
1087 if (c != ovl_chan) return;
1090 scr->mmio[mmoffset[OverlayScaleCntl]] &=
1091 ~(SCALE_ENABLE|OVERLAY_ENABLE);
1093 ovl_width = ovl_height = ovl_fib = 0;
1105 static void (*ovl_cmds[])(VGAscr *, Chan *, char **) =
1107 [CMclosectl] ovl_closectl,
1108 [CMconfigure] ovl_configure,
1109 [CMenable] ovl_enable,
1110 [CMopenctl] ovl_openctl,
1111 [CMstatus] ovl_status,
1114 static Cmdtab mach64xxcmd[] =
1116 CMclosectl, "closectl", 1,
1117 CMconfigure, "configure", 4,
1118 CMenable, "enable", 5,
1119 CMopenctl, "openctl", 1,
1120 CMstatus, "status", 1,
1124 mach64xxovlctl(VGAscr *scr, Chan *c, void *a, int n)
1129 if(!mach64type->m64_vtgt)
1132 if(!scr->overlayinit){
1133 scr->overlayinit = 1;
1134 init_overlayclock(scr);
1136 cb = parsecmd(a, n);
1142 ct = lookupcmd(cb, mach64xxcmd, nelem(mach64xxcmd));
1144 ovl_cmds[ct->index](scr, c, cb->f);
1151 mach64xxovlwrite(VGAscr *scr, void *a, int len, vlong offs)
1156 if (ovl_chan == nil) return len; /* Acts as a /dev/null */
1158 /* Calculate the destination address */
1165 _offs = (ulong)(offs % ovl_fib);
1166 nb = (_offs + len > ovl_fib)? ovl_fib - _offs: len;
1167 memmove((uchar *)scr->vaddr + mach64overlay + _offs,
1176 VGAdev vgamach64xxdev = {
1179 mach64xxenable, /* enable */
1182 mach64xxlinear, /* linear */
1183 mach64xxdrawinit, /* drawinit */
1185 mach64xxovlctl, /* overlay control */
1186 mach64xxovlwrite, /* write the overlay */
1189 VGAcur vgamach64xxcur = {
1192 mach64xxcurenable, /* enable */
1193 mach64xxcurdisable, /* disable */
1194 mach64xxcurload, /* load */
1195 mach64xxcurmove, /* move */