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