2 * Copyright (c) 2006-2009 Red Hat Inc.
3 * Copyright (c) 2006-2008 Intel Corporation
4 * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
6 * DRM framebuffer helper functions
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.
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
27 * Dave Airlie <airlied@linux.ie>
28 * Jesse Barnes <jesse.barnes@intel.com>
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <dev/drm2/drmP.h>
35 #include <dev/drm2/drm_crtc.h>
36 #include <dev/drm2/drm_fb_helper.h>
37 #include <dev/drm2/drm_crtc_helper.h>
39 #include <dev/vt/vt.h>
40 #include <dev/vt/colors/vt_termcolors.h>
49 struct drm_fb_helper *fb_helper;
50 struct task fb_mode_task;
54 static vd_init_t vt_kms_init;
55 static vd_blank_t vt_kms_blank;
56 static vd_bitbltchr_t vt_kms_bitbltchr;
57 static vd_postswitch_t vt_kms_postswitch;
58 static void vt_restore_fbdev_mode(void *, int);
60 static struct vt_driver vt_vt_kms_driver = {
61 .vd_init = vt_kms_init,
62 .vd_blank = vt_kms_blank,
63 .vd_bitbltchr = vt_kms_bitbltchr,
64 .vd_postswitch = vt_kms_postswitch,
68 vt_kms_blank(struct vt_device *vd, term_color_t color)
70 struct vt_kms_softc *sc = vd->vd_softc;
74 c = sc->sc_cmap[color];
75 /* TODO handle difference between depth and bpp. */
76 switch (sc->sc_depth) {
78 for (ofs = 0; ofs < (sc->sc_stride * vd->vd_height); ofs++)
79 *(uint8_t *)(sc->sc_vaddr + ofs) = c & 0xff;
82 /* XXX must be 16bits colormap */
83 for (ofs = 0; ofs < (sc->sc_stride * vd->vd_height); ofs++)
84 *(uint16_t *)(sc->sc_vaddr + 2 * ofs) = c & 0xffff;
88 c = sc->sc_cmap[color];
89 for (ofs = 0; ofs < (sc->sc_stride * vd->vd_height); ofs++)
90 *(uint32_t *)(sc->sc_vaddr + 4 * ofs) = c;
99 vt_kms_bitbltchr(struct vt_device *vd, const uint8_t *src,
100 vt_axis_t top, vt_axis_t left, unsigned int width, unsigned int height,
101 term_color_t fg, term_color_t bg)
103 struct vt_kms_softc *sc = vd->vd_softc;
109 fgc = sc->sc_cmap[fg];
110 bgc = sc->sc_cmap[bg];
112 line = (sc->sc_stride * top) + left * sc->sc_depth/8;
113 for (; height > 0; height--) {
114 for (c = 0; c < width; c++) {
119 switch(sc->sc_depth) {
121 *(uint8_t *)(sc->sc_vaddr + line + c) =
122 (b & 0x80 ? fgc : bgc) & 0xff;
127 *(uint32_t *)(sc->sc_vaddr + line + 4*c) =
128 (b & 0x80) ? fgc : bgc;
135 line += sc->sc_stride;
140 vt_kms_init(struct vt_device *vd)
142 struct vt_kms_softc *sc;
147 vd->vd_height = sc->sc_height;
148 vd->vd_width = sc->sc_width;
150 switch (sc->sc_depth) {
152 err = vt_generate_vga_palette(sc->sc_cmap, COLOR_FORMAT_RGB,
153 0x7, 5, 0x7, 2, 0x3, 0);
158 err = vt_generate_vga_palette(sc->sc_cmap, COLOR_FORMAT_RGB,
159 0x1f, 10, 0x1f, 5, 0x1f, 0);
164 err = vt_generate_vga_palette(sc->sc_cmap, COLOR_FORMAT_RGB,
165 0x1f, 11, 0x3f, 5, 0x1f, 0);
170 case 32: /* Ignore alpha. */
171 err = vt_generate_vga_palette(sc->sc_cmap, COLOR_FORMAT_RGB,
172 0xff, 0, 0xff, 8, 0xff, 16);
180 /* Clear the screen. */
181 vt_kms_blank(vd, TC_BLACK);
183 TASK_INIT(&sc->fb_mode_task, 0, vt_restore_fbdev_mode, vd);
185 return (CN_INTERNAL);
188 /* Call restore out of vt(9) locks. */
190 vt_restore_fbdev_mode(void *arg, int pending)
192 struct vt_kms_softc *sc;
193 struct vt_device *vd;
195 vd = (struct vt_device *)arg;
197 drm_fb_helper_restore_fbdev_mode(sc->fb_helper);
201 vt_kms_postswitch(struct vt_device *vd)
203 struct vt_kms_softc *sc;
206 taskqueue_enqueue_fast(taskqueue_thread, &sc->fb_mode_task);
209 static DRM_LIST_HEAD(kernel_fb_helper_list);
211 /* simple single crtc case helper function */
212 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
214 struct drm_device *dev = fb_helper->dev;
215 struct drm_connector *connector;
217 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
218 struct drm_fb_helper_connector *fb_helper_connector;
220 fb_helper_connector = malloc(
221 sizeof(struct drm_fb_helper_connector), DRM_MEM_KMS,
224 fb_helper_connector->connector = connector;
225 fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
230 const char *fb_mode_option;
233 * drm_fb_helper_connector_parse_command_line - parse command line for connector
234 * @connector - connector to parse line for
235 * @mode_option - per connector mode option
237 * This parses the connector specific then generic command lines for
238 * modes and options to configure the connector.
240 * This uses the same parameters as the fb modedb.c, except for extra
241 * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
243 * enable/enable Digital/disable bit at the end
245 static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
246 const char *mode_option)
249 unsigned int namelen;
250 int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
251 unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
252 int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
254 enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
255 struct drm_fb_helper_cmdline_mode *cmdline_mode;
256 struct drm_connector *connector;
260 connector = fb_helper_conn->connector;
262 cmdline_mode = &fb_helper_conn->cmdline_mode;
264 mode_option = fb_mode_option;
267 cmdline_mode->specified = false;
272 namelen = strlen(name);
273 for (i = namelen-1; i >= 0; i--) {
277 if (!refresh_specified && !bpp_specified &&
279 refresh = strtol(&name[i+1], NULL, 10);
280 refresh_specified = 1;
288 if (!bpp_specified && !yres_specified) {
289 bpp = strtol(&name[i+1], NULL, 10);
297 if (!yres_specified) {
298 yres = strtol(&name[i+1], NULL, 10);
321 force = DRM_FORCE_ON;
324 if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
325 (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
326 force = DRM_FORCE_ON;
328 force = DRM_FORCE_ON_DIGITAL;
331 force = DRM_FORCE_OFF;
337 if (i < 0 && yres_specified) {
338 xres = strtol(name, NULL, 10);
343 DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
344 drm_get_connector_name(connector), xres, yres,
345 (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
346 "", (margins) ? " with margins" : "", (interlace) ?
352 case DRM_FORCE_OFF: s = "OFF"; break;
353 case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
355 case DRM_FORCE_ON: s = "ON"; break;
358 DRM_INFO("forcing %s connector %s\n",
359 drm_get_connector_name(connector), s);
360 connector->force = force;
364 cmdline_mode->specified = true;
365 cmdline_mode->xres = xres;
366 cmdline_mode->yres = yres;
369 if (refresh_specified) {
370 cmdline_mode->refresh_specified = true;
371 cmdline_mode->refresh = refresh;
375 cmdline_mode->bpp_specified = true;
376 cmdline_mode->bpp = bpp;
378 cmdline_mode->rb = rb ? true : false;
379 cmdline_mode->cvt = cvt ? true : false;
380 cmdline_mode->interlace = interlace ? true : false;
386 fb_get_options(const char *connector_name, char **option)
390 * TODO: store mode options pointer in ${option} for connector with
391 * name ${connector_name}
396 static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
398 struct drm_fb_helper_connector *fb_helper_conn;
401 for (i = 0; i < fb_helper->connector_count; i++) {
404 fb_helper_conn = fb_helper->connector_info[i];
406 /* do something on return - turn off connector maybe */
407 if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option))
410 drm_fb_helper_connector_parse_command_line(fb_helper_conn, option);
416 static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
418 uint16_t *r_base, *g_base, *b_base;
421 r_base = crtc->gamma_store;
422 g_base = r_base + crtc->gamma_size;
423 b_base = g_base + crtc->gamma_size;
425 for (i = 0; i < crtc->gamma_size; i++)
426 helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
429 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
431 uint16_t *r_base, *g_base, *b_base;
433 r_base = crtc->gamma_store;
434 g_base = r_base + crtc->gamma_size;
435 b_base = g_base + crtc->gamma_size;
437 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
442 int drm_fb_helper_debug_enter(struct fb_info *info)
444 struct drm_fb_helper *helper = info->par;
445 struct drm_crtc_helper_funcs *funcs;
448 if (list_empty(&kernel_fb_helper_list))
451 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
452 for (i = 0; i < helper->crtc_count; i++) {
453 struct drm_mode_set *mode_set =
454 &helper->crtc_info[i].mode_set;
456 if (!mode_set->crtc->enabled)
459 funcs = mode_set->crtc->helper_private;
460 drm_fb_helper_save_lut_atomic(mode_set->crtc, helper);
461 funcs->mode_set_base_atomic(mode_set->crtc,
465 ENTER_ATOMIC_MODE_SET);
474 /* Find the real fb for a given fb helper CRTC */
475 static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
477 struct drm_device *dev = crtc->dev;
480 list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
481 if (crtc->base.id == c->base.id)
490 int drm_fb_helper_debug_leave(struct fb_info *info)
492 struct drm_fb_helper *helper = info->par;
493 struct drm_crtc *crtc;
494 struct drm_crtc_helper_funcs *funcs;
495 struct drm_framebuffer *fb;
498 for (i = 0; i < helper->crtc_count; i++) {
499 struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
500 crtc = mode_set->crtc;
501 funcs = crtc->helper_private;
502 fb = drm_mode_config_fb(crtc);
508 DRM_ERROR("no fb to restore??\n");
512 drm_fb_helper_restore_lut_atomic(mode_set->crtc);
513 funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
514 crtc->y, LEAVE_ATOMIC_MODE_SET);
521 bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
525 for (i = 0; i < fb_helper->crtc_count; i++) {
526 struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
527 ret = drm_crtc_helper_set_config(mode_set);
535 bool drm_fb_helper_force_kernel_mode(void)
537 bool ret, error = false;
538 struct drm_fb_helper *helper;
540 if (list_empty(&kernel_fb_helper_list))
543 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
544 if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF)
547 ret = drm_fb_helper_restore_fbdev_mode(helper);
556 int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
559 printf("panic occurred, switching back to text console\n");
560 return drm_fb_helper_force_kernel_mode();
564 static struct notifier_block paniced = {
565 .notifier_call = drm_fb_helper_panic,
569 * drm_fb_helper_restore - restore the framebuffer console (kernel) config
571 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
573 void drm_fb_helper_restore(void)
576 ret = drm_fb_helper_force_kernel_mode();
578 DRM_ERROR("Failed to restore crtc configuration\n");
581 #ifdef CONFIG_MAGIC_SYSRQ
582 static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
584 drm_fb_helper_restore();
586 static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
588 static void drm_fb_helper_sysrq(int dummy1)
590 schedule_work(&drm_fb_helper_restore_work);
593 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
594 .handler = drm_fb_helper_sysrq,
595 .help_msg = "force-fb(V)",
596 .action_msg = "Restore framebuffer console",
599 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
604 static void drm_fb_helper_on(struct fb_info *info)
606 struct drm_fb_helper *fb_helper = info->par;
607 struct drm_device *dev = fb_helper->dev;
608 struct drm_crtc *crtc;
609 struct drm_crtc_helper_funcs *crtc_funcs;
610 struct drm_connector *connector;
611 struct drm_encoder *encoder;
615 * For each CRTC in this fb, turn the crtc on then,
616 * find all associated encoders and turn them on.
618 sx_xlock(&dev->mode_config.mutex);
619 for (i = 0; i < fb_helper->crtc_count; i++) {
620 crtc = fb_helper->crtc_info[i].mode_set.crtc;
621 crtc_funcs = crtc->helper_private;
626 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
628 /* Walk the connectors & encoders on this fb turning them on */
629 for (j = 0; j < fb_helper->connector_count; j++) {
630 connector = fb_helper->connector_info[j]->connector;
631 connector->dpms = DRM_MODE_DPMS_ON;
632 drm_connector_property_set_value(connector,
633 dev->mode_config.dpms_property,
636 /* Found a CRTC on this fb, now find encoders */
637 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
638 if (encoder->crtc == crtc) {
639 struct drm_encoder_helper_funcs *encoder_funcs;
641 encoder_funcs = encoder->helper_private;
642 encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
646 sx_xunlock(&dev->mode_config.mutex);
651 static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
653 struct drm_fb_helper *fb_helper = info->par;
654 struct drm_device *dev = fb_helper->dev;
655 struct drm_crtc *crtc;
656 struct drm_crtc_helper_funcs *crtc_funcs;
657 struct drm_connector *connector;
658 struct drm_encoder *encoder;
662 * For each CRTC in this fb, find all associated encoders
663 * and turn them off, then turn off the CRTC.
665 sx_xlock(&dev->mode_config.mutex);
666 for (i = 0; i < fb_helper->crtc_count; i++) {
667 crtc = fb_helper->crtc_info[i].mode_set.crtc;
668 crtc_funcs = crtc->helper_private;
673 /* Walk the connectors on this fb and mark them off */
674 for (j = 0; j < fb_helper->connector_count; j++) {
675 connector = fb_helper->connector_info[j]->connector;
676 connector->dpms = dpms_mode;
677 drm_connector_property_set_value(connector,
678 dev->mode_config.dpms_property,
681 /* Found a CRTC on this fb, now find encoders */
682 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
683 if (encoder->crtc == crtc) {
684 struct drm_encoder_helper_funcs *encoder_funcs;
686 encoder_funcs = encoder->helper_private;
687 encoder_funcs->dpms(encoder, dpms_mode);
690 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
692 sx_xunlock(&dev->mode_config.mutex);
697 int drm_fb_helper_blank(int blank, struct fb_info *info)
700 /* Display: On; HSync: On, VSync: On */
701 case FB_BLANK_UNBLANK:
702 drm_fb_helper_on(info);
704 /* Display: Off; HSync: On, VSync: On */
705 case FB_BLANK_NORMAL:
706 drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
708 /* Display: Off; HSync: Off, VSync: On */
709 case FB_BLANK_HSYNC_SUSPEND:
710 drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
712 /* Display: Off; HSync: On, VSync: Off */
713 case FB_BLANK_VSYNC_SUSPEND:
714 drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
716 /* Display: Off; HSync: Off, VSync: Off */
717 case FB_BLANK_POWERDOWN:
718 drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
725 static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
729 for (i = 0; i < helper->connector_count; i++)
730 free(helper->connector_info[i], DRM_MEM_KMS);
731 free(helper->connector_info, DRM_MEM_KMS);
732 for (i = 0; i < helper->crtc_count; i++) {
733 free(helper->crtc_info[i].mode_set.connectors, DRM_MEM_KMS);
734 if (helper->crtc_info[i].mode_set.mode)
735 drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode);
737 free(helper->crtc_info, DRM_MEM_KMS);
740 int drm_fb_helper_init(struct drm_device *dev,
741 struct drm_fb_helper *fb_helper,
742 int crtc_count, int max_conn_count)
744 struct drm_crtc *crtc;
747 fb_helper->dev = dev;
749 INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
751 fb_helper->crtc_info = malloc(crtc_count *
752 sizeof(struct drm_fb_helper_crtc), DRM_MEM_KMS, M_WAITOK | M_ZERO);
754 fb_helper->crtc_count = crtc_count;
755 fb_helper->connector_info = malloc(dev->mode_config.num_connector *
756 sizeof(struct drm_fb_helper_connector *), DRM_MEM_KMS,
758 fb_helper->connector_count = 0;
760 for (i = 0; i < crtc_count; i++) {
761 fb_helper->crtc_info[i].mode_set.connectors =
762 malloc(max_conn_count * sizeof(struct drm_connector *),
763 DRM_MEM_KMS, M_WAITOK | M_ZERO);
765 fb_helper->crtc_info[i].mode_set.num_connectors = 0;
769 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
770 fb_helper->crtc_info[i].crtc_id = crtc->base.id;
771 fb_helper->crtc_info[i].mode_set.crtc = crtc;
774 fb_helper->conn_limit = max_conn_count;
778 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
780 if (!list_empty(&fb_helper->kernel_fb_list)) {
781 list_del(&fb_helper->kernel_fb_list);
782 if (list_empty(&kernel_fb_helper_list)) {
784 printk(KERN_INFO "drm: unregistered panic notifier\n");
785 atomic_notifier_chain_unregister(&panic_notifier_list,
787 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
792 drm_fb_helper_crtc_free(fb_helper);
797 static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
798 u16 blue, u16 regno, struct fb_info *info)
800 struct drm_fb_helper *fb_helper = info->par;
801 struct drm_framebuffer *fb = fb_helper->fb;
804 if (info->fix.visual == FB_VISUAL_trueCOLOR) {
807 /* place color in psuedopalette */
810 palette = (u32 *)info->pseudo_palette;
811 red >>= (16 - info->var.red.length);
812 green >>= (16 - info->var.green.length);
813 blue >>= (16 - info->var.blue.length);
814 value = (red << info->var.red.offset) |
815 (green << info->var.green.offset) |
816 (blue << info->var.blue.offset);
817 if (info->var.transp.length > 0) {
818 u32 mask = (1 << info->var.transp.length) - 1;
819 mask <<= info->var.transp.offset;
822 palette[regno] = value;
828 if (fb->bits_per_pixel == 16) {
831 if (fb->depth == 16 && regno > 63)
833 if (fb->depth == 15 && regno > 31)
836 if (fb->depth == 16) {
840 for (i = 0; i < 8; i++)
841 fb_helper->funcs->gamma_set(crtc, red,
842 green, blue, pindex + i);
845 fb_helper->funcs->gamma_get(crtc, &r,
849 for (i = 0; i < 4; i++)
850 fb_helper->funcs->gamma_set(crtc, r,
857 fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
863 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
865 struct drm_fb_helper *fb_helper = info->par;
866 struct drm_crtc_helper_funcs *crtc_funcs;
867 u16 *red, *green, *blue, *transp;
868 struct drm_crtc *crtc;
872 for (i = 0; i < fb_helper->crtc_count; i++) {
873 crtc = fb_helper->crtc_info[i].mode_set.crtc;
874 crtc_funcs = crtc->helper_private;
879 transp = cmap->transp;
882 for (j = 0; j < cmap->len; j++) {
883 u16 hred, hgreen, hblue, htransp = 0xffff;
892 rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
896 crtc_funcs->load_lut(crtc);
903 int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
904 struct fb_info *info)
906 struct drm_fb_helper *fb_helper = info->par;
907 struct drm_framebuffer *fb = fb_helper->fb;
910 if (var->pixclock != 0 || in_dbg_master())
913 /* Need to resize the fb object !!! */
914 if (var->bits_per_pixel > fb->bits_per_pixel ||
915 var->xres > fb->width || var->yres > fb->height ||
916 var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
917 DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb "
918 "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
919 var->xres, var->yres, var->bits_per_pixel,
920 var->xres_virtual, var->yres_virtual,
921 fb->width, fb->height, fb->bits_per_pixel);
925 switch (var->bits_per_pixel) {
927 depth = (var->green.length == 6) ? 16 : 15;
930 depth = (var->transp.length > 0) ? 32 : 24;
933 depth = var->bits_per_pixel;
940 var->green.offset = 0;
941 var->blue.offset = 0;
943 var->green.length = 8;
944 var->blue.length = 8;
945 var->transp.length = 0;
946 var->transp.offset = 0;
949 var->red.offset = 10;
950 var->green.offset = 5;
951 var->blue.offset = 0;
953 var->green.length = 5;
954 var->blue.length = 5;
955 var->transp.length = 1;
956 var->transp.offset = 15;
959 var->red.offset = 11;
960 var->green.offset = 5;
961 var->blue.offset = 0;
963 var->green.length = 6;
964 var->blue.length = 5;
965 var->transp.length = 0;
966 var->transp.offset = 0;
969 var->red.offset = 16;
970 var->green.offset = 8;
971 var->blue.offset = 0;
973 var->green.length = 8;
974 var->blue.length = 8;
975 var->transp.length = 0;
976 var->transp.offset = 0;
979 var->red.offset = 16;
980 var->green.offset = 8;
981 var->blue.offset = 0;
983 var->green.length = 8;
984 var->blue.length = 8;
985 var->transp.length = 8;
986 var->transp.offset = 24;
996 /* this will let fbcon do the mode init */
997 int drm_fb_helper_set_par(struct fb_info *info)
999 struct drm_fb_helper *fb_helper = info->par;
1000 struct drm_device *dev = fb_helper->dev;
1001 struct fb_var_screeninfo *var = &info->var;
1002 struct drm_crtc *crtc;
1006 if (var->pixclock != 0) {
1007 DRM_ERROR("PIXEL CLOCK SET\n");
1011 mutex_lock(&dev->mode_config.mutex);
1012 for (i = 0; i < fb_helper->crtc_count; i++) {
1013 crtc = fb_helper->crtc_info[i].mode_set.crtc;
1014 ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
1016 mutex_unlock(&dev->mode_config.mutex);
1020 mutex_unlock(&dev->mode_config.mutex);
1022 if (fb_helper->delayed_hotplug) {
1023 fb_helper->delayed_hotplug = false;
1024 drm_fb_helper_hotplug_event(fb_helper);
1031 int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
1032 struct fb_info *info)
1034 struct drm_fb_helper *fb_helper = info->par;
1035 struct drm_device *dev = fb_helper->dev;
1036 struct drm_mode_set *modeset;
1037 struct drm_crtc *crtc;
1041 mutex_lock(&dev->mode_config.mutex);
1042 for (i = 0; i < fb_helper->crtc_count; i++) {
1043 crtc = fb_helper->crtc_info[i].mode_set.crtc;
1045 modeset = &fb_helper->crtc_info[i].mode_set;
1047 modeset->x = var->xoffset;
1048 modeset->y = var->yoffset;
1050 if (modeset->num_connectors) {
1051 ret = crtc->funcs->set_config(modeset);
1053 info->var.xoffset = var->xoffset;
1054 info->var.yoffset = var->yoffset;
1058 mutex_unlock(&dev->mode_config.mutex);
1063 int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
1069 struct fb_info *info;
1070 struct drm_fb_helper_surface_size sizes;
1073 memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
1074 sizes.surface_depth = 24;
1075 sizes.surface_bpp = 32;
1076 sizes.fb_width = (unsigned)-1;
1077 sizes.fb_height = (unsigned)-1;
1079 /* if driver picks 8 or 16 by default use that
1080 for both depth/bpp */
1081 if (preferred_bpp != sizes.surface_bpp) {
1082 sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
1084 /* first up get a count of crtcs now in use and new min/maxes width/heights */
1085 for (i = 0; i < fb_helper->connector_count; i++) {
1086 struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
1087 struct drm_fb_helper_cmdline_mode *cmdline_mode;
1089 cmdline_mode = &fb_helper_conn->cmdline_mode;
1091 if (cmdline_mode->bpp_specified) {
1092 switch (cmdline_mode->bpp) {
1094 sizes.surface_depth = sizes.surface_bpp = 8;
1097 sizes.surface_depth = 15;
1098 sizes.surface_bpp = 16;
1101 sizes.surface_depth = sizes.surface_bpp = 16;
1104 sizes.surface_depth = sizes.surface_bpp = 24;
1107 sizes.surface_depth = 24;
1108 sizes.surface_bpp = 32;
1116 for (i = 0; i < fb_helper->crtc_count; i++) {
1117 struct drm_display_mode *desired_mode;
1118 desired_mode = fb_helper->crtc_info[i].desired_mode;
1121 if (gamma_size == 0)
1122 gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
1123 if (desired_mode->hdisplay < sizes.fb_width)
1124 sizes.fb_width = desired_mode->hdisplay;
1125 if (desired_mode->vdisplay < sizes.fb_height)
1126 sizes.fb_height = desired_mode->vdisplay;
1127 if (desired_mode->hdisplay > sizes.surface_width)
1128 sizes.surface_width = desired_mode->hdisplay;
1129 if (desired_mode->vdisplay > sizes.surface_height)
1130 sizes.surface_height = desired_mode->vdisplay;
1135 if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
1136 /* hmm everyone went away - assume VGA cable just fell out
1137 and will come back later. */
1138 DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n");
1139 sizes.fb_width = sizes.surface_width = 1024;
1140 sizes.fb_height = sizes.surface_height = 768;
1143 /* push down into drivers */
1144 new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
1148 info = fb_helper->fbdev;
1150 /* set the fb pointer */
1151 for (i = 0; i < fb_helper->crtc_count; i++) {
1152 fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
1157 info->var.pixclock = 0;
1158 if (register_framebuffer(info) < 0) {
1162 printf("fb%d: %s frame buffer device\n", info->node,
1166 drm_fb_helper_set_par(info);
1169 /* Switch back to kernel console on panic */
1170 /* multi card linked list maybe */
1171 if (list_empty(&kernel_fb_helper_list)) {
1172 printf("drm: registered panic notifier\n");
1173 atomic_notifier_chain_register(&panic_notifier_list,
1177 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
1180 struct vt_kms_softc *sc = (struct vt_kms_softc *)malloc(sizeof(struct vt_kms_softc), M_TEMP, M_WAITOK);
1181 sc->sc_vaddr = info->fb_vbase;
1182 sc->sc_paddr = info->fb_pbase;
1184 sc->sc_depth = fb_helper->fb->bits_per_pixel; /* XXX: fix depth in VT, bpp is pix size, depth is meaning bits size */
1186 sc->sc_height = fb_helper->fb->height;
1187 sc->sc_stride = fb_helper->fb->pitches[0];
1188 sc->sc_width = fb_helper->fb->width;
1189 /* Save fb_helper (XXX Do we really need it?) */
1190 sc->fb_helper = fb_helper;
1192 drm_fb_helper_restore_fbdev_mode(fb_helper);
1194 vt_allocate(&vt_vt_kms_driver, sc);
1196 DRM_DEBUG("Attach VT to %dx%d fb: P %#lx V %#lx\n",
1197 fb_helper->fb->width, fb_helper->fb->height,
1198 info->fb_pbase, info->fb_vbase);
1204 void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
1207 info->fix.type = FB_TYPE_PACKED_PIXELS;
1208 info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
1209 FB_VISUAL_trueCOLOR;
1210 info->fix.mmio_start = 0;
1211 info->fix.mmio_len = 0;
1212 info->fix.type_aux = 0;
1213 info->fix.xpanstep = 1; /* doing it in hw */
1214 info->fix.ypanstep = 1; /* doing it in hw */
1215 info->fix.ywrapstep = 0;
1216 info->fix.accel = FB_ACCEL_NONE;
1217 info->fix.type_aux = 0;
1219 info->fix.line_length = pitch;
1223 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
1224 uint32_t fb_width, uint32_t fb_height)
1226 struct drm_framebuffer *fb = fb_helper->fb;
1227 info->pseudo_palette = fb_helper->pseudo_palette;
1228 info->var.xres_virtual = fb->width;
1229 info->var.yres_virtual = fb->height;
1230 info->var.bits_per_pixel = fb->bits_per_pixel;
1231 info->var.accel_flags = FB_ACCELF_TEXT;
1232 info->var.xoffset = 0;
1233 info->var.yoffset = 0;
1234 info->var.activate = FB_ACTIVATE_NOW;
1235 info->var.height = -1;
1236 info->var.width = -1;
1238 switch (fb->depth) {
1240 info->var.red.offset = 0;
1241 info->var.green.offset = 0;
1242 info->var.blue.offset = 0;
1243 info->var.red.length = 8; /* 8bit DAC */
1244 info->var.green.length = 8;
1245 info->var.blue.length = 8;
1246 info->var.transp.offset = 0;
1247 info->var.transp.length = 0;
1250 info->var.red.offset = 10;
1251 info->var.green.offset = 5;
1252 info->var.blue.offset = 0;
1253 info->var.red.length = 5;
1254 info->var.green.length = 5;
1255 info->var.blue.length = 5;
1256 info->var.transp.offset = 15;
1257 info->var.transp.length = 1;
1260 info->var.red.offset = 11;
1261 info->var.green.offset = 5;
1262 info->var.blue.offset = 0;
1263 info->var.red.length = 5;
1264 info->var.green.length = 6;
1265 info->var.blue.length = 5;
1266 info->var.transp.offset = 0;
1269 info->var.red.offset = 16;
1270 info->var.green.offset = 8;
1271 info->var.blue.offset = 0;
1272 info->var.red.length = 8;
1273 info->var.green.length = 8;
1274 info->var.blue.length = 8;
1275 info->var.transp.offset = 0;
1276 info->var.transp.length = 0;
1279 info->var.red.offset = 16;
1280 info->var.green.offset = 8;
1281 info->var.blue.offset = 0;
1282 info->var.red.length = 8;
1283 info->var.green.length = 8;
1284 info->var.blue.length = 8;
1285 info->var.transp.offset = 24;
1286 info->var.transp.length = 8;
1292 info->var.xres = fb_width;
1293 info->var.yres = fb_height;
1297 static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
1301 struct drm_connector *connector;
1305 for (i = 0; i < fb_helper->connector_count; i++) {
1306 connector = fb_helper->connector_info[i]->connector;
1307 count += connector->funcs->fill_modes(connector, maxX, maxY);
1313 static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
1315 struct drm_display_mode *mode;
1317 list_for_each_entry(mode, &fb_connector->connector->modes, head) {
1318 if (drm_mode_width(mode) > width ||
1319 drm_mode_height(mode) > height)
1321 if (mode->type & DRM_MODE_TYPE_PREFERRED)
1327 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
1329 struct drm_fb_helper_cmdline_mode *cmdline_mode;
1330 cmdline_mode = &fb_connector->cmdline_mode;
1331 return cmdline_mode->specified;
1334 static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
1335 int width, int height)
1337 struct drm_cmdline_mode *cmdline_mode;
1338 struct drm_display_mode *mode = NULL;
1340 cmdline_mode = &fb_helper_conn->cmdline_mode1;
1341 if (cmdline_mode->specified == false &&
1342 !drm_fetch_cmdline_mode_from_kenv(fb_helper_conn->connector,
1346 /* attempt to find a matching mode in the list of modes
1347 * we have gotten so far, if not add a CVT mode that conforms
1349 if (cmdline_mode->rb || cmdline_mode->margins)
1352 list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
1353 /* check width/height */
1354 if (mode->hdisplay != cmdline_mode->xres ||
1355 mode->vdisplay != cmdline_mode->yres)
1358 if (cmdline_mode->refresh_specified) {
1359 if (mode->vrefresh != cmdline_mode->refresh)
1363 if (cmdline_mode->interlace) {
1364 if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
1371 if (cmdline_mode->cvt)
1372 mode = drm_cvt_mode(fb_helper_conn->connector->dev,
1373 cmdline_mode->xres, cmdline_mode->yres,
1374 cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
1375 cmdline_mode->rb, cmdline_mode->interlace,
1376 cmdline_mode->margins);
1378 mode = drm_gtf_mode(fb_helper_conn->connector->dev,
1379 cmdline_mode->xres, cmdline_mode->yres,
1380 cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
1381 cmdline_mode->interlace,
1382 cmdline_mode->margins);
1383 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1384 list_add(&mode->head, &fb_helper_conn->connector->modes);
1388 static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
1393 enable = connector->status == connector_status_connected;
1395 enable = connector->status != connector_status_disconnected;
1400 static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
1403 bool any_enabled = false;
1404 struct drm_connector *connector;
1407 for (i = 0; i < fb_helper->connector_count; i++) {
1408 connector = fb_helper->connector_info[i]->connector;
1409 enabled[i] = drm_connector_enabled(connector, true);
1410 DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
1411 enabled[i] ? "yes" : "no");
1412 any_enabled |= enabled[i];
1418 for (i = 0; i < fb_helper->connector_count; i++) {
1419 connector = fb_helper->connector_info[i]->connector;
1420 enabled[i] = drm_connector_enabled(connector, false);
1424 static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
1425 struct drm_display_mode **modes,
1426 bool *enabled, int width, int height)
1429 bool can_clone = false;
1430 struct drm_fb_helper_connector *fb_helper_conn;
1431 struct drm_display_mode *dmt_mode, *mode;
1433 /* only contemplate cloning in the single crtc case */
1434 if (fb_helper->crtc_count > 1)
1438 for (i = 0; i < fb_helper->connector_count; i++) {
1443 /* only contemplate cloning if more than one connector is enabled */
1447 /* check the command line or if nothing common pick 1024x768 */
1449 for (i = 0; i < fb_helper->connector_count; i++) {
1452 fb_helper_conn = fb_helper->connector_info[i];
1453 modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1458 for (j = 0; j < i; j++) {
1461 if (!drm_mode_equal(modes[j], modes[i]))
1467 DRM_DEBUG_KMS("can clone using command line\n");
1471 /* try and find a 1024x768 mode on each connector */
1473 dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60);
1475 for (i = 0; i < fb_helper->connector_count; i++) {
1480 fb_helper_conn = fb_helper->connector_info[i];
1481 list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
1482 if (drm_mode_equal(mode, dmt_mode))
1490 DRM_DEBUG_KMS("can clone using 1024x768\n");
1493 DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
1497 static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
1498 struct drm_display_mode **modes,
1499 bool *enabled, int width, int height)
1501 struct drm_fb_helper_connector *fb_helper_conn;
1504 for (i = 0; i < fb_helper->connector_count; i++) {
1505 fb_helper_conn = fb_helper->connector_info[i];
1507 if (enabled[i] == false)
1510 DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
1511 fb_helper_conn->connector->base.id);
1513 /* got for command line mode first */
1514 modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1516 DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
1517 fb_helper_conn->connector->base.id);
1518 modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
1520 /* No preferred modes, pick one off the list */
1521 if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
1522 list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
1525 DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
1531 static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
1532 struct drm_fb_helper_crtc **best_crtcs,
1533 struct drm_display_mode **modes,
1534 int n, int width, int height)
1537 struct drm_device *dev = fb_helper->dev;
1538 struct drm_connector *connector;
1539 struct drm_connector_helper_funcs *connector_funcs;
1540 struct drm_encoder *encoder;
1541 struct drm_fb_helper_crtc *best_crtc;
1542 int my_score, best_score, score;
1543 struct drm_fb_helper_crtc **crtcs, *crtc;
1544 struct drm_fb_helper_connector *fb_helper_conn;
1546 if (n == fb_helper->connector_count)
1549 fb_helper_conn = fb_helper->connector_info[n];
1550 connector = fb_helper_conn->connector;
1552 best_crtcs[n] = NULL;
1554 best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
1555 if (modes[n] == NULL)
1558 crtcs = malloc(dev->mode_config.num_connector *
1559 sizeof(struct drm_fb_helper_crtc *), DRM_MEM_KMS,
1563 if (connector->status == connector_status_connected)
1565 if (drm_has_cmdline_mode(fb_helper_conn))
1567 if (drm_has_preferred_mode(fb_helper_conn, width, height))
1570 connector_funcs = connector->helper_private;
1571 encoder = connector_funcs->best_encoder(connector);
1575 /* select a crtc for this connector and then attempt to configure
1576 remaining connectors */
1577 for (c = 0; c < fb_helper->crtc_count; c++) {
1578 crtc = &fb_helper->crtc_info[c];
1580 if ((encoder->possible_crtcs & (1 << c)) == 0) {
1584 for (o = 0; o < n; o++)
1585 if (best_crtcs[o] == crtc)
1589 /* ignore cloning unless only a single crtc */
1590 if (fb_helper->crtc_count > 1)
1593 if (!drm_mode_equal(modes[o], modes[n]))
1598 memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
1599 score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
1601 if (score > best_score) {
1604 memcpy(best_crtcs, crtcs,
1605 dev->mode_config.num_connector *
1606 sizeof(struct drm_fb_helper_crtc *));
1610 free(crtcs, DRM_MEM_KMS);
1614 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
1616 struct drm_device *dev = fb_helper->dev;
1617 struct drm_fb_helper_crtc **crtcs;
1618 struct drm_display_mode **modes;
1619 struct drm_encoder *encoder;
1620 struct drm_mode_set *modeset;
1625 DRM_DEBUG_KMS("\n");
1627 width = dev->mode_config.max_width;
1628 height = dev->mode_config.max_height;
1630 /* clean out all the encoder/crtc combos */
1631 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1632 encoder->crtc = NULL;
1635 crtcs = malloc(dev->mode_config.num_connector *
1636 sizeof(struct drm_fb_helper_crtc *), DRM_MEM_KMS,
1638 modes = malloc(dev->mode_config.num_connector *
1639 sizeof(struct drm_display_mode *), DRM_MEM_KMS,
1641 enabled = malloc(dev->mode_config.num_connector *
1642 sizeof(bool), DRM_MEM_KMS, M_WAITOK | M_ZERO);
1644 drm_enable_connectors(fb_helper, enabled);
1646 ret = drm_target_cloned(fb_helper, modes, enabled, width, height);
1648 ret = drm_target_preferred(fb_helper, modes, enabled, width, height);
1650 DRM_ERROR("Unable to find initial modes\n");
1653 DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
1655 drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
1657 /* need to set the modesets up here for use later */
1658 /* fill out the connector<->crtc mappings into the modesets */
1659 for (i = 0; i < fb_helper->crtc_count; i++) {
1660 modeset = &fb_helper->crtc_info[i].mode_set;
1661 modeset->num_connectors = 0;
1664 for (i = 0; i < fb_helper->connector_count; i++) {
1665 struct drm_display_mode *mode = modes[i];
1666 struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
1667 modeset = &fb_crtc->mode_set;
1669 if (mode && fb_crtc) {
1670 DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
1671 mode->name, fb_crtc->mode_set.crtc->base.id);
1672 fb_crtc->desired_mode = mode;
1674 drm_mode_destroy(dev, modeset->mode);
1675 modeset->mode = drm_mode_duplicate(dev,
1676 fb_crtc->desired_mode);
1677 modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
1681 free(crtcs, DRM_MEM_KMS);
1682 free(modes, DRM_MEM_KMS);
1683 free(enabled, DRM_MEM_KMS);
1687 * drm_helper_initial_config - setup a sane initial connector configuration
1691 * Called at init time, must take mode config lock.
1693 * Scan the CRTCs and connectors and try to put together an initial setup.
1694 * At the moment, this is a cloned configuration across all heads with
1695 * a new framebuffer object as the backing store.
1698 * Zero if everything went ok, nonzero otherwise.
1700 bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1702 struct drm_device *dev = fb_helper->dev;
1705 /* disable all the possible outputs/crtcs before entering KMS mode */
1706 drm_helper_disable_unused_functions(fb_helper->dev);
1708 drm_fb_helper_parse_command_line(fb_helper);
1710 count = drm_fb_helper_probe_connector_modes(fb_helper,
1711 dev->mode_config.max_width,
1712 dev->mode_config.max_height);
1714 * we shouldn't end up with no modes here.
1717 printf("No connectors reported connected with modes\n");
1719 drm_setup_crtcs(fb_helper);
1721 return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1724 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
1726 struct drm_device *dev = fb_helper->dev;
1728 u32 max_width, max_height, bpp_sel;
1729 bool bound = false, crtcs_bound = false;
1730 struct drm_crtc *crtc;
1735 sx_xlock(&dev->mode_config.mutex);
1736 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1739 if (crtc->fb == fb_helper->fb)
1743 if (!bound && crtcs_bound) {
1744 fb_helper->delayed_hotplug = true;
1745 sx_xunlock(&dev->mode_config.mutex);
1748 DRM_DEBUG_KMS("\n");
1750 max_width = fb_helper->fb->width;
1751 max_height = fb_helper->fb->height;
1752 bpp_sel = fb_helper->fb->bits_per_pixel;
1754 count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
1756 drm_setup_crtcs(fb_helper);
1757 sx_xunlock(&dev->mode_config.mutex);
1759 return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);