aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/pvr/display/omap_sgx_displayclass.c
diff options
context:
space:
mode:
authorHemant Hariyani <hemanthariyani@ti.com>2011-08-25 02:57:15 -0400
committerPaolo Pisati <paolo.pisati@canonical.com>2012-08-17 04:18:33 -0400
commit6e90775f610ab87bd86a79f189aca993e44b3bdf (patch)
tree3b44756d6a8e69dea6c0dbeb2244482b31d32ffc /drivers/gpu/pvr/display/omap_sgx_displayclass.c
parent1d63da95fb8e073f94c3c63d82f91c49bb2bd08a (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.c1638
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, \
51CONFIG_FB_OMAP2_NUM_FBS must be equal or greater than 2 \
52see 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 */
59static PFN_DC_GET_PVRJTABLE pfnGetPVRJTable = NULL;
60
61/* Pointer to the display devices */
62static struct OMAP_DISP_DEVINFO *pDisplayDevices = NULL;
63static int display_devices_count = 0;
64
65static void display_sync_handler(struct work_struct *work);
66static 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 */
76static 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 */
91static 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 */
103static 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 */
115static 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 */
127static 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 */
139static 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 */
156static 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 */
216static 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 */
259static 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 */
278static 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 */
328static 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 */
356static 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 */
385static 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 */
406static 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 */
427static 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 */
468static 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
677ErrorFreeBuffers:
678 kfree(psBuffer);
679ErrorFreeSwapChain:
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 */
689static 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 */
757static 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 */
793static 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 */
823static 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
866static 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
947ExitUnlock:
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 */
956static 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
1046ExitTrueUnlock:
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 */
1056static 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 */
1086static 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 */
1118static 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 */
1126static 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 */
1180static 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 */
1301static 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 */
1472static 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
1488static volatile enum OMAP_BOOL bDeviceSuspended;
1489
1490/*
1491 * Common suspend driver function
1492 * in: psSwapChain, aPhyAddr
1493 */
1494static 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
1508static struct early_suspend driver_early_suspend;
1509
1510/*
1511 * Android specific, driver is requested to be suspended
1512 * in: ea_event
1513 */
1514static 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 */
1524static void DriverResume_Entry(struct early_suspend *ea_event)
1525{
1526 DEBUG_PRINTK("Requested driver resume");
1527 DriverResume();
1528 bDeviceSuspended = OMAP_FALSE;
1529}
1530
1531static 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 */
1543static 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 */
1555static 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 */
1567static IMG_VOID DriverShutdown_Entry(
1568 struct platform_device unref__ *pDevice)
1569{
1570 DEBUG_PRINTK("Requested driver shutdown");
1571 CommonSuspend();
1572}
1573
1574static 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 */
1590static 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 */
1623static 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
1636MODULE_SUPPORTED_DEVICE(DEVNAME);
1637late_initcall(omap_sgx_dc_init);
1638module_exit(omap_sgx_dc_deinit);