static status_t GetI2CSignals(void* cookie, int* _clock, int* data) { uint32 index = (uint32)cookie; uint8 value = ReadCrtcReg(index); *_clock = (value & 0x4) != 0; *data = (value & 0x8) != 0; return B_OK; }
bool Savage_GetEdidInfo(edid1_info& edidInfo) { // Get the EDID info and return true if successful. SharedInfo& si = *gInfo.sharedInfo; uint32 DDCPort = 0; switch (si.chipType) { case S3_SAVAGE_3D: case S3_SAVAGE_MX: case S3_SUPERSAVAGE: case S3_SAVAGE2000: DDCPort = 0xAA; break; case S3_SAVAGE4: case S3_PROSAVAGE: case S3_TWISTER: case S3_PROSAVAGE_DDR: DDCPort = 0xB1; break; } i2c_bus bus; bus.cookie = (void*)DDCPort; bus.set_signals = &SetI2CSignals; bus.get_signals = &GetI2CSignals; ddc2_init_timing(&bus); uint8 tmp = ReadCrtcReg(DDCPort); WriteCrtcReg(DDCPort, tmp | 0x13); bool bResult = (ddc2_read_edid1(&bus, &edidInfo, NULL, NULL) == B_OK); WriteCrtcReg(DDCPort, tmp); return bResult; }
static void Virge_GEReset(const DisplayModeEx& mode) { SharedInfo& si = *gInfo.sharedInfo; if (si.chipType == S3_TRIO_3D) Virge_NopAllCmdSets(); gInfo.WaitIdleEmpty(); if (si.chipType == S3_TRIO_3D) { bool ge_was_on = false; snooze(10000); for (int r = 1; r < 10; r++) { uint8 resetidx = 0x66; VerticalRetraceWait(); uint8 tmp = ReadCrtcReg(resetidx); VerticalRetraceWait(); IN_SUBSYS_STAT(); // turn off the GE if (tmp & 0x01) { WriteCrtcReg(resetidx, tmp); ge_was_on = true; snooze(10000); } IN_SUBSYS_STAT(); WriteCrtcReg(resetidx, tmp | 0x02); snooze(10000); VerticalRetraceWait(); WriteCrtcReg(resetidx, tmp & ~0x02); snooze(10000); if (ge_was_on) { tmp |= 0x01; WriteCrtcReg(resetidx, tmp); snooze(10000); } VerticalRetraceWait(); Virge_NopAllCmdSets(); gInfo.WaitIdleEmpty(); WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow); snooze(10000); if ((IN_SUBSYS_STAT() & 0x3f802000 & 0x20002000) != 0x20002000) { TRACE("Restarting S3 graphics engine reset %2d ...%lx\n", r, IN_SUBSYS_STAT() ); } else break; } } else { uint8 regIndex = (si.chipType == S3_VIRGE_VX ? 0x63 : 0x66); uint8 tmp = ReadCrtcReg(regIndex); snooze(10000); // try multiple times to avoid lockup of VIRGE/MX for (int r = 1; r < 10; r++) { WriteCrtcReg(regIndex, tmp | 0x02); snooze(10000); WriteCrtcReg(regIndex, tmp & ~0x02); snooze(10000); gInfo.WaitIdleEmpty(); WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow); snooze(10000); if (((IN_SUBSYS_STAT() & 0x3f00) != 0x3000)) { TRACE("Restarting S3 graphics engine reset %2d ...\n", r); } else break; } } gInfo.WaitQueue(2); WriteReg32(SRC_BASE, 0); WriteReg32(DEST_BASE, 0); gInfo.WaitQueue(4); WriteReg32(CLIP_L_R, ((0) << 16) | mode.timing.h_display); WriteReg32(CLIP_T_B, ((0) << 16) | mode.timing.v_display); WriteReg32(MONO_PAT_0, ~0); WriteReg32(MONO_PAT_1, ~0); if (si.chipType == S3_TRIO_3D) Virge_NopAllCmdSets(); }
static bool Virge_ModeInit(const DisplayModeEx& mode) { SharedInfo& si = *gInfo.sharedInfo; VirgeRegRec regRec; TRACE("Virge_ModeInit(%d x %d, %d KHz)\n", mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock); // Set scale factors for mode timings. int horizScaleFactor = 1; if (si.chipType == S3_VIRGE_VX || S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType)) { horizScaleFactor = 1; } else if (mode.bpp == 8) { horizScaleFactor = 1; } else if (mode.bpp == 16) { if (si.chipType == S3_TRIO_3D && mode.timing.pixel_clock > 115000) horizScaleFactor = 1; else horizScaleFactor = 2; } else { horizScaleFactor = 1; } InitCrtcTimingValues(mode, horizScaleFactor, regRec.CRTC, regRec.CR3B, regRec.CR3C, regRec.CR5D, regRec.CR5E); // Now we fill in the rest of the stuff we need for the Virge. // Start with MMIO, linear address regs. uint8 temp = ReadCrtcReg(0x3a); if ( S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) ) regRec.CR3A = (temp & 0x7f) | 0x10; // ENH 256, PCI burst else regRec.CR3A = (temp & 0x7f) | 0x15; // ENH 256, PCI burst regRec.CR53 = ReadCrtcReg(0x53); if (si.chipType == S3_TRIO_3D) { regRec.CR31 = 0x0c; // [trio3d] page 54 } else { regRec.CR53 = 0x08; // Enables MMIO regRec.CR31 = 0x8c; // Dis. 64k window, en. ENH maps } // Enables S3D graphic engine and PCI disconnects. if (si.chipType == S3_VIRGE_VX) { regRec.CR66 = 0x90; regRec.CR63 = 0x09; } else { regRec.CR66 = 0x89; // Set display fifo. if ( S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) ) { // Changed from 0x08 based on reports that this // prevents MX from running properly below 1024x768. regRec.CR63 = 0x10; } else { regRec.CR63 = 0; } } // Now set linear address registers. // LAW size: we have 2 cases, 2MB, 4MB or >= 4MB for VX. regRec.CR58 = ReadCrtcReg(0x58) & 0x80; if (si.videoMemSize == 1 * 1024 * 1024) regRec.CR58 |= 0x01 | 0x10; else if (si.videoMemSize == 2 * 1024 * 1024) regRec.CR58 |= 0x02 | 0x10; else { if (si.chipType == S3_TRIO_3D_2X && si.videoMemSize == 8 * 1024 * 1024) regRec.CR58 |= 0x07 | 0x10; // 8MB window on Trio3D/2X else regRec.CR58 |= 0x03 | 0x10; // 4MB window on virge, 8MB on VX } if (si.chipType == S3_VIRGE_VX) regRec.CR58 |= 0x40; // ** On PCI bus, no need to reprogram the linear window base address. // Now do clock PLL programming. Use the s3gendac function to get m,n. // Also determine if we need doubling etc. int dclk = mode.timing.pixel_clock; if (si.chipType == S3_TRIO_3D) { regRec.SR15 = (ReadSeqReg(0x15) & 0x80) | 0x03; // keep BIOS init defaults regRec.SR0A = ReadSeqReg(0x0a); } else regRec.SR15 = 0x03 | 0x80; regRec.SR18 = 0x00; regRec.CR43 = 0x00; regRec.CR45 = 0x00; // Enable MMIO to RAMDAC registers. regRec.CR65 = 0x00; // CR65_2 must be zero, doc seems to be wrong regRec.CR54 = 0x00; if (si.chipType != S3_TRIO_3D && si.chipType != S3_VIRGE_MX) { regRec.CR40 = ReadCrtcReg(0x40) & ~0x01; } if (S3_VIRGE_MX_SERIES(si.chipType)) { // Fix problems with APM suspend/resume trashing CR90/91. switch (mode.bpp) { case 8: regRec.CR41 = 0x38; break; case 16: regRec.CR41 = 0x48; break; default: regRec.CR41 = 0x77; } } regRec.CR67 = 0x00; // defaults if (si.chipType == S3_VIRGE_VX) { if (mode.bpp == 8) { if (dclk <= 110000) regRec.CR67 = 0x00; // 8bpp, 135MHz else regRec.CR67 = 0x10; // 8bpp, 220MHz } else if (mode.bpp == 16) { if (dclk <= 110000) regRec.CR67 = 0x40; // 16bpp, 135MHz else regRec.CR67 = 0x50; // 16bpp, 220MHz } Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 220000, 440000, ®Rec.SR13, ®Rec.SR12); } // end VX if() else if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType)) { uint8 ndiv; if (mode.bpp == 8) regRec.CR67 = 0x00; else if (mode.bpp == 16) regRec.CR67 = 0x50; // X.org code had a somewhat convuluted way of computing the clock for // MX chips. I hope this simpler method works for most MX cases. Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 170000, 340000, ®Rec.SR13, &ndiv); regRec.SR29 = ndiv >> 7; regRec.SR12 = (ndiv & 0x1f) | ((ndiv & 0x60) << 1); } // end GX2 or MX if()
static void Virge_WriteMode(const DisplayModeEx& mode, VirgeRegRec& regRec) { // This function writes out all of the standard VGA and extended S3 registers // needed to setup a video mode. TRACE("Virge_WriteMode()\n"); SharedInfo& si = *gInfo.sharedInfo; // First reset GE to make sure nothing is going on. if (ReadCrtcReg(si.chipType == S3_VIRGE_VX ? 0x63 : 0x66) & 0x01) Virge_GEReset(mode); // As per databook, always disable STREAMS before changing modes. if ((ReadCrtcReg(0x67) & 0x0c) == 0x0c) { // STREAMS running, disable it VerticalRetraceWait(); WriteReg32(FIFO_CONTROL_REG, 0xC000); WriteCrtcReg(0x67, 0x00, 0x0c); // disable STREAMS processor } // Restore S3 extended regs. WriteCrtcReg(0x63, regRec.CR63); WriteCrtcReg(0x66, regRec.CR66); WriteCrtcReg(0x3a, regRec.CR3A); WriteCrtcReg(0x31, regRec.CR31); WriteCrtcReg(0x58, regRec.CR58); // Extended mode timings registers. WriteCrtcReg(0x53, regRec.CR53); WriteCrtcReg(0x5d, regRec.CR5D); WriteCrtcReg(0x5e, regRec.CR5E); WriteCrtcReg(0x3b, regRec.CR3B); WriteCrtcReg(0x3c, regRec.CR3C); WriteCrtcReg(0x43, regRec.CR43); WriteCrtcReg(0x65, regRec.CR65); WriteCrtcReg(0x6d, regRec.CR6D); // Restore the desired video mode with CR67. WriteCrtcReg(0x67, 0x50, 0xf0); // possible hardware bug on VX? snooze(10000); WriteCrtcReg(0x67, regRec.CR67 & ~0x0c); // Don't enable STREAMS // Other mode timing and extended regs. WriteCrtcReg(0x34, regRec.CR34); if (si.chipType != S3_TRIO_3D && si.chipType != S3_VIRGE_MX) { WriteCrtcReg(0x40, regRec.CR40); } if (S3_VIRGE_MX_SERIES(si.chipType)) { WriteCrtcReg(0x41, regRec.CR41); } WriteCrtcReg(0x42, regRec.CR42); WriteCrtcReg(0x45, regRec.CR45); WriteCrtcReg(0x51, regRec.CR51); WriteCrtcReg(0x54, regRec.CR54); // Memory timings. WriteCrtcReg(0x68, regRec.CR68); WriteCrtcReg(0x69, regRec.CR69); WriteCrtcReg(0x33, regRec.CR33); if (si.chipType == S3_TRIO_3D_2X || S3_VIRGE_GX2_SERIES(si.chipType) /* MXTESTME */ || S3_VIRGE_MX_SERIES(si.chipType) ) { WriteCrtcReg(0x85, regRec.CR85); } if (si.chipType == S3_VIRGE_DXGX) { WriteCrtcReg(0x86, regRec.CR86); } if ( (si.chipType == S3_VIRGE_GX2) || S3_VIRGE_MX_SERIES(si.chipType) ) { WriteCrtcReg(0x7b, regRec.CR7B); WriteCrtcReg(0x7d, regRec.CR7D); WriteCrtcReg(0x87, regRec.CR87); WriteCrtcReg(0x92, regRec.CR92); WriteCrtcReg(0x93, regRec.CR93); } if (si.chipType == S3_VIRGE_DXGX || S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) || si.chipType == S3_TRIO_3D) { WriteCrtcReg(0x90, regRec.CR90); WriteCrtcReg(0x91, regRec.CR91); } WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs // Restore extended sequencer regs for DCLK. WriteSeqReg(0x12, regRec.SR12); WriteSeqReg(0x13, regRec.SR13); if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType)) { WriteSeqReg(0x29, regRec.SR29); } if (S3_VIRGE_MX_SERIES(si.chipType)) { WriteSeqReg(0x54, regRec.SR54); WriteSeqReg(0x55, regRec.SR55); WriteSeqReg(0x56, regRec.SR56); WriteSeqReg(0x57, regRec.SR57); } WriteSeqReg(0x18, regRec.SR18); // Load new m,n PLL values for DCLK & MCLK. uint8 tmp = ReadSeqReg(0x15) & ~0x21; WriteSeqReg(0x15, tmp | 0x03); WriteSeqReg(0x15, tmp | 0x23); WriteSeqReg(0x15, tmp | 0x03); WriteSeqReg(0x15, regRec.SR15); if (si.chipType == S3_TRIO_3D) { WriteSeqReg(0x0a, regRec.SR0A); WriteSeqReg(0x0f, regRec.SR0F); } // Now write out CR67 in full, possibly starting STREAMS. VerticalRetraceWait(); WriteCrtcReg(0x67, 0x50); // For possible bug on VX?! snooze(10000); WriteCrtcReg(0x67, regRec.CR67); uint8 cr66 = ReadCrtcReg(0x66); WriteCrtcReg(0x66, cr66 | 0x80); WriteCrtcReg(0x3a, regRec.CR3A | 0x80); // Now, before we continue, check if this mode has the graphic engine ON. // If yes, then we reset it. if (si.chipType == S3_VIRGE_VX) { if (regRec.CR63 & 0x01) Virge_GEReset(mode); } else { if (regRec.CR66 & 0x01) Virge_GEReset(mode); } VerticalRetraceWait(); if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) ) { WriteCrtcReg(0x85, 0x1f); // primary stream threshold } // Set the standard CRTC vga regs. WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11 for (int j = 0; j < NUM_ELEMENTS(regRec.CRTC); j++) { WriteCrtcReg(j, regRec.CRTC[j]); } // Setup HSYNC & VSYNC polarity and select clock source 2 (0x0c) for // programmable PLL. uint8 miscOutReg = 0x23 | 0x0c; if (!(mode.timing.flags & B_POSITIVE_HSYNC)) miscOutReg |= 0x40; if (!(mode.timing.flags & B_POSITIVE_VSYNC)) miscOutReg |= 0x80; WriteMiscOutReg(miscOutReg); WriteCrtcReg(0x66, cr66); WriteCrtcReg(0x3a, regRec.CR3A); return ; }
status_t Virge_Init(void) { TRACE("Virge_Init()\n"); SharedInfo& si = *gInfo.sharedInfo; // Use PIO for following operations since MMIO may not be currently enabled. WritePIO_8(VGA_ENABLE, ReadPIO_8(VGA_ENABLE) | 0x01); // enable VGA WritePIO_8(MISC_OUT_W, ReadPIO_8(MISC_OUT_R) | 0x01); // enable color // Set linear base register to the PCI register value; // some DX chipsets don't seem to do it automatically. WritePIO_8(CRTC_INDEX, 0x59); WritePIO_8(CRTC_DATA, (uint32)(si.videoMemPCI) >> 24); WritePIO_8(CRTC_INDEX, 0x5A); WritePIO_8(CRTC_DATA, (uint32)(si.videoMemPCI) >> 16); // Enable MMIO. WritePIO_8(CRTC_INDEX, 0x53); WritePIO_8(CRTC_DATA, ReadPIO_8(CRTC_DATA) | 0x8); if (si.chipType == S3_TRIO_3D) WriteCrtcReg(0x40, 0x01, 0x01); // Detect amount of installed ram. uint8 config1 = ReadCrtcReg(0x36); // get amount of vram installed uint8 config2 = ReadCrtcReg(0x37); // get amount of off-screen ram // Compute the amount of video memory and offscreen memory. int ramOffScreenMB = 0; // off screen memory size in megabytes int ramSizeMB = 0; // memory size in megabytes if (si.chipType == S3_VIRGE_VX) { switch ((config2 & 0x60) >> 5) { case 1: ramOffScreenMB = 4; break; case 2: ramOffScreenMB = 2; break; } switch ((config1 & 0x60) >> 5) { case 0: ramSizeMB = 2; break; case 1: ramSizeMB = 4; break; case 2: ramSizeMB = 6; break; case 3: ramSizeMB = 8; break; } ramSizeMB -= ramOffScreenMB; } else if (si.chipType == S3_TRIO_3D_2X) {