📄 vgamach64xx.c
字号:
iow32(scr, CurHVposn, (0<<16)|0); iow32(scr, CurHVoff, ((64-16)<<16)|(64-16)); /* * Load, locate and enable the 64x64 cursor. */ mach64xxcurload(scr, &arrow); mach64xxcurmove(scr, ZP); iow32(scr, GenTestCntl, 0x80|r);}static voidwaitforfifo(VGAscr *scr, int entries){ int x; x = 0; while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && x++ < 1000000) ; if(x >= 1000000) iprint("fifo %d stat %.8lux %.8lux scrio %.8lux mmio %p scr %p pc %luX\n", entries, ior32(scr, FifoStat), scr->mmio[mmoffset[FifoStat]], scr->io, scr->mmio, scr, getcallerpc(&scr));}static voidwaitforidle(VGAscr *scr){ int x; waitforfifo(scr, 16); x = 0; while((ior32(scr, GuiStat)&1) && x++ < 1000000) ; if(x >= 1000000) iprint("idle stat %.8lux %.8lux scrio %.8lux mmio %p scr %p pc %luX\n", ior32(scr, GuiStat), scr->mmio[mmoffset[GuiStat]], scr->io, scr->mmio, scr, getcallerpc(&scr));}static voidresetengine(VGAscr *scr){ ulong x; x = ior32(scr, GenTestCntl); iow32(scr, GenTestCntl, x&~0x100); iow32(scr, GenTestCntl, x|0x100); iow32(scr, BusCntl, ior32(scr, BusCntl)|0x00A00000);}static voidinit_overlayclock(VGAscr *scr){ uchar *cc, save, pll_ref_div, pll_vclk_cntl, vclk_post_div, vclk_fb_div, ecp_div; int i; ulong dotclock; /* Taken from GLX */ /* Get monitor dotclock, check for Overlay Scaler clock limit */ cc = (uchar *)&scr->mmio[mmoffset[ClockCntl]]; save = cc[1]; i = cc[0] & 3; cc[1] = 2<<2; pll_ref_div = cc[2]; cc[1] = 5<<2; pll_vclk_cntl = cc[2]; cc[1] = 6<<2; vclk_post_div = (cc[2]>>(i+i)) & 3; cc[1] = (7+i)<<2; vclk_fb_div = cc[2]; dotclock = 2 * mach64refclock * vclk_fb_div / (pll_ref_div * (1 << vclk_post_div)); /* ecp_div: 0=dotclock, 1=dotclock/2, 2=dotclock/4 */ ecp_div = dotclock / mach64type->m64_ovlclock; if (ecp_div>2) ecp_div = 2; /* Force a scaler clock factor of 1 if refclock * * is unknown (VCLK_SRC not PLLVCLK) */ if ((pll_vclk_cntl & 0x03) != 0x03) ecp_div = 0; if ((pll_vclk_cntl & 0x30) != ecp_div<<4) { cc[1] = (5<<2)|2; cc[2] = (pll_vclk_cntl&0xCF) | (ecp_div<<4); } /* Restore PLL Register Index */ cc[1] = save;}static voidinitengine(VGAscr *scr){ ulong pitch; uchar *bios; ushort table; pitch = Dx(scr->gscreen->r)/8; if(scr->gscreen->depth == 24) pitch *= 3; resetengine(scr); waitforfifo(scr, 14); iow32(scr, ContextMask, ~0); iow32(scr, DstOffPitch, pitch<<22); iow32(scr, DstYX, 0); iow32(scr, DstHeight, 0); iow32(scr, DstBresErr, 0); iow32(scr, DstBresInc, 0); iow32(scr, DstBresDec, 0); iow32(scr, DstCntl, 0x23); iow32(scr, SrcOffPitch, pitch<<22); iow32(scr, SrcYX, 0); iow32(scr, SrcHeight1Width1, 1); iow32(scr, SrcYXstart, 0); iow32(scr, SrcHeight2Width2, 1); iow32(scr, SrcCntl, 0x01); waitforfifo(scr, 13); iow32(scr, HostCntl, 0); iow32(scr, PatReg0, 0); iow32(scr, PatReg1, 0); iow32(scr, PatCntl, 0); iow32(scr, ScLeft, 0); iow32(scr, ScTop, 0); iow32(scr, ScBottom, 0xFFFF); iow32(scr, ScRight, 0xFFFF); iow32(scr, DpBkgdClr, 0); iow32(scr, DpFrgdClr, ~0); iow32(scr, DpWriteMask, ~0); iow32(scr, DpMix, 0x70003); iow32(scr, DpSrc, 0x00010100); waitforfifo(scr, 3); iow32(scr, ClrCmpClr, 0); iow32(scr, ClrCmpMask, ~0); iow32(scr, ClrCmpCntl, 0); waitforfifo(scr, 2); switch(scr->gscreen->depth){ case 8: case 24: /* [sic] */ iow32(scr, DpPixWidth, 0x00020202); iow32(scr, DpChainMask, 0x8080); break; case 16: iow32(scr, DpPixWidth, 0x00040404); iow32(scr, DpChainMask, 0x8410); break; case 32: iow32(scr, DpPixWidth, 0x00060606); iow32(scr, DpChainMask, 0x8080); break; } /* Get the base freq from the BIOS */ bios = kaddr(0xC000); table = *(ushort *)(bios + 0x48); table = *(ushort *)(bios + table + 0x10); switch (*(ushort *)(bios + table + 0x08)) { case 2700: mach64refclock = 270000; break; case 2863: case 2864: mach64refclock = 286363; break; case 2950: mach64refclock = 294989; break; case 1432: default: mach64refclock = 143181; break ; } /* Figure out which revision this chip is */ switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) { case VTGTB1S1: case GTB1U1: case GTB1S2: case GTB2U1: case GTB2U2: case GTB2U3: case GTBC: case GTIIIC1U1: case GTIIIC1U2: case GTIIIC2U1: case GTIIIC2U2: case GTIIIC2U3: case LTPRO: mach64revb = 1; break; default: mach64revb = 0; break; } waitforidle(scr);}static intmach64hwfill(VGAscr *scr, Rectangle r, ulong sval){ ulong pitch; ulong ctl;if(drawdebug) iprint("hwfill %R val %lux...\n", r, sval); /* shouldn't happen */ if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0) return 0; pitch = Dx(scr->gscreen->r)/8; ctl = 1|2; /* left-to-right, top-to-bottom */ if(scr->gscreen->depth == 24){ r.min.x *= 3; r.max.x *= 3; pitch *= 3; ctl |= (1<<7)|(((r.min.x/4)%6)<<8); } waitforfifo(scr, 11); iow32(scr, DpFrgdClr, sval); iow32(scr, DpWriteMask, 0xFFFFFFFF); iow32(scr, DpMix, 0x00070003); iow32(scr, DpSrc, 0x00000111); iow32(scr, ClrCmpCntl, 0x00000000); iow32(scr, ScLeftRight, 0x1FFF0000); iow32(scr, ScTopBottom, 0x1FFF0000); iow32(scr, DstOffPitch, pitch<<22); iow32(scr, DstCntl, ctl); iow32(scr, DstYX, (r.min.x<<16)|r.min.y); iow32(scr, DstHeightWidth, (Dx(r)<<16)|Dy(r)); waitforidle(scr); return 1;}static intmach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr){ ulong pitch; Point dp, sp; ulong ctl; int dx, dy; dx = Dx(r); dy = Dy(r); pitch = Dx(scr->gscreen->r)/8; if(scr->gscreen->depth == 24){ dx *= 3; pitch *= 3; r.min.x *= 3; sr.min.x *= 3; } ctl = 0; if(r.min.x <= sr.min.x){ ctl |= 1; dp.x = r.min.x; sp.x = sr.min.x; }else{ dp.x = r.min.x+dx-1; sp.x = sr.min.x+dx-1; } if(r.min.y <= sr.min.y){ ctl |= 2; dp.y = r.min.y; sp.y = sr.min.y; }else{ dp.y = r.min.y+dy-1; sp.y = sr.min.y+dy-1; } if(scr->gscreen->depth == 24) ctl |= (1<<7)|(((dp.x/4)%6)<<8); waitforfifo(scr, 6); iow32(scr, ScLeftRight, 0x1FFF0000); iow32(scr, ScTopBottom, 0x1FFF0000); iow32(scr, DpWriteMask, 0xFFFFFFFF); iow32(scr, DpMix, 0x00070003); iow32(scr, DpSrc, 0x00000300); iow32(scr, ClrCmpCntl, 0x00000000); waitforfifo(scr, 8); iow32(scr, SrcOffPitch, pitch<<22); iow32(scr, SrcCntl, 0x00000000); iow32(scr, SrcYX, (sp.x<<16)|sp.y); iow32(scr, SrcWidth1, dx); iow32(scr, DstOffPitch, pitch<<22); iow32(scr, DstCntl, ctl); iow32(scr, DstYX, (dp.x<<16)|dp.y); iow32(scr, DstHeightWidth, (dx<<16)|dy); waitforidle(scr); return 1;}/* * This should work, but doesn't. * It messes up the screen timings for some reason. */static voidmach64blank(VGAscr *scr, int blank){ ulong ctl; ctl = ior32(scr, CrtcGenCtl) & ~(CrtcHsyncDis|CrtcVsyncDis); if(blank) ctl |= CrtcHsyncDis|CrtcVsyncDis; iow32(scr, CrtcGenCtl, ctl);}/* * We squirrel away whether the LCD and/or CRT were * on when we were called to blank the screen, and * restore the old state. If we are called to blank the * screen when it is already blank, we don't update the state. * Such a call sequence should not happen, though. * * We could try forcing the chip into power management * mode instead, but I'm not sure how that would interact * with screen updates going on while the screen is blanked. */static voidmach64lcdblank(VGAscr *scr, int blank){ static int crtlcd; ulong x; if(blank) { x = lcdr32(scr, LCD_GenCtrl); if(x & 3) { crtlcd = x & 3; lcdw32(scr, LCD_GenCtrl, x&~3); } } else { if(crtlcd == 0) crtlcd = 2; /* lcd only */ x = lcdr32(scr, LCD_GenCtrl); lcdw32(scr, LCD_GenCtrl, x | crtlcd); }}static voidmach64xxdrawinit(VGAscr *scr){ if(scr->io > 0x2FF){ initengine(scr); scr->fill = mach64hwfill; scr->scroll = mach64hwscroll; }/* scr->blank = mach64blank; */ switch(scr->id){ default: break; case ('L'<<8)|'B': /* 4C42: Rage 3D LTPro */ case ('L'<<8)|'I': /* 4C49: Rage 3D LTPro */ case ('L'<<8)|'M': /* 4C4D: Rage Mobility */ case ('L'<<8)|'P': /* 4C50: Rage 3D LTPro */ scr->blank = mach64lcdblank; hwblank = 1; break; }}static voidovl_configure(VGAscr *scr, Chan *c, char **field){ int w, h; char *format; w = (int)strtol(field[1], nil, 0); h = (int)strtol(field[2], nil, 0); format = field[3]; if (c != ovl_chan) error(Einuse); if (strcmp(format, "YUYV")) error(Eunsupportedformat); ovl_width = w; ovl_height = h; ovl_fib = w * h * sizeof(ushort); waitforidle(scr); scr->mmio[mmoffset[BusCntl]] |= 0x08000000; /* Enable regblock 1 */ scr->mmio[mmoffset[OverlayScaleCntl]] = SCALE_ZERO_EXTEND|SCALE_RED_TEMP_6500K| SCALE_HORZ_BLEND|SCALE_VERT_BLEND; scr->mmio[mmoffset[!mach64revb? Buf0Pitch: ScalerBuf0Pitch]] = w; scr->mmio[mmoffset[CaptureConfig]] = SCALER_FRAME_READ_MODE_FULL| SCALER_BUF_MODE_SINGLE| SCALER_BUF_NEXT_0; scr->mmio[mmoffset[OverlayKeyCntl]] = !mach64revb? OVERLAY_MIX_ALWAYS_V|(OVERLAY_EXCLUSIVE_NORMAL << 28): 0x011; if (mach64type->m64_pro) { waitforfifo(scr, 6); /* set the scaler co-efficient registers */ scr->mmio[mmoffset[ScalerColourCntl]] = (0x00) | (0x10 << 8) | (0x10 << 16); scr->mmio[mmoffset[ScalerHCoef0]] = (0x00) | (0x20 << 8); scr->mmio[mmoffset[ScalerHCoef1]] = (0x0D) | (0x20 << 8) | (0x06 << 16) | (0x0D << 24); scr->mmio[mmoffset[ScalerHCoef2]] = (0x0D) | (0x1C << 8) | (0x0A << 16) | (0x0D << 24); scr->mmio[mmoffset[ScalerHCoef3]] = (0x0C) | (0x1A << 8) | (0x0E << 16) | (0x0C << 24); scr->mmio[mmoffset[ScalerHCoef4]] = (0x0C) | (0x14 << 8) | (0x14 << 16) | (0x0C << 24); } waitforfifo(scr, 3); scr->mmio[mmoffset[VideoFormat]] = SCALE_IN_YVYU422 | (!mach64revb? 0xC: 0); if (mach64overlay == 0) mach64overlay = scr->storage + 64 * 64 * sizeof(uchar); scr->mmio[mmoffset[!mach64revb? Buf0Offset: ScalerBuf0Offset]] = mach64overlay;}static voidovl_enable(VGAscr *scr, Chan *c, char **field){ int x, y, w, h; long h_inc, v_inc; x = (int)strtol(field[1], nil, 0); y = (int)strtol(field[2], nil, 0); w = (int)strtol(field[3], nil, 0); h = (int)strtol(field[4], nil, 0); if (x < 0 || x + w > physgscreenr.max.x || y < 0 || y + h > physgscreenr.max.y) error(Ebadarg); if (c != ovl_chan) error(Einuse); if (scr->mmio[mmoffset[CrtcGenCntl]] & 1) { /* double scan enable */ y *= 2; h *= 2; } waitforfifo(scr, 2); scr->mmio[mmoffset[OverlayYX]] = ((x & 0xFFFF) << 16) | (y & 0xFFFF); scr->mmio[mmoffset[OverlayYXEnd]] = (((x + w) & 0xFFFF) << 16) | ((y + h) & 0xFFFF); h_inc = (ovl_width << 12) / (w >> 1); /* ??? */ v_inc = (ovl_height << 12) / h; waitforfifo(scr, 2); scr->mmio[mmoffset[OverlayScaleInc]] = ((h_inc & 0xFFFF) << 16) | (v_inc & 0xFFFF); scr->mmio[mmoffset[ScalerHeightWidth]] = ((ovl_width & 0xFFFF) << 16) | (ovl_height & 0xFFFF); waitforidle(scr); scr->mmio[mmoffset[OverlayScaleCntl]] |= (SCALE_ENABLE|OVERLAY_ENABLE);}static voidovl_status(VGAscr *scr, Chan *, char **field){ pprint("%s: %s %.4uX, VT/GT %s, PRO %s, ovlclock %d, rev B %s, refclock %ld\n", scr->dev->name, field[0], mach64type->m64_id, mach64type->m64_vtgt? "yes": "no", mach64type->m64_pro? "yes": "no", mach64type->m64_ovlclock, mach64revb? "yes": "no", mach64refclock); pprint("%s: storage @%.8luX, aperture @%8.ulX, ovl buf @%.8ulX\n", scr->dev->name, scr->storage, scr->paddr, mach64overlay);} static voidovl_openctl(VGAscr *, Chan *c, char **){ if (ovl_chan) error(Einuse); ovl_chan = c;}static voidovl_closectl(VGAscr *scr, Chan *c, char **){ if (c != ovl_chan) return; waitforidle(scr); scr->mmio[mmoffset[OverlayScaleCntl]] &= ~(SCALE_ENABLE|OVERLAY_ENABLE); ovl_chan = nil; ovl_width = ovl_height = ovl_fib = 0;}enum{ CMclosectl, CMconfigure, CMenable, CMopenctl, CMstatus,};static void (*ovl_cmds[])(VGAscr *, Chan *, char **) ={ [CMclosectl] ovl_closectl, [CMconfigure] ovl_configure, [CMenable] ovl_enable, [CMopenctl] ovl_openctl, [CMstatus] ovl_status,};static Cmdtab mach64xxcmd[] ={ CMclosectl, "closectl", 1, CMconfigure, "configure", 4, CMenable, "enable", 5, CMopenctl, "openctl", 1, CMstatus, "status", 1,};static voidmach64xxovlctl(VGAscr *scr, Chan *c, void *a, int n){ Cmdbuf *cb; Cmdtab *ct; if(!mach64type->m64_vtgt) error(Enodev); if(!scr->overlayinit){ scr->overlayinit = 1; init_overlayclock(scr); } cb = parsecmd(a, n); if(waserror()){ free(cb); nexterror(); } ct = lookupcmd(cb, mach64xxcmd, nelem(mach64xxcmd)); ovl_cmds[ct->index](scr, c, cb->f); poperror(); free(cb);}static intmach64xxovlwrite(VGAscr *scr, void *a, int len, vlong offs){ uchar *src; int _len; if (ovl_chan == nil) return len; /* Acts as a /dev/null */ /* Calculate the destination address */ _len = len; src = (uchar *)a; while (len > 0) { ulong _offs; int nb; _offs = (ulong)(offs % ovl_fib); nb = (_offs + len > ovl_fib)? ovl_fib - _offs: len; memmove((uchar *)scr->vaddr + mach64overlay + _offs, src, nb); offs += nb; src += nb; len -= nb; } return _len;}VGAdev vgamach64xxdev = { "mach64xx", mach64xxenable, /* enable */ 0, /* disable */ 0, /* page */ mach64xxlinear, /* linear */ mach64xxdrawinit, /* drawinit */ 0, mach64xxovlctl, /* overlay control */ mach64xxovlwrite, /* write the overlay */};VGAcur vgamach64xxcur = { "mach64xxhwgc", mach64xxcurenable, /* enable */ mach64xxcurdisable, /* disable */ mach64xxcurload, /* load */ mach64xxcurmove, /* move */ 1 /* doespanning */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -