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 "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 48 const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE, 49 B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8}; 50 51 gInfo->mode_list_area = create_display_modes("radeon HD modes", 52 gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL, 53 NULL, 0, kRadeonHDSpaces, 54 sizeof(kRadeonHDSpaces) / sizeof(kRadeonHDSpaces[0]), 55 is_mode_supported, &gInfo->mode_list, &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 73 return gInfo->shared_info->mode_count; 74 } 75 76 77 status_t 78 radeon_get_mode_list(display_mode* modeList) 79 { 80 TRACE("%s\n", __func__); 81 memcpy(modeList, gInfo->mode_list, 82 gInfo->shared_info->mode_count * sizeof(display_mode)); 83 return B_OK; 84 } 85 86 87 status_t 88 radeon_get_preferred_mode(display_mode* preferredMode) 89 { 90 TRACE("%s\n", __func__); 91 92 // TODO: Argh! Which display? :) 93 uint8_t crtc = 0; 94 95 if (gDisplay[crtc]->preferredMode.virtual_width > 0 96 && gDisplay[crtc]->preferredMode.virtual_height > 0) { 97 TRACE("%s: preferred mode was found for display %" B_PRIu8 "\n", 98 __func__, crtc); 99 memcpy(preferredMode, &gDisplay[crtc]->preferredMode, 100 sizeof(gDisplay[crtc]->preferredMode)); 101 return B_OK; 102 } 103 104 return B_ERROR; 105 } 106 107 108 status_t 109 radeon_get_edid_info(void* info, size_t size, uint32* edid_version) 110 { 111 // TODO: multi-monitor? for now we use VESA edid 112 113 TRACE("%s\n", __func__); 114 if (!gInfo->shared_info->has_edid) 115 return B_ERROR; 116 if (size < sizeof(struct edid1_info)) 117 return B_BUFFER_OVERFLOW; 118 119 memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info)); 120 // VESA 121 //memcpy(info, &gDisplay[0]->edid_info, sizeof(struct edid1_info)); 122 // BitBanged display 0 123 124 *edid_version = EDID_VERSION_1; 125 126 return B_OK; 127 } 128 129 130 uint32 131 radeon_dpms_capabilities(void) 132 { 133 // These should be pretty universally supported on Radeon HD cards 134 return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; 135 } 136 137 138 uint32 139 radeon_dpms_mode(void) 140 { 141 // TODO: this really isn't a good long-term solution 142 // we may need to look at the encoder dpms scratch registers 143 return gInfo->dpms_mode; 144 } 145 146 147 void 148 radeon_dpms_set(int mode) 149 { 150 radeon_shared_info &info = *gInfo->shared_info; 151 152 switch (mode) { 153 case B_DPMS_ON: 154 TRACE("%s: ON\n", __func__); 155 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 156 if (gDisplay[id]->active == false) 157 continue; 158 encoder_output_lock(true); 159 encoder_dpms_set(id, mode); 160 encoder_output_lock(false); 161 display_crtc_lock(id, ATOM_ENABLE); 162 display_crtc_power(id, ATOM_ENABLE); 163 if (info.dceMajor >= 3) 164 display_crtc_memreq(id, ATOM_ENABLE); 165 display_crtc_blank(id, ATOM_BLANKING_OFF); 166 display_crtc_lock(id, ATOM_DISABLE); 167 } 168 break; 169 case B_DPMS_STAND_BY: 170 case B_DPMS_SUSPEND: 171 case B_DPMS_OFF: 172 TRACE("%s: OFF\n", __func__); 173 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 174 if (gDisplay[id]->active == false) 175 continue; 176 display_crtc_lock(id, ATOM_ENABLE); 177 display_crtc_blank(id, ATOM_BLANKING); 178 if (info.dceMajor >= 3) 179 display_crtc_memreq(id, ATOM_DISABLE); 180 display_crtc_power(id, ATOM_DISABLE); 181 display_crtc_lock(id, ATOM_DISABLE); 182 encoder_output_lock(true); 183 encoder_dpms_set(id, mode); 184 encoder_output_lock(false); 185 } 186 break; 187 } 188 gInfo->dpms_mode = mode; 189 } 190 191 192 status_t 193 radeon_set_display_mode(display_mode* mode) 194 { 195 radeon_shared_info &info = *gInfo->shared_info; 196 197 // Set mode on each display 198 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 199 if (gDisplay[id]->active == false) 200 continue; 201 202 uint16 connectorIndex = gDisplay[id]->connectorIndex; 203 204 // Determine DP lanes if DP 205 if (connector_is_dp(connectorIndex)) 206 gDPInfo[connectorIndex]->laneCount 207 = dp_get_lane_count(connectorIndex, mode); 208 209 // *** encoder prep 210 encoder_output_lock(true); 211 encoder_dpms_set(id, B_DPMS_OFF); 212 encoder_assign_crtc(id); 213 214 // *** CRT controler prep 215 display_crtc_lock(id, ATOM_ENABLE); 216 display_crtc_blank(id, ATOM_BLANKING); 217 if (info.dceMajor >= 3) 218 display_crtc_memreq(id, ATOM_DISABLE); 219 display_crtc_power(id, ATOM_DISABLE); 220 221 // *** CRT controler mode set 222 // TODO: program SS 223 pll_set(ATOM_PPLL1, mode->timing.pixel_clock, id); 224 // TODO: check if ATOM_PPLL1 is used and use ATOM_PPLL2 if so 225 display_crtc_set_dtd(id, mode); 226 227 display_crtc_fb_set(id, mode); 228 // atombios_overscan_setup 229 display_crtc_scale(id, mode); 230 231 // *** encoder mode set 232 encoder_mode_set(id, mode->timing.pixel_clock); 233 234 // *** CRT controler commit 235 display_crtc_power(id, ATOM_ENABLE); 236 if (info.dceMajor >= 3) 237 display_crtc_memreq(id, ATOM_ENABLE); 238 display_crtc_blank(id, ATOM_BLANKING_OFF); 239 display_crtc_lock(id, ATOM_DISABLE); 240 241 // *** encoder commit 242 243 // handle DisplayPort link training 244 if (connector_is_dp(connectorIndex)) { 245 if (info.dceMajor >= 4) 246 encoder_dig_setup(connectorIndex, 247 ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); 248 249 dp_link_train(id, mode); 250 251 if (info.dceMajor >= 4) 252 encoder_dig_setup(connectorIndex, 253 ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); 254 } 255 256 encoder_dpms_set(id, B_DPMS_ON); 257 encoder_output_lock(false); 258 } 259 260 // for debugging 261 TRACE("D1CRTC_STATUS Value: 0x%X\n", Read32(CRT, D1CRTC_STATUS)); 262 TRACE("D2CRTC_STATUS Value: 0x%X\n", Read32(CRT, D2CRTC_STATUS)); 263 TRACE("D1CRTC_CONTROL Value: 0x%X\n", Read32(CRT, D1CRTC_CONTROL)); 264 TRACE("D2CRTC_CONTROL Value: 0x%X\n", Read32(CRT, D2CRTC_CONTROL)); 265 TRACE("D1GRPH_ENABLE Value: 0x%X\n", 266 Read32(CRT, AVIVO_D1GRPH_ENABLE)); 267 TRACE("D2GRPH_ENABLE Value: 0x%X\n", 268 Read32(CRT, AVIVO_D2GRPH_ENABLE)); 269 TRACE("D1SCL_ENABLE Value: 0x%X\n", 270 Read32(CRT, AVIVO_D1SCL_SCALER_ENABLE)); 271 TRACE("D2SCL_ENABLE Value: 0x%X\n", 272 Read32(CRT, AVIVO_D2SCL_SCALER_ENABLE)); 273 TRACE("D1CRTC_BLANK_CONTROL Value: 0x%X\n", 274 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); 275 TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n", 276 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); 277 278 return B_OK; 279 } 280 281 282 status_t 283 radeon_get_display_mode(display_mode* _currentMode) 284 { 285 TRACE("%s\n", __func__); 286 287 *_currentMode = gInfo->shared_info->current_mode; 288 return B_OK; 289 } 290 291 292 status_t 293 radeon_get_frame_buffer_config(frame_buffer_config* config) 294 { 295 TRACE("%s\n", __func__); 296 297 config->frame_buffer = gInfo->shared_info->frame_buffer; 298 config->frame_buffer_dma = (uint8*)gInfo->shared_info->frame_buffer_phys; 299 300 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 301 302 return B_OK; 303 } 304 305 306 status_t 307 radeon_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) 308 { 309 TRACE("%s\n", __func__); 310 311 if (_low != NULL) { 312 // lower limit of about 48Hz vertical refresh 313 uint32 totalClocks = (uint32)mode->timing.h_total 314 * (uint32)mode->timing.v_total; 315 uint32 low = (totalClocks * 48L) / 1000L; 316 317 if (low < PLL_MIN_DEFAULT) 318 low = PLL_MIN_DEFAULT; 319 else if (low > PLL_MAX_DEFAULT) 320 return B_ERROR; 321 322 *_low = low; 323 } 324 325 if (_high != NULL) 326 *_high = PLL_MAX_DEFAULT; 327 328 //*_low = 48L; 329 //*_high = 100 * 1000000L; 330 return B_OK; 331 } 332 333 334 bool 335 is_mode_supported(display_mode* mode) 336 { 337 bool sane = true; 338 339 // Validate modeline is within a sane range 340 if (is_mode_sane(mode) != B_OK) 341 sane = false; 342 343 // TODO: is_mode_supported on *which* display? 344 uint32 crtid = 0; 345 346 // if we have edid info, check frequency adginst crt reported valid ranges 347 if (gInfo->shared_info->has_edid 348 && gDisplay[crtid]->found_ranges) { 349 350 // validate horizontal frequency range 351 uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total; 352 if (hfreq > gDisplay[crtid]->hfreq_max + 1 353 || hfreq < gDisplay[crtid]->hfreq_min - 1) { 354 //TRACE("!!! mode below falls outside of hfreq range!\n"); 355 sane = false; 356 } 357 358 // validate vertical frequency range 359 uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total 360 * mode->timing.h_total) / 1000); 361 if (vfreq > gDisplay[crtid]->vfreq_max + 1 362 || vfreq < gDisplay[crtid]->vfreq_min - 1) { 363 //TRACE("!!! mode below falls outside of vfreq range!\n"); 364 sane = false; 365 } 366 } 367 368 TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d is %s\n", 369 mode->timing.pixel_clock, mode->timing.h_display, 370 mode->timing.h_sync_start, mode->timing.h_sync_end, 371 mode->timing.h_total, mode->timing.v_display, 372 mode->timing.v_sync_start, mode->timing.v_sync_end, 373 mode->timing.v_total, 374 sane ? "OK." : "BAD, out of range!"); 375 376 return sane; 377 } 378 379 380 /* 381 * A quick sanity check of the provided display_mode 382 */ 383 status_t 384 is_mode_sane(display_mode* mode) 385 { 386 // horizontal timing 387 // validate h_sync_start is less then h_sync_end 388 if (mode->timing.h_sync_start > mode->timing.h_sync_end) { 389 TRACE("%s: ERROR: (%dx%d) " 390 "received h_sync_start greater then h_sync_end!\n", 391 __func__, mode->timing.h_display, mode->timing.v_display); 392 return B_ERROR; 393 } 394 // validate h_total is greater then h_display 395 if (mode->timing.h_total < mode->timing.h_display) { 396 TRACE("%s: ERROR: (%dx%d) " 397 "received h_total greater then h_display!\n", 398 __func__, mode->timing.h_display, mode->timing.v_display); 399 return B_ERROR; 400 } 401 402 // vertical timing 403 // validate v_start is less then v_end 404 if (mode->timing.v_sync_start > mode->timing.v_sync_end) { 405 TRACE("%s: ERROR: (%dx%d) " 406 "received v_sync_start greater then v_sync_end!\n", 407 __func__, mode->timing.h_display, mode->timing.v_display); 408 return B_ERROR; 409 } 410 // validate v_total is greater then v_display 411 if (mode->timing.v_total < mode->timing.v_display) { 412 TRACE("%s: ERROR: (%dx%d) " 413 "received v_total greater then v_display!\n", 414 __func__, mode->timing.h_display, mode->timing.v_display); 415 return B_ERROR; 416 } 417 418 // calculate refresh rate for given timings to whole int (in Hz) 419 int refresh = mode->timing.pixel_clock * 1000 420 / (mode->timing.h_total * mode->timing.v_total); 421 422 if (refresh < 30 || refresh > 250) { 423 TRACE("%s: ERROR: (%dx%d) " 424 "refresh rate of %dHz is unlikely for any kind of monitor!\n", 425 __func__, mode->timing.h_display, mode->timing.v_display, refresh); 426 return B_ERROR; 427 } 428 429 return B_OK; 430 } 431 432 433 uint32 434 get_mode_bpp(display_mode* mode) 435 { 436 // Get bitsPerPixel for given mode 437 438 switch (mode->space) { 439 case B_CMAP8: 440 return 8; 441 case B_RGB15_LITTLE: 442 return 15; 443 case B_RGB16_LITTLE: 444 return 16; 445 case B_RGB24_LITTLE: 446 case B_RGB32_LITTLE: 447 return 32; 448 } 449 ERROR("%s: Unknown colorspace for mode, guessing 32 bits per pixel\n", 450 __func__); 451 return 32; 452 } 453