aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/pvr/display
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/pvr/display')
-rw-r--r--drivers/gpu/pvr/display/omap_display.c1078
-rw-r--r--drivers/gpu/pvr/display/omap_display.h109
-rw-r--r--drivers/gpu/pvr/display/omap_sgx_displayclass.c1638
-rw-r--r--drivers/gpu/pvr/display/omap_sgx_displayclass.h123
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 */
61static struct omap_display_device *omap_display_list;
62static unsigned int omap_display_number;
63
64/* Forward declarations */
65static struct omap_display_buffer *create_main_buffer(
66 struct omap_display_device *display);
67static int display_destroy_buffer(struct omap_display_buffer *buffer);
68
69static 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
103static 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
126static 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
168static 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
299static 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
331static int rotate_display(struct omap_display_device *display,
332 unsigned int rotation)
333{
334 ERR_PRINT("Not supported yet");
335 return 1;
336}
337
338static int display_destroy_buffer(struct omap_display_buffer *buffer)
339{
340 kfree(buffer);
341 return 0;
342}
343
344static 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
399static 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
467static 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
489static 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
501static 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
613static 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
626static 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
670static 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
750static 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
844static 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
951static 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
1002struct 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}
1021EXPORT_SYMBOL(omap_display_get);
1022
1023int omap_display_count(void)
1024{
1025 return omap_display_number;
1026}
1027EXPORT_SYMBOL(omap_display_count);
1028
1029int 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}
1043EXPORT_SYMBOL(omap_display_init);
1044
1045int 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}
1077EXPORT_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
32struct omap_display_device;
33
34/* On OMAP 4 we can only manage 3 displays at the same time + virtual */
35enum 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
43enum omap_display_pixel_format {
44 RGB_565 = 0,
45 ARGB_8888 = 1,
46};
47
48/* Primary display location for virtual display */
49enum omap_display_feature {
50 ORIENTATION_VERTICAL = 1 << 0,
51 ORIENTATION_HORIZONTAL = 1 << 1,
52 ORIENTATION_INVERT = 1 << 2,
53};
54
55struct 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
62struct 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
68struct omap_display_sync_item {
69 struct omap_display_buffer *buffer;
70 struct completion *task;
71 int invalidate;
72};
73
74struct 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
104int omap_display_init(void);
105int omap_display_deinit(void);
106int omap_display_count(void);
107struct 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, \
51CONFIG_FB_OMAP2_NUM_FBS must be equal or greater than 2 \
52see 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 */
59static PFN_DC_GET_PVRJTABLE pfnGetPVRJTable = NULL;
60
61/* Pointer to the display devices */
62static struct OMAP_DISP_DEVINFO *pDisplayDevices = NULL;
63static int display_devices_count = 0;
64
65static void display_sync_handler(struct work_struct *work);
66static 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 */
76static 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 */
91static 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 */
103static 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 */
115static 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 */
127static 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 */
139static 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 */
156static 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 */
216static 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 */
259static 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 */
278static 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 */
328static 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 */
356static 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 */
385static 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 */
406static 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 */
427static 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 */
468static 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
677ErrorFreeBuffers:
678 kfree(psBuffer);
679ErrorFreeSwapChain:
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 */
689static 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 */
757static 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 */
793static 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 */
823static 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
866static 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
947ExitUnlock:
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 */
956static 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
1046ExitTrueUnlock:
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 */
1056static 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 */
1086static 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 */
1118static 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 */
1126static 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 */
1180static 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 */
1301static 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 */
1472static 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
1488static volatile enum OMAP_BOOL bDeviceSuspended;
1489
1490/*
1491 * Common suspend driver function
1492 * in: psSwapChain, aPhyAddr
1493 */
1494static 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
1508static struct early_suspend driver_early_suspend;
1509
1510/*
1511 * Android specific, driver is requested to be suspended
1512 * in: ea_event
1513 */
1514static 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 */
1524static void DriverResume_Entry(struct early_suspend *ea_event)
1525{
1526 DEBUG_PRINTK("Requested driver resume");
1527 DriverResume();
1528 bDeviceSuspended = OMAP_FALSE;
1529}
1530
1531static 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 */
1543static 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 */
1555static 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 */
1567static IMG_VOID DriverShutdown_Entry(
1568 struct platform_device unref__ *pDevice)
1569{
1570 DEBUG_PRINTK("Requested driver shutdown");
1571 CommonSuspend();
1572}
1573
1574static 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 */
1590static 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 */
1623static 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
1636MODULE_SUPPORTED_DEVICE(DEVNAME);
1637late_initcall(omap_sgx_dc_init);
1638module_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
30extern IMG_BOOL PVRGetDisplayClassJTable(
31 PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable);
32
33typedef void * OMAP_HANDLE;
34
35enum OMAP_BOOL
36{
37 OMAP_FALSE = 0,
38 OMAP_TRUE = 1,
39};
40
41struct 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
51struct 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
62struct 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
77struct 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
97enum 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