aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/pvr/display/omap_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/pvr/display/omap_display.c')
-rw-r--r--drivers/gpu/pvr/display/omap_display.c1078
1 files changed, 1078 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