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