summaryrefslogtreecommitdiffstats
path: root/meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0004-DSS2-OMAP-framebuffer-driver.patch
diff options
context:
space:
mode:
authorRichard Purdie <rpurdie@linux.intel.com>2010-08-27 15:14:24 +0100
committerRichard Purdie <rpurdie@linux.intel.com>2010-08-27 15:29:45 +0100
commit29d6678fd546377459ef75cf54abeef5b969b5cf (patch)
tree8edd65790e37a00d01c3f203f773fe4b5012db18 /meta/recipes-kernel/linux/linux-omap-2.6.29/dss2/0004-DSS2-OMAP-framebuffer-driver.patch
parentda49de6885ee1bc424e70bc02f21f6ab920efb55 (diff)
downloadpoky-29d6678fd546377459ef75cf54abeef5b969b5cf.tar.gz
Major layout change to the packages directory
Having one monolithic packages directory makes it hard to find things and is generally overwhelming. This commit splits it into several logical sections roughly based on function, recipes.txt gives more information about the classifications used. The opportunity is also used to switch from "packages" to "recipes" as used in OpenEmbedded as the term "packages" can be confusing to people and has many different meanings. Not all recipes have been classified yet, this is just a first pass at separating things out. Some packages are moved to meta-extras as they're no longer actively used or maintained. Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
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