Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
drm_fb_helper.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2006-2009 Red Hat Inc.
3  * Copyright (c) 2006-2008 Intel Corporation
4  * Copyright (c) 2007 Dave Airlie <[email protected]>
5  *
6  * DRM framebuffer helper functions
7  *
8  * Permission to use, copy, modify, distribute, and sell this software and its
9  * documentation for any purpose is hereby granted without fee, provided that
10  * the above copyright notice appear in all copies and that both that copyright
11  * notice and this permission notice appear in supporting documentation, and
12  * that the name of the copyright holders not be used in advertising or
13  * publicity pertaining to distribution of the software without specific,
14  * written prior permission. The copyright holders make no representations
15  * about the suitability of this software for any purpose. It is provided "as
16  * is" without express or implied warranty.
17  *
18  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
20  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
21  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
23  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24  * OF THIS SOFTWARE.
25  *
26  * Authors:
27  * Dave Airlie <[email protected]>
28  * Jesse Barnes <[email protected]>
29  */
30 #include <linux/kernel.h>
31 #include <linux/sysrq.h>
32 #include <linux/slab.h>
33 #include <linux/fb.h>
34 #include <linux/module.h>
35 #include <drm/drmP.h>
36 #include <drm/drm_crtc.h>
37 #include <drm/drm_fb_helper.h>
38 #include <drm/drm_crtc_helper.h>
39 
40 MODULE_AUTHOR("David Airlie, Jesse Barnes");
41 MODULE_DESCRIPTION("DRM KMS helper");
42 MODULE_LICENSE("GPL and additional rights");
43 
44 static LIST_HEAD(kernel_fb_helper_list);
45 
46 /* simple single crtc case helper function */
48 {
49  struct drm_device *dev = fb_helper->dev;
50  struct drm_connector *connector;
51  int i;
52 
53  list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
54  struct drm_fb_helper_connector *fb_helper_connector;
55 
56  fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
57  if (!fb_helper_connector)
58  goto fail;
59 
60  fb_helper_connector->connector = connector;
61  fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
62  }
63  return 0;
64 fail:
65  for (i = 0; i < fb_helper->connector_count; i++) {
66  kfree(fb_helper->connector_info[i]);
67  fb_helper->connector_info[i] = NULL;
68  }
69  fb_helper->connector_count = 0;
70  return -ENOMEM;
71 }
73 
74 static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
75 {
76  struct drm_fb_helper_connector *fb_helper_conn;
77  int i;
78 
79  for (i = 0; i < fb_helper->connector_count; i++) {
80  struct drm_cmdline_mode *mode;
81  struct drm_connector *connector;
82  char *option = NULL;
83 
84  fb_helper_conn = fb_helper->connector_info[i];
85  connector = fb_helper_conn->connector;
86  mode = &fb_helper_conn->cmdline_mode;
87 
88  /* do something on return - turn off connector maybe */
89  if (fb_get_options(drm_get_connector_name(connector), &option))
90  continue;
91 
93  connector,
94  mode)) {
95  if (mode->force) {
96  const char *s;
97  switch (mode->force) {
98  case DRM_FORCE_OFF: s = "OFF"; break;
99  case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
100  default:
101  case DRM_FORCE_ON: s = "ON"; break;
102  }
103 
104  DRM_INFO("forcing %s connector %s\n",
105  drm_get_connector_name(connector), s);
106  connector->force = mode->force;
107  }
108 
109  DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
110  drm_get_connector_name(connector),
111  mode->xres, mode->yres,
112  mode->refresh_specified ? mode->refresh : 60,
113  mode->rb ? " reduced blanking" : "",
114  mode->margins ? " with margins" : "",
115  mode->interlace ? " interlaced" : "");
116  }
117 
118  }
119  return 0;
120 }
121 
122 static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
123 {
124  uint16_t *r_base, *g_base, *b_base;
125  int i;
126 
127  r_base = crtc->gamma_store;
128  g_base = r_base + crtc->gamma_size;
129  b_base = g_base + crtc->gamma_size;
130 
131  for (i = 0; i < crtc->gamma_size; i++)
132  helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
133 }
134 
135 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
136 {
137  uint16_t *r_base, *g_base, *b_base;
138 
139  if (crtc->funcs->gamma_set == NULL)
140  return;
141 
142  r_base = crtc->gamma_store;
143  g_base = r_base + crtc->gamma_size;
144  b_base = g_base + crtc->gamma_size;
145 
146  crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
147 }
148 
150 {
151  struct drm_fb_helper *helper = info->par;
152  struct drm_crtc_helper_funcs *funcs;
153  int i;
154 
155  if (list_empty(&kernel_fb_helper_list))
156  return false;
157 
158  list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
159  for (i = 0; i < helper->crtc_count; i++) {
160  struct drm_mode_set *mode_set =
161  &helper->crtc_info[i].mode_set;
162 
163  if (!mode_set->crtc->enabled)
164  continue;
165 
166  funcs = mode_set->crtc->helper_private;
167  drm_fb_helper_save_lut_atomic(mode_set->crtc, helper);
168  funcs->mode_set_base_atomic(mode_set->crtc,
169  mode_set->fb,
170  mode_set->x,
171  mode_set->y,
173  }
174  }
175 
176  return 0;
177 }
179 
180 /* Find the real fb for a given fb helper CRTC */
181 static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
182 {
183  struct drm_device *dev = crtc->dev;
184  struct drm_crtc *c;
185 
186  list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
187  if (crtc->base.id == c->base.id)
188  return c->fb;
189  }
190 
191  return NULL;
192 }
193 
195 {
196  struct drm_fb_helper *helper = info->par;
197  struct drm_crtc *crtc;
198  struct drm_crtc_helper_funcs *funcs;
199  struct drm_framebuffer *fb;
200  int i;
201 
202  for (i = 0; i < helper->crtc_count; i++) {
203  struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
204  crtc = mode_set->crtc;
205  funcs = crtc->helper_private;
206  fb = drm_mode_config_fb(crtc);
207 
208  if (!crtc->enabled)
209  continue;
210 
211  if (!fb) {
212  DRM_ERROR("no fb to restore??\n");
213  continue;
214  }
215 
216  drm_fb_helper_restore_lut_atomic(mode_set->crtc);
217  funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
218  crtc->y, LEAVE_ATOMIC_MODE_SET);
219  }
220 
221  return 0;
222 }
224 
226 {
227  bool error = false;
228  int i, ret;
229  for (i = 0; i < fb_helper->crtc_count; i++) {
230  struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
231  ret = mode_set->crtc->funcs->set_config(mode_set);
232  if (ret)
233  error = true;
234  }
235  return error;
236 }
238 
239 static bool drm_fb_helper_force_kernel_mode(void)
240 {
241  bool ret, error = false;
242  struct drm_fb_helper *helper;
243 
244  if (list_empty(&kernel_fb_helper_list))
245  return false;
246 
247  list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
248  if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF)
249  continue;
250 
251  ret = drm_fb_helper_restore_fbdev_mode(helper);
252  if (ret)
253  error = true;
254  }
255  return error;
256 }
257 
258 int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
259  void *panic_str)
260 {
261  /*
262  * It's a waste of time and effort to switch back to text console
263  * if the kernel should reboot before panic messages can be seen.
264  */
265  if (panic_timeout < 0)
266  return 0;
267 
268  printk(KERN_ERR "panic occurred, switching back to text console\n");
269  return drm_fb_helper_force_kernel_mode();
270 }
272 
273 static struct notifier_block paniced = {
274  .notifier_call = drm_fb_helper_panic,
275 };
276 
283 {
284  bool ret;
285  ret = drm_fb_helper_force_kernel_mode();
286  if (ret == true)
287  DRM_ERROR("Failed to restore crtc configuration\n");
288 }
290 
291 #ifdef CONFIG_MAGIC_SYSRQ
292 static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
293 {
295 }
296 static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
297 
298 static void drm_fb_helper_sysrq(int dummy1)
299 {
300  schedule_work(&drm_fb_helper_restore_work);
301 }
302 
303 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
304  .handler = drm_fb_helper_sysrq,
305  .help_msg = "force-fb(V)",
306  .action_msg = "Restore framebuffer console",
307 };
308 #else
309 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
310 #endif
311 
312 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
313 {
314  struct drm_fb_helper *fb_helper = info->par;
315  struct drm_device *dev = fb_helper->dev;
316  struct drm_crtc *crtc;
317  struct drm_connector *connector;
318  int i, j;
319 
320  /*
321  * For each CRTC in this fb, turn the connectors on/off.
322  */
323  mutex_lock(&dev->mode_config.mutex);
324  for (i = 0; i < fb_helper->crtc_count; i++) {
325  crtc = fb_helper->crtc_info[i].mode_set.crtc;
326 
327  if (!crtc->enabled)
328  continue;
329 
330  /* Walk the connectors & encoders on this fb turning them on/off */
331  for (j = 0; j < fb_helper->connector_count; j++) {
332  connector = fb_helper->connector_info[j]->connector;
333  connector->funcs->dpms(connector, dpms_mode);
335  dev->mode_config.dpms_property, dpms_mode);
336  }
337  }
338  mutex_unlock(&dev->mode_config.mutex);
339 }
340 
341 int drm_fb_helper_blank(int blank, struct fb_info *info)
342 {
343  switch (blank) {
344  /* Display: On; HSync: On, VSync: On */
345  case FB_BLANK_UNBLANK:
346  drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
347  break;
348  /* Display: Off; HSync: On, VSync: On */
349  case FB_BLANK_NORMAL:
350  drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
351  break;
352  /* Display: Off; HSync: Off, VSync: On */
354  drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
355  break;
356  /* Display: Off; HSync: On, VSync: Off */
358  drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND);
359  break;
360  /* Display: Off; HSync: Off, VSync: Off */
361  case FB_BLANK_POWERDOWN:
362  drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
363  break;
364  }
365  return 0;
366 }
368 
369 static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
370 {
371  int i;
372 
373  for (i = 0; i < helper->connector_count; i++)
374  kfree(helper->connector_info[i]);
375  kfree(helper->connector_info);
376  for (i = 0; i < helper->crtc_count; i++) {
377  kfree(helper->crtc_info[i].mode_set.connectors);
378  if (helper->crtc_info[i].mode_set.mode)
379  drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode);
380  }
381  kfree(helper->crtc_info);
382 }
383 
385  struct drm_fb_helper *fb_helper,
386  int crtc_count, int max_conn_count)
387 {
388  struct drm_crtc *crtc;
389  int i;
390 
391  fb_helper->dev = dev;
392 
393  INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
394 
395  fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
396  if (!fb_helper->crtc_info)
397  return -ENOMEM;
398 
399  fb_helper->crtc_count = crtc_count;
400  fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
401  if (!fb_helper->connector_info) {
402  kfree(fb_helper->crtc_info);
403  return -ENOMEM;
404  }
405  fb_helper->connector_count = 0;
406 
407  for (i = 0; i < crtc_count; i++) {
408  fb_helper->crtc_info[i].mode_set.connectors =
409  kcalloc(max_conn_count,
410  sizeof(struct drm_connector *),
411  GFP_KERNEL);
412 
413  if (!fb_helper->crtc_info[i].mode_set.connectors)
414  goto out_free;
415  fb_helper->crtc_info[i].mode_set.num_connectors = 0;
416  }
417 
418  i = 0;
419  list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
420  fb_helper->crtc_info[i].mode_set.crtc = crtc;
421  i++;
422  }
423 
424  return 0;
425 out_free:
426  drm_fb_helper_crtc_free(fb_helper);
427  return -ENOMEM;
428 }
430 
431 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
432 {
433  if (!list_empty(&fb_helper->kernel_fb_list)) {
434  list_del(&fb_helper->kernel_fb_list);
435  if (list_empty(&kernel_fb_helper_list)) {
436  printk(KERN_INFO "drm: unregistered panic notifier\n");
438  &paniced);
439  unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
440  }
441  }
442 
443  drm_fb_helper_crtc_free(fb_helper);
444 
445 }
447 
448 static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
449  u16 blue, u16 regno, struct fb_info *info)
450 {
451  struct drm_fb_helper *fb_helper = info->par;
452  struct drm_framebuffer *fb = fb_helper->fb;
453  int pindex;
454 
455  if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
456  u32 *palette;
457  u32 value;
458  /* place color in psuedopalette */
459  if (regno > 16)
460  return -EINVAL;
461  palette = (u32 *)info->pseudo_palette;
462  red >>= (16 - info->var.red.length);
463  green >>= (16 - info->var.green.length);
464  blue >>= (16 - info->var.blue.length);
465  value = (red << info->var.red.offset) |
466  (green << info->var.green.offset) |
467  (blue << info->var.blue.offset);
468  if (info->var.transp.length > 0) {
469  u32 mask = (1 << info->var.transp.length) - 1;
470  mask <<= info->var.transp.offset;
471  value |= mask;
472  }
473  palette[regno] = value;
474  return 0;
475  }
476 
477  pindex = regno;
478 
479  if (fb->bits_per_pixel == 16) {
480  pindex = regno << 3;
481 
482  if (fb->depth == 16 && regno > 63)
483  return -EINVAL;
484  if (fb->depth == 15 && regno > 31)
485  return -EINVAL;
486 
487  if (fb->depth == 16) {
488  u16 r, g, b;
489  int i;
490  if (regno < 32) {
491  for (i = 0; i < 8; i++)
492  fb_helper->funcs->gamma_set(crtc, red,
493  green, blue, pindex + i);
494  }
495 
496  fb_helper->funcs->gamma_get(crtc, &r,
497  &g, &b,
498  pindex >> 1);
499 
500  for (i = 0; i < 4; i++)
501  fb_helper->funcs->gamma_set(crtc, r,
502  green, b,
503  (pindex >> 1) + i);
504  }
505  }
506 
507  if (fb->depth != 16)
508  fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
509  return 0;
510 }
511 
512 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
513 {
514  struct drm_fb_helper *fb_helper = info->par;
515  struct drm_crtc_helper_funcs *crtc_funcs;
516  u16 *red, *green, *blue, *transp;
517  struct drm_crtc *crtc;
518  int i, j, rc = 0;
519  int start;
520 
521  for (i = 0; i < fb_helper->crtc_count; i++) {
522  crtc = fb_helper->crtc_info[i].mode_set.crtc;
523  crtc_funcs = crtc->helper_private;
524 
525  red = cmap->red;
526  green = cmap->green;
527  blue = cmap->blue;
528  transp = cmap->transp;
529  start = cmap->start;
530 
531  for (j = 0; j < cmap->len; j++) {
532  u16 hred, hgreen, hblue, htransp = 0xffff;
533 
534  hred = *red++;
535  hgreen = *green++;
536  hblue = *blue++;
537 
538  if (transp)
539  htransp = *transp++;
540 
541  rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
542  if (rc)
543  return rc;
544  }
545  crtc_funcs->load_lut(crtc);
546  }
547  return rc;
548 }
550 
552  struct fb_info *info)
553 {
554  struct drm_fb_helper *fb_helper = info->par;
555  struct drm_framebuffer *fb = fb_helper->fb;
556  int depth;
557 
558  if (var->pixclock != 0 || in_dbg_master())
559  return -EINVAL;
560 
561  /* Need to resize the fb object !!! */
562  if (var->bits_per_pixel > fb->bits_per_pixel ||
563  var->xres > fb->width || var->yres > fb->height ||
564  var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
565  DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb "
566  "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
567  var->xres, var->yres, var->bits_per_pixel,
568  var->xres_virtual, var->yres_virtual,
569  fb->width, fb->height, fb->bits_per_pixel);
570  return -EINVAL;
571  }
572 
573  switch (var->bits_per_pixel) {
574  case 16:
575  depth = (var->green.length == 6) ? 16 : 15;
576  break;
577  case 32:
578  depth = (var->transp.length > 0) ? 32 : 24;
579  break;
580  default:
581  depth = var->bits_per_pixel;
582  break;
583  }
584 
585  switch (depth) {
586  case 8:
587  var->red.offset = 0;
588  var->green.offset = 0;
589  var->blue.offset = 0;
590  var->red.length = 8;
591  var->green.length = 8;
592  var->blue.length = 8;
593  var->transp.length = 0;
594  var->transp.offset = 0;
595  break;
596  case 15:
597  var->red.offset = 10;
598  var->green.offset = 5;
599  var->blue.offset = 0;
600  var->red.length = 5;
601  var->green.length = 5;
602  var->blue.length = 5;
603  var->transp.length = 1;
604  var->transp.offset = 15;
605  break;
606  case 16:
607  var->red.offset = 11;
608  var->green.offset = 5;
609  var->blue.offset = 0;
610  var->red.length = 5;
611  var->green.length = 6;
612  var->blue.length = 5;
613  var->transp.length = 0;
614  var->transp.offset = 0;
615  break;
616  case 24:
617  var->red.offset = 16;
618  var->green.offset = 8;
619  var->blue.offset = 0;
620  var->red.length = 8;
621  var->green.length = 8;
622  var->blue.length = 8;
623  var->transp.length = 0;
624  var->transp.offset = 0;
625  break;
626  case 32:
627  var->red.offset = 16;
628  var->green.offset = 8;
629  var->blue.offset = 0;
630  var->red.length = 8;
631  var->green.length = 8;
632  var->blue.length = 8;
633  var->transp.length = 8;
634  var->transp.offset = 24;
635  break;
636  default:
637  return -EINVAL;
638  }
639  return 0;
640 }
642 
643 /* this will let fbcon do the mode init */
645 {
646  struct drm_fb_helper *fb_helper = info->par;
647  struct drm_device *dev = fb_helper->dev;
648  struct fb_var_screeninfo *var = &info->var;
649  struct drm_crtc *crtc;
650  int ret;
651  int i;
652 
653  if (var->pixclock != 0) {
654  DRM_ERROR("PIXEL CLOCK SET\n");
655  return -EINVAL;
656  }
657 
658  mutex_lock(&dev->mode_config.mutex);
659  for (i = 0; i < fb_helper->crtc_count; i++) {
660  crtc = fb_helper->crtc_info[i].mode_set.crtc;
661  ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
662  if (ret) {
663  mutex_unlock(&dev->mode_config.mutex);
664  return ret;
665  }
666  }
667  mutex_unlock(&dev->mode_config.mutex);
668 
669  if (fb_helper->delayed_hotplug) {
670  fb_helper->delayed_hotplug = false;
671  drm_fb_helper_hotplug_event(fb_helper);
672  }
673  return 0;
674 }
676 
678  struct fb_info *info)
679 {
680  struct drm_fb_helper *fb_helper = info->par;
681  struct drm_device *dev = fb_helper->dev;
682  struct drm_mode_set *modeset;
683  struct drm_crtc *crtc;
684  int ret = 0;
685  int i;
686 
687  mutex_lock(&dev->mode_config.mutex);
688  for (i = 0; i < fb_helper->crtc_count; i++) {
689  crtc = fb_helper->crtc_info[i].mode_set.crtc;
690 
691  modeset = &fb_helper->crtc_info[i].mode_set;
692 
693  modeset->x = var->xoffset;
694  modeset->y = var->yoffset;
695 
696  if (modeset->num_connectors) {
697  ret = crtc->funcs->set_config(modeset);
698  if (!ret) {
699  info->var.xoffset = var->xoffset;
700  info->var.yoffset = var->yoffset;
701  }
702  }
703  }
704  mutex_unlock(&dev->mode_config.mutex);
705  return ret;
706 }
708 
710  int preferred_bpp)
711 {
712  int new_fb = 0;
713  int crtc_count = 0;
714  int i;
715  struct fb_info *info;
716  struct drm_fb_helper_surface_size sizes;
717  int gamma_size = 0;
718 
719  memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
720  sizes.surface_depth = 24;
721  sizes.surface_bpp = 32;
722  sizes.fb_width = (unsigned)-1;
723  sizes.fb_height = (unsigned)-1;
724 
725  /* if driver picks 8 or 16 by default use that
726  for both depth/bpp */
727  if (preferred_bpp != sizes.surface_bpp) {
728  sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
729  }
730  /* first up get a count of crtcs now in use and new min/maxes width/heights */
731  for (i = 0; i < fb_helper->connector_count; i++) {
732  struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
733  struct drm_cmdline_mode *cmdline_mode;
734 
735  cmdline_mode = &fb_helper_conn->cmdline_mode;
736 
737  if (cmdline_mode->bpp_specified) {
738  switch (cmdline_mode->bpp) {
739  case 8:
740  sizes.surface_depth = sizes.surface_bpp = 8;
741  break;
742  case 15:
743  sizes.surface_depth = 15;
744  sizes.surface_bpp = 16;
745  break;
746  case 16:
747  sizes.surface_depth = sizes.surface_bpp = 16;
748  break;
749  case 24:
750  sizes.surface_depth = sizes.surface_bpp = 24;
751  break;
752  case 32:
753  sizes.surface_depth = 24;
754  sizes.surface_bpp = 32;
755  break;
756  }
757  break;
758  }
759  }
760 
761  crtc_count = 0;
762  for (i = 0; i < fb_helper->crtc_count; i++) {
763  struct drm_display_mode *desired_mode;
764  desired_mode = fb_helper->crtc_info[i].desired_mode;
765 
766  if (desired_mode) {
767  if (gamma_size == 0)
768  gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
769  if (desired_mode->hdisplay < sizes.fb_width)
770  sizes.fb_width = desired_mode->hdisplay;
771  if (desired_mode->vdisplay < sizes.fb_height)
772  sizes.fb_height = desired_mode->vdisplay;
773  if (desired_mode->hdisplay > sizes.surface_width)
774  sizes.surface_width = desired_mode->hdisplay;
775  if (desired_mode->vdisplay > sizes.surface_height)
776  sizes.surface_height = desired_mode->vdisplay;
777  crtc_count++;
778  }
779  }
780 
781  if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
782  /* hmm everyone went away - assume VGA cable just fell out
783  and will come back later. */
784  DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n");
785  sizes.fb_width = sizes.surface_width = 1024;
786  sizes.fb_height = sizes.surface_height = 768;
787  }
788 
789  /* push down into drivers */
790  new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
791  if (new_fb < 0)
792  return new_fb;
793 
794  info = fb_helper->fbdev;
795 
796  /* set the fb pointer */
797  for (i = 0; i < fb_helper->crtc_count; i++) {
798  fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
799  }
800 
801  if (new_fb) {
802  info->var.pixclock = 0;
803  if (register_framebuffer(info) < 0) {
804  return -EINVAL;
805  }
806 
807  printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
808  info->fix.id);
809 
810  } else {
811  drm_fb_helper_set_par(info);
812  }
813 
814  /* Switch back to kernel console on panic */
815  /* multi card linked list maybe */
816  if (list_empty(&kernel_fb_helper_list)) {
817  printk(KERN_INFO "drm: registered panic notifier\n");
819  &paniced);
820  register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
821  }
822  if (new_fb)
823  list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
824 
825  return 0;
826 }
828 
829 void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
830  uint32_t depth)
831 {
832  info->fix.type = FB_TYPE_PACKED_PIXELS;
833  info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
835  info->fix.mmio_start = 0;
836  info->fix.mmio_len = 0;
837  info->fix.type_aux = 0;
838  info->fix.xpanstep = 1; /* doing it in hw */
839  info->fix.ypanstep = 1; /* doing it in hw */
840  info->fix.ywrapstep = 0;
841  info->fix.accel = FB_ACCEL_NONE;
842  info->fix.type_aux = 0;
843 
844  info->fix.line_length = pitch;
845  return;
846 }
848 
849 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
850  uint32_t fb_width, uint32_t fb_height)
851 {
852  struct drm_framebuffer *fb = fb_helper->fb;
853  info->pseudo_palette = fb_helper->pseudo_palette;
854  info->var.xres_virtual = fb->width;
855  info->var.yres_virtual = fb->height;
856  info->var.bits_per_pixel = fb->bits_per_pixel;
857  info->var.accel_flags = FB_ACCELF_TEXT;
858  info->var.xoffset = 0;
859  info->var.yoffset = 0;
860  info->var.activate = FB_ACTIVATE_NOW;
861  info->var.height = -1;
862  info->var.width = -1;
863 
864  switch (fb->depth) {
865  case 8:
866  info->var.red.offset = 0;
867  info->var.green.offset = 0;
868  info->var.blue.offset = 0;
869  info->var.red.length = 8; /* 8bit DAC */
870  info->var.green.length = 8;
871  info->var.blue.length = 8;
872  info->var.transp.offset = 0;
873  info->var.transp.length = 0;
874  break;
875  case 15:
876  info->var.red.offset = 10;
877  info->var.green.offset = 5;
878  info->var.blue.offset = 0;
879  info->var.red.length = 5;
880  info->var.green.length = 5;
881  info->var.blue.length = 5;
882  info->var.transp.offset = 15;
883  info->var.transp.length = 1;
884  break;
885  case 16:
886  info->var.red.offset = 11;
887  info->var.green.offset = 5;
888  info->var.blue.offset = 0;
889  info->var.red.length = 5;
890  info->var.green.length = 6;
891  info->var.blue.length = 5;
892  info->var.transp.offset = 0;
893  break;
894  case 24:
895  info->var.red.offset = 16;
896  info->var.green.offset = 8;
897  info->var.blue.offset = 0;
898  info->var.red.length = 8;
899  info->var.green.length = 8;
900  info->var.blue.length = 8;
901  info->var.transp.offset = 0;
902  info->var.transp.length = 0;
903  break;
904  case 32:
905  info->var.red.offset = 16;
906  info->var.green.offset = 8;
907  info->var.blue.offset = 0;
908  info->var.red.length = 8;
909  info->var.green.length = 8;
910  info->var.blue.length = 8;
911  info->var.transp.offset = 24;
912  info->var.transp.length = 8;
913  break;
914  default:
915  break;
916  }
917 
918  info->var.xres = fb_width;
919  info->var.yres = fb_height;
920 }
922 
923 static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
924  uint32_t maxX,
925  uint32_t maxY)
926 {
927  struct drm_connector *connector;
928  int count = 0;
929  int i;
930 
931  for (i = 0; i < fb_helper->connector_count; i++) {
932  connector = fb_helper->connector_info[i]->connector;
933  count += connector->funcs->fill_modes(connector, maxX, maxY);
934  }
935 
936  return count;
937 }
938 
939 static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
940 {
941  struct drm_display_mode *mode;
942 
943  list_for_each_entry(mode, &fb_connector->connector->modes, head) {
944  if (drm_mode_width(mode) > width ||
945  drm_mode_height(mode) > height)
946  continue;
947  if (mode->type & DRM_MODE_TYPE_PREFERRED)
948  return mode;
949  }
950  return NULL;
951 }
952 
953 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
954 {
955  struct drm_cmdline_mode *cmdline_mode;
956  cmdline_mode = &fb_connector->cmdline_mode;
957  return cmdline_mode->specified;
958 }
959 
960 static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
961  int width, int height)
962 {
963  struct drm_cmdline_mode *cmdline_mode;
964  struct drm_display_mode *mode = NULL;
965 
966  cmdline_mode = &fb_helper_conn->cmdline_mode;
967  if (cmdline_mode->specified == false)
968  return mode;
969 
970  /* attempt to find a matching mode in the list of modes
971  * we have gotten so far, if not add a CVT mode that conforms
972  */
973  if (cmdline_mode->rb || cmdline_mode->margins)
974  goto create_mode;
975 
976  list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
977  /* check width/height */
978  if (mode->hdisplay != cmdline_mode->xres ||
979  mode->vdisplay != cmdline_mode->yres)
980  continue;
981 
982  if (cmdline_mode->refresh_specified) {
983  if (mode->vrefresh != cmdline_mode->refresh)
984  continue;
985  }
986 
987  if (cmdline_mode->interlace) {
988  if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
989  continue;
990  }
991  return mode;
992  }
993 
994 create_mode:
995  mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
996  cmdline_mode);
997  list_add(&mode->head, &fb_helper_conn->connector->modes);
998  return mode;
999 }
1000 
1001 static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
1002 {
1003  bool enable;
1004 
1005  if (strict) {
1006  enable = connector->status == connector_status_connected;
1007  } else {
1008  enable = connector->status != connector_status_disconnected;
1009  }
1010  return enable;
1011 }
1012 
1013 static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
1014  bool *enabled)
1015 {
1016  bool any_enabled = false;
1017  struct drm_connector *connector;
1018  int i = 0;
1019 
1020  for (i = 0; i < fb_helper->connector_count; i++) {
1021  connector = fb_helper->connector_info[i]->connector;
1022  enabled[i] = drm_connector_enabled(connector, true);
1023  DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
1024  enabled[i] ? "yes" : "no");
1025  any_enabled |= enabled[i];
1026  }
1027 
1028  if (any_enabled)
1029  return;
1030 
1031  for (i = 0; i < fb_helper->connector_count; i++) {
1032  connector = fb_helper->connector_info[i]->connector;
1033  enabled[i] = drm_connector_enabled(connector, false);
1034  }
1035 }
1036 
1037 static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
1038  struct drm_display_mode **modes,
1039  bool *enabled, int width, int height)
1040 {
1041  int count, i, j;
1042  bool can_clone = false;
1043  struct drm_fb_helper_connector *fb_helper_conn;
1044  struct drm_display_mode *dmt_mode, *mode;
1045 
1046  /* only contemplate cloning in the single crtc case */
1047  if (fb_helper->crtc_count > 1)
1048  return false;
1049 
1050  count = 0;
1051  for (i = 0; i < fb_helper->connector_count; i++) {
1052  if (enabled[i])
1053  count++;
1054  }
1055 
1056  /* only contemplate cloning if more than one connector is enabled */
1057  if (count <= 1)
1058  return false;
1059 
1060  /* check the command line or if nothing common pick 1024x768 */
1061  can_clone = true;
1062  for (i = 0; i < fb_helper->connector_count; i++) {
1063  if (!enabled[i])
1064  continue;
1065  fb_helper_conn = fb_helper->connector_info[i];
1066  modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1067  if (!modes[i]) {
1068  can_clone = false;
1069  break;
1070  }
1071  for (j = 0; j < i; j++) {
1072  if (!enabled[j])
1073  continue;
1074  if (!drm_mode_equal(modes[j], modes[i]))
1075  can_clone = false;
1076  }
1077  }
1078 
1079  if (can_clone) {
1080  DRM_DEBUG_KMS("can clone using command line\n");
1081  return true;
1082  }
1083 
1084  /* try and find a 1024x768 mode on each connector */
1085  can_clone = true;
1086  dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false);
1087 
1088  for (i = 0; i < fb_helper->connector_count; i++) {
1089 
1090  if (!enabled[i])
1091  continue;
1092 
1093  fb_helper_conn = fb_helper->connector_info[i];
1094  list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
1095  if (drm_mode_equal(mode, dmt_mode))
1096  modes[i] = mode;
1097  }
1098  if (!modes[i])
1099  can_clone = false;
1100  }
1101 
1102  if (can_clone) {
1103  DRM_DEBUG_KMS("can clone using 1024x768\n");
1104  return true;
1105  }
1106  DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
1107  return false;
1108 }
1109 
1110 static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
1111  struct drm_display_mode **modes,
1112  bool *enabled, int width, int height)
1113 {
1114  struct drm_fb_helper_connector *fb_helper_conn;
1115  int i;
1116 
1117  for (i = 0; i < fb_helper->connector_count; i++) {
1118  fb_helper_conn = fb_helper->connector_info[i];
1119 
1120  if (enabled[i] == false)
1121  continue;
1122 
1123  DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
1124  fb_helper_conn->connector->base.id);
1125 
1126  /* got for command line mode first */
1127  modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1128  if (!modes[i]) {
1129  DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
1130  fb_helper_conn->connector->base.id);
1131  modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
1132  }
1133  /* No preferred modes, pick one off the list */
1134  if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
1135  list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
1136  break;
1137  }
1138  DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
1139  "none");
1140  }
1141  return true;
1142 }
1143 
1144 static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
1145  struct drm_fb_helper_crtc **best_crtcs,
1146  struct drm_display_mode **modes,
1147  int n, int width, int height)
1148 {
1149  int c, o;
1150  struct drm_device *dev = fb_helper->dev;
1151  struct drm_connector *connector;
1152  struct drm_connector_helper_funcs *connector_funcs;
1153  struct drm_encoder *encoder;
1154  struct drm_fb_helper_crtc *best_crtc;
1155  int my_score, best_score, score;
1156  struct drm_fb_helper_crtc **crtcs, *crtc;
1157  struct drm_fb_helper_connector *fb_helper_conn;
1158 
1159  if (n == fb_helper->connector_count)
1160  return 0;
1161 
1162  fb_helper_conn = fb_helper->connector_info[n];
1163  connector = fb_helper_conn->connector;
1164 
1165  best_crtcs[n] = NULL;
1166  best_crtc = NULL;
1167  best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
1168  if (modes[n] == NULL)
1169  return best_score;
1170 
1171  crtcs = kzalloc(dev->mode_config.num_connector *
1172  sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
1173  if (!crtcs)
1174  return best_score;
1175 
1176  my_score = 1;
1177  if (connector->status == connector_status_connected)
1178  my_score++;
1179  if (drm_has_cmdline_mode(fb_helper_conn))
1180  my_score++;
1181  if (drm_has_preferred_mode(fb_helper_conn, width, height))
1182  my_score++;
1183 
1184  connector_funcs = connector->helper_private;
1185  encoder = connector_funcs->best_encoder(connector);
1186  if (!encoder)
1187  goto out;
1188 
1189  /* select a crtc for this connector and then attempt to configure
1190  remaining connectors */
1191  for (c = 0; c < fb_helper->crtc_count; c++) {
1192  crtc = &fb_helper->crtc_info[c];
1193 
1194  if ((encoder->possible_crtcs & (1 << c)) == 0) {
1195  continue;
1196  }
1197 
1198  for (o = 0; o < n; o++)
1199  if (best_crtcs[o] == crtc)
1200  break;
1201 
1202  if (o < n) {
1203  /* ignore cloning unless only a single crtc */
1204  if (fb_helper->crtc_count > 1)
1205  continue;
1206 
1207  if (!drm_mode_equal(modes[o], modes[n]))
1208  continue;
1209  }
1210 
1211  crtcs[n] = crtc;
1212  memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
1213  score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
1214  width, height);
1215  if (score > best_score) {
1216  best_crtc = crtc;
1217  best_score = score;
1218  memcpy(best_crtcs, crtcs,
1219  dev->mode_config.num_connector *
1220  sizeof(struct drm_fb_helper_crtc *));
1221  }
1222  }
1223 out:
1224  kfree(crtcs);
1225  return best_score;
1226 }
1227 
1228 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
1229 {
1230  struct drm_device *dev = fb_helper->dev;
1231  struct drm_fb_helper_crtc **crtcs;
1232  struct drm_display_mode **modes;
1233  struct drm_mode_set *modeset;
1234  bool *enabled;
1235  int width, height;
1236  int i, ret;
1237 
1238  DRM_DEBUG_KMS("\n");
1239 
1240  width = dev->mode_config.max_width;
1241  height = dev->mode_config.max_height;
1242 
1243  crtcs = kcalloc(dev->mode_config.num_connector,
1244  sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
1245  modes = kcalloc(dev->mode_config.num_connector,
1246  sizeof(struct drm_display_mode *), GFP_KERNEL);
1247  enabled = kcalloc(dev->mode_config.num_connector,
1248  sizeof(bool), GFP_KERNEL);
1249 
1250  drm_enable_connectors(fb_helper, enabled);
1251 
1252  ret = drm_target_cloned(fb_helper, modes, enabled, width, height);
1253  if (!ret) {
1254  ret = drm_target_preferred(fb_helper, modes, enabled, width, height);
1255  if (!ret)
1256  DRM_ERROR("Unable to find initial modes\n");
1257  }
1258 
1259  DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
1260 
1261  drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
1262 
1263  /* need to set the modesets up here for use later */
1264  /* fill out the connector<->crtc mappings into the modesets */
1265  for (i = 0; i < fb_helper->crtc_count; i++) {
1266  modeset = &fb_helper->crtc_info[i].mode_set;
1267  modeset->num_connectors = 0;
1268  }
1269 
1270  for (i = 0; i < fb_helper->connector_count; i++) {
1271  struct drm_display_mode *mode = modes[i];
1272  struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
1273  modeset = &fb_crtc->mode_set;
1274 
1275  if (mode && fb_crtc) {
1276  DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
1277  mode->name, fb_crtc->mode_set.crtc->base.id);
1278  fb_crtc->desired_mode = mode;
1279  if (modeset->mode)
1280  drm_mode_destroy(dev, modeset->mode);
1281  modeset->mode = drm_mode_duplicate(dev,
1282  fb_crtc->desired_mode);
1283  modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
1284  }
1285  }
1286 
1287  kfree(crtcs);
1288  kfree(modes);
1289  kfree(enabled);
1290 }
1291 
1306 bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1307 {
1308  struct drm_device *dev = fb_helper->dev;
1309  int count = 0;
1310 
1311  /* disable all the possible outputs/crtcs before entering KMS mode */
1313 
1314  drm_fb_helper_parse_command_line(fb_helper);
1315 
1316  count = drm_fb_helper_probe_connector_modes(fb_helper,
1317  dev->mode_config.max_width,
1318  dev->mode_config.max_height);
1319  /*
1320  * we shouldn't end up with no modes here.
1321  */
1322  if (count == 0) {
1323  printk(KERN_INFO "No connectors reported connected with modes\n");
1324  }
1325  drm_setup_crtcs(fb_helper);
1326 
1327  return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1328 }
1330 
1346 {
1347  struct drm_device *dev = fb_helper->dev;
1348  int count = 0;
1349  u32 max_width, max_height, bpp_sel;
1350  int bound = 0, crtcs_bound = 0;
1351  struct drm_crtc *crtc;
1352 
1353  if (!fb_helper->fb)
1354  return 0;
1355 
1356  mutex_lock(&dev->mode_config.mutex);
1357  list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1358  if (crtc->fb)
1359  crtcs_bound++;
1360  if (crtc->fb == fb_helper->fb)
1361  bound++;
1362  }
1363 
1364  if (bound < crtcs_bound) {
1365  fb_helper->delayed_hotplug = true;
1366  mutex_unlock(&dev->mode_config.mutex);
1367  return 0;
1368  }
1369  DRM_DEBUG_KMS("\n");
1370 
1371  max_width = fb_helper->fb->width;
1372  max_height = fb_helper->fb->height;
1373  bpp_sel = fb_helper->fb->bits_per_pixel;
1374 
1375  count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
1376  max_height);
1377  drm_setup_crtcs(fb_helper);
1378  mutex_unlock(&dev->mode_config.mutex);
1379 
1380  return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1381 }
1383 
1384 /* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
1385  * but the module doesn't depend on any fb console symbols. At least
1386  * attempt to load fbcon to avoid leaving the system without a usable console.
1387  */
1388 #if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
1389 static int __init drm_fb_helper_modinit(void)
1390 {
1391  const char *name = "fbcon";
1392  struct module *fbcon;
1393 
1394  mutex_lock(&module_mutex);
1395  fbcon = find_module(name);
1396  mutex_unlock(&module_mutex);
1397 
1398  if (!fbcon)
1399  request_module_nowait(name);
1400  return 0;
1401 }
1402 
1403 module_init(drm_fb_helper_modinit);
1404 #endif