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