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