1a90ebd77SClemens Zeidler /* 2d5c3acacSAlexander von Gluck IV * Copyright 2006-2011, Haiku, Inc. All Rights Reserved. 3a90ebd77SClemens Zeidler * Distributed under the terms of the MIT License. 4a90ebd77SClemens Zeidler * 5a90ebd77SClemens Zeidler * Support for i915 chipset and up based on the X driver, 6a90ebd77SClemens Zeidler * Copyright 2006-2007 Intel Corporation. 7a90ebd77SClemens Zeidler * 8a90ebd77SClemens Zeidler * Authors: 9a90ebd77SClemens Zeidler * Axel Dörfler, axeld@pinc-software.de 10d5c3acacSAlexander von Gluck IV * Alexander von Gluck, kallisti5@unixzen.com 11a90ebd77SClemens Zeidler */ 12a90ebd77SClemens Zeidler 13a90ebd77SClemens Zeidler 14a90ebd77SClemens Zeidler #include "accelerant_protos.h" 15a90ebd77SClemens Zeidler #include "accelerant.h" 16d77ff85eSAlexander von Gluck IV #include "bios.h" 17a90ebd77SClemens Zeidler #include "utility.h" 18d5c3acacSAlexander von Gluck IV #include "mode.h" 196ab8261bSAlexander von Gluck IV #include "display.h" 20a90ebd77SClemens Zeidler 21a90ebd77SClemens Zeidler #include <stdio.h> 22a90ebd77SClemens Zeidler #include <string.h> 23a90ebd77SClemens Zeidler #include <math.h> 24a90ebd77SClemens Zeidler 25192781ddSAlexander von Gluck IV #include <create_display_modes.h> 26192781ddSAlexander von Gluck IV 27a90ebd77SClemens Zeidler 28a90ebd77SClemens Zeidler #define TRACE_MODE 29a90ebd77SClemens Zeidler #ifdef TRACE_MODE 30a90ebd77SClemens Zeidler extern "C" void _sPrintf(const char *format, ...); 31d5c3acacSAlexander von Gluck IV # define TRACE(x...) _sPrintf("radeon_hd: " x) 32a90ebd77SClemens Zeidler #else 33d5c3acacSAlexander von Gluck IV # define TRACE(x...) ; 34a90ebd77SClemens Zeidler #endif 35a90ebd77SClemens Zeidler 36a90ebd77SClemens Zeidler 37a90ebd77SClemens Zeidler status_t 38a90ebd77SClemens Zeidler create_mode_list(void) 39a90ebd77SClemens Zeidler { 40192781ddSAlexander von Gluck IV const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE, 41192781ddSAlexander von Gluck IV B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8}; 42a90ebd77SClemens Zeidler 43192781ddSAlexander von Gluck IV gInfo->mode_list_area = create_display_modes("radeon HD modes", 442613175eSAlexander von Gluck IV gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL, 452613175eSAlexander von Gluck IV NULL, 0, kRadeonHDSpaces, 46192781ddSAlexander von Gluck IV sizeof(kRadeonHDSpaces) / sizeof(kRadeonHDSpaces[0]), 47192781ddSAlexander von Gluck IV is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count); 48192781ddSAlexander von Gluck IV if (gInfo->mode_list_area < B_OK) 49192781ddSAlexander von Gluck IV return gInfo->mode_list_area; 50a90ebd77SClemens Zeidler 51192781ddSAlexander von Gluck IV gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 52d5c3acacSAlexander von Gluck IV 53a90ebd77SClemens Zeidler return B_OK; 54a90ebd77SClemens Zeidler } 55a90ebd77SClemens Zeidler 56a90ebd77SClemens Zeidler 57a90ebd77SClemens Zeidler // #pragma mark - 58a90ebd77SClemens Zeidler 59a90ebd77SClemens Zeidler 60a90ebd77SClemens Zeidler uint32 61a90ebd77SClemens Zeidler radeon_accelerant_mode_count(void) 62a90ebd77SClemens Zeidler { 63333bd770SAlexander von Gluck IV TRACE("%s\n", __func__); 64a90ebd77SClemens Zeidler 65a90ebd77SClemens Zeidler return gInfo->shared_info->mode_count; 66a90ebd77SClemens Zeidler } 67a90ebd77SClemens Zeidler 68a90ebd77SClemens Zeidler 69a90ebd77SClemens Zeidler status_t 70a90ebd77SClemens Zeidler radeon_get_mode_list(display_mode *modeList) 71a90ebd77SClemens Zeidler { 72333bd770SAlexander von Gluck IV TRACE("%s\n", __func__); 73a90ebd77SClemens Zeidler memcpy(modeList, gInfo->mode_list, 74a90ebd77SClemens Zeidler gInfo->shared_info->mode_count * sizeof(display_mode)); 75a90ebd77SClemens Zeidler return B_OK; 76a90ebd77SClemens Zeidler } 77a90ebd77SClemens Zeidler 78a90ebd77SClemens Zeidler 7988bfef92SAlexander von Gluck IV status_t 8088bfef92SAlexander von Gluck IV radeon_get_edid_info(void* info, size_t size, uint32* edid_version) 8188bfef92SAlexander von Gluck IV { 8288bfef92SAlexander von Gluck IV TRACE("%s\n", __func__); 8388bfef92SAlexander von Gluck IV if (!gInfo->shared_info->has_edid) 8488bfef92SAlexander von Gluck IV return B_ERROR; 8588bfef92SAlexander von Gluck IV if (size < sizeof(struct edid1_info)) 8688bfef92SAlexander von Gluck IV return B_BUFFER_OVERFLOW; 8788bfef92SAlexander von Gluck IV 8888bfef92SAlexander von Gluck IV memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info)); 8988bfef92SAlexander von Gluck IV *edid_version = EDID_VERSION_1; 9088bfef92SAlexander von Gluck IV 9188bfef92SAlexander von Gluck IV return B_OK; 9288bfef92SAlexander von Gluck IV } 9388bfef92SAlexander von Gluck IV 9488bfef92SAlexander von Gluck IV 95a90ebd77SClemens Zeidler status_t 96a90ebd77SClemens Zeidler radeon_set_display_mode(display_mode *mode) 97a90ebd77SClemens Zeidler { 986ab8261bSAlexander von Gluck IV // TODO : We set the same VESA EDID mode on each display 99e7e76b29SAlexander von Gluck IV 1006ab8261bSAlexander von Gluck IV // Set mode on each display 1016ab8261bSAlexander von Gluck IV for (uint8 id = 0; id < MAX_DISPLAY; id++) { 102*6da3f7d4SAlexander von Gluck IV display_crtc_lock(id, ATOM_ENABLE); 1036ab8261bSAlexander von Gluck IV // Skip if display is inactive 1046ab8261bSAlexander von Gluck IV if (gDisplay[id]->active == false) { 105*6da3f7d4SAlexander von Gluck IV display_crtc_blank(id, ATOM_ENABLE); 106*6da3f7d4SAlexander von Gluck IV display_crtc_power(id, ATOM_DISABLE); 107*6da3f7d4SAlexander von Gluck IV display_crtc_lock(id, ATOM_DISABLE); 1086ab8261bSAlexander von Gluck IV continue; 10995e1d7e8SAlexander von Gluck IV } 110f2fe29a0SAlexander von Gluck IV 111*6da3f7d4SAlexander von Gluck IV //pll_set(gDisplay[id]->connection_id, 112*6da3f7d4SAlexander von Gluck IV // mode->timing.pixel_clock, id); 1136ab8261bSAlexander von Gluck IV 114*6da3f7d4SAlexander von Gluck IV // Program CRT Controller 115*6da3f7d4SAlexander von Gluck IV display_crtc_set_dtd(id, mode); 116*6da3f7d4SAlexander von Gluck IV //display_crtc_fb_set_dce1(id, mode); 117*6da3f7d4SAlexander von Gluck IV display_crtc_fb_set_legacy(id, mode); 118*6da3f7d4SAlexander von Gluck IV display_crtc_scale(id, mode); 1196ab8261bSAlexander von Gluck IV 1206ab8261bSAlexander von Gluck IV // Program connector controllers 1216ab8261bSAlexander von Gluck IV switch (gDisplay[id]->connection_type) { 1226ab8261bSAlexander von Gluck IV case CONNECTION_DAC: 1236ab8261bSAlexander von Gluck IV DACSet(gDisplay[id]->connection_id, id); 1246ab8261bSAlexander von Gluck IV break; 1256ab8261bSAlexander von Gluck IV case CONNECTION_TMDS: 1266ab8261bSAlexander von Gluck IV TMDSSet(gDisplay[id]->connection_id, mode); 1276ab8261bSAlexander von Gluck IV break; 1286ab8261bSAlexander von Gluck IV case CONNECTION_LVDS: 1296ab8261bSAlexander von Gluck IV LVDSSet(gDisplay[id]->connection_id, mode); 1306ab8261bSAlexander von Gluck IV break; 1316ab8261bSAlexander von Gluck IV } 1326ab8261bSAlexander von Gluck IV 1336ab8261bSAlexander von Gluck IV // Power CRT Controller 134*6da3f7d4SAlexander von Gluck IV display_crtc_blank(id, ATOM_DISABLE); 135*6da3f7d4SAlexander von Gluck IV display_crtc_power(id, ATOM_ENABLE); 136*6da3f7d4SAlexander von Gluck IV 137*6da3f7d4SAlexander von Gluck IV PLLPower(gDisplay[id]->connection_id, RHD_POWER_ON); 1386ab8261bSAlexander von Gluck IV 1396ab8261bSAlexander von Gluck IV // Power connector controllers 1406ab8261bSAlexander von Gluck IV switch (gDisplay[id]->connection_type) { 1416ab8261bSAlexander von Gluck IV case CONNECTION_DAC: 1426ab8261bSAlexander von Gluck IV DACPower(gDisplay[id]->connection_id, RHD_POWER_ON); 1436ab8261bSAlexander von Gluck IV break; 1446ab8261bSAlexander von Gluck IV case CONNECTION_TMDS: 1456ab8261bSAlexander von Gluck IV TMDSPower(gDisplay[id]->connection_id, RHD_POWER_ON); 1466ab8261bSAlexander von Gluck IV break; 1476ab8261bSAlexander von Gluck IV case CONNECTION_LVDS: 1486ab8261bSAlexander von Gluck IV LVDSPower(gDisplay[id]->connection_id, RHD_POWER_ON); 1496ab8261bSAlexander von Gluck IV break; 1506ab8261bSAlexander von Gluck IV } 151*6da3f7d4SAlexander von Gluck IV 152*6da3f7d4SAlexander von Gluck IV display_crtc_lock(id, ATOM_DISABLE); 153*6da3f7d4SAlexander von Gluck IV // commit 1546ab8261bSAlexander von Gluck IV } 1556604b1b6SAlexander von Gluck IV 156aa2a6e33SAlexander von Gluck IV int32 crtstatus = Read32(CRT, D1CRTC_STATUS); 1575f6744a8SAlexander von Gluck IV TRACE("CRT0 Status: 0x%X\n", crtstatus); 158f2fe29a0SAlexander von Gluck IV crtstatus = Read32(CRT, D2CRTC_STATUS); 159f2fe29a0SAlexander von Gluck IV TRACE("CRT1 Status: 0x%X\n", crtstatus); 1603be5e036SAlexander von Gluck IV 161a90ebd77SClemens Zeidler return B_OK; 162a90ebd77SClemens Zeidler } 163a90ebd77SClemens Zeidler 164a90ebd77SClemens Zeidler 165a90ebd77SClemens Zeidler status_t 166a90ebd77SClemens Zeidler radeon_get_display_mode(display_mode *_currentMode) 167a90ebd77SClemens Zeidler { 168d5c3acacSAlexander von Gluck IV TRACE("%s\n", __func__); 169a90ebd77SClemens Zeidler 170192781ddSAlexander von Gluck IV *_currentMode = gInfo->shared_info->current_mode; 171a90ebd77SClemens Zeidler return B_OK; 172a90ebd77SClemens Zeidler } 173a90ebd77SClemens Zeidler 174a90ebd77SClemens Zeidler 175a90ebd77SClemens Zeidler status_t 176a90ebd77SClemens Zeidler radeon_get_frame_buffer_config(frame_buffer_config *config) 177a90ebd77SClemens Zeidler { 178d5c3acacSAlexander von Gluck IV TRACE("%s\n", __func__); 179a90ebd77SClemens Zeidler 1803be5e036SAlexander von Gluck IV config->frame_buffer = gInfo->shared_info->frame_buffer; 1813be5e036SAlexander von Gluck IV config->frame_buffer_dma = (uint8 *)gInfo->shared_info->frame_buffer_phys; 18251a43d0fSAlexander von Gluck IV 183a90ebd77SClemens Zeidler config->bytes_per_row = gInfo->shared_info->bytes_per_row; 184a90ebd77SClemens Zeidler 185a90ebd77SClemens Zeidler return B_OK; 186a90ebd77SClemens Zeidler } 187a90ebd77SClemens Zeidler 188a90ebd77SClemens Zeidler 189a90ebd77SClemens Zeidler status_t 190a90ebd77SClemens Zeidler radeon_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high) 191a90ebd77SClemens Zeidler { 192d5c3acacSAlexander von Gluck IV TRACE("%s\n", __func__); 193e7e76b29SAlexander von Gluck IV 194a90ebd77SClemens Zeidler if (_low != NULL) { 195a90ebd77SClemens Zeidler // lower limit of about 48Hz vertical refresh 1965f6744a8SAlexander von Gluck IV uint32 totalClocks = (uint32)mode->timing.h_total 1975f6744a8SAlexander von Gluck IV *(uint32)mode->timing.v_total; 198a90ebd77SClemens Zeidler uint32 low = (totalClocks * 48L) / 1000L; 199e7e76b29SAlexander von Gluck IV 200a90ebd77SClemens Zeidler if (low < gInfo->shared_info->pll_info.min_frequency) 201a90ebd77SClemens Zeidler low = gInfo->shared_info->pll_info.min_frequency; 202a90ebd77SClemens Zeidler else if (low > gInfo->shared_info->pll_info.max_frequency) 203a90ebd77SClemens Zeidler return B_ERROR; 204a90ebd77SClemens Zeidler 205a90ebd77SClemens Zeidler *_low = low; 206a90ebd77SClemens Zeidler } 207a90ebd77SClemens Zeidler 208a90ebd77SClemens Zeidler if (_high != NULL) 209a90ebd77SClemens Zeidler *_high = gInfo->shared_info->pll_info.max_frequency; 210e7e76b29SAlexander von Gluck IV 211e7e76b29SAlexander von Gluck IV //*_low = 48L; 212e7e76b29SAlexander von Gluck IV //*_high = 100 * 1000000L; 213a90ebd77SClemens Zeidler return B_OK; 214a90ebd77SClemens Zeidler } 215a90ebd77SClemens Zeidler 216a90ebd77SClemens Zeidler 217192781ddSAlexander von Gluck IV bool 218192781ddSAlexander von Gluck IV is_mode_supported(display_mode *mode) 219192781ddSAlexander von Gluck IV { 220d1d65a79SAlexander von Gluck IV TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d\n", 221d1d65a79SAlexander von Gluck IV mode->timing.pixel_clock, mode->timing.h_display, 222d1d65a79SAlexander von Gluck IV mode->timing.h_sync_start, mode->timing.h_sync_end, 223d1d65a79SAlexander von Gluck IV mode->timing.h_total, mode->timing.v_display, 224d1d65a79SAlexander von Gluck IV mode->timing.v_sync_start, mode->timing.v_sync_end, 225d1d65a79SAlexander von Gluck IV mode->timing.v_total); 226d1d65a79SAlexander von Gluck IV 2271dac4469SAlexander von Gluck IV // Validate modeline is within a sane range 228192781ddSAlexander von Gluck IV if (is_mode_sane(mode) != B_OK) 229192781ddSAlexander von Gluck IV return false; 230192781ddSAlexander von Gluck IV 23195e1d7e8SAlexander von Gluck IV // TODO : is_mode_supported on *which* display? 232d1d65a79SAlexander von Gluck IV uint32 crtid = 0; 2331dac4469SAlexander von Gluck IV 234d1d65a79SAlexander von Gluck IV // if we have edid info, check frequency adginst crt reported valid ranges 235e1b9d6e6SAlexander von Gluck IV if (gInfo->shared_info->has_edid 236e1b9d6e6SAlexander von Gluck IV && gDisplay[crtid]->found_ranges) { 2371dac4469SAlexander von Gluck IV 238d1d65a79SAlexander von Gluck IV uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total; 23995e1d7e8SAlexander von Gluck IV if (hfreq > gDisplay[crtid]->hfreq_max + 1 24095e1d7e8SAlexander von Gluck IV || hfreq < gDisplay[crtid]->hfreq_min - 1) { 241d1d65a79SAlexander von Gluck IV TRACE("!!! hfreq : %d , hfreq_min : %d, hfreq_max : %d\n", 24295e1d7e8SAlexander von Gluck IV hfreq, gDisplay[crtid]->hfreq_min, gDisplay[crtid]->hfreq_max); 243d1d65a79SAlexander von Gluck IV TRACE("!!! %dx%d falls outside of CRT %d's valid " 244d1d65a79SAlexander von Gluck IV "horizontal range.\n", mode->timing.h_display, 245d1d65a79SAlexander von Gluck IV mode->timing.v_display, crtid); 246d1d65a79SAlexander von Gluck IV return false; 247d1d65a79SAlexander von Gluck IV } 248d1d65a79SAlexander von Gluck IV 249d1d65a79SAlexander von Gluck IV uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total 250d1d65a79SAlexander von Gluck IV * mode->timing.h_total) / 1000); 251d1d65a79SAlexander von Gluck IV 25295e1d7e8SAlexander von Gluck IV if (vfreq > gDisplay[crtid]->vfreq_max + 1 25395e1d7e8SAlexander von Gluck IV || vfreq < gDisplay[crtid]->vfreq_min - 1) { 254d1d65a79SAlexander von Gluck IV TRACE("!!! vfreq : %d , vfreq_min : %d, vfreq_max : %d\n", 25595e1d7e8SAlexander von Gluck IV vfreq, gDisplay[crtid]->vfreq_min, gDisplay[crtid]->vfreq_max); 256d1d65a79SAlexander von Gluck IV TRACE("!!! %dx%d falls outside of CRT %d's valid vertical range\n", 257d1d65a79SAlexander von Gluck IV mode->timing.h_display, mode->timing.v_display, crtid); 258d1d65a79SAlexander von Gluck IV return false; 259d1d65a79SAlexander von Gluck IV } 260e1b9d6e6SAlexander von Gluck IV } 261e1b9d6e6SAlexander von Gluck IV 262d1d65a79SAlexander von Gluck IV TRACE("%dx%d is within CRT %d's valid frequency range\n", 263d1d65a79SAlexander von Gluck IV mode->timing.h_display, mode->timing.v_display, crtid); 264192781ddSAlexander von Gluck IV 265192781ddSAlexander von Gluck IV return true; 266192781ddSAlexander von Gluck IV } 267192781ddSAlexander von Gluck IV 268192781ddSAlexander von Gluck IV 269d5c3acacSAlexander von Gluck IV /* 270d5c3acacSAlexander von Gluck IV * A quick sanity check of the provided display_mode 271d5c3acacSAlexander von Gluck IV */ 272d5c3acacSAlexander von Gluck IV status_t 273192781ddSAlexander von Gluck IV is_mode_sane(display_mode *mode) 274d5c3acacSAlexander von Gluck IV { 275333bd770SAlexander von Gluck IV // horizontal timing 276333bd770SAlexander von Gluck IV // validate h_sync_start is less then h_sync_end 277333bd770SAlexander von Gluck IV if (mode->timing.h_sync_start > mode->timing.h_sync_end) { 27891235829SAlexander von Gluck IV TRACE("%s: ERROR: (%dx%d) " 27991235829SAlexander von Gluck IV "received h_sync_start greater then h_sync_end!\n", 280333bd770SAlexander von Gluck IV __func__, mode->timing.h_display, mode->timing.v_display); 281333bd770SAlexander von Gluck IV return B_ERROR; 282333bd770SAlexander von Gluck IV } 283333bd770SAlexander von Gluck IV // validate h_total is greater then h_display 284333bd770SAlexander von Gluck IV if (mode->timing.h_total < mode->timing.h_display) { 28591235829SAlexander von Gluck IV TRACE("%s: ERROR: (%dx%d) " 28691235829SAlexander von Gluck IV "received h_total greater then h_display!\n", 287333bd770SAlexander von Gluck IV __func__, mode->timing.h_display, mode->timing.v_display); 288d5c3acacSAlexander von Gluck IV return B_ERROR; 289d5c3acacSAlexander von Gluck IV } 290d5c3acacSAlexander von Gluck IV 291333bd770SAlexander von Gluck IV // vertical timing 292333bd770SAlexander von Gluck IV // validate v_start is less then v_end 293333bd770SAlexander von Gluck IV if (mode->timing.v_sync_start > mode->timing.v_sync_end) { 29491235829SAlexander von Gluck IV TRACE("%s: ERROR: (%dx%d) " 29591235829SAlexander von Gluck IV "received v_sync_start greater then v_sync_end!\n", 296333bd770SAlexander von Gluck IV __func__, mode->timing.h_display, mode->timing.v_display); 297d5c3acacSAlexander von Gluck IV return B_ERROR; 298d5c3acacSAlexander von Gluck IV } 299333bd770SAlexander von Gluck IV // validate v_total is greater then v_display 300333bd770SAlexander von Gluck IV if (mode->timing.v_total < mode->timing.v_display) { 30191235829SAlexander von Gluck IV TRACE("%s: ERROR: (%dx%d) " 30291235829SAlexander von Gluck IV "received v_total greater then v_display!\n", 303333bd770SAlexander von Gluck IV __func__, mode->timing.h_display, mode->timing.v_display); 304d5c3acacSAlexander von Gluck IV return B_ERROR; 305d5c3acacSAlexander von Gluck IV } 306d5c3acacSAlexander von Gluck IV 30791235829SAlexander von Gluck IV // calculate refresh rate for given timings to whole int (in Hz) 30891235829SAlexander von Gluck IV int refresh = mode->timing.pixel_clock * 1000 30991235829SAlexander von Gluck IV / (mode->timing.h_total * mode->timing.v_total); 31091235829SAlexander von Gluck IV 31191235829SAlexander von Gluck IV if (refresh < 30 || refresh > 250) { 31291235829SAlexander von Gluck IV TRACE("%s: ERROR: (%dx%d) " 31391235829SAlexander von Gluck IV "refresh rate of %dHz is unlikely for any kind of monitor!\n", 31491235829SAlexander von Gluck IV __func__, mode->timing.h_display, mode->timing.v_display, refresh); 31591235829SAlexander von Gluck IV return B_ERROR; 31691235829SAlexander von Gluck IV } 31791235829SAlexander von Gluck IV 318d5c3acacSAlexander von Gluck IV return B_OK; 319d5c3acacSAlexander von Gluck IV } 320d5c3acacSAlexander von Gluck IV 321d1d65a79SAlexander von Gluck IV 322