1/* 2 * Copyright 2007-2012 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Gerald Zajac 7 */ 8 9 10#include "accelerant.h" 11 12#include <create_display_modes.h> // common accelerant header file 13#include <string.h> 14#include <unistd.h> 15 16 17static bool 18IsThereEnoughFBMemory(const display_mode* mode, uint32 bitsPerPixel) 19{ 20 // Test if there is enough Frame Buffer memory for the mode and color depth 21 // specified by the caller, and return true if there is sufficient memory. 22 23 uint32 maxWidth = mode->virtual_width; 24 if (mode->timing.h_display > maxWidth) 25 maxWidth = mode->timing.h_display; 26 27 uint32 maxHeight = mode->virtual_height; 28 if (mode->timing.v_display > maxHeight) 29 maxHeight = mode->timing.v_display; 30 31 uint32 bytesPerPixel = (bitsPerPixel + 7) / 8; 32 33 return (maxWidth * maxHeight * bytesPerPixel 34 <= gInfo.sharedInfo->maxFrameBufferSize); 35} 36 37 38bool 39IsModeUsable(const display_mode* mode) 40{ 41 // Test if the display mode is usable by the current video chip. That is, 42 // does the chip have enough memory for the mode and is the pixel clock 43 // within the chips allowable range, etc. 44 // 45 // Return true if the mode is usable. 46 47 SharedInfo& si = *gInfo.sharedInfo; 48 uint8 bitsPerPixel; 49 uint32 maxPixelClock; 50 51 if (!I810_GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock)) 52 return false; 53 54 // Is there enough frame buffer memory to handle the mode? 55 56 if (!IsThereEnoughFBMemory(mode, bitsPerPixel)) 57 return false; 58 59 if (mode->timing.pixel_clock > maxPixelClock) 60 return false; 61 62 // Is the color space supported? 63 64 bool colorSpaceSupported = false; 65 for (uint32 j = 0; j < si.colorSpaceCount; j++) { 66 if (mode->space == uint32(si.colorSpaces[j])) { 67 colorSpaceSupported = true; 68 break; 69 } 70 } 71 72 if (!colorSpaceSupported) 73 return false; 74 75 // Reject modes with a width of 640 and a height < 480 since they do not 76 // work properly with the i810 chipsets. 77 78 if (mode->timing.h_display == 640 && mode->timing.v_display < 480) 79 return false; 80 81 return true; 82} 83 84 85status_t 86CreateModeList(bool (*checkMode)(const display_mode* mode)) 87{ 88 SharedInfo& si = *gInfo.sharedInfo; 89 90 // Obtain EDID info which is needed for for building the mode list. 91 92 si.bHaveEDID = false; 93 94 if (!si.bHaveEDID) { 95 edid1_raw rawEdid; // raw EDID info to obtain 96 97 if (ioctl(gInfo.deviceFileDesc, INTEL_GET_EDID, &rawEdid, 98 sizeof(rawEdid)) == B_OK) { 99 if (rawEdid.version.version != 1 || rawEdid.version.revision > 4) { 100 TRACE("CreateModeList(); EDID version %d.%d out of range\n", 101 rawEdid.version.version, rawEdid.version.revision); 102 } else { 103 edid_decode(&si.edidInfo, &rawEdid); // decode & save EDID info 104 si.bHaveEDID = true; 105 } 106 } 107 108 if (si.bHaveEDID) { 109#ifdef ENABLE_DEBUG_TRACE 110 edid_dump(&(si.edidInfo)); 111#endif 112 } else { 113 TRACE("CreateModeList(); Unable to get EDID info\n"); 114 } 115 } 116 117 display_mode* list; 118 uint32 count = 0; 119 area_id listArea; 120 121 listArea = create_display_modes("i810 modes", 122 si.bHaveEDID ? &si.edidInfo : NULL, 123 NULL, 0, si.colorSpaces, si.colorSpaceCount, 124 (check_display_mode_hook)checkMode, &list, &count); 125 126 if (listArea < 0) 127 return listArea; // listArea has error code 128 129 si.modeArea = gInfo.modeListArea = listArea; 130 si.modeCount = count; 131 gInfo.modeList = list; 132 return B_OK; 133} 134 135 136status_t 137ProposeDisplayMode(display_mode* target, const display_mode* low, 138 const display_mode* high) 139{ 140 (void)low; // avoid compiler warning for unused arg 141 (void)high; // avoid compiler warning for unused arg 142 143 TRACE("ProposeDisplayMode() %dx%d, pixel clock: %d kHz, space: 0x%X\n", 144 target->timing.h_display, target->timing.v_display, 145 target->timing.pixel_clock, target->space); 146 147 // Search the mode list for the specified mode. 148 149 uint32 modeCount = gInfo.sharedInfo->modeCount; 150 151 for (uint32 j = 0; j < modeCount; j++) { 152 display_mode& mode = gInfo.modeList[j]; 153 154 if (target->timing.h_display == mode.timing.h_display 155 && target->timing.v_display == mode.timing.v_display 156 && target->space == mode.space) 157 return B_OK; // mode found in list 158 } 159 160 return B_BAD_VALUE; // mode not found in list 161} 162 163 164status_t 165SetDisplayMode(display_mode* pMode) 166{ 167 // First validate the mode, then call a function to set the registers. 168 169 TRACE("SetDisplayMode() begin\n"); 170 171 SharedInfo& si = *gInfo.sharedInfo; 172 DisplayModeEx mode; 173 (display_mode&)mode = *pMode; 174 175 uint32 maxPixelClock; 176 if (!I810_GetColorSpaceParams(mode.space, mode.bitsPerPixel, maxPixelClock)) 177 return B_BAD_VALUE; 178 179 if (ProposeDisplayMode(&mode, pMode, pMode) != B_OK) 180 return B_BAD_VALUE; 181 182 mode.bytesPerPixel = (mode.bitsPerPixel + 7) / 8; 183 mode.bytesPerRow = mode.timing.h_display * mode.bytesPerPixel; 184 185 // Is there enough frame buffer memory for this mode? 186 187 if ( ! IsThereEnoughFBMemory(&mode, mode.bitsPerPixel)) 188 return B_NO_MEMORY; 189 190 TRACE("Set display mode: %dx%d virtual size: %dx%d " 191 "color depth: %d bits/pixel\n", 192 mode.timing.h_display, mode.timing.v_display, 193 mode.virtual_width, mode.virtual_height, mode.bitsPerPixel); 194 195 TRACE(" mode timing: %d %d %d %d %d %d %d %d %d\n", 196 mode.timing.pixel_clock, 197 mode.timing.h_display, 198 mode.timing.h_sync_start, mode.timing.h_sync_end, 199 mode.timing.h_total, 200 mode.timing.v_display, 201 mode.timing.v_sync_start, mode.timing.v_sync_end, 202 mode.timing.v_total); 203 204 TRACE(" mode hFreq: %.1f kHz vFreq: %.1f Hz %chSync %cvSync\n", 205 double(mode.timing.pixel_clock) / mode.timing.h_total, 206 ((double(mode.timing.pixel_clock) / mode.timing.h_total) * 1000.0) 207 / mode.timing.v_total, 208 (mode.timing.flags & B_POSITIVE_HSYNC) ? '+' : '-', 209 (mode.timing.flags & B_POSITIVE_VSYNC) ? '+' : '-'); 210 211 status_t status = I810_SetDisplayMode(mode); 212 if (status != B_OK) { 213 TRACE("SetDisplayMode() failed; status 0x%x\n", status); 214 return status; 215 } 216 217 si.displayMode = mode; 218 219 TRACE("SetDisplayMode() done\n"); 220 return B_OK; 221} 222 223 224status_t 225MoveDisplay(uint16 horizontalStart, uint16 verticalStart) 226{ 227 // Set which pixel of the virtual frame buffer will show up in the 228 // top left corner of the display device. Used for page-flipping 229 // games and virtual desktops. 230 231 DisplayModeEx& mode = gInfo.sharedInfo->displayMode; 232 233 if (mode.timing.h_display + horizontalStart > mode.virtual_width 234 || mode.timing.v_display + verticalStart > mode.virtual_height) 235 return B_ERROR; 236 237 mode.h_display_start = horizontalStart; 238 mode.v_display_start = verticalStart; 239 240 I810_AdjustFrame(mode); 241 return B_OK; 242} 243 244 245uint32 246AccelerantModeCount(void) 247{ 248 // Return the number of display modes in the mode list. 249 250 return gInfo.sharedInfo->modeCount; 251} 252 253 254status_t 255GetModeList(display_mode* dmList) 256{ 257 // Copy the list of supported video modes to the location pointed at 258 // by dmList. 259 260 memcpy(dmList, gInfo.modeList, 261 gInfo.sharedInfo->modeCount * sizeof(display_mode)); 262 return B_OK; 263} 264 265 266status_t 267GetDisplayMode(display_mode* current_mode) 268{ 269 *current_mode = gInfo.sharedInfo->displayMode; // current display mode 270 return B_OK; 271} 272 273 274status_t 275GetFrameBufferConfig(frame_buffer_config* pFBC) 276{ 277 SharedInfo& si = *gInfo.sharedInfo; 278 279 pFBC->frame_buffer = (void*)((addr_t)(si.videoMemAddr)); 280 pFBC->frame_buffer_dma = (void*)((addr_t)(si.videoMemPCI)); 281 pFBC->bytes_per_row = si.displayMode.virtual_width 282 * si.displayMode.bytesPerPixel; 283 284 return B_OK; 285} 286 287 288status_t 289GetPixelClockLimits(display_mode* mode, uint32* low, uint32* high) 290{ 291 // Return the maximum and minium pixel clock limits for the specified mode. 292 293 uint8 bitsPerPixel; 294 uint32 maxPixelClock; 295 296 if (!I810_GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock)) 297 return B_ERROR; 298 299 if (low != NULL) { 300 // lower limit of about 48Hz vertical refresh 301 uint32 totalClocks = (uint32)mode->timing.h_total 302 * (uint32)mode->timing.v_total; 303 uint32 lowClock = (totalClocks * 48L) / 1000L; 304 if (lowClock > maxPixelClock) 305 return B_ERROR; 306 307 *low = lowClock; 308 } 309 310 if (high != NULL) 311 *high = maxPixelClock; 312 313 return B_OK; 314} 315 316 317#ifdef __HAIKU__ 318status_t 319GetEdidInfo(void* info, size_t size, uint32* _version) 320{ 321 SharedInfo& si = *gInfo.sharedInfo; 322 323 if ( ! si.bHaveEDID) 324 return B_ERROR; 325 326 if (size < sizeof(struct edid1_info)) 327 return B_BUFFER_OVERFLOW; 328 329 memcpy(info, &si.edidInfo, sizeof(struct edid1_info)); 330 *_version = EDID_VERSION_1; 331 return B_OK; 332} 333#endif // __HAIKU__ 334