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 u8
get_mem_idx(struct omapfb_info
*ofbi
)
39 if (ofbi
->id
== ofbi
->region
->id
)
42 return OMAPFB_MEM_IDX_ENABLED
| ofbi
->region
->id
;
45 static struct omapfb2_mem_region
*get_mem_region(struct omapfb_info
*ofbi
,
48 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
50 if (mem_idx
& OMAPFB_MEM_IDX_ENABLED
)
51 mem_idx
&= OMAPFB_MEM_IDX_MASK
;
55 if (mem_idx
>= fbdev
->num_fbs
)
58 return &fbdev
->regions
[mem_idx
];
61 static int omapfb_setup_plane(struct fb_info
*fbi
, struct omapfb_plane_info
*pi
)
63 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
64 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
65 struct omap_overlay
*ovl
;
66 struct omap_overlay_info old_info
;
67 struct omapfb2_mem_region
*old_rg
, *new_rg
;
70 DBG("omapfb_setup_plane\n");
72 if (ofbi
->num_overlays
!= 1) {
77 /* XXX uses only the first overlay */
78 ovl
= ofbi
->overlays
[0];
80 old_rg
= ofbi
->region
;
81 new_rg
= get_mem_region(ofbi
, pi
->mem_idx
);
87 if (pi
->enabled
&& !new_rg
->size
) {
89 * This plane's memory was freed, can't enable it
90 * until it's reallocated.
96 ovl
->get_overlay_info(ovl
, &old_info
);
98 if (old_rg
!= new_rg
) {
99 ofbi
->region
= new_rg
;
104 struct omap_overlay_info info
;
106 r
= omapfb_setup_overlay(fbi
, ovl
, pi
->pos_x
, pi
->pos_y
,
107 pi
->out_width
, pi
->out_height
);
111 ovl
->get_overlay_info(ovl
, &info
);
114 info
.enabled
= pi
->enabled
;
115 r
= ovl
->set_overlay_info(ovl
, &info
);
120 struct omap_overlay_info info
;
122 ovl
->get_overlay_info(ovl
, &info
);
124 info
.enabled
= pi
->enabled
;
125 info
.pos_x
= pi
->pos_x
;
126 info
.pos_y
= pi
->pos_y
;
127 info
.out_width
= pi
->out_width
;
128 info
.out_height
= pi
->out_height
;
130 r
= ovl
->set_overlay_info(ovl
, &info
);
136 ovl
->manager
->apply(ovl
->manager
);
141 if (old_rg
!= new_rg
) {
142 ofbi
->region
= old_rg
;
146 ovl
->set_overlay_info(ovl
, &old_info
);
148 dev_err(fbdev
->dev
, "setup_plane failed\n");
153 static int omapfb_query_plane(struct fb_info
*fbi
, struct omapfb_plane_info
*pi
)
155 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
157 if (ofbi
->num_overlays
!= 1) {
158 memset(pi
, 0, sizeof(*pi
));
160 struct omap_overlay
*ovl
;
161 struct omap_overlay_info
*ovli
;
163 ovl
= ofbi
->overlays
[0];
166 pi
->pos_x
= ovli
->pos_x
;
167 pi
->pos_y
= ovli
->pos_y
;
168 pi
->enabled
= ovli
->enabled
;
169 pi
->channel_out
= 0; /* xxx */
171 pi
->mem_idx
= get_mem_idx(ofbi
);
172 pi
->out_width
= ovli
->out_width
;
173 pi
->out_height
= ovli
->out_height
;
179 static int omapfb_setup_mem(struct fb_info
*fbi
, struct omapfb_mem_info
*mi
)
181 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
182 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
183 struct omapfb2_mem_region
*rg
;
187 if (mi
->type
> OMAPFB_MEMTYPE_MAX
)
190 size
= PAGE_ALIGN(mi
->size
);
194 if (atomic_read(&rg
->map_count
))
197 for (i
= 0; i
< fbdev
->num_fbs
; i
++) {
198 struct omapfb_info
*ofbi2
= FB2OFB(fbdev
->fbs
[i
]);
201 if (ofbi2
->region
!= rg
)
204 for (j
= 0; j
< ofbi2
->num_overlays
; j
++) {
205 if (ofbi2
->overlays
[j
]->info
.enabled
) {
212 if (rg
->size
!= size
|| rg
->type
!= mi
->type
) {
213 r
= omapfb_realloc_fbmem(fbi
, size
, mi
->type
);
215 dev_err(fbdev
->dev
, "realloc fbmem failed\n");
223 static int omapfb_query_mem(struct fb_info
*fbi
, struct omapfb_mem_info
*mi
)
225 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
226 struct omapfb2_mem_region
*rg
;
229 memset(mi
, 0, sizeof(*mi
));
237 static int omapfb_update_window_nolock(struct fb_info
*fbi
,
238 u32 x
, u32 y
, u32 w
, u32 h
)
240 struct omap_dss_device
*display
= fb2display(fbi
);
246 if (w
== 0 || h
== 0)
249 display
->driver
->get_resolution(display
, &dw
, &dh
);
251 if (x
+ w
> dw
|| y
+ h
> dh
)
254 return display
->driver
->update(display
, x
, y
, w
, h
);
257 /* This function is exported for SGX driver use */
258 int omapfb_update_window(struct fb_info
*fbi
,
259 u32 x
, u32 y
, u32 w
, u32 h
)
261 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
262 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
265 if (!lock_fb_info(fbi
))
269 r
= omapfb_update_window_nolock(fbi
, x
, y
, w
, h
);
271 omapfb_unlock(fbdev
);
276 EXPORT_SYMBOL(omapfb_update_window
);
278 static int omapfb_set_update_mode(struct fb_info
*fbi
,
279 enum omapfb_update_mode mode
)
281 struct omap_dss_device
*display
= fb2display(fbi
);
282 enum omap_dss_update_mode um
;
285 if (!display
|| !display
->driver
->set_update_mode
)
289 case OMAPFB_UPDATE_DISABLED
:
290 um
= OMAP_DSS_UPDATE_DISABLED
;
293 case OMAPFB_AUTO_UPDATE
:
294 um
= OMAP_DSS_UPDATE_AUTO
;
297 case OMAPFB_MANUAL_UPDATE
:
298 um
= OMAP_DSS_UPDATE_MANUAL
;
305 r
= display
->driver
->set_update_mode(display
, um
);
310 static int omapfb_get_update_mode(struct fb_info
*fbi
,
311 enum omapfb_update_mode
*mode
)
313 struct omap_dss_device
*display
= fb2display(fbi
);
314 enum omap_dss_update_mode m
;
319 if (!display
->driver
->get_update_mode
) {
320 *mode
= OMAPFB_AUTO_UPDATE
;
324 m
= display
->driver
->get_update_mode(display
);
327 case OMAP_DSS_UPDATE_DISABLED
:
328 *mode
= OMAPFB_UPDATE_DISABLED
;
330 case OMAP_DSS_UPDATE_AUTO
:
331 *mode
= OMAPFB_AUTO_UPDATE
;
333 case OMAP_DSS_UPDATE_MANUAL
:
334 *mode
= OMAPFB_MANUAL_UPDATE
;
343 /* XXX this color key handling is a hack... */
344 static struct omapfb_color_key omapfb_color_keys
[2];
346 static int _omapfb_set_color_key(struct omap_overlay_manager
*mgr
,
347 struct omapfb_color_key
*ck
)
349 struct omap_overlay_manager_info info
;
350 enum omap_dss_trans_key_type kt
;
353 mgr
->get_manager_info(mgr
, &info
);
355 if (ck
->key_type
== OMAPFB_COLOR_KEY_DISABLED
) {
356 info
.trans_enabled
= false;
357 omapfb_color_keys
[mgr
->id
] = *ck
;
359 r
= mgr
->set_manager_info(mgr
, &info
);
368 switch (ck
->key_type
) {
369 case OMAPFB_COLOR_KEY_GFX_DST
:
370 kt
= OMAP_DSS_COLOR_KEY_GFX_DST
;
372 case OMAPFB_COLOR_KEY_VID_SRC
:
373 kt
= OMAP_DSS_COLOR_KEY_VID_SRC
;
379 info
.default_color
= ck
->background
;
380 info
.trans_key
= ck
->trans_key
;
381 info
.trans_key_type
= kt
;
382 info
.trans_enabled
= true;
384 omapfb_color_keys
[mgr
->id
] = *ck
;
386 r
= mgr
->set_manager_info(mgr
, &info
);
395 static int omapfb_set_color_key(struct fb_info
*fbi
,
396 struct omapfb_color_key
*ck
)
398 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
399 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
402 struct omap_overlay_manager
*mgr
= NULL
;
406 for (i
= 0; i
< ofbi
->num_overlays
; i
++) {
407 if (ofbi
->overlays
[i
]->manager
) {
408 mgr
= ofbi
->overlays
[i
]->manager
;
418 r
= _omapfb_set_color_key(mgr
, ck
);
420 omapfb_unlock(fbdev
);
425 static int omapfb_get_color_key(struct fb_info
*fbi
,
426 struct omapfb_color_key
*ck
)
428 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
429 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
430 struct omap_overlay_manager
*mgr
= NULL
;
436 for (i
= 0; i
< ofbi
->num_overlays
; i
++) {
437 if (ofbi
->overlays
[i
]->manager
) {
438 mgr
= ofbi
->overlays
[i
]->manager
;
448 *ck
= omapfb_color_keys
[mgr
->id
];
450 omapfb_unlock(fbdev
);
455 static int omapfb_memory_read(struct fb_info
*fbi
,
456 struct omapfb_memory_read
*mr
)
458 struct omap_dss_device
*display
= fb2display(fbi
);
462 if (!display
|| !display
->driver
->memory_read
)
465 if (!access_ok(VERIFY_WRITE
, mr
->buffer
, mr
->buffer_size
))
468 if (mr
->w
* mr
->h
* 3 > mr
->buffer_size
)
471 buf
= vmalloc(mr
->buffer_size
);
473 DBG("vmalloc failed\n");
477 r
= display
->driver
->memory_read(display
, buf
, mr
->buffer_size
,
478 mr
->x
, mr
->y
, mr
->w
, mr
->h
);
481 if (copy_to_user(mr
->buffer
, buf
, mr
->buffer_size
))
490 static int omapfb_get_ovl_colormode(struct omapfb2_device
*fbdev
,
491 struct omapfb_ovl_colormode
*mode
)
493 int ovl_idx
= mode
->overlay_idx
;
494 int mode_idx
= mode
->mode_idx
;
495 struct omap_overlay
*ovl
;
496 enum omap_color_mode supported_modes
;
497 struct fb_var_screeninfo var
;
500 if (ovl_idx
>= fbdev
->num_overlays
)
502 ovl
= fbdev
->overlays
[ovl_idx
];
503 supported_modes
= ovl
->supported_modes
;
505 mode_idx
= mode
->mode_idx
;
507 for (i
= 0; i
< sizeof(supported_modes
) * 8; i
++) {
508 if (!(supported_modes
& (1 << i
)))
511 * It's possible that the FB doesn't support a mode
512 * that is supported by the overlay, so call the
515 if (dss_mode_to_fb_mode(1 << i
, &var
) < 0)
523 if (i
== sizeof(supported_modes
) * 8)
526 mode
->bits_per_pixel
= var
.bits_per_pixel
;
527 mode
->nonstd
= var
.nonstd
;
529 mode
->green
= var
.green
;
530 mode
->blue
= var
.blue
;
531 mode
->transp
= var
.transp
;
536 static int omapfb_wait_for_go(struct fb_info
*fbi
)
538 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
542 for (i
= 0; i
< ofbi
->num_overlays
; ++i
) {
543 struct omap_overlay
*ovl
= ofbi
->overlays
[i
];
544 r
= ovl
->wait_for_go(ovl
);
552 int omapfb_ioctl(struct fb_info
*fbi
, unsigned int cmd
, unsigned long arg
)
554 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
555 struct omapfb2_device
*fbdev
= ofbi
->fbdev
;
556 struct omap_dss_device
*display
= fb2display(fbi
);
559 struct omapfb_update_window_old uwnd_o
;
560 struct omapfb_update_window uwnd
;
561 struct omapfb_plane_info plane_info
;
562 struct omapfb_caps caps
;
563 struct omapfb_mem_info mem_info
;
564 struct omapfb_color_key color_key
;
565 struct omapfb_ovl_colormode ovl_colormode
;
566 enum omapfb_update_mode update_mode
;
568 struct omapfb_memory_read memory_read
;
569 struct omapfb_vram_info vram_info
;
570 struct omapfb_tearsync_info tearsync_info
;
571 struct omapfb_display_info display_info
;
577 case OMAPFB_SYNC_GFX
:
578 DBG("ioctl SYNC_GFX\n");
579 if (!display
|| !display
->driver
->sync
) {
580 /* DSS1 never returns an error here, so we neither */
585 r
= display
->driver
->sync(display
);
588 case OMAPFB_UPDATE_WINDOW_OLD
:
589 DBG("ioctl UPDATE_WINDOW_OLD\n");
590 if (!display
|| !display
->driver
->update
) {
595 if (copy_from_user(&p
.uwnd_o
,
602 r
= omapfb_update_window_nolock(fbi
, p
.uwnd_o
.x
, p
.uwnd_o
.y
,
603 p
.uwnd_o
.width
, p
.uwnd_o
.height
);
606 case OMAPFB_UPDATE_WINDOW
:
607 DBG("ioctl UPDATE_WINDOW\n");
608 if (!display
|| !display
->driver
->update
) {
613 if (copy_from_user(&p
.uwnd
, (void __user
*)arg
,
619 r
= omapfb_update_window_nolock(fbi
, p
.uwnd
.x
, p
.uwnd
.y
,
620 p
.uwnd
.width
, p
.uwnd
.height
);
623 case OMAPFB_SETUP_PLANE
:
624 DBG("ioctl SETUP_PLANE\n");
625 if (copy_from_user(&p
.plane_info
, (void __user
*)arg
,
626 sizeof(p
.plane_info
)))
629 r
= omapfb_setup_plane(fbi
, &p
.plane_info
);
632 case OMAPFB_QUERY_PLANE
:
633 DBG("ioctl QUERY_PLANE\n");
634 r
= omapfb_query_plane(fbi
, &p
.plane_info
);
637 if (copy_to_user((void __user
*)arg
, &p
.plane_info
,
638 sizeof(p
.plane_info
)))
642 case OMAPFB_SETUP_MEM
:
643 DBG("ioctl SETUP_MEM\n");
644 if (copy_from_user(&p
.mem_info
, (void __user
*)arg
,
648 r
= omapfb_setup_mem(fbi
, &p
.mem_info
);
651 case OMAPFB_QUERY_MEM
:
652 DBG("ioctl QUERY_MEM\n");
653 r
= omapfb_query_mem(fbi
, &p
.mem_info
);
656 if (copy_to_user((void __user
*)arg
, &p
.mem_info
,
661 case OMAPFB_GET_CAPS
:
662 DBG("ioctl GET_CAPS\n");
668 memset(&p
.caps
, 0, sizeof(p
.caps
));
669 if (display
->caps
& OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE
)
670 p
.caps
.ctrl
|= OMAPFB_CAPS_MANUAL_UPDATE
;
671 if (display
->caps
& OMAP_DSS_DISPLAY_CAP_TEAR_ELIM
)
672 p
.caps
.ctrl
|= OMAPFB_CAPS_TEARSYNC
;
674 if (copy_to_user((void __user
*)arg
, &p
.caps
, sizeof(p
.caps
)))
678 case OMAPFB_GET_OVERLAY_COLORMODE
:
679 DBG("ioctl GET_OVERLAY_COLORMODE\n");
680 if (copy_from_user(&p
.ovl_colormode
, (void __user
*)arg
,
681 sizeof(p
.ovl_colormode
))) {
685 r
= omapfb_get_ovl_colormode(fbdev
, &p
.ovl_colormode
);
688 if (copy_to_user((void __user
*)arg
, &p
.ovl_colormode
,
689 sizeof(p
.ovl_colormode
)))
693 case OMAPFB_SET_UPDATE_MODE
:
694 DBG("ioctl SET_UPDATE_MODE\n");
695 if (get_user(p
.update_mode
, (int __user
*)arg
))
698 r
= omapfb_set_update_mode(fbi
, p
.update_mode
);
701 case OMAPFB_GET_UPDATE_MODE
:
702 DBG("ioctl GET_UPDATE_MODE\n");
703 r
= omapfb_get_update_mode(fbi
, &p
.update_mode
);
706 if (put_user(p
.update_mode
,
707 (enum omapfb_update_mode __user
*)arg
))
711 case OMAPFB_SET_COLOR_KEY
:
712 DBG("ioctl SET_COLOR_KEY\n");
713 if (copy_from_user(&p
.color_key
, (void __user
*)arg
,
714 sizeof(p
.color_key
)))
717 r
= omapfb_set_color_key(fbi
, &p
.color_key
);
720 case OMAPFB_GET_COLOR_KEY
:
721 DBG("ioctl GET_COLOR_KEY\n");
722 r
= omapfb_get_color_key(fbi
, &p
.color_key
);
725 if (copy_to_user((void __user
*)arg
, &p
.color_key
,
726 sizeof(p
.color_key
)))
730 case OMAPFB_WAITFORVSYNC
:
731 DBG("ioctl WAITFORVSYNC\n");
737 r
= display
->manager
->wait_for_vsync(display
->manager
);
740 case OMAPFB_WAITFORGO
:
741 DBG("ioctl WAITFORGO\n");
747 r
= omapfb_wait_for_go(fbi
);
750 /* LCD and CTRL tests do the same thing for backward
752 case OMAPFB_LCD_TEST
:
753 DBG("ioctl LCD_TEST\n");
754 if (get_user(p
.test_num
, (int __user
*)arg
)) {
758 if (!display
|| !display
->driver
->run_test
) {
763 r
= display
->driver
->run_test(display
, p
.test_num
);
767 case OMAPFB_CTRL_TEST
:
768 DBG("ioctl CTRL_TEST\n");
769 if (get_user(p
.test_num
, (int __user
*)arg
)) {
773 if (!display
|| !display
->driver
->run_test
) {
778 r
= display
->driver
->run_test(display
, p
.test_num
);
782 case OMAPFB_MEMORY_READ
:
783 DBG("ioctl MEMORY_READ\n");
785 if (copy_from_user(&p
.memory_read
, (void __user
*)arg
,
786 sizeof(p
.memory_read
))) {
791 r
= omapfb_memory_read(fbi
, &p
.memory_read
);
795 case OMAPFB_GET_VRAM_INFO
: {
796 unsigned long vram
, free
, largest
;
798 DBG("ioctl GET_VRAM_INFO\n");
800 omap_vram_get_info(&vram
, &free
, &largest
);
801 p
.vram_info
.total
= vram
;
802 p
.vram_info
.free
= free
;
803 p
.vram_info
.largest_free_block
= largest
;
805 if (copy_to_user((void __user
*)arg
, &p
.vram_info
,
806 sizeof(p
.vram_info
)))
811 case OMAPFB_SET_TEARSYNC
: {
812 DBG("ioctl SET_TEARSYNC\n");
814 if (copy_from_user(&p
.tearsync_info
, (void __user
*)arg
,
815 sizeof(p
.tearsync_info
))) {
820 if (!display
->driver
->enable_te
) {
825 r
= display
->driver
->enable_te(display
,
826 !!p
.tearsync_info
.enabled
);
831 case OMAPFB_GET_DISPLAY_INFO
: {
834 DBG("ioctl GET_DISPLAY_INFO\n");
836 if (display
== NULL
) {
841 display
->driver
->get_resolution(display
, &xres
, &yres
);
843 p
.display_info
.xres
= xres
;
844 p
.display_info
.yres
= yres
;
845 p
.display_info
.width
= 0;
846 p
.display_info
.height
= 0;
848 if (copy_to_user((void __user
*)arg
, &p
.display_info
,
849 sizeof(p
.display_info
)))
855 dev_err(fbdev
->dev
, "Unknown ioctl 0x%x\n", cmd
);
860 DBG("ioctl failed: %d\n", r
);