gpu: pvr: pdump: review use of PDumpSuspended
[sgx.git] / pvr / omaplfb_displayclass.c
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 with
15  * 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 #include <linux/fb.h>
31 #include <linux/module.h>
32 #include <linux/string.h>
33 #include <linux/notifier.h>
34
35 #include <asm/div64.h>
36 #include <video/sgx-util.h>
37
38 #include "img_defs.h"
39 #include "servicesext.h"
40 #include "kerneldisplay.h"
41 #include "omaplfb.h"
42
43 static void *gpvAnchor;
44
45 static int fb_idx;
46
47 #define OMAPLFB_COMMAND_COUNT           1
48
49 static IMG_BOOL (*pfnGetPVRJTable)(struct PVRSRV_DC_DISP2SRV_KMJTABLE *);
50
51 static struct OMAPLFB_DEVINFO *GetAnchorPtr(void)
52 {
53         return (struct OMAPLFB_DEVINFO *)gpvAnchor;
54 }
55
56 static void SetAnchorPtr(struct OMAPLFB_DEVINFO *psDevInfo)
57 {
58         gpvAnchor = (void *) psDevInfo;
59 }
60
61 static int FrameBufferEvents(struct notifier_block *psNotif,
62                              unsigned long event, void *data)
63 {
64         struct OMAPLFB_DEVINFO *psDevInfo;
65         struct OMAPLFB_SWAPCHAIN *psSwapChain;
66         struct fb_event *psFBEvent = (struct fb_event *)data;
67
68         if (event != FB_EVENT_BLANK)
69                 return 0;
70
71         psDevInfo = GetAnchorPtr();
72         psSwapChain = psDevInfo->psSwapChain;
73         psSwapChain->bBlanked = (*(int *)psFBEvent->data != 0);
74
75         return 0;
76 }
77
78 static enum PVRSRV_ERROR EnableLFBEventNotification(struct OMAPLFB_DEVINFO
79                                                                    *psDevInfo)
80 {
81         int res;
82         struct OMAPLFB_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain;
83
84         memset(&psDevInfo->sLINNotifBlock, 0,
85                sizeof(psDevInfo->sLINNotifBlock));
86
87         psDevInfo->sLINNotifBlock.notifier_call = FrameBufferEvents;
88
89         psSwapChain->bBlanked = IMG_FALSE;
90
91         res = fb_register_client(&psDevInfo->sLINNotifBlock);
92         if (res != 0) {
93                 printk(KERN_WARNING DRIVER_PREFIX
94                        ": fb_register_client failed (%d)", res);
95
96                 return PVRSRV_ERROR_GENERIC;
97         }
98
99         return PVRSRV_OK;
100 }
101
102 static enum PVRSRV_ERROR DisableLFBEventNotification(struct OMAPLFB_DEVINFO
103                                                                    *psDevInfo)
104 {
105         int res;
106
107         res = fb_unregister_client(&psDevInfo->sLINNotifBlock);
108         if (res != 0) {
109                 printk(KERN_WARNING DRIVER_PREFIX
110                        ": fb_unregister_client failed (%d)", res);
111                 return PVRSRV_ERROR_GENERIC;
112         }
113
114         return PVRSRV_OK;
115 }
116
117 static enum PVRSRV_ERROR OpenDCDevice(u32 ui32DeviceID, void **phDevice,
118                                 struct PVRSRV_SYNC_DATA *psSystemBufferSyncData)
119 {
120         struct OMAPLFB_DEVINFO *psDevInfo;
121
122         PVR_UNREFERENCED_PARAMETER(ui32DeviceID);
123
124         psDevInfo = GetAnchorPtr();
125
126         psDevInfo->sSystemBuffer.psSyncData = psSystemBufferSyncData;
127
128         *phDevice = (void *) psDevInfo;
129
130         return PVRSRV_OK;
131 }
132
133 static enum PVRSRV_ERROR CloseDCDevice(void *hDevice)
134 {
135         PVR_UNREFERENCED_PARAMETER(hDevice);
136
137         return PVRSRV_OK;
138 }
139
140 static enum PVRSRV_ERROR EnumDCFormats(void *hDevice, u32 *pui32NumFormats,
141                                   struct DISPLAY_FORMAT *psFormat)
142 {
143         struct OMAPLFB_DEVINFO *psDevInfo;
144
145         if (!hDevice || !pui32NumFormats)
146                 return PVRSRV_ERROR_INVALID_PARAMS;
147
148         psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice;
149
150         *pui32NumFormats = 1;
151
152         if (psFormat)
153                 psFormat[0] = psDevInfo->sDisplayFormat;
154
155         return PVRSRV_OK;
156 }
157
158 static enum PVRSRV_ERROR EnumDCDims(void *hDevice,
159                                struct DISPLAY_FORMAT *psFormat,
160                                u32 *pui32NumDims, struct DISPLAY_DIMS *psDim)
161 {
162         struct OMAPLFB_DEVINFO *psDevInfo;
163
164         if (!hDevice || !psFormat || !pui32NumDims)
165                 return PVRSRV_ERROR_INVALID_PARAMS;
166
167         psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice;
168
169         *pui32NumDims = 1;
170
171         if (psDim)
172                 psDim[0] = psDevInfo->sDisplayDim;
173
174         return PVRSRV_OK;
175 }
176
177 static enum PVRSRV_ERROR GetDCSystemBuffer(void *hDevice, void **phBuffer)
178 {
179         struct OMAPLFB_DEVINFO *psDevInfo;
180
181         if (!hDevice || !phBuffer)
182                 return PVRSRV_ERROR_INVALID_PARAMS;
183
184         psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice;
185
186         *phBuffer = (void *) &psDevInfo->sSystemBuffer;
187
188         return PVRSRV_OK;
189 }
190
191 static enum PVRSRV_ERROR GetDCInfo(void *hDevice, struct DISPLAY_INFO *psDCInfo)
192 {
193         struct OMAPLFB_DEVINFO *psDevInfo;
194
195         if (!hDevice || !psDCInfo)
196                 return PVRSRV_ERROR_INVALID_PARAMS;
197
198         psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice;
199
200         *psDCInfo = psDevInfo->sDisplayInfo;
201
202         return PVRSRV_OK;
203 }
204
205 static enum PVRSRV_ERROR GetDCBufferAddr(void *hDevice, void *hBuffer,
206                                     struct IMG_SYS_PHYADDR **ppsSysAddr,
207                                     u32 *pui32ByteSize,
208                                     void __iomem **ppvCpuVAddr,
209                                     void **phOSMapInfo,
210                                     IMG_BOOL *pbIsContiguous)
211 {
212         struct OMAPLFB_DEVINFO *psDevInfo;
213         struct OMAPLFB_BUFFER *psSystemBuffer;
214
215         if (!hDevice)
216                 return PVRSRV_ERROR_INVALID_PARAMS;
217         psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice;
218
219         if (!hBuffer)
220                 return PVRSRV_ERROR_INVALID_PARAMS;
221         psSystemBuffer = (struct OMAPLFB_BUFFER *)hBuffer;
222
223         if (!ppsSysAddr)
224                 return PVRSRV_ERROR_INVALID_PARAMS;
225
226         *ppsSysAddr = &psSystemBuffer->sSysAddr;
227
228         if (!pui32ByteSize)
229                 return PVRSRV_ERROR_INVALID_PARAMS;
230
231         *pui32ByteSize = psDevInfo->sFBInfo.ui32BufferSize;
232
233         if (ppvCpuVAddr)
234                 *ppvCpuVAddr = psSystemBuffer->sCPUVAddr;
235
236         if (phOSMapInfo)
237                 *phOSMapInfo = (void *) 0;
238
239         if (pbIsContiguous)
240                 *pbIsContiguous = IMG_TRUE;
241
242         return PVRSRV_OK;
243 }
244
245 static enum PVRSRV_ERROR CreateDCSwapChain(void *hDevice, u32 ui32Flags,
246                               struct DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib,
247                               struct DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib,
248                               u32 ui32BufferCount,
249                               struct PVRSRV_SYNC_DATA **ppsSyncData,
250                               u32 ui32OEMFlags, void **phSwapChain,
251                               u32 *pui32SwapChainID)
252 {
253         struct OMAPLFB_DEVINFO *psDevInfo;
254         struct OMAPLFB_SWAPCHAIN *psSwapChain;
255         struct OMAPLFB_BUFFER *psBuffer;
256         u32 i;
257         enum PVRSRV_ERROR eError = PVRSRV_ERROR_GENERIC;
258
259         PVR_UNREFERENCED_PARAMETER(ui32OEMFlags);
260         PVR_UNREFERENCED_PARAMETER(pui32SwapChainID);
261
262         if (!hDevice || !psDstSurfAttrib || !psSrcSurfAttrib ||
263             !ppsSyncData || !phSwapChain)
264                 return PVRSRV_ERROR_INVALID_PARAMS;
265
266         psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice;
267
268         if (psDevInfo->sDisplayInfo.ui32MaxSwapChains == 0)
269                 return PVRSRV_ERROR_NOT_SUPPORTED;
270
271         if (psDevInfo->psSwapChain != NULL)
272                 return PVRSRV_ERROR_FLIP_CHAIN_EXISTS;
273
274         if (ui32BufferCount > psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers)
275                 return PVRSRV_ERROR_TOOMANYBUFFERS;
276
277         if ((psDevInfo->sFBInfo.ui32RoundedBufferSize * ui32BufferCount) >
278             psDevInfo->sFBInfo.ui32FBSize)
279                 return PVRSRV_ERROR_TOOMANYBUFFERS;
280
281         if (psDstSurfAttrib->pixelformat !=
282                         psDevInfo->sDisplayFormat.pixelformat ||
283             psDstSurfAttrib->sDims.ui32ByteStride !=
284                         psDevInfo->sDisplayDim.ui32ByteStride ||
285             psDstSurfAttrib->sDims.ui32Width !=
286                         psDevInfo->sDisplayDim.ui32Width ||
287             psDstSurfAttrib->sDims.ui32Height !=
288                         psDevInfo->sDisplayDim.ui32Height)
289                 return PVRSRV_ERROR_INVALID_PARAMS;
290
291         if (psDstSurfAttrib->pixelformat != psSrcSurfAttrib->pixelformat ||
292             psDstSurfAttrib->sDims.ui32ByteStride !=
293                         psSrcSurfAttrib->sDims.ui32ByteStride ||
294             psDstSurfAttrib->sDims.ui32Width !=
295                         psSrcSurfAttrib->sDims.ui32Width ||
296             psDstSurfAttrib->sDims.ui32Height !=
297                         psSrcSurfAttrib->sDims.ui32Height)
298                 return PVRSRV_ERROR_INVALID_PARAMS;
299
300         PVR_UNREFERENCED_PARAMETER(ui32Flags);
301
302         psSwapChain = (struct OMAPLFB_SWAPCHAIN *)
303                         OMAPLFBAllocKernelMem(sizeof(struct OMAPLFB_SWAPCHAIN));
304         if (!psSwapChain)
305                 return PVRSRV_ERROR_OUT_OF_MEMORY;
306
307         psBuffer = (struct OMAPLFB_BUFFER *)
308              OMAPLFBAllocKernelMem(sizeof(struct OMAPLFB_BUFFER) *
309                                                      ui32BufferCount);
310         if (!psBuffer) {
311                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
312                 goto ErrorFreeSwapChain;
313         }
314
315         psSwapChain->ui32BufferCount = ui32BufferCount;
316         psSwapChain->psBuffer = psBuffer;
317         psSwapChain->psPVRJTable = &psDevInfo->sPVRJTable;
318
319         for (i = 0; i < ui32BufferCount - 1; i++)
320                 psBuffer[i].psNext = &psBuffer[i + 1];
321
322         psBuffer[i].psNext = &psBuffer[0];
323
324         for (i = 0; i < ui32BufferCount; i++) {
325                 u32 ui32BufferOffset = i *
326                         psDevInfo->sFBInfo.ui32RoundedBufferSize;
327
328                 psBuffer[i].psSyncData = ppsSyncData[i];
329
330                 psBuffer[i].sSysAddr.uiAddr =
331                     psDevInfo->sFBInfo.sSysAddr.uiAddr + ui32BufferOffset;
332                 psBuffer[i].sCPUVAddr =
333                     psDevInfo->sFBInfo.sCPUVAddr + ui32BufferOffset;
334         }
335
336         psDevInfo->psSwapChain = psSwapChain;
337
338         eError = EnableLFBEventNotification(psDevInfo);
339         if (eError != PVRSRV_OK) {
340                 printk(DRIVER_PREFIX
341                        ": Couldn't enable framebuffer event notification\n");
342                 goto ErrorFreeBuffer;
343         }
344
345         *phSwapChain = (void *) psSwapChain;
346
347         return PVRSRV_OK;
348
349 ErrorFreeBuffer:
350         OMAPLFBFreeKernelMem(psBuffer);
351 ErrorFreeSwapChain:
352         OMAPLFBFreeKernelMem(psSwapChain);
353
354         return eError;
355 }
356
357 static enum PVRSRV_ERROR DestroyDCSwapChain(void *hDevice, void *hSwapChain)
358 {
359         struct OMAPLFB_DEVINFO *psDevInfo;
360         struct OMAPLFB_SWAPCHAIN *psSwapChain;
361         enum PVRSRV_ERROR eError;
362
363         if (!hDevice || !hSwapChain)
364                 return PVRSRV_ERROR_INVALID_PARAMS;
365
366         psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice;
367         psSwapChain = (struct OMAPLFB_SWAPCHAIN *)hSwapChain;
368         if (psSwapChain != psDevInfo->psSwapChain)
369                 return PVRSRV_ERROR_INVALID_PARAMS;
370
371         eError = DisableLFBEventNotification(psDevInfo);
372         if (eError != PVRSRV_OK)
373                 printk(KERN_WARNING DRIVER_PREFIX
374                        ": Couldn't disable framebuffer event notification\n");
375
376         psDevInfo->psSwapChain = NULL;
377
378         OMAPLFBFreeKernelMem(psSwapChain->psBuffer);
379         OMAPLFBFreeKernelMem(psSwapChain);
380
381         return PVRSRV_OK;
382 }
383
384 static enum PVRSRV_ERROR SetDCDstRect(void *hDevice,
385                                  void *hSwapChain, struct IMG_RECT *psRect)
386 {
387         PVR_UNREFERENCED_PARAMETER(hDevice);
388         PVR_UNREFERENCED_PARAMETER(hSwapChain);
389         PVR_UNREFERENCED_PARAMETER(psRect);
390
391         return PVRSRV_ERROR_NOT_SUPPORTED;
392 }
393
394 static enum PVRSRV_ERROR SetDCSrcRect(void *hDevice,
395                                  void *hSwapChain, struct IMG_RECT *psRect)
396 {
397         PVR_UNREFERENCED_PARAMETER(hDevice);
398         PVR_UNREFERENCED_PARAMETER(hSwapChain);
399         PVR_UNREFERENCED_PARAMETER(psRect);
400
401         return PVRSRV_ERROR_NOT_SUPPORTED;
402 }
403
404 static enum PVRSRV_ERROR SetDCDstColourKey(void *hDevice, void *hSwapChain,
405                                       u32 ui32CKColour)
406 {
407         PVR_UNREFERENCED_PARAMETER(hDevice);
408         PVR_UNREFERENCED_PARAMETER(hSwapChain);
409         PVR_UNREFERENCED_PARAMETER(ui32CKColour);
410
411         return PVRSRV_ERROR_NOT_SUPPORTED;
412 }
413
414 static enum PVRSRV_ERROR SetDCSrcColourKey(void *hDevice, void *hSwapChain,
415                                       u32 ui32CKColour)
416 {
417         PVR_UNREFERENCED_PARAMETER(hDevice);
418         PVR_UNREFERENCED_PARAMETER(hSwapChain);
419         PVR_UNREFERENCED_PARAMETER(ui32CKColour);
420
421         return PVRSRV_ERROR_NOT_SUPPORTED;
422 }
423
424 static enum PVRSRV_ERROR GetDCBuffers(void *hDevice, void *hSwapChain,
425                                  u32 *pui32BufferCount, void **phBuffer)
426 {
427         struct OMAPLFB_DEVINFO *psDevInfo;
428         struct OMAPLFB_SWAPCHAIN *psSwapChain;
429         u32 i;
430
431         if (!hDevice || !hSwapChain || !pui32BufferCount || !phBuffer)
432                 return PVRSRV_ERROR_INVALID_PARAMS;
433
434         psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice;
435         psSwapChain = (struct OMAPLFB_SWAPCHAIN *)hSwapChain;
436         if (psSwapChain != psDevInfo->psSwapChain)
437                 return PVRSRV_ERROR_INVALID_PARAMS;
438
439         *pui32BufferCount = psSwapChain->ui32BufferCount;
440
441         for (i = 0; i < psSwapChain->ui32BufferCount; i++)
442                 phBuffer[i] = (void *) &psSwapChain->psBuffer[i];
443
444         return PVRSRV_OK;
445 }
446
447 static IMG_BOOL ProcessFlip(void *hCmdCookie, u32 ui32DataSize, void *pvData)
448 {
449         struct DISPLAYCLASS_FLIP_COMMAND *psFlipCmd;
450         struct OMAPLFB_DEVINFO *psDevInfo;
451         struct OMAPLFB_BUFFER *psBuffer;
452         struct OMAPLFB_SWAPCHAIN *psSwapChain;
453
454         if (!hCmdCookie || !pvData)
455                 return IMG_FALSE;
456
457         psFlipCmd = (struct DISPLAYCLASS_FLIP_COMMAND *)pvData;
458
459         if (psFlipCmd == NULL
460             || sizeof(struct DISPLAYCLASS_FLIP_COMMAND) != ui32DataSize)
461                 return IMG_FALSE;
462
463         psDevInfo = (struct OMAPLFB_DEVINFO *)psFlipCmd->hExtDevice;
464
465         psBuffer = (struct OMAPLFB_BUFFER *)psFlipCmd->hExtBuffer;
466         psSwapChain = (struct OMAPLFB_SWAPCHAIN *)psFlipCmd->hExtSwapChain;
467
468         psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete(hCmdCookie, IMG_TRUE);
469
470         return IMG_TRUE;
471 }
472
473 static void CalcSwapChainSize(struct OMAPLFB_DEVINFO *psDevInfo)
474 {
475         if (psDevInfo->sFBInfo.ui32RoundedBufferSize)
476                 psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers =
477                         psDevInfo->sFBInfo.ui32FBSize /
478                         psDevInfo->sFBInfo.ui32RoundedBufferSize;
479         else
480                 psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = 0;
481
482         if (psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers == 0) {
483                 psDevInfo->sDisplayInfo.ui32MaxSwapChains = 0;
484                 psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 0;
485         } else {
486                 psDevInfo->sDisplayInfo.ui32MaxSwapChains = 1;
487                 psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 3;
488         }
489
490         psDevInfo->sDisplayInfo.ui32MinSwapInterval = 0;
491
492         DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
493                       ": Maximum number of swap chain buffers: %u\n",
494                       psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers));
495 }
496
497 static void SetDevinfo(struct OMAPLFB_DEVINFO *psDevInfo)
498 {
499         struct OMAPLFB_FBINFO *psPVRFBInfo = &psDevInfo->sFBInfo;
500         struct fb_info *psLINFBInfo = psDevInfo->psLINFBInfo;
501         unsigned long FBSize;
502
503         FBSize = (psLINFBInfo->screen_size) != 0 ?
504             psLINFBInfo->screen_size : psLINFBInfo->fix.smem_len;
505         DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
506                       ": Framebuffer physical address: 0x%lx\n",
507                       psLINFBInfo->fix.smem_start));
508         DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
509                       ": Framebuffer virtual address: 0x%lx\n",
510                       (unsigned long)psLINFBInfo->screen_base));
511         DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
512                       ": Framebuffer size: %lu\n", FBSize));
513         DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
514                       ": Framebuffer virtual width: %u\n",
515                       psLINFBInfo->var.xres_virtual));
516         DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
517                       ": Framebuffer virtual height: %u\n",
518                       psLINFBInfo->var.yres_virtual));
519         DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
520                       ": Framebuffer width: %u\n", psLINFBInfo->var.xres));
521         DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
522                       ": Framebuffer height: %u\n", psLINFBInfo->var.yres));
523         DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
524                       ": Framebuffer stride: %u\n",
525                       psLINFBInfo->fix.line_length));
526
527         psPVRFBInfo->sSysAddr.uiAddr = psLINFBInfo->fix.smem_start;
528         psPVRFBInfo->sCPUVAddr = psLINFBInfo->screen_base;
529
530         psPVRFBInfo->ui32Width = psLINFBInfo->var.xres_virtual;
531         psPVRFBInfo->ui32ByteStride = psLINFBInfo->fix.line_length;
532         psPVRFBInfo->ui32FBSize = FBSize;
533
534         /* Try double buffering */
535         psPVRFBInfo->ui32Height = psLINFBInfo->var.yres_virtual >> 1;
536         psPVRFBInfo->ui32BufferSize = psPVRFBInfo->ui32ByteStride *
537                 psPVRFBInfo->ui32Height;
538         psPVRFBInfo->ui32RoundedBufferSize =
539                 sgx_buffer_align(psPVRFBInfo->ui32ByteStride,
540                                  psPVRFBInfo->ui32BufferSize);
541
542         /* If the buffers aren't aligned assume single buffering */
543         if (psPVRFBInfo->ui32BufferSize != psPVRFBInfo->ui32RoundedBufferSize) {
544                 psPVRFBInfo->ui32Height = psLINFBInfo->var.yres_virtual;
545                 psPVRFBInfo->ui32BufferSize = psPVRFBInfo->ui32ByteStride *
546                         psPVRFBInfo->ui32Height;
547                 psPVRFBInfo->ui32RoundedBufferSize =
548                         sgx_buffer_align(psPVRFBInfo->ui32ByteStride,
549                                          psPVRFBInfo->ui32BufferSize);
550         }
551
552         CalcSwapChainSize(psDevInfo);
553
554         if (psLINFBInfo->var.bits_per_pixel == 16) {
555                 if ((psLINFBInfo->var.red.length == 5) &&
556                     (psLINFBInfo->var.green.length == 6) &&
557                     (psLINFBInfo->var.blue.length == 5) &&
558                     (psLINFBInfo->var.red.offset == 11) &&
559                     (psLINFBInfo->var.green.offset == 5) &&
560                     (psLINFBInfo->var.blue.offset == 0) &&
561                     (psLINFBInfo->var.red.msb_right == 0))
562                         psPVRFBInfo->ePixelFormat = PVRSRV_PIXEL_FORMAT_RGB565;
563                 else
564                         printk("Unknown FB format\n");
565         } else if (psLINFBInfo->var.bits_per_pixel == 32) {
566                 if ((psLINFBInfo->var.transp.length == 8) &&
567                     (psLINFBInfo->var.red.length == 8) &&
568                     (psLINFBInfo->var.green.length == 8) &&
569                     (psLINFBInfo->var.blue.length == 8) &&
570                     (psLINFBInfo->var.transp.offset == 24) &&
571                     (psLINFBInfo->var.red.offset == 16) &&
572                     (psLINFBInfo->var.green.offset == 8) &&
573                     (psLINFBInfo->var.blue.offset == 0) &&
574                     (psLINFBInfo->var.red.msb_right == 0))
575                         psPVRFBInfo->ePixelFormat =
576                             PVRSRV_PIXEL_FORMAT_ARGB8888;
577                 else if ((psLINFBInfo->var.transp.length == 0) &&
578                          (psLINFBInfo->var.red.length == 8) &&
579                          (psLINFBInfo->var.green.length == 8) &&
580                          (psLINFBInfo->var.blue.length == 8) &&
581                          (psLINFBInfo->var.transp.offset == 0) &&
582                          (psLINFBInfo->var.red.offset == 16) &&
583                          (psLINFBInfo->var.green.offset == 8) &&
584                          (psLINFBInfo->var.blue.offset == 0) &&
585                          (psLINFBInfo->var.red.msb_right == 0))
586                         psPVRFBInfo->ePixelFormat = PVRSRV_PIXEL_FORMAT_RGB888;
587                 else
588                         printk(KERN_ERR "Unknown FB format\n");
589         } else {
590                 printk(KERN_ERR "Unknown FB format\n");
591         }
592
593         psDevInfo->sDisplayFormat.pixelformat = psDevInfo->sFBInfo.ePixelFormat;
594         psDevInfo->sDisplayDim.ui32Width = psDevInfo->sFBInfo.ui32Width;
595         psDevInfo->sDisplayDim.ui32Height = psDevInfo->sFBInfo.ui32Height;
596         psDevInfo->sDisplayDim.ui32ByteStride =
597             psDevInfo->sFBInfo.ui32ByteStride;
598         psDevInfo->sSystemBuffer.sSysAddr = psDevInfo->sFBInfo.sSysAddr;
599         psDevInfo->sSystemBuffer.sCPUVAddr = psDevInfo->sFBInfo.sCPUVAddr;
600         psDevInfo->sSystemBuffer.ui32BufferSize =
601             psDevInfo->sFBInfo.ui32RoundedBufferSize;
602 }
603
604 static struct FB_EVENTS {
605         struct notifier_block notif;
606         struct OMAPLFB_DEVINFO *psDevInfo;
607 } gFBEventsData;
608
609 static int FBEvents(struct notifier_block *psNotif,
610                     unsigned long event, void *data)
611 {
612         if (event == FB_EVENT_MODE_CHANGE) {
613                 struct FB_EVENTS *psEvents =
614                     container_of(psNotif, struct FB_EVENTS, notif);
615                 SetDevinfo(psEvents->psDevInfo);
616         }
617         return 0;
618 }
619
620 static enum PVRSRV_ERROR InitDev(struct OMAPLFB_DEVINFO *psDevInfo)
621 {
622         struct fb_info *psLINFBInfo;
623         struct module *psLINFBOwner;
624         struct OMAPLFB_FBINFO *psPVRFBInfo = &psDevInfo->sFBInfo;
625         enum PVRSRV_ERROR eError = PVRSRV_ERROR_GENERIC;
626
627         acquire_console_sem();
628
629         if (fb_idx < 0 || fb_idx >= num_registered_fb) {
630                 eError = PVRSRV_ERROR_INVALID_DEVICE;
631                 goto errRelSem;
632         }
633
634         psLINFBInfo = registered_fb[fb_idx];
635
636         psLINFBOwner = psLINFBInfo->fbops->owner;
637         if (!try_module_get(psLINFBOwner)) {
638                 printk(KERN_INFO DRIVER_PREFIX
639                        ": Couldn't get framebuffer module\n");
640
641                 goto errRelSem;
642         }
643
644         if (psLINFBInfo->fbops->fb_open != NULL) {
645                 int res;
646
647                 res = psLINFBInfo->fbops->fb_open(psLINFBInfo, 0);
648                 if (res != 0) {
649                         printk(KERN_INFO DRIVER_PREFIX
650                                ": Couldn't open framebuffer: %d\n", res);
651
652                         goto errModPut;
653                 }
654         }
655
656         psDevInfo->psLINFBInfo = psLINFBInfo;
657
658         SetDevinfo(psDevInfo);
659
660         gFBEventsData.notif.notifier_call = FBEvents;
661         gFBEventsData.psDevInfo = psDevInfo;
662         fb_register_client(&gFBEventsData.notif);
663
664         psDevInfo->sFBInfo.sSysAddr.uiAddr = psPVRFBInfo->sSysAddr.uiAddr;
665         psDevInfo->sFBInfo.sCPUVAddr = psPVRFBInfo->sCPUVAddr;
666
667         eError = PVRSRV_OK;
668         goto errRelSem;
669
670 errModPut:
671         module_put(psLINFBOwner);
672 errRelSem:
673         release_console_sem();
674         return eError;
675 }
676
677 static void DeInitDev(struct OMAPLFB_DEVINFO *psDevInfo)
678 {
679         struct fb_info *psLINFBInfo = psDevInfo->psLINFBInfo;
680         struct module *psLINFBOwner;
681
682         acquire_console_sem();
683
684         fb_unregister_client(&gFBEventsData.notif);
685
686         psLINFBOwner = psLINFBInfo->fbops->owner;
687
688         if (psLINFBInfo->fbops->fb_release != NULL)
689                 (void)psLINFBInfo->fbops->fb_release(psLINFBInfo, 0);
690
691         module_put(psLINFBOwner);
692
693         release_console_sem();
694 }
695
696 enum PVRSRV_ERROR OMAPLFBInit(void)
697 {
698         struct OMAPLFB_DEVINFO *psDevInfo;
699
700         psDevInfo = GetAnchorPtr();
701
702         if (psDevInfo == NULL) {
703                 IMG_BOOL (*pfnCmdProcList[OMAPLFB_COMMAND_COUNT])
704                                                         (void *, u32, void *);
705                 u32 aui32SyncCountList[OMAPLFB_COMMAND_COUNT][2];
706
707                 psDevInfo = (struct OMAPLFB_DEVINFO *)
708                           OMAPLFBAllocKernelMem(sizeof(struct OMAPLFB_DEVINFO));
709
710                 if (!psDevInfo)
711                         return PVRSRV_ERROR_OUT_OF_MEMORY;
712
713                 memset(psDevInfo, 0, sizeof(struct OMAPLFB_DEVINFO));
714
715                 SetAnchorPtr((void *) psDevInfo);
716
717                 psDevInfo->ui32RefCount = 0;
718
719                 if (InitDev(psDevInfo) != PVRSRV_OK)
720                         return PVRSRV_ERROR_INIT_FAILURE;
721
722                 if (OMAPLFBGetLibFuncAddr("PVRGetDisplayClassJTable",
723                      &pfnGetPVRJTable) != PVRSRV_OK)
724                         return PVRSRV_ERROR_INIT_FAILURE;
725
726                 if (!(*pfnGetPVRJTable) (&psDevInfo->sPVRJTable))
727                         return PVRSRV_ERROR_INIT_FAILURE;
728
729                 psDevInfo->psSwapChain = NULL;
730
731                 CalcSwapChainSize(psDevInfo);
732
733                 strncpy(psDevInfo->sDisplayInfo.szDisplayName,
734                         DISPLAY_DEVICE_NAME, MAX_DISPLAY_NAME_SIZE);
735
736                 psDevInfo->sDCJTable.ui32TableSize =
737                     sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE);
738                 psDevInfo->sDCJTable.owner = THIS_MODULE;
739                 psDevInfo->sDCJTable.pfnOpenDCDevice = OpenDCDevice;
740                 psDevInfo->sDCJTable.pfnCloseDCDevice = CloseDCDevice;
741                 psDevInfo->sDCJTable.pfnEnumDCFormats = EnumDCFormats;
742                 psDevInfo->sDCJTable.pfnEnumDCDims = EnumDCDims;
743                 psDevInfo->sDCJTable.pfnGetDCSystemBuffer = GetDCSystemBuffer;
744                 psDevInfo->sDCJTable.pfnGetDCInfo = GetDCInfo;
745                 psDevInfo->sDCJTable.pfnGetBufferAddr = GetDCBufferAddr;
746                 psDevInfo->sDCJTable.pfnCreateDCSwapChain = CreateDCSwapChain;
747                 psDevInfo->sDCJTable.pfnDestroyDCSwapChain = DestroyDCSwapChain;
748                 psDevInfo->sDCJTable.pfnSetDCDstRect = SetDCDstRect;
749                 psDevInfo->sDCJTable.pfnSetDCSrcRect = SetDCSrcRect;
750                 psDevInfo->sDCJTable.pfnSetDCDstColourKey = SetDCDstColourKey;
751                 psDevInfo->sDCJTable.pfnSetDCSrcColourKey = SetDCSrcColourKey;
752                 psDevInfo->sDCJTable.pfnGetDCBuffers = GetDCBuffers;
753                 psDevInfo->sDCJTable.pfnSetDCState = NULL;
754
755                 if (psDevInfo->sPVRJTable.
756                     pfnPVRSRVRegisterDCDevice(&psDevInfo->sDCJTable,
757                                               &psDevInfo->ui32DeviceID) !=
758                     PVRSRV_OK)
759                         return PVRSRV_ERROR_DEVICE_REGISTER_FAILED;
760
761                 pfnCmdProcList[DC_FLIP_COMMAND] = ProcessFlip;
762
763                 aui32SyncCountList[DC_FLIP_COMMAND][0] = 0;
764                 aui32SyncCountList[DC_FLIP_COMMAND][1] = 2;
765
766                 if (psDevInfo->sPVRJTable.
767                     pfnPVRSRVRegisterCmdProcList(psDevInfo->ui32DeviceID,
768                                                  &pfnCmdProcList[0],
769                                                  aui32SyncCountList,
770                                                  OMAPLFB_COMMAND_COUNT) !=
771                     PVRSRV_OK) {
772                         printk(KERN_WARNING DRIVER_PREFIX
773                                ": Can't register callback\n");
774                         return PVRSRV_ERROR_CANT_REGISTER_CALLBACK;
775                 }
776
777         }
778
779         psDevInfo->ui32RefCount++;
780
781         return PVRSRV_OK;
782
783 }
784
785 enum PVRSRV_ERROR OMAPLFBDeinit(void)
786 {
787         struct OMAPLFB_DEVINFO *psDevInfo, *psDevFirst;
788
789         psDevFirst = GetAnchorPtr();
790         psDevInfo = psDevFirst;
791
792         if (psDevInfo == NULL)
793                 return PVRSRV_ERROR_GENERIC;
794
795         psDevInfo->ui32RefCount--;
796
797         if (psDevInfo->ui32RefCount == 0) {
798                 struct PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable =
799                                                         &psDevInfo->sPVRJTable;
800                 if (psDevInfo->sPVRJTable.
801                     pfnPVRSRVRemoveCmdProcList(psDevInfo->ui32DeviceID,
802                                                OMAPLFB_COMMAND_COUNT) !=
803                     PVRSRV_OK)
804                         return PVRSRV_ERROR_GENERIC;
805
806                 if (psJTable->
807                             pfnPVRSRVRemoveDCDevice(psDevInfo->ui32DeviceID) !=
808                     PVRSRV_OK)
809                         return PVRSRV_ERROR_GENERIC;
810
811                 DeInitDev(psDevInfo);
812
813                 OMAPLFBFreeKernelMem(psDevInfo);
814         }
815
816         SetAnchorPtr(NULL);
817
818         return PVRSRV_OK;
819 }
820