1 /* 2 Haiku ATI video driver adapted from the X.org ATI driver. 3 4 Copyright 1992,1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Carolina. 5 Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org 6 7 Copyright 2009 Haiku, Inc. All rights reserved. 8 Distributed under the terms of the MIT license. 9 10 Authors: 11 Gerald Zajac 2009 12 */ 13 14 15 #include "accelerant.h" 16 #include "mach64.h" 17 18 #include <unistd.h> 19 20 21 22 23 static void SetClockRegisters(const DisplayModeEx& mode) 24 { 25 SharedInfo& si = *gInfo.sharedInfo; 26 M64_Params& params = si.m64Params; 27 28 int p; 29 int postDiv; 30 bool extendedDiv = false; 31 uint32 pixelClock = mode.timing.pixel_clock; 32 33 if (pixelClock > params.maxPixelClock) 34 pixelClock = params.maxPixelClock; 35 36 double q = ((pixelClock / 10.0) * params.refDivider) / (2.0 * params.refFreq); 37 38 if (si.chipType >= MACH64_264VTB) { 39 if (q > 255) { 40 TRACE("SetClockRegisters(): Warning: q > 255\n"); 41 q = 255; 42 p = 0; 43 postDiv = 1; 44 } else if (q > 127.5) { 45 p = 0; 46 postDiv = 1; 47 } else if (q > 85) { 48 p = 1; 49 postDiv = 2; 50 } else if (q > 63.75) { 51 p = 0; 52 postDiv = 3; 53 extendedDiv = true; 54 } else if (q > 42.5) { 55 p = 2; 56 postDiv = 4; 57 } else if (q > 31.875) { 58 p = 2; 59 postDiv = 6; 60 extendedDiv = true; 61 } else if (q > 21.25) { 62 p = 3; 63 postDiv = 8; 64 } else if (q >= 10.6666666667) { 65 p = 3; 66 postDiv = 12; 67 extendedDiv = true; 68 } else { 69 TRACE("SetClockRegisters(): Warning: q < 10.66666667\n"); 70 p = 3; 71 postDiv = 12; 72 extendedDiv = true; 73 } 74 } else { 75 if (q > 255) { 76 TRACE("SetClockRegisters(): Warning: q > 255\n"); 77 q = 255; 78 p = 0; 79 } else if (q > 127.5) 80 p = 0; 81 else if (q > 63.75) 82 p = 1; 83 else if (q > 31.875) 84 p = 2; 85 else if (q >= 16) 86 p = 3; 87 else { 88 TRACE("SetClockRegisters(): Warning: q < 16\n"); 89 p = 3; 90 } 91 postDiv = 1 << p; 92 } 93 94 uint8 fbDiv = uint8(q * postDiv); 95 96 // With some chips such as those with ID's 4750 & 475A, the display has 97 // ripples when using resolution 1440x900 at 60 Hz refresh rate. 98 // Decrementing fbDiv by 1 seems to fix this problem. 99 100 if (mode.timing.h_display == 1440 && pixelClock < 108000) 101 fbDiv--; 102 103 int clkNum = params.clockNumberToProgram; 104 105 OUTREG8(CLOCK_CNTL, clkNum | CLOCK_STROBE); 106 107 // Temporarily switch to accelerator mode. 108 uint32 crtc_gen_cntl = INREG(CRTC_GEN_CNTL); 109 if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) 110 OUTREG(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN); 111 112 // Reset VCLK generator. 113 uint8 vclkCntl = Mach64_GetPLLReg(PLL_VCLK_CNTL); 114 Mach64_SetPLLReg(PLL_VCLK_CNTL, vclkCntl | PLL_VCLK_RESET); 115 116 // Set post-divider. 117 uint8 tmp = Mach64_GetPLLReg(PLL_VCLK_POST_DIV); 118 Mach64_SetPLLReg(PLL_VCLK_POST_DIV, 119 (tmp & ~(0x03 << (2 * clkNum))) | (p << (2 * clkNum))); 120 121 // Set feedback divider. 122 Mach64_SetPLLReg(PLL_VCLK0_FB_DIV + clkNum, fbDiv); 123 124 // Set extended post-divider. 125 if (si.chipType >= MACH64_264VTB) { 126 tmp = Mach64_GetPLLReg(PLL_XCLK_CNTL); 127 if (extendedDiv) 128 Mach64_SetPLLReg(PLL_XCLK_CNTL, tmp | (0x10 << clkNum)); 129 else 130 Mach64_SetPLLReg(PLL_XCLK_CNTL, tmp & ~(0x10 << clkNum)); 131 } 132 133 // End VCLK generator reset. 134 Mach64_SetPLLReg(PLL_VCLK_CNTL, vclkCntl & ~PLL_VCLK_RESET); 135 136 snooze(5000); 137 INREG8(DAC_W_INDEX); // Clear DAC counter 138 139 if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) 140 OUTREG(CRTC_GEN_CNTL, crtc_gen_cntl); // Restore register 141 142 // Save parameters that will be used for computing the DSP parameters. 143 144 params.vClkPostDivider = postDiv; 145 params.vClkFeedbackDivider = fbDiv; 146 147 return; 148 } 149 150 151 static void 152 SetDSPRegisters(const DisplayModeEx& mode) 153 { 154 // Set up DSP register values for a VTB or later. 155 156 SharedInfo& si = *gInfo.sharedInfo; 157 M64_Params& params = si.m64Params; 158 159 #define Maximum_DSP_PRECISION 7 160 161 uint8 mClkFeedbackDivider = Mach64_GetPLLReg(PLL_MCLK_FB_DIV); 162 163 /* Compute a memory-to-screen bandwidth ratio */ 164 uint32 multiplier = uint32(mClkFeedbackDivider) * params.vClkPostDivider; 165 uint32 divider = uint32(params.vClkFeedbackDivider) * params.xClkRefDivider; 166 divider *= ((mode.bitsPerPixel + 1) / 4); 167 168 // Start by assuming a display FIFO width of 64 bits. 169 170 int vshift = (6 - 2) - params.xClkPostDivider; 171 172 int RASMultiplier = params.xClkMaxRASDelay; 173 int RASDivider = 1; 174 175 // Determine dsp_precision first. 176 177 int tmp = Mach64_Divide(multiplier * params.displayFIFODepth, divider, vshift, -1); 178 int dsp_precision; 179 180 for (dsp_precision = -5; tmp; dsp_precision++) 181 tmp >>= 1; 182 if (dsp_precision < 0) 183 dsp_precision = 0; 184 else if (dsp_precision > Maximum_DSP_PRECISION) 185 dsp_precision = Maximum_DSP_PRECISION; 186 187 int xshift = 6 - dsp_precision; 188 vshift += xshift; 189 190 int dsp_off = Mach64_Divide(multiplier * (params.displayFIFODepth - 1), 191 divider, vshift, -1) - Mach64_Divide(1, 1, vshift - xshift, 1); 192 193 int dsp_on = Mach64_Divide(multiplier, divider, vshift, 1); 194 tmp = Mach64_Divide(RASMultiplier, RASDivider, xshift, 1); 195 if (dsp_on < tmp) 196 dsp_on = tmp; 197 dsp_on += (tmp * 2) + 198 Mach64_Divide(params.xClkPageFaultDelay, 1, xshift, 1); 199 200 /* Calculate rounding factor and apply it to dsp_on */ 201 tmp = ((1 << (Maximum_DSP_PRECISION - dsp_precision)) - 1) >> 1; 202 dsp_on = ((dsp_on + tmp) / (tmp + 1)) * (tmp + 1); 203 204 if (dsp_on >= ((dsp_off / (tmp + 1)) * (tmp + 1))) { 205 dsp_on = dsp_off - Mach64_Divide(multiplier, divider, vshift, -1); 206 dsp_on = (dsp_on / (tmp + 1)) * (tmp + 1); 207 } 208 209 int dsp_xclks = Mach64_Divide(multiplier, divider, vshift + 5, 1); 210 211 // Build DSP register contents. 212 213 uint32 dsp_on_off = SetBits(dsp_on, DSP_ON) 214 | SetBits(dsp_off, DSP_OFF); 215 uint32 dsp_config = SetBits(dsp_precision, DSP_PRECISION) 216 | SetBits(dsp_xclks, DSP_XCLKS_PER_QW) 217 | SetBits(params.displayLoopLatency, DSP_LOOP_LATENCY); 218 219 OUTREG(DSP_ON_OFF, dsp_on_off); 220 OUTREG(DSP_CONFIG, dsp_config); 221 } 222 223 224 static void 225 SetCrtcRegisters(const DisplayModeEx& mode) 226 { 227 // Calculate the CRTC register values for requested video mode, and then set 228 // set the registers to the calculated values. 229 230 SharedInfo& si = *gInfo.sharedInfo; 231 232 uint32 crtc_h_total_disp = ((mode.timing.h_total / 8) - 1) 233 | (((mode.timing.h_display / 8) - 1) << 16); 234 235 int hSyncWidth = (mode.timing.h_sync_end - mode.timing.h_sync_start) / 8; 236 if (hSyncWidth > 0x3f) 237 hSyncWidth = 0x3f; 238 239 int hSyncStart = mode.timing.h_sync_start / 8 - 1; 240 241 uint32 crtc_h_sync_strt_wid = (hSyncWidth << 16) 242 | (hSyncStart & 0xff) | ((hSyncStart & 0x100) << 4) 243 | ((mode.timing.flags & B_POSITIVE_HSYNC) ? 0 : CRTC_H_SYNC_NEG); 244 245 uint32 crtc_v_total_disp = ((mode.timing.v_total - 1) 246 | ((mode.timing.v_display - 1) << 16)); 247 248 int vSyncWidth = mode.timing.v_sync_end - mode.timing.v_sync_start; 249 if (vSyncWidth > 0x1f) 250 vSyncWidth = 0x1f; 251 252 uint32 crtc_v_sync_strt_wid = (mode.timing.v_sync_start - 1) 253 | (vSyncWidth << 16) 254 | ((mode.timing.flags & B_POSITIVE_VSYNC) ? 0 : CRTC_V_SYNC_NEG); 255 256 uint32 crtc_off_pitch = SetBits(mode.timing.h_display >> 3, CRTC_PITCH); 257 258 uint32 crtc_gen_cntl = INREG(CRTC_GEN_CNTL) & 259 ~(CRTC_DBL_SCAN_EN | CRTC_INTERLACE_EN | 260 CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_CSYNC_EN | 261 CRTC_PIX_BY_2_EN | CRTC_VGA_XOVERSCAN | 262 CRTC_PIX_WIDTH | CRTC_BYTE_PIX_ORDER | 263 CRTC_VGA_128KAP_PAGING | CRTC_VFC_SYNC_TRISTATE | 264 CRTC_LOCK_REGS | // already off, but ... 265 CRTC_SYNC_TRISTATE | CRTC_DISP_REQ_EN | 266 CRTC_VGA_TEXT_132 | CRTC_CUR_B_TEST); 267 268 crtc_gen_cntl |= CRTC_EXT_DISP_EN | CRTC_EN | CRTC_VGA_LINEAR | CRTC_CNT_EN; 269 270 switch (mode.bitsPerPixel) { 271 case 8: 272 crtc_gen_cntl |= CRTC_PIX_WIDTH_8BPP; 273 break; 274 case 15: 275 crtc_gen_cntl |= CRTC_PIX_WIDTH_15BPP; 276 break; 277 case 16: 278 crtc_gen_cntl |= CRTC_PIX_WIDTH_16BPP; 279 break; 280 case 32: 281 crtc_gen_cntl |= CRTC_PIX_WIDTH_32BPP; 282 break; 283 default: 284 TRACE("Undefined color depth, bitsPerPixel: %d\n", mode.bitsPerPixel); 285 break; 286 } 287 288 // For now, set display FIFO low water mark as high as possible. 289 if (si.chipType < MACH64_264VTB) 290 crtc_gen_cntl |= CRTC_FIFO_LWM; 291 292 293 // Write the CRTC registers. 294 //-------------------------- 295 296 // Stop CRTC. 297 OUTREG(CRTC_GEN_CNTL, crtc_gen_cntl & ~(CRTC_EXT_DISP_EN | CRTC_EN)); 298 299 OUTREG(CRTC_H_TOTAL_DISP, crtc_h_total_disp); 300 OUTREG(CRTC_H_SYNC_STRT_WID, crtc_h_sync_strt_wid); 301 OUTREG(CRTC_V_TOTAL_DISP, crtc_v_total_disp); 302 OUTREG(CRTC_V_SYNC_STRT_WID, crtc_v_sync_strt_wid); 303 304 OUTREG(CRTC_OFF_PITCH, crtc_off_pitch); 305 306 // Clear overscan registers. 307 OUTREG(OVR_CLR, 0); 308 OUTREG(OVR_WID_LEFT_RIGHT, 0); 309 OUTREG(OVR_WID_TOP_BOTTOM, 0); 310 311 // Finalise CRTC setup and turn on the screen. 312 OUTREG(CRTC_GEN_CNTL, crtc_gen_cntl); 313 314 return; 315 } 316 317 318 319 status_t 320 Mach64_SetDisplayMode(const DisplayModeEx& mode) 321 { 322 // The code to actually configure the display. 323 // All the error checking must be done in ProposeDisplayMode(), 324 // and assume that the mode values we get here are acceptable. 325 326 SharedInfo& si = *gInfo.sharedInfo; 327 328 if (si.displayType == MT_VGA) { 329 // Chip is connected to a monitor via a VGA connector. 330 331 SetCrtcRegisters(mode); 332 SetClockRegisters(mode); 333 334 if (si.chipType >= MACH64_264VTB) 335 SetDSPRegisters(mode); 336 337 } else { 338 // Chip is connected to a laptop LCD monitor; or via a DVI interface. 339 340 uint16 vesaMode = GetVesaModeNumber(display_mode(mode), mode.bitsPerPixel); 341 if (vesaMode == 0) 342 return B_BAD_VALUE; 343 344 status_t status = ioctl(gInfo.deviceFileDesc, ATI_SET_VESA_DISPLAY_MODE, 345 &vesaMode, sizeof(vesaMode)); 346 if (status != B_OK) 347 return status; 348 } 349 350 Mach64_AdjustFrame(mode); 351 352 // Initialize the palette so that the various color depths will display 353 // the correct colors. 354 355 OUTREGM(DAC_CNTL, DAC_8BIT_EN, DAC_8BIT_EN); 356 OUTREG8(DAC_MASK, 0xff); 357 OUTREG8(DAC_W_INDEX, 0); // initial color index 358 359 for (int i = 0; i < 256; i++) { 360 OUTREG8(DAC_DATA, i); 361 OUTREG8(DAC_DATA, i); 362 OUTREG8(DAC_DATA, i); 363 } 364 365 Mach64_EngineInit(mode); 366 367 return B_OK; 368 } 369 370 371 372 void 373 Mach64_AdjustFrame(const DisplayModeEx& mode) 374 { 375 // Adjust start address in frame buffer. 376 377 SharedInfo& si = *gInfo.sharedInfo; 378 379 int address = (mode.v_display_start * mode.virtual_width 380 + mode.h_display_start) * ((mode.bitsPerPixel + 1) / 8); 381 382 address &= ~0x07; 383 address += si.frameBufferOffset; 384 385 OUTREGM(CRTC_OFF_PITCH, address, 0xfffff); 386 return; 387 } 388 389 390 void 391 Mach64_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags) 392 { 393 // Set the indexed color palette for 8-bit color depth mode. 394 395 (void)flags; // avoid compiler warning for unused arg 396 397 if (gInfo.sharedInfo->displayMode.space != B_CMAP8) 398 return ; 399 400 OUTREG8(DAC_MASK, 0xff); 401 OUTREG8(DAC_W_INDEX, first); // initial color index 402 403 while (count--) { 404 OUTREG8(DAC_DATA, colorData[0]); // red 405 OUTREG8(DAC_DATA, colorData[1]); // green 406 OUTREG8(DAC_DATA, colorData[2]); // blue 407 408 colorData += 3; 409 } 410 } 411