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 "accelerant_protos.h" 15 #include "accelerant.h" 16 #include "bios.h" 17 #include "utility.h" 18 #include "mode.h" 19 #include "display.h" 20 #include "pll.h" 21 22 #include <stdio.h> 23 #include <string.h> 24 #include <math.h> 25 26 #include <create_display_modes.h> 27 28 29 #define TRACE_MODE 30 #ifdef TRACE_MODE 31 extern "C" void _sPrintf(const char *format, ...); 32 # define TRACE(x...) _sPrintf("radeon_hd: " x) 33 #else 34 # define TRACE(x...) ; 35 #endif 36 37 38 status_t 39 create_mode_list(void) 40 { 41 // TODO: multi-monitor? for now we use VESA and not gDisplay edid 42 43 const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE, 44 B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8}; 45 46 gInfo->mode_list_area = create_display_modes("radeon HD modes", 47 gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL, 48 NULL, 0, kRadeonHDSpaces, 49 sizeof(kRadeonHDSpaces) / sizeof(kRadeonHDSpaces[0]), 50 is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count); 51 if (gInfo->mode_list_area < B_OK) 52 return gInfo->mode_list_area; 53 54 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 55 56 return B_OK; 57 } 58 59 60 // #pragma mark - 61 62 63 uint32 64 radeon_accelerant_mode_count(void) 65 { 66 TRACE("%s\n", __func__); 67 68 return gInfo->shared_info->mode_count; 69 } 70 71 72 status_t 73 radeon_get_mode_list(display_mode *modeList) 74 { 75 TRACE("%s\n", __func__); 76 memcpy(modeList, gInfo->mode_list, 77 gInfo->shared_info->mode_count * sizeof(display_mode)); 78 return B_OK; 79 } 80 81 82 status_t 83 radeon_get_edid_info(void* info, size_t size, uint32* edid_version) 84 { 85 // TODO: multi-monitor? for now we use VESA edid 86 87 TRACE("%s\n", __func__); 88 if (!gInfo->shared_info->has_edid) 89 return B_ERROR; 90 if (size < sizeof(struct edid1_info)) 91 return B_BUFFER_OVERFLOW; 92 93 memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info)); 94 // VESA 95 //memcpy(info, &gDisplay[0]->edid_info, sizeof(struct edid1_info)); 96 // BitBanged display 0 97 98 *edid_version = EDID_VERSION_1; 99 100 return B_OK; 101 } 102 103 104 uint32 105 radeon_dpms_capabilities(void) 106 { 107 // These should be pretty universally supported on Radeon HD cards 108 return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; 109 } 110 111 112 uint32 113 radeon_dpms_mode(void) 114 { 115 // TODO: this really isn't a good long-term solution 116 // we may need to look at the encoder dpms scratch registers 117 return gInfo->dpms_mode; 118 } 119 120 121 void 122 radeon_dpms_set(int mode) 123 { 124 radeon_shared_info &info = *gInfo->shared_info; 125 126 switch(mode) { 127 case B_DPMS_ON: 128 TRACE("%s: ON\n", __func__); 129 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 130 if (gDisplay[id]->active == false) 131 continue; 132 display_crtc_lock(id, ATOM_ENABLE); 133 display_crtc_power(id, ATOM_ENABLE); 134 if (info.dceMajor >= 3) 135 display_crtc_memreq(id, ATOM_ENABLE); 136 display_crtc_blank(id, ATOM_BLANKING_OFF); 137 display_crtc_lock(id, ATOM_DISABLE); 138 } 139 break; 140 case B_DPMS_STAND_BY: 141 case B_DPMS_SUSPEND: 142 case B_DPMS_OFF: 143 TRACE("%s: OFF\n", __func__); 144 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 145 if (gDisplay[id]->active == false) 146 continue; 147 display_crtc_lock(id, ATOM_ENABLE); 148 display_crtc_blank(id, ATOM_BLANKING); 149 if (info.dceMajor >= 3) 150 display_crtc_memreq(id, ATOM_DISABLE); 151 display_crtc_power(id, ATOM_DISABLE); 152 display_crtc_lock(id, ATOM_DISABLE); 153 } 154 break; 155 } 156 gInfo->dpms_mode = mode; 157 } 158 159 160 status_t 161 radeon_set_display_mode(display_mode *mode) 162 { 163 radeon_shared_info &info = *gInfo->shared_info; 164 165 // Set mode on each display 166 for (uint8 id = 0; id < MAX_DISPLAY; id++) { 167 if (gDisplay[id]->active == false) 168 continue; 169 170 uint16 connectorIndex = gDisplay[id]->connectorIndex; 171 172 // *** encoder prep 173 encoder_output_lock(true); 174 encoder_dpms_set(id, gConnector[connectorIndex]->encoder.objectID, 175 B_DPMS_OFF); 176 encoder_assign_crtc(id); 177 178 // *** CRT controler prep 179 display_crtc_lock(id, ATOM_ENABLE); 180 display_crtc_blank(id, ATOM_BLANKING); 181 if (info.dceMajor >= 3) 182 display_crtc_memreq(id, ATOM_DISABLE); 183 display_crtc_power(id, ATOM_DISABLE); 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_power(id, ATOM_ENABLE); 200 if (info.dceMajor >= 3) 201 display_crtc_memreq(id, ATOM_ENABLE); 202 display_crtc_blank(id, ATOM_BLANKING_OFF); 203 display_crtc_lock(id, ATOM_DISABLE); 204 205 // *** encoder commit 206 encoder_dpms_set(id, gConnector[connectorIndex]->encoder.objectID, 207 B_DPMS_ON); 208 encoder_output_lock(false); 209 } 210 211 // for debugging 212 TRACE("D1CRTC_STATUS Value: 0x%X\n", Read32(CRT, D1CRTC_STATUS)); 213 TRACE("D2CRTC_STATUS Value: 0x%X\n", Read32(CRT, D2CRTC_STATUS)); 214 TRACE("D1CRTC_CONTROL Value: 0x%X\n", Read32(CRT, D1CRTC_CONTROL)); 215 TRACE("D2CRTC_CONTROL Value: 0x%X\n", Read32(CRT, D2CRTC_CONTROL)); 216 TRACE("D1GRPH_ENABLE Value: 0x%X\n", 217 Read32(CRT, AVIVO_D1GRPH_ENABLE)); 218 TRACE("D2GRPH_ENABLE Value: 0x%X\n", 219 Read32(CRT, AVIVO_D2GRPH_ENABLE)); 220 TRACE("D1SCL_ENABLE Value: 0x%X\n", 221 Read32(CRT, AVIVO_D1SCL_SCALER_ENABLE)); 222 TRACE("D2SCL_ENABLE Value: 0x%X\n", 223 Read32(CRT, AVIVO_D2SCL_SCALER_ENABLE)); 224 TRACE("D1CRTC_BLANK_CONTROL Value: 0x%X\n", 225 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); 226 TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n", 227 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); 228 229 return B_OK; 230 } 231 232 233 status_t 234 radeon_get_display_mode(display_mode *_currentMode) 235 { 236 TRACE("%s\n", __func__); 237 238 *_currentMode = gInfo->shared_info->current_mode; 239 return B_OK; 240 } 241 242 243 status_t 244 radeon_get_frame_buffer_config(frame_buffer_config *config) 245 { 246 TRACE("%s\n", __func__); 247 248 config->frame_buffer = gInfo->shared_info->frame_buffer; 249 config->frame_buffer_dma = (uint8*)gInfo->shared_info->frame_buffer_phys; 250 251 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 252 253 return B_OK; 254 } 255 256 257 status_t 258 radeon_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high) 259 { 260 TRACE("%s\n", __func__); 261 262 if (_low != NULL) { 263 // lower limit of about 48Hz vertical refresh 264 uint32 totalClocks = (uint32)mode->timing.h_total 265 *(uint32)mode->timing.v_total; 266 uint32 low = (totalClocks * 48L) / 1000L; 267 268 if (low < PLL_MIN_DEFAULT) 269 low = PLL_MIN_DEFAULT; 270 else if (low > PLL_MAX_DEFAULT) 271 return B_ERROR; 272 273 *_low = low; 274 } 275 276 if (_high != NULL) 277 *_high = PLL_MAX_DEFAULT; 278 279 //*_low = 48L; 280 //*_high = 100 * 1000000L; 281 return B_OK; 282 } 283 284 285 bool 286 is_mode_supported(display_mode *mode) 287 { 288 bool sane = true; 289 290 // Validate modeline is within a sane range 291 if (is_mode_sane(mode) != B_OK) 292 sane = false; 293 294 // TODO: is_mode_supported on *which* display? 295 uint32 crtid = 0; 296 297 // if we have edid info, check frequency adginst crt reported valid ranges 298 if (gInfo->shared_info->has_edid 299 && gDisplay[crtid]->found_ranges) { 300 301 // validate horizontal frequency range 302 uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total; 303 if (hfreq > gDisplay[crtid]->hfreq_max + 1 304 || hfreq < gDisplay[crtid]->hfreq_min - 1) { 305 //TRACE("!!! mode below falls outside of hfreq range!\n"); 306 sane = false; 307 } 308 309 // validate vertical frequency range 310 uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total 311 * mode->timing.h_total) / 1000); 312 if (vfreq > gDisplay[crtid]->vfreq_max + 1 313 || vfreq < gDisplay[crtid]->vfreq_min - 1) { 314 //TRACE("!!! mode below falls outside of vfreq range!\n"); 315 sane = false; 316 } 317 } 318 319 TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d is %s\n", 320 mode->timing.pixel_clock, mode->timing.h_display, 321 mode->timing.h_sync_start, mode->timing.h_sync_end, 322 mode->timing.h_total, mode->timing.v_display, 323 mode->timing.v_sync_start, mode->timing.v_sync_end, 324 mode->timing.v_total, 325 sane ? "OK." : "BAD, out of range!"); 326 327 return sane; 328 } 329 330 331 /* 332 * A quick sanity check of the provided display_mode 333 */ 334 status_t 335 is_mode_sane(display_mode *mode) 336 { 337 // horizontal timing 338 // validate h_sync_start is less then h_sync_end 339 if (mode->timing.h_sync_start > mode->timing.h_sync_end) { 340 TRACE("%s: ERROR: (%dx%d) " 341 "received h_sync_start greater then h_sync_end!\n", 342 __func__, mode->timing.h_display, mode->timing.v_display); 343 return B_ERROR; 344 } 345 // validate h_total is greater then h_display 346 if (mode->timing.h_total < mode->timing.h_display) { 347 TRACE("%s: ERROR: (%dx%d) " 348 "received h_total greater then h_display!\n", 349 __func__, mode->timing.h_display, mode->timing.v_display); 350 return B_ERROR; 351 } 352 353 // vertical timing 354 // validate v_start is less then v_end 355 if (mode->timing.v_sync_start > mode->timing.v_sync_end) { 356 TRACE("%s: ERROR: (%dx%d) " 357 "received v_sync_start greater then v_sync_end!\n", 358 __func__, mode->timing.h_display, mode->timing.v_display); 359 return B_ERROR; 360 } 361 // validate v_total is greater then v_display 362 if (mode->timing.v_total < mode->timing.v_display) { 363 TRACE("%s: ERROR: (%dx%d) " 364 "received v_total greater then v_display!\n", 365 __func__, mode->timing.h_display, mode->timing.v_display); 366 return B_ERROR; 367 } 368 369 // calculate refresh rate for given timings to whole int (in Hz) 370 int refresh = mode->timing.pixel_clock * 1000 371 / (mode->timing.h_total * mode->timing.v_total); 372 373 if (refresh < 30 || refresh > 250) { 374 TRACE("%s: ERROR: (%dx%d) " 375 "refresh rate of %dHz is unlikely for any kind of monitor!\n", 376 __func__, mode->timing.h_display, mode->timing.v_display, refresh); 377 return B_ERROR; 378 } 379 380 return B_OK; 381 } 382 383 384