aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@nokia.com>2009-08-04 09:12:50 -0400
committerTomi Valkeinen <tomi.valkeinen@nokia.com>2009-12-09 05:12:44 -0500
commitb39a982ddecf1d95ed96f8457c39d3ea11df93f6 (patch)
tree07d233ede4b49bddb2776ee013cbdf5621e7845b /drivers/video
parent3de7a1dc0c9d29b138713ecb85df4b6ca3af2ef3 (diff)
OMAP: DSS2: omapfb driver
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/omap/Kconfig5
-rw-r--r--drivers/video/omap2/Kconfig1
-rw-r--r--drivers/video/omap2/Makefile1
-rw-r--r--drivers/video/omap2/omapfb/Kconfig37
-rw-r--r--drivers/video/omap2/omapfb/Makefile2
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c755
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c2261
-rw-r--r--drivers/video/omap2/omapfb/omapfb-sysfs.c507
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h146
9 files changed, 3713 insertions, 2 deletions
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
index 551e3e9c4cbe..455c6055325d 100644
--- a/drivers/video/omap/Kconfig
+++ b/drivers/video/omap/Kconfig
@@ -1,6 +1,7 @@
1config FB_OMAP 1config FB_OMAP
2 tristate "OMAP frame buffer support (EXPERIMENTAL)" 2 tristate "OMAP frame buffer support (EXPERIMENTAL)"
3 depends on FB && ARCH_OMAP 3 depends on FB && ARCH_OMAP && (OMAP2_DSS = "n")
4
4 select FB_CFB_FILLRECT 5 select FB_CFB_FILLRECT
5 select FB_CFB_COPYAREA 6 select FB_CFB_COPYAREA
6 select FB_CFB_IMAGEBLIT 7 select FB_CFB_IMAGEBLIT
@@ -72,7 +73,7 @@ config FB_OMAP_LCD_MIPID
72 73
73config FB_OMAP_BOOTLOADER_INIT 74config FB_OMAP_BOOTLOADER_INIT
74 bool "Check bootloader initialization" 75 bool "Check bootloader initialization"
75 depends on FB_OMAP 76 depends on FB_OMAP || FB_OMAP2
76 help 77 help
77 Say Y here if you want to enable checking if the bootloader has 78 Say Y here if you want to enable checking if the bootloader has
78 already initialized the display controller. In this case the 79 already initialized the display controller. In this case the
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig
index 55b4c4265f57..3e60d7e88540 100644
--- a/drivers/video/omap2/Kconfig
+++ b/drivers/video/omap2/Kconfig
@@ -5,3 +5,4 @@ config OMAP2_VRFB
5 bool 5 bool
6 6
7source "drivers/video/omap2/dss/Kconfig" 7source "drivers/video/omap2/dss/Kconfig"
8source "drivers/video/omap2/omapfb/Kconfig"
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile
index ee0644f9d3c1..3ba6ef5e30d4 100644
--- a/drivers/video/omap2/Makefile
+++ b/drivers/video/omap2/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_OMAP2_VRAM) += vram.o
2obj-$(CONFIG_OMAP2_VRFB) += vrfb.o 2obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
3 3
4obj-y += dss/ 4obj-y += dss/
5obj-y += omapfb/
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
new file mode 100644
index 000000000000..bb694cc52a50
--- /dev/null
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -0,0 +1,37 @@
1menuconfig FB_OMAP2
2 tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)"
3 depends on FB && OMAP2_DSS
4
5 select OMAP2_VRAM
6 select OMAP2_VRFB
7 select FB_CFB_FILLRECT
8 select FB_CFB_COPYAREA
9 select FB_CFB_IMAGEBLIT
10 help
11 Frame buffer driver for OMAP2/3 based boards.
12
13config FB_OMAP2_DEBUG_SUPPORT
14 bool "Debug support for OMAP2/3 FB"
15 default y
16 depends on FB_OMAP2
17 help
18 Support for debug output. You have to enable the actual printing
19 with debug module parameter.
20
21config FB_OMAP2_FORCE_AUTO_UPDATE
22 bool "Force main display to automatic update mode"
23 depends on FB_OMAP2
24 help
25 Forces main display to automatic update mode (if possible),
26 and also enables tearsync (if possible). By default
27 displays that support manual update are started in manual
28 update mode.
29
30config FB_OMAP2_NUM_FBS
31 int "Number of framebuffers"
32 range 1 10
33 default 3
34 depends on FB_OMAP2
35 help
36 Select the number of framebuffers created. OMAP2/3 has 3 overlays
37 so normally this would be 3.
diff --git a/drivers/video/omap2/omapfb/Makefile b/drivers/video/omap2/omapfb/Makefile
new file mode 100644
index 000000000000..51c2e00d9bf8
--- /dev/null
+++ b/drivers/video/omap2/omapfb/Makefile
@@ -0,0 +1,2 @@
1obj-$(CONFIG_FB_OMAP2) += omapfb.o
2omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
new file mode 100644
index 000000000000..4c4bafdfaa43
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -0,0 +1,755 @@
1/*
2 * linux/drivers/video/omap2/omapfb-ioctl.c
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <linux/fb.h>
24#include <linux/device.h>
25#include <linux/uaccess.h>
26#include <linux/platform_device.h>
27#include <linux/mm.h>
28#include <linux/omapfb.h>
29#include <linux/vmalloc.h>
30
31#include <plat/display.h>
32#include <plat/vrfb.h>
33#include <plat/vram.h>
34
35#include "omapfb.h"
36
37static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
38{
39 struct omapfb_info *ofbi = FB2OFB(fbi);
40 struct omapfb2_device *fbdev = ofbi->fbdev;
41 struct omap_overlay *ovl;
42 struct omap_overlay_info info;
43 int r = 0;
44
45 DBG("omapfb_setup_plane\n");
46
47 if (ofbi->num_overlays != 1) {
48 r = -EINVAL;
49 goto out;
50 }
51
52 /* XXX uses only the first overlay */
53 ovl = ofbi->overlays[0];
54
55 if (pi->enabled && !ofbi->region.size) {
56 /*
57 * This plane's memory was freed, can't enable it
58 * until it's reallocated.
59 */
60 r = -EINVAL;
61 goto out;
62 }
63
64 ovl->get_overlay_info(ovl, &info);
65
66 info.pos_x = pi->pos_x;
67 info.pos_y = pi->pos_y;
68 info.out_width = pi->out_width;
69 info.out_height = pi->out_height;
70 info.enabled = pi->enabled;
71
72 r = ovl->set_overlay_info(ovl, &info);
73 if (r)
74 goto out;
75
76 if (ovl->manager) {
77 r = ovl->manager->apply(ovl->manager);
78 if (r)
79 goto out;
80 }
81
82out:
83 if (r)
84 dev_err(fbdev->dev, "setup_plane failed\n");
85 return r;
86}
87
88static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
89{
90 struct omapfb_info *ofbi = FB2OFB(fbi);
91
92 if (ofbi->num_overlays != 1) {
93 memset(pi, 0, sizeof(*pi));
94 } else {
95 struct omap_overlay_info *ovli;
96 struct omap_overlay *ovl;
97
98 ovl = ofbi->overlays[0];
99 ovli = &ovl->info;
100
101 pi->pos_x = ovli->pos_x;
102 pi->pos_y = ovli->pos_y;
103 pi->enabled = ovli->enabled;
104 pi->channel_out = 0; /* xxx */
105 pi->mirror = 0;
106 pi->out_width = ovli->out_width;
107 pi->out_height = ovli->out_height;
108 }
109
110 return 0;
111}
112
113static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
114{
115 struct omapfb_info *ofbi = FB2OFB(fbi);
116 struct omapfb2_device *fbdev = ofbi->fbdev;
117 struct omapfb2_mem_region *rg;
118 int r, i;
119 size_t size;
120
121 if (mi->type > OMAPFB_MEMTYPE_MAX)
122 return -EINVAL;
123
124 size = PAGE_ALIGN(mi->size);
125
126 rg = &ofbi->region;
127
128 for (i = 0; i < ofbi->num_overlays; i++) {
129 if (ofbi->overlays[i]->info.enabled)
130 return -EBUSY;
131 }
132
133 if (rg->size != size || rg->type != mi->type) {
134 r = omapfb_realloc_fbmem(fbi, size, mi->type);
135 if (r) {
136 dev_err(fbdev->dev, "realloc fbmem failed\n");
137 return r;
138 }
139 }
140
141 return 0;
142}
143
144static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
145{
146 struct omapfb_info *ofbi = FB2OFB(fbi);
147 struct omapfb2_mem_region *rg;
148
149 rg = &ofbi->region;
150 memset(mi, 0, sizeof(*mi));
151
152 mi->size = rg->size;
153 mi->type = rg->type;
154
155 return 0;
156}
157
158static int omapfb_update_window_nolock(struct fb_info *fbi,
159 u32 x, u32 y, u32 w, u32 h)
160{
161 struct omap_dss_device *display = fb2display(fbi);
162 u16 dw, dh;
163
164 if (!display)
165 return 0;
166
167 if (w == 0 || h == 0)
168 return 0;
169
170 display->get_resolution(display, &dw, &dh);
171
172 if (x + w > dw || y + h > dh)
173 return -EINVAL;
174
175 return display->update(display, x, y, w, h);
176}
177
178/* This function is exported for SGX driver use */
179int omapfb_update_window(struct fb_info *fbi,
180 u32 x, u32 y, u32 w, u32 h)
181{
182 struct omapfb_info *ofbi = FB2OFB(fbi);
183 struct omapfb2_device *fbdev = ofbi->fbdev;
184 int r;
185
186 omapfb_lock(fbdev);
187 lock_fb_info(fbi);
188
189 r = omapfb_update_window_nolock(fbi, x, y, w, h);
190
191 unlock_fb_info(fbi);
192 omapfb_unlock(fbdev);
193
194 return r;
195}
196EXPORT_SYMBOL(omapfb_update_window);
197
198static int omapfb_set_update_mode(struct fb_info *fbi,
199 enum omapfb_update_mode mode)
200{
201 struct omap_dss_device *display = fb2display(fbi);
202 enum omap_dss_update_mode um;
203 int r;
204
205 if (!display || !display->set_update_mode)
206 return -EINVAL;
207
208 switch (mode) {
209 case OMAPFB_UPDATE_DISABLED:
210 um = OMAP_DSS_UPDATE_DISABLED;
211 break;
212
213 case OMAPFB_AUTO_UPDATE:
214 um = OMAP_DSS_UPDATE_AUTO;
215 break;
216
217 case OMAPFB_MANUAL_UPDATE:
218 um = OMAP_DSS_UPDATE_MANUAL;
219 break;
220
221 default:
222 return -EINVAL;
223 }
224
225 r = display->set_update_mode(display, um);
226
227 return r;
228}
229
230static int omapfb_get_update_mode(struct fb_info *fbi,
231 enum omapfb_update_mode *mode)
232{
233 struct omap_dss_device *display = fb2display(fbi);
234 enum omap_dss_update_mode m;
235
236 if (!display || !display->get_update_mode)
237 return -EINVAL;
238
239 m = display->get_update_mode(display);
240
241 switch (m) {
242 case OMAP_DSS_UPDATE_DISABLED:
243 *mode = OMAPFB_UPDATE_DISABLED;
244 break;
245 case OMAP_DSS_UPDATE_AUTO:
246 *mode = OMAPFB_AUTO_UPDATE;
247 break;
248 case OMAP_DSS_UPDATE_MANUAL:
249 *mode = OMAPFB_MANUAL_UPDATE;
250 break;
251 default:
252 BUG();
253 }
254
255 return 0;
256}
257
258/* XXX this color key handling is a hack... */
259static struct omapfb_color_key omapfb_color_keys[2];
260
261static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,
262 struct omapfb_color_key *ck)
263{
264 struct omap_overlay_manager_info info;
265 enum omap_dss_trans_key_type kt;
266 int r;
267
268 mgr->get_manager_info(mgr, &info);
269
270 if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {
271 info.trans_enabled = false;
272 omapfb_color_keys[mgr->id] = *ck;
273
274 r = mgr->set_manager_info(mgr, &info);
275 if (r)
276 return r;
277
278 r = mgr->apply(mgr);
279
280 return r;
281 }
282
283 switch (ck->key_type) {
284 case OMAPFB_COLOR_KEY_GFX_DST:
285 kt = OMAP_DSS_COLOR_KEY_GFX_DST;
286 break;
287 case OMAPFB_COLOR_KEY_VID_SRC:
288 kt = OMAP_DSS_COLOR_KEY_VID_SRC;
289 break;
290 default:
291 return -EINVAL;
292 }
293
294 info.default_color = ck->background;
295 info.trans_key = ck->trans_key;
296 info.trans_key_type = kt;
297 info.trans_enabled = true;
298
299 omapfb_color_keys[mgr->id] = *ck;
300
301 r = mgr->set_manager_info(mgr, &info);
302 if (r)
303 return r;
304
305 r = mgr->apply(mgr);
306
307 return r;
308}
309
310static int omapfb_set_color_key(struct fb_info *fbi,
311 struct omapfb_color_key *ck)
312{
313 struct omapfb_info *ofbi = FB2OFB(fbi);
314 struct omapfb2_device *fbdev = ofbi->fbdev;
315 int r;
316 int i;
317 struct omap_overlay_manager *mgr = NULL;
318
319 omapfb_lock(fbdev);
320
321 for (i = 0; i < ofbi->num_overlays; i++) {
322 if (ofbi->overlays[i]->manager) {
323 mgr = ofbi->overlays[i]->manager;
324 break;
325 }
326 }
327
328 if (!mgr) {
329 r = -EINVAL;
330 goto err;
331 }
332
333 r = _omapfb_set_color_key(mgr, ck);
334err:
335 omapfb_unlock(fbdev);
336
337 return r;
338}
339
340static int omapfb_get_color_key(struct fb_info *fbi,
341 struct omapfb_color_key *ck)
342{
343 struct omapfb_info *ofbi = FB2OFB(fbi);
344 struct omapfb2_device *fbdev = ofbi->fbdev;
345 struct omap_overlay_manager *mgr = NULL;
346 int r = 0;
347 int i;
348
349 omapfb_lock(fbdev);
350
351 for (i = 0; i < ofbi->num_overlays; i++) {
352 if (ofbi->overlays[i]->manager) {
353 mgr = ofbi->overlays[i]->manager;
354 break;
355 }
356 }
357
358 if (!mgr) {
359 r = -EINVAL;
360 goto err;
361 }
362
363 *ck = omapfb_color_keys[mgr->id];
364err:
365 omapfb_unlock(fbdev);
366
367 return r;
368}
369
370static int omapfb_memory_read(struct fb_info *fbi,
371 struct omapfb_memory_read *mr)
372{
373 struct omap_dss_device *display = fb2display(fbi);
374 void *buf;
375 int r;
376
377 if (!display || !display->memory_read)
378 return -ENOENT;
379
380 if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
381 return -EFAULT;
382
383 if (mr->w * mr->h * 3 > mr->buffer_size)
384 return -EINVAL;
385
386 buf = vmalloc(mr->buffer_size);
387 if (!buf) {
388 DBG("vmalloc failed\n");
389 return -ENOMEM;
390 }
391
392 r = display->memory_read(display, buf, mr->buffer_size,
393 mr->x, mr->y, mr->w, mr->h);
394
395 if (r > 0) {
396 if (copy_to_user(mr->buffer, buf, mr->buffer_size))
397 r = -EFAULT;
398 }
399
400 vfree(buf);
401
402 return r;
403}
404
405static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,
406 struct omapfb_ovl_colormode *mode)
407{
408 int ovl_idx = mode->overlay_idx;
409 int mode_idx = mode->mode_idx;
410 struct omap_overlay *ovl;
411 enum omap_color_mode supported_modes;
412 struct fb_var_screeninfo var;
413 int i;
414
415 if (ovl_idx >= fbdev->num_overlays)
416 return -ENODEV;
417 ovl = fbdev->overlays[ovl_idx];
418 supported_modes = ovl->supported_modes;
419
420 mode_idx = mode->mode_idx;
421
422 for (i = 0; i < sizeof(supported_modes) * 8; i++) {
423 if (!(supported_modes & (1 << i)))
424 continue;
425 /*
426 * It's possible that the FB doesn't support a mode
427 * that is supported by the overlay, so call the
428 * following here.
429 */
430 if (dss_mode_to_fb_mode(1 << i, &var) < 0)
431 continue;
432
433 mode_idx--;
434 if (mode_idx < 0)
435 break;
436 }
437
438 if (i == sizeof(supported_modes) * 8)
439 return -ENOENT;
440
441 mode->bits_per_pixel = var.bits_per_pixel;
442 mode->nonstd = var.nonstd;
443 mode->red = var.red;
444 mode->green = var.green;
445 mode->blue = var.blue;
446 mode->transp = var.transp;
447
448 return 0;
449}
450
451static int omapfb_wait_for_go(struct fb_info *fbi)
452{
453 struct omapfb_info *ofbi = FB2OFB(fbi);
454 int r = 0;
455 int i;
456
457 for (i = 0; i < ofbi->num_overlays; ++i) {
458 struct omap_overlay *ovl = ofbi->overlays[i];
459 r = ovl->wait_for_go(ovl);
460 if (r)
461 break;
462 }
463
464 return r;
465}
466
467int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
468{
469 struct omapfb_info *ofbi = FB2OFB(fbi);
470 struct omapfb2_device *fbdev = ofbi->fbdev;
471 struct omap_dss_device *display = fb2display(fbi);
472
473 union {
474 struct omapfb_update_window_old uwnd_o;
475 struct omapfb_update_window uwnd;
476 struct omapfb_plane_info plane_info;
477 struct omapfb_caps caps;
478 struct omapfb_mem_info mem_info;
479 struct omapfb_color_key color_key;
480 struct omapfb_ovl_colormode ovl_colormode;
481 enum omapfb_update_mode update_mode;
482 int test_num;
483 struct omapfb_memory_read memory_read;
484 struct omapfb_vram_info vram_info;
485 struct omapfb_tearsync_info tearsync_info;
486 } p;
487
488 int r = 0;
489
490 switch (cmd) {
491 case OMAPFB_SYNC_GFX:
492 DBG("ioctl SYNC_GFX\n");
493 if (!display || !display->sync) {
494 /* DSS1 never returns an error here, so we neither */
495 /*r = -EINVAL;*/
496 break;
497 }
498
499 r = display->sync(display);
500 break;
501
502 case OMAPFB_UPDATE_WINDOW_OLD:
503 DBG("ioctl UPDATE_WINDOW_OLD\n");
504 if (!display || !display->update) {
505 r = -EINVAL;
506 break;
507 }
508
509 if (copy_from_user(&p.uwnd_o,
510 (void __user *)arg,
511 sizeof(p.uwnd_o))) {
512 r = -EFAULT;
513 break;
514 }
515
516 r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y,
517 p.uwnd_o.width, p.uwnd_o.height);
518 break;
519
520 case OMAPFB_UPDATE_WINDOW:
521 DBG("ioctl UPDATE_WINDOW\n");
522 if (!display || !display->update) {
523 r = -EINVAL;
524 break;
525 }
526
527 if (copy_from_user(&p.uwnd, (void __user *)arg,
528 sizeof(p.uwnd))) {
529 r = -EFAULT;
530 break;
531 }
532
533 r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y,
534 p.uwnd.width, p.uwnd.height);
535 break;
536
537 case OMAPFB_SETUP_PLANE:
538 DBG("ioctl SETUP_PLANE\n");
539 if (copy_from_user(&p.plane_info, (void __user *)arg,
540 sizeof(p.plane_info)))
541 r = -EFAULT;
542 else
543 r = omapfb_setup_plane(fbi, &p.plane_info);
544 break;
545
546 case OMAPFB_QUERY_PLANE:
547 DBG("ioctl QUERY_PLANE\n");
548 r = omapfb_query_plane(fbi, &p.plane_info);
549 if (r < 0)
550 break;
551 if (copy_to_user((void __user *)arg, &p.plane_info,
552 sizeof(p.plane_info)))
553 r = -EFAULT;
554 break;
555
556 case OMAPFB_SETUP_MEM:
557 DBG("ioctl SETUP_MEM\n");
558 if (copy_from_user(&p.mem_info, (void __user *)arg,
559 sizeof(p.mem_info)))
560 r = -EFAULT;
561 else
562 r = omapfb_setup_mem(fbi, &p.mem_info);
563 break;
564
565 case OMAPFB_QUERY_MEM:
566 DBG("ioctl QUERY_MEM\n");
567 r = omapfb_query_mem(fbi, &p.mem_info);
568 if (r < 0)
569 break;
570 if (copy_to_user((void __user *)arg, &p.mem_info,
571 sizeof(p.mem_info)))
572 r = -EFAULT;
573 break;
574
575 case OMAPFB_GET_CAPS:
576 DBG("ioctl GET_CAPS\n");
577 if (!display) {
578 r = -EINVAL;
579 break;
580 }
581
582 memset(&p.caps, 0, sizeof(p.caps));
583 if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
584 p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;
585 if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)
586 p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;
587
588 if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
589 r = -EFAULT;
590 break;
591
592 case OMAPFB_GET_OVERLAY_COLORMODE:
593 DBG("ioctl GET_OVERLAY_COLORMODE\n");
594 if (copy_from_user(&p.ovl_colormode, (void __user *)arg,
595 sizeof(p.ovl_colormode))) {
596 r = -EFAULT;
597 break;
598 }
599 r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
600 if (r < 0)
601 break;
602 if (copy_to_user((void __user *)arg, &p.ovl_colormode,
603 sizeof(p.ovl_colormode)))
604 r = -EFAULT;
605 break;
606
607 case OMAPFB_SET_UPDATE_MODE:
608 DBG("ioctl SET_UPDATE_MODE\n");
609 if (get_user(p.update_mode, (int __user *)arg))
610 r = -EFAULT;
611 else
612 r = omapfb_set_update_mode(fbi, p.update_mode);
613 break;
614
615 case OMAPFB_GET_UPDATE_MODE:
616 DBG("ioctl GET_UPDATE_MODE\n");
617 r = omapfb_get_update_mode(fbi, &p.update_mode);
618 if (r)
619 break;
620 if (put_user(p.update_mode,
621 (enum omapfb_update_mode __user *)arg))
622 r = -EFAULT;
623 break;
624
625 case OMAPFB_SET_COLOR_KEY:
626 DBG("ioctl SET_COLOR_KEY\n");
627 if (copy_from_user(&p.color_key, (void __user *)arg,
628 sizeof(p.color_key)))
629 r = -EFAULT;
630 else
631 r = omapfb_set_color_key(fbi, &p.color_key);
632 break;
633
634 case OMAPFB_GET_COLOR_KEY:
635 DBG("ioctl GET_COLOR_KEY\n");
636 r = omapfb_get_color_key(fbi, &p.color_key);
637 if (r)
638 break;
639 if (copy_to_user((void __user *)arg, &p.color_key,
640 sizeof(p.color_key)))
641 r = -EFAULT;
642 break;
643
644 case OMAPFB_WAITFORVSYNC:
645 DBG("ioctl WAITFORVSYNC\n");
646 if (!display) {
647 r = -EINVAL;
648 break;
649 }
650
651 r = display->wait_vsync(display);
652 break;
653
654 case OMAPFB_WAITFORGO:
655 DBG("ioctl WAITFORGO\n");
656 if (!display) {
657 r = -EINVAL;
658 break;
659 }
660
661 r = omapfb_wait_for_go(fbi);
662 break;
663
664 /* LCD and CTRL tests do the same thing for backward
665 * compatibility */
666 case OMAPFB_LCD_TEST:
667 DBG("ioctl LCD_TEST\n");
668 if (get_user(p.test_num, (int __user *)arg)) {
669 r = -EFAULT;
670 break;
671 }
672 if (!display || !display->run_test) {
673 r = -EINVAL;
674 break;
675 }
676
677 r = display->run_test(display, p.test_num);
678
679 break;
680
681 case OMAPFB_CTRL_TEST:
682 DBG("ioctl CTRL_TEST\n");
683 if (get_user(p.test_num, (int __user *)arg)) {
684 r = -EFAULT;
685 break;
686 }
687 if (!display || !display->run_test) {
688 r = -EINVAL;
689 break;
690 }
691
692 r = display->run_test(display, p.test_num);
693
694 break;
695
696 case OMAPFB_MEMORY_READ:
697 DBG("ioctl MEMORY_READ\n");
698
699 if (copy_from_user(&p.memory_read, (void __user *)arg,
700 sizeof(p.memory_read))) {
701 r = -EFAULT;
702 break;
703 }
704
705 r = omapfb_memory_read(fbi, &p.memory_read);
706
707 break;
708
709 case OMAPFB_GET_VRAM_INFO: {
710 unsigned long vram, free, largest;
711
712 DBG("ioctl GET_VRAM_INFO\n");
713
714 omap_vram_get_info(&vram, &free, &largest);
715 p.vram_info.total = vram;
716 p.vram_info.free = free;
717 p.vram_info.largest_free_block = largest;
718
719 if (copy_to_user((void __user *)arg, &p.vram_info,
720 sizeof(p.vram_info)))
721 r = -EFAULT;
722 break;
723 }
724
725 case OMAPFB_SET_TEARSYNC: {
726 DBG("ioctl SET_TEARSYNC\n");
727
728 if (copy_from_user(&p.tearsync_info, (void __user *)arg,
729 sizeof(p.tearsync_info))) {
730 r = -EFAULT;
731 break;
732 }
733
734 if (!display->enable_te) {
735 r = -ENODEV;
736 break;
737 }
738
739 r = display->enable_te(display, !!p.tearsync_info.enabled);
740
741 break;
742 }
743
744 default:
745 dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
746 r = -EINVAL;
747 }
748
749 if (r < 0)
750 DBG("ioctl failed: %d\n", r);
751
752 return r;
753}
754
755
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
new file mode 100644
index 000000000000..ef299839858a
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -0,0 +1,2261 @@
1/*
2 * linux/drivers/video/omap2/omapfb-main.c
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <linux/module.h>
24#include <linux/delay.h>
25#include <linux/fb.h>
26#include <linux/dma-mapping.h>
27#include <linux/vmalloc.h>
28#include <linux/device.h>
29#include <linux/platform_device.h>
30#include <linux/omapfb.h>
31
32#include <plat/display.h>
33#include <plat/vram.h>
34#include <plat/vrfb.h>
35
36#include "omapfb.h"
37
38#define MODULE_NAME "omapfb"
39
40#define OMAPFB_PLANE_XRES_MIN 8
41#define OMAPFB_PLANE_YRES_MIN 8
42
43static char *def_mode;
44static char *def_vram;
45static int def_vrfb;
46static int def_rotate;
47static int def_mirror;
48
49#ifdef DEBUG
50unsigned int omapfb_debug;
51module_param_named(debug, omapfb_debug, bool, 0644);
52static unsigned int omapfb_test_pattern;
53module_param_named(test, omapfb_test_pattern, bool, 0644);
54#endif
55
56static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
57
58#ifdef DEBUG
59static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
60{
61 struct fb_var_screeninfo *var = &fbi->var;
62 struct fb_fix_screeninfo *fix = &fbi->fix;
63 void __iomem *addr = fbi->screen_base;
64 const unsigned bytespp = var->bits_per_pixel >> 3;
65 const unsigned line_len = fix->line_length / bytespp;
66
67 int r = (color >> 16) & 0xff;
68 int g = (color >> 8) & 0xff;
69 int b = (color >> 0) & 0xff;
70
71 if (var->bits_per_pixel == 16) {
72 u16 __iomem *p = (u16 __iomem *)addr;
73 p += y * line_len + x;
74
75 r = r * 32 / 256;
76 g = g * 64 / 256;
77 b = b * 32 / 256;
78
79 __raw_writew((r << 11) | (g << 5) | (b << 0), p);
80 } else if (var->bits_per_pixel == 24) {
81 u8 __iomem *p = (u8 __iomem *)addr;
82 p += (y * line_len + x) * 3;
83
84 __raw_writeb(b, p + 0);
85 __raw_writeb(g, p + 1);
86 __raw_writeb(r, p + 2);
87 } else if (var->bits_per_pixel == 32) {
88 u32 __iomem *p = (u32 __iomem *)addr;
89 p += y * line_len + x;
90 __raw_writel(color, p);
91 }
92}
93
94static void fill_fb(struct fb_info *fbi)
95{
96 struct fb_var_screeninfo *var = &fbi->var;
97 const short w = var->xres_virtual;
98 const short h = var->yres_virtual;
99 void __iomem *addr = fbi->screen_base;
100 int y, x;
101
102 if (!addr)
103 return;
104
105 DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
106
107 for (y = 0; y < h; y++) {
108 for (x = 0; x < w; x++) {
109 if (x < 20 && y < 20)
110 draw_pixel(fbi, x, y, 0xffffff);
111 else if (x < 20 && (y > 20 && y < h - 20))
112 draw_pixel(fbi, x, y, 0xff);
113 else if (y < 20 && (x > 20 && x < w - 20))
114 draw_pixel(fbi, x, y, 0xff00);
115 else if (x > w - 20 && (y > 20 && y < h - 20))
116 draw_pixel(fbi, x, y, 0xff0000);
117 else if (y > h - 20 && (x > 20 && x < w - 20))
118 draw_pixel(fbi, x, y, 0xffff00);
119 else if (x == 20 || x == w - 20 ||
120 y == 20 || y == h - 20)
121 draw_pixel(fbi, x, y, 0xffffff);
122 else if (x == y || w - x == h - y)
123 draw_pixel(fbi, x, y, 0xff00ff);
124 else if (w - x == y || x == h - y)
125 draw_pixel(fbi, x, y, 0x00ffff);
126 else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {
127 int t = x * 3 / w;
128 unsigned r = 0, g = 0, b = 0;
129 unsigned c;
130 if (var->bits_per_pixel == 16) {
131 if (t == 0)
132 b = (y % 32) * 256 / 32;
133 else if (t == 1)
134 g = (y % 64) * 256 / 64;
135 else if (t == 2)
136 r = (y % 32) * 256 / 32;
137 } else {
138 if (t == 0)
139 b = (y % 256);
140 else if (t == 1)
141 g = (y % 256);
142 else if (t == 2)
143 r = (y % 256);
144 }
145 c = (r << 16) | (g << 8) | (b << 0);
146 draw_pixel(fbi, x, y, c);
147 } else {
148 draw_pixel(fbi, x, y, 0);
149 }
150 }
151 }
152}
153#endif
154
155static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)
156{
157 struct vrfb *vrfb = &ofbi->region.vrfb;
158 unsigned offset;
159
160 switch (rot) {
161 case FB_ROTATE_UR:
162 offset = 0;
163 break;
164 case FB_ROTATE_CW:
165 offset = vrfb->yoffset;
166 break;
167 case FB_ROTATE_UD:
168 offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
169 break;
170 case FB_ROTATE_CCW:
171 offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
172 break;
173 default:
174 BUG();
175 }
176
177 offset *= vrfb->bytespp;
178
179 return offset;
180}
181
182static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi, int rot)
183{
184 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
185 return ofbi->region.vrfb.paddr[rot]
186 + omapfb_get_vrfb_offset(ofbi, rot);
187 } else {
188 return ofbi->region.paddr;
189 }
190}
191
192static u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
193{
194 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
195 return ofbi->region.vrfb.paddr[0];
196 else
197 return ofbi->region.paddr;
198}
199
200static void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi)
201{
202 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
203 return ofbi->region.vrfb.vaddr[0];
204 else
205 return ofbi->region.vaddr;
206}
207
208static struct omapfb_colormode omapfb_colormodes[] = {
209 {
210 .dssmode = OMAP_DSS_COLOR_UYVY,
211 .bits_per_pixel = 16,
212 .nonstd = OMAPFB_COLOR_YUV422,
213 }, {
214 .dssmode = OMAP_DSS_COLOR_YUV2,
215 .bits_per_pixel = 16,
216 .nonstd = OMAPFB_COLOR_YUY422,
217 }, {
218 .dssmode = OMAP_DSS_COLOR_ARGB16,
219 .bits_per_pixel = 16,
220 .red = { .length = 4, .offset = 8, .msb_right = 0 },
221 .green = { .length = 4, .offset = 4, .msb_right = 0 },
222 .blue = { .length = 4, .offset = 0, .msb_right = 0 },
223 .transp = { .length = 4, .offset = 12, .msb_right = 0 },
224 }, {
225 .dssmode = OMAP_DSS_COLOR_RGB16,
226 .bits_per_pixel = 16,
227 .red = { .length = 5, .offset = 11, .msb_right = 0 },
228 .green = { .length = 6, .offset = 5, .msb_right = 0 },
229 .blue = { .length = 5, .offset = 0, .msb_right = 0 },
230 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
231 }, {
232 .dssmode = OMAP_DSS_COLOR_RGB24P,
233 .bits_per_pixel = 24,
234 .red = { .length = 8, .offset = 16, .msb_right = 0 },
235 .green = { .length = 8, .offset = 8, .msb_right = 0 },
236 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
237 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
238 }, {
239 .dssmode = OMAP_DSS_COLOR_RGB24U,
240 .bits_per_pixel = 32,
241 .red = { .length = 8, .offset = 16, .msb_right = 0 },
242 .green = { .length = 8, .offset = 8, .msb_right = 0 },
243 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
244 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
245 }, {
246 .dssmode = OMAP_DSS_COLOR_ARGB32,
247 .bits_per_pixel = 32,
248 .red = { .length = 8, .offset = 16, .msb_right = 0 },
249 .green = { .length = 8, .offset = 8, .msb_right = 0 },
250 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
251 .transp = { .length = 8, .offset = 24, .msb_right = 0 },
252 }, {
253 .dssmode = OMAP_DSS_COLOR_RGBA32,
254 .bits_per_pixel = 32,
255 .red = { .length = 8, .offset = 24, .msb_right = 0 },
256 .green = { .length = 8, .offset = 16, .msb_right = 0 },
257 .blue = { .length = 8, .offset = 8, .msb_right = 0 },
258 .transp = { .length = 8, .offset = 0, .msb_right = 0 },
259 }, {
260 .dssmode = OMAP_DSS_COLOR_RGBX32,
261 .bits_per_pixel = 32,
262 .red = { .length = 8, .offset = 24, .msb_right = 0 },
263 .green = { .length = 8, .offset = 16, .msb_right = 0 },
264 .blue = { .length = 8, .offset = 8, .msb_right = 0 },
265 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
266 },
267};
268
269static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
270 struct omapfb_colormode *color)
271{
272 bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
273 {
274 return f1->length == f2->length &&
275 f1->offset == f2->offset &&
276 f1->msb_right == f2->msb_right;
277 }
278
279 if (var->bits_per_pixel == 0 ||
280 var->red.length == 0 ||
281 var->blue.length == 0 ||
282 var->green.length == 0)
283 return 0;
284
285 return var->bits_per_pixel == color->bits_per_pixel &&
286 cmp_component(&var->red, &color->red) &&
287 cmp_component(&var->green, &color->green) &&
288 cmp_component(&var->blue, &color->blue) &&
289 cmp_component(&var->transp, &color->transp);
290}
291
292static void assign_colormode_to_var(struct fb_var_screeninfo *var,
293 struct omapfb_colormode *color)
294{
295 var->bits_per_pixel = color->bits_per_pixel;
296 var->nonstd = color->nonstd;
297 var->red = color->red;
298 var->green = color->green;
299 var->blue = color->blue;
300 var->transp = color->transp;
301}
302
303static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var,
304 enum omap_color_mode *mode)
305{
306 enum omap_color_mode dssmode;
307 int i;
308
309 /* first match with nonstd field */
310 if (var->nonstd) {
311 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
312 struct omapfb_colormode *m = &omapfb_colormodes[i];
313 if (var->nonstd == m->nonstd) {
314 assign_colormode_to_var(var, m);
315 *mode = m->dssmode;
316 return 0;
317 }
318 }
319
320 return -EINVAL;
321 }
322
323 /* then try exact match of bpp and colors */
324 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
325 struct omapfb_colormode *m = &omapfb_colormodes[i];
326 if (cmp_var_to_colormode(var, m)) {
327 assign_colormode_to_var(var, m);
328 *mode = m->dssmode;
329 return 0;
330 }
331 }
332
333 /* match with bpp if user has not filled color fields
334 * properly */
335 switch (var->bits_per_pixel) {
336 case 1:
337 dssmode = OMAP_DSS_COLOR_CLUT1;
338 break;
339 case 2:
340 dssmode = OMAP_DSS_COLOR_CLUT2;
341 break;
342 case 4:
343 dssmode = OMAP_DSS_COLOR_CLUT4;
344 break;
345 case 8:
346 dssmode = OMAP_DSS_COLOR_CLUT8;
347 break;
348 case 12:
349 dssmode = OMAP_DSS_COLOR_RGB12U;
350 break;
351 case 16:
352 dssmode = OMAP_DSS_COLOR_RGB16;
353 break;
354 case 24:
355 dssmode = OMAP_DSS_COLOR_RGB24P;
356 break;
357 case 32:
358 dssmode = OMAP_DSS_COLOR_RGB24U;
359 break;
360 default:
361 return -EINVAL;
362 }
363
364 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
365 struct omapfb_colormode *m = &omapfb_colormodes[i];
366 if (dssmode == m->dssmode) {
367 assign_colormode_to_var(var, m);
368 *mode = m->dssmode;
369 return 0;
370 }
371 }
372
373 return -EINVAL;
374}
375
376static int check_fb_res_bounds(struct fb_var_screeninfo *var)
377{
378 int xres_min = OMAPFB_PLANE_XRES_MIN;
379 int xres_max = 2048;
380 int yres_min = OMAPFB_PLANE_YRES_MIN;
381 int yres_max = 2048;
382
383 /* XXX: some applications seem to set virtual res to 0. */
384 if (var->xres_virtual == 0)
385 var->xres_virtual = var->xres;
386
387 if (var->yres_virtual == 0)
388 var->yres_virtual = var->yres;
389
390 if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
391 return -EINVAL;
392
393 if (var->xres < xres_min)
394 var->xres = xres_min;
395 if (var->yres < yres_min)
396 var->yres = yres_min;
397 if (var->xres > xres_max)
398 var->xres = xres_max;
399 if (var->yres > yres_max)
400 var->yres = yres_max;
401
402 if (var->xres > var->xres_virtual)
403 var->xres = var->xres_virtual;
404 if (var->yres > var->yres_virtual)
405 var->yres = var->yres_virtual;
406
407 return 0;
408}
409
410static void shrink_height(unsigned long max_frame_size,
411 struct fb_var_screeninfo *var)
412{
413 DBG("can't fit FB into memory, reducing y\n");
414 var->yres_virtual = max_frame_size /
415 (var->xres_virtual * var->bits_per_pixel >> 3);
416
417 if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN)
418 var->yres_virtual = OMAPFB_PLANE_YRES_MIN;
419
420 if (var->yres > var->yres_virtual)
421 var->yres = var->yres_virtual;
422}
423
424static void shrink_width(unsigned long max_frame_size,
425 struct fb_var_screeninfo *var)
426{
427 DBG("can't fit FB into memory, reducing x\n");
428 var->xres_virtual = max_frame_size / var->yres_virtual /
429 (var->bits_per_pixel >> 3);
430
431 if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN)
432 var->xres_virtual = OMAPFB_PLANE_XRES_MIN;
433
434 if (var->xres > var->xres_virtual)
435 var->xres = var->xres_virtual;
436}
437
438static int check_vrfb_fb_size(unsigned long region_size,
439 const struct fb_var_screeninfo *var)
440{
441 unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual,
442 var->yres_virtual, var->bits_per_pixel >> 3);
443
444 return min_phys_size > region_size ? -EINVAL : 0;
445}
446
447static int check_fb_size(const struct omapfb_info *ofbi,
448 struct fb_var_screeninfo *var)
449{
450 unsigned long max_frame_size = ofbi->region.size;
451 int bytespp = var->bits_per_pixel >> 3;
452 unsigned long line_size = var->xres_virtual * bytespp;
453
454 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
455 /* One needs to check for both VRFB and OMAPFB limitations. */
456 if (check_vrfb_fb_size(max_frame_size, var))
457 shrink_height(omap_vrfb_max_height(
458 max_frame_size, var->xres_virtual, bytespp) *
459 line_size, var);
460
461 if (check_vrfb_fb_size(max_frame_size, var)) {
462 DBG("cannot fit FB to memory\n");
463 return -EINVAL;
464 }
465
466 return 0;
467 }
468
469 DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
470
471 if (line_size * var->yres_virtual > max_frame_size)
472 shrink_height(max_frame_size, var);
473
474 if (line_size * var->yres_virtual > max_frame_size) {
475 shrink_width(max_frame_size, var);
476 line_size = var->xres_virtual * bytespp;
477 }
478
479 if (line_size * var->yres_virtual > max_frame_size) {
480 DBG("cannot fit FB to memory\n");
481 return -EINVAL;
482 }
483
484 return 0;
485}
486
487/*
488 * Consider if VRFB assisted rotation is in use and if the virtual space for
489 * the zero degree view needs to be mapped. The need for mapping also acts as
490 * the trigger for setting up the hardware on the context in question. This
491 * ensures that one does not attempt to access the virtual view before the
492 * hardware is serving the address translations.
493 */
494static int setup_vrfb_rotation(struct fb_info *fbi)
495{
496 struct omapfb_info *ofbi = FB2OFB(fbi);
497 struct omapfb2_mem_region *rg = &ofbi->region;
498 struct vrfb *vrfb = &rg->vrfb;
499 struct fb_var_screeninfo *var = &fbi->var;
500 struct fb_fix_screeninfo *fix = &fbi->fix;
501 unsigned bytespp;
502 bool yuv_mode;
503 enum omap_color_mode mode;
504 int r;
505 bool reconf;
506
507 if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB)
508 return 0;
509
510 DBG("setup_vrfb_rotation\n");
511
512 r = fb_mode_to_dss_mode(var, &mode);
513 if (r)
514 return r;
515
516 bytespp = var->bits_per_pixel >> 3;
517
518 yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY;
519
520 /* We need to reconfigure VRFB if the resolution changes, if yuv mode
521 * is enabled/disabled, or if bytes per pixel changes */
522
523 /* XXX we shouldn't allow this when framebuffer is mmapped */
524
525 reconf = false;
526
527 if (yuv_mode != vrfb->yuv_mode)
528 reconf = true;
529 else if (bytespp != vrfb->bytespp)
530 reconf = true;
531 else if (vrfb->xres != var->xres_virtual ||
532 vrfb->yres != var->yres_virtual)
533 reconf = true;
534
535 if (vrfb->vaddr[0] && reconf) {
536 fbi->screen_base = NULL;
537 fix->smem_start = 0;
538 fix->smem_len = 0;
539 iounmap(vrfb->vaddr[0]);
540 vrfb->vaddr[0] = NULL;
541 DBG("setup_vrfb_rotation: reset fb\n");
542 }
543
544 if (vrfb->vaddr[0])
545 return 0;
546
547 omap_vrfb_setup(&rg->vrfb, rg->paddr,
548 var->xres_virtual,
549 var->yres_virtual,
550 bytespp, yuv_mode);
551
552 /* Now one can ioremap the 0 angle view */
553 r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0);
554 if (r)
555 return r;
556
557 /* used by open/write in fbmem.c */
558 fbi->screen_base = ofbi->region.vrfb.vaddr[0];
559
560 fix->smem_start = ofbi->region.vrfb.paddr[0];
561
562 switch (var->nonstd) {
563 case OMAPFB_COLOR_YUV422:
564 case OMAPFB_COLOR_YUY422:
565 fix->line_length =
566 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
567 break;
568 default:
569 fix->line_length =
570 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
571 break;
572 }
573
574 fix->smem_len = var->yres_virtual * fix->line_length;
575
576 return 0;
577}
578
579int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
580 struct fb_var_screeninfo *var)
581{
582 int i;
583
584 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
585 struct omapfb_colormode *mode = &omapfb_colormodes[i];
586 if (dssmode == mode->dssmode) {
587 assign_colormode_to_var(var, mode);
588 return 0;
589 }
590 }
591 return -ENOENT;
592}
593
594void set_fb_fix(struct fb_info *fbi)
595{
596 struct fb_fix_screeninfo *fix = &fbi->fix;
597 struct fb_var_screeninfo *var = &fbi->var;
598 struct omapfb_info *ofbi = FB2OFB(fbi);
599 struct omapfb2_mem_region *rg = &ofbi->region;
600
601 DBG("set_fb_fix\n");
602
603 /* used by open/write in fbmem.c */
604 fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
605
606 /* used by mmap in fbmem.c */
607 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
608 switch (var->nonstd) {
609 case OMAPFB_COLOR_YUV422:
610 case OMAPFB_COLOR_YUY422:
611 fix->line_length =
612 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
613 break;
614 default:
615 fix->line_length =
616 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
617 break;
618 }
619
620 fix->smem_len = var->yres_virtual * fix->line_length;
621 } else {
622 fix->line_length =
623 (var->xres_virtual * var->bits_per_pixel) >> 3;
624 fix->smem_len = rg->size;
625 }
626
627 fix->smem_start = omapfb_get_region_paddr(ofbi);
628
629 fix->type = FB_TYPE_PACKED_PIXELS;
630
631 if (var->nonstd)
632 fix->visual = FB_VISUAL_PSEUDOCOLOR;
633 else {
634 switch (var->bits_per_pixel) {
635 case 32:
636 case 24:
637 case 16:
638 case 12:
639 fix->visual = FB_VISUAL_TRUECOLOR;
640 /* 12bpp is stored in 16 bits */
641 break;
642 case 1:
643 case 2:
644 case 4:
645 case 8:
646 fix->visual = FB_VISUAL_PSEUDOCOLOR;
647 break;
648 }
649 }
650
651 fix->accel = FB_ACCEL_NONE;
652
653 fix->xpanstep = 1;
654 fix->ypanstep = 1;
655}
656
657/* check new var and possibly modify it to be ok */
658int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
659{
660 struct omapfb_info *ofbi = FB2OFB(fbi);
661 struct omap_dss_device *display = fb2display(fbi);
662 enum omap_color_mode mode = 0;
663 int i;
664 int r;
665
666 DBG("check_fb_var %d\n", ofbi->id);
667
668 if (ofbi->region.size == 0)
669 return 0;
670
671 r = fb_mode_to_dss_mode(var, &mode);
672 if (r) {
673 DBG("cannot convert var to omap dss mode\n");
674 return r;
675 }
676
677 for (i = 0; i < ofbi->num_overlays; ++i) {
678 if ((ofbi->overlays[i]->supported_modes & mode) == 0) {
679 DBG("invalid mode\n");
680 return -EINVAL;
681 }
682 }
683
684 if (var->rotate < 0 || var->rotate > 3)
685 return -EINVAL;
686
687 if (check_fb_res_bounds(var))
688 return -EINVAL;
689
690 if (check_fb_size(ofbi, var))
691 return -EINVAL;
692
693 if (var->xres + var->xoffset > var->xres_virtual)
694 var->xoffset = var->xres_virtual - var->xres;
695 if (var->yres + var->yoffset > var->yres_virtual)
696 var->yoffset = var->yres_virtual - var->yres;
697
698 DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",
699 var->xres, var->yres,
700 var->xres_virtual, var->yres_virtual);
701
702 var->height = -1;
703 var->width = -1;
704 var->grayscale = 0;
705
706 if (display && display->get_timings) {
707 struct omap_video_timings timings;
708 display->get_timings(display, &timings);
709
710 /* pixclock in ps, the rest in pixclock */
711 var->pixclock = timings.pixel_clock != 0 ?
712 KHZ2PICOS(timings.pixel_clock) :
713 0;
714 var->left_margin = timings.hfp;
715 var->right_margin = timings.hbp;
716 var->upper_margin = timings.vfp;
717 var->lower_margin = timings.vbp;
718 var->hsync_len = timings.hsw;
719 var->vsync_len = timings.vsw;
720 } else {
721 var->pixclock = 0;
722 var->left_margin = 0;
723 var->right_margin = 0;
724 var->upper_margin = 0;
725 var->lower_margin = 0;
726 var->hsync_len = 0;
727 var->vsync_len = 0;
728 }
729
730 /* TODO: get these from panel->config */
731 var->vmode = FB_VMODE_NONINTERLACED;
732 var->sync = 0;
733
734 return 0;
735}
736
737/*
738 * ---------------------------------------------------------------------------
739 * fbdev framework callbacks
740 * ---------------------------------------------------------------------------
741 */
742static int omapfb_open(struct fb_info *fbi, int user)
743{
744 return 0;
745}
746
747static int omapfb_release(struct fb_info *fbi, int user)
748{
749#if 0
750 struct omapfb_info *ofbi = FB2OFB(fbi);
751 struct omapfb2_device *fbdev = ofbi->fbdev;
752 struct omap_dss_device *display = fb2display(fbi);
753
754 DBG("Closing fb with plane index %d\n", ofbi->id);
755
756 omapfb_lock(fbdev);
757
758 if (display && display->get_update_mode && display->update) {
759 /* XXX this update should be removed, I think. But it's
760 * good for debugging */
761 if (display->get_update_mode(display) ==
762 OMAP_DSS_UPDATE_MANUAL) {
763 u16 w, h;
764
765 if (display->sync)
766 display->sync(display);
767
768 display->get_resolution(display, &w, &h);
769 display->update(display, 0, 0, w, h);
770 }
771 }
772
773 if (display && display->sync)
774 display->sync(display);
775
776 omapfb_unlock(fbdev);
777#endif
778 return 0;
779}
780
781static unsigned calc_rotation_offset_dma(struct fb_var_screeninfo *var,
782 struct fb_fix_screeninfo *fix, int rotation)
783{
784 unsigned offset;
785
786 offset = var->yoffset * fix->line_length +
787 var->xoffset * (var->bits_per_pixel >> 3);
788
789 return offset;
790}
791
792static unsigned calc_rotation_offset_vrfb(struct fb_var_screeninfo *var,
793 struct fb_fix_screeninfo *fix, int rotation)
794{
795 unsigned offset;
796
797 if (rotation == FB_ROTATE_UD)
798 offset = (var->yres_virtual - var->yres) *
799 fix->line_length;
800 else if (rotation == FB_ROTATE_CW)
801 offset = (var->yres_virtual - var->yres) *
802 (var->bits_per_pixel >> 3);
803 else
804 offset = 0;
805
806 if (rotation == FB_ROTATE_UR)
807 offset += var->yoffset * fix->line_length +
808 var->xoffset * (var->bits_per_pixel >> 3);
809 else if (rotation == FB_ROTATE_UD)
810 offset -= var->yoffset * fix->line_length +
811 var->xoffset * (var->bits_per_pixel >> 3);
812 else if (rotation == FB_ROTATE_CW)
813 offset -= var->xoffset * fix->line_length +
814 var->yoffset * (var->bits_per_pixel >> 3);
815 else if (rotation == FB_ROTATE_CCW)
816 offset += var->xoffset * fix->line_length +
817 var->yoffset * (var->bits_per_pixel >> 3);
818
819 return offset;
820}
821
822
823/* setup overlay according to the fb */
824static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
825 u16 posx, u16 posy, u16 outw, u16 outh)
826{
827 int r = 0;
828 struct omapfb_info *ofbi = FB2OFB(fbi);
829 struct fb_var_screeninfo *var = &fbi->var;
830 struct fb_fix_screeninfo *fix = &fbi->fix;
831 enum omap_color_mode mode = 0;
832 int offset;
833 u32 data_start_p;
834 void __iomem *data_start_v;
835 struct omap_overlay_info info;
836 int xres, yres;
837 int screen_width;
838 int mirror;
839 int rotation = var->rotate;
840 int i;
841
842 for (i = 0; i < ofbi->num_overlays; i++) {
843 if (ovl != ofbi->overlays[i])
844 continue;
845
846 rotation = (rotation + ofbi->rotation[i]) % 4;
847 break;
848 }
849
850 DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
851 posx, posy, outw, outh);
852
853 if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
854 xres = var->yres;
855 yres = var->xres;
856 } else {
857 xres = var->xres;
858 yres = var->yres;
859 }
860
861
862 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
863 data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
864 data_start_v = NULL;
865 } else {
866 data_start_p = omapfb_get_region_paddr(ofbi);
867 data_start_v = omapfb_get_region_vaddr(ofbi);
868 }
869
870 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
871 offset = calc_rotation_offset_vrfb(var, fix, rotation);
872 else
873 offset = calc_rotation_offset_dma(var, fix, rotation);
874
875 data_start_p += offset;
876 data_start_v += offset;
877
878 if (offset)
879 DBG("offset %d, %d = %d\n",
880 var->xoffset, var->yoffset, offset);
881
882 DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
883
884 r = fb_mode_to_dss_mode(var, &mode);
885 if (r) {
886 DBG("fb_mode_to_dss_mode failed");
887 goto err;
888 }
889
890 switch (var->nonstd) {
891 case OMAPFB_COLOR_YUV422:
892 case OMAPFB_COLOR_YUY422:
893 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
894 screen_width = fix->line_length
895 / (var->bits_per_pixel >> 2);
896 break;
897 }
898 default:
899 screen_width = fix->line_length / (var->bits_per_pixel >> 3);
900 break;
901 }
902
903 ovl->get_overlay_info(ovl, &info);
904
905 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
906 mirror = 0;
907 else
908 mirror = ofbi->mirror;
909
910 info.paddr = data_start_p;
911 info.vaddr = data_start_v;
912 info.screen_width = screen_width;
913 info.width = xres;
914 info.height = yres;
915 info.color_mode = mode;
916 info.rotation_type = ofbi->rotation_type;
917 info.rotation = rotation;
918 info.mirror = mirror;
919
920 info.pos_x = posx;
921 info.pos_y = posy;
922 info.out_width = outw;
923 info.out_height = outh;
924
925 r = ovl->set_overlay_info(ovl, &info);
926 if (r) {
927 DBG("ovl->setup_overlay_info failed\n");
928 goto err;
929 }
930
931 return 0;
932
933err:
934 DBG("setup_overlay failed\n");
935 return r;
936}
937
938/* apply var to the overlay */
939int omapfb_apply_changes(struct fb_info *fbi, int init)
940{
941 int r = 0;
942 struct omapfb_info *ofbi = FB2OFB(fbi);
943 struct fb_var_screeninfo *var = &fbi->var;
944 struct omap_overlay *ovl;
945 u16 posx, posy;
946 u16 outw, outh;
947 int i;
948
949#ifdef DEBUG
950 if (omapfb_test_pattern)
951 fill_fb(fbi);
952#endif
953
954 for (i = 0; i < ofbi->num_overlays; i++) {
955 ovl = ofbi->overlays[i];
956
957 DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
958
959 if (ofbi->region.size == 0) {
960 /* the fb is not available. disable the overlay */
961 omapfb_overlay_enable(ovl, 0);
962 if (!init && ovl->manager)
963 ovl->manager->apply(ovl->manager);
964 continue;
965 }
966
967 if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
968 int rotation = (var->rotate + ofbi->rotation[i]) % 4;
969 if (rotation == FB_ROTATE_CW ||
970 rotation == FB_ROTATE_CCW) {
971 outw = var->yres;
972 outh = var->xres;
973 } else {
974 outw = var->xres;
975 outh = var->yres;
976 }
977 } else {
978 outw = ovl->info.out_width;
979 outh = ovl->info.out_height;
980 }
981
982 if (init) {
983 posx = 0;
984 posy = 0;
985 } else {
986 posx = ovl->info.pos_x;
987 posy = ovl->info.pos_y;
988 }
989
990 r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
991 if (r)
992 goto err;
993
994 if (!init && ovl->manager)
995 ovl->manager->apply(ovl->manager);
996 }
997 return 0;
998err:
999 DBG("apply_changes failed\n");
1000 return r;
1001}
1002
1003/* checks var and eventually tweaks it to something supported,
1004 * DO NOT MODIFY PAR */
1005static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
1006{
1007 int r;
1008
1009 DBG("check_var(%d)\n", FB2OFB(fbi)->id);
1010
1011 r = check_fb_var(fbi, var);
1012
1013 return r;
1014}
1015
1016/* set the video mode according to info->var */
1017static int omapfb_set_par(struct fb_info *fbi)
1018{
1019 int r;
1020
1021 DBG("set_par(%d)\n", FB2OFB(fbi)->id);
1022
1023 set_fb_fix(fbi);
1024
1025 r = setup_vrfb_rotation(fbi);
1026 if (r)
1027 return r;
1028
1029 r = omapfb_apply_changes(fbi, 0);
1030
1031 return r;
1032}
1033
1034static int omapfb_pan_display(struct fb_var_screeninfo *var,
1035 struct fb_info *fbi)
1036{
1037 struct fb_var_screeninfo new_var;
1038 int r;
1039
1040 DBG("pan_display(%d)\n", FB2OFB(fbi)->id);
1041
1042 if (var->xoffset == fbi->var.xoffset &&
1043 var->yoffset == fbi->var.yoffset)
1044 return 0;
1045
1046 new_var = fbi->var;
1047 new_var.xoffset = var->xoffset;
1048 new_var.yoffset = var->yoffset;
1049
1050 fbi->var = new_var;
1051
1052 r = omapfb_apply_changes(fbi, 0);
1053
1054 return r;
1055}
1056
1057static void mmap_user_open(struct vm_area_struct *vma)
1058{
1059 struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
1060
1061 atomic_inc(&ofbi->map_count);
1062}
1063
1064static void mmap_user_close(struct vm_area_struct *vma)
1065{
1066 struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
1067
1068 atomic_dec(&ofbi->map_count);
1069}
1070
1071static struct vm_operations_struct mmap_user_ops = {
1072 .open = mmap_user_open,
1073 .close = mmap_user_close,
1074};
1075
1076static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
1077{
1078 struct omapfb_info *ofbi = FB2OFB(fbi);
1079 struct fb_fix_screeninfo *fix = &fbi->fix;
1080 unsigned long off;
1081 unsigned long start;
1082 u32 len;
1083
1084 if (vma->vm_end - vma->vm_start == 0)
1085 return 0;
1086 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1087 return -EINVAL;
1088 off = vma->vm_pgoff << PAGE_SHIFT;
1089
1090 start = omapfb_get_region_paddr(ofbi);
1091 len = fix->smem_len;
1092 if (off >= len)
1093 return -EINVAL;
1094 if ((vma->vm_end - vma->vm_start + off) > len)
1095 return -EINVAL;
1096
1097 off += start;
1098
1099 DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
1100
1101 vma->vm_pgoff = off >> PAGE_SHIFT;
1102 vma->vm_flags |= VM_IO | VM_RESERVED;
1103 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1104 vma->vm_ops = &mmap_user_ops;
1105 vma->vm_private_data = ofbi;
1106 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
1107 vma->vm_end - vma->vm_start, vma->vm_page_prot))
1108 return -EAGAIN;
1109 /* vm_ops.open won't be called for mmap itself. */
1110 atomic_inc(&ofbi->map_count);
1111 return 0;
1112}
1113
1114/* Store a single color palette entry into a pseudo palette or the hardware
1115 * palette if one is available. For now we support only 16bpp and thus store
1116 * the entry only to the pseudo palette.
1117 */
1118static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
1119 u_int blue, u_int transp, int update_hw_pal)
1120{
1121 /*struct omapfb_info *ofbi = FB2OFB(fbi);*/
1122 /*struct omapfb2_device *fbdev = ofbi->fbdev;*/
1123 struct fb_var_screeninfo *var = &fbi->var;
1124 int r = 0;
1125
1126 enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
1127
1128 /*switch (plane->color_mode) {*/
1129 switch (mode) {
1130 case OMAPFB_COLOR_YUV422:
1131 case OMAPFB_COLOR_YUV420:
1132 case OMAPFB_COLOR_YUY422:
1133 r = -EINVAL;
1134 break;
1135 case OMAPFB_COLOR_CLUT_8BPP:
1136 case OMAPFB_COLOR_CLUT_4BPP:
1137 case OMAPFB_COLOR_CLUT_2BPP:
1138 case OMAPFB_COLOR_CLUT_1BPP:
1139 /*
1140 if (fbdev->ctrl->setcolreg)
1141 r = fbdev->ctrl->setcolreg(regno, red, green, blue,
1142 transp, update_hw_pal);
1143 */
1144 /* Fallthrough */
1145 r = -EINVAL;
1146 break;
1147 case OMAPFB_COLOR_RGB565:
1148 case OMAPFB_COLOR_RGB444:
1149 case OMAPFB_COLOR_RGB24P:
1150 case OMAPFB_COLOR_RGB24U:
1151 if (r != 0)
1152 break;
1153
1154 if (regno < 0) {
1155 r = -EINVAL;
1156 break;
1157 }
1158
1159 if (regno < 16) {
1160 u16 pal;
1161 pal = ((red >> (16 - var->red.length)) <<
1162 var->red.offset) |
1163 ((green >> (16 - var->green.length)) <<
1164 var->green.offset) |
1165 (blue >> (16 - var->blue.length));
1166 ((u32 *)(fbi->pseudo_palette))[regno] = pal;
1167 }
1168 break;
1169 default:
1170 BUG();
1171 }
1172 return r;
1173}
1174
1175static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1176 u_int transp, struct fb_info *info)
1177{
1178 DBG("setcolreg\n");
1179
1180 return _setcolreg(info, regno, red, green, blue, transp, 1);
1181}
1182
1183static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1184{
1185 int count, index, r;
1186 u16 *red, *green, *blue, *transp;
1187 u16 trans = 0xffff;
1188
1189 DBG("setcmap\n");
1190
1191 red = cmap->red;
1192 green = cmap->green;
1193 blue = cmap->blue;
1194 transp = cmap->transp;
1195 index = cmap->start;
1196
1197 for (count = 0; count < cmap->len; count++) {
1198 if (transp)
1199 trans = *transp++;
1200 r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
1201 count == cmap->len - 1);
1202 if (r != 0)
1203 return r;
1204 }
1205
1206 return 0;
1207}
1208
1209static int omapfb_blank(int blank, struct fb_info *fbi)
1210{
1211 struct omapfb_info *ofbi = FB2OFB(fbi);
1212 struct omapfb2_device *fbdev = ofbi->fbdev;
1213 struct omap_dss_device *display = fb2display(fbi);
1214 int do_update = 0;
1215 int r = 0;
1216
1217 omapfb_lock(fbdev);
1218
1219 switch (blank) {
1220 case FB_BLANK_UNBLANK:
1221 if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
1222 goto exit;
1223
1224 if (display->resume)
1225 r = display->resume(display);
1226
1227 if (r == 0 && display->get_update_mode &&
1228 display->get_update_mode(display) ==
1229 OMAP_DSS_UPDATE_MANUAL)
1230 do_update = 1;
1231
1232 break;
1233
1234 case FB_BLANK_NORMAL:
1235 /* FB_BLANK_NORMAL could be implemented.
1236 * Needs DSS additions. */
1237 case FB_BLANK_VSYNC_SUSPEND:
1238 case FB_BLANK_HSYNC_SUSPEND:
1239 case FB_BLANK_POWERDOWN:
1240 if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
1241 goto exit;
1242
1243 if (display->suspend)
1244 r = display->suspend(display);
1245
1246 break;
1247
1248 default:
1249 r = -EINVAL;
1250 }
1251
1252exit:
1253 omapfb_unlock(fbdev);
1254
1255 if (r == 0 && do_update && display->update) {
1256 u16 w, h;
1257 display->get_resolution(display, &w, &h);
1258
1259 r = display->update(display, 0, 0, w, h);
1260 }
1261
1262 return r;
1263}
1264
1265#if 0
1266/* XXX fb_read and fb_write are needed for VRFB */
1267ssize_t omapfb_write(struct fb_info *info, const char __user *buf,
1268 size_t count, loff_t *ppos)
1269{
1270 DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
1271 /* XXX needed for VRFB */
1272 return count;
1273}
1274#endif
1275
1276static struct fb_ops omapfb_ops = {
1277 .owner = THIS_MODULE,
1278 .fb_open = omapfb_open,
1279 .fb_release = omapfb_release,
1280 .fb_fillrect = cfb_fillrect,
1281 .fb_copyarea = cfb_copyarea,
1282 .fb_imageblit = cfb_imageblit,
1283 .fb_blank = omapfb_blank,
1284 .fb_ioctl = omapfb_ioctl,
1285 .fb_check_var = omapfb_check_var,
1286 .fb_set_par = omapfb_set_par,
1287 .fb_pan_display = omapfb_pan_display,
1288 .fb_mmap = omapfb_mmap,
1289 .fb_setcolreg = omapfb_setcolreg,
1290 .fb_setcmap = omapfb_setcmap,
1291 /*.fb_write = omapfb_write,*/
1292};
1293
1294static void omapfb_free_fbmem(struct fb_info *fbi)
1295{
1296 struct omapfb_info *ofbi = FB2OFB(fbi);
1297 struct omapfb2_device *fbdev = ofbi->fbdev;
1298 struct omapfb2_mem_region *rg;
1299
1300 rg = &ofbi->region;
1301
1302 if (rg->paddr)
1303 if (omap_vram_free(rg->paddr, rg->size))
1304 dev_err(fbdev->dev, "VRAM FREE failed\n");
1305
1306 if (rg->vaddr)
1307 iounmap(rg->vaddr);
1308
1309 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1310 /* unmap the 0 angle rotation */
1311 if (rg->vrfb.vaddr[0]) {
1312 iounmap(rg->vrfb.vaddr[0]);
1313 omap_vrfb_release_ctx(&rg->vrfb);
1314 }
1315 }
1316
1317 rg->vaddr = NULL;
1318 rg->paddr = 0;
1319 rg->alloc = 0;
1320 rg->size = 0;
1321}
1322
1323static void clear_fb_info(struct fb_info *fbi)
1324{
1325 memset(&fbi->var, 0, sizeof(fbi->var));
1326 memset(&fbi->fix, 0, sizeof(fbi->fix));
1327 strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
1328}
1329
1330static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
1331{
1332 int i;
1333
1334 DBG("free all fbmem\n");
1335
1336 for (i = 0; i < fbdev->num_fbs; i++) {
1337 struct fb_info *fbi = fbdev->fbs[i];
1338 omapfb_free_fbmem(fbi);
1339 clear_fb_info(fbi);
1340 }
1341
1342 return 0;
1343}
1344
1345static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
1346 unsigned long paddr)
1347{
1348 struct omapfb_info *ofbi = FB2OFB(fbi);
1349 struct omapfb2_device *fbdev = ofbi->fbdev;
1350 struct omapfb2_mem_region *rg;
1351 void __iomem *vaddr;
1352 int r;
1353
1354 rg = &ofbi->region;
1355 memset(rg, 0, sizeof(*rg));
1356
1357 size = PAGE_ALIGN(size);
1358
1359 if (!paddr) {
1360 DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
1361 r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr);
1362 } else {
1363 DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
1364 ofbi->id);
1365 r = omap_vram_reserve(paddr, size);
1366 }
1367
1368 if (r) {
1369 dev_err(fbdev->dev, "failed to allocate framebuffer\n");
1370 return -ENOMEM;
1371 }
1372
1373 if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
1374 vaddr = ioremap_wc(paddr, size);
1375
1376 if (!vaddr) {
1377 dev_err(fbdev->dev, "failed to ioremap framebuffer\n");
1378 omap_vram_free(paddr, size);
1379 return -ENOMEM;
1380 }
1381
1382 DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
1383 } else {
1384 r = omap_vrfb_request_ctx(&rg->vrfb);
1385 if (r) {
1386 dev_err(fbdev->dev, "vrfb create ctx failed\n");
1387 return r;
1388 }
1389
1390 vaddr = NULL;
1391 }
1392
1393 rg->paddr = paddr;
1394 rg->vaddr = vaddr;
1395 rg->size = size;
1396 rg->alloc = 1;
1397
1398 return 0;
1399}
1400
1401/* allocate fbmem using display resolution as reference */
1402static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
1403 unsigned long paddr)
1404{
1405 struct omapfb_info *ofbi = FB2OFB(fbi);
1406 struct omap_dss_device *display;
1407 int bytespp;
1408
1409 display = fb2display(fbi);
1410
1411 if (!display)
1412 return 0;
1413
1414 switch (display->get_recommended_bpp(display)) {
1415 case 16:
1416 bytespp = 2;
1417 break;
1418 case 24:
1419 bytespp = 4;
1420 break;
1421 default:
1422 bytespp = 4;
1423 break;
1424 }
1425
1426 if (!size) {
1427 u16 w, h;
1428
1429 display->get_resolution(display, &w, &h);
1430
1431 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1432 size = max(omap_vrfb_min_phys_size(w, h, bytespp),
1433 omap_vrfb_min_phys_size(h, w, bytespp));
1434
1435 DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
1436 w * h * bytespp, size);
1437 } else {
1438 size = w * h * bytespp;
1439 }
1440 }
1441
1442 if (!size)
1443 return 0;
1444
1445 return omapfb_alloc_fbmem(fbi, size, paddr);
1446}
1447
1448static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt)
1449{
1450 enum omap_color_mode mode;
1451
1452 switch (fmt) {
1453 case OMAPFB_COLOR_RGB565:
1454 mode = OMAP_DSS_COLOR_RGB16;
1455 break;
1456 case OMAPFB_COLOR_YUV422:
1457 mode = OMAP_DSS_COLOR_YUV2;
1458 break;
1459 case OMAPFB_COLOR_CLUT_8BPP:
1460 mode = OMAP_DSS_COLOR_CLUT8;
1461 break;
1462 case OMAPFB_COLOR_CLUT_4BPP:
1463 mode = OMAP_DSS_COLOR_CLUT4;
1464 break;
1465 case OMAPFB_COLOR_CLUT_2BPP:
1466 mode = OMAP_DSS_COLOR_CLUT2;
1467 break;
1468 case OMAPFB_COLOR_CLUT_1BPP:
1469 mode = OMAP_DSS_COLOR_CLUT1;
1470 break;
1471 case OMAPFB_COLOR_RGB444:
1472 mode = OMAP_DSS_COLOR_RGB12U;
1473 break;
1474 case OMAPFB_COLOR_YUY422:
1475 mode = OMAP_DSS_COLOR_UYVY;
1476 break;
1477 case OMAPFB_COLOR_ARGB16:
1478 mode = OMAP_DSS_COLOR_ARGB16;
1479 break;
1480 case OMAPFB_COLOR_RGB24U:
1481 mode = OMAP_DSS_COLOR_RGB24U;
1482 break;
1483 case OMAPFB_COLOR_RGB24P:
1484 mode = OMAP_DSS_COLOR_RGB24P;
1485 break;
1486 case OMAPFB_COLOR_ARGB32:
1487 mode = OMAP_DSS_COLOR_ARGB32;
1488 break;
1489 case OMAPFB_COLOR_RGBA32:
1490 mode = OMAP_DSS_COLOR_RGBA32;
1491 break;
1492 case OMAPFB_COLOR_RGBX32:
1493 mode = OMAP_DSS_COLOR_RGBX32;
1494 break;
1495 default:
1496 mode = -EINVAL;
1497 }
1498
1499 return mode;
1500}
1501
1502static int omapfb_parse_vram_param(const char *param, int max_entries,
1503 unsigned long *sizes, unsigned long *paddrs)
1504{
1505 int fbnum;
1506 unsigned long size;
1507 unsigned long paddr = 0;
1508 char *p, *start;
1509
1510 start = (char *)param;
1511
1512 while (1) {
1513 p = start;
1514
1515 fbnum = simple_strtoul(p, &p, 10);
1516
1517 if (p == param)
1518 return -EINVAL;
1519
1520 if (*p != ':')
1521 return -EINVAL;
1522
1523 if (fbnum >= max_entries)
1524 return -EINVAL;
1525
1526 size = memparse(p + 1, &p);
1527
1528 if (!size)
1529 return -EINVAL;
1530
1531 paddr = 0;
1532
1533 if (*p == '@') {
1534 paddr = simple_strtoul(p + 1, &p, 16);
1535
1536 if (!paddr)
1537 return -EINVAL;
1538
1539 }
1540
1541 paddrs[fbnum] = paddr;
1542 sizes[fbnum] = size;
1543
1544 if (*p == 0)
1545 break;
1546
1547 if (*p != ',')
1548 return -EINVAL;
1549
1550 ++p;
1551
1552 start = p;
1553 }
1554
1555 return 0;
1556}
1557
1558static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
1559{
1560 int i, r;
1561 unsigned long vram_sizes[10];
1562 unsigned long vram_paddrs[10];
1563
1564 memset(&vram_sizes, 0, sizeof(vram_sizes));
1565 memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1566
1567 if (def_vram && omapfb_parse_vram_param(def_vram, 10,
1568 vram_sizes, vram_paddrs)) {
1569 dev_err(fbdev->dev, "failed to parse vram parameter\n");
1570
1571 memset(&vram_sizes, 0, sizeof(vram_sizes));
1572 memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1573 }
1574
1575 if (fbdev->dev->platform_data) {
1576 struct omapfb_platform_data *opd;
1577 opd = fbdev->dev->platform_data;
1578 for (i = 0; i < opd->mem_desc.region_cnt; ++i) {
1579 if (!vram_sizes[i]) {
1580 unsigned long size;
1581 unsigned long paddr;
1582
1583 size = opd->mem_desc.region[i].size;
1584 paddr = opd->mem_desc.region[i].paddr;
1585
1586 vram_sizes[i] = size;
1587 vram_paddrs[i] = paddr;
1588 }
1589 }
1590 }
1591
1592 for (i = 0; i < fbdev->num_fbs; i++) {
1593 /* allocate memory automatically only for fb0, or if
1594 * excplicitly defined with vram or plat data option */
1595 if (i == 0 || vram_sizes[i] != 0) {
1596 r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
1597 vram_sizes[i], vram_paddrs[i]);
1598
1599 if (r)
1600 return r;
1601 }
1602 }
1603
1604 for (i = 0; i < fbdev->num_fbs; i++) {
1605 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1606 struct omapfb2_mem_region *rg;
1607 rg = &ofbi->region;
1608
1609 DBG("region%d phys %08x virt %p size=%lu\n",
1610 i,
1611 rg->paddr,
1612 rg->vaddr,
1613 rg->size);
1614 }
1615
1616 return 0;
1617}
1618
1619int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
1620{
1621 struct omapfb_info *ofbi = FB2OFB(fbi);
1622 struct omapfb2_device *fbdev = ofbi->fbdev;
1623 struct omap_dss_device *display = fb2display(fbi);
1624 struct omapfb2_mem_region *rg = &ofbi->region;
1625 unsigned long old_size = rg->size;
1626 unsigned long old_paddr = rg->paddr;
1627 int old_type = rg->type;
1628 int r;
1629
1630 if (type > OMAPFB_MEMTYPE_MAX)
1631 return -EINVAL;
1632
1633 size = PAGE_ALIGN(size);
1634
1635 if (old_size == size && old_type == type)
1636 return 0;
1637
1638 if (display && display->sync)
1639 display->sync(display);
1640
1641 omapfb_free_fbmem(fbi);
1642
1643 if (size == 0) {
1644 clear_fb_info(fbi);
1645 return 0;
1646 }
1647
1648 r = omapfb_alloc_fbmem(fbi, size, 0);
1649
1650 if (r) {
1651 if (old_size)
1652 omapfb_alloc_fbmem(fbi, old_size, old_paddr);
1653
1654 if (rg->size == 0)
1655 clear_fb_info(fbi);
1656
1657 return r;
1658 }
1659
1660 if (old_size == size)
1661 return 0;
1662
1663 if (old_size == 0) {
1664 DBG("initializing fb %d\n", ofbi->id);
1665 r = omapfb_fb_init(fbdev, fbi);
1666 if (r) {
1667 DBG("omapfb_fb_init failed\n");
1668 goto err;
1669 }
1670 r = omapfb_apply_changes(fbi, 1);
1671 if (r) {
1672 DBG("omapfb_apply_changes failed\n");
1673 goto err;
1674 }
1675 } else {
1676 struct fb_var_screeninfo new_var;
1677 memcpy(&new_var, &fbi->var, sizeof(new_var));
1678 r = check_fb_var(fbi, &new_var);
1679 if (r)
1680 goto err;
1681 memcpy(&fbi->var, &new_var, sizeof(fbi->var));
1682 set_fb_fix(fbi);
1683 r = setup_vrfb_rotation(fbi);
1684 if (r)
1685 goto err;
1686 }
1687
1688 return 0;
1689err:
1690 omapfb_free_fbmem(fbi);
1691 clear_fb_info(fbi);
1692 return r;
1693}
1694
1695/* initialize fb_info, var, fix to something sane based on the display */
1696static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
1697{
1698 struct fb_var_screeninfo *var = &fbi->var;
1699 struct omap_dss_device *display = fb2display(fbi);
1700 struct omapfb_info *ofbi = FB2OFB(fbi);
1701 int r = 0;
1702
1703 fbi->fbops = &omapfb_ops;
1704 fbi->flags = FBINFO_FLAG_DEFAULT;
1705 fbi->pseudo_palette = fbdev->pseudo_palette;
1706
1707 if (ofbi->region.size == 0) {
1708 clear_fb_info(fbi);
1709 return 0;
1710 }
1711
1712 var->nonstd = 0;
1713 var->bits_per_pixel = 0;
1714
1715 var->rotate = def_rotate;
1716
1717 /*
1718 * Check if there is a default color format set in the board file,
1719 * and use this format instead the default deducted from the
1720 * display bpp.
1721 */
1722 if (fbdev->dev->platform_data) {
1723 struct omapfb_platform_data *opd;
1724 int id = ofbi->id;
1725
1726 opd = fbdev->dev->platform_data;
1727 if (opd->mem_desc.region[id].format_used) {
1728 enum omap_color_mode mode;
1729 enum omapfb_color_format format;
1730
1731 format = opd->mem_desc.region[id].format;
1732 mode = fb_format_to_dss_mode(format);
1733 if (mode < 0) {
1734 r = mode;
1735 goto err;
1736 }
1737 r = dss_mode_to_fb_mode(mode, var);
1738 if (r < 0)
1739 goto err;
1740 }
1741 }
1742
1743 if (display) {
1744 u16 w, h;
1745 int rotation = (var->rotate + ofbi->rotation[0]) % 4;
1746
1747 display->get_resolution(display, &w, &h);
1748
1749 if (rotation == FB_ROTATE_CW ||
1750 rotation == FB_ROTATE_CCW) {
1751 var->xres = h;
1752 var->yres = w;
1753 } else {
1754 var->xres = w;
1755 var->yres = h;
1756 }
1757
1758 var->xres_virtual = var->xres;
1759 var->yres_virtual = var->yres;
1760
1761 if (!var->bits_per_pixel) {
1762 switch (display->get_recommended_bpp(display)) {
1763 case 16:
1764 var->bits_per_pixel = 16;
1765 break;
1766 case 24:
1767 var->bits_per_pixel = 32;
1768 break;
1769 default:
1770 dev_err(fbdev->dev, "illegal display "
1771 "bpp\n");
1772 return -EINVAL;
1773 }
1774 }
1775 } else {
1776 /* if there's no display, let's just guess some basic values */
1777 var->xres = 320;
1778 var->yres = 240;
1779 var->xres_virtual = var->xres;
1780 var->yres_virtual = var->yres;
1781 if (!var->bits_per_pixel)
1782 var->bits_per_pixel = 16;
1783 }
1784
1785 r = check_fb_var(fbi, var);
1786 if (r)
1787 goto err;
1788
1789 set_fb_fix(fbi);
1790 r = setup_vrfb_rotation(fbi);
1791 if (r)
1792 goto err;
1793
1794 r = fb_alloc_cmap(&fbi->cmap, 256, 0);
1795 if (r)
1796 dev_err(fbdev->dev, "unable to allocate color map memory\n");
1797
1798err:
1799 return r;
1800}
1801
1802static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
1803{
1804 fb_dealloc_cmap(&fbi->cmap);
1805}
1806
1807
1808static void omapfb_free_resources(struct omapfb2_device *fbdev)
1809{
1810 int i;
1811
1812 DBG("free_resources\n");
1813
1814 if (fbdev == NULL)
1815 return;
1816
1817 for (i = 0; i < fbdev->num_fbs; i++)
1818 unregister_framebuffer(fbdev->fbs[i]);
1819
1820 /* free the reserved fbmem */
1821 omapfb_free_all_fbmem(fbdev);
1822
1823 for (i = 0; i < fbdev->num_fbs; i++) {
1824 fbinfo_cleanup(fbdev, fbdev->fbs[i]);
1825 framebuffer_release(fbdev->fbs[i]);
1826 }
1827
1828 for (i = 0; i < fbdev->num_displays; i++) {
1829 if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
1830 fbdev->displays[i]->disable(fbdev->displays[i]);
1831
1832 omap_dss_put_device(fbdev->displays[i]);
1833 }
1834
1835 dev_set_drvdata(fbdev->dev, NULL);
1836 kfree(fbdev);
1837}
1838
1839static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
1840{
1841 int r, i;
1842
1843 fbdev->num_fbs = 0;
1844
1845 DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
1846
1847 /* allocate fb_infos */
1848 for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
1849 struct fb_info *fbi;
1850 struct omapfb_info *ofbi;
1851
1852 fbi = framebuffer_alloc(sizeof(struct omapfb_info),
1853 fbdev->dev);
1854
1855 if (fbi == NULL) {
1856 dev_err(fbdev->dev,
1857 "unable to allocate memory for plane info\n");
1858 return -ENOMEM;
1859 }
1860
1861 clear_fb_info(fbi);
1862
1863 fbdev->fbs[i] = fbi;
1864
1865 ofbi = FB2OFB(fbi);
1866 ofbi->fbdev = fbdev;
1867 ofbi->id = i;
1868
1869 /* assign these early, so that fb alloc can use them */
1870 ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
1871 OMAP_DSS_ROT_DMA;
1872 ofbi->mirror = def_mirror;
1873
1874 fbdev->num_fbs++;
1875 }
1876
1877 DBG("fb_infos allocated\n");
1878
1879 /* assign overlays for the fbs */
1880 for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
1881 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1882
1883 ofbi->overlays[0] = fbdev->overlays[i];
1884 ofbi->num_overlays = 1;
1885 }
1886
1887 /* allocate fb memories */
1888 r = omapfb_allocate_all_fbs(fbdev);
1889 if (r) {
1890 dev_err(fbdev->dev, "failed to allocate fbmem\n");
1891 return r;
1892 }
1893
1894 DBG("fbmems allocated\n");
1895
1896 /* setup fb_infos */
1897 for (i = 0; i < fbdev->num_fbs; i++) {
1898 r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
1899 if (r) {
1900 dev_err(fbdev->dev, "failed to setup fb_info\n");
1901 return r;
1902 }
1903 }
1904
1905 DBG("fb_infos initialized\n");
1906
1907 for (i = 0; i < fbdev->num_fbs; i++) {
1908 r = register_framebuffer(fbdev->fbs[i]);
1909 if (r != 0) {
1910 dev_err(fbdev->dev,
1911 "registering framebuffer %d failed\n", i);
1912 return r;
1913 }
1914 }
1915
1916 DBG("framebuffers registered\n");
1917
1918 for (i = 0; i < fbdev->num_fbs; i++) {
1919 r = omapfb_apply_changes(fbdev->fbs[i], 1);
1920 if (r) {
1921 dev_err(fbdev->dev, "failed to change mode\n");
1922 return r;
1923 }
1924 }
1925
1926 DBG("create sysfs for fbs\n");
1927 r = omapfb_create_sysfs(fbdev);
1928 if (r) {
1929 dev_err(fbdev->dev, "failed to create sysfs entries\n");
1930 return r;
1931 }
1932
1933 /* Enable fb0 */
1934 if (fbdev->num_fbs > 0) {
1935 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
1936
1937 if (ofbi->num_overlays > 0) {
1938 struct omap_overlay *ovl = ofbi->overlays[0];
1939
1940 r = omapfb_overlay_enable(ovl, 1);
1941
1942 if (r) {
1943 dev_err(fbdev->dev,
1944 "failed to enable overlay\n");
1945 return r;
1946 }
1947 }
1948 }
1949
1950 DBG("create_framebuffers done\n");
1951
1952 return 0;
1953}
1954
1955static int omapfb_mode_to_timings(const char *mode_str,
1956 struct omap_video_timings *timings, u8 *bpp)
1957{
1958 struct fb_info fbi;
1959 struct fb_var_screeninfo var;
1960 struct fb_ops fbops;
1961 int r;
1962
1963#ifdef CONFIG_OMAP2_DSS_VENC
1964 if (strcmp(mode_str, "pal") == 0) {
1965 *timings = omap_dss_pal_timings;
1966 *bpp = 0;
1967 return 0;
1968 } else if (strcmp(mode_str, "ntsc") == 0) {
1969 *timings = omap_dss_ntsc_timings;
1970 *bpp = 0;
1971 return 0;
1972 }
1973#endif
1974
1975 /* this is quite a hack, but I wanted to use the modedb and for
1976 * that we need fb_info and var, so we create dummy ones */
1977
1978 memset(&fbi, 0, sizeof(fbi));
1979 memset(&var, 0, sizeof(var));
1980 memset(&fbops, 0, sizeof(fbops));
1981 fbi.fbops = &fbops;
1982
1983 r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);
1984
1985 if (r != 0) {
1986 timings->pixel_clock = PICOS2KHZ(var.pixclock);
1987 timings->hfp = var.left_margin;
1988 timings->hbp = var.right_margin;
1989 timings->vfp = var.upper_margin;
1990 timings->vbp = var.lower_margin;
1991 timings->hsw = var.hsync_len;
1992 timings->vsw = var.vsync_len;
1993 timings->x_res = var.xres;
1994 timings->y_res = var.yres;
1995
1996 switch (var.bits_per_pixel) {
1997 case 16:
1998 *bpp = 16;
1999 break;
2000 case 24:
2001 case 32:
2002 default:
2003 *bpp = 24;
2004 break;
2005 }
2006
2007 return 0;
2008 } else {
2009 return -EINVAL;
2010 }
2011}
2012
2013static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str)
2014{
2015 int r;
2016 u8 bpp;
2017 struct omap_video_timings timings;
2018
2019 r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
2020 if (r)
2021 return r;
2022
2023 display->panel.recommended_bpp = bpp;
2024
2025 if (!display->check_timings || !display->set_timings)
2026 return -EINVAL;
2027
2028 r = display->check_timings(display, &timings);
2029 if (r)
2030 return r;
2031
2032 display->set_timings(display, &timings);
2033
2034 return 0;
2035}
2036
2037static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
2038{
2039 char *str, *options, *this_opt;
2040 int r = 0;
2041
2042 str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);
2043 strcpy(str, def_mode);
2044 options = str;
2045
2046 while (!r && (this_opt = strsep(&options, ",")) != NULL) {
2047 char *p, *display_str, *mode_str;
2048 struct omap_dss_device *display;
2049 int i;
2050
2051 p = strchr(this_opt, ':');
2052 if (!p) {
2053 r = -EINVAL;
2054 break;
2055 }
2056
2057 *p = 0;
2058 display_str = this_opt;
2059 mode_str = p + 1;
2060
2061 display = NULL;
2062 for (i = 0; i < fbdev->num_displays; ++i) {
2063 if (strcmp(fbdev->displays[i]->name,
2064 display_str) == 0) {
2065 display = fbdev->displays[i];
2066 break;
2067 }
2068 }
2069
2070 if (!display) {
2071 r = -EINVAL;
2072 break;
2073 }
2074
2075 r = omapfb_set_def_mode(display, mode_str);
2076 if (r)
2077 break;
2078 }
2079
2080 kfree(str);
2081
2082 return r;
2083}
2084
2085static int omapfb_probe(struct platform_device *pdev)
2086{
2087 struct omapfb2_device *fbdev = NULL;
2088 int r = 0;
2089 int i;
2090 struct omap_overlay *ovl;
2091 struct omap_dss_device *def_display;
2092 struct omap_dss_device *dssdev;
2093
2094 DBG("omapfb_probe\n");
2095
2096 if (pdev->num_resources != 0) {
2097 dev_err(&pdev->dev, "probed for an unknown device\n");
2098 r = -ENODEV;
2099 goto err0;
2100 }
2101
2102 fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);
2103 if (fbdev == NULL) {
2104 r = -ENOMEM;
2105 goto err0;
2106 }
2107
2108 mutex_init(&fbdev->mtx);
2109
2110 fbdev->dev = &pdev->dev;
2111 platform_set_drvdata(pdev, fbdev);
2112
2113 fbdev->num_displays = 0;
2114 dssdev = NULL;
2115 for_each_dss_dev(dssdev) {
2116 omap_dss_get_device(dssdev);
2117 fbdev->displays[fbdev->num_displays++] = dssdev;
2118 }
2119
2120 if (fbdev->num_displays == 0) {
2121 dev_err(&pdev->dev, "no displays\n");
2122 r = -EINVAL;
2123 goto cleanup;
2124 }
2125
2126 fbdev->num_overlays = omap_dss_get_num_overlays();
2127 for (i = 0; i < fbdev->num_overlays; i++)
2128 fbdev->overlays[i] = omap_dss_get_overlay(i);
2129
2130 fbdev->num_managers = omap_dss_get_num_overlay_managers();
2131 for (i = 0; i < fbdev->num_managers; i++)
2132 fbdev->managers[i] = omap_dss_get_overlay_manager(i);
2133
2134 if (def_mode && strlen(def_mode) > 0) {
2135 if (omapfb_parse_def_modes(fbdev))
2136 dev_warn(&pdev->dev, "cannot parse default modes\n");
2137 }
2138
2139 r = omapfb_create_framebuffers(fbdev);
2140 if (r)
2141 goto cleanup;
2142
2143 for (i = 0; i < fbdev->num_managers; i++) {
2144 struct omap_overlay_manager *mgr;
2145 mgr = fbdev->managers[i];
2146 r = mgr->apply(mgr);
2147 if (r)
2148 dev_warn(fbdev->dev, "failed to apply dispc config\n");
2149 }
2150
2151 DBG("mgr->apply'ed\n");
2152
2153 /* gfx overlay should be the default one. find a display
2154 * connected to that, and use it as default display */
2155 ovl = omap_dss_get_overlay(0);
2156 if (ovl->manager && ovl->manager->device) {
2157 def_display = ovl->manager->device;
2158 } else {
2159 dev_warn(&pdev->dev, "cannot find default display\n");
2160 def_display = NULL;
2161 }
2162
2163 if (def_display) {
2164#ifndef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
2165 u16 w, h;
2166#endif
2167 r = def_display->enable(def_display);
2168 if (r)
2169 dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
2170 def_display->name);
2171
2172 /* set the update mode */
2173 if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
2174#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
2175 if (def_display->enable_te)
2176 def_display->enable_te(def_display, 1);
2177 if (def_display->set_update_mode)
2178 def_display->set_update_mode(def_display,
2179 OMAP_DSS_UPDATE_AUTO);
2180#else /* MANUAL_UPDATE */
2181 if (def_display->enable_te)
2182 def_display->enable_te(def_display, 0);
2183 if (def_display->set_update_mode)
2184 def_display->set_update_mode(def_display,
2185 OMAP_DSS_UPDATE_MANUAL);
2186
2187 def_display->get_resolution(def_display, &w, &h);
2188 def_display->update(def_display, 0, 0, w, h);
2189#endif
2190 } else {
2191 if (def_display->set_update_mode)
2192 def_display->set_update_mode(def_display,
2193 OMAP_DSS_UPDATE_AUTO);
2194 }
2195 }
2196
2197 return 0;
2198
2199cleanup:
2200 omapfb_free_resources(fbdev);
2201err0:
2202 dev_err(&pdev->dev, "failed to setup omapfb\n");
2203 return r;
2204}
2205
2206static int omapfb_remove(struct platform_device *pdev)
2207{
2208 struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
2209
2210 /* FIXME: wait till completion of pending events */
2211
2212 omapfb_remove_sysfs(fbdev);
2213
2214 omapfb_free_resources(fbdev);
2215
2216 return 0;
2217}
2218
2219static struct platform_driver omapfb_driver = {
2220 .probe = omapfb_probe,
2221 .remove = omapfb_remove,
2222 .driver = {
2223 .name = "omapfb",
2224 .owner = THIS_MODULE,
2225 },
2226};
2227
2228static int __init omapfb_init(void)
2229{
2230 DBG("omapfb_init\n");
2231
2232 if (platform_driver_register(&omapfb_driver)) {
2233 printk(KERN_ERR "failed to register omapfb driver\n");
2234 return -ENODEV;
2235 }
2236
2237 return 0;
2238}
2239
2240static void __exit omapfb_exit(void)
2241{
2242 DBG("omapfb_exit\n");
2243 platform_driver_unregister(&omapfb_driver);
2244}
2245
2246module_param_named(mode, def_mode, charp, 0);
2247module_param_named(vram, def_vram, charp, 0);
2248module_param_named(rotate, def_rotate, int, 0);
2249module_param_named(vrfb, def_vrfb, bool, 0);
2250module_param_named(mirror, def_mirror, bool, 0);
2251
2252/* late_initcall to let panel/ctrl drivers loaded first.
2253 * I guess better option would be a more dynamic approach,
2254 * so that omapfb reacts to new panels when they are loaded */
2255late_initcall(omapfb_init);
2256/*module_init(omapfb_init);*/
2257module_exit(omapfb_exit);
2258
2259MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
2260MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
2261MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
new file mode 100644
index 000000000000..62bb88f5c192
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
@@ -0,0 +1,507 @@
1/*
2 * linux/drivers/video/omap2/omapfb-sysfs.c
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <linux/fb.h>
24#include <linux/sysfs.h>
25#include <linux/device.h>
26#include <linux/uaccess.h>
27#include <linux/platform_device.h>
28#include <linux/kernel.h>
29#include <linux/mm.h>
30#include <linux/omapfb.h>
31
32#include <plat/display.h>
33#include <plat/vrfb.h>
34
35#include "omapfb.h"
36
37static ssize_t show_rotate_type(struct device *dev,
38 struct device_attribute *attr, char *buf)
39{
40 struct fb_info *fbi = dev_get_drvdata(dev);
41 struct omapfb_info *ofbi = FB2OFB(fbi);
42
43 return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
44}
45
46static ssize_t store_rotate_type(struct device *dev,
47 struct device_attribute *attr,
48 const char *buf, size_t count)
49{
50 struct fb_info *fbi = dev_get_drvdata(dev);
51 struct omapfb_info *ofbi = FB2OFB(fbi);
52 enum omap_dss_rotation_type rot_type;
53 int r;
54
55 rot_type = simple_strtoul(buf, NULL, 0);
56
57 if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
58 return -EINVAL;
59
60 lock_fb_info(fbi);
61
62 r = 0;
63 if (rot_type == ofbi->rotation_type)
64 goto out;
65
66 if (ofbi->region.size) {
67 r = -EBUSY;
68 goto out;
69 }
70
71 ofbi->rotation_type = rot_type;
72
73 /*
74 * Since the VRAM for this FB is not allocated at the moment we don't
75 * need to do any further parameter checking at this point.
76 */
77out:
78 unlock_fb_info(fbi);
79
80 return r ? r : count;
81}
82
83
84static ssize_t show_mirror(struct device *dev,
85 struct device_attribute *attr, char *buf)
86{
87 struct fb_info *fbi = dev_get_drvdata(dev);
88 struct omapfb_info *ofbi = FB2OFB(fbi);
89
90 return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
91}
92
93static ssize_t store_mirror(struct device *dev,
94 struct device_attribute *attr,
95 const char *buf, size_t count)
96{
97 struct fb_info *fbi = dev_get_drvdata(dev);
98 struct omapfb_info *ofbi = FB2OFB(fbi);
99 bool mirror;
100 int r;
101 struct fb_var_screeninfo new_var;
102
103 mirror = simple_strtoul(buf, NULL, 0);
104
105 if (mirror != 0 && mirror != 1)
106 return -EINVAL;
107
108 lock_fb_info(fbi);
109
110 ofbi->mirror = mirror;
111
112 memcpy(&new_var, &fbi->var, sizeof(new_var));
113 r = check_fb_var(fbi, &new_var);
114 if (r)
115 goto out;
116 memcpy(&fbi->var, &new_var, sizeof(fbi->var));
117
118 set_fb_fix(fbi);
119
120 r = omapfb_apply_changes(fbi, 0);
121 if (r)
122 goto out;
123
124 r = count;
125out:
126 unlock_fb_info(fbi);
127
128 return r;
129}
130
131static ssize_t show_overlays(struct device *dev,
132 struct device_attribute *attr, char *buf)
133{
134 struct fb_info *fbi = dev_get_drvdata(dev);
135 struct omapfb_info *ofbi = FB2OFB(fbi);
136 struct omapfb2_device *fbdev = ofbi->fbdev;
137 ssize_t l = 0;
138 int t;
139
140 omapfb_lock(fbdev);
141 lock_fb_info(fbi);
142
143 for (t = 0; t < ofbi->num_overlays; t++) {
144 struct omap_overlay *ovl = ofbi->overlays[t];
145 int ovlnum;
146
147 for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
148 if (ovl == fbdev->overlays[ovlnum])
149 break;
150
151 l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
152 t == 0 ? "" : ",", ovlnum);
153 }
154
155 l += snprintf(buf + l, PAGE_SIZE - l, "\n");
156
157 unlock_fb_info(fbi);
158 omapfb_unlock(fbdev);
159
160 return l;
161}
162
163static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
164 struct omap_overlay *ovl)
165{
166 int i, t;
167
168 for (i = 0; i < fbdev->num_fbs; i++) {
169 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
170
171 for (t = 0; t < ofbi->num_overlays; t++) {
172 if (ofbi->overlays[t] == ovl)
173 return ofbi;
174 }
175 }
176
177 return NULL;
178}
179
180static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
181 const char *buf, size_t count)
182{
183 struct fb_info *fbi = dev_get_drvdata(dev);
184 struct omapfb_info *ofbi = FB2OFB(fbi);
185 struct omapfb2_device *fbdev = ofbi->fbdev;
186 struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
187 struct omap_overlay *ovl;
188 int num_ovls, r, i;
189 int len;
190 bool added = false;
191
192 num_ovls = 0;
193
194 len = strlen(buf);
195 if (buf[len - 1] == '\n')
196 len = len - 1;
197
198 omapfb_lock(fbdev);
199 lock_fb_info(fbi);
200
201 if (len > 0) {
202 char *p = (char *)buf;
203 int ovlnum;
204
205 while (p < buf + len) {
206 int found;
207 if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
208 r = -EINVAL;
209 goto out;
210 }
211
212 ovlnum = simple_strtoul(p, &p, 0);
213 if (ovlnum > fbdev->num_overlays) {
214 r = -EINVAL;
215 goto out;
216 }
217
218 found = 0;
219 for (i = 0; i < num_ovls; ++i) {
220 if (ovls[i] == fbdev->overlays[ovlnum]) {
221 found = 1;
222 break;
223 }
224 }
225
226 if (!found)
227 ovls[num_ovls++] = fbdev->overlays[ovlnum];
228
229 p++;
230 }
231 }
232
233 for (i = 0; i < num_ovls; ++i) {
234 struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
235 if (ofbi2 && ofbi2 != ofbi) {
236 dev_err(fbdev->dev, "overlay already in use\n");
237 r = -EINVAL;
238 goto out;
239 }
240 }
241
242 /* detach unused overlays */
243 for (i = 0; i < ofbi->num_overlays; ++i) {
244 int t, found;
245
246 ovl = ofbi->overlays[i];
247
248 found = 0;
249
250 for (t = 0; t < num_ovls; ++t) {
251 if (ovl == ovls[t]) {
252 found = 1;
253 break;
254 }
255 }
256
257 if (found)
258 continue;
259
260 DBG("detaching %d\n", ofbi->overlays[i]->id);
261
262 omapfb_overlay_enable(ovl, 0);
263
264 if (ovl->manager)
265 ovl->manager->apply(ovl->manager);
266
267 for (t = i + 1; t < ofbi->num_overlays; t++) {
268 ofbi->rotation[t-1] = ofbi->rotation[t];
269 ofbi->overlays[t-1] = ofbi->overlays[t];
270 }
271
272 ofbi->num_overlays--;
273 i--;
274 }
275
276 for (i = 0; i < num_ovls; ++i) {
277 int t, found;
278
279 ovl = ovls[i];
280
281 found = 0;
282
283 for (t = 0; t < ofbi->num_overlays; ++t) {
284 if (ovl == ofbi->overlays[t]) {
285 found = 1;
286 break;
287 }
288 }
289
290 if (found)
291 continue;
292 ofbi->rotation[ofbi->num_overlays] = 0;
293 ofbi->overlays[ofbi->num_overlays++] = ovl;
294
295 added = true;
296 }
297
298 if (added) {
299 r = omapfb_apply_changes(fbi, 0);
300 if (r)
301 goto out;
302 }
303
304 r = count;
305out:
306 unlock_fb_info(fbi);
307 omapfb_unlock(fbdev);
308
309 return r;
310}
311
312static ssize_t show_overlays_rotate(struct device *dev,
313 struct device_attribute *attr, char *buf)
314{
315 struct fb_info *fbi = dev_get_drvdata(dev);
316 struct omapfb_info *ofbi = FB2OFB(fbi);
317 ssize_t l = 0;
318 int t;
319
320 lock_fb_info(fbi);
321
322 for (t = 0; t < ofbi->num_overlays; t++) {
323 l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
324 t == 0 ? "" : ",", ofbi->rotation[t]);
325 }
326
327 l += snprintf(buf + l, PAGE_SIZE - l, "\n");
328
329 unlock_fb_info(fbi);
330
331 return l;
332}
333
334static ssize_t store_overlays_rotate(struct device *dev,
335 struct device_attribute *attr, const char *buf, size_t count)
336{
337 struct fb_info *fbi = dev_get_drvdata(dev);
338 struct omapfb_info *ofbi = FB2OFB(fbi);
339 int num_ovls = 0, r, i;
340 int len;
341 bool changed = false;
342 u8 rotation[OMAPFB_MAX_OVL_PER_FB];
343
344 len = strlen(buf);
345 if (buf[len - 1] == '\n')
346 len = len - 1;
347
348 lock_fb_info(fbi);
349
350 if (len > 0) {
351 char *p = (char *)buf;
352
353 while (p < buf + len) {
354 int rot;
355
356 if (num_ovls == ofbi->num_overlays) {
357 r = -EINVAL;
358 goto out;
359 }
360
361 rot = simple_strtoul(p, &p, 0);
362 if (rot < 0 || rot > 3) {
363 r = -EINVAL;
364 goto out;
365 }
366
367 if (ofbi->rotation[num_ovls] != rot)
368 changed = true;
369
370 rotation[num_ovls++] = rot;
371
372 p++;
373 }
374 }
375
376 if (num_ovls != ofbi->num_overlays) {
377 r = -EINVAL;
378 goto out;
379 }
380
381 if (changed) {
382 for (i = 0; i < num_ovls; ++i)
383 ofbi->rotation[i] = rotation[i];
384
385 r = omapfb_apply_changes(fbi, 0);
386 if (r)
387 goto out;
388
389 /* FIXME error handling? */
390 }
391
392 r = count;
393out:
394 unlock_fb_info(fbi);
395
396 return r;
397}
398
399static ssize_t show_size(struct device *dev,
400 struct device_attribute *attr, char *buf)
401{
402 struct fb_info *fbi = dev_get_drvdata(dev);
403 struct omapfb_info *ofbi = FB2OFB(fbi);
404
405 return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size);
406}
407
408static ssize_t store_size(struct device *dev, struct device_attribute *attr,
409 const char *buf, size_t count)
410{
411 struct fb_info *fbi = dev_get_drvdata(dev);
412 struct omapfb_info *ofbi = FB2OFB(fbi);
413 unsigned long size;
414 int r;
415 int i;
416
417 size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
418
419 lock_fb_info(fbi);
420
421 for (i = 0; i < ofbi->num_overlays; i++) {
422 if (ofbi->overlays[i]->info.enabled) {
423 r = -EBUSY;
424 goto out;
425 }
426 }
427
428 if (size != ofbi->region.size) {
429 r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type);
430 if (r) {
431 dev_err(dev, "realloc fbmem failed\n");
432 goto out;
433 }
434 }
435
436 r = count;
437out:
438 unlock_fb_info(fbi);
439
440 return r;
441}
442
443static ssize_t show_phys(struct device *dev,
444 struct device_attribute *attr, char *buf)
445{
446 struct fb_info *fbi = dev_get_drvdata(dev);
447 struct omapfb_info *ofbi = FB2OFB(fbi);
448
449 return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr);
450}
451
452static ssize_t show_virt(struct device *dev,
453 struct device_attribute *attr, char *buf)
454{
455 struct fb_info *fbi = dev_get_drvdata(dev);
456 struct omapfb_info *ofbi = FB2OFB(fbi);
457
458 return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr);
459}
460
461static struct device_attribute omapfb_attrs[] = {
462 __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
463 store_rotate_type),
464 __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
465 __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
466 __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
467 __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
468 store_overlays_rotate),
469 __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
470 __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
471};
472
473int omapfb_create_sysfs(struct omapfb2_device *fbdev)
474{
475 int i;
476 int r;
477
478 DBG("create sysfs for fbs\n");
479 for (i = 0; i < fbdev->num_fbs; i++) {
480 int t;
481 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
482 r = device_create_file(fbdev->fbs[i]->dev,
483 &omapfb_attrs[t]);
484
485 if (r) {
486 dev_err(fbdev->dev, "failed to create sysfs "
487 "file\n");
488 return r;
489 }
490 }
491 }
492
493 return 0;
494}
495
496void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
497{
498 int i, t;
499
500 DBG("remove sysfs for fbs\n");
501 for (i = 0; i < fbdev->num_fbs; i++) {
502 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
503 device_remove_file(fbdev->fbs[i]->dev,
504 &omapfb_attrs[t]);
505 }
506}
507
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
new file mode 100644
index 000000000000..f7c9c739e5ef
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -0,0 +1,146 @@
1/*
2 * linux/drivers/video/omap2/omapfb.h
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#ifndef __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
24#define __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
25
26#ifdef CONFIG_FB_OMAP2_DEBUG_SUPPORT
27#define DEBUG
28#endif
29
30#include <plat/display.h>
31
32#ifdef DEBUG
33extern unsigned int omapfb_debug;
34#define DBG(format, ...) \
35 if (omapfb_debug) \
36 printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__)
37#else
38#define DBG(format, ...)
39#endif
40
41#define FB2OFB(fb_info) ((struct omapfb_info *)(fb_info->par))
42
43/* max number of overlays to which a framebuffer data can be direct */
44#define OMAPFB_MAX_OVL_PER_FB 3
45
46struct omapfb2_mem_region {
47 u32 paddr;
48 void __iomem *vaddr;
49 struct vrfb vrfb;
50 unsigned long size;
51 u8 type; /* OMAPFB_PLANE_MEM_* */
52 bool alloc; /* allocated by the driver */
53 bool map; /* kernel mapped by the driver */
54};
55
56/* appended to fb_info */
57struct omapfb_info {
58 int id;
59 struct omapfb2_mem_region region;
60 atomic_t map_count;
61 int num_overlays;
62 struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB];
63 struct omapfb2_device *fbdev;
64 enum omap_dss_rotation_type rotation_type;
65 u8 rotation[OMAPFB_MAX_OVL_PER_FB];
66 bool mirror;
67};
68
69struct omapfb2_device {
70 struct device *dev;
71 struct mutex mtx;
72
73 u32 pseudo_palette[17];
74
75 int state;
76
77 unsigned num_fbs;
78 struct fb_info *fbs[10];
79
80 unsigned num_displays;
81 struct omap_dss_device *displays[10];
82 unsigned num_overlays;
83 struct omap_overlay *overlays[10];
84 unsigned num_managers;
85 struct omap_overlay_manager *managers[10];
86};
87
88struct omapfb_colormode {
89 enum omap_color_mode dssmode;
90 u32 bits_per_pixel;
91 u32 nonstd;
92 struct fb_bitfield red;
93 struct fb_bitfield green;
94 struct fb_bitfield blue;
95 struct fb_bitfield transp;
96};
97
98void set_fb_fix(struct fb_info *fbi);
99int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var);
100int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type);
101int omapfb_apply_changes(struct fb_info *fbi, int init);
102
103int omapfb_create_sysfs(struct omapfb2_device *fbdev);
104void omapfb_remove_sysfs(struct omapfb2_device *fbdev);
105
106int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg);
107
108int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
109 struct fb_var_screeninfo *var);
110
111/* find the display connected to this fb, if any */
112static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
113{
114 struct omapfb_info *ofbi = FB2OFB(fbi);
115 int i;
116
117 /* XXX: returns the display connected to first attached overlay */
118 for (i = 0; i < ofbi->num_overlays; i++) {
119 if (ofbi->overlays[i]->manager)
120 return ofbi->overlays[i]->manager->device;
121 }
122
123 return NULL;
124}
125
126static inline void omapfb_lock(struct omapfb2_device *fbdev)
127{
128 mutex_lock(&fbdev->mtx);
129}
130
131static inline void omapfb_unlock(struct omapfb2_device *fbdev)
132{
133 mutex_unlock(&fbdev->mtx);
134}
135
136static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
137 int enable)
138{
139 struct omap_overlay_info info;
140
141 ovl->get_overlay_info(ovl, &info);
142 info.enabled = enable;
143 return ovl->set_overlay_info(ovl, &info);
144}
145
146#endif