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 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 // 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 VESA edid 114 115 TRACE("%s\n", __func__); 116 if (!gInfo->shared_info->has_edid) 117 return B_ERROR; 118 if (size < sizeof(struct edid1_info)) 119 return B_BUFFER_OVERFLOW; 120 121 memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info)); 122 // VESA 123 //memcpy(info, &gDisplay[0]->edidData, sizeof(struct edid1_info)); 124 // Display 0 125 126 *edid_version = EDID_VERSION_1; 127 128 return B_OK; 129 } 130 131 132 uint32 133 radeon_dpms_capabilities(void) 134 { 135 // These should be pretty universally supported on Radeon HD cards 136 return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; 137 } 138 139 140 uint32 141 radeon_dpms_mode(void) 142 { 143 // TODO: this really isn't a good long-term solution 144 // we may need to look at the encoder dpms scratch registers 145 return gInfo->dpms_mode; 146 } 147 148 149 void 150 radeon_dpms_set(uint8 id, int mode) 151 { 152 if (mode == B_DPMS_ON) { 153 display_crtc_dpms(id, mode); 154 encoder_dpms_set(id, mode); 155 } else { 156 encoder_dpms_set(id, mode); 157 display_crtc_dpms(id, mode); 158 } 159 gInfo->dpms_mode = mode; 160 } 161 162 163 void 164 radeon_dpms_set_hook(int mode) 165 { 166 // TODO: multi-monitor? for now we use VESA edid 167 168 // As the accelerant hook doesn't pass crtc id 169 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 170 radeon_dpms_set(id, mode); 171 } 172 } 173 174 175 status_t 176 radeon_set_display_mode(display_mode* mode) 177 { 178 // TODO: multi-monitor? For now we set the mode on 179 // all displays (this is very incorrect). This also 180 // causes a lot of problems on DisplayPort devices 181 182 // Set mode on each display 183 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 184 if (gDisplay[id]->attached == false) 185 continue; 186 187 // Copy this display mode into the "current mode" for the display 188 memcpy(&gDisplay[id]->currentMode, mode, sizeof(display_mode)); 189 190 uint32 connectorIndex = gDisplay[id]->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(id, ATOM_ENABLE); 202 radeon_dpms_set(id, B_DPMS_OFF); 203 204 // *** Set up encoder -> crtc routing 205 encoder_assign_crtc(id); 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, id); 214 215 display_crtc_set_dtd(id, mode); 216 217 display_crtc_fb_set(id, mode); 218 // atombios_overscan_setup 219 display_crtc_scale(id, mode); 220 221 // *** encoder mode set 222 encoder_mode_set(id); 223 224 // *** encoder and CRT controller commit 225 radeon_dpms_set(id, B_DPMS_ON); 226 display_crtc_lock(id, ATOM_DISABLE); 227 encoder_output_lock(false); 228 } 229 230 #ifdef TRACE_MODE 231 // for debugging 232 debug_dp_info(); 233 234 TRACE("D1CRTC_STATUS Value: 0x%X\n", 235 Read32(CRT, AVIVO_D1CRTC_STATUS)); 236 TRACE("D2CRTC_STATUS Value: 0x%X\n", 237 Read32(CRT, AVIVO_D2CRTC_STATUS)); 238 TRACE("D1CRTC_CONTROL Value: 0x%X\n", 239 Read32(CRT, AVIVO_D1CRTC_CONTROL)); 240 TRACE("D2CRTC_CONTROL Value: 0x%X\n", 241 Read32(CRT, AVIVO_D2CRTC_CONTROL)); 242 TRACE("D1GRPH_ENABLE Value: 0x%X\n", 243 Read32(CRT, AVIVO_D1GRPH_ENABLE)); 244 TRACE("D2GRPH_ENABLE Value: 0x%X\n", 245 Read32(CRT, AVIVO_D2GRPH_ENABLE)); 246 TRACE("D1SCL_ENABLE Value: 0x%X\n", 247 Read32(CRT, AVIVO_D1SCL_SCALER_ENABLE)); 248 TRACE("D2SCL_ENABLE Value: 0x%X\n", 249 Read32(CRT, AVIVO_D2SCL_SCALER_ENABLE)); 250 TRACE("D1CRTC_BLANK_CONTROL Value: 0x%X\n", 251 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); 252 TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n", 253 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); 254 #endif 255 256 return B_OK; 257 } 258 259 260 status_t 261 radeon_get_display_mode(display_mode* _currentMode) 262 { 263 TRACE("%s\n", __func__); 264 265 *_currentMode = gInfo->shared_info->current_mode; 266 //*_currentMode = gDisplay[X]->currentMode; 267 return B_OK; 268 } 269 270 271 status_t 272 radeon_get_frame_buffer_config(frame_buffer_config* config) 273 { 274 TRACE("%s\n", __func__); 275 276 config->frame_buffer = gInfo->shared_info->frame_buffer; 277 config->frame_buffer_dma = (uint8*)gInfo->shared_info->frame_buffer_phys; 278 279 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 280 281 return B_OK; 282 } 283 284 285 status_t 286 radeon_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) 287 { 288 TRACE("%s\n", __func__); 289 290 if (_low != NULL) { 291 // lower limit of about 48Hz vertical refresh 292 uint32 totalClocks = (uint32)mode->timing.h_total 293 * (uint32)mode->timing.v_total; 294 uint32 low = (totalClocks * 48L) / 1000L; 295 296 if (low < PLL_MIN_DEFAULT) 297 low = PLL_MIN_DEFAULT; 298 else if (low > PLL_MAX_DEFAULT) 299 return B_ERROR; 300 301 *_low = low; 302 } 303 304 if (_high != NULL) 305 *_high = PLL_MAX_DEFAULT; 306 307 //*_low = 48L; 308 //*_high = 100 * 1000000L; 309 return B_OK; 310 } 311 312 313 bool 314 is_mode_supported(display_mode* mode) 315 { 316 bool sane = true; 317 318 // Validate modeline is within a sane range 319 if (is_mode_sane(mode) != B_OK) 320 sane = false; 321 322 // TODO: is_mode_supported on *which* display? 323 uint32 crtid = 0; 324 325 // if we have edid info, check frequency adginst crt reported valid ranges 326 if (gInfo->shared_info->has_edid 327 && gDisplay[crtid]->foundRanges) { 328 329 // validate horizontal frequency range 330 uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total; 331 if (hfreq > gDisplay[crtid]->hfreqMax + 1 332 || hfreq < gDisplay[crtid]->hfreqMin - 1) { 333 //TRACE("!!! mode below falls outside of hfreq range!\n"); 334 sane = false; 335 } 336 337 // validate vertical frequency range 338 uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total 339 * mode->timing.h_total) / 1000); 340 if (vfreq > gDisplay[crtid]->vfreqMax + 1 341 || vfreq < gDisplay[crtid]->vfreqMin - 1) { 342 //TRACE("!!! mode below falls outside of vfreq range!\n"); 343 sane = false; 344 } 345 } 346 347 TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d is %s\n", 348 mode->timing.pixel_clock, mode->timing.h_display, 349 mode->timing.h_sync_start, mode->timing.h_sync_end, 350 mode->timing.h_total, mode->timing.v_display, 351 mode->timing.v_sync_start, mode->timing.v_sync_end, 352 mode->timing.v_total, 353 sane ? "OK." : "BAD, out of range!"); 354 355 return sane; 356 } 357 358 359 /* 360 * A quick sanity check of the provided display_mode 361 */ 362 status_t 363 is_mode_sane(display_mode* mode) 364 { 365 // horizontal timing 366 // validate h_sync_start is less then h_sync_end 367 if (mode->timing.h_sync_start > mode->timing.h_sync_end) { 368 TRACE("%s: ERROR: (%dx%d) " 369 "received h_sync_start greater then h_sync_end!\n", 370 __func__, mode->timing.h_display, mode->timing.v_display); 371 return B_ERROR; 372 } 373 // validate h_total is greater then h_display 374 if (mode->timing.h_total < mode->timing.h_display) { 375 TRACE("%s: ERROR: (%dx%d) " 376 "received h_total greater then h_display!\n", 377 __func__, mode->timing.h_display, mode->timing.v_display); 378 return B_ERROR; 379 } 380 381 // vertical timing 382 // validate v_start is less then v_end 383 if (mode->timing.v_sync_start > mode->timing.v_sync_end) { 384 TRACE("%s: ERROR: (%dx%d) " 385 "received v_sync_start greater then v_sync_end!\n", 386 __func__, mode->timing.h_display, mode->timing.v_display); 387 return B_ERROR; 388 } 389 // validate v_total is greater then v_display 390 if (mode->timing.v_total < mode->timing.v_display) { 391 TRACE("%s: ERROR: (%dx%d) " 392 "received v_total greater then v_display!\n", 393 __func__, mode->timing.h_display, mode->timing.v_display); 394 return B_ERROR; 395 } 396 397 // calculate refresh rate for given timings to whole int (in Hz) 398 int refresh = mode->timing.pixel_clock * 1000 399 / (mode->timing.h_total * mode->timing.v_total); 400 401 if (refresh < 30 || refresh > 250) { 402 TRACE("%s: ERROR: (%dx%d) " 403 "refresh rate of %dHz is unlikely for any kind of monitor!\n", 404 __func__, mode->timing.h_display, mode->timing.v_display, refresh); 405 return B_ERROR; 406 } 407 408 return B_OK; 409 } 410 411 412 uint32 413 get_mode_bpp(display_mode* mode) 414 { 415 // Get bitsPerPixel for given mode 416 417 switch (mode->space) { 418 case B_CMAP8: 419 return 8; 420 case B_RGB15_LITTLE: 421 return 15; 422 case B_RGB16_LITTLE: 423 return 16; 424 case B_RGB24_LITTLE: 425 case B_RGB32_LITTLE: 426 return 32; 427 } 428 ERROR("%s: Unknown colorspace for mode, guessing 32 bits per pixel\n", 429 __func__); 430 return 32; 431 } 432