Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
omapfb_main.c
Go to the documentation of this file.
1 /*
2  * Framebuffer driver for TI OMAP boards
3  *
4  * Copyright (C) 2004 Nokia Corporation
5  * Author: Imre Deak <[email protected]>
6  *
7  * Acknowledgements:
8  * Alex McMains <[email protected]> - Original driver
9  * Juha Yrjola <[email protected]> - Original driver and improvements
10  * Dirk Behme <[email protected]> - changes for 2.6 kernel API
11  * Texas Instruments - H3 support
12  *
13  * This program is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU General Public License as published by the
15  * Free Software Foundation; either version 2 of the License, or (at your
16  * option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  * General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, write to the Free Software Foundation, Inc.,
25  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  */
27 #include <linux/platform_device.h>
28 #include <linux/mm.h>
29 #include <linux/slab.h>
30 #include <linux/uaccess.h>
31 #include <linux/module.h>
32 
33 #include <plat/dma.h>
34 
35 #include "omapfb.h"
36 #include "lcdc.h"
37 
38 #define MODULE_NAME "omapfb"
39 
40 static unsigned int def_accel;
41 static unsigned long def_vram[OMAPFB_PLANE_NUM];
42 static unsigned int def_vram_cnt;
43 static unsigned long def_vxres;
44 static unsigned long def_vyres;
45 static unsigned int def_rotate;
46 static unsigned int def_mirror;
47 
48 #ifdef CONFIG_FB_OMAP_MANUAL_UPDATE
49 static bool manual_update = 1;
50 #else
51 static bool manual_update;
52 #endif
53 
54 static struct platform_device *fbdev_pdev;
55 static struct lcd_panel *fbdev_panel;
56 static struct omapfb_device *omapfb_dev;
57 
59  unsigned long flag;
60  const char *name;
61 };
62 
63 static struct caps_table_struct ctrl_caps[] = {
64  { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" },
65  { OMAPFB_CAPS_TEARSYNC, "tearing synchronization" },
66  { OMAPFB_CAPS_PLANE_RELOCATE_MEM, "relocate plane memory" },
67  { OMAPFB_CAPS_PLANE_SCALE, "scale plane" },
68  { OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" },
69  { OMAPFB_CAPS_WINDOW_SCALE, "scale window" },
70  { OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" },
71  { OMAPFB_CAPS_WINDOW_ROTATE, "rotate window" },
72  { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" },
73 };
74 
75 static struct caps_table_struct color_caps[] = {
76  { 1 << OMAPFB_COLOR_RGB565, "RGB565", },
77  { 1 << OMAPFB_COLOR_YUV422, "YUV422", },
78  { 1 << OMAPFB_COLOR_YUV420, "YUV420", },
79  { 1 << OMAPFB_COLOR_CLUT_8BPP, "CLUT8", },
80  { 1 << OMAPFB_COLOR_CLUT_4BPP, "CLUT4", },
81  { 1 << OMAPFB_COLOR_CLUT_2BPP, "CLUT2", },
82  { 1 << OMAPFB_COLOR_CLUT_1BPP, "CLUT1", },
83  { 1 << OMAPFB_COLOR_RGB444, "RGB444", },
84  { 1 << OMAPFB_COLOR_YUY422, "YUY422", },
85 };
86 
87 static void omapdss_release(struct device *dev)
88 {
89 }
90 
91 /* dummy device for clocks */
92 static struct platform_device omapdss_device = {
93  .name = "omapdss_dss",
94  .id = -1,
95  .dev = {
96  .release = omapdss_release,
97  },
98 };
99 
100 /*
101  * ---------------------------------------------------------------------------
102  * LCD panel
103  * ---------------------------------------------------------------------------
104  */
105 extern struct lcd_ctrl hwa742_ctrl;
106 
107 static const struct lcd_ctrl *ctrls[] = {
109 
110 #ifdef CONFIG_FB_OMAP_LCDC_HWA742
111  &hwa742_ctrl,
112 #endif
113 };
114 
115 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
116 extern struct lcd_ctrl_extif omap1_ext_if;
117 #endif
118 
119 static void omapfb_rqueue_lock(struct omapfb_device *fbdev)
120 {
121  mutex_lock(&fbdev->rqueue_mutex);
122 }
123 
124 static void omapfb_rqueue_unlock(struct omapfb_device *fbdev)
125 {
126  mutex_unlock(&fbdev->rqueue_mutex);
127 }
128 
129 /*
130  * ---------------------------------------------------------------------------
131  * LCD controller and LCD DMA
132  * ---------------------------------------------------------------------------
133  */
134 /*
135  * Allocate resources needed for LCD controller and LCD DMA operations. Video
136  * memory is allocated from system memory according to the virtual display
137  * size, except if a bigger memory size is specified explicitly as a kernel
138  * parameter.
139  */
140 static int ctrl_init(struct omapfb_device *fbdev)
141 {
142  int r;
143  int i;
144 
145  /* kernel/module vram parameters override boot tags/board config */
146  if (def_vram_cnt) {
147  for (i = 0; i < def_vram_cnt; i++)
148  fbdev->mem_desc.region[i].size =
149  PAGE_ALIGN(def_vram[i]);
150  fbdev->mem_desc.region_cnt = i;
151  }
152 
153  if (!fbdev->mem_desc.region_cnt) {
154  struct lcd_panel *panel = fbdev->panel;
155  int def_size;
156  int bpp = panel->bpp;
157 
158  /* 12 bpp is packed in 16 bits */
159  if (bpp == 12)
160  bpp = 16;
161  def_size = def_vxres * def_vyres * bpp / 8;
162  fbdev->mem_desc.region_cnt = 1;
163  fbdev->mem_desc.region[0].size = PAGE_ALIGN(def_size);
164  }
165  r = fbdev->ctrl->init(fbdev, 0, &fbdev->mem_desc);
166  if (r < 0) {
167  dev_err(fbdev->dev, "controller initialization failed (%d)\n",
168  r);
169  return r;
170  }
171 
172 #ifdef DEBUG
173  for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
174  dev_dbg(fbdev->dev, "region%d phys %08x virt %p size=%lu\n",
175  i,
176  fbdev->mem_desc.region[i].paddr,
177  fbdev->mem_desc.region[i].vaddr,
178  fbdev->mem_desc.region[i].size);
179  }
180 #endif
181  return 0;
182 }
183 
184 static void ctrl_cleanup(struct omapfb_device *fbdev)
185 {
186  fbdev->ctrl->cleanup();
187 }
188 
189 /* Must be called with fbdev->rqueue_mutex held. */
190 static int ctrl_change_mode(struct fb_info *fbi)
191 {
192  int r;
193  unsigned long offset;
194  struct omapfb_plane_struct *plane = fbi->par;
195  struct omapfb_device *fbdev = plane->fbdev;
196  struct fb_var_screeninfo *var = &fbi->var;
197 
198  offset = var->yoffset * fbi->fix.line_length +
199  var->xoffset * var->bits_per_pixel / 8;
200 
201  if (fbdev->ctrl->sync)
202  fbdev->ctrl->sync();
203  r = fbdev->ctrl->setup_plane(plane->idx, plane->info.channel_out,
204  offset, var->xres_virtual,
205  plane->info.pos_x, plane->info.pos_y,
206  var->xres, var->yres, plane->color_mode);
207  if (r < 0)
208  return r;
209 
210  if (fbdev->ctrl->set_rotate != NULL) {
211  r = fbdev->ctrl->set_rotate(var->rotate);
212  if (r < 0)
213  return r;
214  }
215 
216  if (fbdev->ctrl->set_scale != NULL)
217  r = fbdev->ctrl->set_scale(plane->idx,
218  var->xres, var->yres,
219  plane->info.out_width,
220  plane->info.out_height);
221 
222  return r;
223 }
224 
225 /*
226  * ---------------------------------------------------------------------------
227  * fbdev framework callbacks and the ioctl interface
228  * ---------------------------------------------------------------------------
229  */
230 /* Called each time the omapfb device is opened */
231 static int omapfb_open(struct fb_info *info, int user)
232 {
233  return 0;
234 }
235 
236 static void omapfb_sync(struct fb_info *info);
237 
238 /* Called when the omapfb device is closed. We make sure that any pending
239  * gfx DMA operations are ended, before we return. */
240 static int omapfb_release(struct fb_info *info, int user)
241 {
242  omapfb_sync(info);
243  return 0;
244 }
245 
246 /* Store a single color palette entry into a pseudo palette or the hardware
247  * palette if one is available. For now we support only 16bpp and thus store
248  * the entry only to the pseudo palette.
249  */
250 static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
251  u_int blue, u_int transp, int update_hw_pal)
252 {
253  struct omapfb_plane_struct *plane = info->par;
254  struct omapfb_device *fbdev = plane->fbdev;
255  struct fb_var_screeninfo *var = &info->var;
256  int r = 0;
257 
258  switch (plane->color_mode) {
259  case OMAPFB_COLOR_YUV422:
260  case OMAPFB_COLOR_YUV420:
261  case OMAPFB_COLOR_YUY422:
262  r = -EINVAL;
263  break;
268  if (fbdev->ctrl->setcolreg)
269  r = fbdev->ctrl->setcolreg(regno, red, green, blue,
270  transp, update_hw_pal);
271  /* Fallthrough */
272  case OMAPFB_COLOR_RGB565:
273  case OMAPFB_COLOR_RGB444:
274  if (r != 0)
275  break;
276 
277  if (regno < 0) {
278  r = -EINVAL;
279  break;
280  }
281 
282  if (regno < 16) {
283  u16 pal;
284  pal = ((red >> (16 - var->red.length)) <<
285  var->red.offset) |
286  ((green >> (16 - var->green.length)) <<
287  var->green.offset) |
288  (blue >> (16 - var->blue.length));
289  ((u32 *)(info->pseudo_palette))[regno] = pal;
290  }
291  break;
292  default:
293  BUG();
294  }
295  return r;
296 }
297 
298 static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
299  u_int transp, struct fb_info *info)
300 {
301  return _setcolreg(info, regno, red, green, blue, transp, 1);
302 }
303 
304 static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
305 {
306  int count, index, r;
307  u16 *red, *green, *blue, *transp;
308  u16 trans = 0xffff;
309 
310  red = cmap->red;
311  green = cmap->green;
312  blue = cmap->blue;
313  transp = cmap->transp;
314  index = cmap->start;
315 
316  for (count = 0; count < cmap->len; count++) {
317  if (transp)
318  trans = *transp++;
319  r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
320  count == cmap->len - 1);
321  if (r != 0)
322  return r;
323  }
324 
325  return 0;
326 }
327 
328 static int omapfb_update_full_screen(struct fb_info *fbi);
329 
330 static int omapfb_blank(int blank, struct fb_info *fbi)
331 {
332  struct omapfb_plane_struct *plane = fbi->par;
333  struct omapfb_device *fbdev = plane->fbdev;
334  int do_update = 0;
335  int r = 0;
336 
337  omapfb_rqueue_lock(fbdev);
338  switch (blank) {
339  case FB_BLANK_UNBLANK:
340  if (fbdev->state == OMAPFB_SUSPENDED) {
341  if (fbdev->ctrl->resume)
342  fbdev->ctrl->resume();
343  fbdev->panel->enable(fbdev->panel);
344  fbdev->state = OMAPFB_ACTIVE;
345  if (fbdev->ctrl->get_update_mode() ==
347  do_update = 1;
348  }
349  break;
350  case FB_BLANK_POWERDOWN:
351  if (fbdev->state == OMAPFB_ACTIVE) {
352  fbdev->panel->disable(fbdev->panel);
353  if (fbdev->ctrl->suspend)
354  fbdev->ctrl->suspend();
355  fbdev->state = OMAPFB_SUSPENDED;
356  }
357  break;
358  default:
359  r = -EINVAL;
360  }
361  omapfb_rqueue_unlock(fbdev);
362 
363  if (r == 0 && do_update)
364  r = omapfb_update_full_screen(fbi);
365 
366  return r;
367 }
368 
369 static void omapfb_sync(struct fb_info *fbi)
370 {
371  struct omapfb_plane_struct *plane = fbi->par;
372  struct omapfb_device *fbdev = plane->fbdev;
373 
374  omapfb_rqueue_lock(fbdev);
375  if (fbdev->ctrl->sync)
376  fbdev->ctrl->sync();
377  omapfb_rqueue_unlock(fbdev);
378 }
379 
380 /*
381  * Set fb_info.fix fields and also updates fbdev.
382  * When calling this fb_info.var must be set up already.
383  */
384 static void set_fb_fix(struct fb_info *fbi, int from_init)
385 {
386  struct fb_fix_screeninfo *fix = &fbi->fix;
387  struct fb_var_screeninfo *var = &fbi->var;
388  struct omapfb_plane_struct *plane = fbi->par;
389  struct omapfb_mem_region *rg;
390  int bpp;
391 
392  rg = &plane->fbdev->mem_desc.region[plane->idx];
393  fbi->screen_base = rg->vaddr;
394 
395  if (!from_init) {
396  mutex_lock(&fbi->mm_lock);
397  fix->smem_start = rg->paddr;
398  fix->smem_len = rg->size;
399  mutex_unlock(&fbi->mm_lock);
400  } else {
401  fix->smem_start = rg->paddr;
402  fix->smem_len = rg->size;
403  }
404 
406  bpp = var->bits_per_pixel;
407  if (var->nonstd)
409  else switch (var->bits_per_pixel) {
410  case 16:
411  case 12:
413  /* 12bpp is stored in 16 bits */
414  bpp = 16;
415  break;
416  case 1:
417  case 2:
418  case 4:
419  case 8:
421  break;
422  }
423  fix->accel = FB_ACCEL_OMAP1610;
424  fix->line_length = var->xres_virtual * bpp / 8;
425 }
426 
427 static int set_color_mode(struct omapfb_plane_struct *plane,
428  struct fb_var_screeninfo *var)
429 {
430  switch (var->nonstd) {
431  case 0:
432  break;
433  case OMAPFB_COLOR_YUV422:
434  var->bits_per_pixel = 16;
435  plane->color_mode = var->nonstd;
436  return 0;
437  case OMAPFB_COLOR_YUV420:
438  var->bits_per_pixel = 12;
439  plane->color_mode = var->nonstd;
440  return 0;
441  case OMAPFB_COLOR_YUY422:
442  var->bits_per_pixel = 16;
443  plane->color_mode = var->nonstd;
444  return 0;
445  default:
446  return -EINVAL;
447  }
448 
449  switch (var->bits_per_pixel) {
450  case 1:
452  return 0;
453  case 2:
455  return 0;
456  case 4:
458  return 0;
459  case 8:
461  return 0;
462  case 12:
463  var->bits_per_pixel = 16;
464  case 16:
465  if (plane->fbdev->panel->bpp == 12)
467  else
469  return 0;
470  default:
471  return -EINVAL;
472  }
473 }
474 
475 /*
476  * Check the values in var against our capabilities and in case of out of
477  * bound values try to adjust them.
478  */
479 static int set_fb_var(struct fb_info *fbi,
480  struct fb_var_screeninfo *var)
481 {
482  int bpp;
483  unsigned long max_frame_size;
484  unsigned long line_size;
485  int xres_min, xres_max;
486  int yres_min, yres_max;
487  struct omapfb_plane_struct *plane = fbi->par;
488  struct omapfb_device *fbdev = plane->fbdev;
489  struct lcd_panel *panel = fbdev->panel;
490 
491  if (set_color_mode(plane, var) < 0)
492  return -EINVAL;
493 
494  bpp = var->bits_per_pixel;
495  if (plane->color_mode == OMAPFB_COLOR_RGB444)
496  bpp = 16;
497 
498  switch (var->rotate) {
499  case 0:
500  case 180:
501  xres_min = OMAPFB_PLANE_XRES_MIN;
502  xres_max = panel->x_res;
503  yres_min = OMAPFB_PLANE_YRES_MIN;
504  yres_max = panel->y_res;
505  if (cpu_is_omap15xx()) {
506  var->xres = panel->x_res;
507  var->yres = panel->y_res;
508  }
509  break;
510  case 90:
511  case 270:
512  xres_min = OMAPFB_PLANE_YRES_MIN;
513  xres_max = panel->y_res;
514  yres_min = OMAPFB_PLANE_XRES_MIN;
515  yres_max = panel->x_res;
516  if (cpu_is_omap15xx()) {
517  var->xres = panel->y_res;
518  var->yres = panel->x_res;
519  }
520  break;
521  default:
522  return -EINVAL;
523  }
524 
525  if (var->xres < xres_min)
526  var->xres = xres_min;
527  if (var->yres < yres_min)
528  var->yres = yres_min;
529  if (var->xres > xres_max)
530  var->xres = xres_max;
531  if (var->yres > yres_max)
532  var->yres = yres_max;
533 
534  if (var->xres_virtual < var->xres)
535  var->xres_virtual = var->xres;
536  if (var->yres_virtual < var->yres)
537  var->yres_virtual = var->yres;
538  max_frame_size = fbdev->mem_desc.region[plane->idx].size;
539  line_size = var->xres_virtual * bpp / 8;
540  if (line_size * var->yres_virtual > max_frame_size) {
541  /* Try to keep yres_virtual first */
542  line_size = max_frame_size / var->yres_virtual;
543  var->xres_virtual = line_size * 8 / bpp;
544  if (var->xres_virtual < var->xres) {
545  /* Still doesn't fit. Shrink yres_virtual too */
546  var->xres_virtual = var->xres;
547  line_size = var->xres * bpp / 8;
548  var->yres_virtual = max_frame_size / line_size;
549  }
550  /* Recheck this, as the virtual size changed. */
551  if (var->xres_virtual < var->xres)
552  var->xres = var->xres_virtual;
553  if (var->yres_virtual < var->yres)
554  var->yres = var->yres_virtual;
555  if (var->xres < xres_min || var->yres < yres_min)
556  return -EINVAL;
557  }
558  if (var->xres + var->xoffset > var->xres_virtual)
559  var->xoffset = var->xres_virtual - var->xres;
560  if (var->yres + var->yoffset > var->yres_virtual)
561  var->yoffset = var->yres_virtual - var->yres;
562 
563  if (plane->color_mode == OMAPFB_COLOR_RGB444) {
564  var->red.offset = 8; var->red.length = 4;
565  var->red.msb_right = 0;
566  var->green.offset = 4; var->green.length = 4;
567  var->green.msb_right = 0;
568  var->blue.offset = 0; var->blue.length = 4;
569  var->blue.msb_right = 0;
570  } else {
571  var->red.offset = 11; var->red.length = 5;
572  var->red.msb_right = 0;
573  var->green.offset = 5; var->green.length = 6;
574  var->green.msb_right = 0;
575  var->blue.offset = 0; var->blue.length = 5;
576  var->blue.msb_right = 0;
577  }
578 
579  var->height = -1;
580  var->width = -1;
581  var->grayscale = 0;
582 
583  /* pixclock in ps, the rest in pixclock */
584  var->pixclock = 10000000 / (panel->pixel_clock / 100);
585  var->left_margin = panel->hfp;
586  var->right_margin = panel->hbp;
587  var->upper_margin = panel->vfp;
588  var->lower_margin = panel->vbp;
589  var->hsync_len = panel->hsw;
590  var->vsync_len = panel->vsw;
591 
592  /* TODO: get these from panel->config */
594  var->sync = 0;
595 
596  return 0;
597 }
598 
599 
600 /* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */
601 static void omapfb_rotate(struct fb_info *fbi, int rotate)
602 {
603  struct omapfb_plane_struct *plane = fbi->par;
604  struct omapfb_device *fbdev = plane->fbdev;
605 
606  omapfb_rqueue_lock(fbdev);
607  if (rotate != fbi->var.rotate) {
608  struct fb_var_screeninfo *new_var = &fbdev->new_var;
609 
610  memcpy(new_var, &fbi->var, sizeof(*new_var));
611  new_var->rotate = rotate;
612  if (set_fb_var(fbi, new_var) == 0 &&
613  memcmp(new_var, &fbi->var, sizeof(*new_var))) {
614  memcpy(&fbi->var, new_var, sizeof(*new_var));
615  ctrl_change_mode(fbi);
616  }
617  }
618  omapfb_rqueue_unlock(fbdev);
619 }
620 
621 /*
622  * Set new x,y offsets in the virtual display for the visible area and switch
623  * to the new mode.
624  */
625 static int omapfb_pan_display(struct fb_var_screeninfo *var,
626  struct fb_info *fbi)
627 {
628  struct omapfb_plane_struct *plane = fbi->par;
629  struct omapfb_device *fbdev = plane->fbdev;
630  int r = 0;
631 
632  omapfb_rqueue_lock(fbdev);
633  if (var->xoffset != fbi->var.xoffset ||
634  var->yoffset != fbi->var.yoffset) {
635  struct fb_var_screeninfo *new_var = &fbdev->new_var;
636 
637  memcpy(new_var, &fbi->var, sizeof(*new_var));
638  new_var->xoffset = var->xoffset;
639  new_var->yoffset = var->yoffset;
640  if (set_fb_var(fbi, new_var))
641  r = -EINVAL;
642  else {
643  memcpy(&fbi->var, new_var, sizeof(*new_var));
644  ctrl_change_mode(fbi);
645  }
646  }
647  omapfb_rqueue_unlock(fbdev);
648 
649  return r;
650 }
651 
652 /* Set mirror to vertical axis and switch to the new mode. */
653 static int omapfb_mirror(struct fb_info *fbi, int mirror)
654 {
655  struct omapfb_plane_struct *plane = fbi->par;
656  struct omapfb_device *fbdev = plane->fbdev;
657  int r = 0;
658 
659  omapfb_rqueue_lock(fbdev);
660  mirror = mirror ? 1 : 0;
661  if (cpu_is_omap15xx())
662  r = -EINVAL;
663  else if (mirror != plane->info.mirror) {
664  plane->info.mirror = mirror;
665  r = ctrl_change_mode(fbi);
666  }
667  omapfb_rqueue_unlock(fbdev);
668 
669  return r;
670 }
671 
672 /*
673  * Check values in var, try to adjust them in case of out of bound values if
674  * possible, or return error.
675  */
676 static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
677 {
678  struct omapfb_plane_struct *plane = fbi->par;
679  struct omapfb_device *fbdev = plane->fbdev;
680  int r;
681 
682  omapfb_rqueue_lock(fbdev);
683  if (fbdev->ctrl->sync != NULL)
684  fbdev->ctrl->sync();
685  r = set_fb_var(fbi, var);
686  omapfb_rqueue_unlock(fbdev);
687 
688  return r;
689 }
690 
691 /*
692  * Switch to a new mode. The parameters for it has been check already by
693  * omapfb_check_var.
694  */
695 static int omapfb_set_par(struct fb_info *fbi)
696 {
697  struct omapfb_plane_struct *plane = fbi->par;
698  struct omapfb_device *fbdev = plane->fbdev;
699  int r = 0;
700 
701  omapfb_rqueue_lock(fbdev);
702  set_fb_fix(fbi, 0);
703  r = ctrl_change_mode(fbi);
704  omapfb_rqueue_unlock(fbdev);
705 
706  return r;
707 }
708 
710  struct omapfb_update_window *win,
711  void (*callback)(void *),
712  void *callback_data)
713 {
714  int xres, yres;
715  struct omapfb_plane_struct *plane = fbi->par;
716  struct omapfb_device *fbdev = plane->fbdev;
717  struct fb_var_screeninfo *var = &fbi->var;
718 
719  switch (var->rotate) {
720  case 0:
721  case 180:
722  xres = fbdev->panel->x_res;
723  yres = fbdev->panel->y_res;
724  break;
725  case 90:
726  case 270:
727  xres = fbdev->panel->y_res;
728  yres = fbdev->panel->x_res;
729  break;
730  default:
731  return -EINVAL;
732  }
733 
734  if (win->x >= xres || win->y >= yres ||
735  win->out_x > xres || win->out_y > yres)
736  return -EINVAL;
737 
738  if (!fbdev->ctrl->update_window ||
739  fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
740  return -ENODEV;
741 
742  if (win->x + win->width > xres)
743  win->width = xres - win->x;
744  if (win->y + win->height > yres)
745  win->height = yres - win->y;
746  if (win->out_x + win->out_width > xres)
747  win->out_width = xres - win->out_x;
748  if (win->out_y + win->out_height > yres)
749  win->out_height = yres - win->out_y;
750  if (!win->width || !win->height || !win->out_width || !win->out_height)
751  return 0;
752 
753  return fbdev->ctrl->update_window(fbi, win, callback, callback_data);
754 }
756 
757 static int omapfb_update_win(struct fb_info *fbi,
758  struct omapfb_update_window *win)
759 {
760  struct omapfb_plane_struct *plane = fbi->par;
761  int ret;
762 
763  omapfb_rqueue_lock(plane->fbdev);
764  ret = omapfb_update_window_async(fbi, win, NULL, NULL);
765  omapfb_rqueue_unlock(plane->fbdev);
766 
767  return ret;
768 }
769 
770 static int omapfb_update_full_screen(struct fb_info *fbi)
771 {
772  struct omapfb_plane_struct *plane = fbi->par;
773  struct omapfb_device *fbdev = plane->fbdev;
774  struct omapfb_update_window win;
775  int r;
776 
777  if (!fbdev->ctrl->update_window ||
778  fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
779  return -ENODEV;
780 
781  win.x = 0;
782  win.y = 0;
783  win.width = fbi->var.xres;
784  win.height = fbi->var.yres;
785  win.out_x = 0;
786  win.out_y = 0;
787  win.out_width = fbi->var.xres;
788  win.out_height = fbi->var.yres;
789  win.format = 0;
790 
791  omapfb_rqueue_lock(fbdev);
792  r = fbdev->ctrl->update_window(fbi, &win, NULL, NULL);
793  omapfb_rqueue_unlock(fbdev);
794 
795  return r;
796 }
797 
798 static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
799 {
800  struct omapfb_plane_struct *plane = fbi->par;
801  struct omapfb_device *fbdev = plane->fbdev;
802  struct lcd_panel *panel = fbdev->panel;
803  struct omapfb_plane_info old_info;
804  int r = 0;
805 
806  if (pi->pos_x + pi->out_width > panel->x_res ||
807  pi->pos_y + pi->out_height > panel->y_res)
808  return -EINVAL;
809 
810  omapfb_rqueue_lock(fbdev);
811  if (pi->enabled && !fbdev->mem_desc.region[plane->idx].size) {
812  /*
813  * This plane's memory was freed, can't enable it
814  * until it's reallocated.
815  */
816  r = -EINVAL;
817  goto out;
818  }
819  old_info = plane->info;
820  plane->info = *pi;
821  if (pi->enabled) {
822  r = ctrl_change_mode(fbi);
823  if (r < 0) {
824  plane->info = old_info;
825  goto out;
826  }
827  }
828  r = fbdev->ctrl->enable_plane(plane->idx, pi->enabled);
829  if (r < 0) {
830  plane->info = old_info;
831  goto out;
832  }
833 out:
834  omapfb_rqueue_unlock(fbdev);
835  return r;
836 }
837 
838 static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
839 {
840  struct omapfb_plane_struct *plane = fbi->par;
841 
842  *pi = plane->info;
843  return 0;
844 }
845 
846 static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
847 {
848  struct omapfb_plane_struct *plane = fbi->par;
849  struct omapfb_device *fbdev = plane->fbdev;
850  struct omapfb_mem_region *rg = &fbdev->mem_desc.region[plane->idx];
851  size_t size;
852  int r = 0;
853 
854  if (fbdev->ctrl->setup_mem == NULL)
855  return -ENODEV;
856  if (mi->type != OMAPFB_MEMTYPE_SDRAM)
857  return -EINVAL;
858 
859  size = PAGE_ALIGN(mi->size);
860  omapfb_rqueue_lock(fbdev);
861  if (plane->info.enabled) {
862  r = -EBUSY;
863  goto out;
864  }
865  if (rg->size != size || rg->type != mi->type) {
866  struct fb_var_screeninfo *new_var = &fbdev->new_var;
867  unsigned long old_size = rg->size;
868  u8 old_type = rg->type;
869  unsigned long paddr;
870 
871  rg->size = size;
872  rg->type = mi->type;
873  /*
874  * size == 0 is a special case, for which we
875  * don't check / adjust the screen parameters.
876  * This isn't a problem since the plane can't
877  * be reenabled unless its size is > 0.
878  */
879  if (old_size != size && size) {
880  if (size) {
881  memcpy(new_var, &fbi->var, sizeof(*new_var));
882  r = set_fb_var(fbi, new_var);
883  if (r < 0)
884  goto out;
885  }
886  }
887 
888  if (fbdev->ctrl->sync)
889  fbdev->ctrl->sync();
890  r = fbdev->ctrl->setup_mem(plane->idx, size, mi->type, &paddr);
891  if (r < 0) {
892  /* Revert changes. */
893  rg->size = old_size;
894  rg->type = old_type;
895  goto out;
896  }
897  rg->paddr = paddr;
898 
899  if (old_size != size) {
900  if (size) {
901  memcpy(&fbi->var, new_var, sizeof(fbi->var));
902  set_fb_fix(fbi, 0);
903  } else {
904  /*
905  * Set these explicitly to indicate that the
906  * plane memory is dealloce'd, the other
907  * screen parameters in var / fix are invalid.
908  */
909  mutex_lock(&fbi->mm_lock);
910  fbi->fix.smem_start = 0;
911  fbi->fix.smem_len = 0;
912  mutex_unlock(&fbi->mm_lock);
913  }
914  }
915  }
916 out:
917  omapfb_rqueue_unlock(fbdev);
918 
919  return r;
920 }
921 
922 static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
923 {
924  struct omapfb_plane_struct *plane = fbi->par;
925  struct omapfb_device *fbdev = plane->fbdev;
926  struct omapfb_mem_region *rg;
927 
928  rg = &fbdev->mem_desc.region[plane->idx];
929  memset(mi, 0, sizeof(*mi));
930  mi->size = rg->size;
931  mi->type = rg->type;
932 
933  return 0;
934 }
935 
936 static int omapfb_set_color_key(struct omapfb_device *fbdev,
937  struct omapfb_color_key *ck)
938 {
939  int r;
940 
941  if (!fbdev->ctrl->set_color_key)
942  return -ENODEV;
943 
944  omapfb_rqueue_lock(fbdev);
945  r = fbdev->ctrl->set_color_key(ck);
946  omapfb_rqueue_unlock(fbdev);
947 
948  return r;
949 }
950 
951 static int omapfb_get_color_key(struct omapfb_device *fbdev,
952  struct omapfb_color_key *ck)
953 {
954  int r;
955 
956  if (!fbdev->ctrl->get_color_key)
957  return -ENODEV;
958 
959  omapfb_rqueue_lock(fbdev);
960  r = fbdev->ctrl->get_color_key(ck);
961  omapfb_rqueue_unlock(fbdev);
962 
963  return r;
964 }
965 
966 static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM];
967 static int notifier_inited;
968 
969 static void omapfb_init_notifier(void)
970 {
971  int i;
972 
973  for (i = 0; i < OMAPFB_PLANE_NUM; i++)
974  BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]);
975 }
976 
979  void *callback_data)
980 {
981  int r;
982 
983  if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM)
984  return -EINVAL;
985 
986  if (!notifier_inited) {
987  omapfb_init_notifier();
988  notifier_inited = 1;
989  }
990 
991  omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *,
992  unsigned long, void *))callback;
993  omapfb_nb->data = callback_data;
995  &omapfb_client_list[omapfb_nb->plane_idx],
996  &omapfb_nb->nb);
997  if (r)
998  return r;
999  if (omapfb_dev != NULL &&
1000  omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) {
1001  omapfb_dev->ctrl->bind_client(omapfb_nb);
1002  }
1003 
1004  return 0;
1005 }
1007 
1009 {
1011  &omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb);
1012 }
1014 
1015 void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event)
1016 {
1017  int i;
1018 
1019  if (!notifier_inited)
1020  /* no client registered yet */
1021  return;
1022 
1023  for (i = 0; i < OMAPFB_PLANE_NUM; i++)
1024  blocking_notifier_call_chain(&omapfb_client_list[i], event,
1025  fbdev->fb_info[i]);
1026 }
1028 
1029 static int omapfb_set_update_mode(struct omapfb_device *fbdev,
1030  enum omapfb_update_mode mode)
1031 {
1032  int r;
1033 
1034  omapfb_rqueue_lock(fbdev);
1035  r = fbdev->ctrl->set_update_mode(mode);
1036  omapfb_rqueue_unlock(fbdev);
1037 
1038  return r;
1039 }
1040 
1041 static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev)
1042 {
1043  int r;
1044 
1045  omapfb_rqueue_lock(fbdev);
1046  r = fbdev->ctrl->get_update_mode();
1047  omapfb_rqueue_unlock(fbdev);
1048 
1049  return r;
1050 }
1051 
1052 static void omapfb_get_caps(struct omapfb_device *fbdev, int plane,
1053  struct omapfb_caps *caps)
1054 {
1055  memset(caps, 0, sizeof(*caps));
1056  fbdev->ctrl->get_caps(plane, caps);
1057  caps->ctrl |= fbdev->panel->get_caps(fbdev->panel);
1058 }
1059 
1060 /* For lcd testing */
1061 void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
1062 {
1063  omapfb_rqueue_lock(fbdev);
1064  *(u16 *)fbdev->mem_desc.region[0].vaddr = pixval;
1065  if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) {
1066  struct omapfb_update_window win;
1067 
1068  memset(&win, 0, sizeof(win));
1069  win.width = 2;
1070  win.height = 2;
1071  win.out_width = 2;
1072  win.out_height = 2;
1073  fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, NULL);
1074  }
1075  omapfb_rqueue_unlock(fbdev);
1076 }
1078 
1079 /*
1080  * Ioctl interface. Part of the kernel mode frame buffer API is duplicated
1081  * here to be accessible by user mode code.
1082  */
1083 static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
1084  unsigned long arg)
1085 {
1086  struct omapfb_plane_struct *plane = fbi->par;
1087  struct omapfb_device *fbdev = plane->fbdev;
1088  struct fb_ops *ops = fbi->fbops;
1089  union {
1090  struct omapfb_update_window update_window;
1091  struct omapfb_plane_info plane_info;
1092  struct omapfb_mem_info mem_info;
1093  struct omapfb_color_key color_key;
1095  struct omapfb_caps caps;
1096  unsigned int mirror;
1097  int plane_out;
1098  int enable_plane;
1099  } p;
1100  int r = 0;
1101 
1102  BUG_ON(!ops);
1103  switch (cmd) {
1104  case OMAPFB_MIRROR:
1105  if (get_user(p.mirror, (int __user *)arg))
1106  r = -EFAULT;
1107  else
1108  omapfb_mirror(fbi, p.mirror);
1109  break;
1110  case OMAPFB_SYNC_GFX:
1111  omapfb_sync(fbi);
1112  break;
1113  case OMAPFB_VSYNC:
1114  break;
1116  if (get_user(p.update_mode, (int __user *)arg))
1117  r = -EFAULT;
1118  else
1119  r = omapfb_set_update_mode(fbdev, p.update_mode);
1120  break;
1122  p.update_mode = omapfb_get_update_mode(fbdev);
1123  if (put_user(p.update_mode,
1124  (enum omapfb_update_mode __user *)arg))
1125  r = -EFAULT;
1126  break;
1128  if (copy_from_user(&p.update_window, (void __user *)arg,
1129  sizeof(struct omapfb_update_window_old)))
1130  r = -EFAULT;
1131  else {
1132  struct omapfb_update_window *u = &p.update_window;
1133  u->out_x = u->x;
1134  u->out_y = u->y;
1135  u->out_width = u->width;
1136  u->out_height = u->height;
1137  memset(u->reserved, 0, sizeof(u->reserved));
1138  r = omapfb_update_win(fbi, u);
1139  }
1140  break;
1141  case OMAPFB_UPDATE_WINDOW:
1142  if (copy_from_user(&p.update_window, (void __user *)arg,
1143  sizeof(p.update_window)))
1144  r = -EFAULT;
1145  else
1146  r = omapfb_update_win(fbi, &p.update_window);
1147  break;
1148  case OMAPFB_SETUP_PLANE:
1149  if (copy_from_user(&p.plane_info, (void __user *)arg,
1150  sizeof(p.plane_info)))
1151  r = -EFAULT;
1152  else
1153  r = omapfb_setup_plane(fbi, &p.plane_info);
1154  break;
1155  case OMAPFB_QUERY_PLANE:
1156  if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0)
1157  break;
1158  if (copy_to_user((void __user *)arg, &p.plane_info,
1159  sizeof(p.plane_info)))
1160  r = -EFAULT;
1161  break;
1162  case OMAPFB_SETUP_MEM:
1163  if (copy_from_user(&p.mem_info, (void __user *)arg,
1164  sizeof(p.mem_info)))
1165  r = -EFAULT;
1166  else
1167  r = omapfb_setup_mem(fbi, &p.mem_info);
1168  break;
1169  case OMAPFB_QUERY_MEM:
1170  if ((r = omapfb_query_mem(fbi, &p.mem_info)) < 0)
1171  break;
1172  if (copy_to_user((void __user *)arg, &p.mem_info,
1173  sizeof(p.mem_info)))
1174  r = -EFAULT;
1175  break;
1176  case OMAPFB_SET_COLOR_KEY:
1177  if (copy_from_user(&p.color_key, (void __user *)arg,
1178  sizeof(p.color_key)))
1179  r = -EFAULT;
1180  else
1181  r = omapfb_set_color_key(fbdev, &p.color_key);
1182  break;
1183  case OMAPFB_GET_COLOR_KEY:
1184  if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0)
1185  break;
1186  if (copy_to_user((void __user *)arg, &p.color_key,
1187  sizeof(p.color_key)))
1188  r = -EFAULT;
1189  break;
1190  case OMAPFB_GET_CAPS:
1191  omapfb_get_caps(fbdev, plane->idx, &p.caps);
1192  if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
1193  r = -EFAULT;
1194  break;
1195  case OMAPFB_LCD_TEST:
1196  {
1197  int test_num;
1198 
1199  if (get_user(test_num, (int __user *)arg)) {
1200  r = -EFAULT;
1201  break;
1202  }
1203  if (!fbdev->panel->run_test) {
1204  r = -EINVAL;
1205  break;
1206  }
1207  r = fbdev->panel->run_test(fbdev->panel, test_num);
1208  break;
1209  }
1210  case OMAPFB_CTRL_TEST:
1211  {
1212  int test_num;
1213 
1214  if (get_user(test_num, (int __user *)arg)) {
1215  r = -EFAULT;
1216  break;
1217  }
1218  if (!fbdev->ctrl->run_test) {
1219  r = -EINVAL;
1220  break;
1221  }
1222  r = fbdev->ctrl->run_test(test_num);
1223  break;
1224  }
1225  default:
1226  r = -EINVAL;
1227  }
1228 
1229  return r;
1230 }
1231 
1232 static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
1233 {
1234  struct omapfb_plane_struct *plane = info->par;
1235  struct omapfb_device *fbdev = plane->fbdev;
1236  int r;
1237 
1238  omapfb_rqueue_lock(fbdev);
1239  r = fbdev->ctrl->mmap(info, vma);
1240  omapfb_rqueue_unlock(fbdev);
1241 
1242  return r;
1243 }
1244 
1245 /*
1246  * Callback table for the frame buffer framework. Some of these pointers
1247  * will be changed according to the current setting of fb_info->accel_flags.
1248  */
1249 static struct fb_ops omapfb_ops = {
1250  .owner = THIS_MODULE,
1251  .fb_open = omapfb_open,
1252  .fb_release = omapfb_release,
1253  .fb_setcolreg = omapfb_setcolreg,
1254  .fb_setcmap = omapfb_setcmap,
1255  .fb_fillrect = cfb_fillrect,
1256  .fb_copyarea = cfb_copyarea,
1257  .fb_imageblit = cfb_imageblit,
1258  .fb_blank = omapfb_blank,
1259  .fb_ioctl = omapfb_ioctl,
1260  .fb_check_var = omapfb_check_var,
1261  .fb_set_par = omapfb_set_par,
1262  .fb_rotate = omapfb_rotate,
1263  .fb_pan_display = omapfb_pan_display,
1264 };
1265 
1266 /*
1267  * ---------------------------------------------------------------------------
1268  * Sysfs interface
1269  * ---------------------------------------------------------------------------
1270  */
1271 /* omapfbX sysfs entries */
1272 static ssize_t omapfb_show_caps_num(struct device *dev,
1273  struct device_attribute *attr, char *buf)
1274 {
1275  struct omapfb_device *fbdev = dev_get_drvdata(dev);
1276  int plane;
1277  size_t size;
1278  struct omapfb_caps caps;
1279 
1280  plane = 0;
1281  size = 0;
1282  while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) {
1283  omapfb_get_caps(fbdev, plane, &caps);
1284  size += snprintf(&buf[size], PAGE_SIZE - size,
1285  "plane#%d %#010x %#010x %#010x\n",
1286  plane, caps.ctrl, caps.plane_color, caps.wnd_color);
1287  plane++;
1288  }
1289  return size;
1290 }
1291 
1292 static ssize_t omapfb_show_caps_text(struct device *dev,
1293  struct device_attribute *attr, char *buf)
1294 {
1295  struct omapfb_device *fbdev = dev_get_drvdata(dev);
1296  int i;
1297  struct omapfb_caps caps;
1298  int plane;
1299  size_t size;
1300 
1301  plane = 0;
1302  size = 0;
1303  while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) {
1304  omapfb_get_caps(fbdev, plane, &caps);
1305  size += snprintf(&buf[size], PAGE_SIZE - size,
1306  "plane#%d:\n", plane);
1307  for (i = 0; i < ARRAY_SIZE(ctrl_caps) &&
1308  size < PAGE_SIZE; i++) {
1309  if (ctrl_caps[i].flag & caps.ctrl)
1310  size += snprintf(&buf[size], PAGE_SIZE - size,
1311  " %s\n", ctrl_caps[i].name);
1312  }
1313  size += snprintf(&buf[size], PAGE_SIZE - size,
1314  " plane colors:\n");
1315  for (i = 0; i < ARRAY_SIZE(color_caps) &&
1316  size < PAGE_SIZE; i++) {
1317  if (color_caps[i].flag & caps.plane_color)
1318  size += snprintf(&buf[size], PAGE_SIZE - size,
1319  " %s\n", color_caps[i].name);
1320  }
1321  size += snprintf(&buf[size], PAGE_SIZE - size,
1322  " window colors:\n");
1323  for (i = 0; i < ARRAY_SIZE(color_caps) &&
1324  size < PAGE_SIZE; i++) {
1325  if (color_caps[i].flag & caps.wnd_color)
1326  size += snprintf(&buf[size], PAGE_SIZE - size,
1327  " %s\n", color_caps[i].name);
1328  }
1329 
1330  plane++;
1331  }
1332  return size;
1333 }
1334 
1335 static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL);
1336 static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
1337 
1338 /* panel sysfs entries */
1339 static ssize_t omapfb_show_panel_name(struct device *dev,
1340  struct device_attribute *attr, char *buf)
1341 {
1342  struct omapfb_device *fbdev = dev_get_drvdata(dev);
1343 
1344  return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name);
1345 }
1346 
1347 static ssize_t omapfb_show_bklight_level(struct device *dev,
1348  struct device_attribute *attr,
1349  char *buf)
1350 {
1351  struct omapfb_device *fbdev = dev_get_drvdata(dev);
1352  int r;
1353 
1354  if (fbdev->panel->get_bklight_level) {
1355  r = snprintf(buf, PAGE_SIZE, "%d\n",
1356  fbdev->panel->get_bklight_level(fbdev->panel));
1357  } else
1358  r = -ENODEV;
1359  return r;
1360 }
1361 
1362 static ssize_t omapfb_store_bklight_level(struct device *dev,
1363  struct device_attribute *attr,
1364  const char *buf, size_t size)
1365 {
1366  struct omapfb_device *fbdev = dev_get_drvdata(dev);
1367  int r;
1368 
1369  if (fbdev->panel->set_bklight_level) {
1370  unsigned int level;
1371 
1372  if (sscanf(buf, "%10d", &level) == 1) {
1373  r = fbdev->panel->set_bklight_level(fbdev->panel,
1374  level);
1375  } else
1376  r = -EINVAL;
1377  } else
1378  r = -ENODEV;
1379  return r ? r : size;
1380 }
1381 
1382 static ssize_t omapfb_show_bklight_max(struct device *dev,
1383  struct device_attribute *attr, char *buf)
1384 {
1385  struct omapfb_device *fbdev = dev_get_drvdata(dev);
1386  int r;
1387 
1388  if (fbdev->panel->get_bklight_level) {
1389  r = snprintf(buf, PAGE_SIZE, "%d\n",
1390  fbdev->panel->get_bklight_max(fbdev->panel));
1391  } else
1392  r = -ENODEV;
1393  return r;
1394 }
1395 
1396 static struct device_attribute dev_attr_panel_name =
1397  __ATTR(name, 0444, omapfb_show_panel_name, NULL);
1398 static DEVICE_ATTR(backlight_level, 0664,
1399  omapfb_show_bklight_level, omapfb_store_bklight_level);
1400 static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL);
1401 
1402 static struct attribute *panel_attrs[] = {
1403  &dev_attr_panel_name.attr,
1404  &dev_attr_backlight_level.attr,
1405  &dev_attr_backlight_max.attr,
1406  NULL,
1407 };
1408 
1409 static struct attribute_group panel_attr_grp = {
1410  .name = "panel",
1411  .attrs = panel_attrs,
1412 };
1413 
1414 /* ctrl sysfs entries */
1415 static ssize_t omapfb_show_ctrl_name(struct device *dev,
1416  struct device_attribute *attr, char *buf)
1417 {
1418  struct omapfb_device *fbdev = dev_get_drvdata(dev);
1419 
1420  return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name);
1421 }
1422 
1423 static struct device_attribute dev_attr_ctrl_name =
1424  __ATTR(name, 0444, omapfb_show_ctrl_name, NULL);
1425 
1426 static struct attribute *ctrl_attrs[] = {
1427  &dev_attr_ctrl_name.attr,
1428  NULL,
1429 };
1430 
1431 static struct attribute_group ctrl_attr_grp = {
1432  .name = "ctrl",
1433  .attrs = ctrl_attrs,
1434 };
1435 
1436 static int omapfb_register_sysfs(struct omapfb_device *fbdev)
1437 {
1438  int r;
1439 
1440  if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num)))
1441  goto fail0;
1442 
1443  if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text)))
1444  goto fail1;
1445 
1446  if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp)))
1447  goto fail2;
1448 
1449  if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp)))
1450  goto fail3;
1451 
1452  return 0;
1453 fail3:
1454  sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1455 fail2:
1456  device_remove_file(fbdev->dev, &dev_attr_caps_text);
1457 fail1:
1458  device_remove_file(fbdev->dev, &dev_attr_caps_num);
1459 fail0:
1460  dev_err(fbdev->dev, "unable to register sysfs interface\n");
1461  return r;
1462 }
1463 
1464 static void omapfb_unregister_sysfs(struct omapfb_device *fbdev)
1465 {
1466  sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp);
1467  sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1468  device_remove_file(fbdev->dev, &dev_attr_caps_num);
1469  device_remove_file(fbdev->dev, &dev_attr_caps_text);
1470 }
1471 
1472 /*
1473  * ---------------------------------------------------------------------------
1474  * LDM callbacks
1475  * ---------------------------------------------------------------------------
1476  */
1477 /* Initialize system fb_info object and set the default video mode.
1478  * The frame buffer memory already allocated by lcddma_init
1479  */
1480 static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info)
1481 {
1482  struct fb_var_screeninfo *var = &info->var;
1483  struct fb_fix_screeninfo *fix = &info->fix;
1484  int r = 0;
1485 
1486  info->fbops = &omapfb_ops;
1487  info->flags = FBINFO_FLAG_DEFAULT;
1488 
1489  strncpy(fix->id, MODULE_NAME, sizeof(fix->id));
1490 
1491  info->pseudo_palette = fbdev->pseudo_palette;
1492 
1493  var->accel_flags = def_accel ? FB_ACCELF_TEXT : 0;
1494  var->xres = def_vxres;
1495  var->yres = def_vyres;
1496  var->xres_virtual = def_vxres;
1497  var->yres_virtual = def_vyres;
1498  var->rotate = def_rotate;
1499  var->bits_per_pixel = fbdev->panel->bpp;
1500 
1501  set_fb_var(info, var);
1502  set_fb_fix(info, 1);
1503 
1504  r = fb_alloc_cmap(&info->cmap, 16, 0);
1505  if (r != 0)
1506  dev_err(fbdev->dev, "unable to allocate color map memory\n");
1507 
1508  return r;
1509 }
1510 
1511 /* Release the fb_info object */
1512 static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi)
1513 {
1514  fb_dealloc_cmap(&fbi->cmap);
1515 }
1516 
1517 static void planes_cleanup(struct omapfb_device *fbdev)
1518 {
1519  int i;
1520 
1521  for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
1522  if (fbdev->fb_info[i] == NULL)
1523  break;
1524  fbinfo_cleanup(fbdev, fbdev->fb_info[i]);
1525  framebuffer_release(fbdev->fb_info[i]);
1526  }
1527 }
1528 
1529 static int planes_init(struct omapfb_device *fbdev)
1530 {
1531  struct fb_info *fbi;
1532  int i;
1533  int r;
1534 
1535  for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
1536  struct omapfb_plane_struct *plane;
1537  fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct),
1538  fbdev->dev);
1539  if (fbi == NULL) {
1540  dev_err(fbdev->dev,
1541  "unable to allocate memory for plane info\n");
1542  planes_cleanup(fbdev);
1543  return -ENOMEM;
1544  }
1545  plane = fbi->par;
1546  plane->idx = i;
1547  plane->fbdev = fbdev;
1548  plane->info.mirror = def_mirror;
1549  fbdev->fb_info[i] = fbi;
1550 
1551  if ((r = fbinfo_init(fbdev, fbi)) < 0) {
1552  framebuffer_release(fbi);
1553  planes_cleanup(fbdev);
1554  return r;
1555  }
1556  plane->info.out_width = fbi->var.xres;
1557  plane->info.out_height = fbi->var.yres;
1558  }
1559  return 0;
1560 }
1561 
1562 /*
1563  * Free driver resources. Can be called to rollback an aborted initialization
1564  * sequence.
1565  */
1566 static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
1567 {
1568  int i;
1569 
1570  switch (state) {
1571  case OMAPFB_ACTIVE:
1572  for (i = 0; i < fbdev->mem_desc.region_cnt; i++)
1573  unregister_framebuffer(fbdev->fb_info[i]);
1574  case 7:
1575  omapfb_unregister_sysfs(fbdev);
1576  case 6:
1577  fbdev->panel->disable(fbdev->panel);
1578  case 5:
1579  omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
1580  case 4:
1581  planes_cleanup(fbdev);
1582  case 3:
1583  ctrl_cleanup(fbdev);
1584  case 2:
1585  fbdev->panel->cleanup(fbdev->panel);
1586  case 1:
1587  dev_set_drvdata(fbdev->dev, NULL);
1588  kfree(fbdev);
1589  case 0:
1590  /* nothing to free */
1591  break;
1592  default:
1593  BUG();
1594  }
1595 }
1596 
1597 static int omapfb_find_ctrl(struct omapfb_device *fbdev)
1598 {
1599  struct omapfb_platform_data *conf;
1600  char name[17];
1601  int i;
1602 
1603  conf = fbdev->dev->platform_data;
1604 
1605  fbdev->ctrl = NULL;
1606 
1607  strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1);
1608  name[sizeof(name) - 1] = '\0';
1609 
1610  if (strcmp(name, "internal") == 0) {
1611  fbdev->ctrl = fbdev->int_ctrl;
1612  return 0;
1613  }
1614 
1615  for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
1616  dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name);
1617  if (strcmp(ctrls[i]->name, name) == 0) {
1618  fbdev->ctrl = ctrls[i];
1619  break;
1620  }
1621  }
1622 
1623  if (fbdev->ctrl == NULL) {
1624  dev_dbg(fbdev->dev, "ctrl %s not supported\n", name);
1625  return -1;
1626  }
1627 
1628  return 0;
1629 }
1630 
1631 static void check_required_callbacks(struct omapfb_device *fbdev)
1632 {
1633 #define _C(x) (fbdev->ctrl->x != NULL)
1634 #define _P(x) (fbdev->panel->x != NULL)
1635  BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL);
1636  BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) &&
1637  _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) &&
1638  _P(init) && _P(cleanup) && _P(enable) && _P(disable) &&
1639  _P(get_caps)));
1640 #undef _P
1641 #undef _C
1642 }
1643 
1644 /*
1645  * Called by LDM binding to probe and attach a new device.
1646  * Initialization sequence:
1647  * 1. allocate system omapfb_device structure
1648  * 2. select controller type according to platform configuration
1649  * init LCD panel
1650  * 3. init LCD controller and LCD DMA
1651  * 4. init system fb_info structure for all planes
1652  * 5. setup video mode for first plane and enable it
1653  * 6. enable LCD panel
1654  * 7. register sysfs attributes
1655  * OMAPFB_ACTIVE: register system fb_info structure for all planes
1656  */
1657 static int omapfb_do_probe(struct platform_device *pdev,
1658  struct lcd_panel *panel)
1659 {
1660  struct omapfb_device *fbdev = NULL;
1661  int init_state;
1662  unsigned long phz, hhz, vhz;
1663  unsigned long vram;
1664  int i;
1665  int r = 0;
1666 
1667  init_state = 0;
1668 
1669  if (pdev->num_resources != 0) {
1670  dev_err(&pdev->dev, "probed for an unknown device\n");
1671  r = -ENODEV;
1672  goto cleanup;
1673  }
1674 
1675  if (pdev->dev.platform_data == NULL) {
1676  dev_err(&pdev->dev, "missing platform data\n");
1677  r = -ENOENT;
1678  goto cleanup;
1679  }
1680 
1681  fbdev = kzalloc(sizeof(struct omapfb_device), GFP_KERNEL);
1682  if (fbdev == NULL) {
1683  dev_err(&pdev->dev,
1684  "unable to allocate memory for device info\n");
1685  r = -ENOMEM;
1686  goto cleanup;
1687  }
1688  init_state++;
1689 
1690  fbdev->dev = &pdev->dev;
1691  fbdev->panel = panel;
1692  fbdev->dssdev = &omapdss_device;
1693  platform_set_drvdata(pdev, fbdev);
1694 
1695  mutex_init(&fbdev->rqueue_mutex);
1696 
1697  fbdev->int_ctrl = &omap1_int_ctrl;
1698 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1699  fbdev->ext_if = &omap1_ext_if;
1700 #endif
1701  if (omapfb_find_ctrl(fbdev) < 0) {
1702  dev_err(fbdev->dev,
1703  "LCD controller not found, board not supported\n");
1704  r = -ENODEV;
1705  goto cleanup;
1706  }
1707 
1708  r = fbdev->panel->init(fbdev->panel, fbdev);
1709  if (r)
1710  goto cleanup;
1711 
1712  pr_info("omapfb: configured for panel %s\n", fbdev->panel->name);
1713 
1714  def_vxres = def_vxres ? def_vxres : fbdev->panel->x_res;
1715  def_vyres = def_vyres ? def_vyres : fbdev->panel->y_res;
1716 
1717  init_state++;
1718 
1719  r = ctrl_init(fbdev);
1720  if (r)
1721  goto cleanup;
1722  if (fbdev->ctrl->mmap != NULL)
1723  omapfb_ops.fb_mmap = omapfb_mmap;
1724  init_state++;
1725 
1726  check_required_callbacks(fbdev);
1727 
1728  r = planes_init(fbdev);
1729  if (r)
1730  goto cleanup;
1731  init_state++;
1732 
1733 #ifdef CONFIG_FB_OMAP_DMA_TUNE
1734  /* Set DMA priority for EMIFF access to highest */
1736 #endif
1737 
1738  r = ctrl_change_mode(fbdev->fb_info[0]);
1739  if (r) {
1740  dev_err(fbdev->dev, "mode setting failed\n");
1741  goto cleanup;
1742  }
1743 
1744  /* GFX plane is enabled by default */
1745  r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);
1746  if (r)
1747  goto cleanup;
1748 
1749  omapfb_set_update_mode(fbdev, manual_update ?
1751  init_state++;
1752 
1753  r = fbdev->panel->enable(fbdev->panel);
1754  if (r)
1755  goto cleanup;
1756  init_state++;
1757 
1758  r = omapfb_register_sysfs(fbdev);
1759  if (r)
1760  goto cleanup;
1761  init_state++;
1762 
1763  vram = 0;
1764  for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
1765  r = register_framebuffer(fbdev->fb_info[i]);
1766  if (r != 0) {
1767  dev_err(fbdev->dev,
1768  "registering framebuffer %d failed\n", i);
1769  goto cleanup;
1770  }
1771  vram += fbdev->mem_desc.region[i].size;
1772  }
1773 
1774  fbdev->state = OMAPFB_ACTIVE;
1775 
1776  panel = fbdev->panel;
1777  phz = panel->pixel_clock * 1000;
1778  hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw);
1779  vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw);
1780 
1781  omapfb_dev = fbdev;
1782 
1783  pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n",
1784  vram, fbdev->mem_desc.region_cnt);
1785  pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz "
1786  "vfreq %lu.%lu Hz\n",
1787  phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10);
1788 
1789  return 0;
1790 
1791 cleanup:
1792  omapfb_free_resources(fbdev, init_state);
1793 
1794  return r;
1795 }
1796 
1797 static int omapfb_probe(struct platform_device *pdev)
1798 {
1799  int r;
1800 
1801  BUG_ON(fbdev_pdev != NULL);
1802 
1803  r = platform_device_register(&omapdss_device);
1804  if (r) {
1805  dev_err(&pdev->dev, "can't register omapdss device\n");
1806  return r;
1807  }
1808 
1809  /* Delay actual initialization until the LCD is registered */
1810  fbdev_pdev = pdev;
1811  if (fbdev_panel != NULL)
1812  omapfb_do_probe(fbdev_pdev, fbdev_panel);
1813  return 0;
1814 }
1815 
1817 {
1818  BUG_ON(fbdev_panel != NULL);
1819 
1820  fbdev_panel = panel;
1821  if (fbdev_pdev != NULL)
1822  omapfb_do_probe(fbdev_pdev, fbdev_panel);
1823 }
1824 
1825 /* Called when the device is being detached from the driver */
1826 static int omapfb_remove(struct platform_device *pdev)
1827 {
1828  struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1829  enum omapfb_state saved_state = fbdev->state;
1830 
1831  /* FIXME: wait till completion of pending events */
1832 
1833  fbdev->state = OMAPFB_DISABLED;
1834  omapfb_free_resources(fbdev, saved_state);
1835 
1836  platform_device_unregister(&omapdss_device);
1837  fbdev->dssdev = NULL;
1838 
1839  return 0;
1840 }
1841 
1842 /* PM suspend */
1843 static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg)
1844 {
1845  struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1846 
1847  if (fbdev != NULL)
1848  omapfb_blank(FB_BLANK_POWERDOWN, fbdev->fb_info[0]);
1849  return 0;
1850 }
1851 
1852 /* PM resume */
1853 static int omapfb_resume(struct platform_device *pdev)
1854 {
1855  struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1856 
1857  if (fbdev != NULL)
1858  omapfb_blank(FB_BLANK_UNBLANK, fbdev->fb_info[0]);
1859  return 0;
1860 }
1861 
1862 static struct platform_driver omapfb_driver = {
1863  .probe = omapfb_probe,
1864  .remove = omapfb_remove,
1865  .suspend = omapfb_suspend,
1866  .resume = omapfb_resume,
1867  .driver = {
1868  .name = MODULE_NAME,
1869  .owner = THIS_MODULE,
1870  },
1871 };
1872 
1873 #ifndef MODULE
1874 
1875 /* Process kernel command line parameters */
1876 static int __init omapfb_setup(char *options)
1877 {
1878  char *this_opt = NULL;
1879  int r = 0;
1880 
1881  pr_debug("omapfb: options %s\n", options);
1882 
1883  if (!options || !*options)
1884  return 0;
1885 
1886  while (!r && (this_opt = strsep(&options, ",")) != NULL) {
1887  if (!strncmp(this_opt, "accel", 5))
1888  def_accel = 1;
1889  else if (!strncmp(this_opt, "vram:", 5)) {
1890  char *suffix;
1891  unsigned long vram;
1892  vram = (simple_strtoul(this_opt + 5, &suffix, 0));
1893  switch (suffix[0]) {
1894  case '\0':
1895  break;
1896  case 'm':
1897  case 'M':
1898  vram *= 1024;
1899  /* Fall through */
1900  case 'k':
1901  case 'K':
1902  vram *= 1024;
1903  break;
1904  default:
1905  pr_debug("omapfb: invalid vram suffix %c\n",
1906  suffix[0]);
1907  r = -1;
1908  }
1909  def_vram[def_vram_cnt++] = vram;
1910  }
1911  else if (!strncmp(this_opt, "vxres:", 6))
1912  def_vxres = simple_strtoul(this_opt + 6, NULL, 0);
1913  else if (!strncmp(this_opt, "vyres:", 6))
1914  def_vyres = simple_strtoul(this_opt + 6, NULL, 0);
1915  else if (!strncmp(this_opt, "rotate:", 7))
1916  def_rotate = (simple_strtoul(this_opt + 7, NULL, 0));
1917  else if (!strncmp(this_opt, "mirror:", 7))
1918  def_mirror = (simple_strtoul(this_opt + 7, NULL, 0));
1919  else if (!strncmp(this_opt, "manual_update", 13))
1920  manual_update = 1;
1921  else {
1922  pr_debug("omapfb: invalid option\n");
1923  r = -1;
1924  }
1925  }
1926 
1927  return r;
1928 }
1929 
1930 #endif
1931 
1932 /* Register both the driver and the device */
1933 static int __init omapfb_init(void)
1934 {
1935 #ifndef MODULE
1936  char *option;
1937 
1938  if (fb_get_options("omapfb", &option))
1939  return -ENODEV;
1940  omapfb_setup(option);
1941 #endif
1942  /* Register the driver with LDM */
1943  if (platform_driver_register(&omapfb_driver)) {
1944  pr_debug("failed to register omapfb driver\n");
1945  return -ENODEV;
1946  }
1947 
1948  return 0;
1949 }
1950 
1951 static void __exit omapfb_cleanup(void)
1952 {
1953  platform_driver_unregister(&omapfb_driver);
1954 }
1955 
1956 module_param_named(accel, def_accel, uint, 0664);
1957 module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664);
1958 module_param_named(vxres, def_vxres, long, 0664);
1959 module_param_named(vyres, def_vyres, long, 0664);
1960 module_param_named(rotate, def_rotate, uint, 0664);
1961 module_param_named(mirror, def_mirror, uint, 0664);
1962 module_param_named(manual_update, manual_update, bool, 0664);
1963 
1964 module_init(omapfb_init);
1965 module_exit(omapfb_cleanup);
1966 
1967 MODULE_DESCRIPTION("TI OMAP framebuffer driver");
1968 MODULE_AUTHOR("Imre Deak <[email protected]>");
1969 MODULE_LICENSE("GPL");