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