diff options
Diffstat (limited to 'drivers/gpu/pvr/display')
-rw-r--r-- | drivers/gpu/pvr/display/omap_display.c | 1078 | ||||
-rw-r--r-- | drivers/gpu/pvr/display/omap_display.h | 109 | ||||
-rw-r--r-- | drivers/gpu/pvr/display/omap_sgx_displayclass.c | 1638 | ||||
-rw-r--r-- | drivers/gpu/pvr/display/omap_sgx_displayclass.h | 123 |
4 files changed, 2948 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/display/omap_display.c b/drivers/gpu/pvr/display/omap_display.c new file mode 100644 index 00000000000..1fb5f353870 --- /dev/null +++ b/drivers/gpu/pvr/display/omap_display.c | |||
@@ -0,0 +1,1078 @@ | |||
1 | /* | ||
2 | * drivers/gpu/pvr/display/omap_display.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/fb.h> | ||
22 | |||
23 | #include <plat/vrfb.h> | ||
24 | #include <plat/display.h> | ||
25 | |||
26 | /* Workaround for DEBUG macro clash in framebuffer */ | ||
27 | #ifdef RELEASE | ||
28 | #include <../drivers/video/omap2/omapfb/omapfb.h> | ||
29 | #undef DEBUG | ||
30 | #else | ||
31 | #undef DEBUG | ||
32 | #include <../drivers/video/omap2/omapfb/omapfb.h> | ||
33 | #endif | ||
34 | |||
35 | #define OMAP_DISP_DRV_NAME "omap_display" | ||
36 | #define OMAP_DISP_FRAMEBUFFER_COUNT num_registered_fb | ||
37 | |||
38 | #define OMAP_DISP_PAGE_MASK (PAGE_SIZE - 1) | ||
39 | #define OMAP_DISP_PAGE_TRUNCATE (~OMAP_DISP_PAGE_MASK) | ||
40 | #define OMAP_DISP_PAGE_ROUND_UP(x) \ | ||
41 | (((x)+OMAP_DISP_PAGE_MASK) & OMAP_DISP_PAGE_TRUNCATE) | ||
42 | |||
43 | #define OMAP_DISP_IRQ_TIMEOUT 500 | ||
44 | |||
45 | #ifdef DEBUG | ||
46 | #define DBG_PRINT(format, ...) printk(KERN_DEBUG OMAP_DISP_DRV_NAME \ | ||
47 | " (%s %i): " format "\n", __func__, __LINE__, ## __VA_ARGS__) | ||
48 | #define WRN_PRINT(format, ...) printk(KERN_WARNING OMAP_DISP_DRV_NAME \ | ||
49 | " (%s %i): " format "\n", __func__, __LINE__, ## __VA_ARGS__) | ||
50 | #define ERR_PRINT(format, ...) printk(KERN_ERR OMAP_DISP_DRV_NAME \ | ||
51 | " (%s %i): " format "\n", __func__, __LINE__, ## __VA_ARGS__) | ||
52 | #else | ||
53 | #define DBG_PRINT(format, ...) | ||
54 | #define WRN_PRINT(format, ...) | ||
55 | #define ERR_PRINT(format, ...) | ||
56 | #endif | ||
57 | |||
58 | #include "omap_display.h" | ||
59 | |||
60 | /* List for the available displays */ | ||
61 | static struct omap_display_device *omap_display_list; | ||
62 | static unsigned int omap_display_number; | ||
63 | |||
64 | /* Forward declarations */ | ||
65 | static struct omap_display_buffer *create_main_buffer( | ||
66 | struct omap_display_device *display); | ||
67 | static int display_destroy_buffer(struct omap_display_buffer *buffer); | ||
68 | |||
69 | static int open_display(struct omap_display_device *display, | ||
70 | enum omap_display_feature features) | ||
71 | { | ||
72 | int i; | ||
73 | |||
74 | DBG_PRINT("Opening display '%s'", display->name); | ||
75 | |||
76 | /* TODO: Support horizontal orientation */ | ||
77 | if (features & ORIENTATION_HORIZONTAL) { | ||
78 | DBG_PRINT("Horizontal orientation is not supported yet , " | ||
79 | "falling back to vertical orientation"); | ||
80 | features = ORIENTATION_VERTICAL; | ||
81 | } | ||
82 | |||
83 | display->features = features; | ||
84 | display->reference_count++; | ||
85 | for (i = 0; i < display->overlay_managers_count; i++) | ||
86 | omap_dss_get_device(display->overlay_managers[i]->device); | ||
87 | |||
88 | /* If the main buffer doesn't exist create it */ | ||
89 | if (!display->main_buffer) { | ||
90 | DBG_PRINT("Main buffer doesn't exist for display '%s', create" | ||
91 | " one", display->name); | ||
92 | display->main_buffer = create_main_buffer(display); | ||
93 | if (!display->main_buffer) { | ||
94 | ERR_PRINT("Failed to create main buffer for '%s'", | ||
95 | display->name); | ||
96 | return 1; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int close_display(struct omap_display_device *display) | ||
104 | { | ||
105 | int err; | ||
106 | int i; | ||
107 | |||
108 | /* TODO: Is it the same thing to close a virtual and single display? */ | ||
109 | DBG_PRINT("Closing display '%s'", display->name); | ||
110 | |||
111 | display->reference_count--; | ||
112 | for (i = 0; i < display->overlay_managers_count; i++) | ||
113 | omap_dss_put_device(display->overlay_managers[i]->device); | ||
114 | |||
115 | if (display->flip_chain) { | ||
116 | err = display->destroy_flip_chain(display); | ||
117 | display->flip_chain = 0; | ||
118 | if (err) | ||
119 | WRN_PRINT("An error happened when destroying flip " | ||
120 | "chain for '%s'", display->name); | ||
121 | } | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int get_max_buffers(struct omap_display_device *display) | ||
127 | { | ||
128 | /* TODO: If TILER is wanted to be used how do you calculate this? */ | ||
129 | int fb_idx; | ||
130 | switch (display->id) { | ||
131 | case OMAP_DISPID_PRIMARY: | ||
132 | fb_idx = 0; | ||
133 | break; | ||
134 | case OMAP_DISPID_SECONDARY: | ||
135 | fb_idx = 1; | ||
136 | break; | ||
137 | case OMAP_DISPID_TERTIARY: | ||
138 | fb_idx = 2; | ||
139 | break; | ||
140 | case OMAP_DISPID_VIRTUAL: | ||
141 | fb_idx = 0; | ||
142 | break; | ||
143 | case OMAP_DISPID_BADSTATE: | ||
144 | default: | ||
145 | ERR_PRINT("Unknown display id %i", display->id); | ||
146 | BUG(); | ||
147 | } | ||
148 | |||
149 | /* Use the framebuffer memory */ | ||
150 | if (fb_idx >= 0 && fb_idx < num_registered_fb) { | ||
151 | struct fb_info *framebuffer = registered_fb[fb_idx]; | ||
152 | unsigned long buffer_size; | ||
153 | |||
154 | /* Single buffer size */ | ||
155 | buffer_size = display->width * display->height * | ||
156 | display->bytes_per_pixel; | ||
157 | /* Page align the buffer size, round up to the page size */ | ||
158 | buffer_size = OMAP_DISP_PAGE_ROUND_UP(buffer_size); | ||
159 | |||
160 | return (int) (framebuffer->fix.smem_len / buffer_size); | ||
161 | } else { | ||
162 | ERR_PRINT("Framebuffer %i doesn't exist for display '%s'", | ||
163 | fb_idx, display->name); | ||
164 | return 0; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | static int create_flip_chain(struct omap_display_device *display, | ||
169 | unsigned int buffer_count) | ||
170 | { | ||
171 | int fb_idx; | ||
172 | |||
173 | /* TODO: What about TILER buffers */ | ||
174 | if (buffer_count <= 1) { | ||
175 | ERR_PRINT("Flip chains with %i buffers not supported", | ||
176 | buffer_count); | ||
177 | return 1; | ||
178 | } else if (buffer_count > display->buffers_available) { | ||
179 | ERR_PRINT("Requesting %i buffers when there is %i available" | ||
180 | " for '%s'", buffer_count, display->buffers_available, | ||
181 | display->name); | ||
182 | return 1; | ||
183 | } else if (display->flip_chain) { | ||
184 | ERR_PRINT("Flip chain already exists for '%s'", display->name); | ||
185 | return 1; | ||
186 | } | ||
187 | |||
188 | /* Create the flip chain with the framebuffer memory */ | ||
189 | switch (display->id) { | ||
190 | case OMAP_DISPID_PRIMARY: | ||
191 | fb_idx = 0; | ||
192 | break; | ||
193 | case OMAP_DISPID_SECONDARY: | ||
194 | fb_idx = 1; | ||
195 | break; | ||
196 | case OMAP_DISPID_TERTIARY: | ||
197 | fb_idx = 2; | ||
198 | break; | ||
199 | case OMAP_DISPID_VIRTUAL: | ||
200 | fb_idx = 0; | ||
201 | break; | ||
202 | case OMAP_DISPID_BADSTATE: | ||
203 | default: | ||
204 | ERR_PRINT("Unknown display id %i", display->id); | ||
205 | BUG(); | ||
206 | } | ||
207 | |||
208 | /* Use the framebuffer memory */ | ||
209 | if (fb_idx >= 0 && fb_idx < num_registered_fb) { | ||
210 | struct fb_info *framebuffer = registered_fb[fb_idx]; | ||
211 | unsigned long buffer_size; | ||
212 | struct omap_display_flip_chain *flip_chain; | ||
213 | int i; | ||
214 | |||
215 | if (!framebuffer || !framebuffer->fix.smem_start || | ||
216 | !framebuffer->screen_base) { | ||
217 | ERR_PRINT("Framebuffer %i doesn't seem to be " | ||
218 | "initialized", fb_idx); | ||
219 | return 1; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * Check if there is enough memory in the fb for the requested | ||
224 | * buffers | ||
225 | */ | ||
226 | buffer_size = display->width * display->height * | ||
227 | display->bytes_per_pixel; | ||
228 | /* Page align the buffer size, round up to the page size */ | ||
229 | buffer_size = OMAP_DISP_PAGE_ROUND_UP(buffer_size); | ||
230 | |||
231 | if (buffer_size * buffer_count > framebuffer->fix.smem_len) { | ||
232 | ERR_PRINT("Not enough memory to allocate %i buffers " | ||
233 | "(%lu bytes each), memory available %lu for " | ||
234 | "display '%s'", buffer_count, buffer_size, | ||
235 | (unsigned long)framebuffer->fix.smem_len, | ||
236 | display->name); | ||
237 | return 1; | ||
238 | } | ||
239 | |||
240 | flip_chain = kzalloc(sizeof(*flip_chain), GFP_KERNEL); | ||
241 | |||
242 | if (!flip_chain) { | ||
243 | ERR_PRINT("Out of memory"); | ||
244 | return 1; | ||
245 | } | ||
246 | |||
247 | for (i = 0; i < buffer_count; i++) { | ||
248 | struct omap_display_buffer *buffer; | ||
249 | |||
250 | /* | ||
251 | * Reuse the main buffer as the first buffer in the | ||
252 | * flip chain | ||
253 | */ | ||
254 | if (i == 0) { | ||
255 | buffer = display->main_buffer; | ||
256 | flip_chain->buffers[i] = buffer; | ||
257 | DBG_PRINT("Flip chain buffer %i has address " | ||
258 | "%lx for display '%s'", i, | ||
259 | buffer->physical_addr, display->name); | ||
260 | continue; | ||
261 | } | ||
262 | |||
263 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); | ||
264 | |||
265 | if (!buffer) { | ||
266 | /* | ||
267 | * FIXME: If one buffer allocation fails, | ||
268 | * deallocate flip chain and buffers | ||
269 | */ | ||
270 | ERR_PRINT("Out of memory"); | ||
271 | return 1; | ||
272 | } | ||
273 | |||
274 | buffer->physical_addr = framebuffer->fix.smem_start + | ||
275 | (buffer_size * i); | ||
276 | buffer->virtual_addr = | ||
277 | (unsigned long) framebuffer->screen_base + | ||
278 | (buffer_size * i); | ||
279 | buffer->size = buffer_size; | ||
280 | buffer->display = display; | ||
281 | flip_chain->buffers[i] = buffer; | ||
282 | |||
283 | DBG_PRINT("Flip chain buffer %i has address %lx for" | ||
284 | " display '%s'", i, buffer->physical_addr, | ||
285 | display->name); | ||
286 | } | ||
287 | |||
288 | display->flip_chain = flip_chain; | ||
289 | return 0; | ||
290 | } else { | ||
291 | ERR_PRINT("Framebuffer %i doesn't exist for display '%s'", | ||
292 | fb_idx, display->name); | ||
293 | return 1; | ||
294 | } | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int destroy_flip_chain(struct omap_display_device *display) | ||
300 | { | ||
301 | int i; | ||
302 | int err; | ||
303 | |||
304 | if (!display->flip_chain) { | ||
305 | DBG_PRINT("No flip chain to destroy for '%s'", display->name); | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | for (i = 0; i < display->flip_chain->buffer_count; i++) { | ||
310 | struct omap_display_buffer *buffer = | ||
311 | display->flip_chain->buffers[i]; | ||
312 | /* If buffer is main buffer don't touch it */ | ||
313 | if (display->main_buffer == buffer) | ||
314 | continue; | ||
315 | |||
316 | err = display_destroy_buffer(buffer); | ||
317 | if (err) { | ||
318 | ERR_PRINT("Error destroying buffer in flip chain for" | ||
319 | " '%s'", display->name); | ||
320 | return 1; | ||
321 | } | ||
322 | } | ||
323 | |||
324 | DBG_PRINT("Destroying flip chain for '%s'", display->name); | ||
325 | kfree(display->flip_chain); | ||
326 | display->flip_chain = 0; | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static int rotate_display(struct omap_display_device *display, | ||
332 | unsigned int rotation) | ||
333 | { | ||
334 | ERR_PRINT("Not supported yet"); | ||
335 | return 1; | ||
336 | } | ||
337 | |||
338 | static int display_destroy_buffer(struct omap_display_buffer *buffer) | ||
339 | { | ||
340 | kfree(buffer); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static int present_buffer_virtual(struct omap_display_buffer *buffer) | ||
345 | { | ||
346 | /* | ||
347 | * TODO: Support for ORIENTATION_VERTICAL is in place, | ||
348 | * ORIENTATION_HORIZONTAL is missing | ||
349 | */ | ||
350 | struct omap_display_device *display_virtual = buffer->display; | ||
351 | struct omap_display_device *display_primary; | ||
352 | struct omap_display_device *display_secondary; | ||
353 | struct omap_display_buffer temp_buffer; | ||
354 | unsigned int buffer_offset; | ||
355 | |||
356 | if (display_virtual->id != OMAP_DISPID_VIRTUAL) { | ||
357 | ERR_PRINT("Not a virtual display"); | ||
358 | BUG(); | ||
359 | } | ||
360 | |||
361 | display_primary = omap_display_get(OMAP_DISPID_PRIMARY); | ||
362 | display_secondary = omap_display_get(OMAP_DISPID_SECONDARY); | ||
363 | /* | ||
364 | * Calculate offset without page alignment round up otherwise second | ||
365 | * display may see incorrect data | ||
366 | */ | ||
367 | buffer_offset = display_primary->height * display_virtual->byte_stride; | ||
368 | |||
369 | /* The first buffer will be the base */ | ||
370 | temp_buffer.physical_addr = buffer->physical_addr; | ||
371 | temp_buffer.virtual_addr = buffer->virtual_addr; | ||
372 | temp_buffer.size = buffer->size >> 1; | ||
373 | |||
374 | if (display_virtual->features & ORIENTATION_INVERT) { | ||
375 | /* Secondary display has the base */ | ||
376 | temp_buffer.display = display_secondary; | ||
377 | display_secondary->present_buffer(&temp_buffer); | ||
378 | } else { | ||
379 | /* Primary display has the base */ | ||
380 | temp_buffer.display = display_primary; | ||
381 | display_primary->present_buffer(&temp_buffer); | ||
382 | } | ||
383 | |||
384 | /* Remaining display will show the rest */ | ||
385 | temp_buffer.physical_addr = buffer->physical_addr + buffer_offset; | ||
386 | temp_buffer.virtual_addr = buffer->virtual_addr + buffer_offset; | ||
387 | |||
388 | if (display_virtual->features & ORIENTATION_INVERT) { | ||
389 | temp_buffer.display = display_primary; | ||
390 | display_primary->present_buffer(&temp_buffer); | ||
391 | } else { | ||
392 | temp_buffer.display = display_secondary; | ||
393 | display_secondary->present_buffer(&temp_buffer); | ||
394 | } | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static int present_buffer(struct omap_display_buffer *buffer) | ||
400 | { | ||
401 | struct omap_display_device *display = buffer->display; | ||
402 | int fb_idx; | ||
403 | |||
404 | switch (display->id) { | ||
405 | case OMAP_DISPID_PRIMARY: | ||
406 | fb_idx = 0; | ||
407 | break; | ||
408 | case OMAP_DISPID_SECONDARY: | ||
409 | fb_idx = 1; | ||
410 | break; | ||
411 | case OMAP_DISPID_TERTIARY: | ||
412 | fb_idx = 2; | ||
413 | break; | ||
414 | case OMAP_DISPID_VIRTUAL: | ||
415 | case OMAP_DISPID_BADSTATE: | ||
416 | default: | ||
417 | ERR_PRINT("Unable to handle display %i", display->id); | ||
418 | BUG(); | ||
419 | } | ||
420 | |||
421 | if (fb_idx >= 0 && fb_idx < num_registered_fb) { | ||
422 | struct fb_info *framebuffer = registered_fb[fb_idx]; | ||
423 | struct omapfb_info *ofbi = FB2OFB(framebuffer); | ||
424 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
425 | struct omap_overlay *overlay; | ||
426 | struct omap_overlay_info overlay_info; | ||
427 | int i; | ||
428 | |||
429 | omapfb_lock(fbdev); | ||
430 | |||
431 | /* Get the overlays attached to the framebuffer */ | ||
432 | for (i = 0; i < ofbi->num_overlays ; i++) { | ||
433 | overlay = ofbi->overlays[i]; | ||
434 | overlay->get_overlay_info(overlay, &overlay_info); | ||
435 | |||
436 | /* If the overlay is not enabled don't update it */ | ||
437 | if (!overlay_info.enabled) | ||
438 | continue; | ||
439 | |||
440 | overlay_info.paddr = buffer->physical_addr; | ||
441 | overlay_info.vaddr = (void *) buffer->virtual_addr; | ||
442 | overlay->set_overlay_info(overlay, &overlay_info); | ||
443 | |||
444 | if (overlay->manager) { | ||
445 | overlay->manager->apply(overlay->manager); | ||
446 | if (overlay->manager->device && | ||
447 | overlay->manager->device->update) { | ||
448 | overlay->manager->device->update( | ||
449 | overlay->manager->device, | ||
450 | 0, 0, | ||
451 | overlay_info.width, | ||
452 | overlay_info.height); | ||
453 | } | ||
454 | } | ||
455 | } | ||
456 | |||
457 | omapfb_unlock(fbdev); | ||
458 | } else { | ||
459 | ERR_PRINT("Framebuffer %i doesn't exist for display '%s'", | ||
460 | fb_idx, display->name); | ||
461 | return 1; | ||
462 | } | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static u32 get_dss_irq(struct omap_dss_device *dss_device) | ||
468 | { | ||
469 | u32 irq; | ||
470 | |||
471 | if (dss_device->type == OMAP_DISPLAY_TYPE_VENC) | ||
472 | irq = DISPC_IRQ_EVSYNC_ODD; | ||
473 | else if (dss_device->type == OMAP_DISPLAY_TYPE_HDMI) | ||
474 | irq = DISPC_IRQ_EVSYNC_EVEN; | ||
475 | else if (dss_device->type == OMAP_DISPLAY_TYPE_DSI) | ||
476 | if (!strcmp(dss_device->name, "lcd")) | ||
477 | irq = DISPC_IRQ_FRAMEDONE; | ||
478 | else | ||
479 | irq = DISPC_IRQ_FRAMEDONE2; | ||
480 | else | ||
481 | if (!strcmp(dss_device->name, "lcd")) | ||
482 | irq = DISPC_IRQ_VSYNC; | ||
483 | else | ||
484 | irq = DISPC_IRQ_VSYNC2; | ||
485 | |||
486 | return irq; | ||
487 | } | ||
488 | |||
489 | static int present_buffer_sync(struct omap_display_buffer *buffer) | ||
490 | { | ||
491 | /* TODO: Cloning may tear with this implementation */ | ||
492 | int err = 0; | ||
493 | struct omap_display_device *display = buffer->display; | ||
494 | |||
495 | err = display->sync(display); | ||
496 | err |= display->present_buffer(buffer); | ||
497 | |||
498 | return err; | ||
499 | } | ||
500 | |||
501 | static int present_buffer_sync_virtual(struct omap_display_buffer *buffer) | ||
502 | { | ||
503 | void display_irq_wait_1(void *data, u32 mask) | ||
504 | { | ||
505 | struct omap_display_sync_item *sync_item = | ||
506 | (struct omap_display_sync_item *) data; | ||
507 | |||
508 | if (sync_item->invalidate) | ||
509 | return; | ||
510 | |||
511 | /* IRQ happened, present immediately */ | ||
512 | sync_item->invalidate = 1; | ||
513 | sync_item->buffer->display->present_buffer(sync_item->buffer); | ||
514 | complete(sync_item->task); | ||
515 | } | ||
516 | |||
517 | void display_irq_wait_2(void *data, u32 mask) | ||
518 | { | ||
519 | struct omap_display_sync_item *sync_item = | ||
520 | (struct omap_display_sync_item *) data; | ||
521 | |||
522 | if (sync_item->invalidate) | ||
523 | return; | ||
524 | |||
525 | /* IRQ happened, present immediately */ | ||
526 | sync_item->invalidate = 1; | ||
527 | sync_item->buffer->display->present_buffer(sync_item->buffer); | ||
528 | complete(sync_item->task); | ||
529 | } | ||
530 | |||
531 | /* | ||
532 | * TODO: Support for ORIENTATION_VERTICAL is in place, | ||
533 | * ORIENTATION_HORIZONTAL is missing. Some code can be reduced here, | ||
534 | * it will be simplified in the future. | ||
535 | */ | ||
536 | struct omap_display_device *display_virtual = buffer->display; | ||
537 | struct omap_display_device *display_primary; | ||
538 | struct omap_display_device *display_secondary; | ||
539 | struct omap_display_buffer temp_buffer_top; | ||
540 | struct omap_display_buffer temp_buffer_bottom; | ||
541 | struct omap_display_sync_item sync_item_primary; | ||
542 | struct omap_display_sync_item sync_item_secondary; | ||
543 | DECLARE_COMPLETION_ONSTACK(completion_primary); | ||
544 | DECLARE_COMPLETION_ONSTACK(completion_secondary); | ||
545 | unsigned int buffer_offset; | ||
546 | |||
547 | if (display_virtual->id != OMAP_DISPID_VIRTUAL) { | ||
548 | ERR_PRINT("Not a virtual display"); | ||
549 | BUG(); | ||
550 | } | ||
551 | |||
552 | display_primary = omap_display_get(OMAP_DISPID_PRIMARY); | ||
553 | display_secondary = omap_display_get(OMAP_DISPID_SECONDARY); | ||
554 | /* | ||
555 | * Calculate offset without page alignment round up otherwise second | ||
556 | * display may see incorrect data | ||
557 | */ | ||
558 | buffer_offset = display_primary->height * display_virtual->byte_stride; | ||
559 | |||
560 | /* The first buffer will be the top */ | ||
561 | temp_buffer_top.physical_addr = buffer->physical_addr; | ||
562 | temp_buffer_top.virtual_addr = buffer->virtual_addr; | ||
563 | temp_buffer_top.size = buffer->size >> 1; | ||
564 | /* Then the bottom */ | ||
565 | temp_buffer_bottom.physical_addr = buffer->physical_addr + | ||
566 | buffer_offset; | ||
567 | temp_buffer_bottom.virtual_addr = buffer->virtual_addr + buffer_offset; | ||
568 | temp_buffer_bottom.size = buffer->size >> 1; | ||
569 | |||
570 | if (display_virtual->features & ORIENTATION_INVERT) { | ||
571 | /* Secondary display has the base */ | ||
572 | temp_buffer_top.display = display_secondary; | ||
573 | temp_buffer_bottom.display = display_primary; | ||
574 | sync_item_primary.buffer = &temp_buffer_bottom; | ||
575 | sync_item_secondary.buffer = &temp_buffer_top; | ||
576 | |||
577 | } else { | ||
578 | /* Primary display has the base */ | ||
579 | temp_buffer_top.display = display_primary; | ||
580 | temp_buffer_bottom.display = display_secondary; | ||
581 | sync_item_primary.buffer = &temp_buffer_top; | ||
582 | sync_item_secondary.buffer = &temp_buffer_bottom; | ||
583 | } | ||
584 | |||
585 | sync_item_primary.task = &completion_primary; | ||
586 | sync_item_secondary.task = &completion_secondary; | ||
587 | sync_item_primary.invalidate = 0; | ||
588 | sync_item_secondary.invalidate = 0; | ||
589 | |||
590 | /* Register an ISR per display with its corresponding IRQ */ | ||
591 | omap_dispc_register_isr(display_irq_wait_1, &sync_item_primary, | ||
592 | get_dss_irq(display_primary->overlay_managers[0]->device)); | ||
593 | |||
594 | omap_dispc_register_isr(display_irq_wait_2, &sync_item_secondary, | ||
595 | get_dss_irq(display_secondary->overlay_managers[0]->device)); | ||
596 | |||
597 | /* Wait until each display sync and present */ | ||
598 | wait_for_completion_interruptible_timeout(&completion_primary, | ||
599 | OMAP_DISP_IRQ_TIMEOUT); | ||
600 | wait_for_completion_interruptible_timeout(&completion_secondary, | ||
601 | OMAP_DISP_IRQ_TIMEOUT); | ||
602 | |||
603 | /* Unregister ISRs */ | ||
604 | omap_dispc_unregister_isr(display_irq_wait_1, &sync_item_primary, | ||
605 | get_dss_irq(display_primary->overlay_managers[0]->device)); | ||
606 | |||
607 | omap_dispc_unregister_isr(display_irq_wait_2, &sync_item_secondary, | ||
608 | get_dss_irq(display_secondary->overlay_managers[0]->device)); | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | static int display_sync(struct omap_display_device *display) | ||
614 | { | ||
615 | /* TODO: Synchronize properly with multiple managers */ | ||
616 | struct omap_dss_device *dss_device = | ||
617 | display->overlay_managers[0]->device; | ||
618 | if (!dss_device || !dss_device->wait_vsync) { | ||
619 | ERR_PRINT("Unable to synchronize with '%s'", display->name); | ||
620 | return 1; | ||
621 | } | ||
622 | dss_device->wait_vsync(dss_device); | ||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | static int display_sync_virtual(struct omap_display_device *display_virtual) | ||
627 | { | ||
628 | void display_irq_wait(void *data, u32 mask) | ||
629 | { | ||
630 | complete((struct completion *)data); | ||
631 | } | ||
632 | |||
633 | /* | ||
634 | * Return as soon as one display generates an IRQ | ||
635 | */ | ||
636 | struct omap_display_device *display_primary; | ||
637 | struct omap_display_device *display_secondary; | ||
638 | u32 irq_primary; | ||
639 | u32 irq_secondary; | ||
640 | u32 irq_mask; | ||
641 | DECLARE_COMPLETION_ONSTACK(completion); | ||
642 | |||
643 | if (display_virtual->id != OMAP_DISPID_VIRTUAL) { | ||
644 | ERR_PRINT("Not a virtual display"); | ||
645 | BUG(); | ||
646 | } | ||
647 | |||
648 | display_primary = omap_display_get(OMAP_DISPID_PRIMARY); | ||
649 | display_secondary = omap_display_get(OMAP_DISPID_SECONDARY); | ||
650 | |||
651 | irq_primary = get_dss_irq( | ||
652 | display_primary->overlay_managers[0]->device); | ||
653 | |||
654 | irq_secondary = get_dss_irq( | ||
655 | display_secondary->overlay_managers[0]->device); | ||
656 | |||
657 | irq_mask = irq_primary | irq_secondary; | ||
658 | |||
659 | /* Register an ISR with both IRQs and wait, then unregister */ | ||
660 | omap_dispc_register_isr(display_irq_wait, &completion, irq_mask); | ||
661 | |||
662 | wait_for_completion_interruptible_timeout(&completion, | ||
663 | OMAP_DISP_IRQ_TIMEOUT); | ||
664 | |||
665 | omap_dispc_unregister_isr(display_irq_wait, &completion, irq_mask); | ||
666 | |||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | static struct omap_display_buffer *create_main_buffer( | ||
671 | struct omap_display_device *display) | ||
672 | { | ||
673 | int fb_idx; | ||
674 | switch (display->id) { | ||
675 | case OMAP_DISPID_PRIMARY: | ||
676 | fb_idx = 0; | ||
677 | break; | ||
678 | case OMAP_DISPID_SECONDARY: | ||
679 | fb_idx = 1; | ||
680 | break; | ||
681 | case OMAP_DISPID_TERTIARY: | ||
682 | fb_idx = 2; | ||
683 | break; | ||
684 | case OMAP_DISPID_VIRTUAL: | ||
685 | /* Use fb0 for virtual display */ | ||
686 | fb_idx = 0; | ||
687 | break; | ||
688 | case OMAP_DISPID_BADSTATE: | ||
689 | default: | ||
690 | ERR_PRINT("Unknown display id %i", display->id); | ||
691 | BUG(); | ||
692 | } | ||
693 | |||
694 | /* Use the framebuffer memory */ | ||
695 | if (fb_idx >= 0 && fb_idx < num_registered_fb) { | ||
696 | struct fb_info *framebuffer = registered_fb[fb_idx]; | ||
697 | unsigned long buffer_size; | ||
698 | struct omap_display_buffer *buffer; | ||
699 | |||
700 | if (!framebuffer || !framebuffer->fix.smem_start || | ||
701 | !framebuffer->screen_base) { | ||
702 | ERR_PRINT("Framebuffer %i doesn't seem to be " | ||
703 | "initialized", fb_idx); | ||
704 | return NULL; | ||
705 | } | ||
706 | |||
707 | /* | ||
708 | * Check if there is enough memory in the fb for the | ||
709 | * main buffer | ||
710 | */ | ||
711 | buffer_size = display->width * display->height * | ||
712 | display->bytes_per_pixel; | ||
713 | /* Page align the buffer size */ | ||
714 | buffer_size = OMAP_DISP_PAGE_ROUND_UP(buffer_size); | ||
715 | |||
716 | if (buffer_size > framebuffer->fix.smem_len) { | ||
717 | ERR_PRINT("Main buffer needs %lu bytes while the " | ||
718 | "framebuffer %i has only %lu bytes for display" | ||
719 | " '%s'", buffer_size, fb_idx, | ||
720 | (unsigned long)framebuffer->fix.smem_len, | ||
721 | display->name); | ||
722 | return NULL; | ||
723 | } | ||
724 | |||
725 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); | ||
726 | |||
727 | if (!buffer) { | ||
728 | ERR_PRINT("Out of memory"); | ||
729 | return NULL; | ||
730 | } | ||
731 | |||
732 | /* Use base addresses reported by the framebuffer */ | ||
733 | buffer->physical_addr = framebuffer->fix.smem_start; | ||
734 | buffer->virtual_addr = | ||
735 | (unsigned long) framebuffer->screen_base; | ||
736 | buffer->size = buffer_size; | ||
737 | buffer->display = display; | ||
738 | |||
739 | DBG_PRINT("Created main buffer %lx for display '%s'", | ||
740 | buffer->physical_addr, display->name); | ||
741 | |||
742 | return buffer; | ||
743 | } else { | ||
744 | ERR_PRINT("Framebuffer %i doesn't exist for display '%s'", | ||
745 | fb_idx, display->name); | ||
746 | return NULL; | ||
747 | } | ||
748 | } | ||
749 | |||
750 | static int populate_display_info(struct omap_display_device *display, | ||
751 | struct omap_overlay_manager *overlay_manager) | ||
752 | { | ||
753 | struct omap_dss_device *dss_device = overlay_manager->device; | ||
754 | u16 xres; | ||
755 | u16 yres; | ||
756 | int i; | ||
757 | |||
758 | if (!strcmp(dss_device->name, "lcd")) { | ||
759 | display->id = OMAP_DISPID_PRIMARY; | ||
760 | display->name = "primary"; | ||
761 | } else if (!strcmp(dss_device->name, "2lcd")) { | ||
762 | display->id = OMAP_DISPID_SECONDARY; | ||
763 | display->name = "secondary"; | ||
764 | } else if (!strcmp(dss_device->name, "hdmi")) { | ||
765 | display->id = OMAP_DISPID_TERTIARY; | ||
766 | display->name = "tertiary"; | ||
767 | } else { | ||
768 | ERR_PRINT("Display id '%s' not supported", dss_device->name); | ||
769 | return 1; | ||
770 | } | ||
771 | |||
772 | dss_device->get_resolution(dss_device, &xres, &yres); | ||
773 | if (xres == 0 || yres == 0) { | ||
774 | ERR_PRINT("Unable to handle display '%s' with width %i " | ||
775 | "and height %i", dss_device->name, xres, yres); | ||
776 | return 1; | ||
777 | } | ||
778 | |||
779 | display->width = xres; | ||
780 | display->height = yres; | ||
781 | |||
782 | display->bits_per_pixel = dss_device->get_recommended_bpp(dss_device); | ||
783 | switch (display->bits_per_pixel) { | ||
784 | case 16: | ||
785 | /* | ||
786 | * TODO: Asume RGB_565, maybe need to double check in | ||
787 | * the DSS if this is true | ||
788 | */ | ||
789 | display->pixel_format = RGB_565; | ||
790 | display->bytes_per_pixel = 2; | ||
791 | break; | ||
792 | case 24: /* 24 bits are encapsulated with 32 bits */ | ||
793 | case 32: | ||
794 | /* | ||
795 | * TODO: Asume ARGB_8888, maybe need to double check in | ||
796 | * the DSS if this is true | ||
797 | */ | ||
798 | display->pixel_format = ARGB_8888; | ||
799 | display->bytes_per_pixel = 4; | ||
800 | break; | ||
801 | default: | ||
802 | ERR_PRINT("Unable to handle %i bpp", display->bits_per_pixel); | ||
803 | return 1; | ||
804 | } | ||
805 | |||
806 | display->byte_stride = display->bytes_per_pixel * display->width; | ||
807 | display->rotation = OMAP_DSS_ROT_0; /* Asume rotation 0 degrees */ | ||
808 | display->main_buffer = 0; | ||
809 | display->flip_chain = 0; | ||
810 | |||
811 | /* Add the manager to the list */ | ||
812 | for (i = 0; i < OMAP_DISP_MAX_MANAGERS; i++) | ||
813 | display->overlay_managers[i] = 0; | ||
814 | |||
815 | display->overlay_managers[0] = overlay_manager; | ||
816 | display->overlay_managers_count = 1; | ||
817 | |||
818 | /* Assign function pointers for display operations */ | ||
819 | display->open = open_display; | ||
820 | display->close = close_display; | ||
821 | display->create_flip_chain = create_flip_chain; | ||
822 | display->destroy_flip_chain = destroy_flip_chain; | ||
823 | display->rotate = rotate_display; | ||
824 | display->present_buffer = present_buffer; | ||
825 | display->sync = display_sync; | ||
826 | display->present_buffer_sync = present_buffer_sync; | ||
827 | |||
828 | display->main_buffer = create_main_buffer(display); | ||
829 | if (!display->main_buffer) | ||
830 | WRN_PRINT("Failed to create main buffer for '%s'", | ||
831 | display->name); | ||
832 | |||
833 | display->buffers_available = get_max_buffers(display); | ||
834 | |||
835 | /* Just print some display info */ | ||
836 | DBG_PRINT("Found display '%s-%s' (%i,%i) %i bpp (%i bytes per pixel)" | ||
837 | " rotation %i", display->name, dss_device->name, | ||
838 | display->width, display->height, display->bits_per_pixel, | ||
839 | display->bytes_per_pixel, display->rotation); | ||
840 | |||
841 | return 0; | ||
842 | } | ||
843 | |||
844 | static int populate_virtual_display_info(struct omap_display_device *display) | ||
845 | { | ||
846 | struct omap_display_device *display_primary ; | ||
847 | struct omap_display_device *display_secondary; | ||
848 | int i; | ||
849 | |||
850 | display->id = OMAP_DISPID_VIRTUAL; | ||
851 | display->name = "virtual"; | ||
852 | |||
853 | display_primary = omap_display_get(OMAP_DISPID_PRIMARY); | ||
854 | display_secondary = omap_display_get(OMAP_DISPID_SECONDARY); | ||
855 | |||
856 | if (!display_primary) { | ||
857 | ERR_PRINT("Primary display doesn't exist"); | ||
858 | return 1; | ||
859 | } else if (!display_secondary) { | ||
860 | ERR_PRINT("Secondary display doesn't exist"); | ||
861 | return 1; | ||
862 | } | ||
863 | |||
864 | /* Combine primary and secondary display resolutions */ | ||
865 | if (display_primary->width != display_secondary->width || | ||
866 | display_primary->height != display_secondary->height) { | ||
867 | ERR_PRINT("Primary and seconday displays resolution are not" | ||
868 | " the same"); | ||
869 | return 1; | ||
870 | } | ||
871 | |||
872 | /* | ||
873 | * TODO: Here it is hardcoded the resolution asumming a vertical | ||
874 | * virtual config, what about horizontal? | ||
875 | */ | ||
876 | display->width = display_primary->width; | ||
877 | display->height = display_primary->height * 2; | ||
878 | |||
879 | if (display_primary->bits_per_pixel != | ||
880 | display_secondary->bits_per_pixel) { | ||
881 | ERR_PRINT("Primary and seconday displays format are" | ||
882 | " not the same"); | ||
883 | return 1; | ||
884 | } | ||
885 | |||
886 | display->bits_per_pixel = display_primary->bits_per_pixel; | ||
887 | switch (display->bits_per_pixel) { | ||
888 | case 16: | ||
889 | /* | ||
890 | * TODO: Asume RGB_565, maybe need to double check in | ||
891 | * the DSS if this is true | ||
892 | */ | ||
893 | display->pixel_format = RGB_565; | ||
894 | display->bytes_per_pixel = 2; | ||
895 | break; | ||
896 | case 24: /* 24 bits are encapsulated with 32 bits */ | ||
897 | case 32: | ||
898 | /* | ||
899 | * TODO: Asume ARGB_8888, maybe need to double check in | ||
900 | * the DSS if this is true | ||
901 | */ | ||
902 | display->pixel_format = ARGB_8888; | ||
903 | display->bytes_per_pixel = 4; | ||
904 | break; | ||
905 | default: | ||
906 | ERR_PRINT("Unable to handle %i bpp", | ||
907 | display->bits_per_pixel); | ||
908 | return 1; | ||
909 | } | ||
910 | |||
911 | /* TODO: Asumming a vertical virtual config too for stride */ | ||
912 | display->byte_stride = display->bytes_per_pixel * display->width; | ||
913 | display->rotation = OMAP_DSS_ROT_0; /* Asume rotation 0 degrees */ | ||
914 | display->main_buffer = 0; | ||
915 | display->flip_chain = 0; | ||
916 | |||
917 | /* Add the primary and secondary overlay managers */ | ||
918 | for (i = 0; i < OMAP_DISP_MAX_MANAGERS; i++) | ||
919 | display->overlay_managers[i] = 0; | ||
920 | |||
921 | display->overlay_managers[0] = display_primary->overlay_managers[0]; | ||
922 | display->overlay_managers[1] = display_secondary->overlay_managers[0]; | ||
923 | display->overlay_managers_count = 2; | ||
924 | |||
925 | /* Assign function pointers for display operations */ | ||
926 | display->open = open_display; | ||
927 | display->close = close_display; | ||
928 | display->create_flip_chain = create_flip_chain; | ||
929 | display->destroy_flip_chain = destroy_flip_chain; | ||
930 | display->rotate = rotate_display; | ||
931 | display->present_buffer = present_buffer_virtual; | ||
932 | display->sync = display_sync_virtual; | ||
933 | display->present_buffer_sync = present_buffer_sync_virtual; | ||
934 | |||
935 | display->main_buffer = create_main_buffer(display); | ||
936 | if (!display->main_buffer) | ||
937 | WRN_PRINT("Failed to create main buffer for '%s'", | ||
938 | display->name); | ||
939 | |||
940 | display->buffers_available = get_max_buffers(display); | ||
941 | |||
942 | /* Just print some display info */ | ||
943 | DBG_PRINT("Found display '%s' (%i,%i) %i bpp (%i bytes per pixel)" | ||
944 | " rotation %i", display->name, display->width, display->height, | ||
945 | display->bits_per_pixel, display->bytes_per_pixel, | ||
946 | display->rotation); | ||
947 | |||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | static int create_display_list(void) | ||
952 | { | ||
953 | int i; | ||
954 | unsigned int bytes_to_alloc; | ||
955 | struct omap_display_device *display; | ||
956 | |||
957 | /* Query number of possible displays available first */ | ||
958 | omap_display_number = omap_dss_get_num_overlay_managers(); | ||
959 | /* For virtual display */ | ||
960 | omap_display_number++; | ||
961 | |||
962 | /* Allocate custom display list */ | ||
963 | omap_display_list = kzalloc( | ||
964 | sizeof(*display) * omap_display_number, GFP_KERNEL); | ||
965 | |||
966 | if (!omap_display_list) { | ||
967 | ERR_PRINT("Out of memory"); | ||
968 | return 1; | ||
969 | } | ||
970 | |||
971 | /* Populate each display info */ | ||
972 | for (i = 0; i < omap_display_number - 1; i++) { | ||
973 | struct omap_overlay_manager *overlay_manager = | ||
974 | omap_dss_get_overlay_manager(i); | ||
975 | display = &omap_display_list[i]; | ||
976 | if (!overlay_manager->device) { | ||
977 | WRN_PRINT("Display '%s' doesn't have a dss device " | ||
978 | "attached to it, ignoring", | ||
979 | overlay_manager->name); | ||
980 | display->id = OMAP_DISPID_BADSTATE; | ||
981 | continue; | ||
982 | } | ||
983 | if (populate_display_info(display, overlay_manager)) { | ||
984 | ERR_PRINT("Error populating display %i info with " | ||
985 | "manager '%s'", i, | ||
986 | overlay_manager->device->name); | ||
987 | display->id = OMAP_DISPID_BADSTATE; | ||
988 | continue; | ||
989 | } | ||
990 | } | ||
991 | |||
992 | /* Populate virtual display */ | ||
993 | display = &omap_display_list[omap_display_number - 1]; | ||
994 | if (populate_virtual_display_info(display)) { | ||
995 | ERR_PRINT("Error populating virtual display info"); | ||
996 | display->id = OMAP_DISPID_BADSTATE; | ||
997 | } | ||
998 | |||
999 | return 0; | ||
1000 | } | ||
1001 | |||
1002 | struct omap_display_device *omap_display_get(enum omap_display_id id) | ||
1003 | { | ||
1004 | int i; | ||
1005 | struct omap_display_device *display; | ||
1006 | |||
1007 | if (id == OMAP_DISPID_BADSTATE) { | ||
1008 | ERR_PRINT("Oops.. user must never request a bad display"); | ||
1009 | BUG(); | ||
1010 | } | ||
1011 | |||
1012 | for (i = 0; i < omap_display_number; i++) { | ||
1013 | display = &omap_display_list[i]; | ||
1014 | if (display->id == id) | ||
1015 | return display; | ||
1016 | } | ||
1017 | |||
1018 | ERR_PRINT("Unknown display %i requested", id); | ||
1019 | return 0; | ||
1020 | } | ||
1021 | EXPORT_SYMBOL(omap_display_get); | ||
1022 | |||
1023 | int omap_display_count(void) | ||
1024 | { | ||
1025 | return omap_display_number; | ||
1026 | } | ||
1027 | EXPORT_SYMBOL(omap_display_count); | ||
1028 | |||
1029 | int omap_display_init(void) | ||
1030 | { | ||
1031 | /* | ||
1032 | * TODO: Is there a better way to check if list is already created? | ||
1033 | */ | ||
1034 | if (!omap_display_list) { | ||
1035 | DBG_PRINT("Initializing driver"); | ||
1036 | if (create_display_list()) { | ||
1037 | ERR_PRINT("Error loading driver"); | ||
1038 | return 1; | ||
1039 | } | ||
1040 | } | ||
1041 | return 0; | ||
1042 | } | ||
1043 | EXPORT_SYMBOL(omap_display_init); | ||
1044 | |||
1045 | int omap_display_deinit(void) | ||
1046 | { | ||
1047 | int i; | ||
1048 | int err = 0; | ||
1049 | DBG_PRINT("Driver exiting"); | ||
1050 | |||
1051 | for (i = 0; i < omap_display_number; i++) { | ||
1052 | struct omap_display_device *display = &omap_display_list[i]; | ||
1053 | |||
1054 | if (!display) | ||
1055 | continue; | ||
1056 | |||
1057 | if (display->main_buffer) { | ||
1058 | err = display_destroy_buffer(display->main_buffer); | ||
1059 | display->main_buffer = 0; | ||
1060 | if (err) | ||
1061 | WRN_PRINT("An error happened when destroying " | ||
1062 | "main buffer for '%s'", display->name); | ||
1063 | } | ||
1064 | |||
1065 | err = display->close(display); | ||
1066 | |||
1067 | if (err) | ||
1068 | ERR_PRINT("Unable to close display '%s'", | ||
1069 | display->name); | ||
1070 | } | ||
1071 | |||
1072 | kfree(omap_display_list); | ||
1073 | omap_display_list = 0; | ||
1074 | |||
1075 | return err; | ||
1076 | } | ||
1077 | EXPORT_SYMBOL(omap_display_deinit); | ||
1078 | |||
diff --git a/drivers/gpu/pvr/display/omap_display.h b/drivers/gpu/pvr/display/omap_display.h new file mode 100644 index 00000000000..13916a9461f --- /dev/null +++ b/drivers/gpu/pvr/display/omap_display.h | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * drivers/gpu/pvr/display/omap_display.h | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <plat/vrfb.h> | ||
20 | #include <plat/display.h> | ||
21 | #include <linux/completion.h> | ||
22 | |||
23 | #ifndef __OMAP_DISPLAY_H_ | ||
24 | #define __OMAP_DISPLAY_H_ | ||
25 | |||
26 | /* Max overlay managers for virtual display */ | ||
27 | #define OMAP_DISP_MAX_MANAGERS 2 | ||
28 | /* 3 for triple buffering, 4 for virtual display */ | ||
29 | #define OMAP_DISP_MAX_FLIPCHAIN_BUFFERS 4 | ||
30 | #define OMAP_DISP_NUM_DISPLAYS 4 /* lcd, 2lcd, tv, virtual */ | ||
31 | |||
32 | struct omap_display_device; | ||
33 | |||
34 | /* On OMAP 4 we can only manage 3 displays at the same time + virtual */ | ||
35 | enum omap_display_id { | ||
36 | OMAP_DISPID_PRIMARY = 1 << 0, | ||
37 | OMAP_DISPID_SECONDARY = 1 << 1, | ||
38 | OMAP_DISPID_TERTIARY = 1 << 2, | ||
39 | OMAP_DISPID_VIRTUAL = 1 << 15, /* Multiple displays */ | ||
40 | OMAP_DISPID_BADSTATE = 1 << 30, /* Used to say a display is unusable*/ | ||
41 | }; | ||
42 | |||
43 | enum omap_display_pixel_format { | ||
44 | RGB_565 = 0, | ||
45 | ARGB_8888 = 1, | ||
46 | }; | ||
47 | |||
48 | /* Primary display location for virtual display */ | ||
49 | enum omap_display_feature { | ||
50 | ORIENTATION_VERTICAL = 1 << 0, | ||
51 | ORIENTATION_HORIZONTAL = 1 << 1, | ||
52 | ORIENTATION_INVERT = 1 << 2, | ||
53 | }; | ||
54 | |||
55 | struct omap_display_buffer { | ||
56 | unsigned long physical_addr; | ||
57 | unsigned long virtual_addr; | ||
58 | unsigned long size; | ||
59 | struct omap_display_device *display; | ||
60 | }; | ||
61 | |||
62 | struct omap_display_flip_chain { | ||
63 | int buffer_count; | ||
64 | struct omap_display_buffer *buffers[OMAP_DISP_MAX_FLIPCHAIN_BUFFERS]; | ||
65 | struct omap_display_device *display; | ||
66 | }; | ||
67 | |||
68 | struct omap_display_sync_item { | ||
69 | struct omap_display_buffer *buffer; | ||
70 | struct completion *task; | ||
71 | int invalidate; | ||
72 | }; | ||
73 | |||
74 | struct omap_display_device { | ||
75 | char *name; | ||
76 | enum omap_display_id id; | ||
77 | enum omap_display_pixel_format pixel_format; | ||
78 | enum omap_display_feature features; | ||
79 | unsigned int width; | ||
80 | unsigned int height; | ||
81 | unsigned int bits_per_pixel; | ||
82 | unsigned int bytes_per_pixel; | ||
83 | unsigned int byte_stride; | ||
84 | enum omap_dss_rotation_angle rotation; | ||
85 | unsigned int reference_count; | ||
86 | unsigned int buffers_available; | ||
87 | struct omap_display_buffer *main_buffer; | ||
88 | struct omap_display_flip_chain *flip_chain; | ||
89 | struct omap_overlay_manager *overlay_managers[OMAP_DISP_MAX_MANAGERS]; | ||
90 | unsigned int overlay_managers_count; | ||
91 | int (*open)(struct omap_display_device *display, | ||
92 | enum omap_display_feature features); | ||
93 | int (*close) (struct omap_display_device *display); | ||
94 | int (*create_flip_chain) (struct omap_display_device *display, | ||
95 | unsigned int buffer_count); | ||
96 | int (*destroy_flip_chain) (struct omap_display_device *display); | ||
97 | int (*rotate) (struct omap_display_device *display, | ||
98 | enum omap_dss_rotation_angle rotation); | ||
99 | int (*present_buffer) (struct omap_display_buffer *buffer); | ||
100 | int (*sync) (struct omap_display_device *display); | ||
101 | int (*present_buffer_sync) (struct omap_display_buffer *buffer); | ||
102 | }; | ||
103 | |||
104 | int omap_display_init(void); | ||
105 | int omap_display_deinit(void); | ||
106 | int omap_display_count(void); | ||
107 | struct omap_display_device *omap_display_get(enum omap_display_id id); | ||
108 | |||
109 | #endif | ||
diff --git a/drivers/gpu/pvr/display/omap_sgx_displayclass.c b/drivers/gpu/pvr/display/omap_sgx_displayclass.c new file mode 100644 index 00000000000..7b493f1d94e --- /dev/null +++ b/drivers/gpu/pvr/display/omap_sgx_displayclass.c | |||
@@ -0,0 +1,1638 @@ | |||
1 | /************************************************************************* | ||
2 | * | ||
3 | * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful but, except | ||
10 | * as otherwise stated in writing, without any warranty; without even the | ||
11 | * implied warranty of merchantability or fitness for a particular purpose. | ||
12 | * See the GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along | ||
15 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in | ||
19 | * the file called "COPYING". | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * Imagination Technologies Ltd. <gpl-support@imgtec.com> | ||
23 | * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK | ||
24 | * | ||
25 | *************************************************************************/ | ||
26 | |||
27 | #include <linux/version.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/console.h> | ||
30 | |||
31 | #include <linux/module.h> | ||
32 | #include <linux/string.h> | ||
33 | #include <linux/notifier.h> | ||
34 | |||
35 | #if defined(LDM_PLATFORM) | ||
36 | #include <linux/platform_device.h> | ||
37 | #if defined(SGX_EARLYSUSPEND) | ||
38 | #include <linux/earlysuspend.h> | ||
39 | #endif | ||
40 | #endif | ||
41 | |||
42 | #include "img_defs.h" | ||
43 | #include "servicesext.h" | ||
44 | #include "kerneldisplay.h" | ||
45 | #include "omap_sgx_displayclass.h" | ||
46 | #include "omap_display.h" | ||
47 | |||
48 | /* XXX: Expect 2 framebuffers for virtual display */ | ||
49 | #if (CONFIG_FB_OMAP2_NUM_FBS < 2) | ||
50 | #error "Virtual display is supported only with 2 or more framebuffers, \ | ||
51 | CONFIG_FB_OMAP2_NUM_FBS must be equal or greater than 2 \ | ||
52 | see CONFIG_FB_OMAP2_NUM_FBS for details in the kernel config" | ||
53 | #endif | ||
54 | |||
55 | #define OMAP_DC_CMD_COUNT 1 | ||
56 | #define MAX_BUFFERS_FLIPPING 4 | ||
57 | |||
58 | /* Pointer Display->Services */ | ||
59 | static PFN_DC_GET_PVRJTABLE pfnGetPVRJTable = NULL; | ||
60 | |||
61 | /* Pointer to the display devices */ | ||
62 | static struct OMAP_DISP_DEVINFO *pDisplayDevices = NULL; | ||
63 | static int display_devices_count = 0; | ||
64 | |||
65 | static void display_sync_handler(struct work_struct *work); | ||
66 | static enum OMAP_ERROR get_pvr_dc_jtable (char *szFunctionName, | ||
67 | PFN_DC_GET_PVRJTABLE *ppfnFuncTable); | ||
68 | |||
69 | |||
70 | /* | ||
71 | * Swap to display buffer. This buffer refers to one inside the | ||
72 | * framebuffer memory. | ||
73 | * in: hDevice, hBuffer, ui32SwapInterval, hPrivateTag, ui32ClipRectCount, | ||
74 | * psClipRect | ||
75 | */ | ||
76 | static PVRSRV_ERROR SwapToDCBuffer(IMG_HANDLE hDevice, | ||
77 | IMG_HANDLE hBuffer, | ||
78 | IMG_UINT32 ui32SwapInterval, | ||
79 | IMG_HANDLE hPrivateTag, | ||
80 | IMG_UINT32 ui32ClipRectCount, | ||
81 | IMG_RECT *psClipRect) | ||
82 | { | ||
83 | /* Nothing to do */ | ||
84 | return PVRSRV_OK; | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * Set display destination rectangle. | ||
89 | * in: hDevice, hSwapChain, psRect | ||
90 | */ | ||
91 | static PVRSRV_ERROR SetDCDstRect(IMG_HANDLE hDevice, | ||
92 | IMG_HANDLE hSwapChain, | ||
93 | IMG_RECT *psRect) | ||
94 | { | ||
95 | /* Nothing to do */ | ||
96 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * Set display source rectangle. | ||
101 | * in: hDevice, hSwapChain, psRect | ||
102 | */ | ||
103 | static PVRSRV_ERROR SetDCSrcRect(IMG_HANDLE hDevice, | ||
104 | IMG_HANDLE hSwapChain, | ||
105 | IMG_RECT *psRect) | ||
106 | { | ||
107 | /* Nothing to do */ | ||
108 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * Set display destination colour key. | ||
113 | * in: hDevice, hSwapChain, ui32CKColour | ||
114 | */ | ||
115 | static PVRSRV_ERROR SetDCDstColourKey(IMG_HANDLE hDevice, | ||
116 | IMG_HANDLE hSwapChain, | ||
117 | IMG_UINT32 ui32CKColour) | ||
118 | { | ||
119 | /* Nothing to do */ | ||
120 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * Set display source colour key. | ||
125 | * in: hDevice, hSwapChain, ui32CKColour | ||
126 | */ | ||
127 | static PVRSRV_ERROR SetDCSrcColourKey(IMG_HANDLE hDevice, | ||
128 | IMG_HANDLE hSwapChain, | ||
129 | IMG_UINT32 ui32CKColour) | ||
130 | { | ||
131 | /* Nothing to do */ | ||
132 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * Closes the display. | ||
137 | * in: hDevice | ||
138 | */ | ||
139 | static PVRSRV_ERROR CloseDCDevice(IMG_HANDLE hDevice) | ||
140 | { | ||
141 | struct OMAP_DISP_DEVINFO *psDevInfo = | ||
142 | (struct OMAP_DISP_DEVINFO*) hDevice; | ||
143 | struct omap_display_device *display = psDevInfo->display; | ||
144 | |||
145 | if(display->close(display)) | ||
146 | WARNING_PRINTK("Unable to close properly display '%s'", | ||
147 | display->name); | ||
148 | |||
149 | return PVRSRV_OK; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * Flushes the sync queue present in the specified swap chain. | ||
154 | * in: psSwapChain | ||
155 | */ | ||
156 | static void FlushInternalSyncQueue(struct OMAP_DISP_SWAPCHAIN *psSwapChain) | ||
157 | { | ||
158 | struct OMAP_DISP_DEVINFO *psDevInfo = | ||
159 | (struct OMAP_DISP_DEVINFO*) psSwapChain->pvDevInfo; | ||
160 | struct OMAP_DISP_FLIP_ITEM *psFlipItem; | ||
161 | struct omap_display_device *display = psDevInfo->display; | ||
162 | unsigned long ulMaxIndex; | ||
163 | unsigned long i; | ||
164 | |||
165 | psFlipItem = &psSwapChain->psFlipItems[psSwapChain->ulRemoveIndex]; | ||
166 | ulMaxIndex = psSwapChain->ulBufferCount - 1; | ||
167 | |||
168 | DEBUG_PRINTK("Flushing sync queue on display %lu", | ||
169 | psDevInfo->ulDeviceID); | ||
170 | for(i = 0; i < psSwapChain->ulBufferCount; i++) | ||
171 | { | ||
172 | if (psFlipItem->bValid == OMAP_FALSE) | ||
173 | continue; | ||
174 | |||
175 | DEBUG_PRINTK("Flushing swap buffer index %lu", | ||
176 | psSwapChain->ulRemoveIndex); | ||
177 | |||
178 | /* Flip the buffer if it hasn't been flipped */ | ||
179 | if(psFlipItem->bFlipped == OMAP_FALSE) | ||
180 | { | ||
181 | display->present_buffer(psFlipItem->display_buffer); | ||
182 | } | ||
183 | |||
184 | /* If the command didn't complete, assume it did */ | ||
185 | if(psFlipItem->bCmdCompleted == OMAP_FALSE) | ||
186 | { | ||
187 | DEBUG_PRINTK("Calling command complete for swap " | ||
188 | "buffer index %lu", | ||
189 | psSwapChain->ulRemoveIndex); | ||
190 | psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete( | ||
191 | (IMG_HANDLE)psFlipItem->hCmdComplete, | ||
192 | IMG_TRUE); | ||
193 | } | ||
194 | |||
195 | psSwapChain->ulRemoveIndex++; | ||
196 | if(psSwapChain->ulRemoveIndex > ulMaxIndex) | ||
197 | psSwapChain->ulRemoveIndex = 0; | ||
198 | |||
199 | /* Put the state of the buffer to be used again later */ | ||
200 | psFlipItem->bFlipped = OMAP_FALSE; | ||
201 | psFlipItem->bCmdCompleted = OMAP_FALSE; | ||
202 | psFlipItem->bValid = OMAP_FALSE; | ||
203 | psFlipItem = | ||
204 | &psSwapChain->psFlipItems[psSwapChain->ulRemoveIndex]; | ||
205 | } | ||
206 | |||
207 | psSwapChain->ulInsertIndex = 0; | ||
208 | psSwapChain->ulRemoveIndex = 0; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Sets the flush state of the specified display device | ||
213 | * at the swap chain level without blocking the call. | ||
214 | * in: psDevInfo, bFlushState | ||
215 | */ | ||
216 | static void SetFlushStateInternalNoLock(struct OMAP_DISP_DEVINFO* psDevInfo, | ||
217 | enum OMAP_BOOL bFlushState) | ||
218 | { | ||
219 | struct OMAP_DISP_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain; | ||
220 | |||
221 | /* Nothing to do if there is no swap chain */ | ||
222 | if (psSwapChain == NULL){ | ||
223 | DEBUG_PRINTK("Swap chain is null, nothing to do for" | ||
224 | " display %lu", psDevInfo->ulDeviceID); | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | if (bFlushState) | ||
229 | { | ||
230 | DEBUG_PRINTK("Desired flushState is true for display %lu", | ||
231 | psDevInfo->ulDeviceID); | ||
232 | if (psSwapChain->ulSetFlushStateRefCount == 0) | ||
233 | { | ||
234 | psSwapChain->bFlushCommands = OMAP_TRUE; | ||
235 | FlushInternalSyncQueue(psSwapChain); | ||
236 | } | ||
237 | psSwapChain->ulSetFlushStateRefCount++; | ||
238 | } | ||
239 | else | ||
240 | { | ||
241 | DEBUG_PRINTK("Desired flushState is false for display %lu", | ||
242 | psDevInfo->ulDeviceID); | ||
243 | if (psSwapChain->ulSetFlushStateRefCount != 0) | ||
244 | { | ||
245 | psSwapChain->ulSetFlushStateRefCount--; | ||
246 | if (psSwapChain->ulSetFlushStateRefCount == 0) | ||
247 | { | ||
248 | psSwapChain->bFlushCommands = OMAP_FALSE; | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Sets the flush state of the specified display device | ||
256 | * at device level blocking the call if needed. | ||
257 | * in: psDevInfo, bFlushState | ||
258 | */ | ||
259 | static void SetFlushStateExternal(struct OMAP_DISP_DEVINFO* psDevInfo, | ||
260 | enum OMAP_BOOL bFlushState) | ||
261 | { | ||
262 | DEBUG_PRINTK("Executing for display %lu", | ||
263 | psDevInfo->ulDeviceID); | ||
264 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
265 | if (psDevInfo->bFlushCommands != bFlushState) | ||
266 | { | ||
267 | psDevInfo->bFlushCommands = bFlushState; | ||
268 | SetFlushStateInternalNoLock(psDevInfo, bFlushState); | ||
269 | } | ||
270 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Opens the display. | ||
275 | * in: ui32DeviceID, phDevice | ||
276 | * out: psSystemBufferSyncData | ||
277 | */ | ||
278 | static PVRSRV_ERROR OpenDCDevice(IMG_UINT32 ui32DeviceID, | ||
279 | IMG_HANDLE *phDevice, | ||
280 | PVRSRV_SYNC_DATA* psSystemBufferSyncData) | ||
281 | { | ||
282 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
283 | struct omap_display_device *display; | ||
284 | int i; | ||
285 | |||
286 | psDevInfo = 0; | ||
287 | for(i = 0; i < display_devices_count; i++) | ||
288 | { | ||
289 | if(ui32DeviceID == (&pDisplayDevices[i])->ulDeviceID) | ||
290 | { | ||
291 | psDevInfo = &pDisplayDevices[i]; | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | if(!psDevInfo) | ||
297 | { | ||
298 | WARNING_PRINTK("Unable to identify display device with id %i", | ||
299 | (int)ui32DeviceID); | ||
300 | return OMAP_ERROR_INVALID_DEVICE; | ||
301 | } | ||
302 | |||
303 | psDevInfo->sSystemBuffer.psSyncData = psSystemBufferSyncData; | ||
304 | display = psDevInfo->display; | ||
305 | |||
306 | DEBUG_PRINTK("Opening display %lu '%s'",psDevInfo->ulDeviceID, | ||
307 | display->name); | ||
308 | |||
309 | /* TODO: Explain here why ORIENTATION_VERTICAL is used*/ | ||
310 | if(display->open(display, ORIENTATION_VERTICAL | ORIENTATION_INVERT)) | ||
311 | ERROR_PRINTK("Unable to open properly display '%s'", | ||
312 | psDevInfo->display->name); | ||
313 | |||
314 | display->present_buffer(display->main_buffer); | ||
315 | |||
316 | /* TODO: Turn on display here? */ | ||
317 | |||
318 | *phDevice = (IMG_HANDLE)psDevInfo; | ||
319 | |||
320 | return PVRSRV_OK; | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * Gets the available formats for the display. | ||
325 | * in: hDevice | ||
326 | * out: pui32NumFormats, psFormat | ||
327 | */ | ||
328 | static PVRSRV_ERROR EnumDCFormats(IMG_HANDLE hDevice, | ||
329 | IMG_UINT32 *pui32NumFormats, | ||
330 | DISPLAY_FORMAT *psFormat) | ||
331 | { | ||
332 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
333 | if(!hDevice || !pui32NumFormats) | ||
334 | { | ||
335 | ERROR_PRINTK("Invalid parameters"); | ||
336 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
337 | } | ||
338 | |||
339 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
340 | *pui32NumFormats = 1; | ||
341 | |||
342 | if(psFormat) | ||
343 | psFormat[0] = psDevInfo->sDisplayFormat; | ||
344 | else | ||
345 | WARNING_PRINTK("Display format is null for" | ||
346 | " display %lu", psDevInfo->ulDeviceID); | ||
347 | |||
348 | return PVRSRV_OK; | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * Gets the available dimensions for the display. | ||
353 | * in: hDevice, psFormat | ||
354 | * out: pui32NumDims, psDim | ||
355 | */ | ||
356 | static PVRSRV_ERROR EnumDCDims(IMG_HANDLE hDevice, | ||
357 | DISPLAY_FORMAT *psFormat, | ||
358 | IMG_UINT32 *pui32NumDims, | ||
359 | DISPLAY_DIMS *psDim) | ||
360 | { | ||
361 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
362 | if(!hDevice || !psFormat || !pui32NumDims) | ||
363 | { | ||
364 | ERROR_PRINTK("Invalid parameters"); | ||
365 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
366 | } | ||
367 | |||
368 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
369 | *pui32NumDims = 1; | ||
370 | |||
371 | if(psDim) | ||
372 | psDim[0] = psDevInfo->sDisplayDim; | ||
373 | else | ||
374 | WARNING_PRINTK("Display dimensions are null for" | ||
375 | " display %lu", psDevInfo->ulDeviceID); | ||
376 | |||
377 | return PVRSRV_OK; | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * Gets the display framebuffer physical address. | ||
382 | * in: hDevice | ||
383 | * out: phBuffer | ||
384 | */ | ||
385 | static PVRSRV_ERROR GetDCSystemBuffer(IMG_HANDLE hDevice, IMG_HANDLE *phBuffer) | ||
386 | { | ||
387 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
388 | |||
389 | if(!hDevice || !phBuffer) | ||
390 | { | ||
391 | ERROR_PRINTK("Invalid parameters"); | ||
392 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
393 | } | ||
394 | |||
395 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
396 | *phBuffer = (IMG_HANDLE)&psDevInfo->sSystemBuffer; | ||
397 | |||
398 | return PVRSRV_OK; | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * Gets the display general information. | ||
403 | * in: hDevice | ||
404 | * out: psDCInfo | ||
405 | */ | ||
406 | static PVRSRV_ERROR GetDCInfo(IMG_HANDLE hDevice, DISPLAY_INFO *psDCInfo) | ||
407 | { | ||
408 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
409 | |||
410 | if(!hDevice || !psDCInfo) | ||
411 | { | ||
412 | ERROR_PRINTK("Invalid parameters"); | ||
413 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
414 | } | ||
415 | |||
416 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
417 | *psDCInfo = psDevInfo->sDisplayInfo; | ||
418 | |||
419 | return PVRSRV_OK; | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * Gets the display framebuffer virtual address. | ||
424 | * in: hDevice | ||
425 | * out: ppsSysAddr, pui32ByteSize, ppvCpuVAddr, phOSMapInfo, pbIsContiguous | ||
426 | */ | ||
427 | static PVRSRV_ERROR GetDCBufferAddr(IMG_HANDLE hDevice, | ||
428 | IMG_HANDLE hBuffer, | ||
429 | IMG_SYS_PHYADDR **ppsSysAddr, | ||
430 | IMG_UINT32 *pui32ByteSize, | ||
431 | IMG_VOID **ppvCpuVAddr, | ||
432 | IMG_HANDLE *phOSMapInfo, | ||
433 | IMG_BOOL *pbIsContiguous, | ||
434 | IMG_UINT32 *pui32TilingStride) | ||
435 | { | ||
436 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
437 | struct OMAP_DISP_BUFFER *psSystemBuffer; | ||
438 | |||
439 | if(!hDevice || !hBuffer || !ppsSysAddr || !pui32ByteSize ) | ||
440 | { | ||
441 | ERROR_PRINTK("Invalid parameters"); | ||
442 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
443 | } | ||
444 | |||
445 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
446 | psSystemBuffer = (struct OMAP_DISP_BUFFER *)hBuffer; | ||
447 | *ppsSysAddr = &psSystemBuffer->sSysAddr; | ||
448 | *pui32ByteSize = (IMG_UINT32)psDevInfo->sSystemBuffer.ulBufferSize; | ||
449 | |||
450 | if (ppvCpuVAddr) | ||
451 | *ppvCpuVAddr = psSystemBuffer->sCPUVAddr; | ||
452 | |||
453 | if (phOSMapInfo) | ||
454 | *phOSMapInfo = (IMG_HANDLE)0; | ||
455 | |||
456 | if (pbIsContiguous) | ||
457 | *pbIsContiguous = IMG_TRUE; | ||
458 | |||
459 | return PVRSRV_OK; | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * Creates a swap chain. Called when a 3D application begins. | ||
464 | * in: hDevice, ui32Flags, ui32BufferCount, psDstSurfAttrib, psSrcSurfAttrib | ||
465 | * ui32OEMFlags | ||
466 | * out: phSwapChain, ppsSyncData, pui32SwapChainID | ||
467 | */ | ||
468 | static PVRSRV_ERROR CreateDCSwapChain(IMG_HANDLE hDevice, | ||
469 | IMG_UINT32 ui32Flags, | ||
470 | DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib, | ||
471 | DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib, | ||
472 | IMG_UINT32 ui32BufferCount, | ||
473 | PVRSRV_SYNC_DATA **ppsSyncData, | ||
474 | IMG_UINT32 ui32OEMFlags, | ||
475 | IMG_HANDLE *phSwapChain, | ||
476 | IMG_UINT32 *pui32SwapChainID) | ||
477 | { | ||
478 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
479 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
480 | struct OMAP_DISP_BUFFER *psBuffer; | ||
481 | struct OMAP_DISP_FLIP_ITEM *psFlipItems; | ||
482 | IMG_UINT32 i; | ||
483 | PVRSRV_ERROR eError; | ||
484 | IMG_UINT32 ui32BuffersToSkip; | ||
485 | struct omap_display_device *display; | ||
486 | int err; | ||
487 | |||
488 | if(!hDevice || !psDstSurfAttrib || !psSrcSurfAttrib || | ||
489 | !ppsSyncData || !phSwapChain) | ||
490 | { | ||
491 | ERROR_PRINTK("Invalid parameters"); | ||
492 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
493 | } | ||
494 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
495 | |||
496 | if (psDevInfo->sDisplayInfo.ui32MaxSwapChains == 0) | ||
497 | { | ||
498 | ERROR_PRINTK("Unable to operate with 0 MaxSwapChains for" | ||
499 | " display %lu", psDevInfo->ulDeviceID); | ||
500 | return PVRSRV_ERROR_NOT_SUPPORTED; | ||
501 | } | ||
502 | |||
503 | if(psDevInfo->psSwapChain != NULL) | ||
504 | { | ||
505 | ERROR_PRINTK("Swap chain already exists for" | ||
506 | " display %lu", psDevInfo->ulDeviceID); | ||
507 | return PVRSRV_ERROR_FLIP_CHAIN_EXISTS; | ||
508 | } | ||
509 | |||
510 | if(ui32BufferCount > psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers) | ||
511 | { | ||
512 | ERROR_PRINTK("Too many buffers. Trying to use %u buffers while" | ||
513 | " there is only %u available for display %lu", | ||
514 | (unsigned int)ui32BufferCount, | ||
515 | (unsigned int)psDevInfo-> | ||
516 | sDisplayInfo.ui32MaxSwapChainBuffers, | ||
517 | psDevInfo->ulDeviceID); | ||
518 | return PVRSRV_ERROR_TOOMANYBUFFERS; | ||
519 | } | ||
520 | |||
521 | ui32BuffersToSkip = psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers - | ||
522 | ui32BufferCount; | ||
523 | |||
524 | if((psDstSurfAttrib->pixelformat != | ||
525 | psDevInfo->sDisplayFormat.pixelformat) || | ||
526 | (psDstSurfAttrib->sDims.ui32ByteStride != | ||
527 | psDevInfo->sDisplayDim.ui32ByteStride) || | ||
528 | (psDstSurfAttrib->sDims.ui32Width != | ||
529 | psDevInfo->sDisplayDim.ui32Width) || | ||
530 | (psDstSurfAttrib->sDims.ui32Height != | ||
531 | psDevInfo->sDisplayDim.ui32Height)) | ||
532 | { | ||
533 | ERROR_PRINTK("Destination surface attributes differ from the" | ||
534 | " current framebuffer for display %lu", | ||
535 | psDevInfo->ulDeviceID); | ||
536 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
537 | } | ||
538 | |||
539 | if((psDstSurfAttrib->pixelformat != | ||
540 | psSrcSurfAttrib->pixelformat) || | ||
541 | (psDstSurfAttrib->sDims.ui32ByteStride != | ||
542 | psSrcSurfAttrib->sDims.ui32ByteStride) || | ||
543 | (psDstSurfAttrib->sDims.ui32Width != | ||
544 | psSrcSurfAttrib->sDims.ui32Width) || | ||
545 | (psDstSurfAttrib->sDims.ui32Height != | ||
546 | psSrcSurfAttrib->sDims.ui32Height)) | ||
547 | { | ||
548 | ERROR_PRINTK("Destination surface attributes differ from the" | ||
549 | " target destination surface for display %lu", | ||
550 | psDevInfo->ulDeviceID); | ||
551 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
552 | } | ||
553 | |||
554 | /* Create the flip chain in display side */ | ||
555 | display = psDevInfo->display; | ||
556 | /* TODO: What about TILER buffers? */ | ||
557 | /* | ||
558 | * Creating the flip chain with the maximum number of buffers | ||
559 | * we will decide which ones will be used later | ||
560 | */ | ||
561 | err = display->create_flip_chain( | ||
562 | display, psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers); | ||
563 | if(err) | ||
564 | { | ||
565 | ERROR_PRINTK("Unable to create the flip chain for '%s' display" | ||
566 | " id %lu", display->name, psDevInfo->ulDeviceID); | ||
567 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
568 | } | ||
569 | |||
570 | /* Allocate memory needed for the swap chain */ | ||
571 | psSwapChain = (struct OMAP_DISP_SWAPCHAIN*) kmalloc( | ||
572 | sizeof(struct OMAP_DISP_SWAPCHAIN), GFP_KERNEL); | ||
573 | if(!psSwapChain) | ||
574 | { | ||
575 | ERROR_PRINTK("Out of memory to allocate swap chain for" | ||
576 | " display %lu", psDevInfo->ulDeviceID); | ||
577 | return PVRSRV_ERROR_OUT_OF_MEMORY; | ||
578 | } | ||
579 | |||
580 | DEBUG_PRINTK("Creating swap chain for display %lu", | ||
581 | psDevInfo->ulDeviceID ); | ||
582 | |||
583 | /* Allocate memory for the buffer abstraction structures */ | ||
584 | psBuffer = (struct OMAP_DISP_BUFFER*) kmalloc( | ||
585 | sizeof(struct OMAP_DISP_BUFFER) * ui32BufferCount, GFP_KERNEL); | ||
586 | if(!psBuffer) | ||
587 | { | ||
588 | ERROR_PRINTK("Out of memory to allocate the buffer" | ||
589 | " abstraction structures for display %lu", | ||
590 | psDevInfo->ulDeviceID); | ||
591 | eError = PVRSRV_ERROR_OUT_OF_MEMORY; | ||
592 | goto ErrorFreeSwapChain; | ||
593 | } | ||
594 | |||
595 | /* Allocate memory for the flip item abstraction structures */ | ||
596 | psFlipItems = (struct OMAP_DISP_FLIP_ITEM *) kmalloc ( | ||
597 | sizeof(struct OMAP_DISP_FLIP_ITEM) * ui32BufferCount, | ||
598 | GFP_KERNEL); | ||
599 | if (!psFlipItems) | ||
600 | { | ||
601 | ERROR_PRINTK("Out of memory to allocate the flip item" | ||
602 | " abstraction structures for display %lu", | ||
603 | psDevInfo->ulDeviceID); | ||
604 | eError = PVRSRV_ERROR_OUT_OF_MEMORY; | ||
605 | goto ErrorFreeBuffers; | ||
606 | } | ||
607 | |||
608 | /* Assign to the swap chain structure the initial data */ | ||
609 | psSwapChain->ulBufferCount = (unsigned long)ui32BufferCount; | ||
610 | psSwapChain->psBuffer = psBuffer; | ||
611 | psSwapChain->psFlipItems = psFlipItems; | ||
612 | psSwapChain->ulInsertIndex = 0; | ||
613 | psSwapChain->ulRemoveIndex = 0; | ||
614 | psSwapChain->psPVRJTable = &psDevInfo->sPVRJTable; | ||
615 | psSwapChain->pvDevInfo = (void*)psDevInfo; | ||
616 | |||
617 | /* | ||
618 | * Init the workqueue (single thread, freezable and real time) | ||
619 | * and its own work for this display | ||
620 | */ | ||
621 | INIT_WORK(&psDevInfo->sync_display_work, display_sync_handler); | ||
622 | psDevInfo->sync_display_wq = | ||
623 | __create_workqueue("pvr_display_sync_wq", 1, 1, 1); | ||
624 | |||
625 | DEBUG_PRINTK("Swap chain will have %u buffers for display %lu", | ||
626 | (unsigned int)ui32BufferCount, psDevInfo->ulDeviceID); | ||
627 | /* Link the buffers available like a circular list */ | ||
628 | for(i=0; i<ui32BufferCount-1; i++) | ||
629 | { | ||
630 | psBuffer[i].psNext = &psBuffer[i+1]; | ||
631 | } | ||
632 | psBuffer[i].psNext = &psBuffer[0]; | ||
633 | |||
634 | /* Initialize each buffer abstraction structure */ | ||
635 | for(i=0; i<ui32BufferCount; i++) | ||
636 | { | ||
637 | /* Get the needed buffers from the display flip chain */ | ||
638 | IMG_UINT32 ui32SwapBuffer = i + ui32BuffersToSkip; | ||
639 | struct omap_display_buffer * flip_buffer = | ||
640 | display->flip_chain->buffers[ui32SwapBuffer]; | ||
641 | psBuffer[i].display_buffer = flip_buffer; | ||
642 | psBuffer[i].psSyncData = ppsSyncData[i]; | ||
643 | psBuffer[i].sSysAddr.uiAddr = flip_buffer->physical_addr; | ||
644 | psBuffer[i].sCPUVAddr = | ||
645 | (IMG_CPU_VIRTADDR) flip_buffer->virtual_addr; | ||
646 | DEBUG_PRINTK("Display %lu buffer index %u has physical " | ||
647 | "address 0x%x", | ||
648 | psDevInfo->ulDeviceID, | ||
649 | (unsigned int)i, | ||
650 | (unsigned int)psBuffer[i].sSysAddr.uiAddr); | ||
651 | } | ||
652 | |||
653 | /* Initialize each flip item abstraction structure */ | ||
654 | for(i=0; i<ui32BufferCount; i++) | ||
655 | { | ||
656 | psFlipItems[i].bValid = OMAP_FALSE; | ||
657 | psFlipItems[i].bFlipped = OMAP_FALSE; | ||
658 | psFlipItems[i].bCmdCompleted = OMAP_FALSE; | ||
659 | psFlipItems[i].display_buffer = 0; | ||
660 | } | ||
661 | |||
662 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
663 | |||
664 | psDevInfo->psSwapChain = psSwapChain; | ||
665 | psSwapChain->bFlushCommands = psDevInfo->bFlushCommands; | ||
666 | if (psSwapChain->bFlushCommands) | ||
667 | psSwapChain->ulSetFlushStateRefCount = 1; | ||
668 | else | ||
669 | psSwapChain->ulSetFlushStateRefCount = 0; | ||
670 | |||
671 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
672 | |||
673 | *phSwapChain = (IMG_HANDLE)psSwapChain; | ||
674 | |||
675 | return PVRSRV_OK; | ||
676 | |||
677 | ErrorFreeBuffers: | ||
678 | kfree(psBuffer); | ||
679 | ErrorFreeSwapChain: | ||
680 | kfree(psSwapChain); | ||
681 | |||
682 | return eError; | ||
683 | } | ||
684 | |||
685 | /* | ||
686 | * Destroy a swap chain. Called when a 3D application ends. | ||
687 | * in: hDevice, hSwapChain | ||
688 | */ | ||
689 | static PVRSRV_ERROR DestroyDCSwapChain(IMG_HANDLE hDevice, | ||
690 | IMG_HANDLE hSwapChain) | ||
691 | { | ||
692 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
693 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
694 | struct omap_display_device *display; | ||
695 | int err; | ||
696 | |||
697 | if(!hDevice || !hSwapChain) | ||
698 | { | ||
699 | ERROR_PRINTK("Invalid parameters"); | ||
700 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
701 | } | ||
702 | |||
703 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
704 | psSwapChain = (struct OMAP_DISP_SWAPCHAIN*)hSwapChain; | ||
705 | display = psDevInfo->display; | ||
706 | |||
707 | if (psSwapChain != psDevInfo->psSwapChain) | ||
708 | { | ||
709 | ERROR_PRINTK("Swap chain handler differs from the one " | ||
710 | "present in the display device pointer"); | ||
711 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
712 | } | ||
713 | |||
714 | DEBUG_PRINTK("Destroying swap chain for display %lu", | ||
715 | psDevInfo->ulDeviceID); | ||
716 | |||
717 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
718 | |||
719 | FlushInternalSyncQueue(psSwapChain); | ||
720 | psDevInfo->psSwapChain = NULL; | ||
721 | |||
722 | /* | ||
723 | * Present the buffer which is at the base of address of | ||
724 | * the framebuffer | ||
725 | */ | ||
726 | display->present_buffer(display->main_buffer); | ||
727 | |||
728 | /* Destroy the flip chain in display side */ | ||
729 | err = display->destroy_flip_chain(display); | ||
730 | if(err) | ||
731 | { | ||
732 | ERROR_PRINTK("Unable to destroy the flip chain for '%s' " | ||
733 | "display id %lu", display->name, | ||
734 | psDevInfo->ulDeviceID); | ||
735 | } | ||
736 | |||
737 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
738 | |||
739 | /* Destroy the workqueue */ | ||
740 | flush_workqueue(psDevInfo->sync_display_wq); | ||
741 | destroy_workqueue(psDevInfo->sync_display_wq); | ||
742 | |||
743 | kfree(psSwapChain->psFlipItems); | ||
744 | kfree(psSwapChain->psBuffer); | ||
745 | kfree(psSwapChain); | ||
746 | |||
747 | return PVRSRV_OK; | ||
748 | } | ||
749 | |||
750 | |||
751 | /* | ||
752 | * Get display buffers. These are the buffers that can be allocated | ||
753 | * inside the framebuffer memory. | ||
754 | * in: hDevice, hSwapChain | ||
755 | * out: pui32BufferCount, phBuffer | ||
756 | */ | ||
757 | static PVRSRV_ERROR GetDCBuffers(IMG_HANDLE hDevice, | ||
758 | IMG_HANDLE hSwapChain, | ||
759 | IMG_UINT32 *pui32BufferCount, | ||
760 | IMG_HANDLE *phBuffer) | ||
761 | { | ||
762 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
763 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
764 | unsigned long i; | ||
765 | |||
766 | if(!hDevice || !hSwapChain || !pui32BufferCount || !phBuffer) | ||
767 | { | ||
768 | ERROR_PRINTK("Invalid parameters"); | ||
769 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
770 | } | ||
771 | |||
772 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
773 | psSwapChain = (struct OMAP_DISP_SWAPCHAIN*)hSwapChain; | ||
774 | if (psSwapChain != psDevInfo->psSwapChain) | ||
775 | { | ||
776 | ERROR_PRINTK("Swap chain handler differs from the one " | ||
777 | "present in the display device %lu pointer", | ||
778 | psDevInfo->ulDeviceID); | ||
779 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
780 | } | ||
781 | *pui32BufferCount = (IMG_UINT32)psSwapChain->ulBufferCount; | ||
782 | |||
783 | for(i=0; i<psSwapChain->ulBufferCount; i++) | ||
784 | phBuffer[i] = (IMG_HANDLE)&psSwapChain->psBuffer[i]; | ||
785 | |||
786 | return PVRSRV_OK; | ||
787 | } | ||
788 | |||
789 | /* | ||
790 | * Sets the display state. | ||
791 | * in: ui32State, hDevice | ||
792 | */ | ||
793 | static IMG_VOID SetDCState(IMG_HANDLE hDevice, IMG_UINT32 ui32State) | ||
794 | { | ||
795 | struct OMAP_DISP_DEVINFO *psDevInfo = | ||
796 | (struct OMAP_DISP_DEVINFO*) hDevice; | ||
797 | |||
798 | switch (ui32State) | ||
799 | { | ||
800 | case DC_STATE_FLUSH_COMMANDS: | ||
801 | DEBUG_PRINTK("Setting state to flush commands for" | ||
802 | " display %lu", psDevInfo->ulDeviceID); | ||
803 | SetFlushStateExternal(psDevInfo, OMAP_TRUE); | ||
804 | break; | ||
805 | case DC_STATE_NO_FLUSH_COMMANDS: | ||
806 | DEBUG_PRINTK("Setting state to not flush commands for" | ||
807 | " display %lu", psDevInfo->ulDeviceID); | ||
808 | SetFlushStateExternal(psDevInfo, OMAP_FALSE); | ||
809 | break; | ||
810 | default: | ||
811 | WARNING_PRINTK("Unknown command state %u for display" | ||
812 | " %lu", (unsigned int)ui32State, | ||
813 | psDevInfo->ulDeviceID); | ||
814 | break; | ||
815 | } | ||
816 | } | ||
817 | |||
818 | /* | ||
819 | * Swap to display system buffer. This buffer refers to the one which | ||
820 | * is that fits in the framebuffer memory. | ||
821 | * in: hDevice, hSwapChain | ||
822 | */ | ||
823 | static PVRSRV_ERROR SwapToDCSystem(IMG_HANDLE hDevice, | ||
824 | IMG_HANDLE hSwapChain) | ||
825 | { | ||
826 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
827 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
828 | struct omap_display_device *display; | ||
829 | |||
830 | if(!hDevice || !hSwapChain) | ||
831 | { | ||
832 | ERROR_PRINTK("Invalid parameters"); | ||
833 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
834 | } | ||
835 | |||
836 | psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; | ||
837 | psSwapChain = (struct OMAP_DISP_SWAPCHAIN*)hSwapChain; | ||
838 | display = psDevInfo->display; | ||
839 | |||
840 | DEBUG_PRINTK("Executing for display %lu", | ||
841 | psDevInfo->ulDeviceID); | ||
842 | |||
843 | if (psSwapChain != psDevInfo->psSwapChain) | ||
844 | { | ||
845 | ERROR_PRINTK("Swap chain handler differs from the one " | ||
846 | "present in the display device %lu pointer", | ||
847 | psDevInfo->ulDeviceID); | ||
848 | return PVRSRV_ERROR_INVALID_PARAMS; | ||
849 | } | ||
850 | |||
851 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
852 | |||
853 | FlushInternalSyncQueue(psSwapChain); | ||
854 | display->present_buffer(display->main_buffer); | ||
855 | |||
856 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
857 | |||
858 | return PVRSRV_OK; | ||
859 | } | ||
860 | |||
861 | /* | ||
862 | * Handles the synchronization with the display | ||
863 | * in: work | ||
864 | */ | ||
865 | |||
866 | static void display_sync_handler(struct work_struct *work) | ||
867 | { | ||
868 | /* | ||
869 | * TODO: Since present_buffer_sync waits and then present, this | ||
870 | * algorithm can be simplified further | ||
871 | */ | ||
872 | struct OMAP_DISP_DEVINFO *psDevInfo = container_of(work, | ||
873 | struct OMAP_DISP_DEVINFO, sync_display_work); | ||
874 | struct omap_display_device *display = psDevInfo->display; | ||
875 | struct OMAP_DISP_FLIP_ITEM *psFlipItem; | ||
876 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
877 | unsigned long ulMaxIndex; | ||
878 | |||
879 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
880 | |||
881 | psSwapChain = psDevInfo->psSwapChain; | ||
882 | if (!psSwapChain || psSwapChain->bFlushCommands) | ||
883 | goto ExitUnlock; | ||
884 | |||
885 | psFlipItem = &psSwapChain->psFlipItems[psSwapChain->ulRemoveIndex]; | ||
886 | ulMaxIndex = psSwapChain->ulBufferCount - 1; | ||
887 | |||
888 | /* Iterate through the flip items and flip them if necessary */ | ||
889 | while(psFlipItem->bValid) | ||
890 | { | ||
891 | if(psFlipItem->bFlipped) | ||
892 | { | ||
893 | if(!psFlipItem->bCmdCompleted) | ||
894 | { | ||
895 | psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete( | ||
896 | (IMG_HANDLE)psFlipItem->hCmdComplete, | ||
897 | IMG_TRUE); | ||
898 | psFlipItem->bCmdCompleted = OMAP_TRUE; | ||
899 | } | ||
900 | |||
901 | if(psFlipItem->ulSwapInterval == 0) | ||
902 | { | ||
903 | psSwapChain->ulRemoveIndex++; | ||
904 | if(psSwapChain->ulRemoveIndex > ulMaxIndex) | ||
905 | psSwapChain->ulRemoveIndex = 0; | ||
906 | psFlipItem->bCmdCompleted = OMAP_FALSE; | ||
907 | psFlipItem->bFlipped = OMAP_FALSE; | ||
908 | psFlipItem->bValid = OMAP_FALSE; | ||
909 | } | ||
910 | else | ||
911 | { | ||
912 | /* | ||
913 | * Here the swap interval is not zero yet | ||
914 | * we need to schedule another work until | ||
915 | * it reaches zero | ||
916 | */ | ||
917 | display->sync(display); | ||
918 | psFlipItem->ulSwapInterval--; | ||
919 | queue_work(psDevInfo->sync_display_wq, | ||
920 | &psDevInfo->sync_display_work); | ||
921 | goto ExitUnlock; | ||
922 | } | ||
923 | } | ||
924 | else | ||
925 | { | ||
926 | display->present_buffer_sync( | ||
927 | psFlipItem->display_buffer); | ||
928 | /* | ||
929 | * present_buffer_sync waits and then present, then | ||
930 | * swap interval decreases here too. | ||
931 | */ | ||
932 | psFlipItem->ulSwapInterval--; | ||
933 | psFlipItem->bFlipped = OMAP_TRUE; | ||
934 | /* | ||
935 | * If the flip has been presented here then we need | ||
936 | * in the next sync execute the command complete, | ||
937 | * schedule another work | ||
938 | */ | ||
939 | queue_work(psDevInfo->sync_display_wq, | ||
940 | &psDevInfo->sync_display_work); | ||
941 | goto ExitUnlock; | ||
942 | } | ||
943 | psFlipItem = | ||
944 | &psSwapChain->psFlipItems[psSwapChain->ulRemoveIndex]; | ||
945 | } | ||
946 | |||
947 | ExitUnlock: | ||
948 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
949 | } | ||
950 | |||
951 | /* | ||
952 | * Performs a flip. This function takes the necessary steps to present | ||
953 | * the buffer to be flipped in the display. | ||
954 | * in: hCmdCookie, ui32DataSize, pvData | ||
955 | */ | ||
956 | static IMG_BOOL ProcessFlip(IMG_HANDLE hCmdCookie, | ||
957 | IMG_UINT32 ui32DataSize, | ||
958 | IMG_VOID *pvData) | ||
959 | { | ||
960 | DISPLAYCLASS_FLIP_COMMAND *psFlipCmd; | ||
961 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
962 | struct OMAP_DISP_BUFFER *psBuffer; | ||
963 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
964 | struct omap_display_device *display; | ||
965 | #if defined(SYS_USING_INTERRUPTS) | ||
966 | struct OMAP_DISP_FLIP_ITEM* psFlipItem; | ||
967 | #endif | ||
968 | |||
969 | if(!hCmdCookie || !pvData) | ||
970 | { | ||
971 | WARNING_PRINTK("Ignoring call with NULL parameters"); | ||
972 | return IMG_FALSE; | ||
973 | } | ||
974 | |||
975 | psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)pvData; | ||
976 | |||
977 | if (psFlipCmd == IMG_NULL || | ||
978 | sizeof(DISPLAYCLASS_FLIP_COMMAND) != ui32DataSize) | ||
979 | { | ||
980 | WARNING_PRINTK("NULL command or command data size is wrong"); | ||
981 | return IMG_FALSE; | ||
982 | } | ||
983 | |||
984 | psDevInfo = (struct OMAP_DISP_DEVINFO*)psFlipCmd->hExtDevice; | ||
985 | psBuffer = (struct OMAP_DISP_BUFFER*)psFlipCmd->hExtBuffer; | ||
986 | psSwapChain = (struct OMAP_DISP_SWAPCHAIN*) psFlipCmd->hExtSwapChain; | ||
987 | display = psDevInfo->display; | ||
988 | |||
989 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
990 | |||
991 | if (psDevInfo->bDeviceSuspended) | ||
992 | { | ||
993 | /* If is suspended then assume the commands are completed */ | ||
994 | psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete( | ||
995 | hCmdCookie, IMG_TRUE); | ||
996 | goto ExitTrueUnlock; | ||
997 | } | ||
998 | |||
999 | #if defined(SYS_USING_INTERRUPTS) | ||
1000 | |||
1001 | if( psFlipCmd->ui32SwapInterval == 0 || | ||
1002 | psSwapChain->bFlushCommands == OMAP_TRUE) | ||
1003 | { | ||
1004 | #endif | ||
1005 | display->present_buffer(psBuffer->display_buffer); | ||
1006 | psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete( | ||
1007 | hCmdCookie, IMG_TRUE); | ||
1008 | |||
1009 | #if defined(SYS_USING_INTERRUPTS) | ||
1010 | goto ExitTrueUnlock; | ||
1011 | } | ||
1012 | |||
1013 | psFlipItem = &psSwapChain->psFlipItems[psSwapChain->ulInsertIndex]; | ||
1014 | |||
1015 | if(psFlipItem->bValid == OMAP_FALSE) | ||
1016 | { | ||
1017 | unsigned long ulMaxIndex = psSwapChain->ulBufferCount - 1; | ||
1018 | |||
1019 | psFlipItem->bFlipped = OMAP_FALSE; | ||
1020 | |||
1021 | /* | ||
1022 | * The buffer is queued here, must be consumed by the workqueue | ||
1023 | */ | ||
1024 | psFlipItem->hCmdComplete = (OMAP_HANDLE)hCmdCookie; | ||
1025 | psFlipItem->ulSwapInterval = | ||
1026 | (unsigned long)psFlipCmd->ui32SwapInterval; | ||
1027 | psFlipItem->sSysAddr = &psBuffer->sSysAddr; | ||
1028 | psFlipItem->bValid = OMAP_TRUE; | ||
1029 | psFlipItem->display_buffer = psBuffer->display_buffer; | ||
1030 | |||
1031 | psSwapChain->ulInsertIndex++; | ||
1032 | if(psSwapChain->ulInsertIndex > ulMaxIndex) | ||
1033 | psSwapChain->ulInsertIndex = 0; | ||
1034 | |||
1035 | /* Give work to the workqueue to sync with the display */ | ||
1036 | queue_work(psDevInfo->sync_display_wq, | ||
1037 | &psDevInfo->sync_display_work); | ||
1038 | |||
1039 | goto ExitTrueUnlock; | ||
1040 | } | ||
1041 | |||
1042 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
1043 | return IMG_FALSE; | ||
1044 | #endif | ||
1045 | |||
1046 | ExitTrueUnlock: | ||
1047 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
1048 | return IMG_TRUE; | ||
1049 | } | ||
1050 | |||
1051 | #if defined(LDM_PLATFORM) | ||
1052 | |||
1053 | /* | ||
1054 | * Function called when the driver must suspend | ||
1055 | */ | ||
1056 | static void DriverSuspend(void) | ||
1057 | { | ||
1058 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
1059 | int i; | ||
1060 | |||
1061 | if(!pDisplayDevices) | ||
1062 | return; | ||
1063 | |||
1064 | for(i = 0; i < display_devices_count; i++) | ||
1065 | { | ||
1066 | psDevInfo = &pDisplayDevices[i]; | ||
1067 | |||
1068 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
1069 | |||
1070 | if (psDevInfo->bDeviceSuspended) | ||
1071 | { | ||
1072 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
1073 | continue; | ||
1074 | } | ||
1075 | |||
1076 | psDevInfo->bDeviceSuspended = OMAP_TRUE; | ||
1077 | SetFlushStateInternalNoLock(psDevInfo, OMAP_TRUE); | ||
1078 | |||
1079 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
1080 | } | ||
1081 | } | ||
1082 | |||
1083 | /* | ||
1084 | * Function called when the driver must resume | ||
1085 | */ | ||
1086 | static void DriverResume(void) | ||
1087 | { | ||
1088 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
1089 | int i; | ||
1090 | |||
1091 | if(!pDisplayDevices) | ||
1092 | return; | ||
1093 | |||
1094 | for(i = 0; i < display_devices_count; i++) | ||
1095 | { | ||
1096 | psDevInfo = &pDisplayDevices[i]; | ||
1097 | |||
1098 | mutex_lock(&psDevInfo->sSwapChainLockMutex); | ||
1099 | |||
1100 | if (!psDevInfo->bDeviceSuspended) | ||
1101 | { | ||
1102 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
1103 | continue; | ||
1104 | } | ||
1105 | |||
1106 | SetFlushStateInternalNoLock(psDevInfo, OMAP_FALSE); | ||
1107 | psDevInfo->bDeviceSuspended = OMAP_FALSE; | ||
1108 | |||
1109 | mutex_unlock(&psDevInfo->sSwapChainLockMutex); | ||
1110 | } | ||
1111 | } | ||
1112 | #endif /* defined(LDM_PLATFORM) */ | ||
1113 | |||
1114 | /* | ||
1115 | * Frees the kernel framebuffer | ||
1116 | * in: psDevInfo | ||
1117 | */ | ||
1118 | static void deinit_display_device(struct OMAP_DISP_DEVINFO *psDevInfo) | ||
1119 | { | ||
1120 | /* TODO: Are we sure there is nothing to do here? */ | ||
1121 | } | ||
1122 | |||
1123 | /* | ||
1124 | * Deinitialization routine for the 3rd party display driver | ||
1125 | */ | ||
1126 | static enum OMAP_ERROR destroy_display_devices(void) | ||
1127 | { | ||
1128 | struct OMAP_DISP_DEVINFO *psDevInfo; | ||
1129 | PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable; | ||
1130 | int i; | ||
1131 | |||
1132 | DEBUG_PRINTK("Deinitializing 3rd party display driver"); | ||
1133 | |||
1134 | if(!pDisplayDevices) | ||
1135 | return OMAP_OK; | ||
1136 | |||
1137 | for(i = 0; i < display_devices_count; i++) | ||
1138 | { | ||
1139 | psDevInfo = &pDisplayDevices[i]; | ||
1140 | if(!psDevInfo->display) | ||
1141 | continue; | ||
1142 | |||
1143 | /* Remove the ProcessFlip command callback */ | ||
1144 | psJTable = &psDevInfo->sPVRJTable; | ||
1145 | |||
1146 | if(!psJTable) | ||
1147 | continue; | ||
1148 | |||
1149 | if (psDevInfo->sPVRJTable.pfnPVRSRVRemoveCmdProcList( | ||
1150 | psDevInfo->ulDeviceID, | ||
1151 | OMAP_DC_CMD_COUNT) != PVRSRV_OK) | ||
1152 | { | ||
1153 | ERROR_PRINTK("Unable to remove callback for " | ||
1154 | "ProcessFlip command for display %lu", | ||
1155 | psDevInfo->ulDeviceID); | ||
1156 | return OMAP_ERROR_GENERIC; | ||
1157 | } | ||
1158 | |||
1159 | /* Remove the display device from services */ | ||
1160 | if (psJTable->pfnPVRSRVRemoveDCDevice( | ||
1161 | psDevInfo->ulDeviceID) != PVRSRV_OK) | ||
1162 | { | ||
1163 | ERROR_PRINTK("Unable to remove the display %lu " | ||
1164 | "from services", psDevInfo->ulDeviceID); | ||
1165 | return OMAP_ERROR_GENERIC; | ||
1166 | } | ||
1167 | |||
1168 | deinit_display_device(psDevInfo); | ||
1169 | } | ||
1170 | |||
1171 | kfree(pDisplayDevices); | ||
1172 | |||
1173 | return OMAP_OK; | ||
1174 | } | ||
1175 | |||
1176 | /* | ||
1177 | * Extracts the framebuffer data from the kernel driver | ||
1178 | * in: psDevInfo | ||
1179 | */ | ||
1180 | static enum OMAP_ERROR init_display_device(struct OMAP_DISP_DEVINFO *psDevInfo, | ||
1181 | struct omap_display_device *display) | ||
1182 | { | ||
1183 | int buffers_available = display->buffers_available; | ||
1184 | |||
1185 | /* Extract the needed data from the display struct */ | ||
1186 | DEBUG_PRINTK("Display '%s' id %i information:", display->name, | ||
1187 | display->id); | ||
1188 | DEBUG_PRINTK("*Width, height: %u,%u", display->width, | ||
1189 | display->height); | ||
1190 | DEBUG_PRINTK("*Rotation: %u", display->rotation); | ||
1191 | DEBUG_PRINTK("*Stride: %u bytes", display->byte_stride); | ||
1192 | DEBUG_PRINTK("*Buffers available: %u", buffers_available); | ||
1193 | DEBUG_PRINTK("*Bytes per pixel: %u (%u bpp)", | ||
1194 | display->bytes_per_pixel, display->bits_per_pixel); | ||
1195 | |||
1196 | if(display->bits_per_pixel == 16) | ||
1197 | { | ||
1198 | if(display->pixel_format == RGB_565) | ||
1199 | { | ||
1200 | DEBUG_PRINTK("*Format: RGB565"); | ||
1201 | psDevInfo->sDisplayFormat.pixelformat = | ||
1202 | PVRSRV_PIXEL_FORMAT_RGB565; | ||
1203 | } | ||
1204 | else | ||
1205 | WARNING_PRINTK("*Format: Unknown framebuffer" | ||
1206 | "format"); | ||
1207 | } | ||
1208 | else if(display->bits_per_pixel == 24 || | ||
1209 | display->bits_per_pixel == 32) | ||
1210 | { | ||
1211 | if(display->pixel_format == ARGB_8888) | ||
1212 | { | ||
1213 | DEBUG_PRINTK("*Format: ARGB8888"); | ||
1214 | psDevInfo->sDisplayFormat.pixelformat = | ||
1215 | PVRSRV_PIXEL_FORMAT_ARGB8888; | ||
1216 | |||
1217 | } | ||
1218 | else | ||
1219 | WARNING_PRINTK("*Format: Unknown framebuffer" | ||
1220 | "format"); | ||
1221 | } | ||
1222 | else | ||
1223 | WARNING_PRINTK("*Format: Unknown framebuffer format"); | ||
1224 | |||
1225 | if(display->main_buffer) | ||
1226 | { | ||
1227 | DEBUG_PRINTK("*Bytes per buffer: %lu", | ||
1228 | display->main_buffer->size); | ||
1229 | DEBUG_PRINTK("*Main buffer physical address: 0x%lx", | ||
1230 | display->main_buffer->physical_addr); | ||
1231 | DEBUG_PRINTK("*Main buffer virtual address: 0x%lx", | ||
1232 | display->main_buffer->virtual_addr); | ||
1233 | DEBUG_PRINTK("*Main buffer size: %lu bytes", | ||
1234 | display->main_buffer->size); | ||
1235 | } | ||
1236 | else | ||
1237 | { | ||
1238 | psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = 0; | ||
1239 | ERROR_PRINTK("*No main buffer found for display '%s'", | ||
1240 | display->name); | ||
1241 | return OMAP_ERROR_INIT_FAILURE; | ||
1242 | } | ||
1243 | |||
1244 | psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = buffers_available; | ||
1245 | mutex_init(&psDevInfo->sSwapChainLockMutex); | ||
1246 | psDevInfo->psSwapChain = 0; | ||
1247 | psDevInfo->bFlushCommands = OMAP_FALSE; | ||
1248 | psDevInfo->bDeviceSuspended = OMAP_FALSE; | ||
1249 | |||
1250 | if(psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers > 1) | ||
1251 | { | ||
1252 | if(MAX_BUFFERS_FLIPPING == 1) | ||
1253 | { | ||
1254 | DEBUG_PRINTK("Flipping support is possible" | ||
1255 | " but you decided not to use it"); | ||
1256 | } | ||
1257 | |||
1258 | DEBUG_PRINTK("*Flipping support"); | ||
1259 | if(psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers > | ||
1260 | MAX_BUFFERS_FLIPPING) | ||
1261 | psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = | ||
1262 | MAX_BUFFERS_FLIPPING; | ||
1263 | } | ||
1264 | else | ||
1265 | { | ||
1266 | DEBUG_PRINTK("*Flipping not supported"); | ||
1267 | } | ||
1268 | |||
1269 | if (psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers == 0) | ||
1270 | { | ||
1271 | psDevInfo->sDisplayInfo.ui32MaxSwapChains = 0; | ||
1272 | psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 0; | ||
1273 | } | ||
1274 | else | ||
1275 | { | ||
1276 | psDevInfo->sDisplayInfo.ui32MaxSwapChains = 1; | ||
1277 | psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 3; | ||
1278 | } | ||
1279 | psDevInfo->sDisplayInfo.ui32MinSwapInterval = 0; | ||
1280 | |||
1281 | /* Get the display and framebuffer needed info */ | ||
1282 | strncpy(psDevInfo->sDisplayInfo.szDisplayName, | ||
1283 | DISPLAY_DEVICE_NAME, MAX_DISPLAY_NAME_SIZE); | ||
1284 | |||
1285 | psDevInfo->sDisplayDim.ui32Width = display->width; | ||
1286 | psDevInfo->sDisplayDim.ui32Height = display->height; | ||
1287 | psDevInfo->sDisplayDim.ui32ByteStride = display->byte_stride; | ||
1288 | psDevInfo->sSystemBuffer.sSysAddr.uiAddr = | ||
1289 | display->main_buffer->physical_addr; | ||
1290 | psDevInfo->sSystemBuffer.sCPUVAddr = | ||
1291 | (IMG_CPU_VIRTADDR) display->main_buffer->virtual_addr; | ||
1292 | psDevInfo->sSystemBuffer.ulBufferSize = display->main_buffer->size; | ||
1293 | psDevInfo->display = display; | ||
1294 | |||
1295 | return OMAP_OK; | ||
1296 | } | ||
1297 | |||
1298 | /* | ||
1299 | * Initialization routine for the 3rd party display driver | ||
1300 | */ | ||
1301 | static enum OMAP_ERROR create_display_devices(void) | ||
1302 | { | ||
1303 | PFN_CMD_PROC pfnCmdProcList[OMAP_DC_CMD_COUNT]; | ||
1304 | IMG_UINT32 aui32SyncCountList[OMAP_DC_CMD_COUNT][2]; | ||
1305 | int i; | ||
1306 | unsigned int bytes_to_alloc; | ||
1307 | |||
1308 | DEBUG_PRINTK("Initializing 3rd party display driver"); | ||
1309 | |||
1310 | /* Ask for the number of displays available */ | ||
1311 | omap_display_init(); | ||
1312 | /* TODO: allow more displays */ | ||
1313 | display_devices_count = 1; // omap_display_count(); | ||
1314 | |||
1315 | DEBUG_PRINTK("Found %i displays", display_devices_count); | ||
1316 | |||
1317 | /* | ||
1318 | * Obtain the function pointer for the jump table from kernel | ||
1319 | * services to fill it with the function pointers that we want | ||
1320 | */ | ||
1321 | if(get_pvr_dc_jtable ("PVRGetDisplayClassJTable", | ||
1322 | &pfnGetPVRJTable) != OMAP_OK) | ||
1323 | { | ||
1324 | ERROR_PRINTK("Unable to get the function to get the" | ||
1325 | " jump table display->services"); | ||
1326 | return OMAP_ERROR_INIT_FAILURE; | ||
1327 | } | ||
1328 | |||
1329 | /* | ||
1330 | * Allocate the display device structures, one per display available | ||
1331 | */ | ||
1332 | bytes_to_alloc = | ||
1333 | sizeof(struct OMAP_DISP_DEVINFO) * display_devices_count; | ||
1334 | pDisplayDevices = (struct OMAP_DISP_DEVINFO *) kmalloc( | ||
1335 | bytes_to_alloc, GFP_KERNEL); | ||
1336 | if(!pDisplayDevices) | ||
1337 | { | ||
1338 | pDisplayDevices = NULL; | ||
1339 | ERROR_PRINTK("Out of memory"); | ||
1340 | return OMAP_ERROR_OUT_OF_MEMORY; | ||
1341 | } | ||
1342 | memset(pDisplayDevices, 0, bytes_to_alloc); | ||
1343 | |||
1344 | /* | ||
1345 | * Initialize each display device | ||
1346 | */ | ||
1347 | for(i = 0; i < display_devices_count; i++) | ||
1348 | { | ||
1349 | struct omap_display_device *display; | ||
1350 | struct OMAP_DISP_DEVINFO * psDevInfo; | ||
1351 | enum omap_display_id id; | ||
1352 | |||
1353 | psDevInfo = &pDisplayDevices[i]; | ||
1354 | psDevInfo->display = 0; | ||
1355 | |||
1356 | id = OMAP_DISPID_VIRTUAL; | ||
1357 | |||
1358 | /* | ||
1359 | * TODO: Modify this to allow primary, secondary, | ||
1360 | * not only virtual | ||
1361 | */ | ||
1362 | #if 0 | ||
1363 | switch(i) | ||
1364 | { | ||
1365 | case 0: | ||
1366 | id = OMAP_DISPID_PRIMARY; | ||
1367 | break; | ||
1368 | case 1: | ||
1369 | id = OMAP_DISPID_SECONDARY; | ||
1370 | break; | ||
1371 | case 2: | ||
1372 | id = OMAP_DISPID_TERTIARY; | ||
1373 | break; | ||
1374 | case 3: | ||
1375 | id = OMAP_DISPID_VIRTUAL; | ||
1376 | break; | ||
1377 | default: | ||
1378 | ERROR_PRINTK("Invalid display type %i", i); | ||
1379 | BUG(); | ||
1380 | } | ||
1381 | |||
1382 | #endif | ||
1383 | |||
1384 | display = omap_display_get(id); | ||
1385 | if(!display) | ||
1386 | continue; | ||
1387 | |||
1388 | if(init_display_device(psDevInfo, display) != OMAP_OK) | ||
1389 | { | ||
1390 | ERROR_PRINTK("Unable to initialize display '%s' type" | ||
1391 | " %u", display->name, display->id); | ||
1392 | continue; | ||
1393 | #if 0 | ||
1394 | kfree(pDisplayDevices); | ||
1395 | pDisplayDevices = NULL; | ||
1396 | return OMAP_ERROR_INIT_FAILURE; | ||
1397 | #endif | ||
1398 | } | ||
1399 | |||
1400 | /* | ||
1401 | * Populate each display device structure | ||
1402 | */ | ||
1403 | if(!(*pfnGetPVRJTable)(&psDevInfo->sPVRJTable)) | ||
1404 | { | ||
1405 | ERROR_PRINTK("Unable to get the jump table" | ||
1406 | " display->services for display '%s'", | ||
1407 | display->name); | ||
1408 | return OMAP_ERROR_INIT_FAILURE; | ||
1409 | } | ||
1410 | |||
1411 | /* Populate the function table that services will use */ | ||
1412 | psDevInfo->sDCJTable.ui32TableSize = | ||
1413 | sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE); | ||
1414 | psDevInfo->sDCJTable.pfnOpenDCDevice = OpenDCDevice; | ||
1415 | psDevInfo->sDCJTable.pfnCloseDCDevice = CloseDCDevice; | ||
1416 | psDevInfo->sDCJTable.pfnEnumDCFormats = EnumDCFormats; | ||
1417 | psDevInfo->sDCJTable.pfnEnumDCDims = EnumDCDims; | ||
1418 | psDevInfo->sDCJTable.pfnGetDCSystemBuffer = GetDCSystemBuffer; | ||
1419 | psDevInfo->sDCJTable.pfnGetDCInfo = GetDCInfo; | ||
1420 | psDevInfo->sDCJTable.pfnGetBufferAddr = GetDCBufferAddr; | ||
1421 | psDevInfo->sDCJTable.pfnCreateDCSwapChain = CreateDCSwapChain; | ||
1422 | psDevInfo->sDCJTable.pfnDestroyDCSwapChain = | ||
1423 | DestroyDCSwapChain; | ||
1424 | psDevInfo->sDCJTable.pfnSetDCDstRect = SetDCDstRect; | ||
1425 | psDevInfo->sDCJTable.pfnSetDCSrcRect = SetDCSrcRect; | ||
1426 | psDevInfo->sDCJTable.pfnSetDCDstColourKey = SetDCDstColourKey; | ||
1427 | psDevInfo->sDCJTable.pfnSetDCSrcColourKey = SetDCSrcColourKey; | ||
1428 | psDevInfo->sDCJTable.pfnGetDCBuffers = GetDCBuffers; | ||
1429 | psDevInfo->sDCJTable.pfnSwapToDCBuffer = SwapToDCBuffer; | ||
1430 | psDevInfo->sDCJTable.pfnSwapToDCSystem = SwapToDCSystem; | ||
1431 | psDevInfo->sDCJTable.pfnSetDCState = SetDCState; | ||
1432 | |||
1433 | /* Register the display device */ | ||
1434 | if(psDevInfo->sPVRJTable.pfnPVRSRVRegisterDCDevice( | ||
1435 | &psDevInfo->sDCJTable, | ||
1436 | (IMG_UINT32*) &psDevInfo->ulDeviceID) != PVRSRV_OK) | ||
1437 | { | ||
1438 | ERROR_PRINTK("Unable to register the jump table" | ||
1439 | " services->display"); | ||
1440 | return OMAP_ERROR_DEVICE_REGISTER_FAILED; | ||
1441 | } | ||
1442 | |||
1443 | DEBUG_PRINTK("Display '%s' registered with the GPU with" | ||
1444 | " id %lu", display->name, psDevInfo->ulDeviceID); | ||
1445 | |||
1446 | /* | ||
1447 | * Register the ProcessFlip function to notify when a frame is | ||
1448 | * ready to be flipped | ||
1449 | */ | ||
1450 | pfnCmdProcList[DC_FLIP_COMMAND] = ProcessFlip; | ||
1451 | aui32SyncCountList[DC_FLIP_COMMAND][0] = 0; | ||
1452 | aui32SyncCountList[DC_FLIP_COMMAND][1] = 2; | ||
1453 | if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterCmdProcList( | ||
1454 | psDevInfo->ulDeviceID, &pfnCmdProcList[0], | ||
1455 | aui32SyncCountList, OMAP_DC_CMD_COUNT) != PVRSRV_OK) | ||
1456 | { | ||
1457 | ERROR_PRINTK("Unable to register callback for " | ||
1458 | "ProcessFlip command"); | ||
1459 | return OMAP_ERROR_CANT_REGISTER_CALLBACK; | ||
1460 | } | ||
1461 | |||
1462 | } | ||
1463 | return OMAP_OK; | ||
1464 | } | ||
1465 | |||
1466 | /* | ||
1467 | * Here we get the function pointer to get jump table from | ||
1468 | * services using an external function. | ||
1469 | * in: szFunctionName | ||
1470 | * out: ppfnFuncTable | ||
1471 | */ | ||
1472 | static enum OMAP_ERROR get_pvr_dc_jtable (char *szFunctionName, | ||
1473 | PFN_DC_GET_PVRJTABLE *ppfnFuncTable) | ||
1474 | { | ||
1475 | if(strcmp("PVRGetDisplayClassJTable", szFunctionName) != 0) | ||
1476 | { | ||
1477 | ERROR_PRINTK("Unable to get function pointer for %s" | ||
1478 | " from services", szFunctionName); | ||
1479 | return OMAP_ERROR_INVALID_PARAMS; | ||
1480 | } | ||
1481 | *ppfnFuncTable = PVRGetDisplayClassJTable; | ||
1482 | |||
1483 | return OMAP_OK; | ||
1484 | } | ||
1485 | |||
1486 | #if defined(LDM_PLATFORM) | ||
1487 | |||
1488 | static volatile enum OMAP_BOOL bDeviceSuspended; | ||
1489 | |||
1490 | /* | ||
1491 | * Common suspend driver function | ||
1492 | * in: psSwapChain, aPhyAddr | ||
1493 | */ | ||
1494 | static void CommonSuspend(void) | ||
1495 | { | ||
1496 | if (bDeviceSuspended) | ||
1497 | { | ||
1498 | DEBUG_PRINTK("Driver is already suspended"); | ||
1499 | return; | ||
1500 | } | ||
1501 | |||
1502 | DriverSuspend(); | ||
1503 | bDeviceSuspended = OMAP_TRUE; | ||
1504 | } | ||
1505 | |||
1506 | #if defined(SGX_EARLYSUSPEND) | ||
1507 | |||
1508 | static struct early_suspend driver_early_suspend; | ||
1509 | |||
1510 | /* | ||
1511 | * Android specific, driver is requested to be suspended | ||
1512 | * in: ea_event | ||
1513 | */ | ||
1514 | static void DriverSuspend_Entry(struct early_suspend *ea_event) | ||
1515 | { | ||
1516 | DEBUG_PRINTK("Requested driver suspend"); | ||
1517 | CommonSuspend(); | ||
1518 | } | ||
1519 | |||
1520 | /* | ||
1521 | * Android specific, driver is requested to be suspended | ||
1522 | * in: ea_event | ||
1523 | */ | ||
1524 | static void DriverResume_Entry(struct early_suspend *ea_event) | ||
1525 | { | ||
1526 | DEBUG_PRINTK("Requested driver resume"); | ||
1527 | DriverResume(); | ||
1528 | bDeviceSuspended = OMAP_FALSE; | ||
1529 | } | ||
1530 | |||
1531 | static struct platform_driver omap_sgx_dc_driver = { | ||
1532 | .driver = { | ||
1533 | .name = DRVNAME, | ||
1534 | } | ||
1535 | }; | ||
1536 | |||
1537 | #else /* defined(SGX_EARLYSUSPEND) */ | ||
1538 | |||
1539 | /* | ||
1540 | * Function called when the driver is requested to be suspended | ||
1541 | * in: pDevice, state | ||
1542 | */ | ||
1543 | static int DriverSuspend_Entry(struct platform_device unref__ *pDevice, | ||
1544 | pm_message_t unref__ state) | ||
1545 | { | ||
1546 | DEBUG_PRINTK("Requested driver suspend"); | ||
1547 | CommonSuspend(); | ||
1548 | return 0; | ||
1549 | } | ||
1550 | |||
1551 | /* | ||
1552 | * Function called when the driver is requested to resume | ||
1553 | * in: pDevice | ||
1554 | */ | ||
1555 | static int DriverResume_Entry(struct platform_device unref__ *pDevice) | ||
1556 | { | ||
1557 | DEBUG_PRINTK("Requested driver resume"); | ||
1558 | DriverResume(); | ||
1559 | bDeviceSuspended = OMAP_FALSE; | ||
1560 | return 0; | ||
1561 | } | ||
1562 | |||
1563 | /* | ||
1564 | * Function called when the driver is requested to shutdown | ||
1565 | * in: pDevice | ||
1566 | */ | ||
1567 | static IMG_VOID DriverShutdown_Entry( | ||
1568 | struct platform_device unref__ *pDevice) | ||
1569 | { | ||
1570 | DEBUG_PRINTK("Requested driver shutdown"); | ||
1571 | CommonSuspend(); | ||
1572 | } | ||
1573 | |||
1574 | static struct platform_driver omap_sgx_dc_driver = { | ||
1575 | .driver = { | ||
1576 | .name = DRVNAME, | ||
1577 | }, | ||
1578 | .suspend = DriverSuspend_Entry, | ||
1579 | .resume = DriverResume_Entry, | ||
1580 | .shutdown = DriverShutdown_Entry, | ||
1581 | }; | ||
1582 | |||
1583 | #endif /* defined(SGX_EARLYSUSPEND) */ | ||
1584 | |||
1585 | #endif /* defined(LDM_PLATFORM) */ | ||
1586 | |||
1587 | /* | ||
1588 | * Driver init function | ||
1589 | */ | ||
1590 | static int __init omap_sgx_dc_init(void) | ||
1591 | { | ||
1592 | if(create_display_devices() != OMAP_OK) | ||
1593 | { | ||
1594 | WARNING_PRINTK("Driver init failed"); | ||
1595 | return -ENODEV; | ||
1596 | } | ||
1597 | |||
1598 | #if defined(LDM_PLATFORM) | ||
1599 | DEBUG_PRINTK("Registering platform driver"); | ||
1600 | if (platform_driver_register(&omap_sgx_dc_driver)) | ||
1601 | { | ||
1602 | WARNING_PRINTK("Unable to register platform driver"); | ||
1603 | if(destroy_display_devices() != OMAP_OK) | ||
1604 | WARNING_PRINTK("Driver cleanup failed\n"); | ||
1605 | return -ENODEV; | ||
1606 | } | ||
1607 | |||
1608 | #if defined(SGX_EARLYSUSPEND) | ||
1609 | driver_early_suspend.suspend = DriverSuspend_Entry; | ||
1610 | driver_early_suspend.resume = DriverResume_Entry; | ||
1611 | driver_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; | ||
1612 | register_early_suspend(&driver_early_suspend); | ||
1613 | DEBUG_PRINTK("Registered early suspend support"); | ||
1614 | #endif | ||
1615 | |||
1616 | #endif | ||
1617 | return 0; | ||
1618 | } | ||
1619 | |||
1620 | /* | ||
1621 | * Driver exit function | ||
1622 | */ | ||
1623 | static IMG_VOID __exit omap_sgx_dc_deinit(IMG_VOID) | ||
1624 | { | ||
1625 | #if defined(LDM_PLATFORM) | ||
1626 | DEBUG_PRINTK("Removing platform driver"); | ||
1627 | platform_driver_unregister(&omap_sgx_dc_driver); | ||
1628 | #if defined(SGX_EARLYSUSPEND) | ||
1629 | unregister_early_suspend(&driver_early_suspend); | ||
1630 | #endif | ||
1631 | #endif | ||
1632 | if(destroy_display_devices() != OMAP_OK) | ||
1633 | WARNING_PRINTK("Driver cleanup failed"); | ||
1634 | } | ||
1635 | |||
1636 | MODULE_SUPPORTED_DEVICE(DEVNAME); | ||
1637 | late_initcall(omap_sgx_dc_init); | ||
1638 | module_exit(omap_sgx_dc_deinit); | ||
diff --git a/drivers/gpu/pvr/display/omap_sgx_displayclass.h b/drivers/gpu/pvr/display/omap_sgx_displayclass.h new file mode 100644 index 00000000000..e97c4addc5a --- /dev/null +++ b/drivers/gpu/pvr/display/omap_sgx_displayclass.h | |||
@@ -0,0 +1,123 @@ | |||
1 | /************************************************************************* | ||
2 | * | ||
3 | * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful but, except | ||
10 | * as otherwise stated in writing, without any warranty; without even the | ||
11 | * implied warranty of merchantability or fitness for a particular purpose. | ||
12 | * See the GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along | ||
15 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in | ||
19 | * the file called "COPYING". | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * Imagination Technologies Ltd. <gpl-support@imgtec.com> | ||
23 | * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK | ||
24 | * | ||
25 | *************************************************************************/ | ||
26 | |||
27 | #ifndef __OMAP_SGX_DISPLAYCLASS_H__ | ||
28 | #define __OMAP_SGX_DISPLAYCLASS_H__ | ||
29 | |||
30 | extern IMG_BOOL PVRGetDisplayClassJTable( | ||
31 | PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable); | ||
32 | |||
33 | typedef void * OMAP_HANDLE; | ||
34 | |||
35 | enum OMAP_BOOL | ||
36 | { | ||
37 | OMAP_FALSE = 0, | ||
38 | OMAP_TRUE = 1, | ||
39 | }; | ||
40 | |||
41 | struct OMAP_DISP_BUFFER | ||
42 | { | ||
43 | unsigned long ulBufferSize; | ||
44 | IMG_SYS_PHYADDR sSysAddr; | ||
45 | IMG_CPU_VIRTADDR sCPUVAddr; | ||
46 | PVRSRV_SYNC_DATA *psSyncData; | ||
47 | struct OMAP_DISP_BUFFER *psNext; | ||
48 | struct omap_display_buffer *display_buffer; | ||
49 | }; | ||
50 | |||
51 | struct OMAP_DISP_FLIP_ITEM | ||
52 | { | ||
53 | OMAP_HANDLE hCmdComplete; | ||
54 | unsigned long ulSwapInterval; | ||
55 | enum OMAP_BOOL bValid; | ||
56 | enum OMAP_BOOL bFlipped; | ||
57 | enum OMAP_BOOL bCmdCompleted; | ||
58 | IMG_SYS_PHYADDR *sSysAddr; | ||
59 | struct omap_display_buffer *display_buffer; | ||
60 | }; | ||
61 | |||
62 | struct OMAP_DISP_SWAPCHAIN | ||
63 | { | ||
64 | unsigned long ulBufferCount; | ||
65 | struct OMAP_DISP_BUFFER *psBuffer; | ||
66 | struct OMAP_DISP_FLIP_ITEM *psFlipItems; | ||
67 | unsigned long ulInsertIndex; | ||
68 | unsigned long ulRemoveIndex; | ||
69 | PVRSRV_DC_DISP2SRV_KMJTABLE *psPVRJTable; | ||
70 | enum OMAP_BOOL bFlushCommands; | ||
71 | unsigned long ulSetFlushStateRefCount; | ||
72 | enum OMAP_BOOL bBlanked; | ||
73 | spinlock_t *psSwapChainLock; | ||
74 | void *pvDevInfo; | ||
75 | }; | ||
76 | |||
77 | struct OMAP_DISP_DEVINFO | ||
78 | { | ||
79 | unsigned long ulDeviceID; | ||
80 | struct OMAP_DISP_BUFFER sSystemBuffer; | ||
81 | PVRSRV_DC_DISP2SRV_KMJTABLE sPVRJTable; | ||
82 | PVRSRV_DC_SRV2DISP_KMJTABLE sDCJTable; | ||
83 | struct OMAP_DISP_SWAPCHAIN *psSwapChain; | ||
84 | enum OMAP_BOOL bFlushCommands; | ||
85 | enum OMAP_BOOL bDeviceSuspended; | ||
86 | struct mutex sSwapChainLockMutex; | ||
87 | IMG_DEV_VIRTADDR sDisplayDevVAddr; | ||
88 | DISPLAY_INFO sDisplayInfo; | ||
89 | DISPLAY_FORMAT sDisplayFormat; | ||
90 | DISPLAY_DIMS sDisplayDim; | ||
91 | struct workqueue_struct *sync_display_wq; | ||
92 | struct work_struct sync_display_work; | ||
93 | PVRSRV_PIXEL_FORMAT ePixelFormat; | ||
94 | struct omap_display_device *display; | ||
95 | }; | ||
96 | |||
97 | enum OMAP_ERROR | ||
98 | { | ||
99 | OMAP_OK = 0, | ||
100 | OMAP_ERROR_GENERIC = 1, | ||
101 | OMAP_ERROR_OUT_OF_MEMORY = 2, | ||
102 | OMAP_ERROR_TOO_FEW_BUFFERS = 3, | ||
103 | OMAP_ERROR_INVALID_PARAMS = 4, | ||
104 | OMAP_ERROR_INIT_FAILURE = 5, | ||
105 | OMAP_ERROR_CANT_REGISTER_CALLBACK = 6, | ||
106 | OMAP_ERROR_INVALID_DEVICE = 7, | ||
107 | OMAP_ERROR_DEVICE_REGISTER_FAILED = 8 | ||
108 | |||
109 | }; | ||
110 | |||
111 | #define DISPLAY_DEVICE_NAME "PowerVR OMAP Display Driver" | ||
112 | #define DRVNAME "omap_sgx_displayclass" | ||
113 | #define DEVNAME DRVNAME | ||
114 | #define DRIVER_PREFIX DRVNAME | ||
115 | |||
116 | #define DEBUG_PRINTK(format, ...) printk("DEBUG " DRIVER_PREFIX \ | ||
117 | " (%s %i): " format "\n", __func__, __LINE__, ## __VA_ARGS__) | ||
118 | #define WARNING_PRINTK(format, ...) printk("WARNING " DRIVER_PREFIX \ | ||
119 | " (%s %i): " format "\n", __func__, __LINE__, ## __VA_ARGS__) | ||
120 | #define ERROR_PRINTK(format, ...) printk("ERROR " DRIVER_PREFIX \ | ||
121 | " (%s %i): " format "\n", __func__, __LINE__, ## __VA_ARGS__) | ||
122 | |||
123 | #endif | ||