2 * File: drivers/video/omap/omapfb_main.c
4 * Framebuffer driver for TI OMAP boards
6 * Copyright (C) 2004 Nokia Corporation
7 * Author: Imre Deak <imre.deak@nokia.com>
10 * Alex McMains <aam@ridgerun.com> - Original driver
11 * Juha Yrjola <juha.yrjola@nokia.com> - Original driver and improvements
12 * Dirk Behme <dirk.behme@de.bosch.com> - changes for 2.6 kernel API
13 * Texas Instruments - H3 support
15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the
17 * Free Software Foundation; either version 2 of the License, or (at your
18 * option) any later version.
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #include <linux/config.h>
31 #include <linux/module.h>
33 #include <linux/init.h>
34 #include <linux/delay.h>
35 #include <linux/platform_device.h>
36 #include <linux/dma-mapping.h>
38 #include <asm/uaccess.h>
39 #include <asm/atomic.h>
40 #include <asm/mach-types.h>
42 #include <asm/arch/dma.h>
43 #include <asm/arch/irqs.h>
44 #include <asm/arch/mux.h>
45 #include <asm/arch/board.h>
46 #include <asm/arch/omapfb.h>
48 /* #define OMAPFB_DBG 1 */
52 #define OMAPFB_DRIVER "omapfb"
53 #define MODULE_NAME "omapfb"
55 #define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
57 static unsigned int def_accel;
58 static unsigned long def_vram;
59 static unsigned long def_vxres;
60 static unsigned long def_vyres;
61 static unsigned int def_rotate;
62 static unsigned int def_mirror;
64 #ifdef CONFIG_FB_OMAP_MANUAL_UPDATE
65 static int manual_update = 1;
67 static int manual_update;
70 static struct platform_device *fbdev_pdev;
71 static struct lcd_panel *fbdev_panel;
72 static struct omapfb_device *omapfb_dev;
74 static struct caps_table_struct {
77 } omapfb_caps_table[] = {
78 { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" },
79 { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" },
83 * ---------------------------------------------------------------------------
85 * ---------------------------------------------------------------------------
87 extern struct lcd_ctrl omap1_int_ctrl;
88 extern struct lcd_ctrl omap2_int_ctrl;
89 extern struct lcd_ctrl hwa742_ctrl;
90 extern struct lcd_ctrl blizzard_ctrl;
92 static struct lcd_ctrl *ctrls[] = {
93 #ifdef CONFIG_ARCH_OMAP1
99 #ifdef CONFIG_FB_OMAP_LCDC_HWA742
104 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
105 #ifdef CONFIG_ARCH_OMAP1
106 extern struct lcd_ctrl_extif sossi_extif;
108 extern struct lcd_ctrl_extif rfbi_extif;
112 static void omapfb_rqueue_lock(struct omapfb_device *fbdev)
114 down(&fbdev->rqueue_sema);
117 static void omapfb_rqueue_unlock(struct omapfb_device *fbdev)
119 up(&fbdev->rqueue_sema);
123 * ---------------------------------------------------------------------------
124 * LCD controller and LCD DMA
125 * ---------------------------------------------------------------------------
127 /* Lookup table to map elem size to elem type. */
128 static const int dma_elem_type[] = {
130 OMAP_DMA_DATA_TYPE_S8,
131 OMAP_DMA_DATA_TYPE_S16,
133 OMAP_DMA_DATA_TYPE_S32,
136 /* Allocate resources needed for LCD controller and LCD DMA operations. Video
137 * memory is allocated from system memory according to the virtual display
138 * size, except if a bigger memory size is specified explicitly as a kernel
141 static int ctrl_init(struct omapfb_device *fbdev)
147 r = fbdev->ctrl->init(fbdev, 0, def_vram);
149 pr_err("controller initialization failed\n");
153 fbdev->ctrl->get_vram_layout(&fbdev->vram_size, &fbdev->vram_virt_base,
154 &fbdev->vram_phys_base);
156 DBGPRINT(1, "vram_phys %08x vram_virt %p vram_size=%lu\n",
157 fbdev->vram_phys_base, fbdev->vram_virt_base,
167 static void ctrl_cleanup(struct omapfb_device *fbdev)
169 fbdev->ctrl->cleanup();
172 static int ctrl_change_mode(struct omapfb_device *fbdev)
175 unsigned long offset;
176 struct fb_var_screeninfo *var = &fbdev->fb_info->var;
178 DBGPRINT(1, "xoffset %d yoffset %d line_length %d bits_per_pixel %d\n",
179 var->xoffset, var->yoffset, fbdev->fb_info->fix.line_length,
180 var->bits_per_pixel);
181 offset = var->yoffset * fbdev->fb_info->fix.line_length +
182 var->xoffset * var->bits_per_pixel / 8;
183 r = fbdev->ctrl->setup_plane(OMAPFB_PLANE_GFX, OMAPFB_CHANNEL_OUT_LCD,
184 offset, var->xres_virtual, 0, 0, var->xres,
185 var->yres, fbdev->color_mode);
192 * ---------------------------------------------------------------------------
193 * fbdev framework callbacks and the ioctl interface
194 * ---------------------------------------------------------------------------
196 /* Called each time the omapfb device is opened */
197 static int omapfb_open(struct fb_info *info, int user)
204 static void omapfb_sync(struct fb_info *info);
206 /* Called when the omapfb device is closed. We make sure that any pending
207 * gfx DMA operations are ended, before we return. */
208 static int omapfb_release(struct fb_info *info, int user)
218 /* Store a single color palette entry into a pseudo palette or the hardware
219 * palette if one is available. For now we support only 16bpp and thus store
220 * the entry only to the pseudo palette.
222 static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
223 u_int blue, u_int transp, int update_hw_pal)
225 struct omapfb_device *fbdev = (struct omapfb_device *)info->par;
228 switch (fbdev->color_mode) {
229 case OMAPFB_COLOR_YUV422:
230 case OMAPFB_COLOR_YUV420:
233 case OMAPFB_COLOR_CLUT_8BPP:
234 case OMAPFB_COLOR_CLUT_4BPP:
235 case OMAPFB_COLOR_CLUT_2BPP:
236 case OMAPFB_COLOR_CLUT_1BPP:
237 if (fbdev->ctrl->setcolreg)
238 r = fbdev->ctrl->setcolreg(regno, red, green, blue,
239 transp, update_hw_pal);
241 case OMAPFB_COLOR_RGB565:
252 pal = ((red >> 11) << 11) | ((green >> 10) << 5) |
254 ((u32 *)(info->pseudo_palette))[regno] = pal;
263 static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
264 u_int transp, struct fb_info *info)
270 _setcolreg(info, regno, red, green, blue, transp, 1);
277 static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
280 u16 *red, *green, *blue, *transp;
286 transp = cmap->transp;
289 for (count = 0; count < cmap->len; count++) {
292 r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
293 count == cmap->len - 1);
301 static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
303 struct omapfb_device *fbdev = info->par;
306 omapfb_rqueue_lock(fbdev);
307 r = fbdev->ctrl->mmap(vma);
308 omapfb_rqueue_unlock(fbdev);
313 static void omapfb_update_full_screen(struct omapfb_device *fbdev);
315 static int omapfb_blank(int blank, struct fb_info *fbi)
317 struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
323 omapfb_rqueue_lock(fbdev);
325 case VESA_NO_BLANKING:
326 if (fbdev->state == OMAPFB_SUSPENDED) {
327 if (fbdev->ctrl->resume)
328 fbdev->ctrl->resume();
329 fbdev->panel->enable();
330 fbdev->state = OMAPFB_ACTIVE;
331 if (fbdev->ctrl->get_update_mode() ==
332 OMAPFB_MANUAL_UPDATE)
337 if (fbdev->state == OMAPFB_ACTIVE) {
338 fbdev->panel->disable();
339 if (fbdev->ctrl->suspend)
340 fbdev->ctrl->suspend();
341 fbdev->state = OMAPFB_SUSPENDED;
347 omapfb_rqueue_unlock(fbdev);
350 omapfb_update_full_screen(fbdev);
356 static void omapfb_sync(struct fb_info *fbi)
358 struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
360 omapfb_rqueue_lock(fbdev);
361 if (fbdev->ctrl->sync)
363 omapfb_rqueue_unlock(fbdev);
366 /* Set fb_info.fix fields and also updates fbdev.
367 * When calling this fb_info.var must be set up already.
369 static void set_fb_fix(struct omapfb_device *fbdev)
371 struct fb_info *fbi = fbdev->fb_info;
372 struct fb_fix_screeninfo *fix = &fbi->fix;
373 struct fb_var_screeninfo *var = &fbi->var;
375 strncpy(fix->id, OMAPFB_DRIVER, sizeof(fix->id));
376 fix->type = FB_TYPE_PACKED_PIXELS;
377 switch (var->bits_per_pixel) {
379 fix->visual = FB_VISUAL_TRUECOLOR;
385 fix->visual = FB_VISUAL_PSEUDOCOLOR;
388 fix->accel = FB_ACCEL_OMAP1610;
389 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
390 fix->smem_len = fbdev->vram_size;
391 fix->smem_start = fbdev->vram_phys_base;
394 /* Check the values in var against our capabilities and in case of out of
395 * bound values try to adjust them.
397 static int set_fb_var(struct omapfb_device *fbdev,
398 struct fb_var_screeninfo *var)
401 unsigned long max_frame_size;
402 unsigned long line_size;
403 struct lcd_panel *panel = fbdev->panel;
405 bpp = var->bits_per_pixel = panel->bpp;
409 fbdev->color_mode = OMAPFB_COLOR_RGB565;
412 fbdev->color_mode = OMAPFB_COLOR_CLUT_8BPP;
415 /* FIXME: other BPPs not yet supported */
419 switch (var->rotate) {
422 var->xres = fbdev->panel->x_res;
423 var->yres = fbdev->panel->y_res;
427 var->xres = fbdev->panel->y_res;
428 var->yres = fbdev->panel->x_res;
433 if (var->xres_virtual < var->xres)
434 var->xres_virtual = var->xres;
435 if (var->yres_virtual < var->yres)
436 var->yres_virtual = var->yres;
437 max_frame_size = fbdev->vram_size;
438 line_size = var->xres_virtual * bpp / 8;
439 if (line_size * var->yres_virtual > max_frame_size) {
440 /* Try to keep yres_virtual first */
441 line_size = max_frame_size / var->yres_virtual;
442 var->xres_virtual = line_size * 8 / bpp;
443 if (var->xres_virtual < var->xres) {
444 /* Still doesn't fit. Shrink yres_virtual too */
445 var->xres_virtual = var->xres;
446 line_size = var->xres * bpp / 8;
447 var->yres_virtual = max_frame_size / line_size;
450 if (var->xres + var->xoffset > var->xres_virtual)
451 var->xoffset = var->xres_virtual - var->xres;
452 if (var->yres + var->yoffset > var->yres_virtual)
453 var->yoffset = var->yres_virtual - var->yres;
454 line_size = var->xres * bpp / 8;
456 var->red.offset = 11; var->red.length = 5; var->red.msb_right = 0;
457 var->green.offset= 5; var->green.length = 6; var->green.msb_right = 0;
458 var->blue.offset = 0; var->blue.length = 5; var->blue.msb_right = 0;
465 /* pixclock in ps, the rest in pixclock */
466 var->pixclock = 10000000 / (panel->pixel_clock / 100);
467 var->left_margin = panel->hfp;
468 var->right_margin = panel->hbp;
469 var->upper_margin = panel->vfp;
470 var->lower_margin = panel->vbp;
471 var->hsync_len = panel->hsw;
472 var->vsync_len = panel->vsw;
474 /* TODO: get these from panel->config */
475 var->vmode = FB_VMODE_NONINTERLACED;
481 static struct fb_var_screeninfo new_var;
483 /* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */
484 static void omapfb_rotate(struct fb_info *fbi, int rotate)
486 struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
490 if (cpu_is_omap1510() && rotate != fbdev->fb_info->var.rotate) {
491 memcpy(&new_var, &fbi->var, sizeof(new_var));
492 new_var.rotate = rotate;
493 if (set_fb_var(fbdev, &new_var) == 0 &&
494 memcmp(&new_var, &fbi->var, sizeof(new_var))) {
495 memcpy(&fbi->var, &new_var, sizeof(new_var));
496 ctrl_change_mode(fbdev);
503 /* Set new x,y offsets in the virtual display for the visible area and switch
506 static int omapfb_pan_display(struct fb_var_screeninfo *var,
509 struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
514 if (var->xoffset != fbi->var.xoffset ||
515 var->yoffset != fbi->var.yoffset) {
516 memcpy(&new_var, &fbi->var, sizeof(new_var));
517 new_var.xoffset = var->xoffset;
518 new_var.yoffset = var->yoffset;
519 if (set_fb_var(fbdev, &new_var))
522 memcpy(&fbi->var, &new_var, sizeof(new_var));
523 ctrl_change_mode(fbdev);
531 /* Set mirror to vertical axis and switch to the new mode. */
532 static int omapfb_mirror(struct omapfb_device *fbdev, int mirror)
538 mirror = mirror ? 1 : 0;
539 if (cpu_is_omap1510())
541 else if (mirror != fbdev->mirror) {
542 fbdev->mirror = mirror;
543 r = ctrl_change_mode(fbdev);
550 /* Check values in var, try to adjust them in case of out of bound values if
551 * possible, or return error.
553 static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
555 struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
560 r = set_fb_var(fbdev, var);
566 /* Switch to a new mode. The parameters for it has been check already by
569 static int omapfb_set_par(struct fb_info *fbi)
572 struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
577 r = ctrl_change_mode(fbdev);
583 int omapfb_update_window_async(struct omapfb_update_window *win,
584 void (*callback)(void *),
587 struct omapfb_device *fbdev = omapfb_dev;
588 struct fb_var_screeninfo *var;
592 DBGPRINT(1, "no fbdev\n");
596 var = &fbdev->fb_info->var;
598 if (win->x >= var->xres || win->y >= var->yres) {
599 DBGPRINT(1, "invalid x %d, y %d\n", win->x, win->y);
603 if (!fbdev->ctrl->update_window ||
604 fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) {
605 DBGPRINT(1, "invalid update mode\n");
609 if (win->x + win->width >= var->xres)
610 win->width = var->xres - win->x;
611 if (win->y + win->height >= var->yres)
612 win->height = var->yres - win->y;
613 if (!win->width || !win->height) {
614 DBGPRINT(1, "zero size window\n");
618 return fbdev->ctrl->update_window(win, callback, callback_data);
620 EXPORT_SYMBOL(omapfb_update_window_async);
622 static int omapfb_update_win(struct omapfb_device *fbdev,
623 struct omapfb_update_window *win)
627 omapfb_rqueue_lock(fbdev);
628 ret = omapfb_update_window_async(win, NULL, 0);
629 omapfb_rqueue_unlock(fbdev);
634 static void omapfb_update_full_screen(struct omapfb_device *fbdev)
636 struct omapfb_update_window win;
640 win.width = fbdev->panel->x_res;
641 win.height = fbdev->panel->y_res;
644 omapfb_rqueue_lock(fbdev);
645 fbdev->ctrl->update_window(&win, NULL, 0);
646 omapfb_rqueue_unlock(fbdev);
649 static int omapfb_setup_plane(struct omapfb_device *fbdev,
650 struct omapfb_setup_plane *sp)
654 omapfb_rqueue_lock(fbdev);
655 r = fbdev->ctrl->setup_plane(sp->plane, sp->channel_out, sp->offset,
656 sp->width, sp->pos_x, sp->pos_y, sp->width,
657 sp->height, sp->color_mode);
658 omapfb_rqueue_unlock(fbdev);
663 static int omapfb_enable_plane(struct omapfb_device *fbdev, int plane,
668 omapfb_rqueue_lock(fbdev);
669 r = fbdev->ctrl->enable_plane(plane, enable);
670 omapfb_rqueue_unlock(fbdev);
675 static int omapfb_set_color_key(struct omapfb_device *fbdev,
676 struct omapfb_color_key *ck)
680 if (!fbdev->ctrl->set_color_key)
683 omapfb_rqueue_lock(fbdev);
684 r = fbdev->ctrl->set_color_key(ck);
685 omapfb_rqueue_unlock(fbdev);
690 static struct notifier_block *omapfb_client_list;
692 int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb,
693 omapfb_notifier_callback_t callback,
700 omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *,
701 unsigned long, void *))callback;
702 omapfb_nb->data = callback_data;
703 r = notifier_chain_register(&omapfb_client_list, &omapfb_nb->nb);
706 if (omapfb_dev != NULL &&
707 omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) {
708 omapfb_dev->ctrl->bind_client(omapfb_nb);
713 EXPORT_SYMBOL(omapfb_register_client);
715 int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb)
717 return notifier_chain_unregister(&omapfb_client_list,
720 EXPORT_SYMBOL(omapfb_unregister_client);
722 void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event)
725 notifier_call_chain(&omapfb_client_list, event, fbdev);
727 EXPORT_SYMBOL(omapfb_notify_clients);
729 static int omapfb_set_update_mode(struct omapfb_device *fbdev,
730 enum omapfb_update_mode mode)
734 omapfb_rqueue_lock(fbdev);
735 r = fbdev->ctrl->set_update_mode(mode);
736 omapfb_rqueue_unlock(fbdev);
741 static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev)
745 omapfb_rqueue_lock(fbdev);
746 r = fbdev->ctrl->get_update_mode();
747 omapfb_rqueue_unlock(fbdev);
752 static unsigned long omapfb_get_caps(struct fb_info *fbi)
754 struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
758 caps |= fbdev->panel->get_caps();
759 caps |= fbdev->ctrl->get_caps();
763 /* For lcd testing */
764 void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
766 omapfb_rqueue_lock(fbdev);
767 *(u16 *)fbdev->vram_virt_base = pixval;
768 if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) {
769 struct omapfb_update_window win;
776 fbdev->ctrl->update_window(&win, NULL, 0);
778 omapfb_rqueue_unlock(fbdev);
780 EXPORT_SYMBOL(omapfb_write_first_pixel);
782 /* Ioctl interface. Part of the kernel mode frame buffer API is duplicated
783 * here to be accessible by user mode code. In addition transparent copy
784 * graphics transformations, frame flipping support is provided through this
787 static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
790 struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
791 struct fb_ops *ops = fbi->fbops;
793 struct omapfb_update_window update_window;
794 struct omapfb_setup_plane setup_plane;
795 struct omapfb_enable_plane enable_plane;
796 struct omapfb_color_key color_key;
797 enum omapfb_update_mode update_mode;
804 DBGPRINT(2, "cmd=%010x\n", cmd);
808 if (get_user(p.mirror, (int __user *)arg))
811 omapfb_mirror(fbdev, p.mirror);
813 case OMAPFB_SYNC_GFX:
818 case OMAPFB_SET_UPDATE_MODE:
819 if (get_user(p.update_mode, (int __user *)arg))
822 r = omapfb_set_update_mode(fbdev, p.update_mode);
824 case OMAPFB_GET_UPDATE_MODE:
825 p.update_mode = omapfb_get_update_mode(fbdev);
826 if (put_user(p.update_mode,
827 (enum omapfb_update_mode __user *)arg))
830 case OMAPFB_UPDATE_WINDOW_OLD:
831 if (copy_from_user(&p.update_window, (void __user *)arg,
832 sizeof(struct omapfb_update_window_old)))
835 p.update_window.format = 0;
836 r = omapfb_update_win(fbdev, &p.update_window);
839 case OMAPFB_UPDATE_WINDOW:
840 if (copy_from_user(&p.update_window, (void __user *)arg,
841 sizeof(p.update_window)))
844 r = omapfb_update_win(fbdev, &p.update_window);
846 case OMAPFB_SETUP_PLANE:
847 if (copy_from_user(&p.setup_plane, (void __user *)arg,
848 sizeof(p.setup_plane)))
851 r = omapfb_setup_plane(fbdev, &p.setup_plane);
853 case OMAPFB_ENABLE_PLANE:
854 if (copy_from_user(&p.enable_plane, (void __user *)arg,
855 sizeof(p.enable_plane)))
858 r = omapfb_enable_plane(fbdev,
859 p.enable_plane.plane, p.enable_plane.enable);
861 case OMAPFB_SET_COLOR_KEY:
862 if (copy_from_user(&p.color_key, (void __user *)arg,
863 sizeof(p.color_key)))
866 r = omapfb_set_color_key(fbdev, &p.color_key);
868 case OMAPFB_GET_CAPS:
869 p.caps = omapfb_get_caps(fbi);
870 if (put_user(p.caps, (unsigned long __user *)arg))
873 case OMAPFB_LCD_TEST:
877 if (get_user(test_num, (int __user *)arg)) {
881 if (!fbdev->panel->run_test) {
885 r = fbdev->panel->run_test(test_num);
888 case OMAPFB_CTRL_TEST:
892 if (get_user(test_num, (int __user *)arg)) {
896 if (!fbdev->ctrl->run_test) {
900 r = fbdev->ctrl->run_test(test_num);
911 /* Callback table for the frame buffer framework. Some of these pointers
912 * will be changed according to the current setting of fb_info->accel_flags.
914 static struct fb_ops omapfb_ops = {
915 .owner = THIS_MODULE,
916 .fb_open = omapfb_open,
917 .fb_release = omapfb_release,
918 .fb_setcolreg = omapfb_setcolreg,
919 .fb_setcmap = omapfb_setcmap,
920 .fb_fillrect = cfb_fillrect,
921 .fb_copyarea = cfb_copyarea,
922 .fb_imageblit = cfb_imageblit,
923 .fb_blank = omapfb_blank,
924 .fb_ioctl = omapfb_ioctl,
925 .fb_check_var = omapfb_check_var,
926 .fb_set_par = omapfb_set_par,
927 .fb_rotate = omapfb_rotate,
928 .fb_pan_display = omapfb_pan_display,
932 * ---------------------------------------------------------------------------
934 * ---------------------------------------------------------------------------
936 /* omapfbX sysfs entries */
937 static ssize_t omapfb_show_caps_num(struct device *dev, struct device_attribute *attr, char *buf)
939 struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
941 return snprintf(buf, PAGE_SIZE, "%#010lx\n",
942 omapfb_get_caps(fbdev->fb_info));
945 static ssize_t omapfb_show_caps_text(struct device *dev, struct device_attribute *attr, char *buf)
947 struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
952 caps = omapfb_get_caps(fbdev->fb_info);
953 for (i = 0; i < ARRAY_SIZE(omapfb_caps_table) && pos < PAGE_SIZE; i++) {
954 if (omapfb_caps_table[i].flag & caps) {
955 pos += snprintf(&buf[pos], PAGE_SIZE - pos, "%s\n",
956 omapfb_caps_table[i].name);
959 return min((int)PAGE_SIZE, pos);
962 static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL);
963 static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
965 /* panel sysfs entries */
966 static ssize_t omapfb_show_panel_name(struct device *dev,
967 struct device_attribute *attr, char *buf)
969 struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
971 return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name);
974 static ssize_t omapfb_show_bklight_level(struct device *dev,
975 struct device_attribute *attr,
978 struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
981 if (fbdev->panel->get_bklight_level) {
982 r = snprintf(buf, PAGE_SIZE, "%d\n",
983 fbdev->panel->get_bklight_level());
989 static ssize_t omapfb_store_bklight_level(struct device *dev,
990 struct device_attribute *attr,
991 const char *buf, size_t size)
993 struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
996 if (fbdev->panel->set_bklight_level) {
999 if (sscanf(buf, "%10d", &level) == 1) {
1000 r = fbdev->panel->set_bklight_level(level);
1005 return r ? r : size;
1008 static ssize_t omapfb_show_bklight_max(struct device *dev,
1009 struct device_attribute *attr, char *buf)
1011 struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
1014 if (fbdev->panel->get_bklight_level) {
1015 r = snprintf(buf, PAGE_SIZE, "%d\n",
1016 fbdev->panel->get_bklight_max());
1022 static struct device_attribute dev_attr_panel_name =
1023 __ATTR(name, 0444, omapfb_show_panel_name, NULL);
1024 static DEVICE_ATTR(backlight_level, 0664,
1025 omapfb_show_bklight_level, omapfb_store_bklight_level);
1026 static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL);
1028 static struct attribute *panel_attrs[] = {
1029 &dev_attr_panel_name.attr,
1030 &dev_attr_backlight_level.attr,
1031 &dev_attr_backlight_max.attr,
1035 static struct attribute_group panel_attr_grp = {
1037 .attrs = panel_attrs,
1040 /* ctrl sysfs entries */
1041 static ssize_t omapfb_show_ctrl_name(struct device *dev,
1042 struct device_attribute *attr, char *buf)
1044 struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
1046 return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name);
1049 static struct device_attribute dev_attr_ctrl_name =
1050 __ATTR(name, 0444, omapfb_show_ctrl_name, NULL);
1052 static struct attribute *ctrl_attrs[] = {
1053 &dev_attr_ctrl_name.attr,
1057 static struct attribute_group ctrl_attr_grp = {
1059 .attrs = ctrl_attrs,
1062 static int omapfb_register_sysfs(struct omapfb_device *fbdev)
1066 if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num)))
1069 if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text)))
1072 if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp)))
1075 if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp)))
1080 sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1082 device_remove_file(fbdev->dev, &dev_attr_caps_text);
1084 device_remove_file(fbdev->dev, &dev_attr_caps_num);
1086 pr_err("unable to register sysfs interface\n");
1090 static void omapfb_unregister_sysfs(struct omapfb_device *fbdev)
1092 sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp);
1093 sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1094 device_remove_file(fbdev->dev, &dev_attr_caps_num);
1095 device_remove_file(fbdev->dev, &dev_attr_caps_text);
1099 * ---------------------------------------------------------------------------
1101 * ---------------------------------------------------------------------------
1103 /* Initialize system fb_info object and set the default video mode.
1104 * The frame buffer memory already allocated by lcddma_init
1106 static int fbinfo_init(struct omapfb_device *fbdev)
1108 struct fb_info *info = fbdev->fb_info;
1109 struct fb_var_screeninfo *var = &info->var;
1114 BUG_ON(!fbdev->vram_virt_base);
1116 info->fbops = &omapfb_ops;
1117 info->flags = FBINFO_FLAG_DEFAULT;
1118 info->screen_base = (char __iomem *)fbdev->vram_virt_base;
1120 info->pseudo_palette = fbdev->pseudo_palette;
1122 var->accel_flags = def_accel ? FB_ACCELF_TEXT : 0;
1123 var->xres_virtual = def_vxres;
1124 var->yres_virtual = def_vyres;
1125 var->rotate = def_rotate;
1127 fbdev->mirror = def_mirror;
1129 set_fb_var(fbdev, var);
1132 r = fb_alloc_cmap(&info->cmap, 16, 0);
1134 pr_err("unable to allocate color map memory\n");
1140 /* Release the fb_info object */
1141 static void fbinfo_cleanup(struct omapfb_device *fbdev)
1145 fb_dealloc_cmap(&fbdev->fb_info->cmap);
1150 /* Free driver resources. Can be called to rollback an aborted initialization
1153 static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
1157 unregister_framebuffer(fbdev->fb_info);
1159 omapfb_unregister_sysfs(fbdev);
1161 fbdev->panel->disable();
1163 omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
1165 fbinfo_cleanup(fbdev);
1167 ctrl_cleanup(fbdev);
1169 fbdev->panel->cleanup();
1171 dev_set_drvdata(fbdev->dev, NULL);
1172 framebuffer_release(fbdev->fb_info);
1174 /* nothing to free */
1181 static int omapfb_find_ctrl(struct omapfb_device *fbdev)
1183 struct omapfb_platform_data *conf;
1187 conf = (struct omapfb_platform_data *)fbdev->dev->platform_data;
1191 DBGPRINT(1, "omap_lcd_config not found\n");
1195 strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1);
1196 name[sizeof(name) - 1] = '\0';
1198 if (strcmp(name, "internal") == 0) {
1199 fbdev->ctrl = fbdev->int_ctrl;
1203 for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
1204 DBGPRINT(1, "ctrl %s\n", ctrls[i]->name);
1205 if (strcmp(ctrls[i]->name, name) == 0) {
1206 fbdev->ctrl = ctrls[i];
1211 if (fbdev->ctrl == NULL) {
1212 DBGPRINT(1, "ctrl %s not supported\n", name);
1219 static void check_required_callbacks(struct omapfb_device *fbdev)
1221 #define _C(x) (fbdev->ctrl->x != NULL)
1222 #define _P(x) (fbdev->panel->x != NULL)
1223 BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL);
1224 BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) &&
1225 _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) &&
1226 _P(init) && _P(cleanup) && _P(enable) && _P(disable) &&
1232 /* Called by LDM binding to probe and attach a new device.
1233 * Initialization sequence:
1234 * 1. allocate system fb_info structure
1235 * select panel type according to machine type
1237 * 3. init LCD controller and LCD DMA
1238 * 4. init system fb_info structure
1240 * 6. enable LCD panel
1241 * start LCD frame transfer
1242 * 7. register system fb_info structure
1244 static int omapfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel)
1246 struct omapfb_device *fbdev = NULL;
1247 struct fb_info *fbi;
1249 unsigned long phz, hhz, vhz;
1256 if (pdev->num_resources != 0) {
1257 pr_err("probed for an unknown device\n");
1262 fbi = framebuffer_alloc(sizeof(struct omapfb_device), &pdev->dev);
1264 pr_err("unable to allocate memory for device info\n");
1270 fbdev = (struct omapfb_device *)fbi->par;
1271 fbdev->fb_info = fbi;
1272 fbdev->dev = &pdev->dev;
1273 fbdev->panel = panel;
1274 platform_set_drvdata(pdev, fbdev);
1276 init_MUTEX(&fbdev->rqueue_sema);
1278 #ifdef CONFIG_ARCH_OMAP1
1279 fbdev->int_ctrl = &omap1_int_ctrl;
1280 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1281 fbdev->ext_if = &sossi_extif;
1284 fbdev->int_ctrl = &omap2_int_ctrl;
1285 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1286 fbdev->ext_if = &rfbi_extif;
1289 if (omapfb_find_ctrl(fbdev) < 0) {
1290 pr_err("LCD controller not found, board not supported\n");
1295 pr_info(MODULE_NAME ": configured for panel %s\n", fbdev->panel->name);
1297 r = fbdev->panel->init(fbdev);
1302 r = ctrl_init(fbdev);
1307 /* We depend on doing this after ctrl_init, since it can redefine
1310 if (fbdev->ctrl->mmap)
1311 omapfb_ops.fb_mmap = omapfb_mmap;
1313 check_required_callbacks(fbdev);
1315 r = fbinfo_init(fbdev);
1320 #ifdef CONFIG_FB_OMAP_DMA_TUNE
1321 /* Set DMA priority for EMIFF access to highest */
1322 omap_set_dma_priority(OMAP_DMA_PORT_EMIFF, 15);
1325 r = ctrl_change_mode(fbdev);
1327 pr_err("mode setting failed\n");
1332 omapfb_enable_plane(fbdev, OMAPFB_PLANE_GFX, 1);
1334 omapfb_set_update_mode(fbdev, manual_update ?
1335 OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE);
1338 r = fbdev->panel->enable();
1343 r = omapfb_register_sysfs(fbdev);
1348 r = register_framebuffer(fbdev->fb_info);
1350 pr_err("register_framebuffer failed\n");
1354 fbdev->state = OMAPFB_ACTIVE;
1356 panel = fbdev->panel;
1357 phz = panel->pixel_clock * 1000;
1358 hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw);
1359 vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw);
1363 pr_info(MODULE_NAME ": initialized vram=%lu "
1364 "pixclock %lu kHz hfreq %lu.%lu kHz vfreq %lu.%lu Hz\n",
1366 phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10);
1372 omapfb_free_resources(fbdev, init_state);
1378 static int omapfb_probe(struct platform_device *pdev)
1380 BUG_ON(fbdev_pdev != NULL);
1384 if (fbdev_panel != NULL)
1385 omapfb_do_probe(fbdev_pdev, fbdev_panel);
1389 void omapfb_register_panel(struct lcd_panel *panel)
1391 BUG_ON(fbdev_panel != NULL);
1394 fbdev_panel = panel;
1395 if (fbdev_pdev != NULL)
1396 omapfb_do_probe(fbdev_pdev, fbdev_panel);
1399 /* Called when the device is being detached from the driver */
1400 static int omapfb_remove(struct platform_device *pdev)
1402 struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1403 enum omapfb_state saved_state = fbdev->state;
1406 /* FIXME: wait till completion of pending events */
1408 fbdev->state = OMAPFB_DISABLED;
1409 omapfb_free_resources(fbdev, saved_state);
1416 static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg)
1418 struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1422 omapfb_blank(VESA_POWERDOWN, fbdev->fb_info);
1430 static int omapfb_resume(struct platform_device *pdev)
1432 struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1436 omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info);
1442 static struct platform_driver omapfb_driver = {
1443 .probe = omapfb_probe,
1444 .remove = omapfb_remove,
1445 .suspend = omapfb_suspend,
1446 .resume = omapfb_resume,
1448 .name = OMAPFB_DRIVER,
1449 .owner = THIS_MODULE,
1455 /* Process kernel command line parameters */
1456 static int __init omapfb_setup(char *options)
1458 char *this_opt = NULL;
1463 if (!options || !*options)
1466 while (!r && (this_opt = strsep(&options, ",")) != NULL) {
1467 if (!strncmp(this_opt, "accel", 5))
1469 else if (!strncmp(this_opt, "vram:", 5)) {
1471 def_vram = (simple_strtoul(this_opt + 5, &suffix, 0));
1472 switch (suffix[0]) {
1484 pr_err("invalid vram suffix\n");
1488 else if (!strncmp(this_opt, "vxres:", 6))
1489 def_vxres = simple_strtoul(this_opt + 6, NULL, 0);
1490 else if (!strncmp(this_opt, "vyres:", 6))
1491 def_vyres = simple_strtoul(this_opt + 6, NULL, 0);
1492 else if (!strncmp(this_opt, "rotate:", 7))
1493 def_rotate = (simple_strtoul(this_opt + 7, NULL, 0));
1494 else if (!strncmp(this_opt, "mirror:", 7))
1495 def_mirror = (simple_strtoul(this_opt + 7, NULL, 0));
1496 else if (!strncmp(this_opt, "manual_update", 13))
1499 pr_err("invalid option\n");
1510 /* Register both the driver and the device */
1511 static int __init omapfb_init(void)
1521 if (fb_get_options("omapfb", &option)) {
1525 omapfb_setup(option);
1528 /* Register the driver with LDM */
1529 if (platform_driver_register(&omapfb_driver)) {
1530 pr_err("failed to register omapfb driver\n");
1540 static void __exit omapfb_cleanup(void)
1544 platform_driver_unregister(&omapfb_driver);
1549 module_param_named(accel, def_accel, uint, 0664);
1550 module_param_named(vram, def_vram, ulong, 0664);
1551 module_param_named(vxres, def_vxres, long, 0664);
1552 module_param_named(vyres, def_vyres, long, 0664);
1553 module_param_named(rotate, def_rotate, uint, 0664);
1554 module_param_named(mirror, def_mirror, uint, 0664);
1555 module_param_named(manual_update, manual_update, bool, 0664);
1557 module_init(omapfb_init);
1558 module_exit(omapfb_cleanup);
1560 MODULE_DESCRIPTION("TI OMAP framebuffer driver");
1561 MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>");
1562 MODULE_LICENSE("GPL");