1 /* 2 * Copyright 2006-2013, 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 "mode.h" 15 16 #include <create_display_modes.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <math.h> 20 21 #include "accelerant.h" 22 #include "accelerant_protos.h" 23 #include "bios.h" 24 #include "connector.h" 25 #include "display.h" 26 #include "displayport.h" 27 #include "encoder.h" 28 #include "pll.h" 29 #include "utility.h" 30 31 32 #define TRACE_MODE 33 #ifdef TRACE_MODE 34 extern "C" void _sPrintf(const char* format, ...); 35 # define TRACE(x...) _sPrintf("radeon_hd: " x) 36 #else 37 # define TRACE(x...) ; 38 #endif 39 40 #define ERROR(x...) _sPrintf("radeon_hd: " x) 41 42 43 status_t 44 create_mode_list(void) 45 { 46 // TODO: multi-monitor? for now we use VESA and not gDisplay edid 47 uint8 crtcID = 0; 48 49 const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE, 50 B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8}; 51 52 gInfo->mode_list_area = create_display_modes("radeon HD modes", 53 &gDisplay[crtcID]->edidData, NULL, 0, kRadeonHDSpaces, 54 B_COUNT_OF(kRadeonHDSpaces), is_mode_supported, &gInfo->mode_list, 55 &gInfo->shared_info->mode_count); 56 if (gInfo->mode_list_area < B_OK) 57 return gInfo->mode_list_area; 58 59 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 60 61 return B_OK; 62 } 63 64 65 // #pragma mark - 66 67 68 uint32 69 radeon_accelerant_mode_count(void) 70 { 71 TRACE("%s\n", __func__); 72 // TODO: multi-monitor? we need crtcid here 73 74 return gInfo->shared_info->mode_count; 75 } 76 77 78 status_t 79 radeon_get_mode_list(display_mode* modeList) 80 { 81 TRACE("%s\n", __func__); 82 // TODO: multi-monitor? we need crtcid here 83 memcpy(modeList, gInfo->mode_list, 84 gInfo->shared_info->mode_count * sizeof(display_mode)); 85 return B_OK; 86 } 87 88 89 status_t 90 radeon_get_preferred_mode(display_mode* preferredMode) 91 { 92 TRACE("%s\n", __func__); 93 // TODO: multi-monitor? we need crtcid here 94 95 uint8_t crtc = 0; 96 97 if (gDisplay[crtc]->preferredMode.virtual_width > 0 98 && gDisplay[crtc]->preferredMode.virtual_height > 0) { 99 TRACE("%s: preferred mode was found for display %" B_PRIu8 "\n", 100 __func__, crtc); 101 memcpy(preferredMode, &gDisplay[crtc]->preferredMode, 102 sizeof(gDisplay[crtc]->preferredMode)); 103 return B_OK; 104 } 105 106 return B_ERROR; 107 } 108 109 110 status_t 111 radeon_get_edid_info(void* info, size_t size, uint32* edid_version) 112 { 113 // TODO: multi-monitor? for now we use display 0 114 uint8 crtcID = 0; 115 116 TRACE("%s\n", __func__); 117 if (!gInfo->shared_info->has_edid) 118 return B_ERROR; 119 if (size < sizeof(struct edid1_info)) 120 return B_BUFFER_OVERFLOW; 121 122 //memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info)); 123 // VESA 124 memcpy(info, &gDisplay[crtcID]->edidData, sizeof(struct edid1_info)); 125 // Display 0 126 127 *edid_version = EDID_VERSION_1; 128 129 return B_OK; 130 } 131 132 133 uint32 134 radeon_dpms_capabilities(void) 135 { 136 // These should be pretty universally supported on Radeon HD cards 137 return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; 138 } 139 140 141 uint32 142 radeon_dpms_mode(void) 143 { 144 // TODO: this really isn't a good long-term solution 145 // we may need to look at the encoder dpms scratch registers 146 return gInfo->dpms_mode; 147 } 148 149 150 void 151 radeon_dpms_set(uint8 id, int mode) 152 { 153 if (mode == B_DPMS_ON) { 154 display_crtc_dpms(id, mode); 155 encoder_dpms_set(id, mode); 156 } else { 157 encoder_dpms_set(id, mode); 158 display_crtc_dpms(id, mode); 159 } 160 gInfo->dpms_mode = mode; 161 } 162 163 164 void 165 radeon_dpms_set_hook(int mode) 166 { 167 // TODO: multi-monitor? 168 169 uint8 crtcID = 0; 170 171 if (gDisplay[crtcID]->attached) 172 radeon_dpms_set(crtcID, mode); 173 } 174 175 176 status_t 177 radeon_set_display_mode(display_mode* mode) 178 { 179 // TODO: multi-monitor? For now we set the mode on 180 // the first display found. 181 182 TRACE("%s\n", __func__); 183 TRACE(" mode->space: %#" B_PRIx32 "\n", mode->space); 184 TRACE(" mode->virtual_width: %" B_PRIu16 "\n", mode->virtual_width); 185 TRACE(" mode->virtual_height: %" B_PRIu16 "\n", mode->virtual_height); 186 TRACE(" mode->h_display_start: %" B_PRIu16 "\n", mode->h_display_start); 187 TRACE(" mode->v_display_start: %" B_PRIu16 "\n", mode->v_display_start); 188 TRACE(" mode->flags: %#" B_PRIx32 "\n", mode->flags); 189 190 uint8 crtcID = 0; 191 192 if (gDisplay[crtcID]->attached == false) 193 return B_ERROR; 194 195 // Copy this display mode into the "current mode" for the display 196 memcpy(&gDisplay[crtcID]->currentMode, mode, sizeof(display_mode)); 197 198 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex; 199 200 // Determine DP lanes if DP 201 if (connector_is_dp(connectorIndex)) { 202 dp_info *dpInfo = &gConnector[connectorIndex]->dpInfo; 203 dpInfo->laneCount = dp_get_lane_count(connectorIndex, mode); 204 dpInfo->linkRate = dp_get_link_rate(connectorIndex, mode); 205 } 206 207 // *** crtc and encoder prep 208 encoder_output_lock(true); 209 display_crtc_lock(crtcID, ATOM_ENABLE); 210 radeon_dpms_set(crtcID, B_DPMS_OFF); 211 212 // *** Set up encoder -> crtc routing 213 encoder_assign_crtc(crtcID); 214 215 // *** CRT controler mode set 216 // Set up PLL for connector 217 pll_pick(connectorIndex); 218 pll_info* pll = &gConnector[connectorIndex]->encoder.pll; 219 TRACE("%s: pll %d selected for connector %" B_PRIu32 "\n", __func__, 220 pll->id, connectorIndex); 221 pll_set(mode, crtcID); 222 223 display_crtc_set_dtd(crtcID, mode); 224 225 display_crtc_fb_set(crtcID, mode); 226 // atombios_overscan_setup 227 display_crtc_scale(crtcID, mode); 228 229 // *** encoder mode set 230 encoder_mode_set(crtcID); 231 232 // *** encoder and CRT controller commit 233 radeon_dpms_set(crtcID, B_DPMS_ON); 234 display_crtc_lock(crtcID, ATOM_DISABLE); 235 encoder_output_lock(false); 236 237 #ifdef TRACE_MODE 238 // for debugging 239 debug_dp_info(); 240 241 TRACE("D1CRTC_STATUS Value: 0x%X\n", 242 Read32(CRT, AVIVO_D1CRTC_STATUS)); 243 TRACE("D2CRTC_STATUS Value: 0x%X\n", 244 Read32(CRT, AVIVO_D2CRTC_STATUS)); 245 TRACE("D1CRTC_CONTROL Value: 0x%X\n", 246 Read32(CRT, AVIVO_D1CRTC_CONTROL)); 247 TRACE("D2CRTC_CONTROL Value: 0x%X\n", 248 Read32(CRT, AVIVO_D2CRTC_CONTROL)); 249 TRACE("D1GRPH_ENABLE Value: 0x%X\n", 250 Read32(CRT, AVIVO_D1GRPH_ENABLE)); 251 TRACE("D2GRPH_ENABLE Value: 0x%X\n", 252 Read32(CRT, AVIVO_D2GRPH_ENABLE)); 253 TRACE("D1SCL_ENABLE Value: 0x%X\n", 254 Read32(CRT, AVIVO_D1SCL_SCALER_ENABLE)); 255 TRACE("D2SCL_ENABLE Value: 0x%X\n", 256 Read32(CRT, AVIVO_D2SCL_SCALER_ENABLE)); 257 TRACE("D1CRTC_BLANK_CONTROL Value: 0x%X\n", 258 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); 259 TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n", 260 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); 261 #endif 262 263 return B_OK; 264 } 265 266 267 status_t 268 radeon_get_display_mode(display_mode* _currentMode) 269 { 270 TRACE("%s\n", __func__); 271 272 *_currentMode = gInfo->shared_info->current_mode; 273 //*_currentMode = gDisplay[X]->currentMode; 274 return B_OK; 275 } 276 277 278 status_t 279 radeon_get_frame_buffer_config(frame_buffer_config* config) 280 { 281 TRACE("%s\n", __func__); 282 283 config->frame_buffer = gInfo->shared_info->frame_buffer; 284 config->frame_buffer_dma = (uint8*)gInfo->shared_info->frame_buffer_phys; 285 286 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 287 288 TRACE(" config->frame_buffer: %#" B_PRIxADDR "\n", 289 (phys_addr_t)config->frame_buffer); 290 TRACE(" config->frame_buffer_dma: %#" B_PRIxADDR "\n", 291 (phys_addr_t)config->frame_buffer_dma); 292 TRACE(" config->bytes_per_row: %" B_PRIu32 "\n", config->bytes_per_row); 293 294 return B_OK; 295 } 296 297 298 status_t 299 radeon_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) 300 { 301 TRACE("%s\n", __func__); 302 303 if (_low != NULL) { 304 // lower limit of about 48Hz vertical refresh 305 uint32 totalClocks = (uint32)mode->timing.h_total 306 * (uint32)mode->timing.v_total; 307 uint32 low = (totalClocks * 48L) / 1000L; 308 309 if (low < PLL_MIN_DEFAULT) 310 low = PLL_MIN_DEFAULT; 311 else if (low > PLL_MAX_DEFAULT) 312 return B_ERROR; 313 314 *_low = low; 315 } 316 317 if (_high != NULL) 318 *_high = PLL_MAX_DEFAULT; 319 320 //*_low = 48L; 321 //*_high = 100 * 1000000L; 322 return B_OK; 323 } 324 325 326 bool 327 is_mode_supported(display_mode* mode) 328 { 329 bool sane = true; 330 331 // Validate modeline is within a sane range 332 if (is_mode_sane(mode) != B_OK) 333 sane = false; 334 335 // TODO: is_mode_supported on *which* display? 336 uint32 crtid = 0; 337 338 // if we have edid info, check frequency adginst crt reported valid ranges 339 if (gInfo->shared_info->has_edid 340 && gDisplay[crtid]->foundRanges) { 341 342 // validate horizontal frequency range 343 uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total; 344 if (hfreq > gDisplay[crtid]->hfreqMax + 1 345 || hfreq < gDisplay[crtid]->hfreqMin - 1) { 346 //TRACE("!!! mode below falls outside of hfreq range!\n"); 347 sane = false; 348 } 349 350 // validate vertical frequency range 351 uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total 352 * mode->timing.h_total) / 1000); 353 if (vfreq > gDisplay[crtid]->vfreqMax + 1 354 || vfreq < gDisplay[crtid]->vfreqMin - 1) { 355 //TRACE("!!! mode below falls outside of vfreq range!\n"); 356 sane = false; 357 } 358 } 359 360 #if 0 361 // Lots of spam, but good for understanding what modelines are in use 362 TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d is %s\n", 363 mode->timing.pixel_clock, mode->timing.h_display, 364 mode->timing.h_sync_start, mode->timing.h_sync_end, 365 mode->timing.h_total, mode->timing.v_display, 366 mode->timing.v_sync_start, mode->timing.v_sync_end, 367 mode->timing.v_total, 368 sane ? "OK." : "BAD, out of range!"); 369 #endif 370 371 return sane; 372 } 373 374 375 /* 376 * A quick sanity check of the provided display_mode 377 */ 378 status_t 379 is_mode_sane(display_mode* mode) 380 { 381 // horizontal timing 382 // validate h_sync_start is less then h_sync_end 383 if (mode->timing.h_sync_start > mode->timing.h_sync_end) { 384 TRACE("%s: ERROR: (%dx%d) " 385 "received h_sync_start greater then h_sync_end!\n", 386 __func__, mode->timing.h_display, mode->timing.v_display); 387 return B_ERROR; 388 } 389 // validate h_total is greater then h_display 390 if (mode->timing.h_total < mode->timing.h_display) { 391 TRACE("%s: ERROR: (%dx%d) " 392 "received h_total greater then h_display!\n", 393 __func__, mode->timing.h_display, mode->timing.v_display); 394 return B_ERROR; 395 } 396 397 // vertical timing 398 // validate v_start is less then v_end 399 if (mode->timing.v_sync_start > mode->timing.v_sync_end) { 400 TRACE("%s: ERROR: (%dx%d) " 401 "received v_sync_start greater then v_sync_end!\n", 402 __func__, mode->timing.h_display, mode->timing.v_display); 403 return B_ERROR; 404 } 405 // validate v_total is greater then v_display 406 if (mode->timing.v_total < mode->timing.v_display) { 407 TRACE("%s: ERROR: (%dx%d) " 408 "received v_total greater then v_display!\n", 409 __func__, mode->timing.h_display, mode->timing.v_display); 410 return B_ERROR; 411 } 412 413 // calculate refresh rate for given timings to whole int (in Hz) 414 int refresh = mode->timing.pixel_clock * 1000 415 / (mode->timing.h_total * mode->timing.v_total); 416 417 if (refresh < 30 || refresh > 250) { 418 TRACE("%s: ERROR: (%dx%d) " 419 "refresh rate of %dHz is unlikely for any kind of monitor!\n", 420 __func__, mode->timing.h_display, mode->timing.v_display, refresh); 421 return B_ERROR; 422 } 423 424 return B_OK; 425 } 426 427 428 uint32 429 get_mode_bpp(display_mode* mode) 430 { 431 // Get bitsPerPixel for given mode 432 433 switch (mode->space) { 434 case B_CMAP8: 435 return 8; 436 case B_RGB15_LITTLE: 437 return 15; 438 case B_RGB16_LITTLE: 439 return 16; 440 case B_RGB24_LITTLE: 441 case B_RGB32_LITTLE: 442 return 32; 443 } 444 ERROR("%s: Unknown colorspace for mode, guessing 32 bits per pixel\n", 445 __func__); 446 return 32; 447 } 448 449 450 static uint32_t 451 radeon_get_backlight_register() 452 { 453 // R600 and up is 0x172c else its 0x0018 454 if (gInfo->shared_info->chipsetID >= RADEON_R600) 455 return 0x172c; 456 return 0x0018; 457 } 458 459 460 status_t 461 radeon_set_brightness(float brightness) 462 { 463 TRACE("%s (%f)\n", __func__, brightness); 464 465 if (brightness < 0 || brightness > 1) 466 return B_BAD_VALUE; 467 468 uint32_t backlightReg = radeon_get_backlight_register(); 469 uint8_t brightnessRaw = (uint8_t)ceilf(brightness * 255); 470 uint32_t level = Read32(OUT, backlightReg); 471 TRACE("brightness level = %lx\n", level); 472 level &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK; 473 level |= (( brightnessRaw << ATOM_S2_CURRENT_BL_LEVEL_SHIFT ) 474 & ATOM_S2_CURRENT_BL_LEVEL_MASK); 475 TRACE("new brightness level = %lx\n", level); 476 477 Write32(OUT, backlightReg, level); 478 479 //TODO crtcID = 0: see create_mode 480 // TODO: multi-monitor? for now we use VESA and not gDisplay edid 481 uint8 crtcID = 0; 482 //TODO : test if it is a LCD ? 483 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex; 484 connector_info* connector = gConnector[connectorIndex]; 485 pll_info* pll = &connector->encoder.pll; 486 487 transmitter_dig_setup(connectorIndex, pll->pixelClock, 488 0, 0, ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL); 489 transmitter_dig_setup(connectorIndex, pll->pixelClock, 490 0, 0, ATOM_TRANSMITTER_ACTION_LCD_BLON); 491 492 return B_OK; 493 } 494 495 496 status_t 497 radeon_get_brightness(float* brightness) 498 { 499 TRACE("%s\n", __func__); 500 501 if (brightness == NULL) 502 return B_BAD_VALUE; 503 504 uint32_t backlightReg = Read32(OUT, radeon_get_backlight_register()); 505 uint8_t brightnessRaw = ((backlightReg & ATOM_S2_CURRENT_BL_LEVEL_MASK) >> 506 ATOM_S2_CURRENT_BL_LEVEL_SHIFT); 507 *brightness = (float)brightnessRaw / 255; 508 509 return B_OK; 510 } 511