Rev 3298 | Rev 3746 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3298 | Rev 3480 | ||
---|---|---|---|
Line 50... | Line 50... | ||
50 | * |
50 | * |
51 | * The fb helper functions are useful to provide an fbdev on top of a drm kernel |
51 | * The fb helper functions are useful to provide an fbdev on top of a drm kernel |
52 | * mode setting driver. They can be used mostly independantely from the crtc |
52 | * mode setting driver. They can be used mostly independantely from the crtc |
53 | * helper functions used by many drivers to implement the kernel mode setting |
53 | * helper functions used by many drivers to implement the kernel mode setting |
54 | * interfaces. |
54 | * interfaces. |
- | 55 | * |
|
- | 56 | * Initialization is done as a three-step process with drm_fb_helper_init(), |
|
- | 57 | * drm_fb_helper_single_add_all_connectors() and drm_fb_helper_initial_config(). |
|
- | 58 | * Drivers with fancier requirements than the default beheviour can override the |
|
- | 59 | * second step with their own code. Teardown is done with drm_fb_helper_fini(). |
|
- | 60 | * |
|
- | 61 | * At runtime drivers should restore the fbdev console by calling |
|
- | 62 | * drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They |
|
- | 63 | * should also notify the fb helper code from updates to the output |
|
- | 64 | * configuration by calling drm_fb_helper_hotplug_event(). For easier |
|
- | 65 | * integration with the output polling code in drm_crtc_helper.c the modeset |
|
- | 66 | * code proves a ->output_poll_changed callback. |
|
- | 67 | * |
|
- | 68 | * All other functions exported by the fb helper library can be used to |
|
- | 69 | * implement the fbdev driver interface by the driver. |
|
55 | */ |
70 | */ |
Line -... | Line 71... | ||
- | 71 | ||
- | 72 | /** |
|
- | 73 | * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev |
|
- | 74 | * emulation helper |
|
- | 75 | * @fb_helper: fbdev initialized with drm_fb_helper_init |
|
- | 76 | * |
|
- | 77 | * This functions adds all the available connectors for use with the given |
|
- | 78 | * fb_helper. This is a separate step to allow drivers to freely assign |
|
56 | 79 | * connectors to the fbdev, e.g. if some are reserved for special purposes or |
|
- | 80 | * not adequate to be used for the fbcon. |
|
- | 81 | * |
|
- | 82 | * Since this is part of the initial setup before the fbdev is published, no |
|
- | 83 | * locking is required. |
|
57 | /* simple single crtc case helper function */ |
84 | */ |
58 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) |
85 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) |
59 | { |
86 | { |
60 | struct drm_device *dev = fb_helper->dev; |
87 | struct drm_device *dev = fb_helper->dev; |
61 | struct drm_connector *connector; |
88 | struct drm_connector *connector; |
Line 108... | Line 135... | ||
108 | 135 | ||
109 | crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); |
136 | crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); |
Line -... | Line 137... | ||
- | 137 | } |
|
- | 138 | ||
- | 139 | ||
- | 140 | static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) |
|
- | 141 | { |
|
- | 142 | struct drm_device *dev = fb_helper->dev; |
|
- | 143 | struct drm_crtc *crtc; |
|
- | 144 | int bound = 0, crtcs_bound = 0; |
|
- | 145 | ||
- | 146 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
|
- | 147 | if (crtc->fb) |
|
- | 148 | crtcs_bound++; |
|
- | 149 | if (crtc->fb == fb_helper->fb) |
|
- | 150 | bound++; |
|
- | 151 | } |
|
- | 152 | ||
- | 153 | if (bound < crtcs_bound) |
|
Line 110... | Line 154... | ||
110 | } |
154 | return false; |
111 | 155 | return true; |
|
112 | 156 | } |
|
113 | 157 | ||
114 | static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) |
158 | static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) |
115 | { |
159 | { |
116 | struct drm_fb_helper *fb_helper = info->par; |
160 | struct drm_fb_helper *fb_helper = info->par; |
Line 117... | Line 161... | ||
117 | struct drm_device *dev = fb_helper->dev; |
161 | struct drm_device *dev = fb_helper->dev; |
- | 162 | struct drm_crtc *crtc; |
|
- | 163 | struct drm_connector *connector; |
|
- | 164 | int i, j; |
|
- | 165 | ||
- | 166 | /* |
|
- | 167 | * fbdev->blank can be called from irq context in case of a panic. |
|
118 | struct drm_crtc *crtc; |
168 | * Since we already have our own special panic handler which will |
119 | struct drm_connector *connector; |
169 | * restore the fbdev console mode completely, just bail out early. |
- | 170 | */ |
|
- | 171 | ||
120 | int i, j; |
172 | /* |
- | 173 | * For each CRTC in this fb, turn the connectors on/off. |
|
- | 174 | */ |
|
- | 175 | drm_modeset_lock_all(dev); |
|
121 | 176 | if (!drm_fb_helper_is_bound(fb_helper)) { |
|
122 | /* |
177 | drm_modeset_unlock_all(dev); |
Line 123... | Line 178... | ||
123 | * For each CRTC in this fb, turn the connectors on/off. |
178 | return; |
124 | */ |
179 | } |
Line 135... | Line 190... | ||
135 | connector->funcs->dpms(connector, dpms_mode); |
190 | connector->funcs->dpms(connector, dpms_mode); |
136 | drm_object_property_set_value(&connector->base, |
191 | drm_object_property_set_value(&connector->base, |
137 | dev->mode_config.dpms_property, dpms_mode); |
192 | dev->mode_config.dpms_property, dpms_mode); |
138 | } |
193 | } |
139 | } |
194 | } |
140 | mutex_unlock(&dev->mode_config.mutex); |
195 | drm_modeset_unlock_all(dev); |
141 | } |
196 | } |
Line -... | Line 197... | ||
- | 197 | ||
- | 198 | /** |
|
- | 199 | * drm_fb_helper_blank - implementation for ->fb_blank |
|
- | 200 | * @blank: desired blanking state |
|
- | 201 | * @info: fbdev registered by the helper |
|
142 | 202 | */ |
|
143 | int drm_fb_helper_blank(int blank, struct fb_info *info) |
203 | int drm_fb_helper_blank(int blank, struct fb_info *info) |
144 | { |
204 | { |
145 | switch (blank) { |
205 | switch (blank) { |
146 | /* Display: On; HSync: On, VSync: On */ |
206 | /* Display: On; HSync: On, VSync: On */ |
Line 181... | Line 241... | ||
181 | drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode); |
241 | drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode); |
182 | } |
242 | } |
183 | kfree(helper->crtc_info); |
243 | kfree(helper->crtc_info); |
184 | } |
244 | } |
Line -... | Line 245... | ||
- | 245 | ||
- | 246 | /** |
|
- | 247 | * drm_fb_helper_init - initialize a drm_fb_helper structure |
|
- | 248 | * @dev: drm device |
|
- | 249 | * @fb_helper: driver-allocated fbdev helper structure to initialize |
|
- | 250 | * @crtc_count: maximum number of crtcs to support in this fbdev emulation |
|
- | 251 | * @max_conn_count: max connector count |
|
- | 252 | * |
|
- | 253 | * This allocates the structures for the fbdev helper with the given limits. |
|
- | 254 | * Note that this won't yet touch the hardware (through the driver interfaces) |
|
- | 255 | * nor register the fbdev. This is only done in drm_fb_helper_initial_config() |
|
- | 256 | * to allow driver writes more control over the exact init sequence. |
|
- | 257 | * |
|
- | 258 | * Drivers must set fb_helper->funcs before calling |
|
- | 259 | * drm_fb_helper_initial_config(). |
|
- | 260 | * |
|
- | 261 | * RETURNS: |
|
- | 262 | * Zero if everything went ok, nonzero otherwise. |
|
185 | 263 | */ |
|
186 | int drm_fb_helper_init(struct drm_device *dev, |
264 | int drm_fb_helper_init(struct drm_device *dev, |
187 | struct drm_fb_helper *fb_helper, |
265 | struct drm_fb_helper *fb_helper, |
188 | int crtc_count, int max_conn_count) |
266 | int crtc_count, int max_conn_count) |
189 | { |
267 | { |
Line 292... | Line 370... | ||
292 | if (fb->depth != 16) |
370 | if (fb->depth != 16) |
293 | fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex); |
371 | fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex); |
294 | return 0; |
372 | return 0; |
295 | } |
373 | } |
Line -... | Line 374... | ||
- | 374 | ||
- | 375 | /** |
|
- | 376 | * drm_fb_helper_setcmap - implementation for ->fb_setcmap |
|
- | 377 | * @cmap: cmap to set |
|
- | 378 | * @info: fbdev registered by the helper |
|
296 | 379 | */ |
|
297 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) |
380 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) |
298 | { |
381 | { |
299 | struct drm_fb_helper *fb_helper = info->par; |
382 | struct drm_fb_helper *fb_helper = info->par; |
300 | struct drm_crtc_helper_funcs *crtc_funcs; |
383 | struct drm_crtc_helper_funcs *crtc_funcs; |
Line 331... | Line 414... | ||
331 | } |
414 | } |
332 | return rc; |
415 | return rc; |
333 | } |
416 | } |
334 | EXPORT_SYMBOL(drm_fb_helper_setcmap); |
417 | EXPORT_SYMBOL(drm_fb_helper_setcmap); |
Line -... | Line 418... | ||
- | 418 | ||
- | 419 | /** |
|
- | 420 | * drm_fb_helper_check_var - implementation for ->fb_check_var |
|
- | 421 | * @var: screeninfo to check |
|
- | 422 | * @info: fbdev registered by the helper |
|
335 | 423 | */ |
|
336 | int drm_fb_helper_check_var(struct fb_var_screeninfo *var, |
424 | int drm_fb_helper_check_var(struct fb_var_screeninfo *var, |
337 | struct fb_info *info) |
425 | struct fb_info *info) |
338 | { |
426 | { |
339 | struct drm_fb_helper *fb_helper = info->par; |
427 | struct drm_fb_helper *fb_helper = info->par; |
Line 423... | Line 511... | ||
423 | } |
511 | } |
424 | return 0; |
512 | return 0; |
425 | } |
513 | } |
426 | EXPORT_SYMBOL(drm_fb_helper_check_var); |
514 | EXPORT_SYMBOL(drm_fb_helper_check_var); |
Line -... | Line 515... | ||
- | 515 | ||
- | 516 | /** |
|
- | 517 | * drm_fb_helper_set_par - implementation for ->fb_set_par |
|
- | 518 | * @info: fbdev registered by the helper |
|
427 | 519 | * |
|
- | 520 | * This will let fbcon do the mode init and is called at initialization time by |
|
- | 521 | * the fbdev core when registering the driver, and later on through the hotplug |
|
- | 522 | * callback. |
|
428 | /* this will let fbcon do the mode init */ |
523 | */ |
429 | int drm_fb_helper_set_par(struct fb_info *info) |
524 | int drm_fb_helper_set_par(struct fb_info *info) |
430 | { |
525 | { |
431 | struct drm_fb_helper *fb_helper = info->par; |
526 | struct drm_fb_helper *fb_helper = info->par; |
432 | struct drm_device *dev = fb_helper->dev; |
527 | struct drm_device *dev = fb_helper->dev; |
433 | struct fb_var_screeninfo *var = &info->var; |
- | |
434 | struct drm_crtc *crtc; |
528 | struct fb_var_screeninfo *var = &info->var; |
435 | int ret; |
529 | int ret; |
Line 436... | Line 530... | ||
436 | int i; |
530 | int i; |
437 | 531 | ||
438 | if (var->pixclock != 0) { |
532 | if (var->pixclock != 0) { |
439 | DRM_ERROR("PIXEL CLOCK SET\n"); |
533 | DRM_ERROR("PIXEL CLOCK SET\n"); |
Line 440... | Line 534... | ||
440 | return -EINVAL; |
534 | return -EINVAL; |
441 | } |
535 | } |
442 | - | ||
443 | mutex_lock(&dev->mode_config.mutex); |
536 | |
444 | for (i = 0; i < fb_helper->crtc_count; i++) { |
537 | drm_modeset_lock_all(dev); |
445 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
538 | for (i = 0; i < fb_helper->crtc_count; i++) { |
446 | ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); |
539 | ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set); |
447 | if (ret) { |
540 | if (ret) { |
448 | mutex_unlock(&dev->mode_config.mutex); |
541 | drm_modeset_unlock_all(dev); |
449 | return ret; |
542 | return ret; |
Line 450... | Line 543... | ||
450 | } |
543 | } |
451 | } |
544 | } |
452 | mutex_unlock(&dev->mode_config.mutex); |
545 | drm_modeset_unlock_all(dev); |
453 | 546 | ||
454 | if (fb_helper->delayed_hotplug) { |
547 | if (fb_helper->delayed_hotplug) { |
455 | fb_helper->delayed_hotplug = false; |
548 | fb_helper->delayed_hotplug = false; |
456 | // drm_fb_helper_hotplug_event(fb_helper); |
549 | drm_fb_helper_hotplug_event(fb_helper); |
Line -... | Line 550... | ||
- | 550 | } |
|
- | 551 | return 0; |
|
- | 552 | } |
|
- | 553 | EXPORT_SYMBOL(drm_fb_helper_set_par); |
|
- | 554 | ||
457 | } |
555 | /** |
458 | return 0; |
556 | * drm_fb_helper_pan_display - implementation for ->fb_pan_display |
459 | } |
557 | * @var: updated screen information |
460 | EXPORT_SYMBOL(drm_fb_helper_set_par); |
558 | * @info: fbdev registered by the helper |
461 | 559 | */ |
|
462 | int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, |
560 | int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, |
463 | struct fb_info *info) |
561 | struct fb_info *info) |
464 | { |
562 | { |
465 | struct drm_fb_helper *fb_helper = info->par; |
563 | struct drm_fb_helper *fb_helper = info->par; |
Line -... | Line 564... | ||
- | 564 | struct drm_device *dev = fb_helper->dev; |
|
- | 565 | struct drm_mode_set *modeset; |
|
466 | struct drm_device *dev = fb_helper->dev; |
566 | struct drm_crtc *crtc; |
- | 567 | int ret = 0; |
|
- | 568 | int i; |
|
- | 569 | ||
467 | struct drm_mode_set *modeset; |
570 | drm_modeset_lock_all(dev); |
468 | struct drm_crtc *crtc; |
571 | if (!drm_fb_helper_is_bound(fb_helper)) { |
Line 469... | Line 572... | ||
469 | int ret = 0; |
572 | drm_modeset_unlock_all(dev); |
Line 470... | Line 573... | ||
470 | int i; |
573 | return -EBUSY; |
471 | 574 | } |
|
Line 472... | Line 575... | ||
472 | mutex_lock(&dev->mode_config.mutex); |
575 | |
473 | for (i = 0; i < fb_helper->crtc_count; i++) { |
576 | for (i = 0; i < fb_helper->crtc_count; i++) { |
474 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
577 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
475 | 578 | ||
476 | modeset = &fb_helper->crtc_info[i].mode_set; |
579 | modeset = &fb_helper->crtc_info[i].mode_set; |
477 | 580 | ||
478 | modeset->x = var->xoffset; |
581 | modeset->x = var->xoffset; |
479 | modeset->y = var->yoffset; |
582 | modeset->y = var->yoffset; |
480 | 583 | ||
481 | if (modeset->num_connectors) { |
584 | if (modeset->num_connectors) { |
482 | ret = crtc->funcs->set_config(modeset); |
585 | ret = drm_mode_set_config_internal(modeset); |
483 | if (!ret) { |
586 | if (!ret) { |
Line -... | Line 587... | ||
- | 587 | info->var.xoffset = var->xoffset; |
|
- | 588 | info->var.yoffset = var->yoffset; |
|
- | 589 | } |
|
- | 590 | } |
|
- | 591 | } |
|
484 | info->var.xoffset = var->xoffset; |
592 | drm_modeset_unlock_all(dev); |
485 | info->var.yoffset = var->yoffset; |
593 | return ret; |
486 | } |
594 | } |
487 | } |
595 | EXPORT_SYMBOL(drm_fb_helper_pan_display); |
488 | } |
596 | |
489 | mutex_unlock(&dev->mode_config.mutex); |
597 | /* |
490 | return ret; |
598 | * Allocates the backing storage and sets up the fbdev info structure through |
491 | } |
599 | * the ->fb_probe callback and then registers the fbdev and sets up the panic |
492 | EXPORT_SYMBOL(drm_fb_helper_pan_display); |
600 | * notifier. |
Line 570... | Line 678... | ||
570 | sizes.fb_width = sizes.surface_width = 1024; |
678 | sizes.fb_width = sizes.surface_width = 1024; |
571 | sizes.fb_height = sizes.surface_height = 768; |
679 | sizes.fb_height = sizes.surface_height = 768; |
572 | } |
680 | } |
Line 573... | Line 681... | ||
573 | 681 | ||
574 | /* push down into drivers */ |
682 | /* push down into drivers */ |
575 | new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes); |
683 | ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes); |
576 | if (new_fb < 0) |
684 | if (ret < 0) |
Line 577... | Line 685... | ||
577 | return new_fb; |
685 | return ret; |
Line -... | Line 686... | ||
- | 686 | ||
- | 687 | info = fb_helper->fbdev; |
|
- | 688 | ||
- | 689 | /* |
|
- | 690 | * Set the fb pointer - usually drm_setup_crtcs does this for hotplug |
|
578 | 691 | * events, but at init time drm_setup_crtcs needs to be called before |
|
- | 692 | * the fb is allocated (since we need to figure out the desired size of |
|
579 | info = fb_helper->fbdev; |
693 | * the fb before we can allocate it ...). Hence we need to fix things up |
- | 694 | * here again. |
|
580 | 695 | */ |
|
Line 581... | Line -... | ||
581 | /* set the fb pointer */ |
- | |
582 | for (i = 0; i < fb_helper->crtc_count; i++) |
- | |
583 | fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; |
- | |
584 | - | ||
585 | if (new_fb) { |
- | |
586 | info->var.pixclock = 0; |
- | |
587 | - | ||
588 | // dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n", |
- | |
589 | // info->node, info->fix.id); |
- | |
Line -... | Line 696... | ||
- | 696 | for (i = 0; i < fb_helper->crtc_count; i++) |
|
Line 590... | Line -... | ||
590 | - | ||
591 | } else { |
697 | if (fb_helper->crtc_info[i].mode_set.num_connectors) |
Line 592... | Line 698... | ||
592 | drm_fb_helper_set_par(info); |
698 | fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; |
593 | } |
699 | |
594 | - | ||
Line -... | Line 700... | ||
- | 700 | ||
- | 701 | info->var.pixclock = 0; |
|
- | 702 | ||
- | 703 | list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); |
|
- | 704 | ||
- | 705 | return 0; |
|
- | 706 | } |
|
- | 707 | ||
- | 708 | /** |
|
- | 709 | * drm_fb_helper_fill_fix - initializes fixed fbdev information |
|
- | 710 | * @info: fbdev registered by the helper |
|
- | 711 | * @pitch: desired pitch |
|
- | 712 | * @depth: desired depth |
|
595 | 713 | * |
|
596 | if (new_fb) |
714 | * Helper to fill in the fixed fbdev information useful for a non-accelerated |
597 | list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); |
715 | * fbdev emulations. Drivers which support acceleration methods which impose |
598 | 716 | * additional constraints need to set up their own limits. |
|
599 | return 0; |
717 | * |
Line 618... | Line 736... | ||
618 | info->fix.line_length = pitch; |
736 | info->fix.line_length = pitch; |
619 | return; |
737 | return; |
620 | } |
738 | } |
621 | EXPORT_SYMBOL(drm_fb_helper_fill_fix); |
739 | EXPORT_SYMBOL(drm_fb_helper_fill_fix); |
Line -... | Line 740... | ||
- | 740 | ||
- | 741 | /** |
|
- | 742 | * drm_fb_helper_fill_var - initalizes variable fbdev information |
|
- | 743 | * @info: fbdev instance to set up |
|
- | 744 | * @fb_helper: fb helper instance to use as template |
|
- | 745 | * @fb_width: desired fb width |
|
- | 746 | * @fb_height: desired fb height |
|
- | 747 | * |
|
- | 748 | * Sets up the variable fbdev metainformation from the given fb helper instance |
|
- | 749 | * and the drm framebuffer allocated in fb_helper->fb. |
|
- | 750 | * |
|
- | 751 | * Drivers should call this (or their equivalent setup code) from their |
|
- | 752 | * ->fb_probe callback after having allocated the fbdev backing |
|
- | 753 | * storage framebuffer. |
|
622 | 754 | */ |
|
623 | void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, |
755 | void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, |
624 | uint32_t fb_width, uint32_t fb_height) |
756 | uint32_t fb_width, uint32_t fb_height) |
625 | { |
757 | { |
626 | struct drm_framebuffer *fb = fb_helper->fb; |
758 | struct drm_framebuffer *fb = fb_helper->fb; |
Line 935... | Line 1067... | ||
935 | /* need to set the modesets up here for use later */ |
1067 | /* need to set the modesets up here for use later */ |
936 | /* fill out the connector<->crtc mappings into the modesets */ |
1068 | /* fill out the connector<->crtc mappings into the modesets */ |
937 | for (i = 0; i < fb_helper->crtc_count; i++) { |
1069 | for (i = 0; i < fb_helper->crtc_count; i++) { |
938 | modeset = &fb_helper->crtc_info[i].mode_set; |
1070 | modeset = &fb_helper->crtc_info[i].mode_set; |
939 | modeset->num_connectors = 0; |
1071 | modeset->num_connectors = 0; |
- | 1072 | modeset->fb = NULL; |
|
940 | } |
1073 | } |
Line 941... | Line 1074... | ||
941 | 1074 | ||
942 | for (i = 0; i < fb_helper->connector_count; i++) { |
1075 | for (i = 0; i < fb_helper->connector_count; i++) { |
943 | struct drm_display_mode *mode = modes[i]; |
1076 | struct drm_display_mode *mode = modes[i]; |
Line 951... | Line 1084... | ||
951 | if (modeset->mode) |
1084 | if (modeset->mode) |
952 | drm_mode_destroy(dev, modeset->mode); |
1085 | drm_mode_destroy(dev, modeset->mode); |
953 | modeset->mode = drm_mode_duplicate(dev, |
1086 | modeset->mode = drm_mode_duplicate(dev, |
954 | fb_crtc->desired_mode); |
1087 | fb_crtc->desired_mode); |
955 | modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; |
1088 | modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; |
- | 1089 | modeset->fb = fb_helper->fb; |
|
956 | } |
1090 | } |
957 | } |
1091 | } |
Line -... | Line 1092... | ||
- | 1092 | ||
- | 1093 | /* Clear out any old modes if there are no more connected outputs. */ |
|
- | 1094 | for (i = 0; i < fb_helper->crtc_count; i++) { |
|
- | 1095 | modeset = &fb_helper->crtc_info[i].mode_set; |
|
- | 1096 | if (modeset->num_connectors == 0) { |
|
- | 1097 | BUG_ON(modeset->fb); |
|
- | 1098 | BUG_ON(modeset->num_connectors); |
|
- | 1099 | if (modeset->mode) |
|
- | 1100 | drm_mode_destroy(dev, modeset->mode); |
|
- | 1101 | modeset->mode = NULL; |
|
- | 1102 | } |
|
958 | 1103 | } |
|
959 | out: |
1104 | out: |
960 | kfree(crtcs); |
1105 | kfree(crtcs); |
961 | kfree(modes); |
1106 | kfree(modes); |
962 | kfree(enabled); |
1107 | kfree(enabled); |
Line 963... | Line 1108... | ||
963 | } |
1108 | } |
964 | 1109 | ||
965 | /** |
1110 | /** |
966 | * drm_helper_initial_config - setup a sane initial connector configuration |
1111 | * drm_fb_helper_initial_config - setup a sane initial connector configuration |
967 | * @fb_helper: fb_helper device struct |
1112 | * @fb_helper: fb_helper device struct |
968 | * @bpp_sel: bpp value to use for the framebuffer configuration |
- | |
969 | * |
- | |
970 | * LOCKING: |
- | |
971 | * Called at init time by the driver to set up the @fb_helper initial |
- | |
972 | * configuration, must take the mode config lock. |
1113 | * @bpp_sel: bpp value to use for the framebuffer configuration |
973 | * |
1114 | * |
974 | * Scans the CRTCs and connectors and tries to put together an initial setup. |
1115 | * Scans the CRTCs and connectors and tries to put together an initial setup. |
975 | * At the moment, this is a cloned configuration across all heads with |
1116 | * At the moment, this is a cloned configuration across all heads with |
- | 1117 | * a new framebuffer object as the backing store. |
|
- | 1118 | * |
|
- | 1119 | * Note that this also registers the fbdev and so allows userspace to call into |
|
- | 1120 | * the driver through the fbdev interfaces. |
|
- | 1121 | * |
|
- | 1122 | * This function will call down into the ->fb_probe callback to let |
|
- | 1123 | * the driver allocate and initialize the fbdev info structure and the drm |
|
- | 1124 | * framebuffer used to back the fbdev. drm_fb_helper_fill_var() and |
|
- | 1125 | * drm_fb_helper_fill_fix() are provided as helpers to setup simple default |
|
976 | * a new framebuffer object as the backing store. |
1126 | * values for the fbdev info structure. |
977 | * |
1127 | * |
978 | * RETURNS: |
1128 | * RETURNS: |
979 | * Zero if everything went ok, nonzero otherwise. |
1129 | * Zero if everything went ok, nonzero otherwise. |
980 | */ |
1130 | */ |
981 | bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) |
1131 | bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) |
982 | { |
1132 | { |
Line 983... | Line -... | ||
983 | struct drm_device *dev = fb_helper->dev; |
- | |
984 | int count = 0; |
- | |
985 | - | ||
986 | /* disable all the possible outputs/crtcs before entering KMS mode */ |
1133 | struct drm_device *dev = fb_helper->dev; |
Line 987... | Line 1134... | ||
987 | drm_helper_disable_unused_functions(fb_helper->dev); |
1134 | int count = 0; |
988 | 1135 | ||
989 | // drm_fb_helper_parse_command_line(fb_helper); |
1136 | // drm_fb_helper_parse_command_line(fb_helper); |
Line 1001... | Line 1148... | ||
1001 | 1148 | ||
1002 | return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); |
1149 | return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); |
1003 | } |
1150 | } |
Line 1004... | Line -... | ||
1004 | EXPORT_SYMBOL(drm_fb_helper_initial_config); |
- | |
1005 | 1151 | EXPORT_SYMBOL(drm_fb_helper_initial_config); |
|
1006 | #if 0 |
1152 | |
1007 | /** |
1153 | /** |
1008 | * drm_fb_helper_hotplug_event - respond to a hotplug notification by |
1154 | * drm_fb_helper_hotplug_event - respond to a hotplug notification by |
1009 | * probing all the outputs attached to the fb |
1155 | * probing all the outputs attached to the fb |
1010 | * @fb_helper: the drm_fb_helper |
- | |
1011 | * |
- | |
1012 | * LOCKING: |
- | |
1013 | * Called at runtime, must take mode config lock. |
1156 | * @fb_helper: the drm_fb_helper |
1014 | * |
1157 | * |
1015 | * Scan the connectors attached to the fb_helper and try to put together a |
1158 | * Scan the connectors attached to the fb_helper and try to put together a |
- | 1159 | * setup after *notification of a change in output configuration. |
|
- | 1160 | * |
|
- | 1161 | * Called at runtime, takes the mode config locks to be able to check/change the |
|
- | 1162 | * modeset configuration. Must be run from process context (which usually means |
|
- | 1163 | * either the output polling work or a work item launched from the driver's |
|
- | 1164 | * hotplug interrupt). |
|
- | 1165 | * |
|
- | 1166 | * Note that the driver must ensure that this is only called _after_ the fb has |
|
1016 | * setup after *notification of a change in output configuration. |
1167 | * been fully set up, i.e. after the call to drm_fb_helper_initial_config. |
1017 | * |
1168 | * |
1018 | * RETURNS: |
1169 | * RETURNS: |
1019 | * 0 on success and a non-zero error code otherwise. |
1170 | * 0 on success and a non-zero error code otherwise. |
1020 | */ |
1171 | */ |
1021 | int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) |
1172 | int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) |
1022 | { |
1173 | { |
1023 | struct drm_device *dev = fb_helper->dev; |
1174 | struct drm_device *dev = fb_helper->dev; |
1024 | int count = 0; |
- | |
1025 | u32 max_width, max_height, bpp_sel; |
- | |
Line 1026... | Line 1175... | ||
1026 | int bound = 0, crtcs_bound = 0; |
1175 | int count = 0; |
1027 | struct drm_crtc *crtc; |
1176 | u32 max_width, max_height, bpp_sel; |
Line 1028... | Line 1177... | ||
1028 | 1177 | ||
1029 | if (!fb_helper->fb) |
- | |
1030 | return 0; |
- | |
1031 | - | ||
1032 | mutex_lock(&dev->mode_config.mutex); |
- | |
1033 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
- | |
1034 | if (crtc->fb) |
- | |
1035 | crtcs_bound++; |
- | |
1036 | if (crtc->fb == fb_helper->fb) |
1178 | if (!fb_helper->fb) |
1037 | bound++; |
1179 | return 0; |
1038 | } |
1180 | |
1039 | 1181 | mutex_lock(&fb_helper->dev->mode_config.mutex); |
|
1040 | if (bound < crtcs_bound) { |
1182 | if (!drm_fb_helper_is_bound(fb_helper)) { |
1041 | fb_helper->delayed_hotplug = true; |
1183 | fb_helper->delayed_hotplug = true; |
Line 1042... | Line 1184... | ||
1042 | mutex_unlock(&dev->mode_config.mutex); |
1184 | mutex_unlock(&fb_helper->dev->mode_config.mutex); |
1043 | return 0; |
1185 | return 0; |
1044 | } |
1186 | } |
Line 1045... | Line 1187... | ||
1045 | DRM_DEBUG_KMS("\n"); |
1187 | DRM_DEBUG_KMS("\n"); |
1046 | 1188 | ||
- | 1189 | max_width = fb_helper->fb->width; |
|
- | 1190 | max_height = fb_helper->fb->height; |
|
- | 1191 | bpp_sel = fb_helper->fb->bits_per_pixel; |
|
1047 | max_width = fb_helper->fb->width; |
1192 | |
- | 1193 | count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, |
|
1048 | max_height = fb_helper->fb->height; |
1194 | max_height); |
Line 1049... | Line 1195... | ||
1049 | bpp_sel = fb_helper->fb->bits_per_pixel; |
1195 | mutex_unlock(&fb_helper->dev->mode_config.mutex); |
1050 | 1196 | ||
1051 | count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, |
1197 | drm_modeset_lock_all(dev); |
1052 | max_height); |
- |