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