summaryrefslogtreecommitdiffstats
path: root/meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0004-DSS2-OMAP-framebuffer-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0004-DSS2-OMAP-framebuffer-driver.patch')
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0004-DSS2-OMAP-framebuffer-driver.patch3403
1 files changed, 3403 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0004-DSS2-OMAP-framebuffer-driver.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0004-DSS2-OMAP-framebuffer-driver.patch
new file mode 100644
index 0000000000..09afa7e5be
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0004-DSS2-OMAP-framebuffer-driver.patch
@@ -0,0 +1,3403 @@
1From db9314f01a207e256d545244d3d00dc4ce535280 Mon Sep 17 00:00:00 2001
2From: Tomi Valkeinen <tomi.valkeinen@nokia.com>
3Date: Thu, 2 Apr 2009 10:25:48 +0300
4Subject: [PATCH] DSS2: OMAP framebuffer driver
5
6Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7---
8 arch/arm/plat-omap/fb.c | 28 +
9 drivers/video/omap/Kconfig | 5 +-
10 drivers/video/omap2/omapfb/Kconfig | 35 +
11 drivers/video/omap2/omapfb/Makefile | 2 +
12 drivers/video/omap2/omapfb/omapfb-ioctl.c | 656 ++++++++++
13 drivers/video/omap2/omapfb/omapfb-main.c | 2010 +++++++++++++++++++++++++++++
14 drivers/video/omap2/omapfb/omapfb-sysfs.c | 371 ++++++
15 drivers/video/omap2/omapfb/omapfb.h | 153 +++
16 include/linux/omapfb.h | 20 +
17 9 files changed, 3278 insertions(+), 2 deletions(-)
18 create mode 100644 drivers/video/omap2/omapfb/Kconfig
19 create mode 100644 drivers/video/omap2/omapfb/Makefile
20 create mode 100644 drivers/video/omap2/omapfb/omapfb-ioctl.c
21 create mode 100644 drivers/video/omap2/omapfb/omapfb-main.c
22 create mode 100644 drivers/video/omap2/omapfb/omapfb-sysfs.c
23 create mode 100644 drivers/video/omap2/omapfb/omapfb.h
24
25diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
26index 40615a6..1dc3415 100644
27--- a/arch/arm/plat-omap/fb.c
28+++ b/arch/arm/plat-omap/fb.c
29@@ -327,6 +327,34 @@ static inline int omap_init_fb(void)
30
31 arch_initcall(omap_init_fb);
32
33+#elif defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
34+
35+static u64 omap_fb_dma_mask = ~(u32)0;
36+static struct omapfb_platform_data omapfb_config;
37+
38+static struct platform_device omap_fb_device = {
39+ .name = "omapfb",
40+ .id = -1,
41+ .dev = {
42+ .dma_mask = &omap_fb_dma_mask,
43+ .coherent_dma_mask = ~(u32)0,
44+ .platform_data = &omapfb_config,
45+ },
46+ .num_resources = 0,
47+};
48+
49+void omapfb_set_platform_data(struct omapfb_platform_data *data)
50+{
51+ omapfb_config = *data;
52+}
53+
54+static inline int omap_init_fb(void)
55+{
56+ return platform_device_register(&omap_fb_device);
57+}
58+
59+arch_initcall(omap_init_fb);
60+
61 #else
62
63 void omapfb_reserve_sdram(void) {}
64diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
65index c355b59..a1c10de 100644
66--- a/drivers/video/omap/Kconfig
67+++ b/drivers/video/omap/Kconfig
68@@ -1,6 +1,7 @@
69 config FB_OMAP
70 tristate "OMAP frame buffer support (EXPERIMENTAL)"
71- depends on FB && ARCH_OMAP
72+ depends on FB && ARCH_OMAP && (OMAP2_DSS = "n")
73+
74 select FB_CFB_FILLRECT
75 select FB_CFB_COPYAREA
76 select FB_CFB_IMAGEBLIT
77@@ -72,7 +73,7 @@ config FB_OMAP_LCD_MIPID
78
79 config FB_OMAP_BOOTLOADER_INIT
80 bool "Check bootloader initialization"
81- depends on FB_OMAP
82+ depends on FB_OMAP || FB_OMAP2
83 help
84 Say Y here if you want to enable checking if the bootloader has
85 already initialized the display controller. In this case the
86diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
87new file mode 100644
88index 0000000..4f66033
89--- /dev/null
90+++ b/drivers/video/omap2/omapfb/Kconfig
91@@ -0,0 +1,35 @@
92+menuconfig FB_OMAP2
93+ tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)"
94+ depends on FB && OMAP2_DSS
95+
96+ select FB_CFB_FILLRECT
97+ select FB_CFB_COPYAREA
98+ select FB_CFB_IMAGEBLIT
99+ help
100+ Frame buffer driver for OMAP2/3 based boards.
101+
102+config FB_OMAP2_DEBUG_SUPPORT
103+ bool "Debug support for OMAP2/3 FB"
104+ default y
105+ depends on FB_OMAP2
106+ help
107+ Support for debug output. You have to enable the actual printing
108+ with debug module parameter.
109+
110+config FB_OMAP2_FORCE_AUTO_UPDATE
111+ bool "Force main display to automatic update mode"
112+ depends on FB_OMAP2
113+ help
114+ Forces main display to automatic update mode (if possible),
115+ and also enables tearsync (if possible). By default
116+ displays that support manual update are started in manual
117+ update mode.
118+
119+config FB_OMAP2_NUM_FBS
120+ int "Number of framebuffers"
121+ range 1 10
122+ default 3
123+ depends on FB_OMAP2
124+ help
125+ Select the number of framebuffers created. OMAP2/3 has 3 overlays
126+ so normally this would be 3.
127diff --git a/drivers/video/omap2/omapfb/Makefile b/drivers/video/omap2/omapfb/Makefile
128new file mode 100644
129index 0000000..51c2e00
130--- /dev/null
131+++ b/drivers/video/omap2/omapfb/Makefile
132@@ -0,0 +1,2 @@
133+obj-$(CONFIG_FB_OMAP2) += omapfb.o
134+omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o
135diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
136new file mode 100644
137index 0000000..7f18d2a
138--- /dev/null
139+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
140@@ -0,0 +1,656 @@
141+/*
142+ * linux/drivers/video/omap2/omapfb-ioctl.c
143+ *
144+ * Copyright (C) 2008 Nokia Corporation
145+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
146+ *
147+ * Some code and ideas taken from drivers/video/omap/ driver
148+ * by Imre Deak.
149+ *
150+ * This program is free software; you can redistribute it and/or modify it
151+ * under the terms of the GNU General Public License version 2 as published by
152+ * the Free Software Foundation.
153+ *
154+ * This program is distributed in the hope that it will be useful, but WITHOUT
155+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
156+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
157+ * more details.
158+ *
159+ * You should have received a copy of the GNU General Public License along with
160+ * this program. If not, see <http://www.gnu.org/licenses/>.
161+ */
162+
163+#include <linux/fb.h>
164+#include <linux/device.h>
165+#include <linux/uaccess.h>
166+#include <linux/platform_device.h>
167+#include <linux/mm.h>
168+#include <linux/omapfb.h>
169+#include <linux/vmalloc.h>
170+
171+#include <mach/display.h>
172+#include <mach/vrfb.h>
173+
174+#include "omapfb.h"
175+
176+static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
177+{
178+ struct omapfb_info *ofbi = FB2OFB(fbi);
179+ struct omapfb2_device *fbdev = ofbi->fbdev;
180+ struct omap_display *display = fb2display(fbi);
181+ struct omap_overlay *ovl;
182+ struct omap_overlay_info info;
183+ int r = 0;
184+
185+ DBG("omapfb_setup_plane\n");
186+
187+ omapfb_lock(fbdev);
188+
189+ if (ofbi->num_overlays != 1) {
190+ r = -EINVAL;
191+ goto out;
192+ }
193+
194+ /* XXX uses only the first overlay */
195+ ovl = ofbi->overlays[0];
196+
197+ if (pi->enabled && !ofbi->region.size) {
198+ /*
199+ * This plane's memory was freed, can't enable it
200+ * until it's reallocated.
201+ */
202+ r = -EINVAL;
203+ goto out;
204+ }
205+
206+ ovl->get_overlay_info(ovl, &info);
207+
208+ info.pos_x = pi->pos_x;
209+ info.pos_y = pi->pos_y;
210+ info.out_width = pi->out_width;
211+ info.out_height = pi->out_height;
212+ info.enabled = pi->enabled;
213+
214+ r = ovl->set_overlay_info(ovl, &info);
215+ if (r)
216+ goto out;
217+
218+ if (ovl->manager) {
219+ r = ovl->manager->apply(ovl->manager);
220+ if (r)
221+ goto out;
222+ }
223+
224+ if (display) {
225+ u16 w, h;
226+
227+ if (display->sync)
228+ display->sync(display);
229+
230+ display->get_resolution(display, &w, &h);
231+
232+ if (display->update)
233+ display->update(display, 0, 0, w, h);
234+ }
235+
236+out:
237+ omapfb_unlock(fbdev);
238+ if (r)
239+ dev_err(fbdev->dev, "setup_plane failed\n");
240+ return r;
241+}
242+
243+static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
244+{
245+ struct omapfb_info *ofbi = FB2OFB(fbi);
246+ struct omapfb2_device *fbdev = ofbi->fbdev;
247+
248+ omapfb_lock(fbdev);
249+
250+ if (ofbi->num_overlays != 1) {
251+ memset(pi, 0, sizeof(*pi));
252+ } else {
253+ struct omap_overlay_info *ovli;
254+ struct omap_overlay *ovl;
255+
256+ ovl = ofbi->overlays[0];
257+ ovli = &ovl->info;
258+
259+ pi->pos_x = ovli->pos_x;
260+ pi->pos_y = ovli->pos_y;
261+ pi->enabled = ovli->enabled;
262+ pi->channel_out = 0; /* xxx */
263+ pi->mirror = 0;
264+ pi->out_width = ovli->out_width;
265+ pi->out_height = ovli->out_height;
266+ }
267+
268+ omapfb_unlock(fbdev);
269+
270+ return 0;
271+}
272+
273+static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
274+{
275+ struct omapfb_info *ofbi = FB2OFB(fbi);
276+ struct omapfb2_device *fbdev = ofbi->fbdev;
277+ struct omapfb2_mem_region *rg;
278+ int r, i;
279+ size_t size;
280+
281+ if (mi->type > OMAPFB_MEMTYPE_MAX)
282+ return -EINVAL;
283+
284+ size = PAGE_ALIGN(mi->size);
285+
286+ rg = &ofbi->region;
287+
288+ omapfb_lock(fbdev);
289+
290+ for (i = 0; i < ofbi->num_overlays; i++) {
291+ if (ofbi->overlays[i]->info.enabled) {
292+ r = -EBUSY;
293+ goto out;
294+ }
295+ }
296+
297+ if (rg->size != size || rg->type != mi->type) {
298+ r = omapfb_realloc_fbmem(fbi, size, mi->type);
299+ if (r) {
300+ dev_err(fbdev->dev, "realloc fbmem failed\n");
301+ goto out;
302+ }
303+ }
304+
305+ r = 0;
306+out:
307+ omapfb_unlock(fbdev);
308+
309+ return r;
310+}
311+
312+static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
313+{
314+ struct omapfb_info *ofbi = FB2OFB(fbi);
315+ struct omapfb2_device *fbdev = ofbi->fbdev;
316+ struct omapfb2_mem_region *rg;
317+
318+ rg = &ofbi->region;
319+ memset(mi, 0, sizeof(*mi));
320+
321+ omapfb_lock(fbdev);
322+ mi->size = rg->size;
323+ mi->type = rg->type;
324+ omapfb_unlock(fbdev);
325+
326+ return 0;
327+}
328+
329+static int omapfb_update_window(struct fb_info *fbi,
330+ u32 x, u32 y, u32 w, u32 h)
331+{
332+ struct omapfb_info *ofbi = FB2OFB(fbi);
333+ struct omapfb2_device *fbdev = ofbi->fbdev;
334+ struct omap_display *display = fb2display(fbi);
335+ u16 dw, dh;
336+
337+ if (!display)
338+ return 0;
339+
340+ if (w == 0 || h == 0)
341+ return 0;
342+
343+ display->get_resolution(display, &dw, &dh);
344+
345+ if (x + w > dw || y + h > dh)
346+ return -EINVAL;
347+
348+ omapfb_lock(fbdev);
349+ display->update(display, x, y, w, h);
350+ omapfb_unlock(fbdev);
351+
352+ return 0;
353+}
354+
355+static int omapfb_set_update_mode(struct fb_info *fbi,
356+ enum omapfb_update_mode mode)
357+{
358+ struct omapfb_info *ofbi = FB2OFB(fbi);
359+ struct omapfb2_device *fbdev = ofbi->fbdev;
360+ struct omap_display *display = fb2display(fbi);
361+ enum omap_dss_update_mode um;
362+ int r;
363+
364+ if (!display || !display->set_update_mode)
365+ return -EINVAL;
366+
367+ switch (mode) {
368+ case OMAPFB_UPDATE_DISABLED:
369+ um = OMAP_DSS_UPDATE_DISABLED;
370+ break;
371+
372+ case OMAPFB_AUTO_UPDATE:
373+ um = OMAP_DSS_UPDATE_AUTO;
374+ break;
375+
376+ case OMAPFB_MANUAL_UPDATE:
377+ um = OMAP_DSS_UPDATE_MANUAL;
378+ break;
379+
380+ default:
381+ return -EINVAL;
382+ }
383+
384+ omapfb_lock(fbdev);
385+ r = display->set_update_mode(display, um);
386+ omapfb_unlock(fbdev);
387+
388+ return r;
389+}
390+
391+static int omapfb_get_update_mode(struct fb_info *fbi,
392+ enum omapfb_update_mode *mode)
393+{
394+ struct omapfb_info *ofbi = FB2OFB(fbi);
395+ struct omapfb2_device *fbdev = ofbi->fbdev;
396+ struct omap_display *display = fb2display(fbi);
397+ enum omap_dss_update_mode m;
398+
399+ if (!display || !display->get_update_mode)
400+ return -EINVAL;
401+
402+ omapfb_lock(fbdev);
403+ m = display->get_update_mode(display);
404+ omapfb_unlock(fbdev);
405+
406+ switch (m) {
407+ case OMAP_DSS_UPDATE_DISABLED:
408+ *mode = OMAPFB_UPDATE_DISABLED;
409+ break;
410+ case OMAP_DSS_UPDATE_AUTO:
411+ *mode = OMAPFB_AUTO_UPDATE;
412+ break;
413+ case OMAP_DSS_UPDATE_MANUAL:
414+ *mode = OMAPFB_MANUAL_UPDATE;
415+ break;
416+ default:
417+ BUG();
418+ }
419+
420+ return 0;
421+}
422+
423+/* XXX this color key handling is a hack... */
424+static struct omapfb_color_key omapfb_color_keys[2];
425+
426+static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,
427+ struct omapfb_color_key *ck)
428+{
429+ enum omap_dss_color_key_type kt;
430+
431+ if(!mgr->set_default_color || !mgr->set_trans_key ||
432+ !mgr->enable_trans_key)
433+ return 0;
434+
435+ if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {
436+ mgr->enable_trans_key(mgr, 0);
437+ omapfb_color_keys[mgr->id] = *ck;
438+ return 0;
439+ }
440+
441+ switch(ck->key_type) {
442+ case OMAPFB_COLOR_KEY_GFX_DST:
443+ kt = OMAP_DSS_COLOR_KEY_GFX_DST;
444+ break;
445+ case OMAPFB_COLOR_KEY_VID_SRC:
446+ kt = OMAP_DSS_COLOR_KEY_VID_SRC;
447+ break;
448+ default:
449+ return -EINVAL;
450+ }
451+
452+ mgr->set_default_color(mgr, ck->background);
453+ mgr->set_trans_key(mgr, kt, ck->trans_key);
454+ mgr->enable_trans_key(mgr, 1);
455+
456+ omapfb_color_keys[mgr->id] = *ck;
457+
458+ return 0;
459+}
460+
461+static int omapfb_set_color_key(struct fb_info *fbi,
462+ struct omapfb_color_key *ck)
463+{
464+ struct omapfb_info *ofbi = FB2OFB(fbi);
465+ struct omapfb2_device *fbdev = ofbi->fbdev;
466+ int r;
467+ int i;
468+ struct omap_overlay_manager *mgr = NULL;
469+
470+ omapfb_lock(fbdev);
471+
472+ for (i = 0; i < ofbi->num_overlays; i++) {
473+ if (ofbi->overlays[i]->manager) {
474+ mgr = ofbi->overlays[i]->manager;
475+ break;
476+ }
477+ }
478+
479+ if (!mgr) {
480+ r = -EINVAL;
481+ goto err;
482+ }
483+
484+ if(!mgr->set_default_color || !mgr->set_trans_key ||
485+ !mgr->enable_trans_key) {
486+ r = -ENODEV;
487+ goto err;
488+ }
489+
490+ r = _omapfb_set_color_key(mgr, ck);
491+err:
492+ omapfb_unlock(fbdev);
493+
494+ return r;
495+}
496+
497+static int omapfb_get_color_key(struct fb_info *fbi,
498+ struct omapfb_color_key *ck)
499+{
500+ struct omapfb_info *ofbi = FB2OFB(fbi);
501+ struct omapfb2_device *fbdev = ofbi->fbdev;
502+ struct omap_overlay_manager *mgr = NULL;
503+ int r = 0;
504+ int i;
505+
506+ omapfb_lock(fbdev);
507+
508+ for (i = 0; i < ofbi->num_overlays; i++) {
509+ if (ofbi->overlays[i]->manager) {
510+ mgr = ofbi->overlays[i]->manager;
511+ break;
512+ }
513+ }
514+
515+ if (!mgr) {
516+ r = -EINVAL;
517+ goto err;
518+ }
519+
520+ if(!mgr->set_default_color || !mgr->set_trans_key ||
521+ !mgr->enable_trans_key) {
522+ r = -ENODEV;
523+ goto err;
524+ }
525+
526+ *ck = omapfb_color_keys[mgr->id];
527+err:
528+ omapfb_unlock(fbdev);
529+
530+ return r;
531+}
532+
533+static int omapfb_memory_read(struct fb_info *fbi,
534+ struct omapfb_memory_read *mr)
535+{
536+ struct omap_display *display = fb2display(fbi);
537+ struct omapfb_info *ofbi = FB2OFB(fbi);
538+ struct omapfb2_device *fbdev = ofbi->fbdev;
539+ void *buf;
540+ int r;
541+
542+ if (!display || !display->memory_read)
543+ return -ENOENT;
544+
545+ if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
546+ return -EFAULT;
547+
548+ if (mr->w * mr->h * 3 > mr->buffer_size)
549+ return -EINVAL;
550+
551+ buf = vmalloc(mr->buffer_size);
552+ if (!buf) {
553+ DBG("vmalloc failed\n");
554+ return -ENOMEM;
555+ }
556+
557+ omapfb_lock(fbdev);
558+
559+ r = display->memory_read(display, buf, mr->buffer_size,
560+ mr->x, mr->y, mr->w, mr->h);
561+
562+ if (r > 0) {
563+ if (copy_to_user(mr->buffer, buf, mr->buffer_size))
564+ r = -EFAULT;
565+ }
566+
567+ vfree(buf);
568+
569+ omapfb_unlock(fbdev);
570+
571+ return r;
572+}
573+
574+int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
575+{
576+ struct omapfb_info *ofbi = FB2OFB(fbi);
577+ struct omapfb2_device *fbdev = ofbi->fbdev;
578+ struct omap_display *display = fb2display(fbi);
579+
580+ union {
581+ struct omapfb_update_window_old uwnd_o;
582+ struct omapfb_update_window uwnd;
583+ struct omapfb_plane_info plane_info;
584+ struct omapfb_caps caps;
585+ struct omapfb_mem_info mem_info;
586+ struct omapfb_color_key color_key;
587+ enum omapfb_update_mode update_mode;
588+ int test_num;
589+ struct omapfb_memory_read memory_read;
590+ } p;
591+
592+ int r = 0;
593+
594+ switch (cmd) {
595+ case OMAPFB_SYNC_GFX:
596+ DBG("ioctl SYNC_GFX\n");
597+ if (!display || !display->sync) {
598+ /* DSS1 never returns an error here, so we neither */
599+ /*r = -EINVAL;*/
600+ break;
601+ }
602+
603+ omapfb_lock(fbdev);
604+ r = display->sync(display);
605+ omapfb_unlock(fbdev);
606+ break;
607+
608+ case OMAPFB_UPDATE_WINDOW_OLD:
609+ DBG("ioctl UPDATE_WINDOW_OLD\n");
610+ if (!display || !display->update) {
611+ r = -EINVAL;
612+ break;
613+ }
614+
615+ if (copy_from_user(&p.uwnd_o,
616+ (void __user *)arg,
617+ sizeof(p.uwnd_o))) {
618+ r = -EFAULT;
619+ break;
620+ }
621+
622+ r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y,
623+ p.uwnd_o.width, p.uwnd_o.height);
624+ break;
625+
626+ case OMAPFB_UPDATE_WINDOW:
627+ DBG("ioctl UPDATE_WINDOW\n");
628+ if (!display || !display->update) {
629+ r = -EINVAL;
630+ break;
631+ }
632+
633+ if (copy_from_user(&p.uwnd, (void __user *)arg,
634+ sizeof(p.uwnd))) {
635+ r = -EFAULT;
636+ break;
637+ }
638+
639+ r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y,
640+ p.uwnd.width, p.uwnd.height);
641+ break;
642+
643+ case OMAPFB_SETUP_PLANE:
644+ DBG("ioctl SETUP_PLANE\n");
645+ if (copy_from_user(&p.plane_info, (void __user *)arg,
646+ sizeof(p.plane_info)))
647+ r = -EFAULT;
648+ else
649+ r = omapfb_setup_plane(fbi, &p.plane_info);
650+ break;
651+
652+ case OMAPFB_QUERY_PLANE:
653+ DBG("ioctl QUERY_PLANE\n");
654+ r = omapfb_query_plane(fbi, &p.plane_info);
655+ if (r < 0)
656+ break;
657+ if (copy_to_user((void __user *)arg, &p.plane_info,
658+ sizeof(p.plane_info)))
659+ r = -EFAULT;
660+ break;
661+
662+ case OMAPFB_SETUP_MEM:
663+ DBG("ioctl SETUP_MEM\n");
664+ if (copy_from_user(&p.mem_info, (void __user *)arg,
665+ sizeof(p.mem_info)))
666+ r = -EFAULT;
667+ else
668+ r = omapfb_setup_mem(fbi, &p.mem_info);
669+ break;
670+
671+ case OMAPFB_QUERY_MEM:
672+ DBG("ioctl QUERY_MEM\n");
673+ r = omapfb_query_mem(fbi, &p.mem_info);
674+ if (r < 0)
675+ break;
676+ if (copy_to_user((void __user *)arg, &p.mem_info,
677+ sizeof(p.mem_info)))
678+ r = -EFAULT;
679+ break;
680+
681+ case OMAPFB_GET_CAPS:
682+ DBG("ioctl GET_CAPS\n");
683+ if (!display) {
684+ r = -EINVAL;
685+ break;
686+ }
687+
688+ p.caps.ctrl = display->caps;
689+
690+ if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
691+ r = -EFAULT;
692+ break;
693+
694+ case OMAPFB_SET_UPDATE_MODE:
695+ DBG("ioctl SET_UPDATE_MODE\n");
696+ if (get_user(p.update_mode, (int __user *)arg))
697+ r = -EFAULT;
698+ else
699+ r = omapfb_set_update_mode(fbi, p.update_mode);
700+ break;
701+
702+ case OMAPFB_GET_UPDATE_MODE:
703+ DBG("ioctl GET_UPDATE_MODE\n");
704+ r = omapfb_get_update_mode(fbi, &p.update_mode);
705+ if (r)
706+ break;
707+ if (put_user(p.update_mode,
708+ (enum omapfb_update_mode __user *)arg))
709+ r = -EFAULT;
710+ break;
711+
712+ case OMAPFB_SET_COLOR_KEY:
713+ DBG("ioctl SET_COLOR_KEY\n");
714+ if (copy_from_user(&p.color_key, (void __user *)arg,
715+ sizeof(p.color_key)))
716+ r = -EFAULT;
717+ else
718+ r = omapfb_set_color_key(fbi, &p.color_key);
719+ break;
720+
721+ case OMAPFB_GET_COLOR_KEY:
722+ DBG("ioctl GET_COLOR_KEY\n");
723+ if ((r = omapfb_get_color_key(fbi, &p.color_key)) < 0)
724+ break;
725+ if (copy_to_user((void __user *)arg, &p.color_key,
726+ sizeof(p.color_key)))
727+ r = -EFAULT;
728+ break;
729+
730+ case OMAPFB_WAITFORVSYNC:
731+ DBG("ioctl WAITFORVSYNC\n");
732+ if (!display) {
733+ r = -EINVAL;
734+ break;
735+ }
736+
737+ r = display->wait_vsync(display);
738+ break;
739+
740+ /* LCD and CTRL tests do the same thing for backward
741+ * compatibility */
742+ case OMAPFB_LCD_TEST:
743+ DBG("ioctl LCD_TEST\n");
744+ if (get_user(p.test_num, (int __user *)arg)) {
745+ r = -EFAULT;
746+ break;
747+ }
748+ if (!display || !display->run_test) {
749+ r = -EINVAL;
750+ break;
751+ }
752+
753+ r = display->run_test(display, p.test_num);
754+
755+ break;
756+
757+ case OMAPFB_CTRL_TEST:
758+ DBG("ioctl CTRL_TEST\n");
759+ if (get_user(p.test_num, (int __user *)arg)) {
760+ r = -EFAULT;
761+ break;
762+ }
763+ if (!display || !display->run_test) {
764+ r = -EINVAL;
765+ break;
766+ }
767+
768+ r = display->run_test(display, p.test_num);
769+
770+ break;
771+
772+ case OMAPFB_MEMORY_READ:
773+ DBG("ioctl MEMORY_READ\n");
774+
775+ if (copy_from_user(&p.memory_read, (void __user *)arg,
776+ sizeof(p.memory_read))) {
777+ r = -EFAULT;
778+ break;
779+ }
780+
781+ r = omapfb_memory_read(fbi, &p.memory_read);
782+
783+ break;
784+
785+ default:
786+ dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
787+ r = -EINVAL;
788+ }
789+
790+ if (r < 0)
791+ DBG("ioctl failed: %d\n", r);
792+
793+ return r;
794+}
795+
796+
797diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
798new file mode 100644
799index 0000000..852abe5
800--- /dev/null
801+++ b/drivers/video/omap2/omapfb/omapfb-main.c
802@@ -0,0 +1,2010 @@
803+/*
804+ * linux/drivers/video/omap2/omapfb-main.c
805+ *
806+ * Copyright (C) 2008 Nokia Corporation
807+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
808+ *
809+ * Some code and ideas taken from drivers/video/omap/ driver
810+ * by Imre Deak.
811+ *
812+ * This program is free software; you can redistribute it and/or modify it
813+ * under the terms of the GNU General Public License version 2 as published by
814+ * the Free Software Foundation.
815+ *
816+ * This program is distributed in the hope that it will be useful, but WITHOUT
817+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
818+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
819+ * more details.
820+ *
821+ * You should have received a copy of the GNU General Public License along with
822+ * this program. If not, see <http://www.gnu.org/licenses/>.
823+ */
824+
825+#include <linux/module.h>
826+#include <linux/delay.h>
827+#include <linux/fb.h>
828+#include <linux/dma-mapping.h>
829+#include <linux/vmalloc.h>
830+#include <linux/device.h>
831+#include <linux/platform_device.h>
832+#include <linux/omapfb.h>
833+
834+#include <mach/display.h>
835+#include <mach/vram.h>
836+#include <mach/vrfb.h>
837+
838+#include "omapfb.h"
839+
840+#define MODULE_NAME "omapfb"
841+
842+static char *def_mode;
843+static char *def_vram;
844+static int def_vrfb;
845+static int def_rotate;
846+static int def_mirror;
847+
848+#ifdef DEBUG
849+unsigned int omapfb_debug;
850+module_param_named(debug, omapfb_debug, bool, 0644);
851+static unsigned int omapfb_test_pattern;
852+module_param_named(test, omapfb_test_pattern, bool, 0644);
853+#endif
854+
855+#ifdef DEBUG
856+static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
857+{
858+ struct fb_var_screeninfo *var = &fbi->var;
859+ struct fb_fix_screeninfo *fix = &fbi->fix;
860+ void __iomem *addr = fbi->screen_base;
861+ const unsigned bytespp = var->bits_per_pixel >> 3;
862+ const unsigned line_len = fix->line_length / bytespp;
863+
864+ int r = (color >> 16) & 0xff;
865+ int g = (color >> 8) & 0xff;
866+ int b = (color >> 0) & 0xff;
867+
868+ if (var->bits_per_pixel == 16) {
869+ u16 __iomem *p = (u16 __iomem *)addr;
870+ p += y * line_len + x;
871+
872+ r = r * 32 / 256;
873+ g = g * 64 / 256;
874+ b = b * 32 / 256;
875+
876+ __raw_writew((r << 11) | (g << 5) | (b << 0), p);
877+ } else if (var->bits_per_pixel == 24) {
878+ u8 __iomem *p = (u8 __iomem *)addr;
879+ p += (y * line_len + x) * 3;
880+
881+ __raw_writeb(b, p + 0);
882+ __raw_writeb(g, p + 1);
883+ __raw_writeb(r, p + 2);
884+ } else if (var->bits_per_pixel == 32) {
885+ u32 __iomem *p = (u32 __iomem *)addr;
886+ p += y * line_len + x;
887+ __raw_writel(color, p);
888+ }
889+}
890+
891+static void fill_fb(struct fb_info *fbi)
892+{
893+ struct fb_var_screeninfo *var = &fbi->var;
894+ const short w = var->xres_virtual;
895+ const short h = var->yres_virtual;
896+ void __iomem *addr = fbi->screen_base;
897+ int y, x;
898+
899+ if (!addr)
900+ return;
901+
902+ DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
903+
904+ for (y = 0; y < h; y++) {
905+ for (x = 0; x < w; x++) {
906+ if (x < 20 && y < 20)
907+ draw_pixel(fbi, x, y, 0xffffff);
908+ else if (x < 20 && (y > 20 && y < h - 20))
909+ draw_pixel(fbi, x, y, 0xff);
910+ else if (y < 20 && (x > 20 && x < w - 20))
911+ draw_pixel(fbi, x, y, 0xff00);
912+ else if (x > w - 20 && (y > 20 && y < h - 20))
913+ draw_pixel(fbi, x, y, 0xff0000);
914+ else if (y > h - 20 && (x > 20 && x < w - 20))
915+ draw_pixel(fbi, x, y, 0xffff00);
916+ else if (x == 20 || x == w - 20 ||
917+ y == 20 || y == h - 20)
918+ draw_pixel(fbi, x, y, 0xffffff);
919+ else if (x == y || w - x == h - y)
920+ draw_pixel(fbi, x, y, 0xff00ff);
921+ else if (w - x == y || x == h - y)
922+ draw_pixel(fbi, x, y, 0x00ffff);
923+ else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {
924+ int t = x * 3 / w;
925+ unsigned r = 0, g = 0, b = 0;
926+ unsigned c;
927+ if (var->bits_per_pixel == 16) {
928+ if (t == 0)
929+ b = (y % 32) * 256 / 32;
930+ else if (t == 1)
931+ g = (y % 64) * 256 / 64;
932+ else if (t == 2)
933+ r = (y % 32) * 256 / 32;
934+ } else {
935+ if (t == 0)
936+ b = (y % 256);
937+ else if (t == 1)
938+ g = (y % 256);
939+ else if (t == 2)
940+ r = (y % 256);
941+ }
942+ c = (r << 16) | (g << 8) | (b << 0);
943+ draw_pixel(fbi, x, y, c);
944+ } else {
945+ draw_pixel(fbi, x, y, 0);
946+ }
947+ }
948+ }
949+}
950+#endif
951+
952+static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)
953+{
954+ struct vrfb *vrfb = &ofbi->region.vrfb;
955+ unsigned offset;
956+
957+ switch (rot) {
958+ case FB_ROTATE_UR:
959+ offset = 0;
960+ break;
961+ case FB_ROTATE_CW:
962+ offset = vrfb->yoffset;
963+ break;
964+ case FB_ROTATE_UD:
965+ offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
966+ break;
967+ case FB_ROTATE_CCW:
968+ offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
969+ break;
970+ default:
971+ BUG();
972+ }
973+
974+ offset *= vrfb->bytespp;
975+
976+ return offset;
977+}
978+
979+static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi)
980+{
981+ if (ofbi->rotation_type == OMAPFB_ROT_VRFB) {
982+ unsigned offset;
983+ int rot;
984+
985+ rot = ofbi->rotation;
986+
987+ offset = omapfb_get_vrfb_offset(ofbi, rot);
988+
989+ return ofbi->region.vrfb.paddr[rot] + offset;
990+ } else {
991+ return ofbi->region.paddr;
992+ }
993+}
994+
995+u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
996+{
997+ if (ofbi->rotation_type == OMAPFB_ROT_VRFB)
998+ return ofbi->region.vrfb.paddr[0];
999+ else
1000+ return ofbi->region.paddr;
1001+}
1002+
1003+void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi)
1004+{
1005+ if (ofbi->rotation_type == OMAPFB_ROT_VRFB)
1006+ return ofbi->region.vrfb.vaddr[0];
1007+ else
1008+ return ofbi->region.vaddr;
1009+}
1010+
1011+static struct omapfb_colormode omapfb_colormodes[] = {
1012+ {
1013+ .dssmode = OMAP_DSS_COLOR_UYVY,
1014+ .bits_per_pixel = 16,
1015+ .nonstd = OMAPFB_COLOR_YUV422,
1016+ }, {
1017+ .dssmode = OMAP_DSS_COLOR_YUV2,
1018+ .bits_per_pixel = 16,
1019+ .nonstd = OMAPFB_COLOR_YUY422,
1020+ }, {
1021+ .dssmode = OMAP_DSS_COLOR_ARGB16,
1022+ .bits_per_pixel = 16,
1023+ .red = { .length = 4, .offset = 8, .msb_right = 0 },
1024+ .green = { .length = 4, .offset = 4, .msb_right = 0 },
1025+ .blue = { .length = 4, .offset = 0, .msb_right = 0 },
1026+ .transp = { .length = 4, .offset = 12, .msb_right = 0 },
1027+ }, {
1028+ .dssmode = OMAP_DSS_COLOR_RGB16,
1029+ .bits_per_pixel = 16,
1030+ .red = { .length = 5, .offset = 11, .msb_right = 0 },
1031+ .green = { .length = 6, .offset = 5, .msb_right = 0 },
1032+ .blue = { .length = 5, .offset = 0, .msb_right = 0 },
1033+ .transp = { .length = 0, .offset = 0, .msb_right = 0 },
1034+ }, {
1035+ .dssmode = OMAP_DSS_COLOR_RGB24P,
1036+ .bits_per_pixel = 24,
1037+ .red = { .length = 8, .offset = 16, .msb_right = 0 },
1038+ .green = { .length = 8, .offset = 8, .msb_right = 0 },
1039+ .blue = { .length = 8, .offset = 0, .msb_right = 0 },
1040+ .transp = { .length = 0, .offset = 0, .msb_right = 0 },
1041+ }, {
1042+ .dssmode = OMAP_DSS_COLOR_RGB24U,
1043+ .bits_per_pixel = 32,
1044+ .red = { .length = 8, .offset = 16, .msb_right = 0 },
1045+ .green = { .length = 8, .offset = 8, .msb_right = 0 },
1046+ .blue = { .length = 8, .offset = 0, .msb_right = 0 },
1047+ .transp = { .length = 0, .offset = 0, .msb_right = 0 },
1048+ }, {
1049+ .dssmode = OMAP_DSS_COLOR_ARGB32,
1050+ .bits_per_pixel = 32,
1051+ .red = { .length = 8, .offset = 16, .msb_right = 0 },
1052+ .green = { .length = 8, .offset = 8, .msb_right = 0 },
1053+ .blue = { .length = 8, .offset = 0, .msb_right = 0 },
1054+ .transp = { .length = 8, .offset = 24, .msb_right = 0 },
1055+ }, {
1056+ .dssmode = OMAP_DSS_COLOR_RGBA32,
1057+ .bits_per_pixel = 32,
1058+ .red = { .length = 8, .offset = 24, .msb_right = 0 },
1059+ .green = { .length = 8, .offset = 16, .msb_right = 0 },
1060+ .blue = { .length = 8, .offset = 8, .msb_right = 0 },
1061+ .transp = { .length = 8, .offset = 0, .msb_right = 0 },
1062+ }, {
1063+ .dssmode = OMAP_DSS_COLOR_RGBX32,
1064+ .bits_per_pixel = 32,
1065+ .red = { .length = 8, .offset = 24, .msb_right = 0 },
1066+ .green = { .length = 8, .offset = 16, .msb_right = 0 },
1067+ .blue = { .length = 8, .offset = 8, .msb_right = 0 },
1068+ .transp = { .length = 0, .offset = 0, .msb_right = 0 },
1069+ },
1070+};
1071+
1072+static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
1073+ struct omapfb_colormode *color)
1074+{
1075+ bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
1076+ {
1077+ return f1->length == f2->length &&
1078+ f1->offset == f2->offset &&
1079+ f1->msb_right == f2->msb_right;
1080+ }
1081+
1082+ if (var->bits_per_pixel == 0 ||
1083+ var->red.length == 0 ||
1084+ var->blue.length == 0 ||
1085+ var->green.length == 0)
1086+ return 0;
1087+
1088+ return var->bits_per_pixel == color->bits_per_pixel &&
1089+ cmp_component(&var->red, &color->red) &&
1090+ cmp_component(&var->green, &color->green) &&
1091+ cmp_component(&var->blue, &color->blue) &&
1092+ cmp_component(&var->transp, &color->transp);
1093+}
1094+
1095+static void assign_colormode_to_var(struct fb_var_screeninfo *var,
1096+ struct omapfb_colormode *color)
1097+{
1098+ var->bits_per_pixel = color->bits_per_pixel;
1099+ var->nonstd = color->nonstd;
1100+ var->red = color->red;
1101+ var->green = color->green;
1102+ var->blue = color->blue;
1103+ var->transp = color->transp;
1104+}
1105+
1106+static enum omap_color_mode fb_mode_to_dss_mode(struct fb_var_screeninfo *var)
1107+{
1108+ enum omap_color_mode dssmode;
1109+ int i;
1110+
1111+ /* first match with nonstd field */
1112+ if (var->nonstd) {
1113+ for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
1114+ struct omapfb_colormode *mode = &omapfb_colormodes[i];
1115+ if (var->nonstd == mode->nonstd) {
1116+ assign_colormode_to_var(var, mode);
1117+ return mode->dssmode;
1118+ }
1119+ }
1120+
1121+ return -EINVAL;
1122+ }
1123+
1124+ /* then try exact match of bpp and colors */
1125+ for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
1126+ struct omapfb_colormode *mode = &omapfb_colormodes[i];
1127+ if (cmp_var_to_colormode(var, mode)) {
1128+ assign_colormode_to_var(var, mode);
1129+ return mode->dssmode;
1130+ }
1131+ }
1132+
1133+ /* match with bpp if user has not filled color fields
1134+ * properly */
1135+ switch (var->bits_per_pixel) {
1136+ case 1:
1137+ dssmode = OMAP_DSS_COLOR_CLUT1;
1138+ break;
1139+ case 2:
1140+ dssmode = OMAP_DSS_COLOR_CLUT2;
1141+ break;
1142+ case 4:
1143+ dssmode = OMAP_DSS_COLOR_CLUT4;
1144+ break;
1145+ case 8:
1146+ dssmode = OMAP_DSS_COLOR_CLUT8;
1147+ break;
1148+ case 12:
1149+ dssmode = OMAP_DSS_COLOR_RGB12U;
1150+ break;
1151+ case 16:
1152+ dssmode = OMAP_DSS_COLOR_RGB16;
1153+ break;
1154+ case 24:
1155+ dssmode = OMAP_DSS_COLOR_RGB24P;
1156+ break;
1157+ case 32:
1158+ dssmode = OMAP_DSS_COLOR_RGB24U;
1159+ break;
1160+ default:
1161+ return -EINVAL;
1162+ }
1163+
1164+ for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
1165+ struct omapfb_colormode *mode = &omapfb_colormodes[i];
1166+ if (dssmode == mode->dssmode) {
1167+ assign_colormode_to_var(var, mode);
1168+ return mode->dssmode;
1169+ }
1170+ }
1171+
1172+ return -EINVAL;
1173+}
1174+
1175+void set_fb_fix(struct fb_info *fbi)
1176+{
1177+ struct fb_fix_screeninfo *fix = &fbi->fix;
1178+ struct fb_var_screeninfo *var = &fbi->var;
1179+ struct omapfb_info *ofbi = FB2OFB(fbi);
1180+ struct omapfb2_mem_region *rg = &ofbi->region;
1181+
1182+ DBG("set_fb_fix\n");
1183+
1184+ /* used by open/write in fbmem.c */
1185+ fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
1186+
1187+ /* used by mmap in fbmem.c */
1188+ if (ofbi->rotation_type == OMAPFB_ROT_VRFB)
1189+ fix->line_length =
1190+ (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
1191+ else
1192+ fix->line_length =
1193+ (var->xres_virtual * var->bits_per_pixel) >> 3;
1194+ fix->smem_start = omapfb_get_region_paddr(ofbi);
1195+ fix->smem_len = rg->size;
1196+
1197+ fix->type = FB_TYPE_PACKED_PIXELS;
1198+
1199+ if (var->nonstd)
1200+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
1201+ else {
1202+ switch (var->bits_per_pixel) {
1203+ case 32:
1204+ case 24:
1205+ case 16:
1206+ case 12:
1207+ fix->visual = FB_VISUAL_TRUECOLOR;
1208+ /* 12bpp is stored in 16 bits */
1209+ break;
1210+ case 1:
1211+ case 2:
1212+ case 4:
1213+ case 8:
1214+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
1215+ break;
1216+ }
1217+ }
1218+
1219+ fix->accel = FB_ACCEL_NONE;
1220+
1221+ fix->xpanstep = 1;
1222+ fix->ypanstep = 1;
1223+
1224+ if (rg->size) {
1225+ if (ofbi->rotation_type == OMAPFB_ROT_VRFB)
1226+ omap_vrfb_setup(&rg->vrfb, rg->paddr,
1227+ var->xres_virtual, var->yres_virtual,
1228+ var->bits_per_pixel >> 3);
1229+ }
1230+}
1231+
1232+/* check new var and possibly modify it to be ok */
1233+int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
1234+{
1235+ struct omapfb_info *ofbi = FB2OFB(fbi);
1236+ struct omap_display *display = fb2display(fbi);
1237+ unsigned long max_frame_size;
1238+ unsigned long line_size;
1239+ int xres_min, yres_min;
1240+ int xres_max, yres_max;
1241+ enum omap_color_mode mode = 0;
1242+ int i;
1243+ int bytespp;
1244+
1245+ DBG("check_fb_var %d\n", ofbi->id);
1246+
1247+ if (ofbi->region.size == 0)
1248+ return 0;
1249+
1250+ mode = fb_mode_to_dss_mode(var);
1251+ if (mode < 0) {
1252+ DBG("cannot convert var to omap dss mode\n");
1253+ return -EINVAL;
1254+ }
1255+
1256+ for (i = 0; i < ofbi->num_overlays; ++i) {
1257+ if ((ofbi->overlays[i]->supported_modes & mode) == 0) {
1258+ DBG("invalid mode\n");
1259+ return -EINVAL;
1260+ }
1261+ }
1262+
1263+ if (var->rotate < 0 || var->rotate > 3)
1264+ return -EINVAL;
1265+
1266+ if (var->rotate != fbi->var.rotate) {
1267+ DBG("rotation changing\n");
1268+
1269+ ofbi->rotation = var->rotate;
1270+
1271+ if (abs(var->rotate - fbi->var.rotate) != 2) {
1272+ int tmp;
1273+ DBG("rotate changing 90/270 degrees. "
1274+ "swapping x/y res\n");
1275+
1276+ tmp = var->yres;
1277+ var->yres = var->xres;
1278+ var->xres = tmp;
1279+
1280+ tmp = var->yres_virtual;
1281+ var->yres_virtual = var->xres_virtual;
1282+ var->xres_virtual = tmp;
1283+ }
1284+ }
1285+
1286+ xres_min = OMAPFB_PLANE_XRES_MIN;
1287+ xres_max = 2048;
1288+ yres_min = OMAPFB_PLANE_YRES_MIN;
1289+ yres_max = 2048;
1290+
1291+ bytespp = var->bits_per_pixel >> 3;
1292+
1293+ /* XXX: some applications seem to set virtual res to 0. */
1294+ if (var->xres_virtual == 0)
1295+ var->xres_virtual = var->xres;
1296+
1297+ if (var->yres_virtual == 0)
1298+ var->yres_virtual = var->yres;
1299+
1300+ if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
1301+ return -EINVAL;
1302+
1303+ if (var->xres < xres_min)
1304+ var->xres = xres_min;
1305+ if (var->yres < yres_min)
1306+ var->yres = yres_min;
1307+ if (var->xres > xres_max)
1308+ var->xres = xres_max;
1309+ if (var->yres > yres_max)
1310+ var->yres = yres_max;
1311+
1312+ if (var->xres > var->xres_virtual)
1313+ var->xres = var->xres_virtual;
1314+ if (var->yres > var->yres_virtual)
1315+ var->yres = var->yres_virtual;
1316+
1317+ if (ofbi->rotation_type == OMAPFB_ROT_VRFB)
1318+ line_size = OMAP_VRFB_LINE_LEN * bytespp;
1319+ else
1320+ line_size = var->xres_virtual * bytespp;
1321+
1322+ max_frame_size = ofbi->region.size;
1323+
1324+ DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
1325+
1326+ if (line_size * var->yres_virtual > max_frame_size) {
1327+ DBG("can't fit FB into memory, reducing y\n");
1328+ var->yres_virtual = max_frame_size / line_size;
1329+
1330+ if (var->yres_virtual < yres_min)
1331+ var->yres_virtual = yres_min;
1332+
1333+ if (var->yres > var->yres_virtual)
1334+ var->yres = var->yres_virtual;
1335+ }
1336+
1337+ if (line_size * var->yres_virtual > max_frame_size) {
1338+ DBG("can't fit FB into memory, reducing x\n");
1339+ if (ofbi->rotation_type == OMAPFB_ROT_VRFB)
1340+ return -EINVAL;
1341+
1342+ var->xres_virtual = max_frame_size / var->yres_virtual /
1343+ bytespp;
1344+
1345+ if (var->xres_virtual < xres_min)
1346+ var->xres_virtual = xres_min;
1347+
1348+ if (var->xres > var->xres_virtual)
1349+ var->xres = var->xres_virtual;
1350+
1351+ line_size = var->xres_virtual * bytespp;
1352+ }
1353+
1354+ if (line_size * var->yres_virtual > max_frame_size) {
1355+ DBG("cannot fit FB to memory\n");
1356+ return -EINVAL;
1357+ }
1358+
1359+ if (var->xres + var->xoffset > var->xres_virtual)
1360+ var->xoffset = var->xres_virtual - var->xres;
1361+ if (var->yres + var->yoffset > var->yres_virtual)
1362+ var->yoffset = var->yres_virtual - var->yres;
1363+
1364+ DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",
1365+ var->xres, var->yres,
1366+ var->xres_virtual, var->yres_virtual);
1367+
1368+ var->height = -1;
1369+ var->width = -1;
1370+ var->grayscale = 0;
1371+
1372+ if (display && display->get_timings) {
1373+ struct omap_video_timings timings;
1374+ display->get_timings(display, &timings);
1375+
1376+ /* pixclock in ps, the rest in pixclock */
1377+ var->pixclock = timings.pixel_clock != 0 ?
1378+ KHZ2PICOS(timings.pixel_clock) :
1379+ 0;
1380+ var->left_margin = timings.hfp;
1381+ var->right_margin = timings.hbp;
1382+ var->upper_margin = timings.vfp;
1383+ var->lower_margin = timings.vbp;
1384+ var->hsync_len = timings.hsw;
1385+ var->vsync_len = timings.vsw;
1386+ } else {
1387+ var->pixclock = 0;
1388+ var->left_margin = 0;
1389+ var->right_margin = 0;
1390+ var->upper_margin = 0;
1391+ var->lower_margin = 0;
1392+ var->hsync_len = 0;
1393+ var->vsync_len = 0;
1394+ }
1395+
1396+ /* TODO: get these from panel->config */
1397+ var->vmode = FB_VMODE_NONINTERLACED;
1398+ var->sync = 0;
1399+
1400+ return 0;
1401+}
1402+
1403+/*
1404+ * ---------------------------------------------------------------------------
1405+ * fbdev framework callbacks
1406+ * ---------------------------------------------------------------------------
1407+ */
1408+static int omapfb_open(struct fb_info *fbi, int user)
1409+{
1410+ return 0;
1411+}
1412+
1413+static int omapfb_release(struct fb_info *fbi, int user)
1414+{
1415+ struct omapfb_info *ofbi = FB2OFB(fbi);
1416+ struct omapfb2_device *fbdev = ofbi->fbdev;
1417+ struct omap_display *display = fb2display(fbi);
1418+
1419+ DBG("Closing fb with plane index %d\n", ofbi->id);
1420+
1421+ omapfb_lock(fbdev);
1422+#if 1
1423+ if (display && display->get_update_mode && display->update) {
1424+ /* XXX this update should be removed, I think. But it's
1425+ * good for debugging */
1426+ if (display->get_update_mode(display) ==
1427+ OMAP_DSS_UPDATE_MANUAL) {
1428+ u16 w, h;
1429+
1430+ if (display->sync)
1431+ display->sync(display);
1432+
1433+ display->get_resolution(display, &w, &h);
1434+ display->update(display, 0, 0, w, h);
1435+ }
1436+ }
1437+#endif
1438+
1439+ if (display && display->sync)
1440+ display->sync(display);
1441+
1442+ omapfb_unlock(fbdev);
1443+
1444+ return 0;
1445+}
1446+
1447+/* setup overlay according to the fb */
1448+static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
1449+ u16 posx, u16 posy, u16 outw, u16 outh)
1450+{
1451+ int r = 0;
1452+ struct omapfb_info *ofbi = FB2OFB(fbi);
1453+ struct fb_var_screeninfo *var = &fbi->var;
1454+ struct fb_fix_screeninfo *fix = &fbi->fix;
1455+ enum omap_color_mode mode = 0;
1456+ int offset;
1457+ u32 data_start_p;
1458+ void __iomem *data_start_v;
1459+ struct omap_overlay_info info;
1460+ int xres, yres;
1461+ int screen_width;
1462+ int rot, mirror;
1463+
1464+ DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
1465+ posx, posy, outw, outh);
1466+
1467+ if (ofbi->rotation == FB_ROTATE_CW || ofbi->rotation == FB_ROTATE_CCW) {
1468+ xres = var->yres;
1469+ yres = var->xres;
1470+ } else {
1471+ xres = var->xres;
1472+ yres = var->yres;
1473+ }
1474+
1475+ offset = ((var->yoffset * var->xres_virtual +
1476+ var->xoffset) * var->bits_per_pixel) >> 3;
1477+
1478+ if (ofbi->rotation_type == OMAPFB_ROT_VRFB) {
1479+ data_start_p = omapfb_get_region_rot_paddr(ofbi);
1480+ data_start_v = NULL;
1481+ } else {
1482+ data_start_p = omapfb_get_region_paddr(ofbi);
1483+ data_start_v = omapfb_get_region_vaddr(ofbi);
1484+ }
1485+
1486+ data_start_p += offset;
1487+ data_start_v += offset;
1488+
1489+ mode = fb_mode_to_dss_mode(var);
1490+
1491+ if (mode == -EINVAL) {
1492+ DBG("fb_mode_to_dss_mode failed");
1493+ r = -EINVAL;
1494+ goto err;
1495+ }
1496+
1497+ screen_width = fix->line_length / (var->bits_per_pixel >> 3);
1498+
1499+ ovl->get_overlay_info(ovl, &info);
1500+
1501+ if (ofbi->rotation_type == OMAPFB_ROT_VRFB) {
1502+ rot = 0;
1503+ mirror = 0;
1504+ } else {
1505+ rot = ofbi->rotation;
1506+ mirror = ofbi->mirror;
1507+ }
1508+
1509+ info.paddr = data_start_p;
1510+ info.vaddr = data_start_v;
1511+ info.screen_width = screen_width;
1512+ info.width = xres;
1513+ info.height = yres;
1514+ info.color_mode = mode;
1515+ info.rotation = rot;
1516+ info.mirror = mirror;
1517+
1518+ info.pos_x = posx;
1519+ info.pos_y = posy;
1520+ info.out_width = outw;
1521+ info.out_height = outh;
1522+
1523+ r = ovl->set_overlay_info(ovl, &info);
1524+ if (r) {
1525+ DBG("ovl->setup_overlay_info failed\n");
1526+ goto err;
1527+ }
1528+
1529+ return 0;
1530+
1531+err:
1532+ DBG("setup_overlay failed\n");
1533+ return r;
1534+}
1535+
1536+/* apply var to the overlay */
1537+int omapfb_apply_changes(struct fb_info *fbi, int init)
1538+{
1539+ int r = 0;
1540+ struct omapfb_info *ofbi = FB2OFB(fbi);
1541+ struct fb_var_screeninfo *var = &fbi->var;
1542+ struct omap_overlay *ovl;
1543+ u16 posx, posy;
1544+ u16 outw, outh;
1545+ int i;
1546+
1547+#ifdef DEBUG
1548+ if (omapfb_test_pattern)
1549+ fill_fb(fbi);
1550+#endif
1551+
1552+ for (i = 0; i < ofbi->num_overlays; i++) {
1553+ ovl = ofbi->overlays[i];
1554+
1555+ DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
1556+
1557+ if (ofbi->region.size == 0) {
1558+ /* the fb is not available. disable the overlay */
1559+ omapfb_overlay_enable(ovl, 0);
1560+ if (!init && ovl->manager)
1561+ ovl->manager->apply(ovl->manager);
1562+ continue;
1563+ }
1564+
1565+ if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
1566+ if (ofbi->rotation == FB_ROTATE_CW ||
1567+ ofbi->rotation == FB_ROTATE_CCW) {
1568+ outw = var->yres;
1569+ outh = var->xres;
1570+ } else {
1571+ outw = var->xres;
1572+ outh = var->yres;
1573+ }
1574+ } else {
1575+ outw = ovl->info.out_width;
1576+ outh = ovl->info.out_height;
1577+ }
1578+
1579+ if (init) {
1580+ posx = 0;
1581+ posy = 0;
1582+ } else {
1583+ posx = ovl->info.pos_x;
1584+ posy = ovl->info.pos_y;
1585+ }
1586+
1587+ r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
1588+ if (r)
1589+ goto err;
1590+
1591+ if (!init && ovl->manager)
1592+ ovl->manager->apply(ovl->manager);
1593+ }
1594+ return 0;
1595+err:
1596+ DBG("apply_changes failed\n");
1597+ return r;
1598+}
1599+
1600+/* checks var and eventually tweaks it to something supported,
1601+ * DO NOT MODIFY PAR */
1602+static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
1603+{
1604+ int r;
1605+
1606+ DBG("check_var(%d)\n", FB2OFB(fbi)->id);
1607+
1608+ r = check_fb_var(fbi, var);
1609+
1610+ return r;
1611+}
1612+
1613+/* set the video mode according to info->var */
1614+static int omapfb_set_par(struct fb_info *fbi)
1615+{
1616+ int r;
1617+
1618+ DBG("set_par(%d)\n", FB2OFB(fbi)->id);
1619+
1620+ set_fb_fix(fbi);
1621+ r = omapfb_apply_changes(fbi, 0);
1622+
1623+ return r;
1624+}
1625+
1626+static int omapfb_pan_display(struct fb_var_screeninfo *var,
1627+ struct fb_info *fbi)
1628+{
1629+ struct omapfb_info *ofbi = FB2OFB(fbi);
1630+ struct omapfb2_device *fbdev = ofbi->fbdev;
1631+ int r = 0;
1632+
1633+ DBG("pan_display(%d)\n", ofbi->id);
1634+
1635+ omapfb_lock(fbdev);
1636+
1637+ if (var->xoffset != fbi->var.xoffset ||
1638+ var->yoffset != fbi->var.yoffset) {
1639+ struct fb_var_screeninfo new_var;
1640+
1641+ new_var = fbi->var;
1642+ new_var.xoffset = var->xoffset;
1643+ new_var.yoffset = var->yoffset;
1644+
1645+ r = check_fb_var(fbi, &new_var);
1646+
1647+ if (r == 0) {
1648+ fbi->var = new_var;
1649+ set_fb_fix(fbi);
1650+ r = omapfb_apply_changes(fbi, 0);
1651+ }
1652+ }
1653+
1654+ omapfb_unlock(fbdev);
1655+
1656+ return r;
1657+}
1658+
1659+static void mmap_user_open(struct vm_area_struct *vma)
1660+{
1661+ struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
1662+
1663+ atomic_inc(&ofbi->map_count);
1664+}
1665+
1666+static void mmap_user_close(struct vm_area_struct *vma)
1667+{
1668+ struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
1669+
1670+ atomic_dec(&ofbi->map_count);
1671+}
1672+
1673+static struct vm_operations_struct mmap_user_ops = {
1674+ .open = mmap_user_open,
1675+ .close = mmap_user_close,
1676+};
1677+
1678+static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
1679+{
1680+ struct omapfb_info *ofbi = FB2OFB(fbi);
1681+ struct fb_fix_screeninfo *fix = &fbi->fix;
1682+ unsigned long off;
1683+ unsigned long start;
1684+ u32 len;
1685+
1686+ if (vma->vm_end - vma->vm_start == 0)
1687+ return 0;
1688+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1689+ return -EINVAL;
1690+ off = vma->vm_pgoff << PAGE_SHIFT;
1691+
1692+ start = omapfb_get_region_paddr(ofbi);
1693+ len = fix->smem_len;
1694+ if (off >= len)
1695+ return -EINVAL;
1696+ if ((vma->vm_end - vma->vm_start + off) > len)
1697+ return -EINVAL;
1698+
1699+ off += start;
1700+
1701+ DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
1702+
1703+ vma->vm_pgoff = off >> PAGE_SHIFT;
1704+ vma->vm_flags |= VM_IO | VM_RESERVED;
1705+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1706+ vma->vm_ops = &mmap_user_ops;
1707+ vma->vm_private_data = ofbi;
1708+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
1709+ vma->vm_end - vma->vm_start, vma->vm_page_prot))
1710+ return -EAGAIN;
1711+ /* vm_ops.open won't be called for mmap itself. */
1712+ atomic_inc(&ofbi->map_count);
1713+ return 0;
1714+}
1715+
1716+/* Store a single color palette entry into a pseudo palette or the hardware
1717+ * palette if one is available. For now we support only 16bpp and thus store
1718+ * the entry only to the pseudo palette.
1719+ */
1720+static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
1721+ u_int blue, u_int transp, int update_hw_pal)
1722+{
1723+ /*struct omapfb_info *ofbi = FB2OFB(fbi);*/
1724+ /*struct omapfb2_device *fbdev = ofbi->fbdev;*/
1725+ struct fb_var_screeninfo *var = &fbi->var;
1726+ int r = 0;
1727+
1728+ enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
1729+
1730+ /*switch (plane->color_mode) {*/
1731+ switch (mode) {
1732+ case OMAPFB_COLOR_YUV422:
1733+ case OMAPFB_COLOR_YUV420:
1734+ case OMAPFB_COLOR_YUY422:
1735+ r = -EINVAL;
1736+ break;
1737+ case OMAPFB_COLOR_CLUT_8BPP:
1738+ case OMAPFB_COLOR_CLUT_4BPP:
1739+ case OMAPFB_COLOR_CLUT_2BPP:
1740+ case OMAPFB_COLOR_CLUT_1BPP:
1741+ /*
1742+ if (fbdev->ctrl->setcolreg)
1743+ r = fbdev->ctrl->setcolreg(regno, red, green, blue,
1744+ transp, update_hw_pal);
1745+ */
1746+ /* Fallthrough */
1747+ r = -EINVAL;
1748+ break;
1749+ case OMAPFB_COLOR_RGB565:
1750+ case OMAPFB_COLOR_RGB444:
1751+ case OMAPFB_COLOR_RGB24P:
1752+ case OMAPFB_COLOR_RGB24U:
1753+ if (r != 0)
1754+ break;
1755+
1756+ if (regno < 0) {
1757+ r = -EINVAL;
1758+ break;
1759+ }
1760+
1761+ if (regno < 16) {
1762+ u16 pal;
1763+ pal = ((red >> (16 - var->red.length)) <<
1764+ var->red.offset) |
1765+ ((green >> (16 - var->green.length)) <<
1766+ var->green.offset) |
1767+ (blue >> (16 - var->blue.length));
1768+ ((u32 *)(fbi->pseudo_palette))[regno] = pal;
1769+ }
1770+ break;
1771+ default:
1772+ BUG();
1773+ }
1774+ return r;
1775+}
1776+
1777+static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1778+ u_int transp, struct fb_info *info)
1779+{
1780+ DBG("setcolreg\n");
1781+
1782+ return _setcolreg(info, regno, red, green, blue, transp, 1);
1783+}
1784+
1785+static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1786+{
1787+ int count, index, r;
1788+ u16 *red, *green, *blue, *transp;
1789+ u16 trans = 0xffff;
1790+
1791+ DBG("setcmap\n");
1792+
1793+ red = cmap->red;
1794+ green = cmap->green;
1795+ blue = cmap->blue;
1796+ transp = cmap->transp;
1797+ index = cmap->start;
1798+
1799+ for (count = 0; count < cmap->len; count++) {
1800+ if (transp)
1801+ trans = *transp++;
1802+ r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
1803+ count == cmap->len - 1);
1804+ if (r != 0)
1805+ return r;
1806+ }
1807+
1808+ return 0;
1809+}
1810+
1811+static int omapfb_blank(int blank, struct fb_info *fbi)
1812+{
1813+ struct omapfb_info *ofbi = FB2OFB(fbi);
1814+ struct omapfb2_device *fbdev = ofbi->fbdev;
1815+ struct omap_display *display = fb2display(fbi);
1816+ int do_update = 0;
1817+ int r = 0;
1818+
1819+ omapfb_lock(fbdev);
1820+
1821+ switch (blank) {
1822+ case FB_BLANK_UNBLANK:
1823+ if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
1824+ goto exit;
1825+
1826+ if (display->resume)
1827+ r = display->resume(display);
1828+
1829+ if (r == 0 && display->get_update_mode &&
1830+ display->get_update_mode(display) ==
1831+ OMAP_DSS_UPDATE_MANUAL)
1832+ do_update = 1;
1833+
1834+ break;
1835+
1836+ case FB_BLANK_NORMAL:
1837+ /* FB_BLANK_NORMAL could be implemented.
1838+ * Needs DSS additions. */
1839+ case FB_BLANK_VSYNC_SUSPEND:
1840+ case FB_BLANK_HSYNC_SUSPEND:
1841+ case FB_BLANK_POWERDOWN:
1842+ if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
1843+ goto exit;
1844+
1845+ if (display->suspend)
1846+ r = display->suspend(display);
1847+
1848+ break;
1849+
1850+ default:
1851+ r = -EINVAL;
1852+ }
1853+
1854+exit:
1855+ omapfb_unlock(fbdev);
1856+
1857+ if (r == 0 && do_update && display->update) {
1858+ u16 w, h;
1859+ display->get_resolution(display, &w, &h);
1860+
1861+ r = display->update(display, 0, 0, w, h);
1862+ }
1863+
1864+ return r;
1865+}
1866+
1867+#if 0
1868+/* XXX fb_read and fb_write are needed for VRFB */
1869+ssize_t omapfb_write(struct fb_info *info, const char __user *buf,
1870+ size_t count, loff_t *ppos)
1871+{
1872+ DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
1873+ // XXX needed for VRFB
1874+ return count;
1875+}
1876+#endif
1877+
1878+static struct fb_ops omapfb_ops = {
1879+ .owner = THIS_MODULE,
1880+ .fb_open = omapfb_open,
1881+ .fb_release = omapfb_release,
1882+ .fb_fillrect = cfb_fillrect,
1883+ .fb_copyarea = cfb_copyarea,
1884+ .fb_imageblit = cfb_imageblit,
1885+ .fb_blank = omapfb_blank,
1886+ .fb_ioctl = omapfb_ioctl,
1887+ .fb_check_var = omapfb_check_var,
1888+ .fb_set_par = omapfb_set_par,
1889+ .fb_pan_display = omapfb_pan_display,
1890+ .fb_mmap = omapfb_mmap,
1891+ .fb_setcolreg = omapfb_setcolreg,
1892+ .fb_setcmap = omapfb_setcmap,
1893+ //.fb_write = omapfb_write,
1894+};
1895+
1896+static void omapfb_free_fbmem(struct fb_info *fbi)
1897+{
1898+ struct omapfb_info *ofbi = FB2OFB(fbi);
1899+ struct omapfb2_device *fbdev = ofbi->fbdev;
1900+ struct omapfb2_mem_region *rg;
1901+
1902+ rg = &ofbi->region;
1903+
1904+ if (rg->paddr)
1905+ if (omap_vram_free(rg->paddr, rg->size))
1906+ dev_err(fbdev->dev, "VRAM FREE failed\n");
1907+
1908+ if (rg->vaddr)
1909+ iounmap(rg->vaddr);
1910+
1911+ if (ofbi->rotation_type == OMAPFB_ROT_VRFB) {
1912+ /* unmap the 0 angle rotation */
1913+ if (rg->vrfb.vaddr[0]) {
1914+ iounmap(rg->vrfb.vaddr[0]);
1915+ omap_vrfb_release_ctx(&rg->vrfb);
1916+ }
1917+ }
1918+
1919+ rg->vaddr = NULL;
1920+ rg->paddr = 0;
1921+ rg->alloc = 0;
1922+ rg->size = 0;
1923+}
1924+
1925+static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
1926+{
1927+ int i;
1928+
1929+ DBG("free all fbmem\n");
1930+
1931+ for (i = 0; i < fbdev->num_fbs; i++) {
1932+ struct fb_info *fbi = fbdev->fbs[i];
1933+ omapfb_free_fbmem(fbi);
1934+ memset(&fbi->fix, 0, sizeof(fbi->fix));
1935+ memset(&fbi->var, 0, sizeof(fbi->var));
1936+ }
1937+
1938+ return 0;
1939+}
1940+
1941+static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
1942+ unsigned long paddr)
1943+{
1944+ struct omapfb_info *ofbi = FB2OFB(fbi);
1945+ struct omapfb2_device *fbdev = ofbi->fbdev;
1946+ struct omapfb2_mem_region *rg;
1947+ void __iomem *vaddr;
1948+ int r;
1949+ int clear = 0;
1950+
1951+ rg = &ofbi->region;
1952+ memset(rg, 0, sizeof(*rg));
1953+
1954+ size = PAGE_ALIGN(size);
1955+
1956+ if (!paddr) {
1957+ DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
1958+ r = omap_vram_alloc(OMAPFB_MEMTYPE_SDRAM, size, &paddr);
1959+ clear = 1;
1960+ } else {
1961+ DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
1962+ ofbi->id);
1963+ r = omap_vram_reserve(paddr, size);
1964+ }
1965+
1966+ if (r) {
1967+ dev_err(fbdev->dev, "failed to allocate framebuffer\n");
1968+ return -ENOMEM;
1969+ }
1970+
1971+ if (ofbi->rotation_type != OMAPFB_ROT_VRFB) {
1972+ vaddr = ioremap_wc(paddr, size);
1973+
1974+ if (!vaddr) {
1975+ dev_err(fbdev->dev, "failed to ioremap framebuffer\n");
1976+ omap_vram_free(paddr, size);
1977+ return -ENOMEM;
1978+ }
1979+
1980+ DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
1981+
1982+ if (clear)
1983+ memset_io(vaddr, 0, size);
1984+ } else {
1985+ void __iomem *va;
1986+
1987+ r = omap_vrfb_request_ctx(&rg->vrfb);
1988+ if (r) {
1989+ dev_err(fbdev->dev, "vrfb create ctx failed\n");
1990+ return r;
1991+ }
1992+
1993+ /* only ioremap the 0 angle view */
1994+ va = ioremap_wc(rg->vrfb.paddr[0], size);
1995+
1996+ if(!va) {
1997+ printk(KERN_ERR "vrfb: ioremap failed\n");
1998+ return -ENOMEM;
1999+ }
2000+
2001+ DBG("ioremapped vrfb area 0 to %p\n", va);
2002+
2003+ rg->vrfb.vaddr[0] = va;
2004+
2005+ vaddr = NULL;
2006+
2007+ if (clear)
2008+ memset_io(va, 0, size);
2009+ }
2010+
2011+ rg->paddr = paddr;
2012+ rg->vaddr = vaddr;
2013+ rg->size = size;
2014+ rg->alloc = 1;
2015+
2016+ return 0;
2017+}
2018+
2019+/* allocate fbmem using display resolution as reference */
2020+static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
2021+ unsigned long paddr)
2022+{
2023+ struct omapfb_info *ofbi = FB2OFB(fbi);
2024+ struct omap_display *display;
2025+ int bytespp;
2026+
2027+ display = fb2display(fbi);
2028+
2029+ if (!display)
2030+ return 0;
2031+
2032+ switch (display->get_recommended_bpp(display)) {
2033+ case 16:
2034+ bytespp = 2;
2035+ break;
2036+ case 24:
2037+ bytespp = 4;
2038+ break;
2039+ default:
2040+ bytespp = 4;
2041+ break;
2042+ }
2043+
2044+ if (!size) {
2045+ u16 w, h;
2046+
2047+ display->get_resolution(display, &w, &h);
2048+
2049+ if (ofbi->rotation_type == OMAPFB_ROT_VRFB) {
2050+ int oldw = w, oldh = h;
2051+
2052+ omap_vrfb_adjust_size(&w, &h, bytespp);
2053+
2054+ /* Because we change the resolution of the 0 degree view,
2055+ * we need to alloc max(w, h) for height */
2056+ h = max(w, h);
2057+ w = OMAP_VRFB_LINE_LEN;
2058+
2059+ DBG("adjusting fb mem size for VRFB, %dx%d -> %dx%d\n",
2060+ oldw, oldh, w, h);
2061+ }
2062+
2063+ size = w * h * bytespp;
2064+ }
2065+
2066+ return omapfb_alloc_fbmem(fbi, size, paddr);
2067+}
2068+
2069+static int omapfb_parse_vram_param(const char *param, int max_entries,
2070+ unsigned long *sizes, unsigned long *paddrs)
2071+{
2072+ int fbnum;
2073+ unsigned long size;
2074+ unsigned long paddr = 0;
2075+ char *p, *start;
2076+
2077+ start = (char *)param;
2078+
2079+ while (1) {
2080+ p = start;
2081+
2082+ fbnum = simple_strtoul(p, &p, 10);
2083+
2084+ if (p == param)
2085+ return -EINVAL;
2086+
2087+ if (*p != ':')
2088+ return -EINVAL;
2089+
2090+ if (fbnum >= max_entries)
2091+ return -EINVAL;
2092+
2093+ size = memparse(p + 1, &p);
2094+
2095+ if (!size)
2096+ return -EINVAL;
2097+
2098+ paddr = 0;
2099+
2100+ if (*p == '@') {
2101+ paddr = simple_strtoul(p + 1, &p, 16);
2102+
2103+ if (!paddr)
2104+ return -EINVAL;
2105+
2106+ }
2107+
2108+ paddrs[fbnum] = paddr;
2109+ sizes[fbnum] = size;
2110+
2111+ if (*p == 0)
2112+ break;
2113+
2114+ if (*p != ',')
2115+ return -EINVAL;
2116+
2117+ ++p;
2118+
2119+ start = p;
2120+ }
2121+
2122+ return 0;
2123+}
2124+
2125+static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
2126+{
2127+ int i, r;
2128+ unsigned long vram_sizes[10];
2129+ unsigned long vram_paddrs[10];
2130+
2131+ memset(&vram_sizes, 0, sizeof(vram_sizes));
2132+ memset(&vram_paddrs, 0, sizeof(vram_paddrs));
2133+
2134+ if (def_vram && omapfb_parse_vram_param(def_vram, 10,
2135+ vram_sizes, vram_paddrs)) {
2136+ dev_err(fbdev->dev, "failed to parse vram parameter\n");
2137+
2138+ memset(&vram_sizes, 0, sizeof(vram_sizes));
2139+ memset(&vram_paddrs, 0, sizeof(vram_paddrs));
2140+ }
2141+
2142+ if (fbdev->dev->platform_data) {
2143+ struct omapfb_platform_data *opd;
2144+ opd = fbdev->dev->platform_data;
2145+ for (i = 0; i < opd->mem_desc.region_cnt; ++i) {
2146+ if (!vram_sizes[i]) {
2147+ unsigned long size;
2148+ unsigned long paddr;
2149+
2150+ size = opd->mem_desc.region[i].size;
2151+ paddr = opd->mem_desc.region[i].paddr;
2152+
2153+ vram_sizes[i] = size;
2154+ vram_paddrs[i] = paddr;
2155+ }
2156+ }
2157+ }
2158+
2159+ for (i = 0; i < fbdev->num_fbs; i++) {
2160+ /* allocate memory automatically only for fb0, or if
2161+ * excplicitly defined with vram or plat data option */
2162+ if (i == 0 || vram_sizes[i] != 0) {
2163+ r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
2164+ vram_sizes[i], vram_paddrs[i]);
2165+
2166+ if (r)
2167+ return r;
2168+ }
2169+ }
2170+
2171+ for (i = 0; i < fbdev->num_fbs; i++) {
2172+ struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
2173+ struct omapfb2_mem_region *rg;
2174+ rg = &ofbi->region;
2175+
2176+ DBG("region%d phys %08x virt %p size=%lu\n",
2177+ i,
2178+ rg->paddr,
2179+ rg->vaddr,
2180+ rg->size);
2181+ }
2182+
2183+ return 0;
2184+}
2185+
2186+int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
2187+{
2188+ struct omapfb_info *ofbi = FB2OFB(fbi);
2189+ struct omapfb2_device *fbdev = ofbi->fbdev;
2190+ struct omap_display *display = fb2display(fbi);
2191+ struct omapfb2_mem_region *rg = &ofbi->region;
2192+ unsigned long old_size = rg->size;
2193+ unsigned long old_paddr = rg->paddr;
2194+ int old_type = rg->type;
2195+ int r;
2196+
2197+ if (type > OMAPFB_MEMTYPE_MAX)
2198+ return -EINVAL;
2199+
2200+ size = PAGE_ALIGN(size);
2201+
2202+ if (old_size == size && old_type == type)
2203+ return 0;
2204+
2205+ if (display && display->sync)
2206+ display->sync(display);
2207+
2208+ omapfb_free_fbmem(fbi);
2209+
2210+ if (size == 0) {
2211+ memset(&fbi->fix, 0, sizeof(fbi->fix));
2212+ memset(&fbi->var, 0, sizeof(fbi->var));
2213+ return 0;
2214+ }
2215+
2216+ r = omapfb_alloc_fbmem(fbi, size, 0);
2217+
2218+ if (r) {
2219+ if (old_size)
2220+ omapfb_alloc_fbmem(fbi, old_size, old_paddr);
2221+
2222+ if (rg->size == 0) {
2223+ memset(&fbi->fix, 0, sizeof(fbi->fix));
2224+ memset(&fbi->var, 0, sizeof(fbi->var));
2225+ }
2226+
2227+ return r;
2228+ }
2229+
2230+ if (old_size == size)
2231+ return 0;
2232+
2233+ if (old_size == 0) {
2234+ DBG("initializing fb %d\n", ofbi->id);
2235+ r = omapfb_fb_init(fbdev, fbi);
2236+ if (r) {
2237+ DBG("omapfb_fb_init failed\n");
2238+ goto err;
2239+ }
2240+ r = omapfb_apply_changes(fbi, 1);
2241+ if (r) {
2242+ DBG("omapfb_apply_changes failed\n");
2243+ goto err;
2244+ }
2245+ } else {
2246+ struct fb_var_screeninfo new_var;
2247+ memcpy(&new_var, &fbi->var, sizeof(new_var));
2248+ r = check_fb_var(fbi, &new_var);
2249+ if (r)
2250+ goto err;
2251+ memcpy(&fbi->var, &new_var, sizeof(fbi->var));
2252+ set_fb_fix(fbi);
2253+ }
2254+
2255+ return 0;
2256+err:
2257+ omapfb_free_fbmem(fbi);
2258+ memset(&fbi->fix, 0, sizeof(fbi->fix));
2259+ memset(&fbi->var, 0, sizeof(fbi->var));
2260+ return r;
2261+}
2262+
2263+/* initialize fb_info, var, fix to something sane based on the display */
2264+int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
2265+{
2266+ struct fb_var_screeninfo *var = &fbi->var;
2267+ struct fb_fix_screeninfo *fix = &fbi->fix;
2268+ struct omap_display *display = fb2display(fbi);
2269+ struct omapfb_info *ofbi = FB2OFB(fbi);
2270+ int r = 0;
2271+
2272+ fbi->fbops = &omapfb_ops;
2273+ fbi->flags = FBINFO_FLAG_DEFAULT;
2274+ fbi->pseudo_palette = fbdev->pseudo_palette;
2275+
2276+ strncpy(fix->id, MODULE_NAME, sizeof(fix->id));
2277+
2278+ if (ofbi->region.size == 0) {
2279+ memset(&fbi->fix, 0, sizeof(fbi->fix));
2280+ memset(&fbi->var, 0, sizeof(fbi->var));
2281+ return 0;
2282+ }
2283+
2284+ var->nonstd = 0;
2285+
2286+ var->rotate = ofbi->rotation;
2287+
2288+ if (display) {
2289+ u16 w, h;
2290+ display->get_resolution(display, &w, &h);
2291+
2292+ if (ofbi->rotation == FB_ROTATE_CW ||
2293+ ofbi->rotation == FB_ROTATE_CCW) {
2294+ var->xres = h;
2295+ var->yres = w;
2296+ } else {
2297+ var->xres = w;
2298+ var->yres = h;
2299+ }
2300+
2301+ var->xres_virtual = var->xres;
2302+ var->yres_virtual = var->yres;
2303+
2304+ switch (display->get_recommended_bpp(display)) {
2305+ case 16:
2306+ var->bits_per_pixel = 16;
2307+ break;
2308+ case 24:
2309+ var->bits_per_pixel = 32;
2310+ break;
2311+ default:
2312+ dev_err(fbdev->dev, "illegal display bpp\n");
2313+ return -EINVAL;
2314+ }
2315+ } else {
2316+ /* if there's no display, let's just guess some basic values */
2317+ var->xres = 320;
2318+ var->yres = 240;
2319+ var->xres_virtual = var->xres;
2320+ var->yres_virtual = var->yres;
2321+ var->bits_per_pixel = 16;
2322+ }
2323+
2324+ r = check_fb_var(fbi, var);
2325+ if (r)
2326+ goto err;
2327+
2328+ set_fb_fix(fbi);
2329+err:
2330+ return r;
2331+}
2332+
2333+static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
2334+{
2335+ fb_dealloc_cmap(&fbi->cmap);
2336+}
2337+
2338+
2339+static void omapfb_free_resources(struct omapfb2_device *fbdev)
2340+{
2341+ int i;
2342+
2343+ DBG("free_resources\n");
2344+
2345+ if (fbdev == NULL)
2346+ return;
2347+
2348+ for (i = 0; i < fbdev->num_fbs; i++)
2349+ unregister_framebuffer(fbdev->fbs[i]);
2350+
2351+ /* free the reserved fbmem */
2352+ omapfb_free_all_fbmem(fbdev);
2353+
2354+ for (i = 0; i < fbdev->num_fbs; i++) {
2355+ fbinfo_cleanup(fbdev, fbdev->fbs[i]);
2356+ framebuffer_release(fbdev->fbs[i]);
2357+ }
2358+
2359+ for (i = 0; i < fbdev->num_displays; i++) {
2360+ if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
2361+ fbdev->displays[i]->disable(fbdev->displays[i]);
2362+
2363+ omap_dss_put_display(fbdev->displays[i]);
2364+ }
2365+
2366+ dev_set_drvdata(fbdev->dev, NULL);
2367+ kfree(fbdev);
2368+}
2369+
2370+static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
2371+{
2372+ int r, i;
2373+
2374+ fbdev->num_fbs = 0;
2375+
2376+ DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
2377+
2378+ /* allocate fb_infos */
2379+ for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
2380+ struct fb_info *fbi;
2381+ struct omapfb_info *ofbi;
2382+
2383+ fbi = framebuffer_alloc(sizeof(struct omapfb_info),
2384+ fbdev->dev);
2385+
2386+ if (fbi == NULL) {
2387+ dev_err(fbdev->dev,
2388+ "unable to allocate memory for plane info\n");
2389+ return -ENOMEM;
2390+ }
2391+
2392+ fbdev->fbs[i] = fbi;
2393+
2394+ ofbi = FB2OFB(fbi);
2395+ ofbi->fbdev = fbdev;
2396+ ofbi->id = i;
2397+
2398+ /* assign these early, so that fb alloc can use them */
2399+ ofbi->rotation_type = def_vrfb ? OMAPFB_ROT_VRFB :
2400+ OMAPFB_ROT_DMA;
2401+ ofbi->rotation = def_rotate;
2402+ ofbi->mirror = def_mirror;
2403+
2404+ fbdev->num_fbs++;
2405+ }
2406+
2407+ DBG("fb_infos allocated\n");
2408+
2409+ /* assign overlays for the fbs */
2410+ for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
2411+ struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
2412+
2413+ ofbi->overlays[0] = fbdev->overlays[i];
2414+ ofbi->num_overlays = 1;
2415+ }
2416+
2417+ /* allocate fb memories */
2418+ r = omapfb_allocate_all_fbs(fbdev);
2419+ if (r) {
2420+ dev_err(fbdev->dev, "failed to allocate fbmem\n");
2421+ return r;
2422+ }
2423+
2424+ DBG("fbmems allocated\n");
2425+
2426+ /* setup fb_infos */
2427+ for (i = 0; i < fbdev->num_fbs; i++) {
2428+ r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
2429+ if (r) {
2430+ dev_err(fbdev->dev, "failed to setup fb_info\n");
2431+ return r;
2432+ }
2433+ }
2434+
2435+ DBG("fb_infos initialized\n");
2436+
2437+ for (i = 0; i < fbdev->num_fbs; i++) {
2438+ r = register_framebuffer(fbdev->fbs[i]);
2439+ if (r != 0) {
2440+ dev_err(fbdev->dev,
2441+ "registering framebuffer %d failed\n", i);
2442+ return r;
2443+ }
2444+ }
2445+
2446+ DBG("framebuffers registered\n");
2447+
2448+ for (i = 0; i < fbdev->num_fbs; i++) {
2449+ r = omapfb_apply_changes(fbdev->fbs[i], 1);
2450+ if (r) {
2451+ dev_err(fbdev->dev, "failed to change mode\n");
2452+ return r;
2453+ }
2454+ }
2455+
2456+ DBG("create sysfs for fbs\n");
2457+ r = omapfb_create_sysfs(fbdev);
2458+ if (r) {
2459+ dev_err(fbdev->dev, "failed to create sysfs entries\n");
2460+ return r;
2461+ }
2462+
2463+ /* Enable fb0 */
2464+ if (fbdev->num_fbs > 0) {
2465+ struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
2466+
2467+ if (ofbi->num_overlays > 0 ) {
2468+ struct omap_overlay *ovl = ofbi->overlays[0];
2469+
2470+ r = omapfb_overlay_enable(ovl, 1);
2471+
2472+ if (r) {
2473+ dev_err(fbdev->dev,
2474+ "failed to enable overlay\n");
2475+ return r;
2476+ }
2477+ }
2478+ }
2479+
2480+ DBG("create_framebuffers done\n");
2481+
2482+ return 0;
2483+}
2484+
2485+int omapfb_mode_to_timings(const char *mode_str,
2486+ struct omap_video_timings *timings, u8 *bpp)
2487+{
2488+ struct fb_info fbi;
2489+ struct fb_var_screeninfo var;
2490+ struct fb_ops fbops;
2491+ int r;
2492+
2493+#ifdef CONFIG_OMAP2_DSS_VENC
2494+ if (strcmp(mode_str, "pal") == 0) {
2495+ *timings = omap_dss_pal_timings;
2496+ *bpp = 0;
2497+ return 0;
2498+ } else if (strcmp(mode_str, "ntsc") == 0) {
2499+ *timings = omap_dss_ntsc_timings;
2500+ *bpp = 0;
2501+ return 0;
2502+ }
2503+#endif
2504+
2505+ /* this is quite a hack, but I wanted to use the modedb and for
2506+ * that we need fb_info and var, so we create dummy ones */
2507+
2508+ memset(&fbi, 0, sizeof(fbi));
2509+ memset(&var, 0, sizeof(var));
2510+ memset(&fbops, 0, sizeof(fbops));
2511+ fbi.fbops = &fbops;
2512+
2513+ r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);
2514+
2515+ if (r != 0) {
2516+ timings->pixel_clock = PICOS2KHZ(var.pixclock);
2517+ timings->hfp = var.left_margin;
2518+ timings->hbp = var.right_margin;
2519+ timings->vfp = var.upper_margin;
2520+ timings->vbp = var.lower_margin;
2521+ timings->hsw = var.hsync_len;
2522+ timings->vsw = var.vsync_len;
2523+ timings->x_res = var.xres;
2524+ timings->y_res = var.yres;
2525+
2526+ switch (var.bits_per_pixel) {
2527+ case 16:
2528+ *bpp = 16;
2529+ break;
2530+ case 24:
2531+ case 32:
2532+ default:
2533+ *bpp = 24;
2534+ break;
2535+ }
2536+
2537+ return 0;
2538+ } else {
2539+ return -EINVAL;
2540+ }
2541+}
2542+
2543+static int omapfb_set_def_mode(struct omap_display *display, char *mode_str)
2544+{
2545+ int r;
2546+ u8 bpp;
2547+ struct omap_video_timings timings;
2548+
2549+ r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
2550+ if (r)
2551+ return r;
2552+
2553+ display->panel->recommended_bpp = bpp;
2554+
2555+ if (!display->check_timings || !display->set_timings)
2556+ return -EINVAL;
2557+
2558+ r = display->check_timings(display, &timings);
2559+ if (r)
2560+ return r;
2561+
2562+ display->set_timings(display, &timings);
2563+
2564+ return 0;
2565+}
2566+
2567+static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
2568+{
2569+ char *str, *options, *this_opt;
2570+ int r = 0;
2571+
2572+ str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);
2573+ strcpy(str, def_mode);
2574+ options = str;
2575+
2576+ while (!r && (this_opt = strsep(&options, ",")) != NULL) {
2577+ char *p, *display_str, *mode_str;
2578+ struct omap_display *display;
2579+ int i;
2580+
2581+ p = strchr(this_opt, ':');
2582+ if (!p) {
2583+ r = -EINVAL;
2584+ break;
2585+ }
2586+
2587+ *p = 0;
2588+ display_str = this_opt;
2589+ mode_str = p + 1;
2590+
2591+ display = NULL;
2592+ for (i = 0; i < fbdev->num_displays; ++i) {
2593+ if (strcmp(fbdev->displays[i]->name,
2594+ display_str) == 0) {
2595+ display = fbdev->displays[i];
2596+ break;
2597+ }
2598+ }
2599+
2600+ if (!display) {
2601+ r = -EINVAL;
2602+ break;
2603+ }
2604+
2605+ r = omapfb_set_def_mode(display, mode_str);
2606+ if (r)
2607+ break;
2608+ }
2609+
2610+ kfree(str);
2611+
2612+ return r;
2613+}
2614+
2615+static int omapfb_probe(struct platform_device *pdev)
2616+{
2617+ struct omapfb2_device *fbdev = NULL;
2618+ int r = 0;
2619+ int i, t;
2620+ struct omap_overlay *ovl;
2621+ struct omap_display *def_display;
2622+
2623+ DBG("omapfb_probe\n");
2624+
2625+ if (pdev->num_resources != 0) {
2626+ dev_err(&pdev->dev, "probed for an unknown device\n");
2627+ r = -ENODEV;
2628+ goto err0;
2629+ }
2630+
2631+ fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);
2632+ if (fbdev == NULL) {
2633+ r = -ENOMEM;
2634+ goto err0;
2635+ }
2636+
2637+ mutex_init(&fbdev->mtx);
2638+
2639+ fbdev->dev = &pdev->dev;
2640+ platform_set_drvdata(pdev, fbdev);
2641+
2642+ fbdev->num_displays = 0;
2643+ t = omap_dss_get_num_displays();
2644+ for (i = 0; i < t; i++) {
2645+ struct omap_display *display;
2646+ display = omap_dss_get_display(i);
2647+ if (!display) {
2648+ dev_err(&pdev->dev, "can't get display %d\n", i);
2649+ r = -EINVAL;
2650+ goto cleanup;
2651+ }
2652+
2653+ fbdev->displays[fbdev->num_displays++] = display;
2654+ }
2655+
2656+ if (fbdev->num_displays == 0) {
2657+ dev_err(&pdev->dev, "no displays\n");
2658+ r = -EINVAL;
2659+ goto cleanup;
2660+ }
2661+
2662+ fbdev->num_overlays = omap_dss_get_num_overlays();
2663+ for (i = 0; i < fbdev->num_overlays; i++)
2664+ fbdev->overlays[i] = omap_dss_get_overlay(i);
2665+
2666+ fbdev->num_managers = omap_dss_get_num_overlay_managers();
2667+ for (i = 0; i < fbdev->num_managers; i++)
2668+ fbdev->managers[i] = omap_dss_get_overlay_manager(i);
2669+
2670+
2671+ /* gfx overlay should be the default one. find a display
2672+ * connected to that, and use it as default display */
2673+ ovl = omap_dss_get_overlay(0);
2674+ if (ovl->manager && ovl->manager->display) {
2675+ def_display = ovl->manager->display;
2676+ } else {
2677+ dev_err(&pdev->dev, "cannot find default display\n");
2678+ r = -EINVAL;
2679+ goto cleanup;
2680+ }
2681+
2682+ if (def_mode && strlen(def_mode) > 0) {
2683+ if (omapfb_parse_def_modes(fbdev))
2684+ dev_err(&pdev->dev, "cannot parse default modes\n");
2685+ }
2686+
2687+ r = omapfb_create_framebuffers(fbdev);
2688+ if (r)
2689+ goto cleanup;
2690+
2691+ for (i = 0; i < fbdev->num_managers; i++) {
2692+ struct omap_overlay_manager *mgr;
2693+ mgr = fbdev->managers[i];
2694+ r = mgr->apply(mgr);
2695+ if (r) {
2696+ dev_err(fbdev->dev, "failed to apply dispc config\n");
2697+ goto cleanup;
2698+ }
2699+ }
2700+
2701+ DBG("mgr->apply'ed\n");
2702+
2703+ r = def_display->enable(def_display);
2704+ if (r) {
2705+ dev_err(fbdev->dev, "Failed to enable display '%s'\n",
2706+ def_display->name);
2707+ goto cleanup;
2708+ }
2709+
2710+ /* set the update mode */
2711+ if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
2712+#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
2713+ if (def_display->set_update_mode)
2714+ def_display->set_update_mode(def_display,
2715+ OMAP_DSS_UPDATE_AUTO);
2716+ if (def_display->enable_te)
2717+ def_display->enable_te(def_display, 1);
2718+#else
2719+ if (def_display->set_update_mode)
2720+ def_display->set_update_mode(def_display,
2721+ OMAP_DSS_UPDATE_MANUAL);
2722+ if (def_display->enable_te)
2723+ def_display->enable_te(def_display, 0);
2724+#endif
2725+ } else {
2726+ if (def_display->set_update_mode)
2727+ def_display->set_update_mode(def_display,
2728+ OMAP_DSS_UPDATE_AUTO);
2729+ }
2730+
2731+ for (i = 0; i < fbdev->num_displays; i++) {
2732+ struct omap_display *display = fbdev->displays[i];
2733+ u16 w, h;
2734+
2735+ if (!display->get_update_mode || !display->update)
2736+ continue;
2737+
2738+ if (display->get_update_mode(display) ==
2739+ OMAP_DSS_UPDATE_MANUAL) {
2740+
2741+ display->get_resolution(display, &w, &h);
2742+ display->update(display, 0, 0, w, h);
2743+ }
2744+ }
2745+
2746+ DBG("display->updated\n");
2747+
2748+ return 0;
2749+
2750+cleanup:
2751+ omapfb_free_resources(fbdev);
2752+err0:
2753+ dev_err(&pdev->dev, "failed to setup omapfb\n");
2754+ return r;
2755+}
2756+
2757+static int omapfb_remove(struct platform_device *pdev)
2758+{
2759+ struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
2760+
2761+ /* FIXME: wait till completion of pending events */
2762+
2763+ omapfb_remove_sysfs(fbdev);
2764+
2765+ omapfb_free_resources(fbdev);
2766+
2767+ return 0;
2768+}
2769+
2770+static struct platform_driver omapfb_driver = {
2771+ .probe = omapfb_probe,
2772+ .remove = omapfb_remove,
2773+ .driver = {
2774+ .name = "omapfb",
2775+ .owner = THIS_MODULE,
2776+ },
2777+};
2778+
2779+static int __init omapfb_init(void)
2780+{
2781+ DBG("omapfb_init\n");
2782+
2783+ if (platform_driver_register(&omapfb_driver)) {
2784+ printk(KERN_ERR "failed to register omapfb driver\n");
2785+ return -ENODEV;
2786+ }
2787+
2788+ return 0;
2789+}
2790+
2791+static void __exit omapfb_exit(void)
2792+{
2793+ DBG("omapfb_exit\n");
2794+ platform_driver_unregister(&omapfb_driver);
2795+}
2796+
2797+module_param_named(mode, def_mode, charp, 0);
2798+module_param_named(vram, def_vram, charp, 0);
2799+module_param_named(rotate, def_rotate, int, 0);
2800+module_param_named(vrfb, def_vrfb, bool, 0);
2801+module_param_named(mirror, def_mirror, bool, 0);
2802+
2803+/* late_initcall to let panel/ctrl drivers loaded first.
2804+ * I guess better option would be a more dynamic approach,
2805+ * so that omapfb reacts to new panels when they are loaded */
2806+late_initcall(omapfb_init);
2807+/*module_init(omapfb_init);*/
2808+module_exit(omapfb_exit);
2809+
2810+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
2811+MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
2812+MODULE_LICENSE("GPL v2");
2813diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
2814new file mode 100644
2815index 0000000..2c88718
2816--- /dev/null
2817+++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
2818@@ -0,0 +1,371 @@
2819+/*
2820+ * linux/drivers/video/omap2/omapfb-sysfs.c
2821+ *
2822+ * Copyright (C) 2008 Nokia Corporation
2823+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
2824+ *
2825+ * Some code and ideas taken from drivers/video/omap/ driver
2826+ * by Imre Deak.
2827+ *
2828+ * This program is free software; you can redistribute it and/or modify it
2829+ * under the terms of the GNU General Public License version 2 as published by
2830+ * the Free Software Foundation.
2831+ *
2832+ * This program is distributed in the hope that it will be useful, but WITHOUT
2833+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2834+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
2835+ * more details.
2836+ *
2837+ * You should have received a copy of the GNU General Public License along with
2838+ * this program. If not, see <http://www.gnu.org/licenses/>.
2839+ */
2840+
2841+#include <linux/fb.h>
2842+#include <linux/sysfs.h>
2843+#include <linux/device.h>
2844+#include <linux/uaccess.h>
2845+#include <linux/platform_device.h>
2846+#include <linux/kernel.h>
2847+#include <linux/mm.h>
2848+#include <linux/omapfb.h>
2849+
2850+#include <mach/display.h>
2851+#include <mach/vrfb.h>
2852+
2853+#include "omapfb.h"
2854+
2855+static ssize_t show_rotate_type(struct device *dev,
2856+ struct device_attribute *attr, char *buf)
2857+{
2858+ struct fb_info *fbi = dev_get_drvdata(dev);
2859+ struct omapfb_info *ofbi = FB2OFB(fbi);
2860+
2861+ return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
2862+}
2863+
2864+static ssize_t show_mirror(struct device *dev,
2865+ struct device_attribute *attr, char *buf)
2866+{
2867+ struct fb_info *fbi = dev_get_drvdata(dev);
2868+ struct omapfb_info *ofbi = FB2OFB(fbi);
2869+
2870+ return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
2871+}
2872+
2873+static ssize_t store_mirror(struct device *dev,
2874+ struct device_attribute *attr,
2875+ const char *buf, size_t count)
2876+{
2877+ struct fb_info *fbi = dev_get_drvdata(dev);
2878+ struct omapfb_info *ofbi = FB2OFB(fbi);
2879+ struct omapfb2_device *fbdev = ofbi->fbdev;
2880+ bool mirror;
2881+ int r;
2882+ struct fb_var_screeninfo new_var;
2883+
2884+ mirror = simple_strtoul(buf, NULL, 0);
2885+
2886+ if (mirror != 0 && mirror != 1)
2887+ return -EINVAL;
2888+
2889+ omapfb_lock(fbdev);
2890+
2891+ ofbi->mirror = mirror;
2892+
2893+ memcpy(&new_var, &fbi->var, sizeof(new_var));
2894+ r = check_fb_var(fbi, &new_var);
2895+ if (r)
2896+ goto out;
2897+ memcpy(&fbi->var, &new_var, sizeof(fbi->var));
2898+
2899+ set_fb_fix(fbi);
2900+
2901+ r = omapfb_apply_changes(fbi, 0);
2902+ if (r)
2903+ goto out;
2904+
2905+ r = count;
2906+out:
2907+ omapfb_unlock(fbdev);
2908+
2909+ return r;
2910+}
2911+
2912+static ssize_t show_overlays(struct device *dev,
2913+ struct device_attribute *attr, char *buf)
2914+{
2915+ struct fb_info *fbi = dev_get_drvdata(dev);
2916+ struct omapfb_info *ofbi = FB2OFB(fbi);
2917+ struct omapfb2_device *fbdev = ofbi->fbdev;
2918+ ssize_t l = 0;
2919+ int t;
2920+
2921+ for (t = 0; t < ofbi->num_overlays; t++) {
2922+ struct omap_overlay *ovl = ofbi->overlays[t];
2923+ int ovlnum;
2924+
2925+ for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
2926+ if (ovl == fbdev->overlays[ovlnum])
2927+ break;
2928+
2929+ l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
2930+ t == 0 ? "" : ",", ovlnum);
2931+ }
2932+
2933+ l += snprintf(buf + l, PAGE_SIZE - l, "\n");
2934+
2935+ return l;
2936+}
2937+
2938+static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
2939+ struct omap_overlay *ovl)
2940+{
2941+ int i, t;
2942+
2943+ for (i = 0; i < fbdev->num_fbs; i++) {
2944+ struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
2945+
2946+ for (t = 0; t < ofbi->num_overlays; t++) {
2947+ if (ofbi->overlays[t] == ovl)
2948+ return ofbi;
2949+ }
2950+ }
2951+
2952+ return NULL;
2953+}
2954+
2955+static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
2956+ const char *buf, size_t count)
2957+{
2958+ struct fb_info *fbi = dev_get_drvdata(dev);
2959+ struct omapfb_info *ofbi = FB2OFB(fbi);
2960+ struct omapfb2_device *fbdev = ofbi->fbdev;
2961+ struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
2962+ struct omap_overlay *ovl;
2963+ int num_ovls, r, i;
2964+ int len;
2965+
2966+ num_ovls = 0;
2967+
2968+ len = strlen(buf);
2969+ if (buf[len - 1] == '\n')
2970+ len = len - 1;
2971+
2972+ omapfb_lock(fbdev);
2973+
2974+ if (len > 0) {
2975+ char *p = (char *)buf;
2976+ int ovlnum;
2977+
2978+ while (p < buf + len) {
2979+ int found;
2980+ if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
2981+ r = -EINVAL;
2982+ goto out;
2983+ }
2984+
2985+ ovlnum = simple_strtoul(p, &p, 0);
2986+ if (ovlnum > fbdev->num_overlays) {
2987+ r = -EINVAL;
2988+ goto out;
2989+ }
2990+
2991+ found = 0;
2992+ for (i = 0; i < num_ovls; ++i) {
2993+ if (ovls[i] == fbdev->overlays[ovlnum]) {
2994+ found = 1;
2995+ break;
2996+ }
2997+ }
2998+
2999+ if (!found)
3000+ ovls[num_ovls++] = fbdev->overlays[ovlnum];
3001+
3002+ p++;
3003+ }
3004+ }
3005+
3006+ for (i = 0; i < num_ovls; ++i) {
3007+ struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
3008+ if (ofbi2 && ofbi2 != ofbi) {
3009+ dev_err(fbdev->dev, "overlay already in use\n");
3010+ r = -EINVAL;
3011+ goto out;
3012+ }
3013+ }
3014+
3015+ /* detach unused overlays */
3016+ for (i = 0; i < ofbi->num_overlays; ++i) {
3017+ int t, found;
3018+
3019+ ovl = ofbi->overlays[i];
3020+
3021+ found = 0;
3022+
3023+ for (t = 0; t < num_ovls; ++t) {
3024+ if (ovl == ovls[t]) {
3025+ found = 1;
3026+ break;
3027+ }
3028+ }
3029+
3030+ if (found)
3031+ continue;
3032+
3033+ DBG("detaching %d\n", ofbi->overlays[i]->id);
3034+
3035+ omapfb_overlay_enable(ovl, 0);
3036+
3037+ if (ovl->manager)
3038+ ovl->manager->apply(ovl->manager);
3039+
3040+ for (t = i + 1; t < ofbi->num_overlays; t++)
3041+ ofbi->overlays[t-1] = ofbi->overlays[t];
3042+
3043+ ofbi->num_overlays--;
3044+ i--;
3045+ }
3046+
3047+ for (i = 0; i < num_ovls; ++i) {
3048+ int t, found;
3049+
3050+ ovl = ovls[i];
3051+
3052+ found = 0;
3053+
3054+ for (t = 0; t < ofbi->num_overlays; ++t) {
3055+ if (ovl == ofbi->overlays[t]) {
3056+ found = 1;
3057+ break;
3058+ }
3059+ }
3060+
3061+ if (found)
3062+ continue;
3063+
3064+ ofbi->overlays[ofbi->num_overlays++] = ovl;
3065+
3066+ r = omapfb_apply_changes(fbi, 1);
3067+ if (r)
3068+ goto out;
3069+
3070+ if (ovl->manager) {
3071+ r = ovl->manager->apply(ovl->manager);
3072+ if (r)
3073+ goto out;
3074+ }
3075+ }
3076+
3077+ r = count;
3078+out:
3079+ omapfb_unlock(fbdev);
3080+
3081+ return r;
3082+}
3083+
3084+static ssize_t show_size(struct device *dev,
3085+ struct device_attribute *attr, char *buf)
3086+{
3087+ struct fb_info *fbi = dev_get_drvdata(dev);
3088+ struct omapfb_info *ofbi = FB2OFB(fbi);
3089+
3090+ return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size);
3091+}
3092+
3093+static ssize_t store_size(struct device *dev, struct device_attribute *attr,
3094+ const char *buf, size_t count)
3095+{
3096+ struct fb_info *fbi = dev_get_drvdata(dev);
3097+ struct omapfb_info *ofbi = FB2OFB(fbi);
3098+ struct omapfb2_device *fbdev = ofbi->fbdev;
3099+ unsigned long size;
3100+ int r;
3101+ int i;
3102+
3103+ size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
3104+
3105+ omapfb_lock(fbdev);
3106+
3107+ for (i = 0; i < ofbi->num_overlays; i++) {
3108+ if (ofbi->overlays[i]->info.enabled) {
3109+ r = -EBUSY;
3110+ goto out;
3111+ }
3112+ }
3113+
3114+ if (size != ofbi->region.size) {
3115+ r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type);
3116+ if (r) {
3117+ dev_err(dev, "realloc fbmem failed\n");
3118+ goto out;
3119+ }
3120+ }
3121+
3122+ r = count;
3123+out:
3124+ omapfb_unlock(fbdev);
3125+
3126+ return r;
3127+}
3128+
3129+static ssize_t show_phys(struct device *dev,
3130+ struct device_attribute *attr, char *buf)
3131+{
3132+ struct fb_info *fbi = dev_get_drvdata(dev);
3133+ struct omapfb_info *ofbi = FB2OFB(fbi);
3134+
3135+ return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr);
3136+}
3137+
3138+static ssize_t show_virt(struct device *dev,
3139+ struct device_attribute *attr, char *buf)
3140+{
3141+ struct fb_info *fbi = dev_get_drvdata(dev);
3142+ struct omapfb_info *ofbi = FB2OFB(fbi);
3143+
3144+ return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr);
3145+}
3146+
3147+static struct device_attribute omapfb_attrs[] = {
3148+ __ATTR(rotate_type, S_IRUGO, show_rotate_type, NULL),
3149+ __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
3150+ __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
3151+ __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
3152+ __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
3153+ __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
3154+};
3155+
3156+int omapfb_create_sysfs(struct omapfb2_device *fbdev)
3157+{
3158+ int i;
3159+ int r;
3160+
3161+ DBG("create sysfs for fbs\n");
3162+ for (i = 0; i < fbdev->num_fbs; i++) {
3163+ int t;
3164+ for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
3165+ r = device_create_file(fbdev->fbs[i]->dev,
3166+ &omapfb_attrs[t]);
3167+
3168+ if (r) {
3169+ dev_err(fbdev->dev, "failed to create sysfs file\n");
3170+ return r;
3171+ }
3172+ }
3173+ }
3174+
3175+ return 0;
3176+}
3177+
3178+void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
3179+{
3180+ int i, t;
3181+
3182+ DBG("remove sysfs for fbs\n");
3183+ for (i = 0; i < fbdev->num_fbs; i++) {
3184+ for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
3185+ device_remove_file(fbdev->fbs[i]->dev,
3186+ &omapfb_attrs[t]);
3187+ }
3188+}
3189+
3190diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
3191new file mode 100644
3192index 0000000..65e9e6e
3193--- /dev/null
3194+++ b/drivers/video/omap2/omapfb/omapfb.h
3195@@ -0,0 +1,153 @@
3196+/*
3197+ * linux/drivers/video/omap2/omapfb.h
3198+ *
3199+ * Copyright (C) 2008 Nokia Corporation
3200+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
3201+ *
3202+ * Some code and ideas taken from drivers/video/omap/ driver
3203+ * by Imre Deak.
3204+ *
3205+ * This program is free software; you can redistribute it and/or modify it
3206+ * under the terms of the GNU General Public License version 2 as published by
3207+ * the Free Software Foundation.
3208+ *
3209+ * This program is distributed in the hope that it will be useful, but WITHOUT
3210+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3211+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
3212+ * more details.
3213+ *
3214+ * You should have received a copy of the GNU General Public License along with
3215+ * this program. If not, see <http://www.gnu.org/licenses/>.
3216+ */
3217+
3218+#ifndef __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
3219+#define __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
3220+
3221+#ifdef CONFIG_FB_OMAP2_DEBUG_SUPPORT
3222+#define DEBUG
3223+#endif
3224+
3225+#ifdef DEBUG
3226+extern unsigned int omapfb_debug;
3227+#define DBG(format, ...) \
3228+ if (omapfb_debug) \
3229+ printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__)
3230+#else
3231+#define DBG(format, ...)
3232+#endif
3233+
3234+#define FB2OFB(fb_info) ((struct omapfb_info *)(fb_info->par))
3235+
3236+/* max number of overlays to which a framebuffer data can be direct */
3237+#define OMAPFB_MAX_OVL_PER_FB 3
3238+
3239+struct omapfb2_mem_region {
3240+ u32 paddr;
3241+ void __iomem *vaddr;
3242+ struct vrfb vrfb;
3243+ unsigned long size;
3244+ u8 type; /* OMAPFB_PLANE_MEM_* */
3245+ bool alloc; /* allocated by the driver */
3246+ bool map; /* kernel mapped by the driver */
3247+};
3248+
3249+enum omapfb_rotation_type {
3250+ OMAPFB_ROT_DMA = 0,
3251+ OMAPFB_ROT_VRFB = 1,
3252+};
3253+
3254+/* appended to fb_info */
3255+struct omapfb_info {
3256+ int id;
3257+ struct omapfb2_mem_region region;
3258+ atomic_t map_count;
3259+ int num_overlays;
3260+ struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB];
3261+ struct omapfb2_device *fbdev;
3262+ enum omapfb_rotation_type rotation_type;
3263+ u8 rotation;
3264+ bool mirror;
3265+};
3266+
3267+struct omapfb2_device {
3268+ struct device *dev;
3269+ struct mutex mtx;
3270+
3271+ u32 pseudo_palette[17];
3272+
3273+ int state;
3274+
3275+ unsigned num_fbs;
3276+ struct fb_info *fbs[10];
3277+
3278+ unsigned num_displays;
3279+ struct omap_display *displays[10];
3280+ unsigned num_overlays;
3281+ struct omap_overlay *overlays[10];
3282+ unsigned num_managers;
3283+ struct omap_overlay_manager *managers[10];
3284+};
3285+
3286+struct omapfb_colormode {
3287+ enum omap_color_mode dssmode;
3288+ u32 bits_per_pixel;
3289+ u32 nonstd;
3290+ struct fb_bitfield red;
3291+ struct fb_bitfield green;
3292+ struct fb_bitfield blue;
3293+ struct fb_bitfield transp;
3294+};
3295+
3296+u32 omapfb_get_region_paddr(struct omapfb_info *ofbi);
3297+void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi);
3298+
3299+void set_fb_fix(struct fb_info *fbi);
3300+int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var);
3301+int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type);
3302+int omapfb_apply_changes(struct fb_info *fbi, int init);
3303+int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
3304+
3305+int omapfb_create_sysfs(struct omapfb2_device *fbdev);
3306+void omapfb_remove_sysfs(struct omapfb2_device *fbdev);
3307+
3308+int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg);
3309+
3310+int omapfb_mode_to_timings(const char *mode_str,
3311+ struct omap_video_timings *timings, u8 *bpp);
3312+
3313+/* find the display connected to this fb, if any */
3314+static inline struct omap_display *fb2display(struct fb_info *fbi)
3315+{
3316+ struct omapfb_info *ofbi = FB2OFB(fbi);
3317+ int i;
3318+
3319+ /* XXX: returns the display connected to first attached overlay */
3320+ for (i = 0; i < ofbi->num_overlays; i++) {
3321+ if (ofbi->overlays[i]->manager)
3322+ return ofbi->overlays[i]->manager->display;
3323+ }
3324+
3325+ return NULL;
3326+}
3327+
3328+static inline void omapfb_lock(struct omapfb2_device *fbdev)
3329+{
3330+ mutex_lock(&fbdev->mtx);
3331+}
3332+
3333+static inline void omapfb_unlock(struct omapfb2_device *fbdev)
3334+{
3335+ mutex_unlock(&fbdev->mtx);
3336+}
3337+
3338+static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
3339+ int enable)
3340+{
3341+ struct omap_overlay_info info;
3342+
3343+ ovl->get_overlay_info(ovl, &info);
3344+ info.enabled = enable;
3345+ return ovl->set_overlay_info(ovl, &info);
3346+}
3347+
3348+#endif
3349diff --git a/include/linux/omapfb.h b/include/linux/omapfb.h
3350index b226bdf..96190b2 100644
3351--- a/include/linux/omapfb.h
3352+++ b/include/linux/omapfb.h
3353@@ -50,6 +50,8 @@
3354 #define OMAPFB_UPDATE_WINDOW OMAP_IOW(54, struct omapfb_update_window)
3355 #define OMAPFB_SETUP_MEM OMAP_IOW(55, struct omapfb_mem_info)
3356 #define OMAPFB_QUERY_MEM OMAP_IOW(56, struct omapfb_mem_info)
3357+#define OMAPFB_WAITFORVSYNC OMAP_IO(57)
3358+#define OMAPFB_MEMORY_READ OMAP_IOR(58, struct omapfb_memory_read)
3359
3360 #define OMAPFB_CAPS_GENERIC_MASK 0x00000fff
3361 #define OMAPFB_CAPS_LCDC_MASK 0x00fff000
3362@@ -90,6 +92,13 @@ enum omapfb_color_format {
3363 OMAPFB_COLOR_CLUT_1BPP,
3364 OMAPFB_COLOR_RGB444,
3365 OMAPFB_COLOR_YUY422,
3366+
3367+ OMAPFB_COLOR_ARGB16,
3368+ OMAPFB_COLOR_RGB24U, /* RGB24, 32-bit container */
3369+ OMAPFB_COLOR_RGB24P, /* RGB24, 24-bit container */
3370+ OMAPFB_COLOR_ARGB32,
3371+ OMAPFB_COLOR_RGBA32,
3372+ OMAPFB_COLOR_RGBX32,
3373 };
3374
3375 struct omapfb_update_window {
3376@@ -161,6 +170,15 @@ enum omapfb_update_mode {
3377 OMAPFB_MANUAL_UPDATE
3378 };
3379
3380+struct omapfb_memory_read {
3381+ __u16 x;
3382+ __u16 y;
3383+ __u16 w;
3384+ __u16 h;
3385+ size_t buffer_size;
3386+ void __user *buffer;
3387+};
3388+
3389 #ifdef __KERNEL__
3390
3391 #include <linux/completion.h>
3392@@ -376,6 +394,8 @@ extern struct lcd_ctrl omap1_lcd_ctrl;
3393 extern struct lcd_ctrl omap2_disp_ctrl;
3394 #endif
3395
3396+extern void omapfb_set_platform_data(struct omapfb_platform_data *data);
3397+
3398 extern void omapfb_reserve_sdram(void);
3399 extern void omapfb_register_panel(struct lcd_panel *panel);
3400 extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
3401--
34021.5.6.5
3403