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]->edidData, 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 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 151 encoder_dpms_set(id, mode); 152 display_crtc_dpms(id, mode); 153 } 154 155 gInfo->dpms_mode = mode; 156 } 157 158 159 status_t 160 radeon_set_display_mode(display_mode* mode) 161 { 162 radeon_shared_info &info = *gInfo->shared_info; 163 164 // Set mode on each display 165 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 166 if (gDisplay[id]->attached == false) 167 continue; 168 169 uint32 connectorIndex = gDisplay[id]->connectorIndex; 170 171 // Determine DP lanes if DP 172 if (connector_is_dp(connectorIndex)) { 173 dp_info *dpInfo = &gConnector[connectorIndex]->dpInfo; 174 dpInfo->laneCount = dp_get_lane_count(connectorIndex, mode); 175 dpInfo->linkRate = dp_get_link_rate(connectorIndex, mode); 176 } 177 178 // *** crtc and encoder prep 179 encoder_output_lock(true); 180 encoder_dpms_set(id, B_DPMS_OFF); 181 display_crtc_lock(id, ATOM_ENABLE); 182 display_crtc_dpms(id, B_DPMS_OFF); 183 184 // *** Set up encoder -> crtc routing 185 encoder_assign_crtc(id); 186 187 // *** CRT controler mode set 188 // Set up PLL for connector 189 pll_pick(connectorIndex); 190 pll_info* pll = &gConnector[connectorIndex]->encoder.pll; 191 TRACE("%s: pll %d selected for connector %" B_PRIu32 "\n", __func__, 192 pll->id, connectorIndex); 193 pll_set(mode, id); 194 195 display_crtc_set_dtd(id, mode); 196 197 display_crtc_fb_set(id, mode); 198 // atombios_overscan_setup 199 display_crtc_scale(id, mode); 200 201 // *** encoder mode set 202 encoder_mode_set(id); 203 204 // *** CRT controler commit 205 display_crtc_dpms(id, B_DPMS_ON); 206 display_crtc_lock(id, ATOM_DISABLE); 207 208 // *** encoder commit 209 210 // handle DisplayPort link training 211 if (connector_is_dp(connectorIndex)) { 212 if (info.dceMajor >= 4) 213 encoder_dig_setup(connectorIndex, 214 ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); 215 216 dp_link_train(connectorIndex, mode); 217 218 if (info.dceMajor >= 4) 219 encoder_dig_setup(connectorIndex, 220 ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); 221 } 222 223 encoder_dpms_set(id, B_DPMS_ON); 224 encoder_output_lock(false); 225 } 226 227 // for debugging 228 // debug_dp_info(); 229 230 TRACE("D1CRTC_STATUS Value: 0x%X\n", 231 Read32(CRT, AVIVO_D1CRTC_STATUS)); 232 TRACE("D2CRTC_STATUS Value: 0x%X\n", 233 Read32(CRT, AVIVO_D2CRTC_STATUS)); 234 TRACE("D1CRTC_CONTROL Value: 0x%X\n", 235 Read32(CRT, AVIVO_D1CRTC_CONTROL)); 236 TRACE("D2CRTC_CONTROL Value: 0x%X\n", 237 Read32(CRT, AVIVO_D2CRTC_CONTROL)); 238 TRACE("D1GRPH_ENABLE Value: 0x%X\n", 239 Read32(CRT, AVIVO_D1GRPH_ENABLE)); 240 TRACE("D2GRPH_ENABLE Value: 0x%X\n", 241 Read32(CRT, AVIVO_D2GRPH_ENABLE)); 242 TRACE("D1SCL_ENABLE Value: 0x%X\n", 243 Read32(CRT, AVIVO_D1SCL_SCALER_ENABLE)); 244 TRACE("D2SCL_ENABLE Value: 0x%X\n", 245 Read32(CRT, AVIVO_D2SCL_SCALER_ENABLE)); 246 TRACE("D1CRTC_BLANK_CONTROL Value: 0x%X\n", 247 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); 248 TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n", 249 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); 250 251 return B_OK; 252 } 253 254 255 status_t 256 radeon_get_display_mode(display_mode* _currentMode) 257 { 258 TRACE("%s\n", __func__); 259 260 *_currentMode = gInfo->shared_info->current_mode; 261 return B_OK; 262 } 263 264 265 status_t 266 radeon_get_frame_buffer_config(frame_buffer_config* config) 267 { 268 TRACE("%s\n", __func__); 269 270 config->frame_buffer = gInfo->shared_info->frame_buffer; 271 config->frame_buffer_dma = (uint8*)gInfo->shared_info->frame_buffer_phys; 272 273 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 274 275 return B_OK; 276 } 277 278 279 status_t 280 radeon_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) 281 { 282 TRACE("%s\n", __func__); 283 284 if (_low != NULL) { 285 // lower limit of about 48Hz vertical refresh 286 uint32 totalClocks = (uint32)mode->timing.h_total 287 * (uint32)mode->timing.v_total; 288 uint32 low = (totalClocks * 48L) / 1000L; 289 290 if (low < PLL_MIN_DEFAULT) 291 low = PLL_MIN_DEFAULT; 292 else if (low > PLL_MAX_DEFAULT) 293 return B_ERROR; 294 295 *_low = low; 296 } 297 298 if (_high != NULL) 299 *_high = PLL_MAX_DEFAULT; 300 301 //*_low = 48L; 302 //*_high = 100 * 1000000L; 303 return B_OK; 304 } 305 306 307 bool 308 is_mode_supported(display_mode* mode) 309 { 310 bool sane = true; 311 312 // Validate modeline is within a sane range 313 if (is_mode_sane(mode) != B_OK) 314 sane = false; 315 316 // TODO: is_mode_supported on *which* display? 317 uint32 crtid = 0; 318 319 // if we have edid info, check frequency adginst crt reported valid ranges 320 if (gInfo->shared_info->has_edid 321 && gDisplay[crtid]->foundRanges) { 322 323 // validate horizontal frequency range 324 uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total; 325 if (hfreq > gDisplay[crtid]->hfreqMax + 1 326 || hfreq < gDisplay[crtid]->hfreqMin - 1) { 327 //TRACE("!!! mode below falls outside of hfreq range!\n"); 328 sane = false; 329 } 330 331 // validate vertical frequency range 332 uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total 333 * mode->timing.h_total) / 1000); 334 if (vfreq > gDisplay[crtid]->vfreqMax + 1 335 || vfreq < gDisplay[crtid]->vfreqMin - 1) { 336 //TRACE("!!! mode below falls outside of vfreq range!\n"); 337 sane = false; 338 } 339 } 340 341 TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d is %s\n", 342 mode->timing.pixel_clock, mode->timing.h_display, 343 mode->timing.h_sync_start, mode->timing.h_sync_end, 344 mode->timing.h_total, mode->timing.v_display, 345 mode->timing.v_sync_start, mode->timing.v_sync_end, 346 mode->timing.v_total, 347 sane ? "OK." : "BAD, out of range!"); 348 349 return sane; 350 } 351 352 353 /* 354 * A quick sanity check of the provided display_mode 355 */ 356 status_t 357 is_mode_sane(display_mode* mode) 358 { 359 // horizontal timing 360 // validate h_sync_start is less then h_sync_end 361 if (mode->timing.h_sync_start > mode->timing.h_sync_end) { 362 TRACE("%s: ERROR: (%dx%d) " 363 "received h_sync_start greater then h_sync_end!\n", 364 __func__, mode->timing.h_display, mode->timing.v_display); 365 return B_ERROR; 366 } 367 // validate h_total is greater then h_display 368 if (mode->timing.h_total < mode->timing.h_display) { 369 TRACE("%s: ERROR: (%dx%d) " 370 "received h_total greater then h_display!\n", 371 __func__, mode->timing.h_display, mode->timing.v_display); 372 return B_ERROR; 373 } 374 375 // vertical timing 376 // validate v_start is less then v_end 377 if (mode->timing.v_sync_start > mode->timing.v_sync_end) { 378 TRACE("%s: ERROR: (%dx%d) " 379 "received v_sync_start greater then v_sync_end!\n", 380 __func__, mode->timing.h_display, mode->timing.v_display); 381 return B_ERROR; 382 } 383 // validate v_total is greater then v_display 384 if (mode->timing.v_total < mode->timing.v_display) { 385 TRACE("%s: ERROR: (%dx%d) " 386 "received v_total greater then v_display!\n", 387 __func__, mode->timing.h_display, mode->timing.v_display); 388 return B_ERROR; 389 } 390 391 // calculate refresh rate for given timings to whole int (in Hz) 392 int refresh = mode->timing.pixel_clock * 1000 393 / (mode->timing.h_total * mode->timing.v_total); 394 395 if (refresh < 30 || refresh > 250) { 396 TRACE("%s: ERROR: (%dx%d) " 397 "refresh rate of %dHz is unlikely for any kind of monitor!\n", 398 __func__, mode->timing.h_display, mode->timing.v_display, refresh); 399 return B_ERROR; 400 } 401 402 return B_OK; 403 } 404 405 406 uint32 407 get_mode_bpp(display_mode* mode) 408 { 409 // Get bitsPerPixel for given mode 410 411 switch (mode->space) { 412 case B_CMAP8: 413 return 8; 414 case B_RGB15_LITTLE: 415 return 15; 416 case B_RGB16_LITTLE: 417 return 16; 418 case B_RGB24_LITTLE: 419 case B_RGB32_LITTLE: 420 return 32; 421 } 422 ERROR("%s: Unknown colorspace for mode, guessing 32 bits per pixel\n", 423 __func__); 424 return 32; 425 } 426