1 /* 2 * Copyright 2006-2011, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Support for i915 chipset and up based on the X driver, 6 * Copyright 2006-2007 Intel Corporation. 7 * 8 * Authors: 9 * Axel Dörfler, axeld@pinc-software.de 10 * Alexander von Gluck, kallisti5@unixzen.com 11 */ 12 13 14 #include "accelerant_protos.h" 15 #include "accelerant.h" 16 #include "utility.h" 17 #include "mode.h" 18 19 #include <stdio.h> 20 #include <string.h> 21 #include <math.h> 22 23 #include <create_display_modes.h> 24 25 26 #define TRACE_MODE 27 #ifdef TRACE_MODE 28 extern "C" void _sPrintf(const char *format, ...); 29 # define TRACE(x...) _sPrintf("radeon_hd: " x) 30 #else 31 # define TRACE(x...) ; 32 #endif 33 34 35 status_t 36 create_mode_list(void) 37 { 38 const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE, 39 B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8}; 40 41 gInfo->mode_list_area = create_display_modes("radeon HD modes", 42 gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL, 43 NULL, 0, kRadeonHDSpaces, 44 sizeof(kRadeonHDSpaces) / sizeof(kRadeonHDSpaces[0]), 45 is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count); 46 if (gInfo->mode_list_area < B_OK) 47 return gInfo->mode_list_area; 48 49 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 50 51 return B_OK; 52 } 53 54 55 // #pragma mark - 56 57 58 uint32 59 radeon_accelerant_mode_count(void) 60 { 61 TRACE("%s\n", __func__); 62 63 return gInfo->shared_info->mode_count; 64 } 65 66 67 status_t 68 radeon_get_mode_list(display_mode *modeList) 69 { 70 TRACE("%s\n", __func__); 71 memcpy(modeList, gInfo->mode_list, 72 gInfo->shared_info->mode_count * sizeof(display_mode)); 73 return B_OK; 74 } 75 76 77 status_t 78 radeon_get_edid_info(void* info, size_t size, uint32* edid_version) 79 { 80 TRACE("%s\n", __func__); 81 if (!gInfo->shared_info->has_edid) 82 return B_ERROR; 83 if (size < sizeof(struct edid1_info)) 84 return B_BUFFER_OVERFLOW; 85 86 memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info)); 87 *edid_version = EDID_VERSION_1; 88 89 return B_OK; 90 } 91 92 93 static void 94 get_color_space_format(const display_mode &mode, uint32 &colorMode, 95 uint32 &bytesPerRow, uint32 &bitsPerPixel) 96 { 97 uint32 bytesPerPixel; 98 99 switch (mode.space) { 100 case B_RGB32_LITTLE: 101 colorMode = DISPLAY_CONTROL_RGB32; 102 bytesPerPixel = 4; 103 bitsPerPixel = 32; 104 break; 105 case B_RGB16_LITTLE: 106 colorMode = DISPLAY_CONTROL_RGB16; 107 bytesPerPixel = 2; 108 bitsPerPixel = 16; 109 break; 110 case B_RGB15_LITTLE: 111 colorMode = DISPLAY_CONTROL_RGB15; 112 bytesPerPixel = 2; 113 bitsPerPixel = 15; 114 break; 115 case B_CMAP8: 116 default: 117 colorMode = DISPLAY_CONTROL_CMAP8; 118 bytesPerPixel = 1; 119 bitsPerPixel = 8; 120 break; 121 } 122 123 bytesPerRow = mode.virtual_width * bytesPerPixel; 124 } 125 126 127 // Blacks the screen out, useful for mode setting 128 static void 129 CardBlankSet(bool blank) 130 { 131 int blackColorReg; 132 int blankControlReg; 133 134 blackColorReg = D1CRTC_BLACK_COLOR; 135 blankControlReg = D1CRTC_BLANK_CONTROL; 136 137 Write32(CRT, blackColorReg, 0); 138 Write32Mask(CRT, blankControlReg, blank ? 1 << 8 : 0, 1 << 8); 139 } 140 141 142 static void 143 CardFBSet(display_mode *mode) 144 { 145 uint32 colorMode; 146 uint32 bytesPerRow; 147 uint32 bitsPerPixel; 148 149 get_color_space_format(*mode, colorMode, bytesPerRow, bitsPerPixel); 150 151 // Disable VGA mode to enable Radeon extended registers 152 Write32Mask(VGA, VGA_RENDER_CONTROL, 0, 0x00030000); 153 Write32Mask(VGA, VGA_MODE_CONTROL, 0, 0x00000030); 154 Write32Mask(VGA, VGA_HDP_CONTROL, 0x00010010, 0x00010010); 155 Write32Mask(VGA, gRegister->vgaControl, 0, D1VGA_MODE_ENABLE 156 | D1VGA_TIMING_SELECT | D1VGA_SYNC_POLARITY_SELECT); 157 158 // disable R/B swap, disable tiling, disable 16bit alpha, etc. 159 Write32Mask(CRT, gRegister->grphEnable, 1, 0x00000001); 160 Write32(CRT, gRegister->grphControl, 0); 161 162 // set color mode on video card 163 switch (mode->space) { 164 case B_CMAP8: 165 Write32Mask(CRT, gRegister->grphControl, 166 0, 0x00000703); 167 break; 168 case B_RGB15_LITTLE: 169 Write32Mask(CRT, gRegister->grphControl, 170 0x000001, 0x00000703); 171 break; 172 case B_RGB16_LITTLE: 173 Write32Mask(CRT, gRegister->grphControl, 174 0x000101, 0x00000703); 175 break; 176 case B_RGB24_LITTLE: 177 case B_RGB32_LITTLE: 178 default: 179 Write32Mask(CRT, gRegister->grphControl, 180 0x000002, 0x00000703); 181 break; 182 } 183 184 Write32(CRT, gRegister->grphSwapControl, 0); 185 // only for chipsets > r600 186 // R5xx - RS690 case is GRPH_CONTROL bit 16 187 188 // framebuffersize = w * h * bpp = fb bits / 8 = bytes needed 189 190 uint64_t fbAddress = gInfo->shared_info->frame_buffer_phys; 191 192 // Tell GPU which frame buffer address to draw from 193 if (gInfo->shared_info->device_chipset >= (uint16)(RADEON_R700 & 0x70)) { 194 Write32(CRT, gRegister->grphPrimarySurfaceAddrHigh, 195 (fbAddress >> 32) & 0xf); 196 Write32(CRT, gRegister->grphSecondarySurfaceAddrHigh, 197 (fbAddress >> 32) & 0xf); 198 } 199 200 Write32(CRT, gRegister->grphPrimarySurfaceAddr, 201 fbAddress & 0xffffffff); 202 Write32(CRT, gRegister->grphSecondarySurfaceAddr, 203 fbAddress & 0xffffffff); 204 205 Write32(CRT, gRegister->grphPitch, bytesPerRow / 4); 206 Write32(CRT, gRegister->grphSurfaceOffsetX, 0); 207 Write32(CRT, gRegister->grphSurfaceOffsetY, 0); 208 Write32(CRT, gRegister->grphXStart, 0); 209 Write32(CRT, gRegister->grphYStart, 0); 210 Write32(CRT, gRegister->grphXEnd, mode->virtual_width); 211 Write32(CRT, gRegister->grphYEnd, mode->virtual_height); 212 213 /* D1Mode registers */ 214 Write32(CRT, gRegister->modeDesktopHeight, mode->virtual_height); 215 216 // update shared info 217 gInfo->shared_info->bytes_per_row = bytesPerRow; 218 gInfo->shared_info->current_mode = *mode; 219 gInfo->shared_info->bits_per_pixel = bitsPerPixel; 220 } 221 222 223 static void 224 CardModeSet(display_mode *mode) 225 { 226 display_timing& displayTiming = mode->timing; 227 228 TRACE("%s called to do %dx%d\n", 229 __func__, displayTiming.h_display, displayTiming.v_display); 230 231 // enable read requests 232 Write32Mask(CRT, gRegister->grphControl, 0, 0x01000000); 233 234 // *** Horizontal 235 Write32(CRT, gRegister->crtHTotal, 236 displayTiming.h_total - 1); 237 238 #if 0 239 // determine blanking based on passed modeline 240 uint16 blankStart = displayTiming.h_display; 241 uint16 blankEnd = displayTiming.h_total; 242 243 Write32(CRT, gRegister->crtHBlank, 244 blankStart | (blankEnd << 16)); 245 #endif 246 247 Write32(CRT, gRegister->crtHSync, 248 (displayTiming.h_sync_end - displayTiming.h_sync_start) << 16); 249 250 // set flag for neg. H sync. M76 Register Reference Guide 2-256 251 Write32Mask(CRT, gRegister->crtHPolarity, 252 displayTiming.flags & B_POSITIVE_HSYNC ? 0 : 1, 0x1); 253 254 // *** Vertical 255 Write32(CRT, gRegister->crtVTotal, 256 displayTiming.v_total - 1); 257 258 #if 0 259 blankStart = displayTiming.v_display; 260 blankEnd = displayTiming.v_total; 261 262 Write32(CRT, gRegister->crtVBlank, 263 blankStart | (blankEnd << 16)); 264 #endif 265 266 // Set Interlace if specified within mode line 267 if (displayTiming.flags & B_TIMING_INTERLACED) { 268 Write32(CRT, gRegister->crtInterlace, 0x1); 269 Write32(CRT, gRegister->modeDataFormat, 0x1); 270 } else { 271 Write32(CRT, gRegister->crtInterlace, 0x0); 272 Write32(CRT, gRegister->modeDataFormat, 0x0); 273 } 274 275 Write32(CRT, gRegister->crtVSync, 276 (displayTiming.v_sync_end - displayTiming.v_sync_start) << 16); 277 278 // set flag for neg. V sync. M76 Register Reference Guide 2-258 279 // we don't need a mask here as this is the only param for Vertical 280 Write32(CRT, gRegister->crtVPolarity, 281 displayTiming.flags & B_POSITIVE_VSYNC ? 0 : 1); 282 283 /* set D1CRTC_HORZ_COUNT_BY2_EN to 0; 284 should only be set to 1 on 30bpp DVI modes 285 */ 286 Write32Mask(CRT, gRegister->crtCountControl, 0x0, 0x1); 287 } 288 289 290 static void 291 CardModeScale(display_mode *mode) 292 { 293 Write32(CRT, gRegister->viewportSize, 294 mode->timing.v_display | (mode->timing.h_display << 16)); 295 Write32(CRT, gRegister->viewportStart, 0); 296 297 // For now, no overscan support 298 Write32(CRT, D1MODE_EXT_OVERSCAN_LEFT_RIGHT, 299 (0 << 16) | 0); // LEFT | RIGHT 300 Write32(CRT, D1MODE_EXT_OVERSCAN_TOP_BOTTOM, 301 (0 << 16) | 0); // TOP | BOTTOM 302 303 // No scaling 304 Write32(CRT, gRegister->sclUpdate, (1<<16));// Lock 305 Write32(CRT, gRegister->sclEnable, 0); 306 Write32(CRT, gRegister->sclTapControl, 0); 307 Write32(CRT, gRegister->modeCenter, 0); 308 Write32(CRT, gRegister->sclUpdate, 0); // Unlock 309 310 #if 0 311 // Auto scale keeping aspect ratio 312 Write32(CRT, regOffset + D1MODE_CENTER, 1); 313 314 Write32(CRT, regOffset + D1SCL_UPDATE, 0); 315 Write32(CRT, regOffset + D1SCL_FLIP_CONTROL, 0); 316 317 Write32(CRT, regOffset + D1SCL_ENABLE, 1); 318 Write32(CRT, regOffset + D1SCL_HVSCALE, 0x00010001); 319 320 Write32(CRT, regOffset + D1SCL_TAP_CONTROL, 0x00000101); 321 322 Write32(CRT, regOffset + D1SCL_HFILTER, 0x00030100); 323 Write32(CRT, regOffset + D1SCL_VFILTER, 0x00030100); 324 325 Write32(CRT, regOffset + D1SCL_DITHER, 0x00001010); 326 #endif 327 } 328 329 330 status_t 331 radeon_set_display_mode(display_mode *mode) 332 { 333 int crtNumber = 0; 334 335 init_registers(crtNumber); 336 337 CardBlankSet(true); 338 CardFBSet(mode); 339 CardModeSet(mode); 340 CardModeScale(mode); 341 PLLSet(0, mode->timing.pixel_clock); 342 PLLPower(0, RHD_POWER_ON); 343 DACPower(0, RHD_POWER_ON); 344 CardBlankSet(false); 345 346 int32 crtstatus = Read32(CRT, D1CRTC_STATUS); 347 TRACE("CRT0 Status: 0x%X\n", crtstatus); 348 349 return B_OK; 350 } 351 352 353 status_t 354 radeon_get_display_mode(display_mode *_currentMode) 355 { 356 TRACE("%s\n", __func__); 357 358 *_currentMode = gInfo->shared_info->current_mode; 359 return B_OK; 360 } 361 362 363 status_t 364 radeon_get_frame_buffer_config(frame_buffer_config *config) 365 { 366 TRACE("%s\n", __func__); 367 368 config->frame_buffer = gInfo->shared_info->frame_buffer; 369 config->frame_buffer_dma = (uint8 *)gInfo->shared_info->frame_buffer_phys; 370 371 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 372 373 return B_OK; 374 } 375 376 377 status_t 378 radeon_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high) 379 { 380 TRACE("%s\n", __func__); 381 382 if (_low != NULL) { 383 // lower limit of about 48Hz vertical refresh 384 uint32 totalClocks = (uint32)mode->timing.h_total 385 *(uint32)mode->timing.v_total; 386 uint32 low = (totalClocks * 48L) / 1000L; 387 388 if (low < gInfo->shared_info->pll_info.min_frequency) 389 low = gInfo->shared_info->pll_info.min_frequency; 390 else if (low > gInfo->shared_info->pll_info.max_frequency) 391 return B_ERROR; 392 393 *_low = low; 394 } 395 396 if (_high != NULL) 397 *_high = gInfo->shared_info->pll_info.max_frequency; 398 399 //*_low = 48L; 400 //*_high = 100 * 1000000L; 401 return B_OK; 402 } 403 404 405 bool 406 is_mode_supported(display_mode *mode) 407 { 408 // Validate modeline is within a sane range 409 if (is_mode_sane(mode) != B_OK) 410 return false; 411 412 // TODO : Look at min and max monitor freqs and verify selected 413 // mode is within tolerances. 414 #if 0 415 int crtid = 0; 416 417 edid1_detailed_monitor *monitor 418 = &gInfo->shared_info->edid_info.detailed_monitor[crtid + 1]; 419 edid1_monitor_range& range = monitor->data.monitor_range; 420 421 TRACE("%s CRT Min/Max H %d/%d; CRT Min/Max V %d/%d\n", __func__, 422 range.min_h, range.max_h, range.min_v, range.max_v); 423 #endif 424 425 return true; 426 } 427 428 429 /* 430 * A quick sanity check of the provided display_mode 431 */ 432 status_t 433 is_mode_sane(display_mode *mode) 434 { 435 // horizontal timing 436 // validate h_sync_start is less then h_sync_end 437 if (mode->timing.h_sync_start > mode->timing.h_sync_end) { 438 TRACE("%s: ERROR: (%dx%d) " 439 "received h_sync_start greater then h_sync_end!\n", 440 __func__, mode->timing.h_display, mode->timing.v_display); 441 return B_ERROR; 442 } 443 // validate h_total is greater then h_display 444 if (mode->timing.h_total < mode->timing.h_display) { 445 TRACE("%s: ERROR: (%dx%d) " 446 "received h_total greater then h_display!\n", 447 __func__, mode->timing.h_display, mode->timing.v_display); 448 return B_ERROR; 449 } 450 451 // vertical timing 452 // validate v_start is less then v_end 453 if (mode->timing.v_sync_start > mode->timing.v_sync_end) { 454 TRACE("%s: ERROR: (%dx%d) " 455 "received v_sync_start greater then v_sync_end!\n", 456 __func__, mode->timing.h_display, mode->timing.v_display); 457 return B_ERROR; 458 } 459 // validate v_total is greater then v_display 460 if (mode->timing.v_total < mode->timing.v_display) { 461 TRACE("%s: ERROR: (%dx%d) " 462 "received v_total greater then v_display!\n", 463 __func__, mode->timing.h_display, mode->timing.v_display); 464 return B_ERROR; 465 } 466 467 // calculate refresh rate for given timings to whole int (in Hz) 468 int refresh = mode->timing.pixel_clock * 1000 469 / (mode->timing.h_total * mode->timing.v_total); 470 471 if (refresh < 30 || refresh > 250) { 472 TRACE("%s: ERROR: (%dx%d) " 473 "refresh rate of %dHz is unlikely for any kind of monitor!\n", 474 __func__, mode->timing.h_display, mode->timing.v_display, refresh); 475 return B_ERROR; 476 } 477 478 return B_OK; 479 } 480 481