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 17 static bool 18 IsThereEnoughFBMemory(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 38 bool 39 IsModeUsable(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 85 status_t 86 CreateModeList(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 136 status_t 137 ProposeDisplayMode(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 164 status_t 165 SetDisplayMode(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 224 status_t 225 MoveDisplay(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 245 uint32 246 AccelerantModeCount(void) 247 { 248 // Return the number of display modes in the mode list. 249 250 return gInfo.sharedInfo->modeCount; 251 } 252 253 254 status_t 255 GetModeList(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 266 status_t 267 GetDisplayMode(display_mode* current_mode) 268 { 269 *current_mode = gInfo.sharedInfo->displayMode; // current display mode 270 return B_OK; 271 } 272 273 274 status_t 275 GetFrameBufferConfig(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 288 status_t 289 GetPixelClockLimits(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__ 318 status_t 319 GetEdidInfo(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