Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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();
}
Beispiel #4
0
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,
						&regRec.SR13, &regRec.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,
						&regRec.SR13, &ndiv);

		regRec.SR29 = ndiv >> 7;
		regRec.SR12 = (ndiv & 0x1f) | ((ndiv & 0x60) << 1);
	} // end GX2 or MX if()
Beispiel #5
0
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 ;
}
Beispiel #6
0
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) {