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