1*35db13eaSAxel Dörfler /* 2*35db13eaSAxel Dörfler Haiku S3 Trio64 driver adapted from the X.org S3 driver. 3*35db13eaSAxel Dörfler 4*35db13eaSAxel Dörfler Copyright 2001 Ani Joshi <ajoshi@unixbox.com> 5*35db13eaSAxel Dörfler 6*35db13eaSAxel Dörfler Copyright 2008 Haiku, Inc. All rights reserved. 7*35db13eaSAxel Dörfler Distributed under the terms of the MIT license. 8*35db13eaSAxel Dörfler 9*35db13eaSAxel Dörfler Authors: 10*35db13eaSAxel Dörfler Gerald Zajac 2008 11*35db13eaSAxel Dörfler */ 12*35db13eaSAxel Dörfler 13*35db13eaSAxel Dörfler 14*35db13eaSAxel Dörfler #include "accel.h" 15*35db13eaSAxel Dörfler #include "trio64.h" 16*35db13eaSAxel Dörfler 17*35db13eaSAxel Dörfler 18*35db13eaSAxel Dörfler #define BASE_FREQ 14.31818 // MHz 19*35db13eaSAxel Dörfler 20*35db13eaSAxel Dörfler 21*35db13eaSAxel Dörfler static void 22*35db13eaSAxel Dörfler Trio64_CalcClock(long freq, int min_m, int min_n1, int max_n1, 23*35db13eaSAxel Dörfler int min_n2, int max_n2, long freq_min, long freq_max, 24*35db13eaSAxel Dörfler uint8* mdiv, uint8* ndiv) 25*35db13eaSAxel Dörfler { 26*35db13eaSAxel Dörfler uint8 best_n1 = 18, best_n2 = 2, best_m = 127; 27*35db13eaSAxel Dörfler 28*35db13eaSAxel Dörfler double ffreq = freq / 1000.0 / BASE_FREQ; 29*35db13eaSAxel Dörfler double ffreq_min = freq_min / 1000.0 / BASE_FREQ; 30*35db13eaSAxel Dörfler double ffreq_max = freq_max / 1000.0 / BASE_FREQ; 31*35db13eaSAxel Dörfler 32*35db13eaSAxel Dörfler if (ffreq < ffreq_min / (1 << max_n2)) { 33*35db13eaSAxel Dörfler TRACE("Trio64_CalcClock() invalid frequency %1.3f Mhz [freq >= %1.3f Mhz]\n", 34*35db13eaSAxel Dörfler ffreq*BASE_FREQ, ffreq_min*BASE_FREQ / (1 << max_n2)); 35*35db13eaSAxel Dörfler ffreq = ffreq_min / (1 << max_n2); 36*35db13eaSAxel Dörfler } 37*35db13eaSAxel Dörfler if (ffreq > ffreq_max / (1 << min_n2)) { 38*35db13eaSAxel Dörfler TRACE("Trio64_CalcClock() invalid frequency %1.3f Mhz [freq <= %1.3f Mhz]\n", 39*35db13eaSAxel Dörfler ffreq*BASE_FREQ, ffreq_max*BASE_FREQ / (1 << min_n2)); 40*35db13eaSAxel Dörfler ffreq = ffreq_max / (1 << min_n2); 41*35db13eaSAxel Dörfler } 42*35db13eaSAxel Dörfler 43*35db13eaSAxel Dörfler double best_diff = ffreq; 44*35db13eaSAxel Dörfler 45*35db13eaSAxel Dörfler for (uint8 n2 = min_n2; n2 <= max_n2; n2++) { 46*35db13eaSAxel Dörfler for (uint8 n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) { 47*35db13eaSAxel Dörfler int m = (int)(ffreq * n1 * (1 << n2) + 0.5); 48*35db13eaSAxel Dörfler if (m < min_m + 2 || m > 127 + 2) 49*35db13eaSAxel Dörfler continue; 50*35db13eaSAxel Dörfler 51*35db13eaSAxel Dörfler double div = (double)(m) / (double)(n1); 52*35db13eaSAxel Dörfler if ((div >= ffreq_min) && (div <= ffreq_max)) { 53*35db13eaSAxel Dörfler double diff = ffreq - div / (1 << n2); 54*35db13eaSAxel Dörfler if (diff < 0.0) 55*35db13eaSAxel Dörfler diff = -diff; 56*35db13eaSAxel Dörfler if (diff < best_diff) { 57*35db13eaSAxel Dörfler best_diff = diff; 58*35db13eaSAxel Dörfler best_m = m; 59*35db13eaSAxel Dörfler best_n1 = n1; 60*35db13eaSAxel Dörfler best_n2 = n2; 61*35db13eaSAxel Dörfler } 62*35db13eaSAxel Dörfler } 63*35db13eaSAxel Dörfler } 64*35db13eaSAxel Dörfler } 65*35db13eaSAxel Dörfler 66*35db13eaSAxel Dörfler if (max_n1 == 63) 67*35db13eaSAxel Dörfler *ndiv = (best_n1 - 2) | (best_n2 << 6); 68*35db13eaSAxel Dörfler else 69*35db13eaSAxel Dörfler *ndiv = (best_n1 - 2) | (best_n2 << 5); 70*35db13eaSAxel Dörfler *mdiv = best_m - 2; 71*35db13eaSAxel Dörfler } 72*35db13eaSAxel Dörfler 73*35db13eaSAxel Dörfler 74*35db13eaSAxel Dörfler 75*35db13eaSAxel Dörfler static bool 76*35db13eaSAxel Dörfler Trio64_ModeInit(const DisplayModeEx& mode) 77*35db13eaSAxel Dörfler { 78*35db13eaSAxel Dörfler SharedInfo& si = *gInfo.sharedInfo; 79*35db13eaSAxel Dörfler 80*35db13eaSAxel Dörfler TRACE("Trio64_ModeInit(%d x %d, %d KHz)\n", 81*35db13eaSAxel Dörfler mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock); 82*35db13eaSAxel Dörfler 83*35db13eaSAxel Dörfler uint32 videoRamMB = si.videoMemSize / (1024 * 1024); // MB's of video RAM 84*35db13eaSAxel Dörfler 85*35db13eaSAxel Dörfler WriteCrtcReg(0x38, 0x48); // unlock sys regs 86*35db13eaSAxel Dörfler WriteCrtcReg(0x39, 0xa5); // unlock sys regs 87*35db13eaSAxel Dörfler WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs 88*35db13eaSAxel Dörfler 89*35db13eaSAxel Dörfler WriteCrtcReg(0x45, 0x00, 0x01); // turn off hardware cursor 90*35db13eaSAxel Dörfler 91*35db13eaSAxel Dörfler uint8 sr12, sr13; 92*35db13eaSAxel Dörfler Trio64_CalcClock(mode.timing.pixel_clock, 1, 1, 31, 0, 3, 135000, 270000, 93*35db13eaSAxel Dörfler &sr13, &sr12); 94*35db13eaSAxel Dörfler 95*35db13eaSAxel Dörfler // Set clock registers. 96*35db13eaSAxel Dörfler 97*35db13eaSAxel Dörfler WriteSeqReg(0x12, sr12); 98*35db13eaSAxel Dörfler WriteSeqReg(0x13, sr13); 99*35db13eaSAxel Dörfler 100*35db13eaSAxel Dörfler // Activate clock 101*35db13eaSAxel Dörfler 102*35db13eaSAxel Dörfler uint8 tmp = ReadSeqReg(0x15) & ~0x21; 103*35db13eaSAxel Dörfler WriteSeqReg(0x15, tmp | 0x02); 104*35db13eaSAxel Dörfler WriteSeqReg(0x15, tmp | 0x22); 105*35db13eaSAxel Dörfler WriteSeqReg(0x15, tmp | 0x02); 106*35db13eaSAxel Dörfler 107*35db13eaSAxel Dörfler uint8 cr33 = ReadCrtcReg(0x33) & ~0x28; 108*35db13eaSAxel Dörfler uint8 cr50 = 0; 109*35db13eaSAxel Dörfler uint8 pixmux = 0; 110*35db13eaSAxel Dörfler 111*35db13eaSAxel Dörfler if (si.chipType == S3_TRIO64_V2) 112*35db13eaSAxel Dörfler cr33 |= 0x20; 113*35db13eaSAxel Dörfler 114*35db13eaSAxel Dörfler switch (mode.bpp) { 115*35db13eaSAxel Dörfler case 8: 116*35db13eaSAxel Dörfler break; 117*35db13eaSAxel Dörfler case 15: 118*35db13eaSAxel Dörfler cr33 |= 0x08; 119*35db13eaSAxel Dörfler cr50 = 0x10; 120*35db13eaSAxel Dörfler pixmux = 0x30; 121*35db13eaSAxel Dörfler break; 122*35db13eaSAxel Dörfler case 16: 123*35db13eaSAxel Dörfler cr33 |= 0x08; 124*35db13eaSAxel Dörfler cr50 = 0x10; 125*35db13eaSAxel Dörfler pixmux = 0x50; 126*35db13eaSAxel Dörfler break; 127*35db13eaSAxel Dörfler case 32: 128*35db13eaSAxel Dörfler cr50 = 0x30; 129*35db13eaSAxel Dörfler pixmux = 0xd0; 130*35db13eaSAxel Dörfler break; 131*35db13eaSAxel Dörfler } 132*35db13eaSAxel Dörfler 133*35db13eaSAxel Dörfler bool bEnableAccelFuncs = true; 134*35db13eaSAxel Dörfler 135*35db13eaSAxel Dörfler switch (mode.timing.h_display) { 136*35db13eaSAxel Dörfler case 640: 137*35db13eaSAxel Dörfler cr50 |= 0x40; 138*35db13eaSAxel Dörfler break; 139*35db13eaSAxel Dörfler case 800: 140*35db13eaSAxel Dörfler cr50 |= 0x80; 141*35db13eaSAxel Dörfler break; 142*35db13eaSAxel Dörfler case 1024: 143*35db13eaSAxel Dörfler cr50 |= 0x00; 144*35db13eaSAxel Dörfler break; 145*35db13eaSAxel Dörfler case 1152: 146*35db13eaSAxel Dörfler cr50 |= 0x01; 147*35db13eaSAxel Dörfler break; 148*35db13eaSAxel Dörfler case 1280: 149*35db13eaSAxel Dörfler cr50 |= 0xc0; 150*35db13eaSAxel Dörfler break; 151*35db13eaSAxel Dörfler case 1600: 152*35db13eaSAxel Dörfler cr50 |= 0x81; 153*35db13eaSAxel Dörfler break; 154*35db13eaSAxel Dörfler default: 155*35db13eaSAxel Dörfler bEnableAccelFuncs = false; // use app_server default accel functions 156*35db13eaSAxel Dörfler break; 157*35db13eaSAxel Dörfler } 158*35db13eaSAxel Dörfler 159*35db13eaSAxel Dörfler WriteCrtcReg(0x33, cr33); 160*35db13eaSAxel Dörfler WriteCrtcReg(0x50, cr50); // set number of bits per pixel & display width 161*35db13eaSAxel Dörfler WriteCrtcReg(0x67, pixmux); // set pixel format 162*35db13eaSAxel Dörfler 163*35db13eaSAxel Dörfler WriteSeqReg(0x15, 0x00, 0x10); // turn off pixel multiplex 164*35db13eaSAxel Dörfler WriteSeqReg(0x18, 0x00, 0x80); 165*35db13eaSAxel Dörfler 166*35db13eaSAxel Dörfler // Note that the 2D acceleration (drawing) functions in this accelerant work 167*35db13eaSAxel Dörfler // only with the display widths defined in the above switch statement. For 168*35db13eaSAxel Dörfler // the other widths, the default functions in the app_server will be used. 169*35db13eaSAxel Dörfler 170*35db13eaSAxel Dörfler if (bEnableAccelFuncs) 171*35db13eaSAxel Dörfler { 172*35db13eaSAxel Dörfler gInfo.FillRectangle = Trio64_FillRectangle; 173*35db13eaSAxel Dörfler gInfo.FillSpan = Trio64_FillSpan; 174*35db13eaSAxel Dörfler gInfo.InvertRectangle = Trio64_InvertRectangle; 175*35db13eaSAxel Dörfler gInfo.ScreenToScreenBlit = Trio64_ScreenToScreenBlit; 176*35db13eaSAxel Dörfler } 177*35db13eaSAxel Dörfler else 178*35db13eaSAxel Dörfler { 179*35db13eaSAxel Dörfler gInfo.FillRectangle = NULL; 180*35db13eaSAxel Dörfler gInfo.FillSpan = NULL; 181*35db13eaSAxel Dörfler gInfo.InvertRectangle = NULL; 182*35db13eaSAxel Dörfler gInfo.ScreenToScreenBlit = NULL; 183*35db13eaSAxel Dörfler } 184*35db13eaSAxel Dörfler 185*35db13eaSAxel Dörfler // Set the standard CRTC vga regs. 186*35db13eaSAxel Dörfler 187*35db13eaSAxel Dörfler uint8 crtc[25], cr3b, cr3c, cr5d, cr5e; 188*35db13eaSAxel Dörfler 189*35db13eaSAxel Dörfler InitCrtcTimingValues(mode, (mode.bpp > 8) ? 2 : 1, crtc, cr3b, cr3c, cr5d, cr5e); 190*35db13eaSAxel Dörfler crtc[0x17] = 0xe3; 191*35db13eaSAxel Dörfler 192*35db13eaSAxel Dörfler WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11 193*35db13eaSAxel Dörfler 194*35db13eaSAxel Dörfler for (int k = 0; k < NUM_ELEMENTS(crtc); k++) { 195*35db13eaSAxel Dörfler WriteCrtcReg(k, crtc[k]); 196*35db13eaSAxel Dörfler } 197*35db13eaSAxel Dörfler 198*35db13eaSAxel Dörfler WriteCrtcReg(0x3b, cr3b); 199*35db13eaSAxel Dörfler WriteCrtcReg(0x3c, cr3c); 200*35db13eaSAxel Dörfler WriteCrtcReg(0x5d, cr5d); 201*35db13eaSAxel Dörfler WriteCrtcReg(0x5e, cr5e); 202*35db13eaSAxel Dörfler 203*35db13eaSAxel Dörfler uint8 miscOutReg = 0x2f; 204*35db13eaSAxel Dörfler 205*35db13eaSAxel Dörfler if ( ! (mode.timing.flags & B_POSITIVE_HSYNC)) 206*35db13eaSAxel Dörfler miscOutReg |= 0x40; 207*35db13eaSAxel Dörfler if ( ! (mode.timing.flags & B_POSITIVE_VSYNC)) 208*35db13eaSAxel Dörfler miscOutReg |= 0x80; 209*35db13eaSAxel Dörfler 210*35db13eaSAxel Dörfler WriteMiscOutReg(miscOutReg); 211*35db13eaSAxel Dörfler 212*35db13eaSAxel Dörfler uint8 cr58; 213*35db13eaSAxel Dörfler if (videoRamMB <= 1) 214*35db13eaSAxel Dörfler cr58 = 0x01; 215*35db13eaSAxel Dörfler else if (videoRamMB <= 2) 216*35db13eaSAxel Dörfler cr58 = 0x02; 217*35db13eaSAxel Dörfler else 218*35db13eaSAxel Dörfler cr58 = 0x03; 219*35db13eaSAxel Dörfler 220*35db13eaSAxel Dörfler WriteCrtcReg(0x58, cr58 | 0x10, 0x13); // enable linear addressing & set memory size 221*35db13eaSAxel Dörfler 222*35db13eaSAxel Dörfler WriteCrtcReg(0x31, 0x08); 223*35db13eaSAxel Dörfler WriteCrtcReg(0x32, 0x00); 224*35db13eaSAxel Dörfler WriteCrtcReg(0x34, 0x10); 225*35db13eaSAxel Dörfler WriteCrtcReg(0x3a, 0x15); 226*35db13eaSAxel Dörfler 227*35db13eaSAxel Dörfler WriteCrtcReg(0x51, mode.bytesPerRow >> 7, 0x30); 228*35db13eaSAxel Dörfler WriteCrtcReg(0x53, 0x18, 0x18); 229*35db13eaSAxel Dörfler 230*35db13eaSAxel Dörfler int n = 255; 231*35db13eaSAxel Dörfler int clock2 = mode.timing.pixel_clock * (mode.bpp / 8); 232*35db13eaSAxel Dörfler if (videoRamMB < 2) 233*35db13eaSAxel Dörfler clock2 *= 2; 234*35db13eaSAxel Dörfler int m = (int)((gInfo.sharedInfo->mclk / 1000.0 * .72 + 16.867) * 89.736 235*35db13eaSAxel Dörfler / (clock2 / 1000.0 + 39) - 21.1543); 236*35db13eaSAxel Dörfler if (videoRamMB < 2) 237*35db13eaSAxel Dörfler m /= 2; 238*35db13eaSAxel Dörfler if (m > 31) 239*35db13eaSAxel Dörfler m = 31; 240*35db13eaSAxel Dörfler else if (m < 0) { 241*35db13eaSAxel Dörfler m = 0; 242*35db13eaSAxel Dörfler n = 16; 243*35db13eaSAxel Dörfler } 244*35db13eaSAxel Dörfler 245*35db13eaSAxel Dörfler if (n < 0) 246*35db13eaSAxel Dörfler n = 0; 247*35db13eaSAxel Dörfler else if (n > 255) 248*35db13eaSAxel Dörfler n = 255; 249*35db13eaSAxel Dörfler 250*35db13eaSAxel Dörfler WriteCrtcReg(0x54, m << 3); 251*35db13eaSAxel Dörfler WriteCrtcReg(0x60, n); 252*35db13eaSAxel Dörfler 253*35db13eaSAxel Dörfler WriteCrtcReg(0x42, 0x00, 0x20); // disable interlace mode 254*35db13eaSAxel Dörfler WriteCrtcReg(0x66, 0x89, 0x8f); 255*35db13eaSAxel Dörfler 256*35db13eaSAxel Dörfler WriteReg16(ADVFUNC_CNTL, 0x0001); // enable enhanced functions 257*35db13eaSAxel Dörfler 258*35db13eaSAxel Dörfler WriteReg16(SUBSYS_CNTL, 0x8000); // reset graphics engine 259*35db13eaSAxel Dörfler WriteReg16(SUBSYS_CNTL, 0x4000); // enable graphics engine 260*35db13eaSAxel Dörfler ReadReg16(SUBSYS_STAT); 261*35db13eaSAxel Dörfler 262*35db13eaSAxel Dörfler WriteReg16(MULTIFUNC_CNTL, 0x5000 | 0x0004 | 0x000c); 263*35db13eaSAxel Dörfler 264*35db13eaSAxel Dörfler gInfo.WaitQueue(5); 265*35db13eaSAxel Dörfler WriteReg16(MULTIFUNC_CNTL, SCISSORS_L | 0); 266*35db13eaSAxel Dörfler WriteReg16(MULTIFUNC_CNTL, SCISSORS_T | 0); 267*35db13eaSAxel Dörfler WriteReg16(MULTIFUNC_CNTL, SCISSORS_R | (mode.timing.h_display - 1)); 268*35db13eaSAxel Dörfler WriteReg16(MULTIFUNC_CNTL, SCISSORS_B | ((si.maxFrameBufferSize / mode.bytesPerRow) - 1)); 269*35db13eaSAxel Dörfler 270*35db13eaSAxel Dörfler WriteReg32(WRT_MASK, ~0); // enable all planes 271*35db13eaSAxel Dörfler 272*35db13eaSAxel Dörfler TRACE("Trio64_ModeInit() exit\n"); 273*35db13eaSAxel Dörfler return true; 274*35db13eaSAxel Dörfler } 275*35db13eaSAxel Dörfler 276*35db13eaSAxel Dörfler 277*35db13eaSAxel Dörfler bool 278*35db13eaSAxel Dörfler Trio64_SetDisplayMode(const DisplayModeEx& mode) 279*35db13eaSAxel Dörfler { 280*35db13eaSAxel Dörfler // The code to actually configure the display. 281*35db13eaSAxel Dörfler // All the error checking must be done in ProposeDisplayMode(), 282*35db13eaSAxel Dörfler // and assume that the mode values we get here are acceptable. 283*35db13eaSAxel Dörfler 284*35db13eaSAxel Dörfler WriteSeqReg(0x01, 0x20, 0x20); // blank the screen 285*35db13eaSAxel Dörfler 286*35db13eaSAxel Dörfler if ( ! Trio64_ModeInit(mode)) { 287*35db13eaSAxel Dörfler TRACE("Trio64_ModeInit() failed\n"); 288*35db13eaSAxel Dörfler return false; 289*35db13eaSAxel Dörfler } 290*35db13eaSAxel Dörfler 291*35db13eaSAxel Dörfler Trio64_AdjustFrame(mode); 292*35db13eaSAxel Dörfler 293*35db13eaSAxel Dörfler WriteSeqReg(0x01, 0x00, 0x20); // unblank the screen 294*35db13eaSAxel Dörfler 295*35db13eaSAxel Dörfler return true; 296*35db13eaSAxel Dörfler } 297*35db13eaSAxel Dörfler 298*35db13eaSAxel Dörfler 299*35db13eaSAxel Dörfler 300*35db13eaSAxel Dörfler void 301*35db13eaSAxel Dörfler Trio64_AdjustFrame(const DisplayModeEx& mode) 302*35db13eaSAxel Dörfler { 303*35db13eaSAxel Dörfler // Adjust start address in frame buffer. 304*35db13eaSAxel Dörfler 305*35db13eaSAxel Dörfler int base = (((mode.v_display_start * mode.virtual_width + mode.h_display_start) 306*35db13eaSAxel Dörfler * (mode.bpp / 8)) >> 2) & ~1; 307*35db13eaSAxel Dörfler base += gInfo.sharedInfo->frameBufferOffset; 308*35db13eaSAxel Dörfler 309*35db13eaSAxel Dörfler WriteCrtcReg(0x0c, (base >> 8) & 0xff); 310*35db13eaSAxel Dörfler WriteCrtcReg(0x0d, base & 0xff); 311*35db13eaSAxel Dörfler WriteCrtcReg(0x31, base >> 12, 0x30); // put bits 16-17 in bits 4-5 of CR31 312*35db13eaSAxel Dörfler WriteCrtcReg(0x51, base >> 18, 0x03); // put bits 18-19 in bits 0-1 of CR51 313*35db13eaSAxel Dörfler } 314*35db13eaSAxel Dörfler 315*35db13eaSAxel Dörfler 316*35db13eaSAxel Dörfler void 317*35db13eaSAxel Dörfler Trio64_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags) 318*35db13eaSAxel Dörfler { 319*35db13eaSAxel Dörfler // Set the indexed color palette for 8-bit color depth mode. 320*35db13eaSAxel Dörfler 321*35db13eaSAxel Dörfler (void)flags; // avoid compiler warning for unused arg 322*35db13eaSAxel Dörfler 323*35db13eaSAxel Dörfler if (gInfo.sharedInfo->displayMode.space != B_CMAP8) 324*35db13eaSAxel Dörfler return ; 325*35db13eaSAxel Dörfler 326*35db13eaSAxel Dörfler while (count--) { 327*35db13eaSAxel Dörfler WriteIndexedColor(first++, // color index 328*35db13eaSAxel Dörfler colorData[0] >> 2, // red 329*35db13eaSAxel Dörfler colorData[1] >> 2, // green 330*35db13eaSAxel Dörfler colorData[2] >> 2); // blue 331*35db13eaSAxel Dörfler colorData += 3; 332*35db13eaSAxel Dörfler } 333*35db13eaSAxel Dörfler } 334