diff options
author | Hemant Hariyani <hemanthariyani@ti.com> | 2011-08-25 02:57:15 -0400 |
---|---|---|
committer | Paolo Pisati <paolo.pisati@canonical.com> | 2012-08-17 04:18:33 -0400 |
commit | 6e90775f610ab87bd86a79f189aca993e44b3bdf (patch) | |
tree | 3b44756d6a8e69dea6c0dbeb2244482b31d32ffc /drivers/gpu/pvr/display/omap_sgx_displayclass.c | |
parent | 1d63da95fb8e073f94c3c63d82f91c49bb2bd08a (diff) |
SGX-KM Initial SGX driver integration for 2.6.35 kernel.
This is the first version of SGX driver integration to ensure UI
boot-up. Power management and hwmod modifications will be added
as patches.
Change-Id: If71e6cd651a53f4809e7b978b693cb7d1a89178d
Signed-off-by: Hemant Hariyani <hemanthariyani@ti.com>
Diffstat (limited to 'drivers/gpu/pvr/display/omap_sgx_displayclass.c')
-rw-r--r-- | drivers/gpu/pvr/display/omap_sgx_displayclass.c | 1638 |
1 files changed, 1638 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/display/omap_sgx_displayclass.c b/drivers/gpu/pvr/display/omap_sgx_displayclass.c new file mode 100644 index 00000000000..7b493f1d94e --- /dev/null +++ b/drivers/gpu/pvr/display/omap_sgx_displayclass.c | |||
@@ -0,0 +1,1638 @@ | |||
1 | /************************************************************************* | ||
2 | * | ||
3 | * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful but, except | ||
10 | * as otherwise stated in writing, without any warranty; without even the | ||
11 | * implied warranty of merchantability or fitness for a particular purpose. | ||
12 | * See the GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along | ||
15 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in | ||
19 | * the file called "COPYING". | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * Imagination Technologies Ltd. <gpl-support@imgtec.com> | ||
23 | * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK | ||
24 | * | ||
25 | *************************************************************************/ | ||
26 | |||
27 | #include <linux/version.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/console.h> | ||
30 | |||
31 | #include <linux/module.h> | ||
32 | #include <linux/string.h> | ||
33 | #include <linux/notifier.h> | ||
34 | |||
35 | #if defined(LDM_PLATFORM) | ||
36 | #include <linux/platform_device.h> | ||
37 | #if defined(SGX_EARLYSUSPEND) | ||
38 | #include <linux/earlysuspend.h> | ||
39 | #endif | ||
40 | #endif | ||
41 | |||
42 | #include "img_defs.h" | ||
43 | #include "servicesext.h" | ||
44 | #include "kerneldisplay.h" | ||
45 | #include "omap_sgx_displayclass.h" | ||
46 | #include "omap_display.h" | ||
47 | |||
48 | /* XXX: Expect 2 framebuffers for virtual display */ | ||
49 | #if (CONFIG_FB_OMAP2_NUM_FBS < 2) | ||
50 | #error "Virtual display is supported only with 2 or more framebuffers, \ | ||
51 | CONFIG_FB_OMAP2_NUM_FBS must be equal or greater than 2 \ | ||
52 | see CONFIG_FB_OMAP2_NUM_FBS for details in the kernel config" | ||
53 | #endif | ||
54 | |||
55 | #define OMAP_DC_CMD_COUNT 1 | ||
56 | #define MAX_BUFFERS_FLIPPING 4 | ||
57 | |||
58 | /* Pointer Display->Services */ | ||
59 | static PFN_DC_GET_PVRJTABLE pfnGetPVRJTable = NULL; | ||
60 | |||
61 | /* Pointer to the display devices */ | ||
62 | static struct OMAP_DISP_DEVINFO *pDisplayDevices = NULL; | ||
63 | static int display_devices_count = 0; | ||
64 | |||
65 | static void display_sync_handler(struct work_struct *work); | ||
66 | static enum OMAP_ERROR get_pvr_dc_jtable (char *szFunctionName, | ||
67 | PFN_DC_GET_PVRJTABLE *ppfnFuncTable); | ||
68 | |||
69 | |||
70 | /* | ||
71 | * Swap to display buffer. This buffer refers to one inside the | ||
72 | * framebuffer memory. | ||
73 | * in: hDevice, hBuffer, ui32SwapInterval, hPrivateTag, ui32ClipRectCount, | ||
74 | * psClipRect | ||
75 | */ | ||
76 | static PVRSRV_ERROR SwapToDCBuffer(IMG_HANDLE hDevice, | ||
77 | IMG_HANDLE hBuffer, | ||
78 | IMG_UINT32 ui32SwapInterval, | ||
79 | IMG_HANDLE hPrivateTag, | ||
80 | IMG_UINT32 ui32ClipRectCount, | ||
81 | IMG_RECT *psClipRect) | ||
82 | { | ||
83 | /* Nothing to do */ | ||
84 | return PVRSRV_OK; | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * Set display destination rectangle. | ||
89 | * in: hDevice, hSwapChain, psRect | ||
90 | */ | ||
91 | static PVRSRV_ERROR SetDCDstRect(IMG_HANDLE hDevice, | ||
92 | IMG_HANDLE hSwapChain, | ||
93 | IMG_RECT *psRect) | ||
94 | { | ||
95 | /* Nothing to do */ | ||
96 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * Set display source rectangle. | ||
101 | * in: hDevice, hSwapChain, psRect | ||
102 | */ | ||
103 | static PVRSRV_ERROR SetDCSrcRect(IMG_HANDLE hDevice, | ||
104 | IMG_HANDLE hSwapChain, | ||
105 | IMG_RECT *psRect) | ||
106 | { | ||
107 | /* Nothing to do */ | ||
108 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * Set display destination colour key. | ||
113 | * in: hDevice, hSwapChain, ui32CKColour | ||
114 | */ | ||
115 | static PVRSRV_ERROR SetDCDstColourKey(IMG_HANDLE hDevice, | ||
116 | IMG_HANDLE hSwapChain, | ||
117 | IMG_UINT32 ui32CKColour) | ||
118 | { | ||
119 | /* Nothing to do */ | ||
120 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * Set display source colour key. | ||
125 | * in: hDevice, hSwapChain, ui32CKColour | ||
126 | */ | ||
127 | static PVRSRV_ERROR SetDCSrcColourKey(IMG_HANDLE hDevice, | ||
128 | IMG_HANDLE hSwapChain, | ||
129 | IMG_UINT32 ui32CKColour) | ||
130 | { | ||
131 | /* Nothing to do */ | ||
132 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * Closes the display. | ||
137 | * in: hDevice | ||
138 | */ | ||
139 | static PVRSRV_ERROR CloseDCDevice(IMG_HANDLE hDevice) | ||
140 | { | ||
141 | struct OMAP_DISP_DEVINFO *psDevInfo = | ||
142 | (struct OMAP_DISP_DEVINFO*) hDevice; | ||
143 | struct omap_display_device *display = psDevInfo->display; | ||
144 | |||
145 | if(display->close(display)) | ||
146 | WARNING_PRINTK("Unable to close properly display '%s'", | ||
147 | display->name); | ||
148 | |||
149 | return PVRSRV_OK; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * Flushes the sync queue present in the specified swap chain. | ||
154 | * in: psSwapChain | ||
155 | */ | ||
156 | static void FlushInternalSyncQueue(struct OMAP_DISP_SWAPCHAIN *psSwapChain) | ||
157 | { | ||
158 | struct OMAP_DISP_DEVINFO *psDevInfo = | ||
159 | (struct OMAP_DISP_DEVINFO*) psSwapChain->pvDevInfo; | ||
160 | struct OMAP_DISP_FLIP_ITEM *psFlipItem; | ||
161 | struct omap_display_device *display = psDevInfo->display; | ||
162 | unsigned long ulMaxIndex; | ||
163 | unsigned long i; | ||
164 | |||
165 | psFlipItem = &psSwapChain->psFlipItems[psSwapChain->ulRemoveIndex]; | ||
166 | ulMaxIndex = psSwapChain->ulBufferCount - 1; | ||
167 | |||
168 | DEBUG_PRINTK("Flushing sync queue on display %lu", | ||
169 | psDevInfo->ulDeviceID); | ||
170 | for(i = 0; i < psSwapChain->ulBufferCount; i++) | ||
171 | { | ||
172 | if (psFlipItem->bValid == OMAP_FALSE) | ||
173 | continue; | ||
174 | |||
175 | DEBUG_PRINTK("Flushing swap buffer index %lu", | ||
176 | psSwapChain->ulRemoveIndex); | ||
177 | |||
178 | /* Flip the buffer if it hasn't been flipped */ | ||
179 | if(psFlipItem->bFlipped == OMAP_FALSE) | ||
180 | { | ||
181 | display->present_buffer(psFlipItem->display_buffer); | ||
182 | } | ||
183 | |||
184 | /* If the command didn't complete, assume it did */ | ||
185 | if(psFlipItem->bCmdCompleted == OMAP_FALSE) | ||
186 | { | ||
187 | DEBUG_PRINTK("Calling command complete for swap " | ||
188 | "buffer index %lu", | ||
189 | psSwapChain->ulRemoveIndex); | ||
190 | psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete( | ||
191 | (IMG_HANDLE)psFlipItem->hCmdComplete, | ||
192 | IMG_TRUE); | ||
193 | } | ||
194 | |||
195 | psSwapChain->ulRemoveIndex++; | ||
196 | if(psSwapChain->ulRemoveIndex > ulMaxIndex) | ||
197 | psSwapChain->ulRemoveIndex = 0; | ||
198 | |||
199 | /* Put the state of the buffer to be used again later */ | ||
200 | psFlipItem->bFlipped = OMAP_FALSE; | ||
201 | psFlipItem->bCmdCompleted = OMAP_FALSE; | ||
202 | psFlipItem->bValid = OMAP_FALSE; | ||
203 | psFlipItem = | ||
204 | &psSwapChain->psFlipItems[psSwapChain->ulRemoveIndex]; | ||
205 | } | ||
206 | |||
207 | psSwapChain->ulInsertIndex = 0; | ||
208 | psSwapChain->ulRemoveIndex = 0; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Sets the flush state of the specified display device | ||
213 | * at the swap chain level without blocking the call. | ||
214 | * in: psDevInfo, bFlushState | ||
215 | */ | ||
216 | static void SetFlushStateInternalNoLock(struct OMAP_DISP_DEVINFO* psDevInfo, | ||
217 | enum OMAP_BOOL bFlushState) | ||
218 | { | ||
219 | struct OMAP_DISP_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain; | ||
220 | |||
221 | /* Nothing to do if there is no swap chain */ | ||
222 | if (psSwapChain == NULL){ | ||
223 | DEBUG_PRINTK("Swap chain is null, nothing to do for" | ||
224 | " display %lu", psDevInfo->ulDeviceID); | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | if (bFlushState) | ||
229 | { | ||
230 | DEBUG_PRINTK("Desired flushState is true for display %lu", | ||
231 | psDevInfo->ulDeviceID); | ||
232 | if (psSwapChain->ulSetFlushStateRefCount == 0) | ||
233 | { | ||
234 | psSwapChain->bFlushCommands = OMAP_TRUE; | ||
235 | FlushInternalSyncQueue(psSwapChain); | ||
236 | } | ||
237 | psSwapChain->ulSetFlushStateRefCount++; | ||
238 | } | ||
239 | else | ||
240 | { | ||
241 | DEBUG_PRINTK("Desired flushState is false for display %lu", | ||
242 | psDevInfo->ulDeviceID); | ||
243 | if (psSwapChain->ulSetFlushStateRefCount != 0) | ||
244 | { | ||
245 | psSwapChain->ulSetFlushStateRefCount--; | ||
246 | if (psSwapChain->ulSetFlushStateRefCount == 0) | ||
247 | { | ||
248 | psSwapChain->bFlushCommands = OMAP_FALSE; | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Sets the flush state of the specified display device | ||
256 | * at device level blocking the call if needed. | ||
257 | * in: psDevInfo, bFlushState | ||
258 | */ | ||
259 | static void SetFlushStateExternal(struct OMAP_DISP_DEVINFO* psDevInfo, | ||
260 | enum OMAP_BOOL bFlushState) | ||
261 | { | ||
262 | DEBUG_PRINTK("Executing for display %lu", | ||
263 | psDevInfo->ulDeviceID); | ||
264 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
265 | if (psDevInfo->bFlushCommands != bFlushState) | ||
266 | { | ||
267 | psDevInfo->bFlushCommands = bFlushState; | ||
268 | SetFlushStateInternalNoLock(psDevInfo, bFlushState); | ||
269 | } | ||
270 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Opens the display. | ||
275 | * in: ui32DeviceID, phDevice | ||
276 | * out: psSystemBufferSyncData | ||
277 | */ | ||
278 | static PVRSRV_ERROR OpenDCDevice(IMG_UINT32 ui32DeviceID, | ||
279 | IMG_HANDLE *phDevice, | ||
280 | PVRSRV_SYNC_DATA* psSystemBufferSyncData) | ||
281 | { | ||
282 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
283 | struct omap_display_device *display; | ||
284 | int i; | ||
285 | |||
286 | psDevInfo = 0; | ||
287 | for(i = 0; i < display_devices_count; i++) | ||
288 | { | ||
289 | if(ui32DeviceID == (&pDisplayDevices[i])->ulDeviceID) | ||
290 | { | ||
291 | psDevInfo = &pDisplayDevices[i]; | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | if(!psDevInfo) | ||
297 | { | ||
298 | WARNING_PRINTK("Unable to identify display device with id %i", | ||
299 | (int)ui32DeviceID); | ||
300 | return OMAP_ERROR_INVALID_DEVICE; | ||
301 | } | ||
302 | |||
303 | psDevInfo->sSystemBuffer.psSyncData = psSystemBufferSyncData; | ||
304 | display = psDevInfo->display; | ||
305 | |||
306 | DEBUG_PRINTK("Opening display %lu '%s'",psDevInfo->ulDeviceID, | ||
307 | display->name); | ||
308 | |||
309 | /* TODO: Explain here why ORIENTATION_VERTICAL is used*/ | ||
310 | if(display->open(display, ORIENTATION_VERTICAL | ORIENTATION_INVERT)) | ||
311 | ERROR_PRINTK("Unable to open properly display '%s'", | ||
312 | psDevInfo->display->name); | ||
313 | |||
314 | display->present_buffer(display->main_buffer); | ||
315 | |||
316 | /* TODO: Turn on display here? */ | ||
317 | |||
318 | *phDevice = (IMG_HANDLE)psDevInfo; | ||
319 | |||
320 | return PVRSRV_OK; | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * Gets the available formats for the display. | ||
325 | * in: hDevice | ||
326 | * out: pui32NumFormats, psFormat | ||
327 | */ | ||
328 | static PVRSRV_ERROR EnumDCFormats(IMG_HANDLE hDevice, | ||
329 | IMG_UINT32 *pui32NumFormats, | ||
330 | DISPLAY_FORMAT *psFormat) | ||
331 | { | ||
332 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
333 | if(!hDevice || !pui32NumFormats) | ||
334 | { | ||
335 | ERROR_PRINTK("Invalid parameters"); | ||
336 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
337 | } | ||
338 | |||
339 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
340 | *pui32NumFormats = 1; | ||
341 | |||
342 | if(psFormat) | ||
343 | psFormat[0] = psDevInfo->sDisplayFormat; | ||
344 | else | ||
345 | WARNING_PRINTK("Display format is null for" | ||
346 | " display %lu", psDevInfo->ulDeviceID); | ||
347 | |||
348 | return PVRSRV_OK; | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * Gets the available dimensions for the display. | ||
353 | * in: hDevice, psFormat | ||
354 | * out: pui32NumDims, psDim | ||
355 | */ | ||
356 | static PVRSRV_ERROR EnumDCDims(IMG_HANDLE hDevice, | ||
357 | DISPLAY_FORMAT *psFormat, | ||
358 | IMG_UINT32 *pui32NumDims, | ||
359 | DISPLAY_DIMS *psDim) | ||
360 | { | ||
361 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
362 | if(!hDevice || !psFormat || !pui32NumDims) | ||
363 | { | ||
364 | ERROR_PRINTK("Invalid parameters"); | ||
365 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
366 | } | ||
367 | |||
368 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
369 | *pui32NumDims = 1; | ||
370 | |||
371 | if(psDim) | ||
372 | psDim[0] = psDevInfo->sDisplayDim; | ||
373 | else | ||
374 | WARNING_PRINTK("Display dimensions are null for" | ||
375 | " display %lu", psDevInfo->ulDeviceID); | ||
376 | |||
377 | return PVRSRV_OK; | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * Gets the display framebuffer physical address. | ||
382 | * in: hDevice | ||
383 | * out: phBuffer | ||
384 | */ | ||
385 | static PVRSRV_ERROR GetDCSystemBuffer(IMG_HANDLE hDevice, IMG_HANDLE *phBuffer) | ||
386 | { | ||
387 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
388 | |||
389 | if(!hDevice || !phBuffer) | ||
390 | { | ||
391 | ERROR_PRINTK("Invalid parameters"); | ||
392 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
393 | } | ||
394 | |||
395 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
396 | *phBuffer = (IMG_HANDLE)&psDevInfo->sSystemBuffer; | ||
397 | |||
398 | return PVRSRV_OK; | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * Gets the display general information. | ||
403 | * in: hDevice | ||
404 | * out: psDCInfo | ||
405 | */ | ||
406 | static PVRSRV_ERROR GetDCInfo(IMG_HANDLE hDevice, DISPLAY_INFO *psDCInfo) | ||
407 | { | ||
408 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
409 | |||
410 | if(!hDevice || !psDCInfo) | ||
411 | { | ||
412 | ERROR_PRINTK("Invalid parameters"); | ||
413 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
414 | } | ||
415 | |||
416 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
417 | *psDCInfo = psDevInfo->sDisplayInfo; | ||
418 | |||
419 | return PVRSRV_OK; | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * Gets the display framebuffer virtual address. | ||
424 | * in: hDevice | ||
425 | * out: ppsSysAddr, pui32ByteSize, ppvCpuVAddr, phOSMapInfo, pbIsContiguous | ||
426 | */ | ||
427 | static PVRSRV_ERROR GetDCBufferAddr(IMG_HANDLE hDevice, | ||
428 | IMG_HANDLE hBuffer, | ||
429 | IMG_SYS_PHYADDR **ppsSysAddr, | ||
430 | IMG_UINT32 *pui32ByteSize, | ||
431 | IMG_VOID **ppvCpuVAddr, | ||
432 | IMG_HANDLE *phOSMapInfo, | ||
433 | IMG_BOOL *pbIsContiguous, | ||
434 | IMG_UINT32 *pui32TilingStride) | ||
435 | { | ||
436 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
437 | struct OMAP_DISP_BUFFER *psSystemBuffer; | ||
438 | |||
439 | if(!hDevice || !hBuffer || !ppsSysAddr || !pui32ByteSize ) | ||
440 | { | ||
441 | ERROR_PRINTK("Invalid parameters"); | ||
442 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
443 | } | ||
444 | |||
445 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
446 | psSystemBuffer = (struct OMAP_DISP_BUFFER *)hBuffer; | ||
447 | *ppsSysAddr = &psSystemBuffer->sSysAddr; | ||
448 | *pui32ByteSize = (IMG_UINT32)psDevInfo->sSystemBuffer.ulBufferSize; | ||
449 | |||
450 | if (ppvCpuVAddr) | ||
451 | *ppvCpuVAddr = psSystemBuffer->sCPUVAddr; | ||
452 | |||
453 | if (phOSMapInfo) | ||
454 | *phOSMapInfo = (IMG_HANDLE)0; | ||
455 | |||
456 | if (pbIsContiguous) | ||
457 | *pbIsContiguous = IMG_TRUE; | ||
458 | |||
459 | return PVRSRV_OK; | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * Creates a swap chain. Called when a 3D application begins. | ||
464 | * in: hDevice, ui32Flags, ui32BufferCount, psDstSurfAttrib, psSrcSurfAttrib | ||
465 | * ui32OEMFlags | ||
466 | * out: phSwapChain, ppsSyncData, pui32SwapChainID | ||
467 | */ | ||
468 | static PVRSRV_ERROR CreateDCSwapChain(IMG_HANDLE hDevice, | ||
469 | IMG_UINT32 ui32Flags, | ||
470 | DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib, | ||
471 | DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib, | ||
472 | IMG_UINT32 ui32BufferCount, | ||
473 | PVRSRV_SYNC_DATA **ppsSyncData, | ||
474 | IMG_UINT32 ui32OEMFlags, | ||
475 | IMG_HANDLE *phSwapChain, | ||
476 | IMG_UINT32 *pui32SwapChainID) | ||
477 | { | ||
478 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
479 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
480 | struct OMAP_DISP_BUFFER *psBuffer; | ||
481 | struct OMAP_DISP_FLIP_ITEM *psFlipItems; | ||
482 | IMG_UINT32 i; | ||
483 | PVRSRV_ERROR eError; | ||
484 | IMG_UINT32 ui32BuffersToSkip; | ||
485 | struct omap_display_device *display; | ||
486 | int err; | ||
487 | |||
488 | if(!hDevice || !psDstSurfAttrib || !psSrcSurfAttrib || | ||
489 | !ppsSyncData || !phSwapChain) | ||
490 | { | ||
491 | ERROR_PRINTK("Invalid parameters"); | ||
492 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
493 | } | ||
494 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
495 | |||
496 | if (psDevInfo->sDisplayInfo.ui32MaxSwapChains == 0) | ||
497 | { | ||
498 | ERROR_PRINTK("Unable to operate with 0 MaxSwapChains for" | ||
499 | " display %lu", psDevInfo->ulDeviceID); | ||
500 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
501 | } | ||
502 | |||
503 | if(psDevInfo->psSwapChain != NULL) | ||
504 | { | ||
505 | ERROR_PRINTK("Swap chain already exists for" | ||
506 | " display %lu", psDevInfo->ulDeviceID); | ||
507 | return PVRSRV_ERROR_FLIP_CHAIN_EXISTS; | ||
508 | } | ||
509 | |||
510 | if(ui32BufferCount > psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers) | ||
511 | { | ||
512 | ERROR_PRINTK("Too many buffers. Trying to use %u buffers while" | ||
513 | " there is only %u available for display %lu", | ||
514 | (unsigned int)ui32BufferCount, | ||
515 | (unsigned int)psDevInfo-> | ||
516 | sDisplayInfo.ui32MaxSwapChainBuffers, | ||
517 | psDevInfo->ulDeviceID); | ||
518 | return PVRSRV_ERROR_TOOMANYBUFFERS; | ||
519 | } | ||
520 | |||
521 | ui32BuffersToSkip = psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers - | ||
522 | ui32BufferCount; | ||
523 | |||
524 | if((psDstSurfAttrib->pixelformat != | ||
525 | psDevInfo->sDisplayFormat.pixelformat) || | ||
526 | (psDstSurfAttrib->sDims.ui32ByteStride != | ||
527 | psDevInfo->sDisplayDim.ui32ByteStride) || | ||
528 | (psDstSurfAttrib->sDims.ui32Width != | ||
529 | psDevInfo->sDisplayDim.ui32Width) || | ||
530 | (psDstSurfAttrib->sDims.ui32Height != | ||
531 | psDevInfo->sDisplayDim.ui32Height)) | ||
532 | { | ||
533 | ERROR_PRINTK("Destination surface attributes differ from the" | ||
534 | " current framebuffer for display %lu", | ||
535 | psDevInfo->ulDeviceID); | ||
536 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
537 | } | ||
538 | |||
539 | if((psDstSurfAttrib->pixelformat != | ||
540 | psSrcSurfAttrib->pixelformat) || | ||
541 | (psDstSurfAttrib->sDims.ui32ByteStride != | ||
542 | psSrcSurfAttrib->sDims.ui32ByteStride) || | ||
543 | (psDstSurfAttrib->sDims.ui32Width != | ||
544 | psSrcSurfAttrib->sDims.ui32Width) || | ||
545 | (psDstSurfAttrib->sDims.ui32Height != | ||
546 | psSrcSurfAttrib->sDims.ui32Height)) | ||
547 | { | ||
548 | ERROR_PRINTK("Destination surface attributes differ from the" | ||
549 | " target destination surface for display %lu", | ||
550 | psDevInfo->ulDeviceID); | ||
551 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
552 | } | ||
553 | |||
554 | /* Create the flip chain in display side */ | ||
555 | display = psDevInfo->display; | ||
556 | /* TODO: What about TILER buffers? */ | ||
557 | /* | ||
558 | * Creating the flip chain with the maximum number of buffers | ||
559 | * we will decide which ones will be used later | ||
560 | */ | ||
561 | err = display->create_flip_chain( | ||
562 | display, psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers); | ||
563 | if(err) | ||
564 | { | ||
565 | ERROR_PRINTK("Unable to create the flip chain for '%s' display" | ||
566 | " id %lu", display->name, psDevInfo->ulDeviceID); | ||
567 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
568 | } | ||
569 | |||
570 | /* Allocate memory needed for the swap chain */ | ||
571 | psSwapChain = (struct OMAP_DISP_SWAPCHAIN*) kmalloc( | ||
572 | sizeof(struct OMAP_DISP_SWAPCHAIN), GFP_KERNEL); | ||
573 | if(!psSwapChain) | ||
574 | { | ||
575 | ERROR_PRINTK("Out of memory to allocate swap chain for" | ||
576 | " display %lu", psDevInfo->ulDeviceID); | ||
577 | return PVRSRV_ERROR_OUT_OF_MEMORY; | ||
578 | } | ||
579 | |||
580 | DEBUG_PRINTK("Creating swap chain for display %lu", | ||
581 | psDevInfo->ulDeviceID ); | ||
582 | |||
583 | /* Allocate memory for the buffer abstraction structures */ | ||
584 | psBuffer = (struct OMAP_DISP_BUFFER*) kmalloc( | ||
585 | sizeof(struct OMAP_DISP_BUFFER) * ui32BufferCount, GFP_KERNEL); | ||
586 | if(!psBuffer) | ||
587 | { | ||
588 | ERROR_PRINTK("Out of memory to allocate the buffer" | ||
589 | " abstraction structures for display %lu", | ||
590 | psDevInfo->ulDeviceID); | ||
591 | eError = PVRSRV_ERROR_OUT_OF_MEMORY; | ||
592 | goto ErrorFreeSwapChain; | ||
593 | } | ||
594 | |||
595 | /* Allocate memory for the flip item abstraction structures */ | ||
596 | psFlipItems = (struct OMAP_DISP_FLIP_ITEM *) kmalloc ( | ||
597 | sizeof(struct OMAP_DISP_FLIP_ITEM) * ui32BufferCount, | ||
598 | GFP_KERNEL); | ||
599 | if (!psFlipItems) | ||
600 | { | ||
601 | ERROR_PRINTK("Out of memory to allocate the flip item" | ||
602 | " abstraction structures for display %lu", | ||
603 | psDevInfo->ulDeviceID); | ||
604 | eError = PVRSRV_ERROR_OUT_OF_MEMORY; | ||
605 | goto ErrorFreeBuffers; | ||
606 | } | ||
607 | |||
608 | /* Assign to the swap chain structure the initial data */ | ||
609 | psSwapChain->ulBufferCount = (unsigned long)ui32BufferCount; | ||
610 | psSwapChain->psBuffer = psBuffer; | ||
611 | psSwapChain->psFlipItems = psFlipItems; | ||
612 | psSwapChain->ulInsertIndex = 0; | ||
613 | psSwapChain->ulRemoveIndex = 0; | ||
614 | psSwapChain->psPVRJTable = &psDevInfo->sPVRJTable; | ||
615 | psSwapChain->pvDevInfo = (void*)psDevInfo; | ||
616 | |||
617 | /* | ||
618 | * Init the workqueue (single thread, freezable and real time) | ||
619 | * and its own work for this display | ||
620 | */ | ||
621 | INIT_WORK(&psDevInfo->sync_display_work, display_sync_handler); | ||
622 | psDevInfo->sync_display_wq = | ||
623 | __create_workqueue("pvr_display_sync_wq", 1, 1, 1); | ||
624 | |||
625 | DEBUG_PRINTK("Swap chain will have %u buffers for display %lu", | ||
626 | (unsigned int)ui32BufferCount, psDevInfo->ulDeviceID); | ||
627 | /* Link the buffers available like a circular list */ | ||
628 | for(i=0; i<ui32BufferCount-1; i++) | ||
629 | { | ||
630 | psBuffer[i].psNext = &psBuffer[i+1]; | ||
631 | } | ||
632 | psBuffer[i].psNext = &psBuffer[0]; | ||
633 | |||
634 | /* Initialize each buffer abstraction structure */ | ||
635 | for(i=0; i<ui32BufferCount; i++) | ||
636 | { | ||
637 | /* Get the needed buffers from the display flip chain */ | ||
638 | IMG_UINT32 ui32SwapBuffer = i + ui32BuffersToSkip; | ||
639 | struct omap_display_buffer * flip_buffer = | ||
640 | display->flip_chain->buffers[ui32SwapBuffer]; | ||
641 | psBuffer[i].display_buffer = flip_buffer; | ||
642 | psBuffer[i].psSyncData = ppsSyncData[i]; | ||
643 | psBuffer[i].sSysAddr.uiAddr = flip_buffer->physical_addr; | ||
644 | psBuffer[i].sCPUVAddr = | ||
645 | (IMG_CPU_VIRTADDR) flip_buffer->virtual_addr; | ||
646 | DEBUG_PRINTK("Display %lu buffer index %u has physical " | ||
647 | "address 0x%x", | ||
648 | psDevInfo->ulDeviceID, | ||
649 | (unsigned int)i, | ||
650 | (unsigned int)psBuffer[i].sSysAddr.uiAddr); | ||
651 | } | ||
652 | |||
653 | /* Initialize each flip item abstraction structure */ | ||
654 | for(i=0; i<ui32BufferCount; i++) | ||
655 | { | ||
656 | psFlipItems[i].bValid = OMAP_FALSE; | ||
657 | psFlipItems[i].bFlipped = OMAP_FALSE; | ||
658 | psFlipItems[i].bCmdCompleted = OMAP_FALSE; | ||
659 | psFlipItems[i].display_buffer = 0; | ||
660 | } | ||
661 | |||
662 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
663 | |||
664 | psDevInfo->psSwapChain = psSwapChain; | ||
665 | psSwapChain->bFlushCommands = psDevInfo->bFlushCommands; | ||
666 | if (psSwapChain->bFlushCommands) | ||
667 | psSwapChain->ulSetFlushStateRefCount = 1; | ||
668 | else | ||
669 | psSwapChain->ulSetFlushStateRefCount = 0; | ||
670 | |||
671 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
672 | |||
673 | *phSwapChain = (IMG_HANDLE)psSwapChain; | ||
674 | |||
675 | return PVRSRV_OK; | ||
676 | |||
677 | ErrorFreeBuffers: | ||
678 | kfree(psBuffer); | ||
679 | ErrorFreeSwapChain: | ||
680 | kfree(psSwapChain); | ||
681 | |||
682 | return eError; | ||
683 | } | ||
684 | |||
685 | /* | ||
686 | * Destroy a swap chain. Called when a 3D application ends. | ||
687 | * in: hDevice, hSwapChain | ||
688 | */ | ||
689 | static PVRSRV_ERROR DestroyDCSwapChain(IMG_HANDLE hDevice, | ||
690 | IMG_HANDLE hSwapChain) | ||
691 | { | ||
692 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
693 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
694 | struct omap_display_device *display; | ||
695 | int err; | ||
696 | |||
697 | if(!hDevice || !hSwapChain) | ||
698 | { | ||
699 | ERROR_PRINTK("Invalid parameters"); | ||
700 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
701 | } | ||
702 | |||
703 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
704 | psSwapChain = (struct OMAP_DISP_SWAPCHAIN*)hSwapChain; | ||
705 | display = psDevInfo->display; | ||
706 | |||
707 | if (psSwapChain != psDevInfo->psSwapChain) | ||
708 | { | ||
709 | ERROR_PRINTK("Swap chain handler differs from the one " | ||
710 | "present in the display device pointer"); | ||
711 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
712 | } | ||
713 | |||
714 | DEBUG_PRINTK("Destroying swap chain for display %lu", | ||
715 | psDevInfo->ulDeviceID); | ||
716 | |||
717 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
718 | |||
719 | FlushInternalSyncQueue(psSwapChain); | ||
720 | psDevInfo->psSwapChain = NULL; | ||
721 | |||
722 | /* | ||
723 | * Present the buffer which is at the base of address of | ||
724 | * the framebuffer | ||
725 | */ | ||
726 | display->present_buffer(display->main_buffer); | ||
727 | |||
728 | /* Destroy the flip chain in display side */ | ||
729 | err = display->destroy_flip_chain(display); | ||
730 | if(err) | ||
731 | { | ||
732 | ERROR_PRINTK("Unable to destroy the flip chain for '%s' " | ||
733 | "display id %lu", display->name, | ||
734 | psDevInfo->ulDeviceID); | ||
735 | } | ||
736 | |||
737 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
738 | |||
739 | /* Destroy the workqueue */ | ||
740 | flush_workqueue(psDevInfo->sync_display_wq); | ||
741 | destroy_workqueue(psDevInfo->sync_display_wq); | ||
742 | |||
743 | kfree(psSwapChain->psFlipItems); | ||
744 | kfree(psSwapChain->psBuffer); | ||
745 | kfree(psSwapChain); | ||
746 | |||
747 | return PVRSRV_OK; | ||
748 | } | ||
749 | |||
750 | |||
751 | /* | ||
752 | * Get display buffers. These are the buffers that can be allocated | ||
753 | * inside the framebuffer memory. | ||
754 | * in: hDevice, hSwapChain | ||
755 | * out: pui32BufferCount, phBuffer | ||
756 | */ | ||
757 | static PVRSRV_ERROR GetDCBuffers(IMG_HANDLE hDevice, | ||
758 | IMG_HANDLE hSwapChain, | ||
759 | IMG_UINT32 *pui32BufferCount, | ||
760 | IMG_HANDLE *phBuffer) | ||
761 | { | ||
762 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
763 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
764 | unsigned long i; | ||
765 | |||
766 | if(!hDevice || !hSwapChain || !pui32BufferCount || !phBuffer) | ||
767 | { | ||
768 | ERROR_PRINTK("Invalid parameters"); | ||
769 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
770 | } | ||
771 | |||
772 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
773 | psSwapChain = (struct OMAP_DISP_SWAPCHAIN*)hSwapChain; | ||
774 | if (psSwapChain != psDevInfo->psSwapChain) | ||
775 | { | ||
776 | ERROR_PRINTK("Swap chain handler differs from the one " | ||
777 | "present in the display device %lu pointer", | ||
778 | psDevInfo->ulDeviceID); | ||
779 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
780 | } | ||
781 | *pui32BufferCount = (IMG_UINT32)psSwapChain->ulBufferCount; | ||
782 | |||
783 | for(i=0; i<psSwapChain->ulBufferCount; i++) | ||
784 | phBuffer[i] = (IMG_HANDLE)&psSwapChain->psBuffer[i]; | ||
785 | |||
786 | return PVRSRV_OK; | ||
787 | } | ||
788 | |||
789 | /* | ||
790 | * Sets the display state. | ||
791 | * in: ui32State, hDevice | ||
792 | */ | ||
793 | static IMG_VOID SetDCState(IMG_HANDLE hDevice, IMG_UINT32 ui32State) | ||
794 | { | ||
795 | struct OMAP_DISP_DEVINFO *psDevInfo = | ||
796 | (struct OMAP_DISP_DEVINFO*) hDevice; | ||
797 | |||
798 | switch (ui32State) | ||
799 | { | ||
800 | case DC_STATE_FLUSH_COMMANDS: | ||
801 | DEBUG_PRINTK("Setting state to flush commands for" | ||
802 | " display %lu", psDevInfo->ulDeviceID); | ||
803 | SetFlushStateExternal(psDevInfo, OMAP_TRUE); | ||
804 | break; | ||
805 | case DC_STATE_NO_FLUSH_COMMANDS: | ||
806 | DEBUG_PRINTK("Setting state to not flush commands for" | ||
807 | " display %lu", psDevInfo->ulDeviceID); | ||
808 | SetFlushStateExternal(psDevInfo, OMAP_FALSE); | ||
809 | break; | ||
810 | default: | ||
811 | WARNING_PRINTK("Unknown command state %u for display" | ||
812 | " %lu", (unsigned int)ui32State, | ||
813 | psDevInfo->ulDeviceID); | ||
814 | break; | ||
815 | } | ||
816 | } | ||
817 | |||
818 | /* | ||
819 | * Swap to display system buffer. This buffer refers to the one which | ||
820 | * is that fits in the framebuffer memory. | ||
821 | * in: hDevice, hSwapChain | ||
822 | */ | ||
823 | static PVRSRV_ERROR SwapToDCSystem(IMG_HANDLE hDevice, | ||
824 | IMG_HANDLE hSwapChain) | ||
825 | { | ||
826 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
827 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
828 | struct omap_display_device *display; | ||
829 | |||
830 | if(!hDevice || !hSwapChain) | ||
831 | { | ||
832 | ERROR_PRINTK("Invalid parameters"); | ||
833 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
834 | } | ||
835 | |||
836 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
837 | psSwapChain = (struct OMAP_DISP_SWAPCHAIN*)hSwapChain; | ||
838 | display = psDevInfo->display; | ||
839 | |||
840 | DEBUG_PRINTK("Executing for display %lu", | ||
841 | psDevInfo->ulDeviceID); | ||
842 | |||
843 | if (psSwapChain != psDevInfo->psSwapChain) | ||
844 | { | ||
845 | ERROR_PRINTK("Swap chain handler differs from the one " | ||
846 | "present in the display device %lu pointer", | ||
847 | psDevInfo->ulDeviceID); | ||
848 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
849 | } | ||
850 | |||
851 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
852 | |||
853 | FlushInternalSyncQueue(psSwapChain); | ||
854 | display->present_buffer(display->main_buffer); | ||
855 | |||
856 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
857 | |||
858 | return PVRSRV_OK; | ||
859 | } | ||
860 | |||
861 | /* | ||
862 | * Handles the synchronization with the display | ||
863 | * in: work | ||
864 | */ | ||
865 | |||
866 | static void display_sync_handler(struct work_struct *work) | ||
867 | { | ||
868 | /* | ||
869 | * TODO: Since present_buffer_sync waits and then present, this | ||
870 | * algorithm can be simplified further | ||
871 | */ | ||
872 | struct OMAP_DISP_DEVINFO *psDevInfo = container_of(work, | ||
873 | struct OMAP_DISP_DEVINFO, sync_display_work); | ||
874 | struct omap_display_device *display = psDevInfo->display; | ||
875 | struct OMAP_DISP_FLIP_ITEM *psFlipItem; | ||
876 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
877 | unsigned long ulMaxIndex; | ||
878 | |||
879 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
880 | |||
881 | psSwapChain = psDevInfo->psSwapChain; | ||
882 | if (!psSwapChain || psSwapChain->bFlushCommands) | ||
883 | goto ExitUnlock; | ||
884 | |||
885 | psFlipItem = &psSwapChain->psFlipItems[psSwapChain->ulRemoveIndex]; | ||
886 | ulMaxIndex = psSwapChain->ulBufferCount - 1; | ||
887 | |||
888 | /* Iterate through the flip items and flip them if necessary */ | ||
889 | while(psFlipItem->bValid) | ||
890 | { | ||
891 | if(psFlipItem->bFlipped) | ||
892 | { | ||
893 | if(!psFlipItem->bCmdCompleted) | ||
894 | { | ||
895 | psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete( | ||
896 | (IMG_HANDLE)psFlipItem->hCmdComplete, | ||
897 | IMG_TRUE); | ||
898 | psFlipItem->bCmdCompleted = OMAP_TRUE; | ||
899 | } | ||
900 | |||
901 | if(psFlipItem->ulSwapInterval == 0) | ||
902 | { | ||
903 | psSwapChain->ulRemoveIndex++; | ||
904 | if(psSwapChain->ulRemoveIndex > ulMaxIndex) | ||
905 | psSwapChain->ulRemoveIndex = 0; | ||
906 | psFlipItem->bCmdCompleted = OMAP_FALSE; | ||
907 | psFlipItem->bFlipped = OMAP_FALSE; | ||
908 | psFlipItem->bValid = OMAP_FALSE; | ||
909 | } | ||
910 | else | ||
911 | { | ||
912 | /* | ||
913 | * Here the swap interval is not zero yet | ||
914 | * we need to schedule another work until | ||
915 | * it reaches zero | ||
916 | */ | ||
917 | display->sync(display); | ||
918 | psFlipItem->ulSwapInterval--; | ||
919 | queue_work(psDevInfo->sync_display_wq, | ||
920 | &psDevInfo->sync_display_work); | ||
921 | goto ExitUnlock; | ||
922 | } | ||
923 | } | ||
924 | else | ||
925 | { | ||
926 | display->present_buffer_sync( | ||
927 | psFlipItem->display_buffer); | ||
928 | /* | ||
929 | * present_buffer_sync waits and then present, then | ||
930 | * swap interval decreases here too. | ||
931 | */ | ||
932 | psFlipItem->ulSwapInterval--; | ||
933 | psFlipItem->bFlipped = OMAP_TRUE; | ||
934 | /* | ||
935 | * If the flip has been presented here then we need | ||
936 | * in the next sync execute the command complete, | ||
937 | * schedule another work | ||
938 | */ | ||
939 | queue_work(psDevInfo->sync_display_wq, | ||
940 | &psDevInfo->sync_display_work); | ||
941 | goto ExitUnlock; | ||
942 | } | ||
943 | psFlipItem = | ||
944 | &psSwapChain->psFlipItems[psSwapChain->ulRemoveIndex]; | ||
945 | } | ||
946 | |||
947 | ExitUnlock: | ||
948 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
949 | } | ||
950 | |||
951 | /* | ||
952 | * Performs a flip. This function takes the necessary steps to present | ||
953 | * the buffer to be flipped in the display. | ||
954 | * in: hCmdCookie, ui32DataSize, pvData | ||
955 | */ | ||
956 | static IMG_BOOL ProcessFlip(IMG_HANDLE hCmdCookie, | ||
957 | IMG_UINT32 ui32DataSize, | ||
958 | IMG_VOID *pvData) | ||
959 | { | ||
960 | DISPLAYCLASS_FLIP_COMMAND *psFlipCmd; | ||
961 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
962 | struct OMAP_DISP_BUFFER *psBuffer; | ||
963 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
964 | struct omap_display_device *display; | ||
965 | #if defined(SYS_USING_INTERRUPTS) | ||
966 | struct OMAP_DISP_FLIP_ITEM* psFlipItem; | ||
967 | #endif | ||
968 | |||
969 | if(!hCmdCookie || !pvData) | ||
970 | { | ||
971 | WARNING_PRINTK("Ignoring call with NULL parameters"); | ||
972 | return IMG_FALSE; | ||
973 | } | ||
974 | |||
975 | psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)pvData; | ||
976 | |||
977 | if (psFlipCmd == IMG_NULL || | ||
978 | sizeof(DISPLAYCLASS_FLIP_COMMAND) != ui32DataSize) | ||
979 | { | ||
980 | WARNING_PRINTK("NULL command or command data size is wrong"); | ||
981 | return IMG_FALSE; | ||
982 | } | ||
983 | |||
984 | psDevInfo = (struct OMAP_DISP_DEVINFO*)psFlipCmd->hExtDevice; | ||
985 | psBuffer = (struct OMAP_DISP_BUFFER*)psFlipCmd->hExtBuffer; | ||
986 | psSwapChain = (struct OMAP_DISP_SWAPCHAIN*) psFlipCmd->hExtSwapChain; | ||
987 | display = psDevInfo->display; | ||
988 | |||
989 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
990 | |||
991 | if (psDevInfo->bDeviceSuspended) | ||
992 | { | ||
993 | /* If is suspended then assume the commands are completed */ | ||
994 | psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete( | ||
995 | hCmdCookie, IMG_TRUE); | ||
996 | goto ExitTrueUnlock; | ||
997 | } | ||
998 | |||
999 | #if defined(SYS_USING_INTERRUPTS) | ||
1000 | |||
1001 | if( psFlipCmd->ui32SwapInterval == 0 || | ||
1002 | psSwapChain->bFlushCommands == OMAP_TRUE) | ||
1003 | { | ||
1004 | #endif | ||
1005 | display->present_buffer(psBuffer->display_buffer); | ||
1006 | psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete( | ||
1007 | hCmdCookie, IMG_TRUE); | ||
1008 | |||
1009 | #if defined(SYS_USING_INTERRUPTS) | ||
1010 | goto ExitTrueUnlock; | ||
1011 | } | ||
1012 | |||
1013 | psFlipItem = &psSwapChain->psFlipItems[psSwapChain->ulInsertIndex]; | ||
1014 | |||
1015 | if(psFlipItem->bValid == OMAP_FALSE) | ||
1016 | { | ||
1017 | unsigned long ulMaxIndex = psSwapChain->ulBufferCount - 1; | ||
1018 | |||
1019 | psFlipItem->bFlipped = OMAP_FALSE; | ||
1020 | |||
1021 | /* | ||
1022 | * The buffer is queued here, must be consumed by the workqueue | ||
1023 | */ | ||
1024 | psFlipItem->hCmdComplete = (OMAP_HANDLE)hCmdCookie; | ||
1025 | psFlipItem->ulSwapInterval = | ||
1026 | (unsigned long)psFlipCmd->ui32SwapInterval; | ||
1027 | psFlipItem->sSysAddr = &psBuffer->sSysAddr; | ||
1028 | psFlipItem->bValid = OMAP_TRUE; | ||
1029 | psFlipItem->display_buffer = psBuffer->display_buffer; | ||
1030 | |||
1031 | psSwapChain->ulInsertIndex++; | ||
1032 | if(psSwapChain->ulInsertIndex > ulMaxIndex) | ||
1033 | psSwapChain->ulInsertIndex = 0; | ||
1034 | |||
1035 | /* Give work to the workqueue to sync with the display */ | ||
1036 | queue_work(psDevInfo->sync_display_wq, | ||
1037 | &psDevInfo->sync_display_work); | ||
1038 | |||
1039 | goto ExitTrueUnlock; | ||
1040 | } | ||
1041 | |||
1042 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
1043 | return IMG_FALSE; | ||
1044 | #endif | ||
1045 | |||
1046 | ExitTrueUnlock: | ||
1047 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
1048 | return IMG_TRUE; | ||
1049 | } | ||
1050 | |||
1051 | #if defined(LDM_PLATFORM) | ||
1052 | |||
1053 | /* | ||
1054 | * Function called when the driver must suspend | ||
1055 | */ | ||
1056 | static void DriverSuspend(void) | ||
1057 | { | ||
1058 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
1059 | int i; | ||
1060 | |||
1061 | if(!pDisplayDevices) | ||
1062 | return; | ||
1063 | |||
1064 | for(i = 0; i < display_devices_count; i++) | ||
1065 | { | ||
1066 | psDevInfo = &pDisplayDevices[i]; | ||
1067 | |||
1068 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
1069 | |||
1070 | if (psDevInfo->bDeviceSuspended) | ||
1071 | { | ||
1072 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
1073 | continue; | ||
1074 | } | ||
1075 | |||
1076 | psDevInfo->bDeviceSuspended = OMAP_TRUE; | ||
1077 | SetFlushStateInternalNoLock(psDevInfo, OMAP_TRUE); | ||
1078 | |||
1079 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
1080 | } | ||
1081 | } | ||
1082 | |||
1083 | /* | ||
1084 | * Function called when the driver must resume | ||
1085 | */ | ||
1086 | static void DriverResume(void) | ||
1087 | { | ||
1088 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
1089 | int i; | ||
1090 | |||
1091 | if(!pDisplayDevices) | ||
1092 | return; | ||
1093 | |||
1094 | for(i = 0; i < display_devices_count; i++) | ||
1095 | { | ||
1096 | psDevInfo = &pDisplayDevices[i]; | ||
1097 | |||
1098 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
1099 | |||
1100 | if (!psDevInfo->bDeviceSuspended) | ||
1101 | { | ||
1102 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
1103 | continue; | ||
1104 | } | ||
1105 | |||
1106 | SetFlushStateInternalNoLock(psDevInfo, OMAP_FALSE); | ||
1107 | psDevInfo->bDeviceSuspended = OMAP_FALSE; | ||
1108 | |||
1109 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
1110 | } | ||
1111 | } | ||
1112 | #endif /* defined(LDM_PLATFORM) */ | ||
1113 | |||
1114 | /* | ||
1115 | * Frees the kernel framebuffer | ||
1116 | * in: psDevInfo | ||
1117 | */ | ||
1118 | static void deinit_display_device(struct OMAP_DISP_DEVINFO *psDevInfo) | ||
1119 | { | ||
1120 | /* TODO: Are we sure there is nothing to do here? */ | ||
1121 | } | ||
1122 | |||
1123 | /* | ||
1124 | * Deinitialization routine for the 3rd party display driver | ||
1125 | */ | ||
1126 | static enum OMAP_ERROR destroy_display_devices(void) | ||
1127 | { | ||
1128 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
1129 | PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable; | ||
1130 | int i; | ||
1131 | |||
1132 | DEBUG_PRINTK("Deinitializing 3rd party display driver"); | ||
1133 | |||
1134 | if(!pDisplayDevices) | ||
1135 | return OMAP_OK; | ||
1136 | |||
1137 | for(i = 0; i < display_devices_count; i++) | ||
1138 | { | ||
1139 | psDevInfo = &pDisplayDevices[i]; | ||
1140 | if(!psDevInfo->display) | ||
1141 | continue; | ||
1142 | |||
1143 | /* Remove the ProcessFlip command callback */ | ||
1144 | psJTable = &psDevInfo->sPVRJTable; | ||
1145 | |||
1146 | if(!psJTable) | ||
1147 | continue; | ||
1148 | |||
1149 | if (psDevInfo->sPVRJTable.pfnPVRSRVRemoveCmdProcList( | ||
1150 | psDevInfo->ulDeviceID, | ||
1151 | OMAP_DC_CMD_COUNT) != PVRSRV_OK) | ||
1152 | { | ||
1153 | ERROR_PRINTK("Unable to remove callback for " | ||
1154 | "ProcessFlip command for display %lu", | ||
1155 | psDevInfo->ulDeviceID); | ||
1156 | return OMAP_ERROR_GENERIC; | ||
1157 | } | ||
1158 | |||
1159 | /* Remove the display device from services */ | ||
1160 | if (psJTable->pfnPVRSRVRemoveDCDevice( | ||
1161 | psDevInfo->ulDeviceID) != PVRSRV_OK) | ||
1162 | { | ||
1163 | ERROR_PRINTK("Unable to remove the display %lu " | ||
1164 | "from services", psDevInfo->ulDeviceID); | ||
1165 | return OMAP_ERROR_GENERIC; | ||
1166 | } | ||
1167 | |||
1168 | deinit_display_device(psDevInfo); | ||
1169 | } | ||
1170 | |||
1171 | kfree(pDisplayDevices); | ||
1172 | |||
1173 | return OMAP_OK; | ||
1174 | } | ||
1175 | |||
1176 | /* | ||
1177 | * Extracts the framebuffer data from the kernel driver | ||
1178 | * in: psDevInfo | ||
1179 | */ | ||
1180 | static enum OMAP_ERROR init_display_device(struct OMAP_DISP_DEVINFO *psDevInfo, | ||
1181 | struct omap_display_device *display) | ||
1182 | { | ||
1183 | int buffers_available = display->buffers_available; | ||
1184 | |||
1185 | /* Extract the needed data from the display struct */ | ||
1186 | DEBUG_PRINTK("Display '%s' id %i information:", display->name, | ||
1187 | display->id); | ||
1188 | DEBUG_PRINTK("*Width, height: %u,%u", display->width, | ||
1189 | display->height); | ||
1190 | DEBUG_PRINTK("*Rotation: %u", display->rotation); | ||
1191 | DEBUG_PRINTK("*Stride: %u bytes", display->byte_stride); | ||
1192 | DEBUG_PRINTK("*Buffers available: %u", buffers_available); | ||
1193 | DEBUG_PRINTK("*Bytes per pixel: %u (%u bpp)", | ||
1194 | display->bytes_per_pixel, display->bits_per_pixel); | ||
1195 | |||
1196 | if(display->bits_per_pixel == 16) | ||
1197 | { | ||
1198 | if(display->pixel_format == RGB_565) | ||
1199 | { | ||
1200 | DEBUG_PRINTK("*Format: RGB565"); | ||
1201 | psDevInfo->sDisplayFormat.pixelformat = | ||
1202 | PVRSRV_PIXEL_FORMAT_RGB565; | ||
1203 | } | ||
1204 | else | ||
1205 | WARNING_PRINTK("*Format: Unknown framebuffer" | ||
1206 | "format"); | ||
1207 | } | ||
1208 | else if(display->bits_per_pixel == 24 || | ||
1209 | display->bits_per_pixel == 32) | ||
1210 | { | ||
1211 | if(display->pixel_format == ARGB_8888) | ||
1212 | { | ||
1213 | DEBUG_PRINTK("*Format: ARGB8888"); | ||
1214 | psDevInfo->sDisplayFormat.pixelformat = | ||
1215 | PVRSRV_PIXEL_FORMAT_ARGB8888; | ||
1216 | |||
1217 | } | ||
1218 | else | ||
1219 | WARNING_PRINTK("*Format: Unknown framebuffer" | ||
1220 | "format"); | ||
1221 | } | ||
1222 | else | ||
1223 | WARNING_PRINTK("*Format: Unknown framebuffer format"); | ||
1224 | |||
1225 | if(display->main_buffer) | ||
1226 | { | ||
1227 | DEBUG_PRINTK("*Bytes per buffer: %lu", | ||
1228 | display->main_buffer->size); | ||
1229 | DEBUG_PRINTK("*Main buffer physical address: 0x%lx", | ||
1230 | display->main_buffer->physical_addr); | ||
1231 | DEBUG_PRINTK("*Main buffer virtual address: 0x%lx", | ||
1232 | display->main_buffer->virtual_addr); | ||
1233 | DEBUG_PRINTK("*Main buffer size: %lu bytes", | ||
1234 | display->main_buffer->size); | ||
1235 | } | ||
1236 | else | ||
1237 | { | ||
1238 | psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = 0; | ||
1239 | ERROR_PRINTK("*No main buffer found for display '%s'", | ||
1240 | display->name); | ||
1241 | return OMAP_ERROR_INIT_FAILURE; | ||
1242 | } | ||
1243 | |||
1244 | psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = buffers_available; | ||
1245 | mutex_init(&psDevInfo->sSwapChainLockMutex); | ||
1246 | psDevInfo->psSwapChain = 0; | ||
1247 | psDevInfo->bFlushCommands = OMAP_FALSE; | ||
1248 | psDevInfo->bDeviceSuspended = OMAP_FALSE; | ||
1249 | |||
1250 | if(psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers > 1) | ||
1251 | { | ||
1252 | if(MAX_BUFFERS_FLIPPING == 1) | ||
1253 | { | ||
1254 | DEBUG_PRINTK("Flipping support is possible" | ||
1255 | " but you decided not to use it"); | ||
1256 | } | ||
1257 | |||
1258 | DEBUG_PRINTK("*Flipping support"); | ||
1259 | if(psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers > | ||
1260 | MAX_BUFFERS_FLIPPING) | ||
1261 | psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = | ||
1262 | MAX_BUFFERS_FLIPPING; | ||
1263 | } | ||
1264 | else | ||
1265 | { | ||
1266 | DEBUG_PRINTK("*Flipping not supported"); | ||
1267 | } | ||
1268 | |||
1269 | if (psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers == 0) | ||
1270 | { | ||
1271 | psDevInfo->sDisplayInfo.ui32MaxSwapChains = 0; | ||
1272 | psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 0; | ||
1273 | } | ||
1274 | else | ||
1275 | { | ||
1276 | psDevInfo->sDisplayInfo.ui32MaxSwapChains = 1; | ||
1277 | psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 3; | ||
1278 | } | ||
1279 | psDevInfo->sDisplayInfo.ui32MinSwapInterval = 0; | ||
1280 | |||
1281 | /* Get the display and framebuffer needed info */ | ||
1282 | strncpy(psDevInfo->sDisplayInfo.szDisplayName, | ||
1283 | DISPLAY_DEVICE_NAME, MAX_DISPLAY_NAME_SIZE); | ||
1284 | |||
1285 | psDevInfo->sDisplayDim.ui32Width = display->width; | ||
1286 | psDevInfo->sDisplayDim.ui32Height = display->height; | ||
1287 | psDevInfo->sDisplayDim.ui32ByteStride = display->byte_stride; | ||
1288 | psDevInfo->sSystemBuffer.sSysAddr.uiAddr = | ||
1289 | display->main_buffer->physical_addr; | ||
1290 | psDevInfo->sSystemBuffer.sCPUVAddr = | ||
1291 | (IMG_CPU_VIRTADDR) display->main_buffer->virtual_addr; | ||
1292 | psDevInfo->sSystemBuffer.ulBufferSize = display->main_buffer->size; | ||
1293 | psDevInfo->display = display; | ||
1294 | |||
1295 | return OMAP_OK; | ||
1296 | } | ||
1297 | |||
1298 | /* | ||
1299 | * Initialization routine for the 3rd party display driver | ||
1300 | */ | ||
1301 | static enum OMAP_ERROR create_display_devices(void) | ||
1302 | { | ||
1303 | PFN_CMD_PROC pfnCmdProcList[OMAP_DC_CMD_COUNT]; | ||
1304 | IMG_UINT32 aui32SyncCountList[OMAP_DC_CMD_COUNT][2]; | ||
1305 | int i; | ||
1306 | unsigned int bytes_to_alloc; | ||
1307 | |||
1308 | DEBUG_PRINTK("Initializing 3rd party display driver"); | ||
1309 | |||
1310 | /* Ask for the number of displays available */ | ||
1311 | omap_display_init(); | ||
1312 | /* TODO: allow more displays */ | ||
1313 | display_devices_count = 1; // omap_display_count(); | ||
1314 | |||
1315 | DEBUG_PRINTK("Found %i displays", display_devices_count); | ||
1316 | |||
1317 | /* | ||
1318 | * Obtain the function pointer for the jump table from kernel | ||
1319 | * services to fill it with the function pointers that we want | ||
1320 | */ | ||
1321 | if(get_pvr_dc_jtable ("PVRGetDisplayClassJTable", | ||
1322 | &pfnGetPVRJTable) != OMAP_OK) | ||
1323 | { | ||
1324 | ERROR_PRINTK("Unable to get the function to get the" | ||
1325 | " jump table display->services"); | ||
1326 | return OMAP_ERROR_INIT_FAILURE; | ||
1327 | } | ||
1328 | |||
1329 | /* | ||
1330 | * Allocate the display device structures, one per display available | ||
1331 | */ | ||
1332 | bytes_to_alloc = | ||
1333 | sizeof(struct OMAP_DISP_DEVINFO) * display_devices_count; | ||
1334 | pDisplayDevices = (struct OMAP_DISP_DEVINFO *) kmalloc( | ||
1335 | bytes_to_alloc, GFP_KERNEL); | ||
1336 | if(!pDisplayDevices) | ||
1337 | { | ||
1338 | pDisplayDevices = NULL; | ||
1339 | ERROR_PRINTK("Out of memory"); | ||
1340 | return OMAP_ERROR_OUT_OF_MEMORY; | ||
1341 | } | ||
1342 | memset(pDisplayDevices, 0, bytes_to_alloc); | ||
1343 | |||
1344 | /* | ||
1345 | * Initialize each display device | ||
1346 | */ | ||
1347 | for(i = 0; i < display_devices_count; i++) | ||
1348 | { | ||
1349 | struct omap_display_device *display; | ||
1350 | struct OMAP_DISP_DEVINFO * psDevInfo; | ||
1351 | enum omap_display_id id; | ||
1352 | |||
1353 | psDevInfo = &pDisplayDevices[i]; | ||
1354 | psDevInfo->display = 0; | ||
1355 | |||
1356 | id = OMAP_DISPID_VIRTUAL; | ||
1357 | |||
1358 | /* | ||
1359 | * TODO: Modify this to allow primary, secondary, | ||
1360 | * not only virtual | ||
1361 | */ | ||
1362 | #if 0 | ||
1363 | switch(i) | ||
1364 | { | ||
1365 | case 0: | ||
1366 | id = OMAP_DISPID_PRIMARY; | ||
1367 | break; | ||
1368 | case 1: | ||
1369 | id = OMAP_DISPID_SECONDARY; | ||
1370 | break; | ||
1371 | case 2: | ||
1372 | id = OMAP_DISPID_TERTIARY; | ||
1373 | break; | ||
1374 | case 3: | ||
1375 | id = OMAP_DISPID_VIRTUAL; | ||
1376 | break; | ||
1377 | default: | ||
1378 | ERROR_PRINTK("Invalid display type %i", i); | ||
1379 | BUG(); | ||
1380 | } | ||
1381 | |||
1382 | #endif | ||
1383 | |||
1384 | display = omap_display_get(id); | ||
1385 | if(!display) | ||
1386 | continue; | ||
1387 | |||
1388 | if(init_display_device(psDevInfo, display) != OMAP_OK) | ||
1389 | { | ||
1390 | ERROR_PRINTK("Unable to initialize display '%s' type" | ||
1391 | " %u", display->name, display->id); | ||
1392 | continue; | ||
1393 | #if 0 | ||
1394 | kfree(pDisplayDevices); | ||
1395 | pDisplayDevices = NULL; | ||
1396 | return OMAP_ERROR_INIT_FAILURE; | ||
1397 | #endif | ||
1398 | } | ||
1399 | |||
1400 | /* | ||
1401 | * Populate each display device structure | ||
1402 | */ | ||
1403 | if(!(*pfnGetPVRJTable)(&psDevInfo->sPVRJTable)) | ||
1404 | { | ||
1405 | ERROR_PRINTK("Unable to get the jump table" | ||
1406 | " display->services for display '%s'", | ||
1407 | display->name); | ||
1408 | return OMAP_ERROR_INIT_FAILURE; | ||
1409 | } | ||
1410 | |||
1411 | /* Populate the function table that services will use */ | ||
1412 | psDevInfo->sDCJTable.ui32TableSize = | ||
1413 | sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE); | ||
1414 | psDevInfo->sDCJTable.pfnOpenDCDevice = OpenDCDevice; | ||
1415 | psDevInfo->sDCJTable.pfnCloseDCDevice = CloseDCDevice; | ||
1416 | psDevInfo->sDCJTable.pfnEnumDCFormats = EnumDCFormats; | ||
1417 | psDevInfo->sDCJTable.pfnEnumDCDims = EnumDCDims; | ||
1418 | psDevInfo->sDCJTable.pfnGetDCSystemBuffer = GetDCSystemBuffer; | ||
1419 | psDevInfo->sDCJTable.pfnGetDCInfo = GetDCInfo; | ||
1420 | psDevInfo->sDCJTable.pfnGetBufferAddr = GetDCBufferAddr; | ||
1421 | psDevInfo->sDCJTable.pfnCreateDCSwapChain = CreateDCSwapChain; | ||
1422 | psDevInfo->sDCJTable.pfnDestroyDCSwapChain = | ||
1423 | DestroyDCSwapChain; | ||
1424 | psDevInfo->sDCJTable.pfnSetDCDstRect = SetDCDstRect; | ||
1425 | psDevInfo->sDCJTable.pfnSetDCSrcRect = SetDCSrcRect; | ||
1426 | psDevInfo->sDCJTable.pfnSetDCDstColourKey = SetDCDstColourKey; | ||
1427 | psDevInfo->sDCJTable.pfnSetDCSrcColourKey = SetDCSrcColourKey; | ||
1428 | psDevInfo->sDCJTable.pfnGetDCBuffers = GetDCBuffers; | ||
1429 | psDevInfo->sDCJTable.pfnSwapToDCBuffer = SwapToDCBuffer; | ||
1430 | psDevInfo->sDCJTable.pfnSwapToDCSystem = SwapToDCSystem; | ||
1431 | psDevInfo->sDCJTable.pfnSetDCState = SetDCState; | ||
1432 | |||
1433 | /* Register the display device */ | ||
1434 | if(psDevInfo->sPVRJTable.pfnPVRSRVRegisterDCDevice( | ||
1435 | &psDevInfo->sDCJTable, | ||
1436 | (IMG_UINT32*) &psDevInfo->ulDeviceID) != PVRSRV_OK) | ||
1437 | { | ||
1438 | ERROR_PRINTK("Unable to register the jump table" | ||
1439 | " services->display"); | ||
1440 | return OMAP_ERROR_DEVICE_REGISTER_FAILED; | ||
1441 | } | ||
1442 | |||
1443 | DEBUG_PRINTK("Display '%s' registered with the GPU with" | ||
1444 | " id %lu", display->name, psDevInfo->ulDeviceID); | ||
1445 | |||
1446 | /* | ||
1447 | * Register the ProcessFlip function to notify when a frame is | ||
1448 | * ready to be flipped | ||
1449 | */ | ||
1450 | pfnCmdProcList[DC_FLIP_COMMAND] = ProcessFlip; | ||
1451 | aui32SyncCountList[DC_FLIP_COMMAND][0] = 0; | ||
1452 | aui32SyncCountList[DC_FLIP_COMMAND][1] = 2; | ||
1453 | if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterCmdProcList( | ||
1454 | psDevInfo->ulDeviceID, &pfnCmdProcList[0], | ||
1455 | aui32SyncCountList, OMAP_DC_CMD_COUNT) != PVRSRV_OK) | ||
1456 | { | ||
1457 | ERROR_PRINTK("Unable to register callback for " | ||
1458 | "ProcessFlip command"); | ||
1459 | return OMAP_ERROR_CANT_REGISTER_CALLBACK; | ||
1460 | } | ||
1461 | |||
1462 | } | ||
1463 | return OMAP_OK; | ||
1464 | } | ||
1465 | |||
1466 | /* | ||
1467 | * Here we get the function pointer to get jump table from | ||
1468 | * services using an external function. | ||
1469 | * in: szFunctionName | ||
1470 | * out: ppfnFuncTable | ||
1471 | */ | ||
1472 | static enum OMAP_ERROR get_pvr_dc_jtable (char *szFunctionName, | ||
1473 | PFN_DC_GET_PVRJTABLE *ppfnFuncTable) | ||
1474 | { | ||
1475 | if(strcmp("PVRGetDisplayClassJTable", szFunctionName) != 0) | ||
1476 | { | ||
1477 | ERROR_PRINTK("Unable to get function pointer for %s" | ||
1478 | " from services", szFunctionName); | ||
1479 | return OMAP_ERROR_INVALID_PARAMS; | ||
1480 | } | ||
1481 | *ppfnFuncTable = PVRGetDisplayClassJTable; | ||
1482 | |||
1483 | return OMAP_OK; | ||
1484 | } | ||
1485 | |||
1486 | #if defined(LDM_PLATFORM) | ||
1487 | |||
1488 | static volatile enum OMAP_BOOL bDeviceSuspended; | ||
1489 | |||
1490 | /* | ||
1491 | * Common suspend driver function | ||
1492 | * in: psSwapChain, aPhyAddr | ||
1493 | */ | ||
1494 | static void CommonSuspend(void) | ||
1495 | { | ||
1496 | if (bDeviceSuspended) | ||
1497 | { | ||
1498 | DEBUG_PRINTK("Driver is already suspended"); | ||
1499 | return; | ||
1500 | } | ||
1501 | |||
1502 | DriverSuspend(); | ||
1503 | bDeviceSuspended = OMAP_TRUE; | ||
1504 | } | ||
1505 | |||
1506 | #if defined(SGX_EARLYSUSPEND) | ||
1507 | |||
1508 | static struct early_suspend driver_early_suspend; | ||
1509 | |||
1510 | /* | ||
1511 | * Android specific, driver is requested to be suspended | ||
1512 | * in: ea_event | ||
1513 | */ | ||
1514 | static void DriverSuspend_Entry(struct early_suspend *ea_event) | ||
1515 | { | ||
1516 | DEBUG_PRINTK("Requested driver suspend"); | ||
1517 | CommonSuspend(); | ||
1518 | } | ||
1519 | |||
1520 | /* | ||
1521 | * Android specific, driver is requested to be suspended | ||
1522 | * in: ea_event | ||
1523 | */ | ||
1524 | static void DriverResume_Entry(struct early_suspend *ea_event) | ||
1525 | { | ||
1526 | DEBUG_PRINTK("Requested driver resume"); | ||
1527 | DriverResume(); | ||
1528 | bDeviceSuspended = OMAP_FALSE; | ||
1529 | } | ||
1530 | |||
1531 | static struct platform_driver omap_sgx_dc_driver = { | ||
1532 | .driver = { | ||
1533 | .name = DRVNAME, | ||
1534 | } | ||
1535 | }; | ||
1536 | |||
1537 | #else /* defined(SGX_EARLYSUSPEND) */ | ||
1538 | |||
1539 | /* | ||
1540 | * Function called when the driver is requested to be suspended | ||
1541 | * in: pDevice, state | ||
1542 | */ | ||
1543 | static int DriverSuspend_Entry(struct platform_device unref__ *pDevice, | ||
1544 | pm_message_t unref__ state) | ||
1545 | { | ||
1546 | DEBUG_PRINTK("Requested driver suspend"); | ||
1547 | CommonSuspend(); | ||
1548 | return 0; | ||
1549 | } | ||
1550 | |||
1551 | /* | ||
1552 | * Function called when the driver is requested to resume | ||
1553 | * in: pDevice | ||
1554 | */ | ||
1555 | static int DriverResume_Entry(struct platform_device unref__ *pDevice) | ||
1556 | { | ||
1557 | DEBUG_PRINTK("Requested driver resume"); | ||
1558 | DriverResume(); | ||
1559 | bDeviceSuspended = OMAP_FALSE; | ||
1560 | return 0; | ||
1561 | } | ||
1562 | |||
1563 | /* | ||
1564 | * Function called when the driver is requested to shutdown | ||
1565 | * in: pDevice | ||
1566 | */ | ||
1567 | static IMG_VOID DriverShutdown_Entry( | ||
1568 | struct platform_device unref__ *pDevice) | ||
1569 | { | ||
1570 | DEBUG_PRINTK("Requested driver shutdown"); | ||
1571 | CommonSuspend(); | ||
1572 | } | ||
1573 | |||
1574 | static struct platform_driver omap_sgx_dc_driver = { | ||
1575 | .driver = { | ||
1576 | .name = DRVNAME, | ||
1577 | }, | ||
1578 | .suspend = DriverSuspend_Entry, | ||
1579 | .resume = DriverResume_Entry, | ||
1580 | .shutdown = DriverShutdown_Entry, | ||
1581 | }; | ||
1582 | |||
1583 | #endif /* defined(SGX_EARLYSUSPEND) */ | ||
1584 | |||
1585 | #endif /* defined(LDM_PLATFORM) */ | ||
1586 | |||
1587 | /* | ||
1588 | * Driver init function | ||
1589 | */ | ||
1590 | static int __init omap_sgx_dc_init(void) | ||
1591 | { | ||
1592 | if(create_display_devices() != OMAP_OK) | ||
1593 | { | ||
1594 | WARNING_PRINTK("Driver init failed"); | ||
1595 | return -ENODEV; | ||
1596 | } | ||
1597 | |||
1598 | #if defined(LDM_PLATFORM) | ||
1599 | DEBUG_PRINTK("Registering platform driver"); | ||
1600 | if (platform_driver_register(&omap_sgx_dc_driver)) | ||
1601 | { | ||
1602 | WARNING_PRINTK("Unable to register platform driver"); | ||
1603 | if(destroy_display_devices() != OMAP_OK) | ||
1604 | WARNING_PRINTK("Driver cleanup failed\n"); | ||
1605 | return -ENODEV; | ||
1606 | } | ||
1607 | |||
1608 | #if defined(SGX_EARLYSUSPEND) | ||
1609 | driver_early_suspend.suspend = DriverSuspend_Entry; | ||
1610 | driver_early_suspend.resume = DriverResume_Entry; | ||
1611 | driver_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; | ||
1612 | register_early_suspend(&driver_early_suspend); | ||
1613 | DEBUG_PRINTK("Registered early suspend support"); | ||
1614 | #endif | ||
1615 | |||
1616 | #endif | ||
1617 | return 0; | ||
1618 | } | ||
1619 | |||
1620 | /* | ||
1621 | * Driver exit function | ||
1622 | */ | ||
1623 | static IMG_VOID __exit omap_sgx_dc_deinit(IMG_VOID) | ||
1624 | { | ||
1625 | #if defined(LDM_PLATFORM) | ||
1626 | DEBUG_PRINTK("Removing platform driver"); | ||
1627 | platform_driver_unregister(&omap_sgx_dc_driver); | ||
1628 | #if defined(SGX_EARLYSUSPEND) | ||
1629 | unregister_early_suspend(&driver_early_suspend); | ||
1630 | #endif | ||
1631 | #endif | ||
1632 | if(destroy_display_devices() != OMAP_OK) | ||
1633 | WARNING_PRINTK("Driver cleanup failed"); | ||
1634 | } | ||
1635 | |||
1636 | MODULE_SUPPORTED_DEVICE(DEVNAME); | ||
1637 | late_initcall(omap_sgx_dc_init); | ||
1638 | module_exit(omap_sgx_dc_deinit); | ||