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 status_t 43 create_mode_list(void) 44 { 45 // TODO: multi-monitor? for now we use VESA and not gDisplay edid 46 47 const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE, 48 B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8}; 49 50 gInfo->mode_list_area = create_display_modes("radeon HD modes", 51 gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL, 52 NULL, 0, kRadeonHDSpaces, 53 sizeof(kRadeonHDSpaces) / sizeof(kRadeonHDSpaces[0]), 54 is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count); 55 if (gInfo->mode_list_area < B_OK) 56 return gInfo->mode_list_area; 57 58 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 59 60 return B_OK; 61 } 62 63 64 // #pragma mark - 65 66 67 uint32 68 radeon_accelerant_mode_count(void) 69 { 70 TRACE("%s\n", __func__); 71 72 return gInfo->shared_info->mode_count; 73 } 74 75 76 status_t 77 radeon_get_mode_list(display_mode* modeList) 78 { 79 TRACE("%s\n", __func__); 80 memcpy(modeList, gInfo->mode_list, 81 gInfo->shared_info->mode_count * sizeof(display_mode)); 82 return B_OK; 83 } 84 85 86 status_t 87 radeon_get_edid_info(void* info, size_t size, uint32* edid_version) 88 { 89 // TODO: multi-monitor? for now we use VESA edid 90 91 TRACE("%s\n", __func__); 92 if (!gInfo->shared_info->has_edid) 93 return B_ERROR; 94 if (size < sizeof(struct edid1_info)) 95 return B_BUFFER_OVERFLOW; 96 97 memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info)); 98 // VESA 99 //memcpy(info, &gDisplay[0]->edid_info, sizeof(struct edid1_info)); 100 // BitBanged display 0 101 102 *edid_version = EDID_VERSION_1; 103 104 return B_OK; 105 } 106 107 108 uint32 109 radeon_dpms_capabilities(void) 110 { 111 // These should be pretty universally supported on Radeon HD cards 112 return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; 113 } 114 115 116 uint32 117 radeon_dpms_mode(void) 118 { 119 // TODO: this really isn't a good long-term solution 120 // we may need to look at the encoder dpms scratch registers 121 return gInfo->dpms_mode; 122 } 123 124 125 void 126 radeon_dpms_set(int mode) 127 { 128 radeon_shared_info &info = *gInfo->shared_info; 129 130 switch (mode) { 131 case B_DPMS_ON: 132 TRACE("%s: ON\n", __func__); 133 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 134 if (gDisplay[id]->active == false) 135 continue; 136 encoder_output_lock(true); 137 encoder_dpms_set(id, mode); 138 encoder_output_lock(false); 139 display_crtc_lock(id, ATOM_ENABLE); 140 display_crtc_power(id, ATOM_ENABLE); 141 if (info.dceMajor >= 3) 142 display_crtc_memreq(id, ATOM_ENABLE); 143 display_crtc_blank(id, ATOM_BLANKING_OFF); 144 display_crtc_lock(id, ATOM_DISABLE); 145 } 146 break; 147 case B_DPMS_STAND_BY: 148 case B_DPMS_SUSPEND: 149 case B_DPMS_OFF: 150 TRACE("%s: OFF\n", __func__); 151 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 152 if (gDisplay[id]->active == false) 153 continue; 154 display_crtc_lock(id, ATOM_ENABLE); 155 display_crtc_blank(id, ATOM_BLANKING); 156 if (info.dceMajor >= 3) 157 display_crtc_memreq(id, ATOM_DISABLE); 158 display_crtc_power(id, ATOM_DISABLE); 159 display_crtc_lock(id, ATOM_DISABLE); 160 encoder_output_lock(true); 161 encoder_dpms_set(id, mode); 162 encoder_output_lock(false); 163 } 164 break; 165 } 166 gInfo->dpms_mode = mode; 167 } 168 169 170 status_t 171 radeon_set_display_mode(display_mode* mode) 172 { 173 radeon_shared_info &info = *gInfo->shared_info; 174 175 // Set mode on each display 176 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 177 if (gDisplay[id]->active == false) 178 continue; 179 180 uint16 connectorIndex = gDisplay[id]->connectorIndex; 181 182 // Determine DP lanes if DP 183 if (connector_is_dp(connectorIndex)) 184 gDPInfo[connectorIndex]->laneCount 185 = dp_get_lane_count(connectorIndex, mode); 186 187 // *** encoder prep 188 encoder_output_lock(true); 189 encoder_dpms_set(id, B_DPMS_OFF); 190 encoder_assign_crtc(id); 191 192 // *** CRT controler prep 193 display_crtc_lock(id, ATOM_ENABLE); 194 display_crtc_blank(id, ATOM_BLANKING); 195 if (info.dceMajor >= 3) 196 display_crtc_memreq(id, ATOM_DISABLE); 197 display_crtc_power(id, ATOM_DISABLE); 198 199 // *** CRT controler mode set 200 // TODO: program SS 201 pll_set(ATOM_PPLL1, mode->timing.pixel_clock, id); 202 // TODO: check if ATOM_PPLL1 is used and use ATOM_PPLL2 if so 203 display_crtc_set_dtd(id, mode); 204 205 display_crtc_fb_set(id, mode); 206 // atombios_overscan_setup 207 display_crtc_scale(id, mode); 208 209 // *** encoder mode set 210 encoder_mode_set(id, mode->timing.pixel_clock); 211 212 // *** CRT controler commit 213 display_crtc_power(id, ATOM_ENABLE); 214 if (info.dceMajor >= 3) 215 display_crtc_memreq(id, ATOM_ENABLE); 216 display_crtc_blank(id, ATOM_BLANKING_OFF); 217 display_crtc_lock(id, ATOM_DISABLE); 218 219 // *** encoder commit 220 221 // handle DisplayPort link training 222 if (connector_is_dp(connectorIndex)) { 223 if (info.dceMajor >= 4) 224 encoder_dig_setup(connectorIndex, 225 ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); 226 227 dp_link_train(id, mode); 228 229 if (info.dceMajor >= 4) 230 encoder_dig_setup(connectorIndex, 231 ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); 232 } 233 234 encoder_dpms_set(id, B_DPMS_ON); 235 encoder_output_lock(false); 236 } 237 238 // for debugging 239 TRACE("D1CRTC_STATUS Value: 0x%X\n", Read32(CRT, D1CRTC_STATUS)); 240 TRACE("D2CRTC_STATUS Value: 0x%X\n", Read32(CRT, D2CRTC_STATUS)); 241 TRACE("D1CRTC_CONTROL Value: 0x%X\n", Read32(CRT, D1CRTC_CONTROL)); 242 TRACE("D2CRTC_CONTROL Value: 0x%X\n", Read32(CRT, D2CRTC_CONTROL)); 243 TRACE("D1GRPH_ENABLE Value: 0x%X\n", 244 Read32(CRT, AVIVO_D1GRPH_ENABLE)); 245 TRACE("D2GRPH_ENABLE Value: 0x%X\n", 246 Read32(CRT, AVIVO_D2GRPH_ENABLE)); 247 TRACE("D1SCL_ENABLE Value: 0x%X\n", 248 Read32(CRT, AVIVO_D1SCL_SCALER_ENABLE)); 249 TRACE("D2SCL_ENABLE Value: 0x%X\n", 250 Read32(CRT, AVIVO_D2SCL_SCALER_ENABLE)); 251 TRACE("D1CRTC_BLANK_CONTROL Value: 0x%X\n", 252 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); 253 TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n", 254 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); 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 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]->found_ranges) { 327 328 // validate horizontal frequency range 329 uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total; 330 if (hfreq > gDisplay[crtid]->hfreq_max + 1 331 || hfreq < gDisplay[crtid]->hfreq_min - 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]->vfreq_max + 1 340 || vfreq < gDisplay[crtid]->vfreq_min - 1) { 341 //TRACE("!!! mode below falls outside of vfreq range!\n"); 342 sane = false; 343 } 344 } 345 346 TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d is %s\n", 347 mode->timing.pixel_clock, mode->timing.h_display, 348 mode->timing.h_sync_start, mode->timing.h_sync_end, 349 mode->timing.h_total, mode->timing.v_display, 350 mode->timing.v_sync_start, mode->timing.v_sync_end, 351 mode->timing.v_total, 352 sane ? "OK." : "BAD, out of range!"); 353 354 return sane; 355 } 356 357 358 /* 359 * A quick sanity check of the provided display_mode 360 */ 361 status_t 362 is_mode_sane(display_mode* mode) 363 { 364 // horizontal timing 365 // validate h_sync_start is less then h_sync_end 366 if (mode->timing.h_sync_start > mode->timing.h_sync_end) { 367 TRACE("%s: ERROR: (%dx%d) " 368 "received h_sync_start greater then h_sync_end!\n", 369 __func__, mode->timing.h_display, mode->timing.v_display); 370 return B_ERROR; 371 } 372 // validate h_total is greater then h_display 373 if (mode->timing.h_total < mode->timing.h_display) { 374 TRACE("%s: ERROR: (%dx%d) " 375 "received h_total greater then h_display!\n", 376 __func__, mode->timing.h_display, mode->timing.v_display); 377 return B_ERROR; 378 } 379 380 // vertical timing 381 // validate v_start is less then v_end 382 if (mode->timing.v_sync_start > mode->timing.v_sync_end) { 383 TRACE("%s: ERROR: (%dx%d) " 384 "received v_sync_start greater then v_sync_end!\n", 385 __func__, mode->timing.h_display, mode->timing.v_display); 386 return B_ERROR; 387 } 388 // validate v_total is greater then v_display 389 if (mode->timing.v_total < mode->timing.v_display) { 390 TRACE("%s: ERROR: (%dx%d) " 391 "received v_total greater then v_display!\n", 392 __func__, mode->timing.h_display, mode->timing.v_display); 393 return B_ERROR; 394 } 395 396 // calculate refresh rate for given timings to whole int (in Hz) 397 int refresh = mode->timing.pixel_clock * 1000 398 / (mode->timing.h_total * mode->timing.v_total); 399 400 if (refresh < 30 || refresh > 250) { 401 TRACE("%s: ERROR: (%dx%d) " 402 "refresh rate of %dHz is unlikely for any kind of monitor!\n", 403 __func__, mode->timing.h_display, mode->timing.v_display, refresh); 404 return B_ERROR; 405 } 406 407 return B_OK; 408 } 409 410 411 uint32 412 get_mode_bpp(display_mode* mode) 413 { 414 // Get bitsPerPixel for given mode 415 416 switch (mode->space) { 417 case B_CMAP8: 418 return 8; 419 case B_RGB15_LITTLE: 420 return 15; 421 case B_RGB16_LITTLE: 422 return 16; 423 case B_RGB24_LITTLE: 424 case B_RGB32_LITTLE: 425 return 32; 426 } 427 ERROR("%s: Unknown colorspace for mode, guessing 32 bits per pixel\n", 428 __func__); 429 return 32; 430 } 431