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