diff options
Diffstat (limited to 'jacinto6/sgx_src/eurasia_km/services4/3rdparty/dc_sunxi/dc_sunxi_displayclass.c')
-rw-r--r-- | jacinto6/sgx_src/eurasia_km/services4/3rdparty/dc_sunxi/dc_sunxi_displayclass.c | 1765 |
1 files changed, 1765 insertions, 0 deletions
diff --git a/jacinto6/sgx_src/eurasia_km/services4/3rdparty/dc_sunxi/dc_sunxi_displayclass.c b/jacinto6/sgx_src/eurasia_km/services4/3rdparty/dc_sunxi/dc_sunxi_displayclass.c new file mode 100644 index 0000000..6af20f6 --- /dev/null +++ b/jacinto6/sgx_src/eurasia_km/services4/3rdparty/dc_sunxi/dc_sunxi_displayclass.c | |||
@@ -0,0 +1,1765 @@ | |||
1 | /*************************************************************************/ /*! | ||
2 | @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved | ||
3 | @License Dual MIT/GPLv2 | ||
4 | |||
5 | The contents of this file are subject to the MIT license as set out below. | ||
6 | |||
7 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
8 | of this software and associated documentation files (the "Software"), to deal | ||
9 | in the Software without restriction, including without limitation the rights | ||
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
11 | copies of the Software, and to permit persons to whom the Software is | ||
12 | furnished to do so, subject to the following conditions: | ||
13 | |||
14 | The above copyright notice and this permission notice shall be included in | ||
15 | all copies or substantial portions of the Software. | ||
16 | |||
17 | Alternatively, the contents of this file may be used under the terms of | ||
18 | the GNU General Public License Version 2 ("GPL") in which case the provisions | ||
19 | of GPL are applicable instead of those above. | ||
20 | |||
21 | If you wish to allow use of your version of this file only under the terms of | ||
22 | GPL, and not to allow others to use your version of this file under the terms | ||
23 | of the MIT license, indicate your decision by deleting the provisions above | ||
24 | and replace them with the notice and other provisions required by GPL as set | ||
25 | out in the file called "GPL-COPYING" included in this distribution. If you do | ||
26 | not delete the provisions above, a recipient may use your version of this file | ||
27 | under the terms of either the MIT license or GPL. | ||
28 | |||
29 | This License is also included in this distribution in the file called | ||
30 | "MIT-COPYING". | ||
31 | |||
32 | EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS | ||
33 | PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING | ||
34 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | ||
35 | PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR | ||
36 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
37 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
38 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
39 | */ /**************************************************************************/ | ||
40 | |||
41 | #include <linux/version.h> | ||
42 | #include <linux/kernel.h> | ||
43 | #include <linux/console.h> | ||
44 | #include <linux/fb.h> | ||
45 | #include <linux/module.h> | ||
46 | #include <linux/string.h> | ||
47 | #include <linux/notifier.h> | ||
48 | |||
49 | |||
50 | #if defined(SUPPORT_DRI_DRM) | ||
51 | #include <drm/drmP.h> | ||
52 | #endif | ||
53 | |||
54 | /* IMG services headers */ | ||
55 | #include "img_defs.h" | ||
56 | #include "servicesext.h" | ||
57 | #include "kerneldisplay.h" | ||
58 | #include "linux/drv_display.h" | ||
59 | |||
60 | #if defined(SUPPORT_DRI_DRM) | ||
61 | #include "pvr_drm.h" | ||
62 | #else | ||
63 | #include "pvrmodule.h" | ||
64 | #endif | ||
65 | |||
66 | #define DC_SUNXI_COMMAND_COUNT 1 | ||
67 | |||
68 | #define DC_SUNXI_VSYNC_SETTLE_COUNT 5 | ||
69 | |||
70 | #define DC_SUNXI_MAX_NUM_DEVICES 1 | ||
71 | |||
72 | //#define DC_SUNXI_DISPC_GRALLOC_QUEUE_IN_V1_PATH | ||
73 | |||
74 | #if (DC_SUNXI_MAX_NUM_DEVICES > FB_MAX) | ||
75 | #error DC_SUNXI_MAX_NUM_DEVICES must not be greater than FB_MAX | ||
76 | #endif | ||
77 | |||
78 | /* DEBUG only printk */ | ||
79 | #ifdef DEBUG | ||
80 | #define DEBUG_PRINTK(x) printk x | ||
81 | #else | ||
82 | #define DEBUG_PRINTK(x) | ||
83 | #endif | ||
84 | |||
85 | #define DISPLAY_DEVICE_NAME "SUNXI Linux Display Driver" | ||
86 | #define DRVNAME "dc_sunxi" | ||
87 | #define DEVNAME DRVNAME | ||
88 | #define DRIVER_PREFIX DRVNAME | ||
89 | |||
90 | #ifndef UNREFERENCED_PARAMETER | ||
91 | #define UNREFERENCED_PARAMETER(param) (param) = (param) | ||
92 | #endif | ||
93 | |||
94 | #if !defined(SUPPORT_DRI_DRM) | ||
95 | MODULE_SUPPORTED_DEVICE(DEVNAME); | ||
96 | #endif | ||
97 | |||
98 | /* DC_SUNXI buffer structure */ | ||
99 | typedef struct DC_SUNXI_BUFFER_TAG | ||
100 | { | ||
101 | struct DC_SUNXI_BUFFER_TAG *psNext; | ||
102 | struct DC_SUNXI_DEVINFO_TAG *psDevInfo; | ||
103 | |||
104 | struct work_struct sWork; | ||
105 | |||
106 | /* Position of this buffer in the virtual framebuffer */ | ||
107 | unsigned long ulYOffset; | ||
108 | |||
109 | /* IMG structures used, to minimise API function code */ | ||
110 | /* replace with own structures where necessary */ | ||
111 | IMG_SYS_PHYADDR sSysAddr; | ||
112 | IMG_CPU_VIRTADDR sCPUVAddr; | ||
113 | PVRSRV_SYNC_DATA *psSyncData; | ||
114 | |||
115 | void *hCmdComplete; | ||
116 | unsigned long ulSwapInterval; | ||
117 | |||
118 | } DC_SUNXI_BUFFER; | ||
119 | |||
120 | /* DC_SUNXI swapchain structure */ | ||
121 | typedef struct DC_SUNXI_SWAPCHAIN_TAG | ||
122 | { | ||
123 | /* Swap chain ID */ | ||
124 | unsigned int uiSwapChainID; | ||
125 | |||
126 | /* number of buffers in swapchain */ | ||
127 | unsigned long ulBufferCount; | ||
128 | |||
129 | /* list of buffers in the swapchain */ | ||
130 | DC_SUNXI_BUFFER *psBuffer; | ||
131 | |||
132 | /* Swap chain work queue */ | ||
133 | struct workqueue_struct *psWorkQueue; | ||
134 | |||
135 | /* | ||
136 | * Set if we didn't manage to wait for VSync on last swap, | ||
137 | * or if we think we need to wait for VSync on the next flip. | ||
138 | * The flag helps to avoid jitter when the screen is | ||
139 | * unblanked, by forcing an extended wait for VSync before | ||
140 | * attempting the next flip. | ||
141 | */ | ||
142 | bool bNotVSynced; | ||
143 | |||
144 | /* Framebuffer Device ID for messages (e.g. printk) */ | ||
145 | unsigned int uiFBDevID; | ||
146 | |||
147 | } DC_SUNXI_SWAPCHAIN; | ||
148 | |||
149 | typedef struct DC_SUNXI_FBINFO_TAG | ||
150 | { | ||
151 | unsigned long ulFBSize; | ||
152 | unsigned long ulBufferSize; | ||
153 | unsigned long ulRoundedBufferSize; | ||
154 | unsigned long ulWidth; | ||
155 | unsigned long ulHeight; | ||
156 | unsigned long ulByteStride; | ||
157 | unsigned long ulPhysicalWidthmm; | ||
158 | unsigned long ulPhysicalHeightmm; | ||
159 | |||
160 | /* IMG structures used, to minimise API function code */ | ||
161 | /* replace with own structures where necessary */ | ||
162 | IMG_SYS_PHYADDR sSysAddr; | ||
163 | IMG_CPU_VIRTADDR sCPUVAddr; | ||
164 | |||
165 | /* pixelformat of system/primary surface */ | ||
166 | PVRSRV_PIXEL_FORMAT ePixelFormat; | ||
167 | |||
168 | } DC_SUNXI_FBINFO; | ||
169 | |||
170 | /* kernel device information structure */ | ||
171 | typedef struct DC_SUNXI_DEVINFO_TAG | ||
172 | { | ||
173 | /* Framebuffer Device ID */ | ||
174 | unsigned int uiFBDevID; | ||
175 | |||
176 | /* PVR Device ID */ | ||
177 | unsigned int uiPVRDevID; | ||
178 | |||
179 | /* Swapchain create/destroy mutex */ | ||
180 | struct mutex sCreateSwapChainMutex; | ||
181 | |||
182 | /* system surface info */ | ||
183 | DC_SUNXI_BUFFER sSystemBuffer; | ||
184 | |||
185 | /* jump table into PVR services */ | ||
186 | PVRSRV_DC_DISP2SRV_KMJTABLE sPVRJTable; | ||
187 | |||
188 | /* jump table into DC */ | ||
189 | PVRSRV_DC_SRV2DISP_KMJTABLE sDCJTable; | ||
190 | |||
191 | /* fb info structure */ | ||
192 | DC_SUNXI_FBINFO sFBInfo; | ||
193 | |||
194 | /* Only one swapchain supported by this device so hang it here */ | ||
195 | DC_SUNXI_SWAPCHAIN *psSwapChain; | ||
196 | |||
197 | /* Swap chain ID */ | ||
198 | unsigned int uiSwapChainID; | ||
199 | |||
200 | /* True if PVR Services is flushing its command queues */ | ||
201 | atomic_t sFlushCommands; | ||
202 | |||
203 | /* pointer to linux frame buffer information structure */ | ||
204 | struct fb_info *psLINFBInfo; | ||
205 | |||
206 | /* IMG structures used, to minimise API function code */ | ||
207 | /* replace with own structures where necessary */ | ||
208 | |||
209 | DISPLAY_INFO sDisplayInfo; | ||
210 | |||
211 | /* Display format */ | ||
212 | DISPLAY_FORMAT sDisplayFormat; | ||
213 | |||
214 | /* Display dimensions */ | ||
215 | DISPLAY_DIMS sDisplayDim; | ||
216 | |||
217 | /* Number of blank/unblank events */ | ||
218 | atomic_t sBlankEvents; | ||
219 | |||
220 | } DC_SUNXI_DEVINFO; | ||
221 | |||
222 | typedef enum _DC_SUNXI_ERROR_ | ||
223 | { | ||
224 | DC_SUNXI_OK = 0, | ||
225 | DC_SUNXI_ERROR_GENERIC = 1, | ||
226 | DC_SUNXI_ERROR_INIT_FAILURE = 2, | ||
227 | DC_SUNXI_ERROR_INVALID_DEVICE = 3, | ||
228 | |||
229 | } DC_SUNXI_ERROR; | ||
230 | |||
231 | static DC_SUNXI_DEVINFO *gapsDevInfo[DC_SUNXI_MAX_NUM_DEVICES]; | ||
232 | |||
233 | /* Top level 'hook ptr' */ | ||
234 | static PFN_DC_GET_PVRJTABLE gpfnGetPVRJTable; | ||
235 | |||
236 | /* Don't wait for vertical sync */ | ||
237 | static inline bool DontWaitForVSync(DC_SUNXI_DEVINFO *psDevInfo) | ||
238 | { | ||
239 | return atomic_read(&psDevInfo->sFlushCommands); | ||
240 | } | ||
241 | |||
242 | /* | ||
243 | * Called after the screen has unblanked, or after any other occasion | ||
244 | * when we didn't wait for vsync, but now need to. Not doing this after | ||
245 | * unblank leads to screen jitter on some screens. | ||
246 | * Returns true if the screen has been deemed to have settled. | ||
247 | */ | ||
248 | static bool WaitForVSyncSettle(DC_SUNXI_DEVINFO *psDevInfo) | ||
249 | { | ||
250 | unsigned int i; | ||
251 | for(i = 0; i < DC_SUNXI_VSYNC_SETTLE_COUNT; i++) | ||
252 | { | ||
253 | if (DontWaitForVSync(psDevInfo)) | ||
254 | { | ||
255 | return false; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | return true; | ||
260 | } | ||
261 | |||
262 | /* Flip display to given buffer */ | ||
263 | static void DC_SUNXIFlip(DC_SUNXI_DEVINFO *psDevInfo, DC_SUNXI_BUFFER *psBuffer) | ||
264 | { | ||
265 | struct fb_var_screeninfo sFBVar; | ||
266 | unsigned long ulYResVirtual; | ||
267 | int res; | ||
268 | |||
269 | console_lock(); | ||
270 | |||
271 | sFBVar = psDevInfo->psLINFBInfo->var; | ||
272 | |||
273 | sFBVar.xoffset = 0; | ||
274 | sFBVar.yoffset = psBuffer->ulYOffset; | ||
275 | |||
276 | ulYResVirtual = psBuffer->ulYOffset + sFBVar.yres; | ||
277 | |||
278 | res = fb_pan_display(psDevInfo->psLINFBInfo, &sFBVar); | ||
279 | if (res != 0) | ||
280 | { | ||
281 | printk(KERN_ERR DRIVER_PREFIX ": %s: Device %u: fb_pan_display failed (Y Offset: %lu, Error: %d)\n", __FUNCTION__, psDevInfo->uiFBDevID, psBuffer->ulYOffset, res); | ||
282 | } | ||
283 | |||
284 | console_unlock(); | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Swap handler. | ||
289 | * Called from the swap chain work queue handler. | ||
290 | * There is no need to take the swap chain creation lock in here, or use | ||
291 | * some other method of stopping the swap chain from being destroyed. | ||
292 | * This is because the swap chain creation lock is taken when queueing work, | ||
293 | * and the work queue is flushed before the swap chain is destroyed. | ||
294 | */ | ||
295 | static void DC_SUNXISwapHandler(DC_SUNXI_BUFFER *psBuffer) | ||
296 | { | ||
297 | DC_SUNXI_DEVINFO *psDevInfo = psBuffer->psDevInfo; | ||
298 | DC_SUNXI_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain; | ||
299 | bool bPreviouslyNotVSynced; | ||
300 | |||
301 | DC_SUNXIFlip(psDevInfo, psBuffer); | ||
302 | |||
303 | bPreviouslyNotVSynced = psSwapChain->bNotVSynced; | ||
304 | psSwapChain->bNotVSynced = true; | ||
305 | |||
306 | if (!DontWaitForVSync(psDevInfo)) | ||
307 | { | ||
308 | psSwapChain->bNotVSynced = false; | ||
309 | |||
310 | if (bPreviouslyNotVSynced) | ||
311 | { | ||
312 | psSwapChain->bNotVSynced = !WaitForVSyncSettle(psDevInfo); | ||
313 | } | ||
314 | else if (psBuffer->ulSwapInterval != 0) | ||
315 | { | ||
316 | psSwapChain->bNotVSynced = IMG_FALSE; | ||
317 | } | ||
318 | } | ||
319 | |||
320 | psDevInfo->sPVRJTable.pfnPVRSRVCmdComplete((IMG_HANDLE)psBuffer->hCmdComplete, IMG_TRUE); | ||
321 | } | ||
322 | |||
323 | /* Process an item on a swap chain work queue */ | ||
324 | static void WorkQueueHandler(struct work_struct *psWork) | ||
325 | { | ||
326 | DC_SUNXI_BUFFER *psBuffer = container_of(psWork, DC_SUNXI_BUFFER, sWork); | ||
327 | |||
328 | DC_SUNXISwapHandler(psBuffer); | ||
329 | } | ||
330 | |||
331 | /* Create a swap chain work queue */ | ||
332 | static DC_SUNXI_ERROR DC_SUNXICreateSwapQueue(DC_SUNXI_SWAPCHAIN *psSwapChain) | ||
333 | { | ||
334 | /* | ||
335 | * Calling alloc_ordered_workqueue with the WQ_FREEZABLE and | ||
336 | * WQ_MEM_RECLAIM flags set, (currently) has the same effect as | ||
337 | * calling create_freezable_workqueue. None of the other WQ | ||
338 | * flags are valid. Setting WQ_MEM_RECLAIM should allow the | ||
339 | * workqueue to continue to service the swap chain in low memory | ||
340 | * conditions, preventing the driver from holding on to | ||
341 | * resources longer than it needs to. | ||
342 | */ | ||
343 | psSwapChain->psWorkQueue = alloc_ordered_workqueue(DEVNAME, WQ_FREEZABLE | WQ_MEM_RECLAIM); | ||
344 | if (psSwapChain->psWorkQueue == NULL) | ||
345 | { | ||
346 | printk(KERN_ERR DRIVER_PREFIX ": %s: Device %u: Couldn't create workqueue\n", __FUNCTION__, psSwapChain->uiFBDevID); | ||
347 | |||
348 | return (DC_SUNXI_ERROR_INIT_FAILURE); | ||
349 | } | ||
350 | |||
351 | return (DC_SUNXI_OK); | ||
352 | } | ||
353 | |||
354 | /* Prepare buffer for insertion into a swap chain work queue */ | ||
355 | static void DC_SUNXIInitBufferForSwap(DC_SUNXI_BUFFER *psBuffer) | ||
356 | { | ||
357 | INIT_WORK(&psBuffer->sWork, WorkQueueHandler); | ||
358 | } | ||
359 | |||
360 | /* Destroy a swap chain work queue */ | ||
361 | static void DC_SUNXIDestroySwapQueue(DC_SUNXI_SWAPCHAIN *psSwapChain) | ||
362 | { | ||
363 | destroy_workqueue(psSwapChain->psWorkQueue); | ||
364 | } | ||
365 | |||
366 | /* Unblank the screen */ | ||
367 | static DC_SUNXI_ERROR DC_SUNXIUnblankDisplay(DC_SUNXI_DEVINFO *psDevInfo) | ||
368 | { | ||
369 | int res; | ||
370 | |||
371 | console_lock(); | ||
372 | res = fb_blank(psDevInfo->psLINFBInfo, 0); | ||
373 | console_unlock(); | ||
374 | |||
375 | if (res != 0 && res != -EINVAL) | ||
376 | { | ||
377 | printk(KERN_ERR DRIVER_PREFIX | ||
378 | ": %s: Device %u: fb_blank failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, res); | ||
379 | return (DC_SUNXI_ERROR_GENERIC); | ||
380 | } | ||
381 | |||
382 | return (DC_SUNXI_OK); | ||
383 | } | ||
384 | |||
385 | /* Round x up to a multiple of y */ | ||
386 | static inline unsigned long RoundUpToMultiple(unsigned long x, unsigned long y) | ||
387 | { | ||
388 | unsigned long div = x / y; | ||
389 | unsigned long rem = x % y; | ||
390 | |||
391 | return (div + ((rem == 0) ? 0 : 1)) * y; | ||
392 | } | ||
393 | |||
394 | /* Greatest common divisor of x and y */ | ||
395 | static unsigned long GCD(unsigned long x, unsigned long y) | ||
396 | { | ||
397 | while (y != 0) | ||
398 | { | ||
399 | unsigned long r = x % y; | ||
400 | x = y; | ||
401 | y = r; | ||
402 | } | ||
403 | |||
404 | return x; | ||
405 | } | ||
406 | |||
407 | /* Least common multiple of x and y */ | ||
408 | static unsigned long LCM(unsigned long x, unsigned long y) | ||
409 | { | ||
410 | unsigned long gcd = GCD(x, y); | ||
411 | |||
412 | return (gcd == 0) ? 0 : ((x / gcd) * y); | ||
413 | } | ||
414 | |||
415 | static unsigned DC_SUNXIMaxFBDevIDPlusOne(void) | ||
416 | { | ||
417 | return DC_SUNXI_MAX_NUM_DEVICES; | ||
418 | } | ||
419 | |||
420 | /* Returns DevInfo pointer for a given device */ | ||
421 | static DC_SUNXI_DEVINFO *DC_SUNXIGetDevInfoPtr(unsigned uiFBDevID) | ||
422 | { | ||
423 | WARN_ON(uiFBDevID >= DC_SUNXIMaxFBDevIDPlusOne()); | ||
424 | |||
425 | if (uiFBDevID >= DC_SUNXI_MAX_NUM_DEVICES) | ||
426 | { | ||
427 | return NULL; | ||
428 | } | ||
429 | |||
430 | return gapsDevInfo[uiFBDevID]; | ||
431 | } | ||
432 | |||
433 | /* Sets the DevInfo pointer for a given device */ | ||
434 | static inline void DC_SUNXISetDevInfoPtr(unsigned uiFBDevID, DC_SUNXI_DEVINFO *psDevInfo) | ||
435 | { | ||
436 | WARN_ON(uiFBDevID >= DC_SUNXI_MAX_NUM_DEVICES); | ||
437 | |||
438 | if (uiFBDevID < DC_SUNXI_MAX_NUM_DEVICES) | ||
439 | { | ||
440 | gapsDevInfo[uiFBDevID] = psDevInfo; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | static inline bool SwapChainHasChanged(DC_SUNXI_DEVINFO *psDevInfo, DC_SUNXI_SWAPCHAIN *psSwapChain) | ||
445 | { | ||
446 | return (psDevInfo->psSwapChain != psSwapChain) || | ||
447 | (psDevInfo->uiSwapChainID != psSwapChain->uiSwapChainID); | ||
448 | } | ||
449 | |||
450 | extern int dispc_gralloc_queue(setup_dispc_data_t *psDispcData, int ui32DispcDataLength, void (*cb_fn)(void *, int), void *cb_arg); | ||
451 | |||
452 | static void | ||
453 | QueueBufferImmediate(DC_SUNXI_DEVINFO *psDevInfo, IMG_SYS_PHYADDR sSysAddr, | ||
454 | void (*cb_fn)(void *, int), void *cb_arg) | ||
455 | { | ||
456 | setup_dispc_data_t sDispcData = | ||
457 | { | ||
458 | .post2_layers = 1, | ||
459 | .primary_display_layer_num = 1, | ||
460 | .layer_info = | ||
461 | { | ||
462 | [0] = | ||
463 | { | ||
464 | .mode = DISP_LAYER_WORK_MODE_NORMAL, | ||
465 | .src_win = | ||
466 | { | ||
467 | .width = psDevInfo->sFBInfo.ulWidth, | ||
468 | .height = psDevInfo->sFBInfo.ulHeight | ||
469 | }, | ||
470 | .scn_win = | ||
471 | { | ||
472 | .width = psDevInfo->sFBInfo.ulWidth, | ||
473 | .height = psDevInfo->sFBInfo.ulHeight | ||
474 | }, | ||
475 | .alpha_en = 1, | ||
476 | .alpha_val = 0xff, | ||
477 | .fb = | ||
478 | { | ||
479 | .mode = DISP_MOD_INTERLEAVED, | ||
480 | .format = DISP_FORMAT_ARGB8888, | ||
481 | .seq = DISP_SEQ_ARGB, | ||
482 | .pre_multiply = 1, | ||
483 | .size = | ||
484 | { | ||
485 | .width = psDevInfo->sFBInfo.ulWidth, | ||
486 | .height = psDevInfo->sFBInfo.ulHeight | ||
487 | }, | ||
488 | .addr[0] = sSysAddr.uiAddr, | ||
489 | }, | ||
490 | }, | ||
491 | }, | ||
492 | }; | ||
493 | |||
494 | dispc_gralloc_queue(&sDispcData, sizeof(setup_dispc_data_t), cb_fn, cb_arg); | ||
495 | } | ||
496 | |||
497 | static void dispc_proxy_cmdcomplete(void * cookie, int i) | ||
498 | { | ||
499 | /* Workaround for bug in sunxi kernel, where it uses the latest cb_fn | ||
500 | * with older cb_arg (they should be used as a pair). | ||
501 | */ | ||
502 | if (cookie == (void *)0xdeadbeef) | ||
503 | return; | ||
504 | |||
505 | /* XXX: assumes that there is only one display */ | ||
506 | gapsDevInfo[0]->sPVRJTable.pfnPVRSRVCmdComplete(cookie, i); | ||
507 | } | ||
508 | |||
509 | /* | ||
510 | * SetDCState | ||
511 | * Called from services. | ||
512 | */ | ||
513 | static IMG_VOID SetDCState(IMG_HANDLE hDevice, IMG_UINT32 ui32State) | ||
514 | { | ||
515 | DC_SUNXI_DEVINFO *psDevInfo = (DC_SUNXI_DEVINFO *)hDevice; | ||
516 | |||
517 | switch (ui32State) | ||
518 | { | ||
519 | case DC_STATE_FLUSH_COMMANDS: | ||
520 | /* Flush out any 'real' operation waiting for another flip. | ||
521 | * In flush state we won't pass any 'real' operations along | ||
522 | * to dispc_gralloc_queue(); we'll just CmdComplete them | ||
523 | * immediately. | ||
524 | */ | ||
525 | QueueBufferImmediate(psDevInfo, psDevInfo->sSystemBuffer.sSysAddr, | ||
526 | dispc_proxy_cmdcomplete, (void *)0xdeadbeef); | ||
527 | atomic_set(&psDevInfo->sFlushCommands, true); | ||
528 | break; | ||
529 | case DC_STATE_NO_FLUSH_COMMANDS: | ||
530 | atomic_set(&psDevInfo->sFlushCommands, false); | ||
531 | break; | ||
532 | default: | ||
533 | break; | ||
534 | } | ||
535 | } | ||
536 | |||
537 | /* | ||
538 | * OpenDCDevice | ||
539 | * Called from services. | ||
540 | */ | ||
541 | static PVRSRV_ERROR OpenDCDevice(IMG_UINT32 uiPVRDevID, | ||
542 | IMG_HANDLE *phDevice, | ||
543 | PVRSRV_SYNC_DATA* psSystemBufferSyncData) | ||
544 | { | ||
545 | DC_SUNXI_DEVINFO *psDevInfo; | ||
546 | DC_SUNXI_ERROR eError; | ||
547 | unsigned int i, uiMaxFBDevIDPlusOne; | ||
548 | |||
549 | if (!try_module_get(THIS_MODULE)) | ||
550 | { | ||
551 | return PVRSRV_ERROR_UNABLE_TO_OPEN_DC_DEVICE; | ||
552 | } | ||
553 | |||
554 | uiMaxFBDevIDPlusOne = DC_SUNXIMaxFBDevIDPlusOne(); | ||
555 | |||
556 | for (i = 0; i < uiMaxFBDevIDPlusOne; i++) | ||
557 | { | ||
558 | psDevInfo = DC_SUNXIGetDevInfoPtr(i); | ||
559 | if (psDevInfo != NULL && psDevInfo->uiPVRDevID == uiPVRDevID) | ||
560 | { | ||
561 | break; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | if (i == uiMaxFBDevIDPlusOne) | ||
566 | { | ||
567 | DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX | ||
568 | ": %s: PVR Device %u not found\n", __FUNCTION__, uiPVRDevID)); | ||
569 | eError = PVRSRV_ERROR_INVALID_DEVICE; | ||
570 | goto ErrorModulePut; | ||
571 | } | ||
572 | |||
573 | /* store the system surface sync data */ | ||
574 | psDevInfo->sSystemBuffer.psSyncData = psSystemBufferSyncData; | ||
575 | |||
576 | eError = DC_SUNXIUnblankDisplay(psDevInfo); | ||
577 | if (eError != DC_SUNXI_OK) | ||
578 | { | ||
579 | DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX | ||
580 | ": %s: Device %u: DC_SUNXIUnblankDisplay failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, eError)); | ||
581 | eError = PVRSRV_ERROR_UNBLANK_DISPLAY_FAILED; | ||
582 | goto ErrorModulePut; | ||
583 | } | ||
584 | |||
585 | /* return handle to the devinfo */ | ||
586 | *phDevice = (IMG_HANDLE)psDevInfo; | ||
587 | |||
588 | return PVRSRV_OK; | ||
589 | |||
590 | ErrorModulePut: | ||
591 | module_put(THIS_MODULE); | ||
592 | |||
593 | return eError; | ||
594 | } | ||
595 | |||
596 | /* | ||
597 | * CloseDCDevice | ||
598 | * Called from services. | ||
599 | */ | ||
600 | static PVRSRV_ERROR CloseDCDevice(IMG_HANDLE hDevice) | ||
601 | { | ||
602 | UNREFERENCED_PARAMETER(hDevice); | ||
603 | |||
604 | module_put(THIS_MODULE); | ||
605 | |||
606 | return PVRSRV_OK; | ||
607 | } | ||
608 | |||
609 | /* | ||
610 | * EnumDCFormats | ||
611 | * Called from services. | ||
612 | */ | ||
613 | static PVRSRV_ERROR EnumDCFormats(IMG_HANDLE hDevice, | ||
614 | IMG_UINT32 *pui32NumFormats, | ||
615 | DISPLAY_FORMAT *psFormat) | ||
616 | { | ||
617 | DC_SUNXI_DEVINFO *psDevInfo; | ||
618 | |||
619 | if(!hDevice || !pui32NumFormats) | ||
620 | { | ||
621 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
622 | } | ||
623 | |||
624 | psDevInfo = (DC_SUNXI_DEVINFO*)hDevice; | ||
625 | |||
626 | *pui32NumFormats = 1; | ||
627 | |||
628 | if(psFormat) | ||
629 | { | ||
630 | psFormat[0] = psDevInfo->sDisplayFormat; | ||
631 | } | ||
632 | |||
633 | return PVRSRV_OK; | ||
634 | } | ||
635 | |||
636 | /* | ||
637 | * EnumDCDims | ||
638 | * Called from services. | ||
639 | */ | ||
640 | static PVRSRV_ERROR EnumDCDims(IMG_HANDLE hDevice, | ||
641 | DISPLAY_FORMAT *psFormat, | ||
642 | IMG_UINT32 *pui32NumDims, | ||
643 | DISPLAY_DIMS *psDim) | ||
644 | { | ||
645 | DC_SUNXI_DEVINFO *psDevInfo; | ||
646 | |||
647 | if(!hDevice || !psFormat || !pui32NumDims) | ||
648 | { | ||
649 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
650 | } | ||
651 | |||
652 | psDevInfo = (DC_SUNXI_DEVINFO*)hDevice; | ||
653 | |||
654 | *pui32NumDims = 1; | ||
655 | |||
656 | /* No need to look at psFormat; there is only one */ | ||
657 | if(psDim) | ||
658 | { | ||
659 | psDim[0] = psDevInfo->sDisplayDim; | ||
660 | } | ||
661 | |||
662 | return PVRSRV_OK; | ||
663 | } | ||
664 | |||
665 | |||
666 | /* | ||
667 | * GetDCSystemBuffer | ||
668 | * Called from services. | ||
669 | */ | ||
670 | static PVRSRV_ERROR GetDCSystemBuffer(IMG_HANDLE hDevice, IMG_HANDLE *phBuffer) | ||
671 | { | ||
672 | DC_SUNXI_DEVINFO *psDevInfo; | ||
673 | |||
674 | if(!hDevice || !phBuffer) | ||
675 | { | ||
676 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
677 | } | ||
678 | |||
679 | psDevInfo = (DC_SUNXI_DEVINFO*)hDevice; | ||
680 | |||
681 | *phBuffer = (IMG_HANDLE)&psDevInfo->sSystemBuffer; | ||
682 | |||
683 | return PVRSRV_OK; | ||
684 | } | ||
685 | |||
686 | |||
687 | /* | ||
688 | * GetDCInfo | ||
689 | * Called from services. | ||
690 | */ | ||
691 | static PVRSRV_ERROR GetDCInfo(IMG_HANDLE hDevice, DISPLAY_INFO *psDCInfo) | ||
692 | { | ||
693 | DC_SUNXI_DEVINFO *psDevInfo; | ||
694 | |||
695 | if(!hDevice || !psDCInfo) | ||
696 | { | ||
697 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
698 | } | ||
699 | |||
700 | psDevInfo = (DC_SUNXI_DEVINFO*)hDevice; | ||
701 | |||
702 | *psDCInfo = psDevInfo->sDisplayInfo; | ||
703 | |||
704 | return PVRSRV_OK; | ||
705 | } | ||
706 | |||
707 | /* | ||
708 | * GetDCBufferAddr | ||
709 | * Called from services. | ||
710 | */ | ||
711 | static PVRSRV_ERROR GetDCBufferAddr(IMG_HANDLE hDevice, | ||
712 | IMG_HANDLE hBuffer, | ||
713 | IMG_SYS_PHYADDR **ppsSysAddr, | ||
714 | IMG_UINT32 *pui32ByteSize, | ||
715 | IMG_VOID **ppvCpuVAddr, | ||
716 | IMG_HANDLE *phOSMapInfo, | ||
717 | IMG_BOOL *pbIsContiguous, | ||
718 | IMG_UINT32 *pui32TilingStride) | ||
719 | { | ||
720 | DC_SUNXI_DEVINFO *psDevInfo; | ||
721 | DC_SUNXI_BUFFER *psSystemBuffer; | ||
722 | |||
723 | UNREFERENCED_PARAMETER(pui32TilingStride); | ||
724 | |||
725 | if(!hDevice) | ||
726 | { | ||
727 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
728 | } | ||
729 | |||
730 | if(!hBuffer) | ||
731 | { | ||
732 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
733 | } | ||
734 | |||
735 | if (!ppsSysAddr) | ||
736 | { | ||
737 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
738 | } | ||
739 | |||
740 | if (!pui32ByteSize) | ||
741 | { | ||
742 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
743 | } | ||
744 | |||
745 | psDevInfo = (DC_SUNXI_DEVINFO*)hDevice; | ||
746 | |||
747 | psSystemBuffer = (DC_SUNXI_BUFFER *)hBuffer; | ||
748 | |||
749 | *ppsSysAddr = &psSystemBuffer->sSysAddr; | ||
750 | |||
751 | *pui32ByteSize = (IMG_UINT32)psDevInfo->sFBInfo.ulBufferSize; | ||
752 | |||
753 | if (ppvCpuVAddr) | ||
754 | { | ||
755 | *ppvCpuVAddr = psSystemBuffer->sCPUVAddr; | ||
756 | } | ||
757 | |||
758 | if (phOSMapInfo) | ||
759 | { | ||
760 | *phOSMapInfo = (IMG_HANDLE)0; | ||
761 | } | ||
762 | |||
763 | if (pbIsContiguous) | ||
764 | { | ||
765 | *pbIsContiguous = IMG_TRUE; | ||
766 | } | ||
767 | |||
768 | return PVRSRV_OK; | ||
769 | } | ||
770 | |||
771 | /* | ||
772 | * CreateDCSwapChain | ||
773 | * Called from services. | ||
774 | */ | ||
775 | static PVRSRV_ERROR CreateDCSwapChain(IMG_HANDLE hDevice, | ||
776 | IMG_UINT32 ui32Flags, | ||
777 | DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib, | ||
778 | DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib, | ||
779 | IMG_UINT32 ui32BufferCount, | ||
780 | PVRSRV_SYNC_DATA **ppsSyncData, | ||
781 | IMG_UINT32 ui32OEMFlags, | ||
782 | IMG_HANDLE *phSwapChain, | ||
783 | IMG_UINT32 *pui32SwapChainID) | ||
784 | { | ||
785 | DC_SUNXI_SWAPCHAIN *psSwapChain; | ||
786 | DC_SUNXI_DEVINFO *psDevInfo; | ||
787 | PVRSRV_ERROR eError; | ||
788 | IMG_UINT32 i; | ||
789 | |||
790 | UNREFERENCED_PARAMETER(ui32OEMFlags); | ||
791 | UNREFERENCED_PARAMETER(ui32Flags); | ||
792 | |||
793 | /* Check parameters */ | ||
794 | if(!hDevice | ||
795 | || !psDstSurfAttrib | ||
796 | || !psSrcSurfAttrib | ||
797 | || !ppsSyncData | ||
798 | || !phSwapChain) | ||
799 | { | ||
800 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
801 | } | ||
802 | |||
803 | psDevInfo = (DC_SUNXI_DEVINFO*)hDevice; | ||
804 | |||
805 | /* Do we support swap chains? */ | ||
806 | if (psDevInfo->sDisplayInfo.ui32MaxSwapChains == 0) | ||
807 | { | ||
808 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
809 | } | ||
810 | |||
811 | mutex_lock(&psDevInfo->sCreateSwapChainMutex); | ||
812 | |||
813 | /* The driver only supports a single swapchain */ | ||
814 | if(psDevInfo->psSwapChain != NULL) | ||
815 | { | ||
816 | eError = PVRSRV_ERROR_FLIP_CHAIN_EXISTS; | ||
817 | goto ExitUnLock; | ||
818 | } | ||
819 | |||
820 | /* create a swapchain structure */ | ||
821 | psSwapChain = (DC_SUNXI_SWAPCHAIN*)kmalloc(sizeof(DC_SUNXI_SWAPCHAIN), GFP_KERNEL); | ||
822 | if(!psSwapChain) | ||
823 | { | ||
824 | eError = PVRSRV_ERROR_OUT_OF_MEMORY; | ||
825 | goto ExitUnLock; | ||
826 | } | ||
827 | |||
828 | /* If services asks for a 0-length swap chain, it's probably Android. | ||
829 | * | ||
830 | * This will use only non-display memory posting via PVRSRVSwapToDCBuffers2(), | ||
831 | * and we can skip some useless sanity checking. | ||
832 | */ | ||
833 | if(ui32BufferCount > 0) | ||
834 | { | ||
835 | IMG_UINT32 ui32BuffersToSkip; | ||
836 | |||
837 | /* Check the buffer count */ | ||
838 | if(ui32BufferCount > psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers) | ||
839 | { | ||
840 | eError = PVRSRV_ERROR_TOOMANYBUFFERS; | ||
841 | goto ErrorFreeSwapChain; | ||
842 | } | ||
843 | |||
844 | if ((psDevInfo->sFBInfo.ulRoundedBufferSize * (unsigned long)ui32BufferCount) > psDevInfo->sFBInfo.ulFBSize) | ||
845 | { | ||
846 | eError = PVRSRV_ERROR_TOOMANYBUFFERS; | ||
847 | goto ErrorFreeSwapChain; | ||
848 | } | ||
849 | |||
850 | /* | ||
851 | * We will allocate the swap chain buffers at the back of the frame | ||
852 | * buffer area. This preserves the front portion, which may be being | ||
853 | * used by other Linux Framebuffer based applications. | ||
854 | */ | ||
855 | ui32BuffersToSkip = psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers - ui32BufferCount; | ||
856 | |||
857 | /* | ||
858 | * Verify the DST/SRC attributes, | ||
859 | * SRC/DST must match the current display mode config | ||
860 | */ | ||
861 | if(psDstSurfAttrib->pixelformat != psDevInfo->sDisplayFormat.pixelformat | ||
862 | || psDstSurfAttrib->sDims.ui32ByteStride != psDevInfo->sDisplayDim.ui32ByteStride | ||
863 | || psDstSurfAttrib->sDims.ui32Width != psDevInfo->sDisplayDim.ui32Width | ||
864 | || psDstSurfAttrib->sDims.ui32Height != psDevInfo->sDisplayDim.ui32Height) | ||
865 | { | ||
866 | /* DST doesn't match the current mode */ | ||
867 | eError = PVRSRV_ERROR_INVALID_PARAMS; | ||
868 | goto ErrorFreeSwapChain; | ||
869 | } | ||
870 | |||
871 | if(psDstSurfAttrib->pixelformat != psSrcSurfAttrib->pixelformat | ||
872 | || psDstSurfAttrib->sDims.ui32ByteStride != psSrcSurfAttrib->sDims.ui32ByteStride | ||
873 | || psDstSurfAttrib->sDims.ui32Width != psSrcSurfAttrib->sDims.ui32Width | ||
874 | || psDstSurfAttrib->sDims.ui32Height != psSrcSurfAttrib->sDims.ui32Height) | ||
875 | { | ||
876 | /* DST doesn't match the SRC */ | ||
877 | eError = PVRSRV_ERROR_INVALID_PARAMS; | ||
878 | goto ErrorFreeSwapChain; | ||
879 | } | ||
880 | |||
881 | psSwapChain->psBuffer = (DC_SUNXI_BUFFER*)kmalloc(sizeof(DC_SUNXI_BUFFER) * ui32BufferCount, GFP_KERNEL); | ||
882 | if(!psSwapChain->psBuffer) | ||
883 | { | ||
884 | eError = PVRSRV_ERROR_OUT_OF_MEMORY; | ||
885 | goto ErrorFreeSwapChain; | ||
886 | } | ||
887 | |||
888 | /* Link the buffers */ | ||
889 | for(i = 0; i < ui32BufferCount - 1; i++) | ||
890 | { | ||
891 | psSwapChain->psBuffer[i].psNext = &psSwapChain->psBuffer[i + 1]; | ||
892 | } | ||
893 | |||
894 | /* and link last to first */ | ||
895 | psSwapChain->psBuffer[i].psNext = &psSwapChain->psBuffer[0]; | ||
896 | |||
897 | /* Configure the swapchain buffers */ | ||
898 | for(i = 0; i < ui32BufferCount; i++) | ||
899 | { | ||
900 | IMG_UINT32 ui32SwapBuffer = i + ui32BuffersToSkip; | ||
901 | IMG_UINT32 ui32BufferOffset = ui32SwapBuffer * (IMG_UINT32)psDevInfo->sFBInfo.ulRoundedBufferSize; | ||
902 | |||
903 | psSwapChain->psBuffer[i].psSyncData = ppsSyncData[i]; | ||
904 | |||
905 | psSwapChain->psBuffer[i].sSysAddr.uiAddr = psDevInfo->sFBInfo.sSysAddr.uiAddr + ui32BufferOffset; | ||
906 | psSwapChain->psBuffer[i].sCPUVAddr = psDevInfo->sFBInfo.sCPUVAddr + ui32BufferOffset; | ||
907 | psSwapChain->psBuffer[i].ulYOffset = ui32BufferOffset / psDevInfo->sFBInfo.ulByteStride; | ||
908 | psSwapChain->psBuffer[i].psDevInfo = psDevInfo; | ||
909 | |||
910 | DC_SUNXIInitBufferForSwap(&psSwapChain->psBuffer[i]); | ||
911 | } | ||
912 | } | ||
913 | else | ||
914 | { | ||
915 | psSwapChain->psBuffer = NULL; | ||
916 | } | ||
917 | |||
918 | psSwapChain->ulBufferCount = (unsigned long)ui32BufferCount; | ||
919 | psSwapChain->bNotVSynced = true; | ||
920 | psSwapChain->uiFBDevID = psDevInfo->uiFBDevID; | ||
921 | |||
922 | if (DC_SUNXICreateSwapQueue(psSwapChain) != DC_SUNXI_OK) | ||
923 | { | ||
924 | printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Failed to create workqueue\n", __FUNCTION__, psDevInfo->uiFBDevID); | ||
925 | eError = PVRSRV_ERROR_UNABLE_TO_INSTALL_ISR; | ||
926 | goto ErrorFreeBuffers; | ||
927 | } | ||
928 | |||
929 | psDevInfo->uiSwapChainID++; | ||
930 | if (psDevInfo->uiSwapChainID == 0) | ||
931 | { | ||
932 | psDevInfo->uiSwapChainID++; | ||
933 | } | ||
934 | |||
935 | psSwapChain->uiSwapChainID = psDevInfo->uiSwapChainID; | ||
936 | |||
937 | psDevInfo->psSwapChain = psSwapChain; | ||
938 | |||
939 | *pui32SwapChainID = psDevInfo->uiSwapChainID; | ||
940 | |||
941 | *phSwapChain = (IMG_HANDLE)psSwapChain; | ||
942 | |||
943 | eError = PVRSRV_OK; | ||
944 | goto ExitUnLock; | ||
945 | |||
946 | ErrorFreeBuffers: | ||
947 | if(psSwapChain->psBuffer) | ||
948 | { | ||
949 | kfree(psSwapChain->psBuffer); | ||
950 | } | ||
951 | ErrorFreeSwapChain: | ||
952 | kfree(psSwapChain); | ||
953 | ExitUnLock: | ||
954 | mutex_unlock(&psDevInfo->sCreateSwapChainMutex); | ||
955 | return eError; | ||
956 | } | ||
957 | |||
958 | /* | ||
959 | * DestroyDCSwapChain | ||
960 | * Called from services. | ||
961 | */ | ||
962 | static PVRSRV_ERROR DestroyDCSwapChain(IMG_HANDLE hDevice, | ||
963 | IMG_HANDLE hSwapChain) | ||
964 | { | ||
965 | DC_SUNXI_DEVINFO *psDevInfo; | ||
966 | DC_SUNXI_SWAPCHAIN *psSwapChain; | ||
967 | DC_SUNXI_ERROR eError; | ||
968 | |||
969 | /* Check parameters */ | ||
970 | if(!hDevice || !hSwapChain) | ||
971 | { | ||
972 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
973 | } | ||
974 | |||
975 | psDevInfo = (DC_SUNXI_DEVINFO*)hDevice; | ||
976 | psSwapChain = (DC_SUNXI_SWAPCHAIN*)hSwapChain; | ||
977 | |||
978 | mutex_lock(&psDevInfo->sCreateSwapChainMutex); | ||
979 | |||
980 | if (SwapChainHasChanged(psDevInfo, psSwapChain)) | ||
981 | { | ||
982 | printk(KERN_WARNING DRIVER_PREFIX | ||
983 | ": %s: Device %u: Swap chain mismatch\n", __FUNCTION__, psDevInfo->uiFBDevID); | ||
984 | |||
985 | eError = PVRSRV_ERROR_INVALID_PARAMS; | ||
986 | goto ExitUnLock; | ||
987 | } | ||
988 | |||
989 | /* The swap queue is flushed before being destroyed */ | ||
990 | DC_SUNXIDestroySwapQueue(psSwapChain); | ||
991 | |||
992 | /* Free resources */ | ||
993 | if (psSwapChain->psBuffer) | ||
994 | { | ||
995 | kfree(psSwapChain->psBuffer); | ||
996 | } | ||
997 | kfree(psSwapChain); | ||
998 | |||
999 | psDevInfo->psSwapChain = NULL; | ||
1000 | |||
1001 | DC_SUNXIFlip(psDevInfo, &psDevInfo->sSystemBuffer); | ||
1002 | |||
1003 | eError = PVRSRV_OK; | ||
1004 | |||
1005 | ExitUnLock: | ||
1006 | mutex_unlock(&psDevInfo->sCreateSwapChainMutex); | ||
1007 | return eError; | ||
1008 | } | ||
1009 | |||
1010 | /* | ||
1011 | * SetDCDstRect | ||
1012 | * Called from services. | ||
1013 | */ | ||
1014 | static PVRSRV_ERROR SetDCDstRect(IMG_HANDLE hDevice, | ||
1015 | IMG_HANDLE hSwapChain, | ||
1016 | IMG_RECT *psRect) | ||
1017 | { | ||
1018 | UNREFERENCED_PARAMETER(hDevice); | ||
1019 | UNREFERENCED_PARAMETER(hSwapChain); | ||
1020 | UNREFERENCED_PARAMETER(psRect); | ||
1021 | |||
1022 | /* Only full display swapchains on this device */ | ||
1023 | |||
1024 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
1025 | } | ||
1026 | |||
1027 | /* | ||
1028 | * SetDCSrcRect | ||
1029 | * Called from services. | ||
1030 | */ | ||
1031 | static PVRSRV_ERROR SetDCSrcRect(IMG_HANDLE hDevice, | ||
1032 | IMG_HANDLE hSwapChain, | ||
1033 | IMG_RECT *psRect) | ||
1034 | { | ||
1035 | UNREFERENCED_PARAMETER(hDevice); | ||
1036 | UNREFERENCED_PARAMETER(hSwapChain); | ||
1037 | UNREFERENCED_PARAMETER(psRect); | ||
1038 | |||
1039 | /* Only full display swapchains on this device */ | ||
1040 | |||
1041 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
1042 | } | ||
1043 | |||
1044 | /* | ||
1045 | * SetDCDstColourKey | ||
1046 | * Called from services. | ||
1047 | */ | ||
1048 | static PVRSRV_ERROR SetDCDstColourKey(IMG_HANDLE hDevice, | ||
1049 | IMG_HANDLE hSwapChain, | ||
1050 | IMG_UINT32 ui32CKColour) | ||
1051 | { | ||
1052 | UNREFERENCED_PARAMETER(hDevice); | ||
1053 | UNREFERENCED_PARAMETER(hSwapChain); | ||
1054 | UNREFERENCED_PARAMETER(ui32CKColour); | ||
1055 | |||
1056 | /* Don't support DST CK on this device */ | ||
1057 | |||
1058 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
1059 | } | ||
1060 | |||
1061 | /* | ||
1062 | * SetDCSrcColourKey | ||
1063 | * Called from services. | ||
1064 | */ | ||
1065 | static PVRSRV_ERROR SetDCSrcColourKey(IMG_HANDLE hDevice, | ||
1066 | IMG_HANDLE hSwapChain, | ||
1067 | IMG_UINT32 ui32CKColour) | ||
1068 | { | ||
1069 | UNREFERENCED_PARAMETER(hDevice); | ||
1070 | UNREFERENCED_PARAMETER(hSwapChain); | ||
1071 | UNREFERENCED_PARAMETER(ui32CKColour); | ||
1072 | |||
1073 | /* Don't support SRC CK on this device */ | ||
1074 | |||
1075 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
1076 | } | ||
1077 | |||
1078 | /* | ||
1079 | * GetDCBuffers | ||
1080 | * Called from services. | ||
1081 | */ | ||
1082 | static PVRSRV_ERROR GetDCBuffers(IMG_HANDLE hDevice, | ||
1083 | IMG_HANDLE hSwapChain, | ||
1084 | IMG_UINT32 *pui32BufferCount, | ||
1085 | IMG_HANDLE *phBuffer) | ||
1086 | { | ||
1087 | DC_SUNXI_DEVINFO *psDevInfo; | ||
1088 | DC_SUNXI_SWAPCHAIN *psSwapChain; | ||
1089 | PVRSRV_ERROR eError; | ||
1090 | unsigned int i; | ||
1091 | |||
1092 | /* Check parameters */ | ||
1093 | if(!hDevice | ||
1094 | || !hSwapChain | ||
1095 | || !pui32BufferCount | ||
1096 | || !phBuffer) | ||
1097 | { | ||
1098 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
1099 | } | ||
1100 | |||
1101 | psDevInfo = (DC_SUNXI_DEVINFO*)hDevice; | ||
1102 | psSwapChain = (DC_SUNXI_SWAPCHAIN*)hSwapChain; | ||
1103 | |||
1104 | mutex_lock(&psDevInfo->sCreateSwapChainMutex); | ||
1105 | |||
1106 | if (SwapChainHasChanged(psDevInfo, psSwapChain)) | ||
1107 | { | ||
1108 | printk(KERN_WARNING DRIVER_PREFIX | ||
1109 | ": %s: Device %u: Swap chain mismatch\n", __FUNCTION__, psDevInfo->uiFBDevID); | ||
1110 | |||
1111 | eError = PVRSRV_ERROR_INVALID_PARAMS; | ||
1112 | goto Exit; | ||
1113 | } | ||
1114 | |||
1115 | /* Return the buffer count */ | ||
1116 | *pui32BufferCount = (IMG_UINT32)psSwapChain->ulBufferCount; | ||
1117 | |||
1118 | /* Return the buffers */ | ||
1119 | for(i=0; i<psSwapChain->ulBufferCount; i++) | ||
1120 | { | ||
1121 | phBuffer[i] = (IMG_HANDLE)&psSwapChain->psBuffer[i]; | ||
1122 | } | ||
1123 | |||
1124 | eError = PVRSRV_OK; | ||
1125 | |||
1126 | Exit: | ||
1127 | mutex_unlock(&psDevInfo->sCreateSwapChainMutex); | ||
1128 | return eError; | ||
1129 | } | ||
1130 | |||
1131 | /* | ||
1132 | * SwapToDCBuffer | ||
1133 | * Called from services. | ||
1134 | */ | ||
1135 | static PVRSRV_ERROR SwapToDCBuffer(IMG_HANDLE hDevice, | ||
1136 | IMG_HANDLE hBuffer, | ||
1137 | IMG_UINT32 ui32SwapInterval, | ||
1138 | IMG_HANDLE hPrivateTag, | ||
1139 | IMG_UINT32 ui32ClipRectCount, | ||
1140 | IMG_RECT *psClipRect) | ||
1141 | { | ||
1142 | UNREFERENCED_PARAMETER(hDevice); | ||
1143 | UNREFERENCED_PARAMETER(hBuffer); | ||
1144 | UNREFERENCED_PARAMETER(ui32SwapInterval); | ||
1145 | UNREFERENCED_PARAMETER(hPrivateTag); | ||
1146 | UNREFERENCED_PARAMETER(ui32ClipRectCount); | ||
1147 | UNREFERENCED_PARAMETER(psClipRect); | ||
1148 | |||
1149 | /* * Nothing to do since Services common code does the work */ | ||
1150 | |||
1151 | return PVRSRV_OK; | ||
1152 | } | ||
1153 | |||
1154 | /* Triggered by PVRSRVSwapToDCBuffer */ | ||
1155 | static IMG_BOOL ProcessFlipV1(IMG_HANDLE hCmdCookie, | ||
1156 | DC_SUNXI_DEVINFO *psDevInfo, | ||
1157 | DC_SUNXI_SWAPCHAIN *psSwapChain, | ||
1158 | DC_SUNXI_BUFFER *psBuffer, | ||
1159 | unsigned long ulSwapInterval) | ||
1160 | { | ||
1161 | mutex_lock(&psDevInfo->sCreateSwapChainMutex); | ||
1162 | |||
1163 | /* The swap chain has been destroyed */ | ||
1164 | if (SwapChainHasChanged(psDevInfo, psSwapChain)) | ||
1165 | { | ||
1166 | DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX | ||
1167 | ": %s: Device %u (PVR Device ID %u): The swap chain has been destroyed\n", | ||
1168 | __FUNCTION__, psDevInfo->uiFBDevID, psDevInfo->uiPVRDevID)); | ||
1169 | } | ||
1170 | else | ||
1171 | { | ||
1172 | #if defined(DC_SUNXI_DISPC_GRALLOC_QUEUE_IN_V1_PATH) | ||
1173 | /* Not enabled by default yet until we have a way to CmdComplete | ||
1174 | * after vblank rather than after next programming! | ||
1175 | */ | ||
1176 | QueueBufferImmediate(psDevInfo, psBuffer->sSysAddr, | ||
1177 | dispc_proxy_cmdcomplete, (void *)0xdeadbeef); | ||
1178 | |||
1179 | /* When dispc_gralloc_queue() can call back after programming, | ||
1180 | * this can be removed. | ||
1181 | */ | ||
1182 | psDevInfo->sPVRJTable.pfnPVRSRVCmdComplete(hCmdCookie, IMG_TRUE); | ||
1183 | #else /* DC_SUNXI_DISPC_GRALLOC_QUEUE_IN_V1_PATH */ | ||
1184 | int res; | ||
1185 | |||
1186 | psBuffer->hCmdComplete = hCmdCookie; | ||
1187 | psBuffer->ulSwapInterval = ulSwapInterval; | ||
1188 | |||
1189 | res = queue_work(psSwapChain->psWorkQueue, &psBuffer->sWork); | ||
1190 | if (res == 0) | ||
1191 | { | ||
1192 | printk(KERN_WARNING DRIVER_PREFIX | ||
1193 | ": %s: Device %u: Buffer already on work queue\n", | ||
1194 | __FUNCTION__, psSwapChain->uiFBDevID); | ||
1195 | } | ||
1196 | #endif /* DC_SUNXI_DISPC_GRALLOC_QUEUE_IN_V1_PATH */ | ||
1197 | } | ||
1198 | |||
1199 | mutex_unlock(&psDevInfo->sCreateSwapChainMutex); | ||
1200 | return IMG_TRUE; | ||
1201 | } | ||
1202 | |||
1203 | static IMG_BOOL ProcessFlipV2(IMG_HANDLE hCmdCookie, | ||
1204 | DC_SUNXI_DEVINFO *psDevInfo, | ||
1205 | PDC_MEM_INFO *ppsMemInfos, | ||
1206 | IMG_UINT32 ui32NumMemInfos, | ||
1207 | setup_dispc_data_t *psDispcData, | ||
1208 | IMG_UINT32 ui32DispcDataLength) | ||
1209 | { | ||
1210 | int i; | ||
1211 | |||
1212 | if(!psDispcData) | ||
1213 | { | ||
1214 | if(ui32NumMemInfos == 1) | ||
1215 | { | ||
1216 | IMG_CPU_PHYADDR phyAddr; | ||
1217 | IMG_SYS_PHYADDR sSysAddr; | ||
1218 | |||
1219 | psDevInfo->sPVRJTable.pfnPVRSRVDCMemInfoGetCpuPAddr(ppsMemInfos[0], 0, &phyAddr); | ||
1220 | sSysAddr.uiAddr = phyAddr.uiAddr; | ||
1221 | |||
1222 | /* If we got a meminfo but no private data, assume the 'null' HWC | ||
1223 | * backend is in use, and emulate a swapchain-less ProcessFlipV1. | ||
1224 | */ | ||
1225 | QueueBufferImmediate(psDevInfo, sSysAddr, | ||
1226 | dispc_proxy_cmdcomplete, hCmdCookie); | ||
1227 | } | ||
1228 | else | ||
1229 | { | ||
1230 | printk(KERN_WARNING DRIVER_PREFIX | ||
1231 | ": %s: Device %u: WARNING: psDispcData was NULL. " | ||
1232 | "The HWC probably has a bug. Silently ignoring.", | ||
1233 | __FUNCTION__, psDevInfo->uiFBDevID); | ||
1234 | gapsDevInfo[0]->sPVRJTable.pfnPVRSRVCmdComplete(hCmdCookie, IMG_TRUE); | ||
1235 | } | ||
1236 | |||
1237 | return IMG_TRUE; | ||
1238 | } | ||
1239 | |||
1240 | if(ui32DispcDataLength != sizeof(setup_dispc_data_t)) | ||
1241 | { | ||
1242 | printk(KERN_WARNING DRIVER_PREFIX | ||
1243 | ": %s: Device %u: WARNING: Unexpected private data size, %u vs %u.", | ||
1244 | __FUNCTION__, psDevInfo->uiFBDevID, ui32DispcDataLength, | ||
1245 | sizeof(setup_dispc_data_t)); | ||
1246 | gapsDevInfo[0]->sPVRJTable.pfnPVRSRVCmdComplete(hCmdCookie, IMG_TRUE); | ||
1247 | return IMG_TRUE; | ||
1248 | } | ||
1249 | |||
1250 | if(DontWaitForVSync(psDevInfo)) | ||
1251 | { | ||
1252 | gapsDevInfo[0]->sPVRJTable.pfnPVRSRVCmdComplete(hCmdCookie, IMG_TRUE); | ||
1253 | return IMG_TRUE; | ||
1254 | } | ||
1255 | |||
1256 | /* Maximum of 8 layer_infos. Meminfo array is dynamically sized */ | ||
1257 | for(i = 0; i < ui32NumMemInfos && i < 8; i++) | ||
1258 | { | ||
1259 | IMG_CPU_PHYADDR phyAddr; | ||
1260 | |||
1261 | psDevInfo->sPVRJTable.pfnPVRSRVDCMemInfoGetCpuPAddr(ppsMemInfos[i], 0, &phyAddr); | ||
1262 | |||
1263 | psDispcData->layer_info[i].fb.addr[0] = phyAddr.uiAddr; | ||
1264 | } | ||
1265 | |||
1266 | dispc_gralloc_queue(psDispcData, ui32DispcDataLength, dispc_proxy_cmdcomplete, (void *)hCmdCookie); | ||
1267 | |||
1268 | return IMG_TRUE; | ||
1269 | } | ||
1270 | |||
1271 | /* Command processing flip handler function. Called from services. */ | ||
1272 | static IMG_BOOL ProcessFlip(IMG_HANDLE hCmdCookie, | ||
1273 | IMG_UINT32 ui32DataSize, | ||
1274 | IMG_VOID *pvData) | ||
1275 | { | ||
1276 | DISPLAYCLASS_FLIP_COMMAND *psFlipCmd; | ||
1277 | DC_SUNXI_DEVINFO *psDevInfo; | ||
1278 | |||
1279 | /* Check parameters */ | ||
1280 | if(!hCmdCookie || !pvData) | ||
1281 | { | ||
1282 | return IMG_FALSE; | ||
1283 | } | ||
1284 | |||
1285 | /* Validate data packet */ | ||
1286 | psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)pvData; | ||
1287 | |||
1288 | if (psFlipCmd == IMG_NULL) | ||
1289 | { | ||
1290 | return IMG_FALSE; | ||
1291 | } | ||
1292 | |||
1293 | psDevInfo = (DC_SUNXI_DEVINFO*)psFlipCmd->hExtDevice; | ||
1294 | |||
1295 | if(psFlipCmd->hExtBuffer) | ||
1296 | { | ||
1297 | return ProcessFlipV1(hCmdCookie, | ||
1298 | psDevInfo, | ||
1299 | psFlipCmd->hExtSwapChain, | ||
1300 | psFlipCmd->hExtBuffer, | ||
1301 | psFlipCmd->ui32SwapInterval); | ||
1302 | } | ||
1303 | else | ||
1304 | { | ||
1305 | DISPLAYCLASS_FLIP_COMMAND2 *psFlipCmd2; | ||
1306 | psFlipCmd2 = (DISPLAYCLASS_FLIP_COMMAND2 *)pvData; | ||
1307 | return ProcessFlipV2(hCmdCookie, | ||
1308 | psDevInfo, | ||
1309 | psFlipCmd2->ppsMemInfos, | ||
1310 | psFlipCmd2->ui32NumMemInfos, | ||
1311 | psFlipCmd2->pvPrivData, | ||
1312 | psFlipCmd2->ui32PrivDataLength); | ||
1313 | } | ||
1314 | } | ||
1315 | |||
1316 | static DC_SUNXI_ERROR DC_SUNXIInitFBDev(DC_SUNXI_DEVINFO *psDevInfo) | ||
1317 | { | ||
1318 | struct fb_info *psLINFBInfo; | ||
1319 | struct module *psLINFBOwner; | ||
1320 | DC_SUNXI_FBINFO *psPVRFBInfo = &psDevInfo->sFBInfo; | ||
1321 | DC_SUNXI_ERROR eError = DC_SUNXI_ERROR_GENERIC; | ||
1322 | unsigned int uiFBDevID = psDevInfo->uiFBDevID; | ||
1323 | |||
1324 | console_lock(); | ||
1325 | |||
1326 | psLINFBInfo = registered_fb[uiFBDevID]; | ||
1327 | if (psLINFBInfo == NULL) | ||
1328 | { | ||
1329 | eError = DC_SUNXI_ERROR_INVALID_DEVICE; | ||
1330 | goto ErrorRelSem; | ||
1331 | } | ||
1332 | |||
1333 | psLINFBOwner = psLINFBInfo->fbops->owner; | ||
1334 | if (!try_module_get(psLINFBOwner)) | ||
1335 | { | ||
1336 | printk(KERN_INFO DRIVER_PREFIX | ||
1337 | ": %s: Device %u: Couldn't get framebuffer module\n", __FUNCTION__, uiFBDevID); | ||
1338 | |||
1339 | goto ErrorRelSem; | ||
1340 | } | ||
1341 | |||
1342 | if (psLINFBInfo->fbops->fb_open != NULL) | ||
1343 | { | ||
1344 | int res; | ||
1345 | |||
1346 | res = psLINFBInfo->fbops->fb_open(psLINFBInfo, 0); | ||
1347 | if (res != 0) | ||
1348 | { | ||
1349 | printk(KERN_INFO DRIVER_PREFIX | ||
1350 | " %s: Device %u: Couldn't open framebuffer(%d)\n", __FUNCTION__, uiFBDevID, res); | ||
1351 | |||
1352 | goto ErrorModPut; | ||
1353 | } | ||
1354 | } | ||
1355 | |||
1356 | psDevInfo->psLINFBInfo = psLINFBInfo; | ||
1357 | |||
1358 | psPVRFBInfo->ulWidth = psLINFBInfo->var.xres; | ||
1359 | psPVRFBInfo->ulHeight = psLINFBInfo->var.yres; | ||
1360 | |||
1361 | if (psPVRFBInfo->ulWidth == 0 || psPVRFBInfo->ulHeight == 0) | ||
1362 | { | ||
1363 | eError = DC_SUNXI_ERROR_INVALID_DEVICE; | ||
1364 | goto ErrorFBRel; | ||
1365 | } | ||
1366 | |||
1367 | psPVRFBInfo->ulFBSize = (psLINFBInfo->screen_size) != 0 ? | ||
1368 | psLINFBInfo->screen_size : psLINFBInfo->fix.smem_len; | ||
1369 | |||
1370 | /* | ||
1371 | * Try and filter out invalid FB info structures (a problem | ||
1372 | * seen on some systems). | ||
1373 | */ | ||
1374 | if (psPVRFBInfo->ulFBSize == 0 || psLINFBInfo->fix.line_length == 0) | ||
1375 | { | ||
1376 | eError = DC_SUNXI_ERROR_INVALID_DEVICE; | ||
1377 | goto ErrorFBRel; | ||
1378 | } | ||
1379 | |||
1380 | DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX | ||
1381 | ": Device %u: Framebuffer size: %lu\n", | ||
1382 | psDevInfo->uiFBDevID, psPVRFBInfo->ulFBSize)); | ||
1383 | DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX | ||
1384 | ": Device %u: Framebuffer virtual width: %u\n", | ||
1385 | psDevInfo->uiFBDevID, psLINFBInfo->var.xres_virtual)); | ||
1386 | DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX | ||
1387 | ": Device %u: Framebuffer virtual height: %u\n", | ||
1388 | psDevInfo->uiFBDevID, psLINFBInfo->var.yres_virtual)); | ||
1389 | DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX | ||
1390 | ": Device %u: Framebuffer width: %lu\n", | ||
1391 | psDevInfo->uiFBDevID, psPVRFBInfo->ulWidth)); | ||
1392 | DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX | ||
1393 | ": Device %u: Framebuffer height: %lu\n", | ||
1394 | psDevInfo->uiFBDevID, psPVRFBInfo->ulHeight)); | ||
1395 | |||
1396 | /* System Surface */ | ||
1397 | psPVRFBInfo->sSysAddr.uiAddr = psLINFBInfo->fix.smem_start; | ||
1398 | psPVRFBInfo->sCPUVAddr = psLINFBInfo->screen_base; | ||
1399 | |||
1400 | psPVRFBInfo->ulByteStride = psLINFBInfo->fix.line_length; | ||
1401 | |||
1402 | printk(KERN_WARNING | ||
1403 | "#####: Device %u: Framebuffer physical address: 0x%x\n", | ||
1404 | psDevInfo->uiFBDevID, psPVRFBInfo->sSysAddr.uiAddr); | ||
1405 | |||
1406 | if (psPVRFBInfo->sCPUVAddr != NULL) | ||
1407 | { | ||
1408 | DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX | ||
1409 | ": Device %u: Framebuffer virtual address: %p\n", | ||
1410 | psDevInfo->uiFBDevID, psPVRFBInfo->sCPUVAddr)); | ||
1411 | } | ||
1412 | |||
1413 | DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX | ||
1414 | ": Device %u: Framebuffer stride: %lu\n", | ||
1415 | psDevInfo->uiFBDevID, psPVRFBInfo->ulByteStride)); | ||
1416 | |||
1417 | psPVRFBInfo->ulBufferSize = psPVRFBInfo->ulHeight * psPVRFBInfo->ulByteStride; | ||
1418 | |||
1419 | { | ||
1420 | unsigned long ulLCM; | ||
1421 | ulLCM = LCM(psPVRFBInfo->ulByteStride, PAGE_SIZE); | ||
1422 | |||
1423 | DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX | ||
1424 | ": Device %u: LCM of stride and page size: %lu\n", | ||
1425 | psDevInfo->uiFBDevID, ulLCM)); | ||
1426 | |||
1427 | /* Round the buffer size up to a multiple of the number of pages | ||
1428 | * and the byte stride. | ||
1429 | * This is used internally, to ensure buffers start on page | ||
1430 | * boundaries, for the benefit of PVR Services. | ||
1431 | */ | ||
1432 | psPVRFBInfo->ulRoundedBufferSize = RoundUpToMultiple(psPVRFBInfo->ulBufferSize, ulLCM); | ||
1433 | } | ||
1434 | |||
1435 | if(psLINFBInfo->var.bits_per_pixel == 16) | ||
1436 | { | ||
1437 | if((psLINFBInfo->var.red.length == 5) && | ||
1438 | (psLINFBInfo->var.green.length == 6) && | ||
1439 | (psLINFBInfo->var.blue.length == 5) && | ||
1440 | (psLINFBInfo->var.red.offset == 11) && | ||
1441 | (psLINFBInfo->var.green.offset == 5) && | ||
1442 | (psLINFBInfo->var.blue.offset == 0) && | ||
1443 | (psLINFBInfo->var.red.msb_right == 0)) | ||
1444 | { | ||
1445 | psPVRFBInfo->ePixelFormat = PVRSRV_PIXEL_FORMAT_RGB565; | ||
1446 | } | ||
1447 | else | ||
1448 | { | ||
1449 | printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unknown FB format\n", __FUNCTION__, uiFBDevID); | ||
1450 | } | ||
1451 | } | ||
1452 | else if(psLINFBInfo->var.bits_per_pixel == 32) | ||
1453 | { | ||
1454 | if((psLINFBInfo->var.red.length == 8) && | ||
1455 | (psLINFBInfo->var.green.length == 8) && | ||
1456 | (psLINFBInfo->var.blue.length == 8) && | ||
1457 | (psLINFBInfo->var.red.offset == 16) && | ||
1458 | (psLINFBInfo->var.green.offset == 8) && | ||
1459 | (psLINFBInfo->var.blue.offset == 0) && | ||
1460 | (psLINFBInfo->var.red.msb_right == 0)) | ||
1461 | { | ||
1462 | psPVRFBInfo->ePixelFormat = PVRSRV_PIXEL_FORMAT_ARGB8888; | ||
1463 | } | ||
1464 | else | ||
1465 | { | ||
1466 | printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unknown FB format\n", __FUNCTION__, uiFBDevID); | ||
1467 | } | ||
1468 | } | ||
1469 | else | ||
1470 | { | ||
1471 | printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unknown FB format\n", __FUNCTION__, uiFBDevID); | ||
1472 | } | ||
1473 | |||
1474 | psDevInfo->sFBInfo.ulPhysicalWidthmm = | ||
1475 | ((int)psLINFBInfo->var.width > 0) ? psLINFBInfo->var.width : 90; | ||
1476 | |||
1477 | psDevInfo->sFBInfo.ulPhysicalHeightmm = | ||
1478 | ((int)psLINFBInfo->var.height > 0) ? psLINFBInfo->var.height : 54; | ||
1479 | |||
1480 | /* System Surface */ | ||
1481 | psDevInfo->sFBInfo.sSysAddr.uiAddr = psPVRFBInfo->sSysAddr.uiAddr; | ||
1482 | psDevInfo->sFBInfo.sCPUVAddr = psPVRFBInfo->sCPUVAddr; | ||
1483 | |||
1484 | eError = DC_SUNXI_OK; | ||
1485 | goto ErrorRelSem; | ||
1486 | |||
1487 | ErrorFBRel: | ||
1488 | if (psLINFBInfo->fbops->fb_release != NULL) | ||
1489 | { | ||
1490 | (void) psLINFBInfo->fbops->fb_release(psLINFBInfo, 0); | ||
1491 | } | ||
1492 | ErrorModPut: | ||
1493 | module_put(psLINFBOwner); | ||
1494 | ErrorRelSem: | ||
1495 | console_unlock(); | ||
1496 | |||
1497 | return eError; | ||
1498 | } | ||
1499 | |||
1500 | static void DC_SUNXIDeInitFBDev(DC_SUNXI_DEVINFO *psDevInfo) | ||
1501 | { | ||
1502 | struct fb_info *psLINFBInfo = psDevInfo->psLINFBInfo; | ||
1503 | struct module *psLINFBOwner; | ||
1504 | |||
1505 | console_lock(); | ||
1506 | |||
1507 | psLINFBOwner = psLINFBInfo->fbops->owner; | ||
1508 | |||
1509 | if (psLINFBInfo->fbops->fb_release != NULL) | ||
1510 | { | ||
1511 | (void) psLINFBInfo->fbops->fb_release(psLINFBInfo, 0); | ||
1512 | } | ||
1513 | |||
1514 | module_put(psLINFBOwner); | ||
1515 | |||
1516 | console_unlock(); | ||
1517 | } | ||
1518 | |||
1519 | static DC_SUNXI_DEVINFO *DC_SUNXIInitDev(unsigned uiFBDevID) | ||
1520 | { | ||
1521 | PFN_CMD_PROC pfnCmdProcList[DC_SUNXI_COMMAND_COUNT]; | ||
1522 | IMG_UINT32 aui32SyncCountList[DC_SUNXI_COMMAND_COUNT][2]; | ||
1523 | DC_SUNXI_DEVINFO *psDevInfo = NULL; | ||
1524 | |||
1525 | /* Allocate device info. structure */ | ||
1526 | psDevInfo = (DC_SUNXI_DEVINFO *)kmalloc(sizeof(DC_SUNXI_DEVINFO), GFP_KERNEL); | ||
1527 | |||
1528 | if(psDevInfo == NULL) | ||
1529 | { | ||
1530 | printk(KERN_ERR DRIVER_PREFIX | ||
1531 | ": %s: Device %u: Couldn't allocate device information structure\n", __FUNCTION__, uiFBDevID); | ||
1532 | |||
1533 | goto ErrorExit; | ||
1534 | } | ||
1535 | |||
1536 | /* Any fields not set will be zero */ | ||
1537 | memset(psDevInfo, 0, sizeof(DC_SUNXI_DEVINFO)); | ||
1538 | |||
1539 | psDevInfo->uiFBDevID = uiFBDevID; | ||
1540 | |||
1541 | /* Get the kernel services function table */ | ||
1542 | if(!(*gpfnGetPVRJTable)(&psDevInfo->sPVRJTable)) | ||
1543 | { | ||
1544 | goto ErrorFreeDevInfo; | ||
1545 | } | ||
1546 | |||
1547 | /* Save private fbdev information structure in the dev. info. */ | ||
1548 | if(DC_SUNXIInitFBDev(psDevInfo) != DC_SUNXI_OK) | ||
1549 | { | ||
1550 | /* | ||
1551 | * Leave it to DC_SUNXIInitFBDev to print an error message, if | ||
1552 | * required. The function may have failed because | ||
1553 | * there is no Linux framebuffer device corresponding | ||
1554 | * to the device ID. | ||
1555 | */ | ||
1556 | goto ErrorIonClientDestroy; | ||
1557 | } | ||
1558 | |||
1559 | psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = (IMG_UINT32)(psDevInfo->sFBInfo.ulFBSize / psDevInfo->sFBInfo.ulRoundedBufferSize); | ||
1560 | if (psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers != 0) | ||
1561 | { | ||
1562 | psDevInfo->sDisplayInfo.ui32MaxSwapChains = 1; | ||
1563 | psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 1; | ||
1564 | } | ||
1565 | |||
1566 | psDevInfo->sDisplayInfo.ui32PhysicalWidthmm = psDevInfo->sFBInfo.ulPhysicalWidthmm; | ||
1567 | psDevInfo->sDisplayInfo.ui32PhysicalHeightmm = psDevInfo->sFBInfo.ulPhysicalHeightmm; | ||
1568 | |||
1569 | strncpy(psDevInfo->sDisplayInfo.szDisplayName, DISPLAY_DEVICE_NAME, MAX_DISPLAY_NAME_SIZE); | ||
1570 | |||
1571 | psDevInfo->sDisplayFormat.pixelformat = psDevInfo->sFBInfo.ePixelFormat; | ||
1572 | psDevInfo->sDisplayDim.ui32Width = (IMG_UINT32)psDevInfo->sFBInfo.ulWidth; | ||
1573 | psDevInfo->sDisplayDim.ui32Height = (IMG_UINT32)psDevInfo->sFBInfo.ulHeight; | ||
1574 | psDevInfo->sDisplayDim.ui32ByteStride = (IMG_UINT32)psDevInfo->sFBInfo.ulByteStride; | ||
1575 | |||
1576 | DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX | ||
1577 | ": Device %u: Maximum number of swap chain buffers: %u\n", | ||
1578 | psDevInfo->uiFBDevID, psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers)); | ||
1579 | |||
1580 | /* Setup system buffer */ | ||
1581 | psDevInfo->sSystemBuffer.sSysAddr = psDevInfo->sFBInfo.sSysAddr; | ||
1582 | psDevInfo->sSystemBuffer.sCPUVAddr = psDevInfo->sFBInfo.sCPUVAddr; | ||
1583 | psDevInfo->sSystemBuffer.psDevInfo = psDevInfo; | ||
1584 | |||
1585 | DC_SUNXIInitBufferForSwap(&psDevInfo->sSystemBuffer); | ||
1586 | |||
1587 | /* | ||
1588 | * Setup the DC Jtable so SRVKM can call into this driver | ||
1589 | */ | ||
1590 | psDevInfo->sDCJTable.ui32TableSize = sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE); | ||
1591 | psDevInfo->sDCJTable.pfnOpenDCDevice = OpenDCDevice; | ||
1592 | psDevInfo->sDCJTable.pfnCloseDCDevice = CloseDCDevice; | ||
1593 | psDevInfo->sDCJTable.pfnEnumDCFormats = EnumDCFormats; | ||
1594 | psDevInfo->sDCJTable.pfnEnumDCDims = EnumDCDims; | ||
1595 | psDevInfo->sDCJTable.pfnGetDCSystemBuffer = GetDCSystemBuffer; | ||
1596 | psDevInfo->sDCJTable.pfnGetDCInfo = GetDCInfo; | ||
1597 | psDevInfo->sDCJTable.pfnGetBufferAddr = GetDCBufferAddr; | ||
1598 | psDevInfo->sDCJTable.pfnCreateDCSwapChain = CreateDCSwapChain; | ||
1599 | psDevInfo->sDCJTable.pfnDestroyDCSwapChain = DestroyDCSwapChain; | ||
1600 | psDevInfo->sDCJTable.pfnSetDCDstRect = SetDCDstRect; | ||
1601 | psDevInfo->sDCJTable.pfnSetDCSrcRect = SetDCSrcRect; | ||
1602 | psDevInfo->sDCJTable.pfnSetDCDstColourKey = SetDCDstColourKey; | ||
1603 | psDevInfo->sDCJTable.pfnSetDCSrcColourKey = SetDCSrcColourKey; | ||
1604 | psDevInfo->sDCJTable.pfnGetDCBuffers = GetDCBuffers; | ||
1605 | psDevInfo->sDCJTable.pfnSwapToDCBuffer = SwapToDCBuffer; | ||
1606 | psDevInfo->sDCJTable.pfnSetDCState = SetDCState; | ||
1607 | |||
1608 | /* Register device with services and retrieve device index */ | ||
1609 | if(psDevInfo->sPVRJTable.pfnPVRSRVRegisterDCDevice( | ||
1610 | &psDevInfo->sDCJTable, | ||
1611 | &psDevInfo->uiPVRDevID) != PVRSRV_OK) | ||
1612 | { | ||
1613 | printk(KERN_ERR DRIVER_PREFIX | ||
1614 | ": %s: Device %u: PVR Services device registration failed\n", __FUNCTION__, uiFBDevID); | ||
1615 | |||
1616 | goto ErrorDeInitFBDev; | ||
1617 | } | ||
1618 | |||
1619 | DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": Device %u: PVR Device ID: %u\n", | ||
1620 | psDevInfo->uiFBDevID, psDevInfo->uiPVRDevID)); | ||
1621 | |||
1622 | /* Setup private command processing function table ... */ | ||
1623 | pfnCmdProcList[DC_FLIP_COMMAND] = ProcessFlip; | ||
1624 | |||
1625 | /* ... and associated sync count(s) */ | ||
1626 | aui32SyncCountList[DC_FLIP_COMMAND][0] = 0; /* writes */ | ||
1627 | aui32SyncCountList[DC_FLIP_COMMAND][1] = 10; /* reads */ | ||
1628 | |||
1629 | if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterCmdProcList(psDevInfo->uiPVRDevID, | ||
1630 | &pfnCmdProcList[0], | ||
1631 | aui32SyncCountList, | ||
1632 | DC_SUNXI_COMMAND_COUNT) != PVRSRV_OK) | ||
1633 | { | ||
1634 | printk(KERN_ERR DRIVER_PREFIX | ||
1635 | ": %s: Device %u: Couldn't register command processing functions with PVR Services\n", __FUNCTION__, uiFBDevID); | ||
1636 | goto ErrorUnregisterDevice; | ||
1637 | } | ||
1638 | |||
1639 | mutex_init(&psDevInfo->sCreateSwapChainMutex); | ||
1640 | |||
1641 | atomic_set(&psDevInfo->sBlankEvents, 0); | ||
1642 | atomic_set(&psDevInfo->sFlushCommands, false); | ||
1643 | |||
1644 | return psDevInfo; | ||
1645 | |||
1646 | ErrorUnregisterDevice: | ||
1647 | (void)psDevInfo->sPVRJTable.pfnPVRSRVRemoveDCDevice(psDevInfo->uiPVRDevID); | ||
1648 | ErrorDeInitFBDev: | ||
1649 | DC_SUNXIDeInitFBDev(psDevInfo); | ||
1650 | ErrorIonClientDestroy: | ||
1651 | ErrorFreeDevInfo: | ||
1652 | kfree(psDevInfo); | ||
1653 | ErrorExit: | ||
1654 | return NULL; | ||
1655 | } | ||
1656 | |||
1657 | static DC_SUNXI_ERROR DC_SUNXIInit(void) | ||
1658 | { | ||
1659 | unsigned int i, uiMaxFBDevIDPlusOne = DC_SUNXIMaxFBDevIDPlusOne(); | ||
1660 | unsigned int uiDevicesFound = 0; | ||
1661 | |||
1662 | gpfnGetPVRJTable = PVRGetDisplayClassJTable; | ||
1663 | |||
1664 | /* | ||
1665 | * We search for frame buffer devices backwards, as the last device | ||
1666 | * registered with PVR Services will be the first device enumerated | ||
1667 | * by PVR Services. | ||
1668 | */ | ||
1669 | for(i = uiMaxFBDevIDPlusOne; i-- != 0;) | ||
1670 | { | ||
1671 | DC_SUNXI_DEVINFO *psDevInfo = DC_SUNXIInitDev(i); | ||
1672 | |||
1673 | if (psDevInfo != NULL) | ||
1674 | { | ||
1675 | /* Set the top-level anchor */ | ||
1676 | DC_SUNXISetDevInfoPtr(psDevInfo->uiFBDevID, psDevInfo); | ||
1677 | uiDevicesFound++; | ||
1678 | } | ||
1679 | } | ||
1680 | |||
1681 | return (uiDevicesFound != 0) ? DC_SUNXI_OK : DC_SUNXI_ERROR_INIT_FAILURE; | ||
1682 | } | ||
1683 | |||
1684 | static bool DC_SUNXIDeInitDev(DC_SUNXI_DEVINFO *psDevInfo) | ||
1685 | { | ||
1686 | PVRSRV_DC_DISP2SRV_KMJTABLE *psPVRJTable = &psDevInfo->sPVRJTable; | ||
1687 | |||
1688 | if (psPVRJTable->pfnPVRSRVRemoveCmdProcList (psDevInfo->uiPVRDevID, DC_SUNXI_COMMAND_COUNT) != PVRSRV_OK) | ||
1689 | { | ||
1690 | printk(KERN_ERR DRIVER_PREFIX | ||
1691 | ": %s: Device %u: PVR Device %u: Couldn't unregister command processing functions\n", __FUNCTION__, psDevInfo->uiFBDevID, psDevInfo->uiPVRDevID); | ||
1692 | return false; | ||
1693 | } | ||
1694 | |||
1695 | if (psPVRJTable->pfnPVRSRVRemoveDCDevice(psDevInfo->uiPVRDevID) != PVRSRV_OK) | ||
1696 | { | ||
1697 | printk(KERN_ERR DRIVER_PREFIX | ||
1698 | ": %s: Device %u: PVR Device %u: Couldn't remove device from PVR Services\n", __FUNCTION__, psDevInfo->uiFBDevID, psDevInfo->uiPVRDevID); | ||
1699 | return false; | ||
1700 | } | ||
1701 | |||
1702 | mutex_destroy(&psDevInfo->sCreateSwapChainMutex); | ||
1703 | |||
1704 | DC_SUNXIDeInitFBDev(psDevInfo); | ||
1705 | |||
1706 | DC_SUNXISetDevInfoPtr(psDevInfo->uiFBDevID, NULL); | ||
1707 | |||
1708 | /* De-allocate data structure */ | ||
1709 | kfree(psDevInfo); | ||
1710 | |||
1711 | return true; | ||
1712 | } | ||
1713 | |||
1714 | static DC_SUNXI_ERROR DC_SUNXIDeInit(void) | ||
1715 | { | ||
1716 | unsigned int i, uiMaxFBDevIDPlusOne = DC_SUNXIMaxFBDevIDPlusOne(); | ||
1717 | bool bError = false; | ||
1718 | |||
1719 | for(i = 0; i < uiMaxFBDevIDPlusOne; i++) | ||
1720 | { | ||
1721 | DC_SUNXI_DEVINFO *psDevInfo = DC_SUNXIGetDevInfoPtr(i); | ||
1722 | |||
1723 | if (psDevInfo != NULL) | ||
1724 | { | ||
1725 | bError |= !DC_SUNXIDeInitDev(psDevInfo); | ||
1726 | } | ||
1727 | } | ||
1728 | |||
1729 | return (bError) ? DC_SUNXI_ERROR_INIT_FAILURE : DC_SUNXI_OK; | ||
1730 | } | ||
1731 | |||
1732 | #if defined(SUPPORT_DRI_DRM) | ||
1733 | int PVR_DRM_MAKENAME(DISPLAY_CONTROLLER, _Init)(struct drm_device unref__ *dev) | ||
1734 | #else | ||
1735 | static int __init DC_SUNXI_Init(void) | ||
1736 | #endif | ||
1737 | { | ||
1738 | if(DC_SUNXIInit() != DC_SUNXI_OK) | ||
1739 | { | ||
1740 | printk(KERN_ERR DRIVER_PREFIX ": %s: DC_SUNXIInit failed\n", __FUNCTION__); | ||
1741 | return -ENODEV; | ||
1742 | } | ||
1743 | |||
1744 | return 0; | ||
1745 | } | ||
1746 | |||
1747 | #if defined(SUPPORT_DRI_DRM) | ||
1748 | void PVR_DRM_MAKENAME(DISPLAY_CONTROLLER, _Cleanup)(struct drm_device unref__ *dev) | ||
1749 | #else | ||
1750 | static void __exit DC_SUNXI_Cleanup(void) | ||
1751 | #endif | ||
1752 | { | ||
1753 | if(DC_SUNXIDeInit() != DC_SUNXI_OK) | ||
1754 | { | ||
1755 | printk(KERN_ERR DRIVER_PREFIX ": %s: DC_SUNXIDeInit failed\n", __FUNCTION__); | ||
1756 | } | ||
1757 | } | ||
1758 | |||
1759 | #if !defined(SUPPORT_DRI_DRM) | ||
1760 | late_initcall(DC_SUNXI_Init); | ||
1761 | module_exit(DC_SUNXI_Cleanup); | ||
1762 | #endif | ||
1763 | /****************************************************************************** | ||
1764 | * End of file (dc_sunxi_displayclass.c) | ||
1765 | ******************************************************************************/ | ||