This source file includes following definitions.
- drm_fb_helper_restore_lut_atomic
- drm_fb_helper_debug_enter
- drm_fb_helper_debug_leave
- drm_fb_helper_restore_fbdev_mode_unlocked
- drm_fb_helper_force_kernel_mode
- drm_fb_helper_restore_work_fn
- drm_fb_helper_sysrq
- drm_fb_helper_dpms
- drm_fb_helper_blank
- drm_fb_helper_resume_worker
- drm_fb_helper_dirty_blit_real
- drm_fb_helper_dirty_work
- drm_fb_helper_prepare
- drm_fb_helper_init
- drm_fb_helper_alloc_fbi
- drm_fb_helper_unregister_fbi
- drm_fb_helper_fini
- drm_fb_helper_unlink_fbi
- drm_fbdev_use_shadow_fb
- drm_fb_helper_dirty
- drm_fb_helper_deferred_io
- drm_fb_helper_defio_init
- drm_fb_helper_sys_read
- drm_fb_helper_sys_write
- drm_fb_helper_sys_fillrect
- drm_fb_helper_sys_copyarea
- drm_fb_helper_sys_imageblit
- drm_fb_helper_cfb_fillrect
- drm_fb_helper_cfb_copyarea
- drm_fb_helper_cfb_imageblit
- drm_fb_helper_set_suspend
- drm_fb_helper_set_suspend_unlocked
- setcmap_pseudo_palette
- setcmap_legacy
- setcmap_new_gamma_lut
- setcmap_atomic
- drm_fb_helper_setcmap
- drm_fb_helper_ioctl
- drm_fb_pixel_format_equal
- drm_fb_helper_fill_pixel_fmt
- drm_fb_helper_check_var
- drm_fb_helper_set_par
- pan_set
- pan_display_atomic
- pan_display_legacy
- drm_fb_helper_pan_display
- drm_fb_helper_single_fb_probe
- drm_fb_helper_fill_fix
- drm_fb_helper_fill_var
- drm_fb_helper_fill_info
- drm_setup_crtcs_fb
- __drm_fb_helper_initial_config_and_unlock
- drm_fb_helper_initial_config
- drm_fb_helper_hotplug_event
- drm_fb_helper_fbdev_setup
- drm_fb_helper_fbdev_teardown
- drm_fb_helper_lastclose
- drm_fb_helper_output_poll_changed
- drm_fbdev_fb_open
- drm_fbdev_fb_release
- drm_fbdev_cleanup
- drm_fbdev_release
- drm_fbdev_fb_destroy
- drm_fbdev_fb_mmap
- drm_fb_helper_generic_probe
- drm_fbdev_client_unregister
- drm_fbdev_client_restore
- drm_fbdev_client_hotplug
- drm_fbdev_generic_setup
- drm_fb_helper_modinit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31
32 #include <linux/console.h>
33 #include <linux/dma-buf.h>
34 #include <linux/kernel.h>
35 #include <linux/module.h>
36 #include <linux/slab.h>
37 #include <linux/sysrq.h>
38 #include <linux/vmalloc.h>
39
40 #include <drm/drm_atomic.h>
41 #include <drm/drm_crtc.h>
42 #include <drm/drm_crtc_helper.h>
43 #include <drm/drm_drv.h>
44 #include <drm/drm_fb_helper.h>
45 #include <drm/drm_fourcc.h>
46 #include <drm/drm_print.h>
47 #include <drm/drm_vblank.h>
48
49 #include "drm_internal.h"
50
51 static bool drm_fbdev_emulation = true;
52 module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
53 MODULE_PARM_DESC(fbdev_emulation,
54 "Enable legacy fbdev emulation [default=true]");
55
56 static int drm_fbdev_overalloc = CONFIG_DRM_FBDEV_OVERALLOC;
57 module_param(drm_fbdev_overalloc, int, 0444);
58 MODULE_PARM_DESC(drm_fbdev_overalloc,
59 "Overallocation of the fbdev buffer (%) [default="
60 __MODULE_STRING(CONFIG_DRM_FBDEV_OVERALLOC) "]");
61
62
63
64
65
66
67
68
69
70
71
72
73
74 #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
75 static bool drm_leak_fbdev_smem = false;
76 module_param_unsafe(drm_leak_fbdev_smem, bool, 0600);
77 MODULE_PARM_DESC(drm_leak_fbdev_smem,
78 "Allow unsafe leaking fbdev physical smem address [default=false]");
79 #endif
80
81 static LIST_HEAD(kernel_fb_helper_list);
82 static DEFINE_MUTEX(kernel_fb_helper_lock);
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
134 {
135 uint16_t *r_base, *g_base, *b_base;
136
137 if (crtc->funcs->gamma_set == NULL)
138 return;
139
140 r_base = crtc->gamma_store;
141 g_base = r_base + crtc->gamma_size;
142 b_base = g_base + crtc->gamma_size;
143
144 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base,
145 crtc->gamma_size, NULL);
146 }
147
148
149
150
151
152 int drm_fb_helper_debug_enter(struct fb_info *info)
153 {
154 struct drm_fb_helper *helper = info->par;
155 const struct drm_crtc_helper_funcs *funcs;
156 struct drm_mode_set *mode_set;
157
158 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
159 mutex_lock(&helper->client.modeset_mutex);
160 drm_client_for_each_modeset(mode_set, &helper->client) {
161 if (!mode_set->crtc->enabled)
162 continue;
163
164 funcs = mode_set->crtc->helper_private;
165 if (funcs->mode_set_base_atomic == NULL)
166 continue;
167
168 if (drm_drv_uses_atomic_modeset(mode_set->crtc->dev))
169 continue;
170
171 funcs->mode_set_base_atomic(mode_set->crtc,
172 mode_set->fb,
173 mode_set->x,
174 mode_set->y,
175 ENTER_ATOMIC_MODE_SET);
176 }
177 mutex_unlock(&helper->client.modeset_mutex);
178 }
179
180 return 0;
181 }
182 EXPORT_SYMBOL(drm_fb_helper_debug_enter);
183
184
185
186
187
188 int drm_fb_helper_debug_leave(struct fb_info *info)
189 {
190 struct drm_fb_helper *helper = info->par;
191 struct drm_client_dev *client = &helper->client;
192 struct drm_crtc *crtc;
193 const struct drm_crtc_helper_funcs *funcs;
194 struct drm_mode_set *mode_set;
195 struct drm_framebuffer *fb;
196
197 mutex_lock(&client->modeset_mutex);
198 drm_client_for_each_modeset(mode_set, client) {
199 crtc = mode_set->crtc;
200 if (drm_drv_uses_atomic_modeset(crtc->dev))
201 continue;
202
203 funcs = crtc->helper_private;
204 fb = crtc->primary->fb;
205
206 if (!crtc->enabled)
207 continue;
208
209 if (!fb) {
210 DRM_ERROR("no fb to restore??\n");
211 continue;
212 }
213
214 if (funcs->mode_set_base_atomic == NULL)
215 continue;
216
217 drm_fb_helper_restore_lut_atomic(mode_set->crtc);
218 funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
219 crtc->y, LEAVE_ATOMIC_MODE_SET);
220 }
221 mutex_unlock(&client->modeset_mutex);
222
223 return 0;
224 }
225 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
226
227
228
229
230
231
232
233
234
235
236
237
238 int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
239 {
240 bool do_delayed;
241 int ret;
242
243 if (!drm_fbdev_emulation || !fb_helper)
244 return -ENODEV;
245
246 if (READ_ONCE(fb_helper->deferred_setup))
247 return 0;
248
249 mutex_lock(&fb_helper->lock);
250
251
252
253
254
255
256
257
258
259
260 ret = drm_client_modeset_commit_force(&fb_helper->client);
261
262 do_delayed = fb_helper->delayed_hotplug;
263 if (do_delayed)
264 fb_helper->delayed_hotplug = false;
265 mutex_unlock(&fb_helper->lock);
266
267 if (do_delayed)
268 drm_fb_helper_hotplug_event(fb_helper);
269
270 return ret;
271 }
272 EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
273
274 #ifdef CONFIG_MAGIC_SYSRQ
275
276
277
278
279 static bool drm_fb_helper_force_kernel_mode(void)
280 {
281 bool ret, error = false;
282 struct drm_fb_helper *helper;
283
284 if (list_empty(&kernel_fb_helper_list))
285 return false;
286
287 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
288 struct drm_device *dev = helper->dev;
289
290 if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
291 continue;
292
293 mutex_lock(&helper->lock);
294 ret = drm_client_modeset_commit_force(&helper->client);
295 if (ret)
296 error = true;
297 mutex_unlock(&helper->lock);
298 }
299 return error;
300 }
301
302 static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
303 {
304 bool ret;
305
306 ret = drm_fb_helper_force_kernel_mode();
307 if (ret == true)
308 DRM_ERROR("Failed to restore crtc configuration\n");
309 }
310 static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
311
312 static void drm_fb_helper_sysrq(int dummy1)
313 {
314 schedule_work(&drm_fb_helper_restore_work);
315 }
316
317 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
318 .handler = drm_fb_helper_sysrq,
319 .help_msg = "force-fb(V)",
320 .action_msg = "Restore framebuffer console",
321 };
322 #else
323 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
324 #endif
325
326 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
327 {
328 struct drm_fb_helper *fb_helper = info->par;
329
330 mutex_lock(&fb_helper->lock);
331 drm_client_modeset_dpms(&fb_helper->client, dpms_mode);
332 mutex_unlock(&fb_helper->lock);
333 }
334
335
336
337
338
339
340 int drm_fb_helper_blank(int blank, struct fb_info *info)
341 {
342 if (oops_in_progress)
343 return -EBUSY;
344
345 switch (blank) {
346
347 case FB_BLANK_UNBLANK:
348 drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
349 break;
350
351 case FB_BLANK_NORMAL:
352 drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
353 break;
354
355 case FB_BLANK_HSYNC_SUSPEND:
356 drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
357 break;
358
359 case FB_BLANK_VSYNC_SUSPEND:
360 drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND);
361 break;
362
363 case FB_BLANK_POWERDOWN:
364 drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
365 break;
366 }
367 return 0;
368 }
369 EXPORT_SYMBOL(drm_fb_helper_blank);
370
371 static void drm_fb_helper_resume_worker(struct work_struct *work)
372 {
373 struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
374 resume_work);
375
376 console_lock();
377 fb_set_suspend(helper->fbdev, 0);
378 console_unlock();
379 }
380
381 static void drm_fb_helper_dirty_blit_real(struct drm_fb_helper *fb_helper,
382 struct drm_clip_rect *clip)
383 {
384 struct drm_framebuffer *fb = fb_helper->fb;
385 unsigned int cpp = fb->format->cpp[0];
386 size_t offset = clip->y1 * fb->pitches[0] + clip->x1 * cpp;
387 void *src = fb_helper->fbdev->screen_buffer + offset;
388 void *dst = fb_helper->buffer->vaddr + offset;
389 size_t len = (clip->x2 - clip->x1) * cpp;
390 unsigned int y;
391
392 for (y = clip->y1; y < clip->y2; y++) {
393 memcpy(dst, src, len);
394 src += fb->pitches[0];
395 dst += fb->pitches[0];
396 }
397 }
398
399 static void drm_fb_helper_dirty_work(struct work_struct *work)
400 {
401 struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
402 dirty_work);
403 struct drm_clip_rect *clip = &helper->dirty_clip;
404 struct drm_clip_rect clip_copy;
405 unsigned long flags;
406 void *vaddr;
407
408 spin_lock_irqsave(&helper->dirty_lock, flags);
409 clip_copy = *clip;
410 clip->x1 = clip->y1 = ~0;
411 clip->x2 = clip->y2 = 0;
412 spin_unlock_irqrestore(&helper->dirty_lock, flags);
413
414
415 if (clip_copy.x1 < clip_copy.x2 && clip_copy.y1 < clip_copy.y2) {
416
417
418 if (helper->buffer) {
419 vaddr = drm_client_buffer_vmap(helper->buffer);
420 if (IS_ERR(vaddr))
421 return;
422 drm_fb_helper_dirty_blit_real(helper, &clip_copy);
423 }
424 if (helper->fb->funcs->dirty)
425 helper->fb->funcs->dirty(helper->fb, NULL, 0, 0,
426 &clip_copy, 1);
427
428 if (helper->buffer)
429 drm_client_buffer_vunmap(helper->buffer);
430 }
431 }
432
433
434
435
436
437
438
439
440
441
442 void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
443 const struct drm_fb_helper_funcs *funcs)
444 {
445 INIT_LIST_HEAD(&helper->kernel_fb_list);
446 spin_lock_init(&helper->dirty_lock);
447 INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker);
448 INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work);
449 helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
450 mutex_init(&helper->lock);
451 helper->funcs = funcs;
452 helper->dev = dev;
453 }
454 EXPORT_SYMBOL(drm_fb_helper_prepare);
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472 int drm_fb_helper_init(struct drm_device *dev,
473 struct drm_fb_helper *fb_helper,
474 int max_conn_count)
475 {
476 int ret;
477
478 if (!drm_fbdev_emulation) {
479 dev->fb_helper = fb_helper;
480 return 0;
481 }
482
483
484
485
486
487 if (!fb_helper->client.funcs) {
488 ret = drm_client_init(dev, &fb_helper->client, "drm_fb_helper", NULL);
489 if (ret)
490 return ret;
491 }
492
493 dev->fb_helper = fb_helper;
494
495 return 0;
496 }
497 EXPORT_SYMBOL(drm_fb_helper_init);
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512 struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
513 {
514 struct device *dev = fb_helper->dev->dev;
515 struct fb_info *info;
516 int ret;
517
518 info = framebuffer_alloc(0, dev);
519 if (!info)
520 return ERR_PTR(-ENOMEM);
521
522 ret = fb_alloc_cmap(&info->cmap, 256, 0);
523 if (ret)
524 goto err_release;
525
526 info->apertures = alloc_apertures(1);
527 if (!info->apertures) {
528 ret = -ENOMEM;
529 goto err_free_cmap;
530 }
531
532 fb_helper->fbdev = info;
533 info->skip_vt_switch = true;
534
535 return info;
536
537 err_free_cmap:
538 fb_dealloc_cmap(&info->cmap);
539 err_release:
540 framebuffer_release(info);
541 return ERR_PTR(ret);
542 }
543 EXPORT_SYMBOL(drm_fb_helper_alloc_fbi);
544
545
546
547
548
549
550
551
552
553 void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper)
554 {
555 if (fb_helper && fb_helper->fbdev)
556 unregister_framebuffer(fb_helper->fbdev);
557 }
558 EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
559
560
561
562
563
564
565
566
567 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
568 {
569 struct fb_info *info;
570
571 if (!fb_helper)
572 return;
573
574 fb_helper->dev->fb_helper = NULL;
575
576 if (!drm_fbdev_emulation)
577 return;
578
579 cancel_work_sync(&fb_helper->resume_work);
580 cancel_work_sync(&fb_helper->dirty_work);
581
582 info = fb_helper->fbdev;
583 if (info) {
584 if (info->cmap.len)
585 fb_dealloc_cmap(&info->cmap);
586 framebuffer_release(info);
587 }
588 fb_helper->fbdev = NULL;
589
590 mutex_lock(&kernel_fb_helper_lock);
591 if (!list_empty(&fb_helper->kernel_fb_list)) {
592 list_del(&fb_helper->kernel_fb_list);
593 if (list_empty(&kernel_fb_helper_list))
594 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
595 }
596 mutex_unlock(&kernel_fb_helper_lock);
597
598 mutex_destroy(&fb_helper->lock);
599
600 if (!fb_helper->client.funcs)
601 drm_client_release(&fb_helper->client);
602 }
603 EXPORT_SYMBOL(drm_fb_helper_fini);
604
605
606
607
608
609
610
611 void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
612 {
613 if (fb_helper && fb_helper->fbdev)
614 unlink_framebuffer(fb_helper->fbdev);
615 }
616 EXPORT_SYMBOL(drm_fb_helper_unlink_fbi);
617
618 static bool drm_fbdev_use_shadow_fb(struct drm_fb_helper *fb_helper)
619 {
620 struct drm_device *dev = fb_helper->dev;
621 struct drm_framebuffer *fb = fb_helper->fb;
622
623 return dev->mode_config.prefer_shadow_fbdev ||
624 dev->mode_config.prefer_shadow ||
625 fb->funcs->dirty;
626 }
627
628 static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
629 u32 width, u32 height)
630 {
631 struct drm_fb_helper *helper = info->par;
632 struct drm_clip_rect *clip = &helper->dirty_clip;
633 unsigned long flags;
634
635 if (!drm_fbdev_use_shadow_fb(helper))
636 return;
637
638 spin_lock_irqsave(&helper->dirty_lock, flags);
639 clip->x1 = min_t(u32, clip->x1, x);
640 clip->y1 = min_t(u32, clip->y1, y);
641 clip->x2 = max_t(u32, clip->x2, x + width);
642 clip->y2 = max_t(u32, clip->y2, y + height);
643 spin_unlock_irqrestore(&helper->dirty_lock, flags);
644
645 schedule_work(&helper->dirty_work);
646 }
647
648
649
650
651
652
653
654
655
656 void drm_fb_helper_deferred_io(struct fb_info *info,
657 struct list_head *pagelist)
658 {
659 unsigned long start, end, min, max;
660 struct page *page;
661 u32 y1, y2;
662
663 min = ULONG_MAX;
664 max = 0;
665 list_for_each_entry(page, pagelist, lru) {
666 start = page->index << PAGE_SHIFT;
667 end = start + PAGE_SIZE - 1;
668 min = min(min, start);
669 max = max(max, end);
670 }
671
672 if (min < max) {
673 y1 = min / info->fix.line_length;
674 y2 = min_t(u32, DIV_ROUND_UP(max, info->fix.line_length),
675 info->var.yres);
676 drm_fb_helper_dirty(info, 0, y1, info->var.xres, y2 - y1);
677 }
678 }
679 EXPORT_SYMBOL(drm_fb_helper_deferred_io);
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697 int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper)
698 {
699 struct fb_info *info = fb_helper->fbdev;
700 struct fb_deferred_io *fbdefio;
701 struct fb_ops *fbops;
702
703 fbdefio = kzalloc(sizeof(*fbdefio), GFP_KERNEL);
704 fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
705 if (!fbdefio || !fbops) {
706 kfree(fbdefio);
707 kfree(fbops);
708 return -ENOMEM;
709 }
710
711 info->fbdefio = fbdefio;
712 fbdefio->delay = msecs_to_jiffies(50);
713 fbdefio->deferred_io = drm_fb_helper_deferred_io;
714
715 *fbops = *info->fbops;
716 info->fbops = fbops;
717
718 fb_deferred_io_init(info);
719
720 return 0;
721 }
722 EXPORT_SYMBOL(drm_fb_helper_defio_init);
723
724
725
726
727
728
729
730
731
732
733 ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
734 size_t count, loff_t *ppos)
735 {
736 return fb_sys_read(info, buf, count, ppos);
737 }
738 EXPORT_SYMBOL(drm_fb_helper_sys_read);
739
740
741
742
743
744
745
746
747
748
749 ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
750 size_t count, loff_t *ppos)
751 {
752 ssize_t ret;
753
754 ret = fb_sys_write(info, buf, count, ppos);
755 if (ret > 0)
756 drm_fb_helper_dirty(info, 0, 0, info->var.xres,
757 info->var.yres);
758
759 return ret;
760 }
761 EXPORT_SYMBOL(drm_fb_helper_sys_write);
762
763
764
765
766
767
768
769
770 void drm_fb_helper_sys_fillrect(struct fb_info *info,
771 const struct fb_fillrect *rect)
772 {
773 sys_fillrect(info, rect);
774 drm_fb_helper_dirty(info, rect->dx, rect->dy,
775 rect->width, rect->height);
776 }
777 EXPORT_SYMBOL(drm_fb_helper_sys_fillrect);
778
779
780
781
782
783
784
785
786 void drm_fb_helper_sys_copyarea(struct fb_info *info,
787 const struct fb_copyarea *area)
788 {
789 sys_copyarea(info, area);
790 drm_fb_helper_dirty(info, area->dx, area->dy,
791 area->width, area->height);
792 }
793 EXPORT_SYMBOL(drm_fb_helper_sys_copyarea);
794
795
796
797
798
799
800
801
802 void drm_fb_helper_sys_imageblit(struct fb_info *info,
803 const struct fb_image *image)
804 {
805 sys_imageblit(info, image);
806 drm_fb_helper_dirty(info, image->dx, image->dy,
807 image->width, image->height);
808 }
809 EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
810
811
812
813
814
815
816
817
818 void drm_fb_helper_cfb_fillrect(struct fb_info *info,
819 const struct fb_fillrect *rect)
820 {
821 cfb_fillrect(info, rect);
822 drm_fb_helper_dirty(info, rect->dx, rect->dy,
823 rect->width, rect->height);
824 }
825 EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect);
826
827
828
829
830
831
832
833
834 void drm_fb_helper_cfb_copyarea(struct fb_info *info,
835 const struct fb_copyarea *area)
836 {
837 cfb_copyarea(info, area);
838 drm_fb_helper_dirty(info, area->dx, area->dy,
839 area->width, area->height);
840 }
841 EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea);
842
843
844
845
846
847
848
849
850 void drm_fb_helper_cfb_imageblit(struct fb_info *info,
851 const struct fb_image *image)
852 {
853 cfb_imageblit(info, image);
854 drm_fb_helper_dirty(info, image->dx, image->dy,
855 image->width, image->height);
856 }
857 EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
858
859
860
861
862
863
864
865
866
867
868 void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend)
869 {
870 if (fb_helper && fb_helper->fbdev)
871 fb_set_suspend(fb_helper->fbdev, suspend);
872 }
873 EXPORT_SYMBOL(drm_fb_helper_set_suspend);
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891 void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
892 bool suspend)
893 {
894 if (!fb_helper || !fb_helper->fbdev)
895 return;
896
897
898 flush_work(&fb_helper->resume_work);
899
900 if (suspend) {
901 if (fb_helper->fbdev->state != FBINFO_STATE_RUNNING)
902 return;
903
904 console_lock();
905
906 } else {
907 if (fb_helper->fbdev->state == FBINFO_STATE_RUNNING)
908 return;
909
910 if (!console_trylock()) {
911 schedule_work(&fb_helper->resume_work);
912 return;
913 }
914 }
915
916 fb_set_suspend(fb_helper->fbdev, suspend);
917 console_unlock();
918 }
919 EXPORT_SYMBOL(drm_fb_helper_set_suspend_unlocked);
920
921 static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info)
922 {
923 u32 *palette = (u32 *)info->pseudo_palette;
924 int i;
925
926 if (cmap->start + cmap->len > 16)
927 return -EINVAL;
928
929 for (i = 0; i < cmap->len; ++i) {
930 u16 red = cmap->red[i];
931 u16 green = cmap->green[i];
932 u16 blue = cmap->blue[i];
933 u32 value;
934
935 red >>= 16 - info->var.red.length;
936 green >>= 16 - info->var.green.length;
937 blue >>= 16 - info->var.blue.length;
938 value = (red << info->var.red.offset) |
939 (green << info->var.green.offset) |
940 (blue << info->var.blue.offset);
941 if (info->var.transp.length > 0) {
942 u32 mask = (1 << info->var.transp.length) - 1;
943
944 mask <<= info->var.transp.offset;
945 value |= mask;
946 }
947 palette[cmap->start + i] = value;
948 }
949
950 return 0;
951 }
952
953 static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
954 {
955 struct drm_fb_helper *fb_helper = info->par;
956 struct drm_mode_set *modeset;
957 struct drm_crtc *crtc;
958 u16 *r, *g, *b;
959 int ret = 0;
960
961 drm_modeset_lock_all(fb_helper->dev);
962 drm_client_for_each_modeset(modeset, &fb_helper->client) {
963 crtc = modeset->crtc;
964 if (!crtc->funcs->gamma_set || !crtc->gamma_size)
965 return -EINVAL;
966
967 if (cmap->start + cmap->len > crtc->gamma_size)
968 return -EINVAL;
969
970 r = crtc->gamma_store;
971 g = r + crtc->gamma_size;
972 b = g + crtc->gamma_size;
973
974 memcpy(r + cmap->start, cmap->red, cmap->len * sizeof(*r));
975 memcpy(g + cmap->start, cmap->green, cmap->len * sizeof(*g));
976 memcpy(b + cmap->start, cmap->blue, cmap->len * sizeof(*b));
977
978 ret = crtc->funcs->gamma_set(crtc, r, g, b,
979 crtc->gamma_size, NULL);
980 if (ret)
981 return ret;
982 }
983 drm_modeset_unlock_all(fb_helper->dev);
984
985 return ret;
986 }
987
988 static struct drm_property_blob *setcmap_new_gamma_lut(struct drm_crtc *crtc,
989 struct fb_cmap *cmap)
990 {
991 struct drm_device *dev = crtc->dev;
992 struct drm_property_blob *gamma_lut;
993 struct drm_color_lut *lut;
994 int size = crtc->gamma_size;
995 int i;
996
997 if (!size || cmap->start + cmap->len > size)
998 return ERR_PTR(-EINVAL);
999
1000 gamma_lut = drm_property_create_blob(dev, sizeof(*lut) * size, NULL);
1001 if (IS_ERR(gamma_lut))
1002 return gamma_lut;
1003
1004 lut = gamma_lut->data;
1005 if (cmap->start || cmap->len != size) {
1006 u16 *r = crtc->gamma_store;
1007 u16 *g = r + crtc->gamma_size;
1008 u16 *b = g + crtc->gamma_size;
1009
1010 for (i = 0; i < cmap->start; i++) {
1011 lut[i].red = r[i];
1012 lut[i].green = g[i];
1013 lut[i].blue = b[i];
1014 }
1015 for (i = cmap->start + cmap->len; i < size; i++) {
1016 lut[i].red = r[i];
1017 lut[i].green = g[i];
1018 lut[i].blue = b[i];
1019 }
1020 }
1021
1022 for (i = 0; i < cmap->len; i++) {
1023 lut[cmap->start + i].red = cmap->red[i];
1024 lut[cmap->start + i].green = cmap->green[i];
1025 lut[cmap->start + i].blue = cmap->blue[i];
1026 }
1027
1028 return gamma_lut;
1029 }
1030
1031 static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
1032 {
1033 struct drm_fb_helper *fb_helper = info->par;
1034 struct drm_device *dev = fb_helper->dev;
1035 struct drm_property_blob *gamma_lut = NULL;
1036 struct drm_modeset_acquire_ctx ctx;
1037 struct drm_crtc_state *crtc_state;
1038 struct drm_atomic_state *state;
1039 struct drm_mode_set *modeset;
1040 struct drm_crtc *crtc;
1041 u16 *r, *g, *b;
1042 bool replaced;
1043 int ret = 0;
1044
1045 drm_modeset_acquire_init(&ctx, 0);
1046
1047 state = drm_atomic_state_alloc(dev);
1048 if (!state) {
1049 ret = -ENOMEM;
1050 goto out_ctx;
1051 }
1052
1053 state->acquire_ctx = &ctx;
1054 retry:
1055 drm_client_for_each_modeset(modeset, &fb_helper->client) {
1056 crtc = modeset->crtc;
1057
1058 if (!gamma_lut)
1059 gamma_lut = setcmap_new_gamma_lut(crtc, cmap);
1060 if (IS_ERR(gamma_lut)) {
1061 ret = PTR_ERR(gamma_lut);
1062 gamma_lut = NULL;
1063 goto out_state;
1064 }
1065
1066 crtc_state = drm_atomic_get_crtc_state(state, crtc);
1067 if (IS_ERR(crtc_state)) {
1068 ret = PTR_ERR(crtc_state);
1069 goto out_state;
1070 }
1071
1072 replaced = drm_property_replace_blob(&crtc_state->degamma_lut,
1073 NULL);
1074 replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
1075 replaced |= drm_property_replace_blob(&crtc_state->gamma_lut,
1076 gamma_lut);
1077 crtc_state->color_mgmt_changed |= replaced;
1078 }
1079
1080 ret = drm_atomic_commit(state);
1081 if (ret)
1082 goto out_state;
1083
1084 drm_client_for_each_modeset(modeset, &fb_helper->client) {
1085 crtc = modeset->crtc;
1086
1087 r = crtc->gamma_store;
1088 g = r + crtc->gamma_size;
1089 b = g + crtc->gamma_size;
1090
1091 memcpy(r + cmap->start, cmap->red, cmap->len * sizeof(*r));
1092 memcpy(g + cmap->start, cmap->green, cmap->len * sizeof(*g));
1093 memcpy(b + cmap->start, cmap->blue, cmap->len * sizeof(*b));
1094 }
1095
1096 out_state:
1097 if (ret == -EDEADLK)
1098 goto backoff;
1099
1100 drm_property_blob_put(gamma_lut);
1101 drm_atomic_state_put(state);
1102 out_ctx:
1103 drm_modeset_drop_locks(&ctx);
1104 drm_modeset_acquire_fini(&ctx);
1105
1106 return ret;
1107
1108 backoff:
1109 drm_atomic_state_clear(state);
1110 drm_modeset_backoff(&ctx);
1111 goto retry;
1112 }
1113
1114
1115
1116
1117
1118
1119 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1120 {
1121 struct drm_fb_helper *fb_helper = info->par;
1122 struct drm_device *dev = fb_helper->dev;
1123 int ret;
1124
1125 if (oops_in_progress)
1126 return -EBUSY;
1127
1128 mutex_lock(&fb_helper->lock);
1129
1130 if (!drm_master_internal_acquire(dev)) {
1131 ret = -EBUSY;
1132 goto unlock;
1133 }
1134
1135 mutex_lock(&fb_helper->client.modeset_mutex);
1136 if (info->fix.visual == FB_VISUAL_TRUECOLOR)
1137 ret = setcmap_pseudo_palette(cmap, info);
1138 else if (drm_drv_uses_atomic_modeset(fb_helper->dev))
1139 ret = setcmap_atomic(cmap, info);
1140 else
1141 ret = setcmap_legacy(cmap, info);
1142 mutex_unlock(&fb_helper->client.modeset_mutex);
1143
1144 drm_master_internal_release(dev);
1145 unlock:
1146 mutex_unlock(&fb_helper->lock);
1147
1148 return ret;
1149 }
1150 EXPORT_SYMBOL(drm_fb_helper_setcmap);
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161 int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
1162 unsigned long arg)
1163 {
1164 struct drm_fb_helper *fb_helper = info->par;
1165 struct drm_device *dev = fb_helper->dev;
1166 struct drm_crtc *crtc;
1167 int ret = 0;
1168
1169 mutex_lock(&fb_helper->lock);
1170 if (!drm_master_internal_acquire(dev)) {
1171 ret = -EBUSY;
1172 goto unlock;
1173 }
1174
1175 switch (cmd) {
1176 case FBIO_WAITFORVSYNC:
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193 crtc = fb_helper->client.modesets[0].crtc;
1194
1195
1196
1197
1198
1199
1200 ret = drm_crtc_vblank_get(crtc);
1201 if (!ret) {
1202 drm_crtc_wait_one_vblank(crtc);
1203 drm_crtc_vblank_put(crtc);
1204 }
1205
1206 ret = 0;
1207 break;
1208 default:
1209 ret = -ENOTTY;
1210 }
1211
1212 drm_master_internal_release(dev);
1213 unlock:
1214 mutex_unlock(&fb_helper->lock);
1215 return ret;
1216 }
1217 EXPORT_SYMBOL(drm_fb_helper_ioctl);
1218
1219 static bool drm_fb_pixel_format_equal(const struct fb_var_screeninfo *var_1,
1220 const struct fb_var_screeninfo *var_2)
1221 {
1222 return var_1->bits_per_pixel == var_2->bits_per_pixel &&
1223 var_1->grayscale == var_2->grayscale &&
1224 var_1->red.offset == var_2->red.offset &&
1225 var_1->red.length == var_2->red.length &&
1226 var_1->red.msb_right == var_2->red.msb_right &&
1227 var_1->green.offset == var_2->green.offset &&
1228 var_1->green.length == var_2->green.length &&
1229 var_1->green.msb_right == var_2->green.msb_right &&
1230 var_1->blue.offset == var_2->blue.offset &&
1231 var_1->blue.length == var_2->blue.length &&
1232 var_1->blue.msb_right == var_2->blue.msb_right &&
1233 var_1->transp.offset == var_2->transp.offset &&
1234 var_1->transp.length == var_2->transp.length &&
1235 var_1->transp.msb_right == var_2->transp.msb_right;
1236 }
1237
1238 static void drm_fb_helper_fill_pixel_fmt(struct fb_var_screeninfo *var,
1239 u8 depth)
1240 {
1241 switch (depth) {
1242 case 8:
1243 var->red.offset = 0;
1244 var->green.offset = 0;
1245 var->blue.offset = 0;
1246 var->red.length = 8;
1247 var->green.length = 8;
1248 var->blue.length = 8;
1249 var->transp.offset = 0;
1250 var->transp.length = 0;
1251 break;
1252 case 15:
1253 var->red.offset = 10;
1254 var->green.offset = 5;
1255 var->blue.offset = 0;
1256 var->red.length = 5;
1257 var->green.length = 5;
1258 var->blue.length = 5;
1259 var->transp.offset = 15;
1260 var->transp.length = 1;
1261 break;
1262 case 16:
1263 var->red.offset = 11;
1264 var->green.offset = 5;
1265 var->blue.offset = 0;
1266 var->red.length = 5;
1267 var->green.length = 6;
1268 var->blue.length = 5;
1269 var->transp.offset = 0;
1270 break;
1271 case 24:
1272 var->red.offset = 16;
1273 var->green.offset = 8;
1274 var->blue.offset = 0;
1275 var->red.length = 8;
1276 var->green.length = 8;
1277 var->blue.length = 8;
1278 var->transp.offset = 0;
1279 var->transp.length = 0;
1280 break;
1281 case 32:
1282 var->red.offset = 16;
1283 var->green.offset = 8;
1284 var->blue.offset = 0;
1285 var->red.length = 8;
1286 var->green.length = 8;
1287 var->blue.length = 8;
1288 var->transp.offset = 24;
1289 var->transp.length = 8;
1290 break;
1291 default:
1292 break;
1293 }
1294 }
1295
1296
1297
1298
1299
1300
1301 int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
1302 struct fb_info *info)
1303 {
1304 struct drm_fb_helper *fb_helper = info->par;
1305 struct drm_framebuffer *fb = fb_helper->fb;
1306
1307 if (in_dbg_master())
1308 return -EINVAL;
1309
1310 if (var->pixclock != 0) {
1311 DRM_DEBUG("fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n");
1312 var->pixclock = 0;
1313 }
1314
1315 if ((drm_format_info_block_width(fb->format, 0) > 1) ||
1316 (drm_format_info_block_height(fb->format, 0) > 1))
1317 return -EINVAL;
1318
1319
1320
1321
1322
1323 if (var->bits_per_pixel > fb->format->cpp[0] * 8 ||
1324 var->xres > fb->width || var->yres > fb->height ||
1325 var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
1326 DRM_DEBUG("fb requested width/height/bpp can't fit in current fb "
1327 "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
1328 var->xres, var->yres, var->bits_per_pixel,
1329 var->xres_virtual, var->yres_virtual,
1330 fb->width, fb->height, fb->format->cpp[0] * 8);
1331 return -EINVAL;
1332 }
1333
1334
1335
1336
1337
1338
1339 if (!var->red.offset && !var->green.offset &&
1340 !var->blue.offset && !var->transp.offset &&
1341 !var->red.length && !var->green.length &&
1342 !var->blue.length && !var->transp.length &&
1343 !var->red.msb_right && !var->green.msb_right &&
1344 !var->blue.msb_right && !var->transp.msb_right) {
1345 drm_fb_helper_fill_pixel_fmt(var, fb->format->depth);
1346 }
1347
1348
1349
1350
1351 var->bits_per_pixel = fb->format->cpp[0] * 8;
1352
1353
1354
1355
1356
1357 if (!drm_fb_pixel_format_equal(var, &info->var)) {
1358 DRM_DEBUG("fbdev emulation doesn't support changing the pixel format\n");
1359 return -EINVAL;
1360 }
1361
1362 return 0;
1363 }
1364 EXPORT_SYMBOL(drm_fb_helper_check_var);
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374 int drm_fb_helper_set_par(struct fb_info *info)
1375 {
1376 struct drm_fb_helper *fb_helper = info->par;
1377 struct fb_var_screeninfo *var = &info->var;
1378
1379 if (oops_in_progress)
1380 return -EBUSY;
1381
1382 if (var->pixclock != 0) {
1383 DRM_ERROR("PIXEL CLOCK SET\n");
1384 return -EINVAL;
1385 }
1386
1387 drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
1388
1389 return 0;
1390 }
1391 EXPORT_SYMBOL(drm_fb_helper_set_par);
1392
1393 static void pan_set(struct drm_fb_helper *fb_helper, int x, int y)
1394 {
1395 struct drm_mode_set *mode_set;
1396
1397 mutex_lock(&fb_helper->client.modeset_mutex);
1398 drm_client_for_each_modeset(mode_set, &fb_helper->client) {
1399 mode_set->x = x;
1400 mode_set->y = y;
1401 }
1402 mutex_unlock(&fb_helper->client.modeset_mutex);
1403 }
1404
1405 static int pan_display_atomic(struct fb_var_screeninfo *var,
1406 struct fb_info *info)
1407 {
1408 struct drm_fb_helper *fb_helper = info->par;
1409 int ret;
1410
1411 pan_set(fb_helper, var->xoffset, var->yoffset);
1412
1413 ret = drm_client_modeset_commit_force(&fb_helper->client);
1414 if (!ret) {
1415 info->var.xoffset = var->xoffset;
1416 info->var.yoffset = var->yoffset;
1417 } else
1418 pan_set(fb_helper, info->var.xoffset, info->var.yoffset);
1419
1420 return ret;
1421 }
1422
1423 static int pan_display_legacy(struct fb_var_screeninfo *var,
1424 struct fb_info *info)
1425 {
1426 struct drm_fb_helper *fb_helper = info->par;
1427 struct drm_client_dev *client = &fb_helper->client;
1428 struct drm_mode_set *modeset;
1429 int ret = 0;
1430
1431 mutex_lock(&client->modeset_mutex);
1432 drm_modeset_lock_all(fb_helper->dev);
1433 drm_client_for_each_modeset(modeset, client) {
1434 modeset->x = var->xoffset;
1435 modeset->y = var->yoffset;
1436
1437 if (modeset->num_connectors) {
1438 ret = drm_mode_set_config_internal(modeset);
1439 if (!ret) {
1440 info->var.xoffset = var->xoffset;
1441 info->var.yoffset = var->yoffset;
1442 }
1443 }
1444 }
1445 drm_modeset_unlock_all(fb_helper->dev);
1446 mutex_unlock(&client->modeset_mutex);
1447
1448 return ret;
1449 }
1450
1451
1452
1453
1454
1455
1456 int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
1457 struct fb_info *info)
1458 {
1459 struct drm_fb_helper *fb_helper = info->par;
1460 struct drm_device *dev = fb_helper->dev;
1461 int ret;
1462
1463 if (oops_in_progress)
1464 return -EBUSY;
1465
1466 mutex_lock(&fb_helper->lock);
1467 if (!drm_master_internal_acquire(dev)) {
1468 ret = -EBUSY;
1469 goto unlock;
1470 }
1471
1472 if (drm_drv_uses_atomic_modeset(dev))
1473 ret = pan_display_atomic(var, info);
1474 else
1475 ret = pan_display_legacy(var, info);
1476
1477 drm_master_internal_release(dev);
1478 unlock:
1479 mutex_unlock(&fb_helper->lock);
1480
1481 return ret;
1482 }
1483 EXPORT_SYMBOL(drm_fb_helper_pan_display);
1484
1485
1486
1487
1488
1489 static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
1490 int preferred_bpp)
1491 {
1492 struct drm_client_dev *client = &fb_helper->client;
1493 int ret = 0;
1494 int crtc_count = 0;
1495 struct drm_connector_list_iter conn_iter;
1496 struct drm_fb_helper_surface_size sizes;
1497 struct drm_connector *connector;
1498 struct drm_mode_set *mode_set;
1499 int best_depth = 0;
1500
1501 memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
1502 sizes.surface_depth = 24;
1503 sizes.surface_bpp = 32;
1504 sizes.fb_width = (u32)-1;
1505 sizes.fb_height = (u32)-1;
1506
1507
1508
1509
1510
1511 if (preferred_bpp != sizes.surface_bpp)
1512 sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
1513
1514 drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
1515 drm_client_for_each_connector_iter(connector, &conn_iter) {
1516 struct drm_cmdline_mode *cmdline_mode;
1517
1518 cmdline_mode = &connector->cmdline_mode;
1519
1520 if (cmdline_mode->bpp_specified) {
1521 switch (cmdline_mode->bpp) {
1522 case 8:
1523 sizes.surface_depth = sizes.surface_bpp = 8;
1524 break;
1525 case 15:
1526 sizes.surface_depth = 15;
1527 sizes.surface_bpp = 16;
1528 break;
1529 case 16:
1530 sizes.surface_depth = sizes.surface_bpp = 16;
1531 break;
1532 case 24:
1533 sizes.surface_depth = sizes.surface_bpp = 24;
1534 break;
1535 case 32:
1536 sizes.surface_depth = 24;
1537 sizes.surface_bpp = 32;
1538 break;
1539 }
1540 break;
1541 }
1542 }
1543 drm_connector_list_iter_end(&conn_iter);
1544
1545
1546
1547
1548
1549
1550 mutex_lock(&client->modeset_mutex);
1551 drm_client_for_each_modeset(mode_set, client) {
1552 struct drm_crtc *crtc = mode_set->crtc;
1553 struct drm_plane *plane = crtc->primary;
1554 int j;
1555
1556 DRM_DEBUG("test CRTC %u primary plane\n", drm_crtc_index(crtc));
1557
1558 for (j = 0; j < plane->format_count; j++) {
1559 const struct drm_format_info *fmt;
1560
1561 fmt = drm_format_info(plane->format_types[j]);
1562
1563
1564
1565
1566
1567
1568
1569
1570 if (fmt->depth == 0)
1571 continue;
1572
1573
1574 if (fmt->depth == sizes.surface_depth) {
1575 best_depth = fmt->depth;
1576 break;
1577 }
1578
1579
1580 if (fmt->depth > sizes.surface_depth)
1581 continue;
1582
1583
1584 if (fmt->depth > best_depth)
1585 best_depth = fmt->depth;
1586 }
1587 }
1588 if (sizes.surface_depth != best_depth && best_depth) {
1589 DRM_INFO("requested bpp %d, scaled depth down to %d",
1590 sizes.surface_bpp, best_depth);
1591 sizes.surface_depth = best_depth;
1592 }
1593
1594
1595 crtc_count = 0;
1596 drm_client_for_each_modeset(mode_set, client) {
1597 struct drm_display_mode *desired_mode;
1598 int x, y, j;
1599
1600
1601
1602
1603 bool lastv = true, lasth = true;
1604
1605 desired_mode = mode_set->mode;
1606
1607 if (!desired_mode)
1608 continue;
1609
1610 crtc_count++;
1611
1612 x = mode_set->x;
1613 y = mode_set->y;
1614
1615 sizes.surface_width = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
1616 sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
1617
1618 for (j = 0; j < mode_set->num_connectors; j++) {
1619 struct drm_connector *connector = mode_set->connectors[j];
1620
1621 if (connector->has_tile) {
1622 lasth = (connector->tile_h_loc == (connector->num_h_tile - 1));
1623 lastv = (connector->tile_v_loc == (connector->num_v_tile - 1));
1624
1625 break;
1626 }
1627 }
1628
1629 if (lasth)
1630 sizes.fb_width = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width);
1631 if (lastv)
1632 sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
1633 }
1634 mutex_unlock(&client->modeset_mutex);
1635
1636 if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
1637 DRM_INFO("Cannot find any crtc or sizes\n");
1638
1639
1640 if (!fb_helper->deferred_setup)
1641 drm_client_modeset_commit(client);
1642 return -EAGAIN;
1643 }
1644
1645
1646 sizes.surface_height *= drm_fbdev_overalloc;
1647 sizes.surface_height /= 100;
1648
1649
1650 ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
1651 if (ret < 0)
1652 return ret;
1653
1654 strcpy(fb_helper->fb->comm, "[fbcon]");
1655 return 0;
1656 }
1657
1658 static void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
1659 uint32_t depth)
1660 {
1661 info->fix.type = FB_TYPE_PACKED_PIXELS;
1662 info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
1663 FB_VISUAL_TRUECOLOR;
1664 info->fix.mmio_start = 0;
1665 info->fix.mmio_len = 0;
1666 info->fix.type_aux = 0;
1667 info->fix.xpanstep = 1;
1668 info->fix.ypanstep = 1;
1669 info->fix.ywrapstep = 0;
1670 info->fix.accel = FB_ACCEL_NONE;
1671
1672 info->fix.line_length = pitch;
1673 }
1674
1675 static void drm_fb_helper_fill_var(struct fb_info *info,
1676 struct drm_fb_helper *fb_helper,
1677 uint32_t fb_width, uint32_t fb_height)
1678 {
1679 struct drm_framebuffer *fb = fb_helper->fb;
1680
1681 WARN_ON((drm_format_info_block_width(fb->format, 0) > 1) ||
1682 (drm_format_info_block_height(fb->format, 0) > 1));
1683 info->pseudo_palette = fb_helper->pseudo_palette;
1684 info->var.xres_virtual = fb->width;
1685 info->var.yres_virtual = fb->height;
1686 info->var.bits_per_pixel = fb->format->cpp[0] * 8;
1687 info->var.accel_flags = FB_ACCELF_TEXT;
1688 info->var.xoffset = 0;
1689 info->var.yoffset = 0;
1690 info->var.activate = FB_ACTIVATE_NOW;
1691
1692 drm_fb_helper_fill_pixel_fmt(&info->var, fb->format->depth);
1693
1694 info->var.xres = fb_width;
1695 info->var.yres = fb_height;
1696 }
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711 void drm_fb_helper_fill_info(struct fb_info *info,
1712 struct drm_fb_helper *fb_helper,
1713 struct drm_fb_helper_surface_size *sizes)
1714 {
1715 struct drm_framebuffer *fb = fb_helper->fb;
1716
1717 drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
1718 drm_fb_helper_fill_var(info, fb_helper,
1719 sizes->fb_width, sizes->fb_height);
1720
1721 info->par = fb_helper;
1722 snprintf(info->fix.id, sizeof(info->fix.id), "%sdrmfb",
1723 fb_helper->dev->driver->name);
1724
1725 }
1726 EXPORT_SYMBOL(drm_fb_helper_fill_info);
1727
1728
1729
1730
1731
1732
1733
1734
1735 static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
1736 {
1737 struct drm_client_dev *client = &fb_helper->client;
1738 struct drm_connector_list_iter conn_iter;
1739 struct fb_info *info = fb_helper->fbdev;
1740 unsigned int rotation, sw_rotations = 0;
1741 struct drm_connector *connector;
1742 struct drm_mode_set *modeset;
1743
1744 mutex_lock(&client->modeset_mutex);
1745 drm_client_for_each_modeset(modeset, client) {
1746 if (!modeset->num_connectors)
1747 continue;
1748
1749 modeset->fb = fb_helper->fb;
1750
1751 if (drm_client_rotation(modeset, &rotation))
1752
1753 sw_rotations |= DRM_MODE_ROTATE_0;
1754 else
1755 sw_rotations |= rotation;
1756 }
1757 mutex_unlock(&client->modeset_mutex);
1758
1759 drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
1760 drm_client_for_each_connector_iter(connector, &conn_iter) {
1761
1762
1763 if (connector->status == connector_status_connected) {
1764 info->var.width = connector->display_info.width_mm;
1765 info->var.height = connector->display_info.height_mm;
1766 break;
1767 }
1768 }
1769 drm_connector_list_iter_end(&conn_iter);
1770
1771 switch (sw_rotations) {
1772 case DRM_MODE_ROTATE_0:
1773 info->fbcon_rotate_hint = FB_ROTATE_UR;
1774 break;
1775 case DRM_MODE_ROTATE_90:
1776 info->fbcon_rotate_hint = FB_ROTATE_CCW;
1777 break;
1778 case DRM_MODE_ROTATE_180:
1779 info->fbcon_rotate_hint = FB_ROTATE_UD;
1780 break;
1781 case DRM_MODE_ROTATE_270:
1782 info->fbcon_rotate_hint = FB_ROTATE_CW;
1783 break;
1784 default:
1785
1786
1787
1788
1789
1790 info->fbcon_rotate_hint = FB_ROTATE_UR;
1791 }
1792 }
1793
1794
1795 static int
1796 __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
1797 int bpp_sel)
1798 {
1799 struct drm_device *dev = fb_helper->dev;
1800 struct fb_info *info;
1801 unsigned int width, height;
1802 int ret;
1803
1804 width = dev->mode_config.max_width;
1805 height = dev->mode_config.max_height;
1806
1807 drm_client_modeset_probe(&fb_helper->client, width, height);
1808 ret = drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1809 if (ret < 0) {
1810 if (ret == -EAGAIN) {
1811 fb_helper->preferred_bpp = bpp_sel;
1812 fb_helper->deferred_setup = true;
1813 ret = 0;
1814 }
1815 mutex_unlock(&fb_helper->lock);
1816
1817 return ret;
1818 }
1819 drm_setup_crtcs_fb(fb_helper);
1820
1821 fb_helper->deferred_setup = false;
1822
1823 info = fb_helper->fbdev;
1824 info->var.pixclock = 0;
1825
1826 #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
1827 if (!drm_leak_fbdev_smem)
1828 #endif
1829
1830 info->flags |= FBINFO_HIDE_SMEM_START;
1831
1832
1833
1834
1835 mutex_unlock(&fb_helper->lock);
1836
1837 ret = register_framebuffer(info);
1838 if (ret < 0)
1839 return ret;
1840
1841 dev_info(dev->dev, "fb%d: %s frame buffer device\n",
1842 info->node, info->fix.id);
1843
1844 mutex_lock(&kernel_fb_helper_lock);
1845 if (list_empty(&kernel_fb_helper_list))
1846 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
1847
1848 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
1849 mutex_unlock(&kernel_fb_helper_lock);
1850
1851 return 0;
1852 }
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895 int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1896 {
1897 int ret;
1898
1899 if (!drm_fbdev_emulation)
1900 return 0;
1901
1902 mutex_lock(&fb_helper->lock);
1903 ret = __drm_fb_helper_initial_config_and_unlock(fb_helper, bpp_sel);
1904
1905 return ret;
1906 }
1907 EXPORT_SYMBOL(drm_fb_helper_initial_config);
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
1931 {
1932 int err = 0;
1933
1934 if (!drm_fbdev_emulation || !fb_helper)
1935 return 0;
1936
1937 mutex_lock(&fb_helper->lock);
1938 if (fb_helper->deferred_setup) {
1939 err = __drm_fb_helper_initial_config_and_unlock(fb_helper,
1940 fb_helper->preferred_bpp);
1941 return err;
1942 }
1943
1944 if (!fb_helper->fb || !drm_master_internal_acquire(fb_helper->dev)) {
1945 fb_helper->delayed_hotplug = true;
1946 mutex_unlock(&fb_helper->lock);
1947 return err;
1948 }
1949
1950 drm_master_internal_release(fb_helper->dev);
1951
1952 DRM_DEBUG_KMS("\n");
1953
1954 drm_client_modeset_probe(&fb_helper->client, fb_helper->fb->width, fb_helper->fb->height);
1955 drm_setup_crtcs_fb(fb_helper);
1956 mutex_unlock(&fb_helper->lock);
1957
1958 drm_fb_helper_set_par(fb_helper->fbdev);
1959
1960 return 0;
1961 }
1962 EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986 int drm_fb_helper_fbdev_setup(struct drm_device *dev,
1987 struct drm_fb_helper *fb_helper,
1988 const struct drm_fb_helper_funcs *funcs,
1989 unsigned int preferred_bpp,
1990 unsigned int max_conn_count)
1991 {
1992 int ret;
1993
1994 if (!preferred_bpp)
1995 preferred_bpp = dev->mode_config.preferred_depth;
1996 if (!preferred_bpp)
1997 preferred_bpp = 32;
1998
1999 drm_fb_helper_prepare(dev, fb_helper, funcs);
2000
2001 ret = drm_fb_helper_init(dev, fb_helper, 0);
2002 if (ret < 0) {
2003 DRM_DEV_ERROR(dev->dev, "fbdev: Failed to initialize (ret=%d)\n", ret);
2004 return ret;
2005 }
2006
2007 if (!drm_drv_uses_atomic_modeset(dev))
2008 drm_helper_disable_unused_functions(dev);
2009
2010 ret = drm_fb_helper_initial_config(fb_helper, preferred_bpp);
2011 if (ret < 0) {
2012 DRM_DEV_ERROR(dev->dev, "fbdev: Failed to set configuration (ret=%d)\n", ret);
2013 goto err_drm_fb_helper_fini;
2014 }
2015
2016 return 0;
2017
2018 err_drm_fb_helper_fini:
2019 drm_fb_helper_fbdev_teardown(dev);
2020
2021 return ret;
2022 }
2023 EXPORT_SYMBOL(drm_fb_helper_fbdev_setup);
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040 void drm_fb_helper_fbdev_teardown(struct drm_device *dev)
2041 {
2042 struct drm_fb_helper *fb_helper = dev->fb_helper;
2043 struct fb_ops *fbops = NULL;
2044
2045 if (!fb_helper)
2046 return;
2047
2048
2049 if (fb_helper->fbdev && fb_helper->fbdev->dev)
2050 drm_fb_helper_unregister_fbi(fb_helper);
2051
2052 if (fb_helper->fbdev && fb_helper->fbdev->fbdefio) {
2053 fb_deferred_io_cleanup(fb_helper->fbdev);
2054 kfree(fb_helper->fbdev->fbdefio);
2055 fbops = fb_helper->fbdev->fbops;
2056 }
2057
2058 drm_fb_helper_fini(fb_helper);
2059 kfree(fbops);
2060
2061 if (fb_helper->fb)
2062 drm_framebuffer_remove(fb_helper->fb);
2063 }
2064 EXPORT_SYMBOL(drm_fb_helper_fbdev_teardown);
2065
2066
2067
2068
2069
2070
2071
2072
2073 void drm_fb_helper_lastclose(struct drm_device *dev)
2074 {
2075 drm_fb_helper_restore_fbdev_mode_unlocked(dev->fb_helper);
2076 }
2077 EXPORT_SYMBOL(drm_fb_helper_lastclose);
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088 void drm_fb_helper_output_poll_changed(struct drm_device *dev)
2089 {
2090 drm_fb_helper_hotplug_event(dev->fb_helper);
2091 }
2092 EXPORT_SYMBOL(drm_fb_helper_output_poll_changed);
2093
2094
2095 static int drm_fbdev_fb_open(struct fb_info *info, int user)
2096 {
2097 struct drm_fb_helper *fb_helper = info->par;
2098
2099
2100 if (user && !try_module_get(fb_helper->dev->driver->fops->owner))
2101 return -ENODEV;
2102
2103 return 0;
2104 }
2105
2106 static int drm_fbdev_fb_release(struct fb_info *info, int user)
2107 {
2108 struct drm_fb_helper *fb_helper = info->par;
2109
2110 if (user)
2111 module_put(fb_helper->dev->driver->fops->owner);
2112
2113 return 0;
2114 }
2115
2116 static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper)
2117 {
2118 struct fb_info *fbi = fb_helper->fbdev;
2119 struct fb_ops *fbops = NULL;
2120 void *shadow = NULL;
2121
2122 if (!fb_helper->dev)
2123 return;
2124
2125 if (fbi && fbi->fbdefio) {
2126 fb_deferred_io_cleanup(fbi);
2127 shadow = fbi->screen_buffer;
2128 fbops = fbi->fbops;
2129 }
2130
2131 drm_fb_helper_fini(fb_helper);
2132
2133 if (shadow) {
2134 vfree(shadow);
2135 kfree(fbops);
2136 }
2137
2138 drm_client_framebuffer_delete(fb_helper->buffer);
2139 }
2140
2141 static void drm_fbdev_release(struct drm_fb_helper *fb_helper)
2142 {
2143 drm_fbdev_cleanup(fb_helper);
2144 drm_client_release(&fb_helper->client);
2145 kfree(fb_helper);
2146 }
2147
2148
2149
2150
2151
2152 static void drm_fbdev_fb_destroy(struct fb_info *info)
2153 {
2154 drm_fbdev_release(info->par);
2155 }
2156
2157 static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
2158 {
2159 struct drm_fb_helper *fb_helper = info->par;
2160
2161 if (fb_helper->dev->driver->gem_prime_mmap)
2162 return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
2163 else
2164 return -ENODEV;
2165 }
2166
2167 static struct fb_ops drm_fbdev_fb_ops = {
2168 .owner = THIS_MODULE,
2169 DRM_FB_HELPER_DEFAULT_OPS,
2170 .fb_open = drm_fbdev_fb_open,
2171 .fb_release = drm_fbdev_fb_release,
2172 .fb_destroy = drm_fbdev_fb_destroy,
2173 .fb_mmap = drm_fbdev_fb_mmap,
2174 .fb_read = drm_fb_helper_sys_read,
2175 .fb_write = drm_fb_helper_sys_write,
2176 .fb_fillrect = drm_fb_helper_sys_fillrect,
2177 .fb_copyarea = drm_fb_helper_sys_copyarea,
2178 .fb_imageblit = drm_fb_helper_sys_imageblit,
2179 };
2180
2181 static struct fb_deferred_io drm_fbdev_defio = {
2182 .delay = HZ / 20,
2183 .deferred_io = drm_fb_helper_deferred_io,
2184 };
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199 int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
2200 struct drm_fb_helper_surface_size *sizes)
2201 {
2202 struct drm_client_dev *client = &fb_helper->client;
2203 struct drm_client_buffer *buffer;
2204 struct drm_framebuffer *fb;
2205 struct fb_info *fbi;
2206 u32 format;
2207 void *vaddr;
2208
2209 DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
2210 sizes->surface_width, sizes->surface_height,
2211 sizes->surface_bpp);
2212
2213 format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
2214 buffer = drm_client_framebuffer_create(client, sizes->surface_width,
2215 sizes->surface_height, format);
2216 if (IS_ERR(buffer))
2217 return PTR_ERR(buffer);
2218
2219 fb_helper->buffer = buffer;
2220 fb_helper->fb = buffer->fb;
2221 fb = buffer->fb;
2222
2223 fbi = drm_fb_helper_alloc_fbi(fb_helper);
2224 if (IS_ERR(fbi))
2225 return PTR_ERR(fbi);
2226
2227 fbi->fbops = &drm_fbdev_fb_ops;
2228 fbi->screen_size = fb->height * fb->pitches[0];
2229 fbi->fix.smem_len = fbi->screen_size;
2230
2231 drm_fb_helper_fill_info(fbi, fb_helper, sizes);
2232
2233 if (drm_fbdev_use_shadow_fb(fb_helper)) {
2234 struct fb_ops *fbops;
2235 void *shadow;
2236
2237
2238
2239
2240
2241 fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
2242 shadow = vzalloc(fbi->screen_size);
2243 if (!fbops || !shadow) {
2244 kfree(fbops);
2245 vfree(shadow);
2246 return -ENOMEM;
2247 }
2248
2249 *fbops = *fbi->fbops;
2250 fbi->fbops = fbops;
2251 fbi->screen_buffer = shadow;
2252 fbi->fbdefio = &drm_fbdev_defio;
2253
2254 fb_deferred_io_init(fbi);
2255 } else {
2256
2257 vaddr = drm_client_buffer_vmap(fb_helper->buffer);
2258 if (IS_ERR(vaddr))
2259 return PTR_ERR(vaddr);
2260
2261 fbi->screen_buffer = vaddr;
2262
2263 #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
2264 if (drm_leak_fbdev_smem && fbi->fix.smem_start == 0)
2265 fbi->fix.smem_start =
2266 page_to_phys(virt_to_page(fbi->screen_buffer));
2267 #endif
2268 }
2269
2270 return 0;
2271 }
2272 EXPORT_SYMBOL(drm_fb_helper_generic_probe);
2273
2274 static const struct drm_fb_helper_funcs drm_fb_helper_generic_funcs = {
2275 .fb_probe = drm_fb_helper_generic_probe,
2276 };
2277
2278 static void drm_fbdev_client_unregister(struct drm_client_dev *client)
2279 {
2280 struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
2281
2282 if (fb_helper->fbdev)
2283
2284 drm_fb_helper_unregister_fbi(fb_helper);
2285 else
2286 drm_fbdev_release(fb_helper);
2287 }
2288
2289 static int drm_fbdev_client_restore(struct drm_client_dev *client)
2290 {
2291 drm_fb_helper_lastclose(client->dev);
2292
2293 return 0;
2294 }
2295
2296 static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
2297 {
2298 struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
2299 struct drm_device *dev = client->dev;
2300 int ret;
2301
2302
2303 if (!fb_helper->dev && fb_helper->funcs)
2304 return 0;
2305
2306 if (dev->fb_helper)
2307 return drm_fb_helper_hotplug_event(dev->fb_helper);
2308
2309 if (!dev->mode_config.num_connector) {
2310 DRM_DEV_DEBUG(dev->dev, "No connectors found, will not create framebuffer!\n");
2311 return 0;
2312 }
2313
2314 drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
2315
2316 ret = drm_fb_helper_init(dev, fb_helper, 0);
2317 if (ret)
2318 goto err;
2319
2320 if (!drm_drv_uses_atomic_modeset(dev))
2321 drm_helper_disable_unused_functions(dev);
2322
2323 ret = drm_fb_helper_initial_config(fb_helper, fb_helper->preferred_bpp);
2324 if (ret)
2325 goto err_cleanup;
2326
2327 return 0;
2328
2329 err_cleanup:
2330 drm_fbdev_cleanup(fb_helper);
2331 err:
2332 fb_helper->dev = NULL;
2333 fb_helper->fbdev = NULL;
2334
2335 DRM_DEV_ERROR(dev->dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret);
2336
2337 return ret;
2338 }
2339
2340 static const struct drm_client_funcs drm_fbdev_client_funcs = {
2341 .owner = THIS_MODULE,
2342 .unregister = drm_fbdev_client_unregister,
2343 .restore = drm_fbdev_client_restore,
2344 .hotplug = drm_fbdev_client_hotplug,
2345 };
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373 int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
2374 {
2375 struct drm_fb_helper *fb_helper;
2376 int ret;
2377
2378 WARN(dev->fb_helper, "fb_helper is already set!\n");
2379
2380 if (!drm_fbdev_emulation)
2381 return 0;
2382
2383 fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
2384 if (!fb_helper)
2385 return -ENOMEM;
2386
2387 ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
2388 if (ret) {
2389 kfree(fb_helper);
2390 DRM_DEV_ERROR(dev->dev, "Failed to register client: %d\n", ret);
2391 return ret;
2392 }
2393
2394 if (!preferred_bpp)
2395 preferred_bpp = dev->mode_config.preferred_depth;
2396 if (!preferred_bpp)
2397 preferred_bpp = 32;
2398 fb_helper->preferred_bpp = preferred_bpp;
2399
2400 ret = drm_fbdev_client_hotplug(&fb_helper->client);
2401 if (ret)
2402 DRM_DEV_DEBUG(dev->dev, "client hotplug ret=%d\n", ret);
2403
2404 drm_client_register(&fb_helper->client);
2405
2406 return 0;
2407 }
2408 EXPORT_SYMBOL(drm_fbdev_generic_setup);
2409
2410
2411
2412
2413
2414 int __init drm_fb_helper_modinit(void)
2415 {
2416 #if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
2417 const char name[] = "fbcon";
2418 struct module *fbcon;
2419
2420 mutex_lock(&module_mutex);
2421 fbcon = find_module(name);
2422 mutex_unlock(&module_mutex);
2423
2424 if (!fbcon)
2425 request_module_nowait(name);
2426 #endif
2427 return 0;
2428 }
2429 EXPORT_SYMBOL(drm_fb_helper_modinit);