2 * linux/drivers/video/omap2/omapfb-ioctl.c
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7 * Some code and ideas taken from drivers/video/omap/ driver
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.
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
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/>.
24 #include <linux/device.h>
25 #include <linux/uaccess.h>
26 #include <linux/platform_device.h>
28 #include <linux/omapfb.h>
29 #include <linux/vmalloc.h>
31 #include <plat/display.h>
32 #include <plat/vrfb.h>
33 #include <plat/vram.h>
37 static int omapfb_setup_plane(struct fb_info
*fbi
, struct omapfb_plane_info
*pi
)
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
;
45 DBG("omapfb_setup_plane\n");
47 if (ofbi
->num_overlays
!= 1) {
52 /* XXX uses only the first overlay */
53 ovl
= ofbi
->overlays
[0];
55 if (pi
->enabled
&& !ofbi
->region
.size
) {
57 * This plane's memory was freed, can't enable it
58 * until it's reallocated.
64 ovl
->get_overlay_info(ovl
, &info
);
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
;
72 r
= ovl
->set_overlay_info(ovl
, &info
);
77 r
= ovl
->manager
->apply(ovl
->manager
);
84 dev_err(fbdev
->dev
, "setup_plane failed\n");
88 static int omapfb_query_plane(struct fb_info
*fbi
, struct omapfb_plane_info
*pi
)
90 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
92 if (ofbi
->num_overlays
!= 1) {
93 memset(pi
, 0, sizeof(*pi
));
95 struct omap_overlay_info
*ovli
;
96 struct omap_overlay
*ovl
;
98 ovl
= ofbi
->overlays
[0];
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 */
106 pi
->out_width
= ovli
->out_width
;
107 pi
->out_height
= ovli
->out_height
;
113 static int omapfb_setup_mem(struct fb_info
*fbi
, struct omapfb_mem_info
*mi
)
115 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
116 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
117 struct omapfb2_mem_region
*rg
;
121 if (mi
->type
> OMAPFB_MEMTYPE_MAX
)
124 size
= PAGE_ALIGN(mi
->size
);
128 for (i
= 0; i
< ofbi
->num_overlays
; i
++) {
129 if (ofbi
->overlays
[i
]->info
.enabled
)
133 if (rg
->size
!= size
|| rg
->type
!= mi
->type
) {
134 r
= omapfb_realloc_fbmem(fbi
, size
, mi
->type
);
136 dev_err(fbdev
->dev
, "realloc fbmem failed\n");
144 static int omapfb_query_mem(struct fb_info
*fbi
, struct omapfb_mem_info
*mi
)
146 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
147 struct omapfb2_mem_region
*rg
;
150 memset(mi
, 0, sizeof(*mi
));
158 static int omapfb_update_window_nolock(struct fb_info
*fbi
,
159 u32 x
, u32 y
, u32 w
, u32 h
)
161 struct omap_dss_device
*display
= fb2display(fbi
);
167 if (w
== 0 || h
== 0)
170 display
->get_resolution(display
, &dw
, &dh
);
172 if (x
+ w
> dw
|| y
+ h
> dh
)
175 return display
->update(display
, x
, y
, w
, h
);
178 /* This function is exported for SGX driver use */
179 int omapfb_update_window(struct fb_info
*fbi
,
180 u32 x
, u32 y
, u32 w
, u32 h
)
182 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
183 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
189 r
= omapfb_update_window_nolock(fbi
, x
, y
, w
, h
);
192 omapfb_unlock(fbdev
);
196 EXPORT_SYMBOL(omapfb_update_window
);
198 static int omapfb_set_update_mode(struct fb_info
*fbi
,
199 enum omapfb_update_mode mode
)
201 struct omap_dss_device
*display
= fb2display(fbi
);
202 enum omap_dss_update_mode um
;
205 if (!display
|| !display
->set_update_mode
)
209 case OMAPFB_UPDATE_DISABLED
:
210 um
= OMAP_DSS_UPDATE_DISABLED
;
213 case OMAPFB_AUTO_UPDATE
:
214 um
= OMAP_DSS_UPDATE_AUTO
;
217 case OMAPFB_MANUAL_UPDATE
:
218 um
= OMAP_DSS_UPDATE_MANUAL
;
225 r
= display
->set_update_mode(display
, um
);
230 static int omapfb_get_update_mode(struct fb_info
*fbi
,
231 enum omapfb_update_mode
*mode
)
233 struct omap_dss_device
*display
= fb2display(fbi
);
234 enum omap_dss_update_mode m
;
236 if (!display
|| !display
->get_update_mode
)
239 m
= display
->get_update_mode(display
);
242 case OMAP_DSS_UPDATE_DISABLED
:
243 *mode
= OMAPFB_UPDATE_DISABLED
;
245 case OMAP_DSS_UPDATE_AUTO
:
246 *mode
= OMAPFB_AUTO_UPDATE
;
248 case OMAP_DSS_UPDATE_MANUAL
:
249 *mode
= OMAPFB_MANUAL_UPDATE
;
258 /* XXX this color key handling is a hack... */
259 static struct omapfb_color_key omapfb_color_keys
[2];
261 static int _omapfb_set_color_key(struct omap_overlay_manager
*mgr
,
262 struct omapfb_color_key
*ck
)
264 struct omap_overlay_manager_info info
;
265 enum omap_dss_trans_key_type kt
;
268 mgr
->get_manager_info(mgr
, &info
);
270 if (ck
->key_type
== OMAPFB_COLOR_KEY_DISABLED
) {
271 info
.trans_enabled
= false;
272 omapfb_color_keys
[mgr
->id
] = *ck
;
274 r
= mgr
->set_manager_info(mgr
, &info
);
283 switch (ck
->key_type
) {
284 case OMAPFB_COLOR_KEY_GFX_DST
:
285 kt
= OMAP_DSS_COLOR_KEY_GFX_DST
;
287 case OMAPFB_COLOR_KEY_VID_SRC
:
288 kt
= OMAP_DSS_COLOR_KEY_VID_SRC
;
294 info
.default_color
= ck
->background
;
295 info
.trans_key
= ck
->trans_key
;
296 info
.trans_key_type
= kt
;
297 info
.trans_enabled
= true;
299 omapfb_color_keys
[mgr
->id
] = *ck
;
301 r
= mgr
->set_manager_info(mgr
, &info
);
310 static int omapfb_set_color_key(struct fb_info
*fbi
,
311 struct omapfb_color_key
*ck
)
313 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
314 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
317 struct omap_overlay_manager
*mgr
= NULL
;
321 for (i
= 0; i
< ofbi
->num_overlays
; i
++) {
322 if (ofbi
->overlays
[i
]->manager
) {
323 mgr
= ofbi
->overlays
[i
]->manager
;
333 r
= _omapfb_set_color_key(mgr
, ck
);
335 omapfb_unlock(fbdev
);
340 static int omapfb_get_color_key(struct fb_info
*fbi
,
341 struct omapfb_color_key
*ck
)
343 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
344 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
345 struct omap_overlay_manager
*mgr
= NULL
;
351 for (i
= 0; i
< ofbi
->num_overlays
; i
++) {
352 if (ofbi
->overlays
[i
]->manager
) {
353 mgr
= ofbi
->overlays
[i
]->manager
;
363 *ck
= omapfb_color_keys
[mgr
->id
];
365 omapfb_unlock(fbdev
);
370 static int omapfb_memory_read(struct fb_info
*fbi
,
371 struct omapfb_memory_read
*mr
)
373 struct omap_dss_device
*display
= fb2display(fbi
);
377 if (!display
|| !display
->memory_read
)
380 if (!access_ok(VERIFY_WRITE
, mr
->buffer
, mr
->buffer_size
))
383 if (mr
->w
* mr
->h
* 3 > mr
->buffer_size
)
386 buf
= vmalloc(mr
->buffer_size
);
388 DBG("vmalloc failed\n");
392 r
= display
->memory_read(display
, buf
, mr
->buffer_size
,
393 mr
->x
, mr
->y
, mr
->w
, mr
->h
);
396 if (copy_to_user(mr
->buffer
, buf
, mr
->buffer_size
))
405 static int omapfb_get_ovl_colormode(struct omapfb2_device
*fbdev
,
406 struct omapfb_ovl_colormode
*mode
)
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
;
415 if (ovl_idx
>= fbdev
->num_overlays
)
417 ovl
= fbdev
->overlays
[ovl_idx
];
418 supported_modes
= ovl
->supported_modes
;
420 mode_idx
= mode
->mode_idx
;
422 for (i
= 0; i
< sizeof(supported_modes
) * 8; i
++) {
423 if (!(supported_modes
& (1 << i
)))
426 * It's possible that the FB doesn't support a mode
427 * that is supported by the overlay, so call the
430 if (dss_mode_to_fb_mode(1 << i
, &var
) < 0)
438 if (i
== sizeof(supported_modes
) * 8)
441 mode
->bits_per_pixel
= var
.bits_per_pixel
;
442 mode
->nonstd
= var
.nonstd
;
444 mode
->green
= var
.green
;
445 mode
->blue
= var
.blue
;
446 mode
->transp
= var
.transp
;
451 static int omapfb_wait_for_go(struct fb_info
*fbi
)
453 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
457 for (i
= 0; i
< ofbi
->num_overlays
; ++i
) {
458 struct omap_overlay
*ovl
= ofbi
->overlays
[i
];
459 r
= ovl
->wait_for_go(ovl
);
467 int omapfb_ioctl(struct fb_info
*fbi
, unsigned int cmd
, unsigned long arg
)
469 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
470 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
471 struct omap_dss_device
*display
= fb2display(fbi
);
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
;
483 struct omapfb_memory_read memory_read
;
484 struct omapfb_vram_info vram_info
;
485 struct omapfb_tearsync_info tearsync_info
;
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 */
499 r
= display
->sync(display
);
502 case OMAPFB_UPDATE_WINDOW_OLD
:
503 DBG("ioctl UPDATE_WINDOW_OLD\n");
504 if (!display
|| !display
->update
) {
509 if (copy_from_user(&p
.uwnd_o
,
516 r
= omapfb_update_window_nolock(fbi
, p
.uwnd_o
.x
, p
.uwnd_o
.y
,
517 p
.uwnd_o
.width
, p
.uwnd_o
.height
);
520 case OMAPFB_UPDATE_WINDOW
:
521 DBG("ioctl UPDATE_WINDOW\n");
522 if (!display
|| !display
->update
) {
527 if (copy_from_user(&p
.uwnd
, (void __user
*)arg
,
533 r
= omapfb_update_window_nolock(fbi
, p
.uwnd
.x
, p
.uwnd
.y
,
534 p
.uwnd
.width
, p
.uwnd
.height
);
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
)))
543 r
= omapfb_setup_plane(fbi
, &p
.plane_info
);
546 case OMAPFB_QUERY_PLANE
:
547 DBG("ioctl QUERY_PLANE\n");
548 r
= omapfb_query_plane(fbi
, &p
.plane_info
);
551 if (copy_to_user((void __user
*)arg
, &p
.plane_info
,
552 sizeof(p
.plane_info
)))
556 case OMAPFB_SETUP_MEM
:
557 DBG("ioctl SETUP_MEM\n");
558 if (copy_from_user(&p
.mem_info
, (void __user
*)arg
,
562 r
= omapfb_setup_mem(fbi
, &p
.mem_info
);
565 case OMAPFB_QUERY_MEM
:
566 DBG("ioctl QUERY_MEM\n");
567 r
= omapfb_query_mem(fbi
, &p
.mem_info
);
570 if (copy_to_user((void __user
*)arg
, &p
.mem_info
,
575 case OMAPFB_GET_CAPS
:
576 DBG("ioctl GET_CAPS\n");
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
;
588 if (copy_to_user((void __user
*)arg
, &p
.caps
, sizeof(p
.caps
)))
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
))) {
599 r
= omapfb_get_ovl_colormode(fbdev
, &p
.ovl_colormode
);
602 if (copy_to_user((void __user
*)arg
, &p
.ovl_colormode
,
603 sizeof(p
.ovl_colormode
)))
607 case OMAPFB_SET_UPDATE_MODE
:
608 DBG("ioctl SET_UPDATE_MODE\n");
609 if (get_user(p
.update_mode
, (int __user
*)arg
))
612 r
= omapfb_set_update_mode(fbi
, p
.update_mode
);
615 case OMAPFB_GET_UPDATE_MODE
:
616 DBG("ioctl GET_UPDATE_MODE\n");
617 r
= omapfb_get_update_mode(fbi
, &p
.update_mode
);
620 if (put_user(p
.update_mode
,
621 (enum omapfb_update_mode __user
*)arg
))
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
)))
631 r
= omapfb_set_color_key(fbi
, &p
.color_key
);
634 case OMAPFB_GET_COLOR_KEY
:
635 DBG("ioctl GET_COLOR_KEY\n");
636 r
= omapfb_get_color_key(fbi
, &p
.color_key
);
639 if (copy_to_user((void __user
*)arg
, &p
.color_key
,
640 sizeof(p
.color_key
)))
644 case OMAPFB_WAITFORVSYNC
:
645 DBG("ioctl WAITFORVSYNC\n");
651 r
= display
->wait_vsync(display
);
654 case OMAPFB_WAITFORGO
:
655 DBG("ioctl WAITFORGO\n");
661 r
= omapfb_wait_for_go(fbi
);
664 /* LCD and CTRL tests do the same thing for backward
666 case OMAPFB_LCD_TEST
:
667 DBG("ioctl LCD_TEST\n");
668 if (get_user(p
.test_num
, (int __user
*)arg
)) {
672 if (!display
|| !display
->run_test
) {
677 r
= display
->run_test(display
, p
.test_num
);
681 case OMAPFB_CTRL_TEST
:
682 DBG("ioctl CTRL_TEST\n");
683 if (get_user(p
.test_num
, (int __user
*)arg
)) {
687 if (!display
|| !display
->run_test
) {
692 r
= display
->run_test(display
, p
.test_num
);
696 case OMAPFB_MEMORY_READ
:
697 DBG("ioctl MEMORY_READ\n");
699 if (copy_from_user(&p
.memory_read
, (void __user
*)arg
,
700 sizeof(p
.memory_read
))) {
705 r
= omapfb_memory_read(fbi
, &p
.memory_read
);
709 case OMAPFB_GET_VRAM_INFO
: {
710 unsigned long vram
, free
, largest
;
712 DBG("ioctl GET_VRAM_INFO\n");
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
;
719 if (copy_to_user((void __user
*)arg
, &p
.vram_info
,
720 sizeof(p
.vram_info
)))
725 case OMAPFB_SET_TEARSYNC
: {
726 DBG("ioctl SET_TEARSYNC\n");
728 if (copy_from_user(&p
.tearsync_info
, (void __user
*)arg
,
729 sizeof(p
.tearsync_info
))) {
734 if (!display
->enable_te
) {
739 r
= display
->enable_te(display
, !!p
.tearsync_info
.enabled
);
745 dev_err(fbdev
->dev
, "Unknown ioctl 0x%x\n", cmd
);
750 DBG("ioctl failed: %d\n", r
);