1 /* 2 Haiku ATI video driver adapted from the X.org ATI driver. 3 4 Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, 5 Precision Insight, Inc., Cedar Park, Texas, and 6 VA Linux Systems Inc., Fremont, California. 7 8 Copyright 2009 Haiku, Inc. All rights reserved. 9 Distributed under the terms of the MIT license. 10 11 Authors: 12 Gerald Zajac 2009 13 */ 14 15 16 #include "accelerant.h" 17 #include "rage128.h" 18 19 #include <unistd.h> 20 21 22 struct DisplayParams { 23 // CRTC registers 24 uint32 crtc_gen_cntl; 25 uint32 crtc_h_total_disp; 26 uint32 crtc_h_sync_strt_wid; 27 uint32 crtc_v_total_disp; 28 uint32 crtc_v_sync_strt_wid; 29 uint32 crtc_pitch; 30 31 // DDA register 32 uint32 dda_config; 33 uint32 dda_on_off; 34 35 // Computed PLL values 36 int feedback_div; 37 int post_div; 38 39 // PLL registers 40 uint32 ppll_ref_div; 41 uint32 ppll_div_3; 42 }; 43 44 45 46 static inline int 47 DivideWithRounding(int n, int d) 48 { 49 return (n + (d / 2)) / d; // compute n/d with rounding 50 } 51 52 53 static int 54 MinimumBits(uint32 value) 55 { 56 // Compute minimum number of bits required to contain a value (ie, log 57 // base 2 of value). 58 59 if (value == 0) 60 return 1; 61 62 int numBits = 0; 63 64 while (value != 0) { 65 value >>= 1; 66 numBits++; 67 } 68 69 return numBits; 70 } 71 72 73 static bool 74 CalculateCrtcRegisters(const DisplayModeEx& mode, DisplayParams& params) 75 { 76 // Define CRTC registers for requested video mode. 77 // Return true if successful. 78 79 const uint8 hSyncFudge[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; 80 81 uint32 format; 82 83 switch (mode.bitsPerPixel) { 84 case 8: 85 format = 2; 86 break; 87 case 15: 88 format = 3; // 555 89 break; 90 case 16: 91 format = 4; // 565 92 break; 93 case 32: 94 format = 6; // xRGB 95 break; 96 default: 97 TRACE("Unsupported color depth: %d bits/pixel\n", mode.bitsPerPixel); 98 return false; 99 } 100 101 params.crtc_gen_cntl = (R128_CRTC_EXT_DISP_EN 102 | R128_CRTC_EN 103 | (format << 8)); 104 105 params.crtc_h_total_disp = (((mode.timing.h_total / 8) - 1) & 0xffff) 106 | (((mode.timing.h_display / 8) - 1) << 16); 107 108 int hSyncWidth = (mode.timing.h_sync_end - mode.timing.h_sync_start) / 8; 109 if (hSyncWidth <= 0) 110 hSyncWidth = 1; 111 if (hSyncWidth > 0x3f) 112 hSyncWidth = 0x3f; 113 114 int hSyncStart = mode.timing.h_sync_start - 8 + hSyncFudge[format - 1]; 115 116 params.crtc_h_sync_strt_wid = (hSyncStart & 0xfff) | (hSyncWidth << 16) 117 | ((mode.timing.flags & B_POSITIVE_HSYNC) ? 0 : R128_CRTC_H_SYNC_POL); 118 119 params.crtc_v_total_disp = (((mode.timing.v_total - 1) & 0xffff) 120 | ((mode.timing.v_display - 1) << 16)); 121 122 int vSyncWidth = mode.timing.v_sync_end - mode.timing.v_sync_start; 123 if (vSyncWidth <= 0) 124 vSyncWidth = 1; 125 if (vSyncWidth > 0x1f) 126 vSyncWidth = 0x1f; 127 128 params.crtc_v_sync_strt_wid = ((mode.timing.v_sync_start - 1) & 0xfff) 129 | (vSyncWidth << 16) 130 | ((mode.timing.flags & B_POSITIVE_VSYNC) ? 0 : R128_CRTC_V_SYNC_POL); 131 132 params.crtc_pitch = mode.timing.h_display / 8; 133 134 return true; 135 } 136 137 138 static bool 139 CalculateDDARegisters(const DisplayModeEx& mode, DisplayParams& params) 140 { 141 // Compute and write DDA registers for requested video mode. 142 // Return true if successful. 143 144 SharedInfo& si = *gInfo.sharedInfo; 145 R128_RAMSpec& memSpec = si.r128MemSpec; 146 R128_PLLParams& pll = si.r128PLLParams; 147 148 int displayFifoWidth = 128; 149 int displayFifoDepth = 32; 150 int xClkFreq = pll.xclk; 151 152 int vClkFreq = DivideWithRounding(pll.reference_freq * params.feedback_div, 153 pll.reference_div * params.post_div); 154 155 int bytesPerPixel = (mode.bitsPerPixel + 7) / 8; 156 157 int xClksPerTransfer = DivideWithRounding(xClkFreq * displayFifoWidth, 158 vClkFreq * bytesPerPixel * 8); 159 160 int useablePrecision = MinimumBits(xClksPerTransfer) + 1; 161 162 int xClksPerTransferPrecise = DivideWithRounding( 163 (xClkFreq * displayFifoWidth) << (11 - useablePrecision), 164 vClkFreq * bytesPerPixel * 8); 165 166 int rOff = xClksPerTransferPrecise * (displayFifoDepth - 4); 167 168 int rOn = (4 * memSpec.memBurstLen 169 + 3 * MAX(memSpec.rasToCasDelay - 2, 0) 170 + 2 * memSpec.rasPercentage 171 + memSpec.writeRecovery 172 + memSpec.casLatency 173 + memSpec.readToWriteDelay 174 + xClksPerTransfer) << (11 - useablePrecision); 175 176 if (rOn + memSpec.loopLatency >= rOff) { 177 TRACE("Error: (rOn = %d) + (loopLatency = %d) >= (rOff = %d)\n", 178 rOn, memSpec.loopLatency, rOff); 179 return false; 180 } 181 182 params.dda_config = xClksPerTransferPrecise | (useablePrecision << 16) 183 | (memSpec.loopLatency << 20); 184 params.dda_on_off = (rOn << 16) | rOff; 185 186 return true; 187 } 188 189 190 static bool 191 CalculatePLLRegisters(const DisplayModeEx& mode, DisplayParams& params) 192 { 193 // Define PLL registers for requested video mode. 194 195 struct Divider { 196 int divider; 197 int bitValue; 198 }; 199 200 // The following data is from RAGE 128 VR/RAGE 128 GL Register Reference 201 // Manual (Technical Reference Manual P/N RRG-G04100-C Rev. 0.04), page 202 // 3-17 (PLL_DIV_[3:0]). 203 204 const Divider postDividers[] = { 205 { 1, 0 }, // VCLK_SRC 206 { 2, 1 }, // VCLK_SRC/2 207 { 4, 2 }, // VCLK_SRC/4 208 { 8, 3 }, // VCLK_SRC/8 209 { 3, 4 }, // VCLK_SRC/3 210 // bitValue = 5 is reserved 211 { 6, 6 }, // VCLK_SRC/6 212 { 12, 7 } // VCLK_SRC/12 213 }; 214 215 R128_PLLParams& pll = gInfo.sharedInfo->r128PLLParams; 216 uint32 freq = mode.timing.pixel_clock / 10; 217 218 if (freq > pll.max_pll_freq) 219 freq = pll.max_pll_freq; 220 if (freq * 12 < pll.min_pll_freq) 221 freq = pll.min_pll_freq / 12; 222 223 int bitValue = -1; 224 uint32 output_freq; 225 226 for (int j = 0; j < (int)B_COUNT_OF(postDividers); j++) { 227 output_freq = postDividers[j].divider * freq; 228 if (output_freq >= pll.min_pll_freq && output_freq <= pll.max_pll_freq) { 229 params.feedback_div = DivideWithRounding(pll.reference_div * output_freq, 230 pll.reference_freq); 231 params.post_div = postDividers[j].divider; 232 bitValue = postDividers[j].bitValue; 233 break; 234 } 235 } 236 237 if (bitValue < 0) { 238 TRACE("CalculatePLLRegisters(), acceptable divider not found\n"); 239 return false; 240 } 241 242 params.ppll_ref_div = pll.reference_div; 243 params.ppll_div_3 = (params.feedback_div | (bitValue << 16)); 244 245 return true; 246 } 247 248 249 static void 250 PLLWaitForReadUpdateComplete() 251 { 252 while (GetPLLReg(R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R) 253 ; 254 } 255 256 static void 257 PLLWriteUpdate() 258 { 259 PLLWaitForReadUpdateComplete(); 260 261 SetPLLReg(R128_PPLL_REF_DIV, R128_PPLL_ATOMIC_UPDATE_W, R128_PPLL_ATOMIC_UPDATE_W); 262 } 263 264 265 static void 266 SetRegisters(DisplayParams& params) 267 { 268 // Write the common registers (most will be set to zero). 269 //------------------------------------------------------- 270 271 OUTREGM(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, R128_FP_BLANK_DIS); 272 273 OUTREG(R128_OVR_CLR, 0); 274 OUTREG(R128_OVR_WID_LEFT_RIGHT, 0); 275 OUTREG(R128_OVR_WID_TOP_BOTTOM, 0); 276 OUTREG(R128_OV0_SCALE_CNTL, 0); 277 OUTREG(R128_MPP_TB_CONFIG, 0); 278 OUTREG(R128_MPP_GP_CONFIG, 0); 279 OUTREG(R128_SUBPIC_CNTL, 0); 280 OUTREG(R128_VIPH_CONTROL, 0); 281 OUTREG(R128_I2C_CNTL_1, 0); 282 OUTREG(R128_GEN_INT_CNTL, 0); 283 OUTREG(R128_CAP0_TRIG_CNTL, 0); 284 OUTREG(R128_CAP1_TRIG_CNTL, 0); 285 286 // If bursts are enabled, turn on discards and aborts. 287 288 uint32 busCntl = INREG(R128_BUS_CNTL); 289 if (busCntl & (R128_BUS_WRT_BURST | R128_BUS_READ_BURST)) { 290 busCntl |= R128_BUS_RD_DISCARD_EN | R128_BUS_RD_ABORT_EN; 291 OUTREG(R128_BUS_CNTL, busCntl); 292 } 293 294 // Write the DDA registers. 295 //------------------------- 296 297 OUTREG(R128_DDA_CONFIG, params.dda_config); 298 OUTREG(R128_DDA_ON_OFF, params.dda_on_off); 299 300 // Write the CRTC registers. 301 //-------------------------- 302 303 OUTREG(R128_CRTC_GEN_CNTL, params.crtc_gen_cntl); 304 305 OUTREGM(R128_DAC_CNTL, R128_DAC_MASK_ALL | R128_DAC_8BIT_EN, 306 ~(R128_DAC_RANGE_CNTL | R128_DAC_BLANKING)); 307 308 OUTREG(R128_CRTC_H_TOTAL_DISP, params.crtc_h_total_disp); 309 OUTREG(R128_CRTC_H_SYNC_STRT_WID, params.crtc_h_sync_strt_wid); 310 OUTREG(R128_CRTC_V_TOTAL_DISP, params.crtc_v_total_disp); 311 OUTREG(R128_CRTC_V_SYNC_STRT_WID, params.crtc_v_sync_strt_wid); 312 OUTREG(R128_CRTC_OFFSET, 0); 313 OUTREG(R128_CRTC_OFFSET_CNTL, 0); 314 OUTREG(R128_CRTC_PITCH, params.crtc_pitch); 315 316 // Write the PLL registers. 317 //------------------------- 318 319 OUTREGM(R128_CLOCK_CNTL_INDEX, R128_PLL_DIV_SEL, R128_PLL_DIV_SEL); 320 321 SetPLLReg(R128_VCLK_ECP_CNTL, R128_VCLK_SRC_SEL_CPUCLK, R128_VCLK_SRC_SEL_MASK); 322 323 SetPLLReg(R128_PPLL_CNTL, 0xffffffff, 324 R128_PPLL_RESET | R128_PPLL_ATOMIC_UPDATE_EN | R128_PPLL_VGA_ATOMIC_UPDATE_EN); 325 326 PLLWaitForReadUpdateComplete(); 327 SetPLLReg(R128_PPLL_REF_DIV, params.ppll_ref_div, R128_PPLL_REF_DIV_MASK); 328 PLLWriteUpdate(); 329 330 PLLWaitForReadUpdateComplete(); 331 SetPLLReg(R128_PPLL_DIV_3, params.ppll_div_3, 332 R128_PPLL_FB3_DIV_MASK | R128_PPLL_POST3_DIV_MASK); 333 PLLWriteUpdate(); 334 335 PLLWaitForReadUpdateComplete(); 336 SetPLLReg(R128_HTOTAL_CNTL, 0); 337 PLLWriteUpdate(); 338 339 SetPLLReg(R128_PPLL_CNTL, 0, R128_PPLL_RESET 340 | R128_PPLL_SLEEP 341 | R128_PPLL_ATOMIC_UPDATE_EN 342 | R128_PPLL_VGA_ATOMIC_UPDATE_EN); 343 344 snooze(5000); 345 346 SetPLLReg(R128_VCLK_ECP_CNTL, R128_VCLK_SRC_SEL_PPLLCLK, 347 R128_VCLK_SRC_SEL_MASK); 348 } 349 350 351 352 status_t 353 Rage128_SetDisplayMode(const DisplayModeEx& mode) 354 { 355 // The code to actually configure the display. 356 // All the error checking must be done in ProposeDisplayMode(), 357 // and assume that the mode values we get here are acceptable. 358 359 DisplayParams params; // where computed parameters are saved 360 361 if (gInfo.sharedInfo->displayType == MT_VGA) { 362 // Chip is connected to a monitor via a VGA connector. 363 364 if ( ! CalculateCrtcRegisters(mode, params)) 365 return B_BAD_VALUE; 366 367 if ( ! CalculatePLLRegisters(mode, params)) 368 return B_BAD_VALUE; 369 370 if ( ! CalculateDDARegisters(mode, params)) 371 return B_BAD_VALUE; 372 373 SetRegisters(params); 374 375 } else { 376 // Chip is connected to a laptop LCD monitor; or via a DVI interface. 377 378 uint16 vesaMode = GetVesaModeNumber(display_mode(mode), mode.bitsPerPixel); 379 if (vesaMode == 0) 380 return B_BAD_VALUE; 381 382 if (ioctl(gInfo.deviceFileDesc, ATI_SET_VESA_DISPLAY_MODE, 383 &vesaMode, sizeof(vesaMode)) != B_OK) 384 return B_ERROR; 385 } 386 387 Rage128_AdjustFrame(mode); 388 389 // Initialize the palette so that color depths > 8 bits/pixel will display 390 // the correct colors. 391 392 // Select primary monitor and enable 8-bit color. 393 OUTREGM(R128_DAC_CNTL, R128_DAC_8BIT_EN, 394 R128_DAC_PALETTE_ACC_CTL | R128_DAC_8BIT_EN); 395 OUTREG8(R128_PALETTE_INDEX, 0); // set first color index 396 397 for (int i = 0; i < 256; i++) 398 OUTREG(R128_PALETTE_DATA, (i << 16) | (i << 8) | i ); 399 400 Rage128_EngineInit(mode); 401 402 return B_OK; 403 } 404 405 406 407 void 408 Rage128_AdjustFrame(const DisplayModeEx& mode) 409 { 410 // Adjust start address in frame buffer. 411 412 SharedInfo& si = *gInfo.sharedInfo; 413 414 int address = (mode.v_display_start * mode.virtual_width 415 + mode.h_display_start) * ((mode.bitsPerPixel + 1) / 8); 416 417 address &= ~0x07; 418 address += si.frameBufferOffset; 419 420 OUTREG(R128_CRTC_OFFSET, address); 421 return; 422 } 423 424 425 void 426 Rage128_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags) 427 { 428 // Set the indexed color palette for 8-bit color depth mode. 429 430 (void)flags; // avoid compiler warning for unused arg 431 432 if (gInfo.sharedInfo->displayMode.space != B_CMAP8) 433 return ; 434 435 // Select primary monitor and enable 8-bit color. 436 OUTREGM(R128_DAC_CNTL, R128_DAC_8BIT_EN, 437 R128_DAC_PALETTE_ACC_CTL | R128_DAC_8BIT_EN); 438 OUTREG8(R128_PALETTE_INDEX, first); // set first color index 439 440 while (count--) { 441 OUTREG(R128_PALETTE_DATA, ((colorData[0] << 16) // red 442 | (colorData[1] << 8) // green 443 | colorData[2])); // blue 444 colorData += 3; 445 } 446 } 447