xref: /haiku/src/add-ons/accelerants/s3/trio64_mode.cpp (revision 6ab4ff112a084ee6f022e17b4d2668038c0b2014)
135db13eaSAxel Dörfler /*
235db13eaSAxel Dörfler 	Haiku S3 Trio64 driver adapted from the X.org S3 driver.
335db13eaSAxel Dörfler 
435db13eaSAxel Dörfler 	Copyright 2001	Ani Joshi <ajoshi@unixbox.com>
535db13eaSAxel Dörfler 
635db13eaSAxel Dörfler 	Copyright 2008 Haiku, Inc.  All rights reserved.
735db13eaSAxel Dörfler 	Distributed under the terms of the MIT license.
835db13eaSAxel Dörfler 
935db13eaSAxel Dörfler 	Authors:
1035db13eaSAxel Dörfler 	Gerald Zajac 2008
1135db13eaSAxel Dörfler */
1235db13eaSAxel Dörfler 
1335db13eaSAxel Dörfler 
1435db13eaSAxel Dörfler #include "accel.h"
1535db13eaSAxel Dörfler #include "trio64.h"
1635db13eaSAxel Dörfler 
1735db13eaSAxel Dörfler 
1835db13eaSAxel Dörfler #define BASE_FREQ		14.31818	// MHz
1935db13eaSAxel Dörfler 
2035db13eaSAxel Dörfler 
2135db13eaSAxel Dörfler static void
Trio64_CalcClock(long freq,int min_m,int min_n1,int max_n1,int min_n2,int max_n2,long freq_min,long freq_max,uint8 * mdiv,uint8 * ndiv)2235db13eaSAxel Dörfler Trio64_CalcClock(long freq, int min_m, int min_n1, int max_n1,
2335db13eaSAxel Dörfler 				int min_n2, int max_n2, long freq_min, long freq_max,
2435db13eaSAxel Dörfler 				uint8* mdiv, uint8* ndiv)
2535db13eaSAxel Dörfler {
2635db13eaSAxel Dörfler 	uint8 best_n1 = 18, best_n2 = 2, best_m = 127;
2735db13eaSAxel Dörfler 
2835db13eaSAxel Dörfler 	double ffreq = freq / 1000.0 / BASE_FREQ;
2935db13eaSAxel Dörfler 	double ffreq_min = freq_min / 1000.0 / BASE_FREQ;
3035db13eaSAxel Dörfler 	double ffreq_max = freq_max / 1000.0 / BASE_FREQ;
3135db13eaSAxel Dörfler 
3235db13eaSAxel Dörfler 	if (ffreq < ffreq_min / (1 << max_n2)) {
3335db13eaSAxel Dörfler 		TRACE("Trio64_CalcClock() invalid frequency %1.3f Mhz [freq >= %1.3f Mhz]\n",
3435db13eaSAxel Dörfler 			   ffreq*BASE_FREQ, ffreq_min*BASE_FREQ / (1 << max_n2));
3535db13eaSAxel Dörfler 		ffreq = ffreq_min / (1 << max_n2);
3635db13eaSAxel Dörfler 	}
3735db13eaSAxel Dörfler 	if (ffreq > ffreq_max / (1 << min_n2)) {
3835db13eaSAxel Dörfler 		TRACE("Trio64_CalcClock() invalid frequency %1.3f Mhz [freq <= %1.3f Mhz]\n",
3935db13eaSAxel Dörfler 			   ffreq*BASE_FREQ, ffreq_max*BASE_FREQ / (1 << min_n2));
4035db13eaSAxel Dörfler 		ffreq = ffreq_max / (1 << min_n2);
4135db13eaSAxel Dörfler 	}
4235db13eaSAxel Dörfler 
4335db13eaSAxel Dörfler 	double best_diff = ffreq;
4435db13eaSAxel Dörfler 
4535db13eaSAxel Dörfler 	for (uint8 n2 = min_n2; n2 <= max_n2; n2++) {
4635db13eaSAxel Dörfler 		for (uint8 n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) {
4735db13eaSAxel Dörfler 			int m = (int)(ffreq * n1 * (1 << n2) + 0.5);
4835db13eaSAxel Dörfler 			if (m < min_m + 2 || m > 127 + 2)
4935db13eaSAxel Dörfler 				continue;
5035db13eaSAxel Dörfler 
5135db13eaSAxel Dörfler 			double div = (double)(m) / (double)(n1);
5235db13eaSAxel Dörfler 			if ((div >= ffreq_min) && (div <= ffreq_max)) {
5335db13eaSAxel Dörfler 				double diff = ffreq - div / (1 << n2);
5435db13eaSAxel Dörfler 				if (diff < 0.0)
5535db13eaSAxel Dörfler 					diff = -diff;
5635db13eaSAxel Dörfler 				if (diff < best_diff) {
5735db13eaSAxel Dörfler 					best_diff = diff;
5835db13eaSAxel Dörfler 					best_m = m;
5935db13eaSAxel Dörfler 					best_n1 = n1;
6035db13eaSAxel Dörfler 					best_n2 = n2;
6135db13eaSAxel Dörfler 				}
6235db13eaSAxel Dörfler 			}
6335db13eaSAxel Dörfler 		}
6435db13eaSAxel Dörfler 	}
6535db13eaSAxel Dörfler 
6635db13eaSAxel Dörfler 	if (max_n1 == 63)
6735db13eaSAxel Dörfler 		*ndiv = (best_n1 - 2) | (best_n2 << 6);
6835db13eaSAxel Dörfler 	else
6935db13eaSAxel Dörfler 		*ndiv = (best_n1 - 2) | (best_n2 << 5);
7035db13eaSAxel Dörfler 	*mdiv = best_m - 2;
7135db13eaSAxel Dörfler }
7235db13eaSAxel Dörfler 
7335db13eaSAxel Dörfler 
7435db13eaSAxel Dörfler 
7535db13eaSAxel Dörfler static bool
Trio64_ModeInit(const DisplayModeEx & mode)7635db13eaSAxel Dörfler Trio64_ModeInit(const DisplayModeEx& mode)
7735db13eaSAxel Dörfler {
7835db13eaSAxel Dörfler 	SharedInfo& si = *gInfo.sharedInfo;
7935db13eaSAxel Dörfler 
8035db13eaSAxel Dörfler 	TRACE("Trio64_ModeInit(%d x %d, %d KHz)\n",
8135db13eaSAxel Dörfler 		mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock);
8235db13eaSAxel Dörfler 
8335db13eaSAxel Dörfler 	uint32 videoRamMB = si.videoMemSize / (1024 * 1024);	// MB's of video RAM
8435db13eaSAxel Dörfler 
8535db13eaSAxel Dörfler 	WriteCrtcReg(0x38, 0x48);			// unlock sys regs
8635db13eaSAxel Dörfler 	WriteCrtcReg(0x39, 0xa5);			// unlock sys regs
8735db13eaSAxel Dörfler 	WriteSeqReg(0x08, 0x06);			// unlock extended sequencer regs
8835db13eaSAxel Dörfler 
8935db13eaSAxel Dörfler 	WriteCrtcReg(0x45, 0x00, 0x01);		// turn off hardware cursor
9035db13eaSAxel Dörfler 
9135db13eaSAxel Dörfler 	uint8 sr12, sr13;
9235db13eaSAxel Dörfler 	Trio64_CalcClock(mode.timing.pixel_clock, 1, 1, 31, 0, 3, 135000, 270000,
9335db13eaSAxel Dörfler 					 &sr13, &sr12);
9435db13eaSAxel Dörfler 
9535db13eaSAxel Dörfler 	// Set clock registers.
9635db13eaSAxel Dörfler 
9735db13eaSAxel Dörfler 	WriteSeqReg(0x12, sr12);
9835db13eaSAxel Dörfler 	WriteSeqReg(0x13, sr13);
9935db13eaSAxel Dörfler 
10035db13eaSAxel Dörfler 	// Activate clock
10135db13eaSAxel Dörfler 
10235db13eaSAxel Dörfler 	uint8 tmp = ReadSeqReg(0x15) & ~0x21;
10335db13eaSAxel Dörfler 	WriteSeqReg(0x15, tmp | 0x02);
10435db13eaSAxel Dörfler 	WriteSeqReg(0x15, tmp | 0x22);
10535db13eaSAxel Dörfler 	WriteSeqReg(0x15, tmp | 0x02);
10635db13eaSAxel Dörfler 
10735db13eaSAxel Dörfler 	uint8 cr33 = ReadCrtcReg(0x33) & ~0x28;
10835db13eaSAxel Dörfler 	uint8 cr50 = 0;
10935db13eaSAxel Dörfler 	uint8 pixmux = 0;
11035db13eaSAxel Dörfler 
11135db13eaSAxel Dörfler 	if (si.chipType == S3_TRIO64_V2)
11235db13eaSAxel Dörfler 		cr33 |= 0x20;
11335db13eaSAxel Dörfler 
11435db13eaSAxel Dörfler 	switch (mode.bpp) {
11535db13eaSAxel Dörfler 		case 8:
11635db13eaSAxel Dörfler 			break;
11735db13eaSAxel Dörfler 		case 15:
11835db13eaSAxel Dörfler 			cr33 |= 0x08;
11935db13eaSAxel Dörfler 			cr50 = 0x10;
12035db13eaSAxel Dörfler 			pixmux = 0x30;
12135db13eaSAxel Dörfler 			break;
12235db13eaSAxel Dörfler 		case 16:
12335db13eaSAxel Dörfler 			cr33 |= 0x08;
12435db13eaSAxel Dörfler 			cr50 = 0x10;
12535db13eaSAxel Dörfler 			pixmux = 0x50;
12635db13eaSAxel Dörfler 			break;
12735db13eaSAxel Dörfler 		case 32:
12835db13eaSAxel Dörfler 			cr50 = 0x30;
12935db13eaSAxel Dörfler 			pixmux = 0xd0;
13035db13eaSAxel Dörfler 			break;
13135db13eaSAxel Dörfler 	}
13235db13eaSAxel Dörfler 
133c1379d35SAxel Dörfler 	bool bDisableAccelFuncs = false;
13435db13eaSAxel Dörfler 
13535db13eaSAxel Dörfler 	switch (mode.timing.h_display) {
13635db13eaSAxel Dörfler 		case 640:
13735db13eaSAxel Dörfler 			cr50 |= 0x40;
13835db13eaSAxel Dörfler 			break;
13935db13eaSAxel Dörfler 		case 800:
14035db13eaSAxel Dörfler 			cr50 |= 0x80;
14135db13eaSAxel Dörfler 			break;
14235db13eaSAxel Dörfler 		case 1024:
14335db13eaSAxel Dörfler 			cr50 |= 0x00;
14435db13eaSAxel Dörfler 			break;
14535db13eaSAxel Dörfler 		case 1152:
14635db13eaSAxel Dörfler 			cr50 |= 0x01;
14735db13eaSAxel Dörfler 			break;
14835db13eaSAxel Dörfler 		case 1280:
14935db13eaSAxel Dörfler 			cr50 |= 0xc0;
15035db13eaSAxel Dörfler 			break;
15135db13eaSAxel Dörfler 		case 1600:
15235db13eaSAxel Dörfler 			cr50 |= 0x81;
15335db13eaSAxel Dörfler 			break;
15435db13eaSAxel Dörfler 		default:
155c1379d35SAxel Dörfler 			bDisableAccelFuncs = true;	// use app_server default accel functions
15635db13eaSAxel Dörfler 			break;
15735db13eaSAxel Dörfler 	}
15835db13eaSAxel Dörfler 
15935db13eaSAxel Dörfler 	WriteCrtcReg(0x33, cr33);
16035db13eaSAxel Dörfler 	WriteCrtcReg(0x50, cr50);		// set number of bits per pixel & display width
16135db13eaSAxel Dörfler 	WriteCrtcReg(0x67, pixmux);		// set pixel format
16235db13eaSAxel Dörfler 
16335db13eaSAxel Dörfler 	WriteSeqReg(0x15, 0x00, 0x10);		// turn off pixel multiplex
16435db13eaSAxel Dörfler 	WriteSeqReg(0x18, 0x00, 0x80);
16535db13eaSAxel Dörfler 
16635db13eaSAxel Dörfler 	// Note that the 2D acceleration (drawing) functions in this accelerant work
16735db13eaSAxel Dörfler 	// only with the display widths defined in the above switch statement.  For
16835db13eaSAxel Dörfler 	// the other widths, the default functions in the app_server will be used.
16935db13eaSAxel Dörfler 
170c1379d35SAxel Dörfler 	si.bDisableAccelDraw = bDisableAccelFuncs;
17135db13eaSAxel Dörfler 
17235db13eaSAxel Dörfler 	// Set the standard CRTC vga regs.
17335db13eaSAxel Dörfler 
17435db13eaSAxel Dörfler 	uint8 crtc[25], cr3b, cr3c, cr5d, cr5e;
17535db13eaSAxel Dörfler 
17635db13eaSAxel Dörfler 	InitCrtcTimingValues(mode, (mode.bpp > 8) ? 2 : 1, crtc, cr3b, cr3c, cr5d, cr5e);
17735db13eaSAxel Dörfler 	crtc[0x17] = 0xe3;
17835db13eaSAxel Dörfler 
17935db13eaSAxel Dörfler 	WriteCrtcReg(0x11, 0x00, 0x80);	// unlock CRTC reg's 0-7 by clearing bit 7 of cr11
18035db13eaSAxel Dörfler 
181*6ab4ff11SAlexander von Gluck IV 	for (int k = 0; k < (int)B_COUNT_OF(crtc); k++) {
18235db13eaSAxel Dörfler 		WriteCrtcReg(k, crtc[k]);
18335db13eaSAxel Dörfler 	}
18435db13eaSAxel Dörfler 
18535db13eaSAxel Dörfler 	WriteCrtcReg(0x3b, cr3b);
18635db13eaSAxel Dörfler 	WriteCrtcReg(0x3c, cr3c);
18735db13eaSAxel Dörfler 	WriteCrtcReg(0x5d, cr5d);
18835db13eaSAxel Dörfler 	WriteCrtcReg(0x5e, cr5e);
18935db13eaSAxel Dörfler 
19035db13eaSAxel Dörfler 	uint8 miscOutReg = 0x2f;
19135db13eaSAxel Dörfler 
19235db13eaSAxel Dörfler 	if ( ! (mode.timing.flags & B_POSITIVE_HSYNC))
19335db13eaSAxel Dörfler 		miscOutReg |= 0x40;
19435db13eaSAxel Dörfler 	if ( ! (mode.timing.flags & B_POSITIVE_VSYNC))
19535db13eaSAxel Dörfler 		miscOutReg |= 0x80;
19635db13eaSAxel Dörfler 
19735db13eaSAxel Dörfler 	WriteMiscOutReg(miscOutReg);
19835db13eaSAxel Dörfler 
19935db13eaSAxel Dörfler 	uint8 cr58;
20035db13eaSAxel Dörfler 	if (videoRamMB <= 1)
20135db13eaSAxel Dörfler 		cr58 = 0x01;
20235db13eaSAxel Dörfler 	else if (videoRamMB <= 2)
20335db13eaSAxel Dörfler 		cr58 = 0x02;
20435db13eaSAxel Dörfler 	else
20535db13eaSAxel Dörfler 		cr58 = 0x03;
20635db13eaSAxel Dörfler 
20735db13eaSAxel Dörfler 	WriteCrtcReg(0x58, cr58 | 0x10, 0x13);	// enable linear addressing & set memory size
20835db13eaSAxel Dörfler 
20935db13eaSAxel Dörfler 	WriteCrtcReg(0x31, 0x08);
21035db13eaSAxel Dörfler 	WriteCrtcReg(0x32, 0x00);
21135db13eaSAxel Dörfler 	WriteCrtcReg(0x34, 0x10);
21235db13eaSAxel Dörfler 	WriteCrtcReg(0x3a, 0x15);
21335db13eaSAxel Dörfler 
21435db13eaSAxel Dörfler 	WriteCrtcReg(0x51, mode.bytesPerRow >> 7, 0x30);
21535db13eaSAxel Dörfler 	WriteCrtcReg(0x53, 0x18, 0x18);
21635db13eaSAxel Dörfler 
21735db13eaSAxel Dörfler 	int n = 255;
21835db13eaSAxel Dörfler 	int clock2 = mode.timing.pixel_clock * (mode.bpp / 8);
21935db13eaSAxel Dörfler 	if (videoRamMB < 2)
22035db13eaSAxel Dörfler 		clock2 *= 2;
22135db13eaSAxel Dörfler 	int m = (int)((gInfo.sharedInfo->mclk / 1000.0 * .72 + 16.867) * 89.736
22235db13eaSAxel Dörfler 			/ (clock2 / 1000.0 + 39) - 21.1543);
22335db13eaSAxel Dörfler 	if (videoRamMB < 2)
22435db13eaSAxel Dörfler 		m /= 2;
22535db13eaSAxel Dörfler 	if (m > 31)
22635db13eaSAxel Dörfler 		m = 31;
22735db13eaSAxel Dörfler 	else if (m < 0) {
22835db13eaSAxel Dörfler 		m = 0;
22935db13eaSAxel Dörfler 		n = 16;
23035db13eaSAxel Dörfler 	}
23135db13eaSAxel Dörfler 
23235db13eaSAxel Dörfler 	if (n < 0)
23335db13eaSAxel Dörfler 		n = 0;
23435db13eaSAxel Dörfler 	else if (n > 255)
23535db13eaSAxel Dörfler 		n = 255;
23635db13eaSAxel Dörfler 
23735db13eaSAxel Dörfler 	WriteCrtcReg(0x54, m << 3);
23835db13eaSAxel Dörfler 	WriteCrtcReg(0x60, n);
23935db13eaSAxel Dörfler 
24035db13eaSAxel Dörfler 	WriteCrtcReg(0x42, 0x00, 0x20);		// disable interlace mode
24135db13eaSAxel Dörfler 	WriteCrtcReg(0x66, 0x89, 0x8f);
24235db13eaSAxel Dörfler 
24335db13eaSAxel Dörfler 	WriteReg16(ADVFUNC_CNTL, 0x0001);		// enable enhanced functions
24435db13eaSAxel Dörfler 
24535db13eaSAxel Dörfler 	WriteReg16(SUBSYS_CNTL, 0x8000);		// reset graphics engine
24635db13eaSAxel Dörfler 	WriteReg16(SUBSYS_CNTL, 0x4000);		// enable graphics engine
24735db13eaSAxel Dörfler 	ReadReg16(SUBSYS_STAT);
24835db13eaSAxel Dörfler 
24935db13eaSAxel Dörfler 	WriteReg16(MULTIFUNC_CNTL, 0x5000 | 0x0004 | 0x000c);
25035db13eaSAxel Dörfler 
25135db13eaSAxel Dörfler 	gInfo.WaitQueue(5);
25235db13eaSAxel Dörfler 	WriteReg16(MULTIFUNC_CNTL, SCISSORS_L | 0);
25335db13eaSAxel Dörfler 	WriteReg16(MULTIFUNC_CNTL, SCISSORS_T | 0);
25435db13eaSAxel Dörfler 	WriteReg16(MULTIFUNC_CNTL, SCISSORS_R | (mode.timing.h_display - 1));
25535db13eaSAxel Dörfler 	WriteReg16(MULTIFUNC_CNTL, SCISSORS_B | ((si.maxFrameBufferSize / mode.bytesPerRow) - 1));
25635db13eaSAxel Dörfler 
25735db13eaSAxel Dörfler 	WriteReg32(WRT_MASK, ~0);		// enable all planes
25835db13eaSAxel Dörfler 
25935db13eaSAxel Dörfler 	TRACE("Trio64_ModeInit() exit\n");
26035db13eaSAxel Dörfler 	return true;
26135db13eaSAxel Dörfler }
26235db13eaSAxel Dörfler 
26335db13eaSAxel Dörfler 
26435db13eaSAxel Dörfler bool
Trio64_SetDisplayMode(const DisplayModeEx & mode)26535db13eaSAxel Dörfler Trio64_SetDisplayMode(const DisplayModeEx& mode)
26635db13eaSAxel Dörfler {
26735db13eaSAxel Dörfler 	// The code to actually configure the display.
26835db13eaSAxel Dörfler 	// All the error checking must be done in ProposeDisplayMode(),
26935db13eaSAxel Dörfler 	// and assume that the mode values we get here are acceptable.
27035db13eaSAxel Dörfler 
27135db13eaSAxel Dörfler 	WriteSeqReg(0x01, 0x20, 0x20);		// blank the screen
27235db13eaSAxel Dörfler 
27335db13eaSAxel Dörfler 	if ( ! Trio64_ModeInit(mode)) {
27435db13eaSAxel Dörfler 		TRACE("Trio64_ModeInit() failed\n");
27535db13eaSAxel Dörfler 		return false;
27635db13eaSAxel Dörfler 	}
27735db13eaSAxel Dörfler 
27835db13eaSAxel Dörfler 	Trio64_AdjustFrame(mode);
27935db13eaSAxel Dörfler 
28035db13eaSAxel Dörfler 	WriteSeqReg(0x01, 0x00, 0x20);		// unblank the screen
28135db13eaSAxel Dörfler 
28235db13eaSAxel Dörfler 	return true;
28335db13eaSAxel Dörfler }
28435db13eaSAxel Dörfler 
28535db13eaSAxel Dörfler 
28635db13eaSAxel Dörfler 
28735db13eaSAxel Dörfler void
Trio64_AdjustFrame(const DisplayModeEx & mode)28835db13eaSAxel Dörfler Trio64_AdjustFrame(const DisplayModeEx& mode)
28935db13eaSAxel Dörfler {
29035db13eaSAxel Dörfler 	// Adjust start address in frame buffer.
29135db13eaSAxel Dörfler 
29235db13eaSAxel Dörfler 	int base = (((mode.v_display_start * mode.virtual_width + mode.h_display_start)
29335db13eaSAxel Dörfler 			* (mode.bpp / 8)) >> 2) & ~1;
29435db13eaSAxel Dörfler 	base += gInfo.sharedInfo->frameBufferOffset;
29535db13eaSAxel Dörfler 
29635db13eaSAxel Dörfler 	WriteCrtcReg(0x0c, (base >> 8) & 0xff);
29735db13eaSAxel Dörfler 	WriteCrtcReg(0x0d, base & 0xff);
29835db13eaSAxel Dörfler 	WriteCrtcReg(0x31, base >> 12, 0x30);	// put bits 16-17 in bits 4-5 of CR31
29935db13eaSAxel Dörfler 	WriteCrtcReg(0x51, base >> 18, 0x03);	// put bits 18-19 in bits 0-1 of CR51
30035db13eaSAxel Dörfler }
30135db13eaSAxel Dörfler 
30235db13eaSAxel Dörfler 
30335db13eaSAxel Dörfler void
Trio64_SetIndexedColors(uint count,uint8 first,uint8 * colorData,uint32 flags)30435db13eaSAxel Dörfler Trio64_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
30535db13eaSAxel Dörfler {
30635db13eaSAxel Dörfler 	// Set the indexed color palette for 8-bit color depth mode.
30735db13eaSAxel Dörfler 
30835db13eaSAxel Dörfler 	(void)flags;		// avoid compiler warning for unused arg
30935db13eaSAxel Dörfler 
31035db13eaSAxel Dörfler 	if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
31135db13eaSAxel Dörfler 		return ;
31235db13eaSAxel Dörfler 
31335db13eaSAxel Dörfler 	while (count--) {
31435db13eaSAxel Dörfler 		WriteIndexedColor(first++,	// color index
31535db13eaSAxel Dörfler 			colorData[0] >> 2,		// red
31635db13eaSAxel Dörfler 			colorData[1] >> 2,		// green
31735db13eaSAxel Dörfler 			colorData[2] >> 2);		// blue
31835db13eaSAxel Dörfler 		colorData += 3;
31935db13eaSAxel Dörfler 	}
32035db13eaSAxel Dörfler }
321