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>
30 #include <linux/export.h>
32 #include <video/omapdss.h>
33 #include <plat/vrfb.h>
34 #include <plat/vram.h>
38 static u8
get_mem_idx(struct omapfb_info
*ofbi
)
40 if (ofbi
->id
== ofbi
->region
->id
)
43 return OMAPFB_MEM_IDX_ENABLED
| ofbi
->region
->id
;
46 static struct omapfb2_mem_region
*get_mem_region(struct omapfb_info
*ofbi
,
49 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
51 if (mem_idx
& OMAPFB_MEM_IDX_ENABLED
)
52 mem_idx
&= OMAPFB_MEM_IDX_MASK
;
56 if (mem_idx
>= fbdev
->num_fbs
)
59 return &fbdev
->regions
[mem_idx
];
62 static int omapfb_setup_plane(struct fb_info
*fbi
, struct omapfb_plane_info
*pi
)
64 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
65 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
66 struct omap_overlay
*ovl
;
67 struct omap_overlay_info old_info
;
68 struct omapfb2_mem_region
*old_rg
, *new_rg
;
71 DBG("omapfb_setup_plane\n");
73 if (ofbi
->num_overlays
!= 1) {
78 /* XXX uses only the first overlay */
79 ovl
= ofbi
->overlays
[0];
81 old_rg
= ofbi
->region
;
82 new_rg
= get_mem_region(ofbi
, pi
->mem_idx
);
88 /* Take the locks in a specific order to keep lockdep happy */
89 if (old_rg
->id
< new_rg
->id
) {
90 omapfb_get_mem_region(old_rg
);
91 omapfb_get_mem_region(new_rg
);
92 } else if (new_rg
->id
< old_rg
->id
) {
93 omapfb_get_mem_region(new_rg
);
94 omapfb_get_mem_region(old_rg
);
96 omapfb_get_mem_region(old_rg
);
98 if (pi
->enabled
&& !new_rg
->size
) {
100 * This plane's memory was freed, can't enable it
101 * until it's reallocated.
107 ovl
->get_overlay_info(ovl
, &old_info
);
109 if (old_rg
!= new_rg
) {
110 ofbi
->region
= new_rg
;
115 r
= ovl
->disable(ovl
);
121 r
= omapfb_setup_overlay(fbi
, ovl
, pi
->pos_x
, pi
->pos_y
,
122 pi
->out_width
, pi
->out_height
);
126 struct omap_overlay_info info
;
128 ovl
->get_overlay_info(ovl
, &info
);
130 info
.pos_x
= pi
->pos_x
;
131 info
.pos_y
= pi
->pos_y
;
132 info
.out_width
= pi
->out_width
;
133 info
.out_height
= pi
->out_height
;
135 r
= ovl
->set_overlay_info(ovl
, &info
);
141 ovl
->manager
->apply(ovl
->manager
);
144 r
= ovl
->enable(ovl
);
149 /* Release the locks in a specific order to keep lockdep happy */
150 if (old_rg
->id
> new_rg
->id
) {
151 omapfb_put_mem_region(old_rg
);
152 omapfb_put_mem_region(new_rg
);
153 } else if (new_rg
->id
> old_rg
->id
) {
154 omapfb_put_mem_region(new_rg
);
155 omapfb_put_mem_region(old_rg
);
157 omapfb_put_mem_region(old_rg
);
162 if (old_rg
!= new_rg
) {
163 ofbi
->region
= old_rg
;
167 ovl
->set_overlay_info(ovl
, &old_info
);
169 /* Release the locks in a specific order to keep lockdep happy */
170 if (old_rg
->id
> new_rg
->id
) {
171 omapfb_put_mem_region(old_rg
);
172 omapfb_put_mem_region(new_rg
);
173 } else if (new_rg
->id
> old_rg
->id
) {
174 omapfb_put_mem_region(new_rg
);
175 omapfb_put_mem_region(old_rg
);
177 omapfb_put_mem_region(old_rg
);
179 dev_err(fbdev
->dev
, "setup_plane failed\n");
184 static int omapfb_query_plane(struct fb_info
*fbi
, struct omapfb_plane_info
*pi
)
186 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
188 if (ofbi
->num_overlays
!= 1) {
189 memset(pi
, 0, sizeof(*pi
));
191 struct omap_overlay
*ovl
;
192 struct omap_overlay_info ovli
;
194 ovl
= ofbi
->overlays
[0];
195 ovl
->get_overlay_info(ovl
, &ovli
);
197 pi
->pos_x
= ovli
.pos_x
;
198 pi
->pos_y
= ovli
.pos_y
;
199 pi
->enabled
= ovl
->is_enabled(ovl
);
200 pi
->channel_out
= 0; /* xxx */
202 pi
->mem_idx
= get_mem_idx(ofbi
);
203 pi
->out_width
= ovli
.out_width
;
204 pi
->out_height
= ovli
.out_height
;
210 static int omapfb_setup_mem(struct fb_info
*fbi
, struct omapfb_mem_info
*mi
)
212 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
213 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
214 struct omapfb2_mem_region
*rg
;
218 if (mi
->type
> OMAPFB_MEMTYPE_MAX
)
221 size
= PAGE_ALIGN(mi
->size
);
225 down_write_nested(&rg
->lock
, rg
->id
);
226 atomic_inc(&rg
->lock_count
);
228 if (atomic_read(&rg
->map_count
)) {
233 for (i
= 0; i
< fbdev
->num_fbs
; i
++) {
234 struct omapfb_info
*ofbi2
= FB2OFB(fbdev
->fbs
[i
]);
237 if (ofbi2
->region
!= rg
)
240 for (j
= 0; j
< ofbi2
->num_overlays
; j
++) {
241 struct omap_overlay
*ovl
;
242 ovl
= ofbi2
->overlays
[j
];
243 if (ovl
->is_enabled(ovl
)) {
250 if (rg
->size
!= size
|| rg
->type
!= mi
->type
) {
251 r
= omapfb_realloc_fbmem(fbi
, size
, mi
->type
);
253 dev_err(fbdev
->dev
, "realloc fbmem failed\n");
259 atomic_dec(&rg
->lock_count
);
265 static int omapfb_query_mem(struct fb_info
*fbi
, struct omapfb_mem_info
*mi
)
267 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
268 struct omapfb2_mem_region
*rg
;
270 rg
= omapfb_get_mem_region(ofbi
->region
);
271 memset(mi
, 0, sizeof(*mi
));
276 omapfb_put_mem_region(rg
);
281 static int omapfb_update_window_nolock(struct fb_info
*fbi
,
282 u32 x
, u32 y
, u32 w
, u32 h
)
284 struct omap_dss_device
*display
= fb2display(fbi
);
290 if (w
== 0 || h
== 0)
293 display
->driver
->get_resolution(display
, &dw
, &dh
);
295 if (x
+ w
> dw
|| y
+ h
> dh
)
298 return display
->driver
->update(display
, x
, y
, w
, h
);
301 /* This function is exported for SGX driver use */
302 int omapfb_update_window(struct fb_info
*fbi
,
303 u32 x
, u32 y
, u32 w
, u32 h
)
305 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
306 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
309 if (!lock_fb_info(fbi
))
313 r
= omapfb_update_window_nolock(fbi
, x
, y
, w
, h
);
315 omapfb_unlock(fbdev
);
320 EXPORT_SYMBOL(omapfb_update_window
);
322 int omapfb_set_update_mode(struct fb_info
*fbi
,
323 enum omapfb_update_mode mode
)
325 struct omap_dss_device
*display
= fb2display(fbi
);
326 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
327 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
328 struct omapfb_display_data
*d
;
334 if (mode
!= OMAPFB_AUTO_UPDATE
&& mode
!= OMAPFB_MANUAL_UPDATE
)
339 d
= get_display_data(fbdev
, display
);
341 if (d
->update_mode
== mode
) {
342 omapfb_unlock(fbdev
);
348 if (display
->caps
& OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE
) {
349 if (mode
== OMAPFB_AUTO_UPDATE
)
350 omapfb_start_auto_update(fbdev
, display
);
351 else /* MANUAL_UPDATE */
352 omapfb_stop_auto_update(fbdev
, display
);
354 d
->update_mode
= mode
;
355 } else { /* AUTO_UPDATE */
356 if (mode
== OMAPFB_MANUAL_UPDATE
)
360 omapfb_unlock(fbdev
);
365 int omapfb_get_update_mode(struct fb_info
*fbi
,
366 enum omapfb_update_mode
*mode
)
368 struct omap_dss_device
*display
= fb2display(fbi
);
369 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
370 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
371 struct omapfb_display_data
*d
;
378 d
= get_display_data(fbdev
, display
);
380 *mode
= d
->update_mode
;
382 omapfb_unlock(fbdev
);
387 /* XXX this color key handling is a hack... */
388 static struct omapfb_color_key omapfb_color_keys
[2];
390 static int _omapfb_set_color_key(struct omap_overlay_manager
*mgr
,
391 struct omapfb_color_key
*ck
)
393 struct omap_overlay_manager_info info
;
394 enum omap_dss_trans_key_type kt
;
397 mgr
->get_manager_info(mgr
, &info
);
399 if (ck
->key_type
== OMAPFB_COLOR_KEY_DISABLED
) {
400 info
.trans_enabled
= false;
401 omapfb_color_keys
[mgr
->id
] = *ck
;
403 r
= mgr
->set_manager_info(mgr
, &info
);
412 switch (ck
->key_type
) {
413 case OMAPFB_COLOR_KEY_GFX_DST
:
414 kt
= OMAP_DSS_COLOR_KEY_GFX_DST
;
416 case OMAPFB_COLOR_KEY_VID_SRC
:
417 kt
= OMAP_DSS_COLOR_KEY_VID_SRC
;
423 info
.default_color
= ck
->background
;
424 info
.trans_key
= ck
->trans_key
;
425 info
.trans_key_type
= kt
;
426 info
.trans_enabled
= true;
428 omapfb_color_keys
[mgr
->id
] = *ck
;
430 r
= mgr
->set_manager_info(mgr
, &info
);
439 static int omapfb_set_color_key(struct fb_info
*fbi
,
440 struct omapfb_color_key
*ck
)
442 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
443 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
446 struct omap_overlay_manager
*mgr
= NULL
;
450 for (i
= 0; i
< ofbi
->num_overlays
; i
++) {
451 if (ofbi
->overlays
[i
]->manager
) {
452 mgr
= ofbi
->overlays
[i
]->manager
;
462 r
= _omapfb_set_color_key(mgr
, ck
);
464 omapfb_unlock(fbdev
);
469 static int omapfb_get_color_key(struct fb_info
*fbi
,
470 struct omapfb_color_key
*ck
)
472 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
473 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
474 struct omap_overlay_manager
*mgr
= NULL
;
480 for (i
= 0; i
< ofbi
->num_overlays
; i
++) {
481 if (ofbi
->overlays
[i
]->manager
) {
482 mgr
= ofbi
->overlays
[i
]->manager
;
492 *ck
= omapfb_color_keys
[mgr
->id
];
494 omapfb_unlock(fbdev
);
499 static int omapfb_memory_read(struct fb_info
*fbi
,
500 struct omapfb_memory_read
*mr
)
502 struct omap_dss_device
*display
= fb2display(fbi
);
506 if (!display
|| !display
->driver
->memory_read
)
509 if (!access_ok(VERIFY_WRITE
, mr
->buffer
, mr
->buffer_size
))
512 if (mr
->w
* mr
->h
* 3 > mr
->buffer_size
)
515 buf
= vmalloc(mr
->buffer_size
);
517 DBG("vmalloc failed\n");
521 r
= display
->driver
->memory_read(display
, buf
, mr
->buffer_size
,
522 mr
->x
, mr
->y
, mr
->w
, mr
->h
);
525 if (copy_to_user(mr
->buffer
, buf
, mr
->buffer_size
))
534 static int omapfb_get_ovl_colormode(struct omapfb2_device
*fbdev
,
535 struct omapfb_ovl_colormode
*mode
)
537 int ovl_idx
= mode
->overlay_idx
;
538 int mode_idx
= mode
->mode_idx
;
539 struct omap_overlay
*ovl
;
540 enum omap_color_mode supported_modes
;
541 struct fb_var_screeninfo var
;
544 if (ovl_idx
>= fbdev
->num_overlays
)
546 ovl
= fbdev
->overlays
[ovl_idx
];
547 supported_modes
= ovl
->supported_modes
;
549 mode_idx
= mode
->mode_idx
;
551 for (i
= 0; i
< sizeof(supported_modes
) * 8; i
++) {
552 if (!(supported_modes
& (1 << i
)))
555 * It's possible that the FB doesn't support a mode
556 * that is supported by the overlay, so call the
559 if (dss_mode_to_fb_mode(1 << i
, &var
) < 0)
567 if (i
== sizeof(supported_modes
) * 8)
570 mode
->bits_per_pixel
= var
.bits_per_pixel
;
571 mode
->nonstd
= var
.nonstd
;
573 mode
->green
= var
.green
;
574 mode
->blue
= var
.blue
;
575 mode
->transp
= var
.transp
;
580 static int omapfb_wait_for_go(struct fb_info
*fbi
)
582 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
586 for (i
= 0; i
< ofbi
->num_overlays
; ++i
) {
587 struct omap_overlay
*ovl
= ofbi
->overlays
[i
];
588 r
= ovl
->wait_for_go(ovl
);
596 int omapfb_ioctl(struct fb_info
*fbi
, unsigned int cmd
, unsigned long arg
)
598 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
599 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
600 struct omap_dss_device
*display
= fb2display(fbi
);
603 struct omapfb_update_window_old uwnd_o
;
604 struct omapfb_update_window uwnd
;
605 struct omapfb_plane_info plane_info
;
606 struct omapfb_caps caps
;
607 struct omapfb_mem_info mem_info
;
608 struct omapfb_color_key color_key
;
609 struct omapfb_ovl_colormode ovl_colormode
;
610 enum omapfb_update_mode update_mode
;
612 struct omapfb_memory_read memory_read
;
613 struct omapfb_vram_info vram_info
;
614 struct omapfb_tearsync_info tearsync_info
;
615 struct omapfb_display_info display_info
;
622 case OMAPFB_SYNC_GFX
:
623 DBG("ioctl SYNC_GFX\n");
624 if (!display
|| !display
->driver
->sync
) {
625 /* DSS1 never returns an error here, so we neither */
630 r
= display
->driver
->sync(display
);
633 case OMAPFB_UPDATE_WINDOW_OLD
:
634 DBG("ioctl UPDATE_WINDOW_OLD\n");
635 if (!display
|| !display
->driver
->update
) {
640 if (copy_from_user(&p
.uwnd_o
,
647 r
= omapfb_update_window_nolock(fbi
, p
.uwnd_o
.x
, p
.uwnd_o
.y
,
648 p
.uwnd_o
.width
, p
.uwnd_o
.height
);
651 case OMAPFB_UPDATE_WINDOW
:
652 DBG("ioctl UPDATE_WINDOW\n");
653 if (!display
|| !display
->driver
->update
) {
658 if (copy_from_user(&p
.uwnd
, (void __user
*)arg
,
664 r
= omapfb_update_window_nolock(fbi
, p
.uwnd
.x
, p
.uwnd
.y
,
665 p
.uwnd
.width
, p
.uwnd
.height
);
668 case OMAPFB_SETUP_PLANE
:
669 DBG("ioctl SETUP_PLANE\n");
670 if (copy_from_user(&p
.plane_info
, (void __user
*)arg
,
671 sizeof(p
.plane_info
)))
674 r
= omapfb_setup_plane(fbi
, &p
.plane_info
);
677 case OMAPFB_QUERY_PLANE
:
678 DBG("ioctl QUERY_PLANE\n");
679 r
= omapfb_query_plane(fbi
, &p
.plane_info
);
682 if (copy_to_user((void __user
*)arg
, &p
.plane_info
,
683 sizeof(p
.plane_info
)))
687 case OMAPFB_SETUP_MEM
:
688 DBG("ioctl SETUP_MEM\n");
689 if (copy_from_user(&p
.mem_info
, (void __user
*)arg
,
693 r
= omapfb_setup_mem(fbi
, &p
.mem_info
);
696 case OMAPFB_QUERY_MEM
:
697 DBG("ioctl QUERY_MEM\n");
698 r
= omapfb_query_mem(fbi
, &p
.mem_info
);
701 if (copy_to_user((void __user
*)arg
, &p
.mem_info
,
706 case OMAPFB_GET_CAPS
:
707 DBG("ioctl GET_CAPS\n");
713 memset(&p
.caps
, 0, sizeof(p
.caps
));
714 if (display
->caps
& OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE
)
715 p
.caps
.ctrl
|= OMAPFB_CAPS_MANUAL_UPDATE
;
716 if (display
->caps
& OMAP_DSS_DISPLAY_CAP_TEAR_ELIM
)
717 p
.caps
.ctrl
|= OMAPFB_CAPS_TEARSYNC
;
719 if (copy_to_user((void __user
*)arg
, &p
.caps
, sizeof(p
.caps
)))
723 case OMAPFB_GET_OVERLAY_COLORMODE
:
724 DBG("ioctl GET_OVERLAY_COLORMODE\n");
725 if (copy_from_user(&p
.ovl_colormode
, (void __user
*)arg
,
726 sizeof(p
.ovl_colormode
))) {
730 r
= omapfb_get_ovl_colormode(fbdev
, &p
.ovl_colormode
);
733 if (copy_to_user((void __user
*)arg
, &p
.ovl_colormode
,
734 sizeof(p
.ovl_colormode
)))
738 case OMAPFB_SET_UPDATE_MODE
:
739 DBG("ioctl SET_UPDATE_MODE\n");
740 if (get_user(p
.update_mode
, (int __user
*)arg
))
743 r
= omapfb_set_update_mode(fbi
, p
.update_mode
);
746 case OMAPFB_GET_UPDATE_MODE
:
747 DBG("ioctl GET_UPDATE_MODE\n");
748 r
= omapfb_get_update_mode(fbi
, &p
.update_mode
);
751 if (put_user(p
.update_mode
,
752 (enum omapfb_update_mode __user
*)arg
))
756 case OMAPFB_SET_COLOR_KEY
:
757 DBG("ioctl SET_COLOR_KEY\n");
758 if (copy_from_user(&p
.color_key
, (void __user
*)arg
,
759 sizeof(p
.color_key
)))
762 r
= omapfb_set_color_key(fbi
, &p
.color_key
);
765 case OMAPFB_GET_COLOR_KEY
:
766 DBG("ioctl GET_COLOR_KEY\n");
767 r
= omapfb_get_color_key(fbi
, &p
.color_key
);
770 if (copy_to_user((void __user
*)arg
, &p
.color_key
,
771 sizeof(p
.color_key
)))
775 case FBIO_WAITFORVSYNC
:
776 if (get_user(p
.crt
, (__u32 __user
*)arg
)) {
786 case OMAPFB_WAITFORVSYNC
:
787 DBG("ioctl WAITFORVSYNC\n");
793 r
= display
->manager
->wait_for_vsync(display
->manager
);
796 case OMAPFB_WAITFORGO
:
797 DBG("ioctl WAITFORGO\n");
803 r
= omapfb_wait_for_go(fbi
);
806 /* LCD and CTRL tests do the same thing for backward
808 case OMAPFB_LCD_TEST
:
809 DBG("ioctl LCD_TEST\n");
810 if (get_user(p
.test_num
, (int __user
*)arg
)) {
814 if (!display
|| !display
->driver
->run_test
) {
819 r
= display
->driver
->run_test(display
, p
.test_num
);
823 case OMAPFB_CTRL_TEST
:
824 DBG("ioctl CTRL_TEST\n");
825 if (get_user(p
.test_num
, (int __user
*)arg
)) {
829 if (!display
|| !display
->driver
->run_test
) {
834 r
= display
->driver
->run_test(display
, p
.test_num
);
838 case OMAPFB_MEMORY_READ
:
839 DBG("ioctl MEMORY_READ\n");
841 if (copy_from_user(&p
.memory_read
, (void __user
*)arg
,
842 sizeof(p
.memory_read
))) {
847 r
= omapfb_memory_read(fbi
, &p
.memory_read
);
851 case OMAPFB_GET_VRAM_INFO
: {
852 unsigned long vram
, free
, largest
;
854 DBG("ioctl GET_VRAM_INFO\n");
856 omap_vram_get_info(&vram
, &free
, &largest
);
857 p
.vram_info
.total
= vram
;
858 p
.vram_info
.free
= free
;
859 p
.vram_info
.largest_free_block
= largest
;
861 if (copy_to_user((void __user
*)arg
, &p
.vram_info
,
862 sizeof(p
.vram_info
)))
867 case OMAPFB_SET_TEARSYNC
: {
868 DBG("ioctl SET_TEARSYNC\n");
870 if (copy_from_user(&p
.tearsync_info
, (void __user
*)arg
,
871 sizeof(p
.tearsync_info
))) {
876 if (!display
|| !display
->driver
->enable_te
) {
881 r
= display
->driver
->enable_te(display
,
882 !!p
.tearsync_info
.enabled
);
887 case OMAPFB_GET_DISPLAY_INFO
: {
890 DBG("ioctl GET_DISPLAY_INFO\n");
892 if (display
== NULL
) {
897 display
->driver
->get_resolution(display
, &xres
, &yres
);
899 p
.display_info
.xres
= xres
;
900 p
.display_info
.yres
= yres
;
902 if (display
->driver
->get_dimensions
) {
904 display
->driver
->get_dimensions(display
, &w
, &h
);
905 p
.display_info
.width
= w
;
906 p
.display_info
.height
= h
;
908 p
.display_info
.width
= 0;
909 p
.display_info
.height
= 0;
912 if (copy_to_user((void __user
*)arg
, &p
.display_info
,
913 sizeof(p
.display_info
)))
919 dev_err(fbdev
->dev
, "Unknown ioctl 0x%x\n", cmd
);
924 DBG("ioctl failed: %d\n", r
);