0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0031
0032 #include <linux/console.h>
0033 #include <linux/dma-buf.h>
0034 #include <linux/kernel.h>
0035 #include <linux/module.h>
0036 #include <linux/slab.h>
0037 #include <linux/sysrq.h>
0038 #include <linux/vmalloc.h>
0039
0040 #include <drm/drm_atomic.h>
0041 #include <drm/drm_crtc.h>
0042 #include <drm/drm_crtc_helper.h>
0043 #include <drm/drm_drv.h>
0044 #include <drm/drm_fb_helper.h>
0045 #include <drm/drm_fourcc.h>
0046 #include <drm/drm_framebuffer.h>
0047 #include <drm/drm_print.h>
0048 #include <drm/drm_vblank.h>
0049
0050 #include "drm_crtc_helper_internal.h"
0051 #include "drm_internal.h"
0052
0053 static bool drm_fbdev_emulation = true;
0054 module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
0055 MODULE_PARM_DESC(fbdev_emulation,
0056 "Enable legacy fbdev emulation [default=true]");
0057
0058 static int drm_fbdev_overalloc = CONFIG_DRM_FBDEV_OVERALLOC;
0059 module_param(drm_fbdev_overalloc, int, 0444);
0060 MODULE_PARM_DESC(drm_fbdev_overalloc,
0061 "Overallocation of the fbdev buffer (%) [default="
0062 __MODULE_STRING(CONFIG_DRM_FBDEV_OVERALLOC) "]");
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076 #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
0077 static bool drm_leak_fbdev_smem = false;
0078 module_param_unsafe(drm_leak_fbdev_smem, bool, 0600);
0079 MODULE_PARM_DESC(drm_leak_fbdev_smem,
0080 "Allow unsafe leaking fbdev physical smem address [default=false]");
0081 #endif
0082
0083 static LIST_HEAD(kernel_fb_helper_list);
0084 static DEFINE_MUTEX(kernel_fb_helper_lock);
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
0137 {
0138 uint16_t *r_base, *g_base, *b_base;
0139
0140 if (crtc->funcs->gamma_set == NULL)
0141 return;
0142
0143 r_base = crtc->gamma_store;
0144 g_base = r_base + crtc->gamma_size;
0145 b_base = g_base + crtc->gamma_size;
0146
0147 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base,
0148 crtc->gamma_size, NULL);
0149 }
0150
0151
0152
0153
0154
0155 int drm_fb_helper_debug_enter(struct fb_info *info)
0156 {
0157 struct drm_fb_helper *helper = info->par;
0158 const struct drm_crtc_helper_funcs *funcs;
0159 struct drm_mode_set *mode_set;
0160
0161 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
0162 mutex_lock(&helper->client.modeset_mutex);
0163 drm_client_for_each_modeset(mode_set, &helper->client) {
0164 if (!mode_set->crtc->enabled)
0165 continue;
0166
0167 funcs = mode_set->crtc->helper_private;
0168 if (funcs->mode_set_base_atomic == NULL)
0169 continue;
0170
0171 if (drm_drv_uses_atomic_modeset(mode_set->crtc->dev))
0172 continue;
0173
0174 funcs->mode_set_base_atomic(mode_set->crtc,
0175 mode_set->fb,
0176 mode_set->x,
0177 mode_set->y,
0178 ENTER_ATOMIC_MODE_SET);
0179 }
0180 mutex_unlock(&helper->client.modeset_mutex);
0181 }
0182
0183 return 0;
0184 }
0185 EXPORT_SYMBOL(drm_fb_helper_debug_enter);
0186
0187
0188
0189
0190
0191 int drm_fb_helper_debug_leave(struct fb_info *info)
0192 {
0193 struct drm_fb_helper *helper = info->par;
0194 struct drm_client_dev *client = &helper->client;
0195 struct drm_device *dev = helper->dev;
0196 struct drm_crtc *crtc;
0197 const struct drm_crtc_helper_funcs *funcs;
0198 struct drm_mode_set *mode_set;
0199 struct drm_framebuffer *fb;
0200
0201 mutex_lock(&client->modeset_mutex);
0202 drm_client_for_each_modeset(mode_set, client) {
0203 crtc = mode_set->crtc;
0204 if (drm_drv_uses_atomic_modeset(crtc->dev))
0205 continue;
0206
0207 funcs = crtc->helper_private;
0208 fb = crtc->primary->fb;
0209
0210 if (!crtc->enabled)
0211 continue;
0212
0213 if (!fb) {
0214 drm_err(dev, "no fb to restore?\n");
0215 continue;
0216 }
0217
0218 if (funcs->mode_set_base_atomic == NULL)
0219 continue;
0220
0221 drm_fb_helper_restore_lut_atomic(mode_set->crtc);
0222 funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
0223 crtc->y, LEAVE_ATOMIC_MODE_SET);
0224 }
0225 mutex_unlock(&client->modeset_mutex);
0226
0227 return 0;
0228 }
0229 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
0230
0231 static int
0232 __drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper,
0233 bool force)
0234 {
0235 bool do_delayed;
0236 int ret;
0237
0238 if (!drm_fbdev_emulation || !fb_helper)
0239 return -ENODEV;
0240
0241 if (READ_ONCE(fb_helper->deferred_setup))
0242 return 0;
0243
0244 mutex_lock(&fb_helper->lock);
0245 if (force) {
0246
0247
0248
0249
0250
0251 ret = drm_client_modeset_commit_locked(&fb_helper->client);
0252 } else {
0253 ret = drm_client_modeset_commit(&fb_helper->client);
0254 }
0255
0256 do_delayed = fb_helper->delayed_hotplug;
0257 if (do_delayed)
0258 fb_helper->delayed_hotplug = false;
0259 mutex_unlock(&fb_helper->lock);
0260
0261 if (do_delayed)
0262 drm_fb_helper_hotplug_event(fb_helper);
0263
0264 return ret;
0265 }
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278 int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
0279 {
0280 return __drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper, false);
0281 }
0282 EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
0283
0284 #ifdef CONFIG_MAGIC_SYSRQ
0285
0286 static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
0287 {
0288 struct drm_fb_helper *helper;
0289
0290 mutex_lock(&kernel_fb_helper_lock);
0291 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
0292 struct drm_device *dev = helper->dev;
0293
0294 if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
0295 continue;
0296
0297 mutex_lock(&helper->lock);
0298 drm_client_modeset_commit_locked(&helper->client);
0299 mutex_unlock(&helper->lock);
0300 }
0301 mutex_unlock(&kernel_fb_helper_lock);
0302 }
0303
0304 static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
0305
0306 static void drm_fb_helper_sysrq(int dummy1)
0307 {
0308 schedule_work(&drm_fb_helper_restore_work);
0309 }
0310
0311 static const struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
0312 .handler = drm_fb_helper_sysrq,
0313 .help_msg = "force-fb(v)",
0314 .action_msg = "Restore framebuffer console",
0315 };
0316 #else
0317 static const struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
0318 #endif
0319
0320 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
0321 {
0322 struct drm_fb_helper *fb_helper = info->par;
0323
0324 mutex_lock(&fb_helper->lock);
0325 drm_client_modeset_dpms(&fb_helper->client, dpms_mode);
0326 mutex_unlock(&fb_helper->lock);
0327 }
0328
0329
0330
0331
0332
0333
0334 int drm_fb_helper_blank(int blank, struct fb_info *info)
0335 {
0336 if (oops_in_progress)
0337 return -EBUSY;
0338
0339 switch (blank) {
0340
0341 case FB_BLANK_UNBLANK:
0342 drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
0343 break;
0344
0345 case FB_BLANK_NORMAL:
0346 drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
0347 break;
0348
0349 case FB_BLANK_HSYNC_SUSPEND:
0350 drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
0351 break;
0352
0353 case FB_BLANK_VSYNC_SUSPEND:
0354 drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND);
0355 break;
0356
0357 case FB_BLANK_POWERDOWN:
0358 drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
0359 break;
0360 }
0361 return 0;
0362 }
0363 EXPORT_SYMBOL(drm_fb_helper_blank);
0364
0365 static void drm_fb_helper_resume_worker(struct work_struct *work)
0366 {
0367 struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
0368 resume_work);
0369
0370 console_lock();
0371 fb_set_suspend(helper->fbdev, 0);
0372 console_unlock();
0373 }
0374
0375 static void drm_fb_helper_damage_blit_real(struct drm_fb_helper *fb_helper,
0376 struct drm_clip_rect *clip,
0377 struct iosys_map *dst)
0378 {
0379 struct drm_framebuffer *fb = fb_helper->fb;
0380 unsigned int cpp = fb->format->cpp[0];
0381 size_t offset = clip->y1 * fb->pitches[0] + clip->x1 * cpp;
0382 void *src = fb_helper->fbdev->screen_buffer + offset;
0383 size_t len = (clip->x2 - clip->x1) * cpp;
0384 unsigned int y;
0385
0386 iosys_map_incr(dst, offset);
0387
0388 for (y = clip->y1; y < clip->y2; y++) {
0389 iosys_map_memcpy_to(dst, 0, src, len);
0390 iosys_map_incr(dst, fb->pitches[0]);
0391 src += fb->pitches[0];
0392 }
0393 }
0394
0395 static int drm_fb_helper_damage_blit(struct drm_fb_helper *fb_helper,
0396 struct drm_clip_rect *clip)
0397 {
0398 struct drm_client_buffer *buffer = fb_helper->buffer;
0399 struct iosys_map map, dst;
0400 int ret;
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413 mutex_lock(&fb_helper->lock);
0414
0415 ret = drm_client_buffer_vmap(buffer, &map);
0416 if (ret)
0417 goto out;
0418
0419 dst = map;
0420 drm_fb_helper_damage_blit_real(fb_helper, clip, &dst);
0421
0422 drm_client_buffer_vunmap(buffer);
0423
0424 out:
0425 mutex_unlock(&fb_helper->lock);
0426
0427 return ret;
0428 }
0429
0430 static void drm_fb_helper_damage_work(struct work_struct *work)
0431 {
0432 struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
0433 damage_work);
0434 struct drm_device *dev = helper->dev;
0435 struct drm_clip_rect *clip = &helper->damage_clip;
0436 struct drm_clip_rect clip_copy;
0437 unsigned long flags;
0438 int ret;
0439
0440 spin_lock_irqsave(&helper->damage_lock, flags);
0441 clip_copy = *clip;
0442 clip->x1 = clip->y1 = ~0;
0443 clip->x2 = clip->y2 = 0;
0444 spin_unlock_irqrestore(&helper->damage_lock, flags);
0445
0446
0447 if (!(clip_copy.x1 < clip_copy.x2 && clip_copy.y1 < clip_copy.y2))
0448 return;
0449
0450 if (helper->buffer) {
0451 ret = drm_fb_helper_damage_blit(helper, &clip_copy);
0452 if (drm_WARN_ONCE(dev, ret, "Damage blitter failed: ret=%d\n", ret))
0453 goto err;
0454 }
0455
0456 if (helper->fb->funcs->dirty) {
0457 ret = helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
0458 if (drm_WARN_ONCE(dev, ret, "Dirty helper failed: ret=%d\n", ret))
0459 goto err;
0460 }
0461
0462 return;
0463
0464 err:
0465
0466
0467
0468
0469 spin_lock_irqsave(&helper->damage_lock, flags);
0470 clip->x1 = min_t(u32, clip->x1, clip_copy.x1);
0471 clip->y1 = min_t(u32, clip->y1, clip_copy.y1);
0472 clip->x2 = max_t(u32, clip->x2, clip_copy.x2);
0473 clip->y2 = max_t(u32, clip->y2, clip_copy.y2);
0474 spin_unlock_irqrestore(&helper->damage_lock, flags);
0475 }
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486 void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
0487 const struct drm_fb_helper_funcs *funcs)
0488 {
0489 INIT_LIST_HEAD(&helper->kernel_fb_list);
0490 spin_lock_init(&helper->damage_lock);
0491 INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker);
0492 INIT_WORK(&helper->damage_work, drm_fb_helper_damage_work);
0493 helper->damage_clip.x1 = helper->damage_clip.y1 = ~0;
0494 mutex_init(&helper->lock);
0495 helper->funcs = funcs;
0496 helper->dev = dev;
0497 }
0498 EXPORT_SYMBOL(drm_fb_helper_prepare);
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515 int drm_fb_helper_init(struct drm_device *dev,
0516 struct drm_fb_helper *fb_helper)
0517 {
0518 int ret;
0519
0520 if (!drm_fbdev_emulation) {
0521 dev->fb_helper = fb_helper;
0522 return 0;
0523 }
0524
0525
0526
0527
0528
0529 if (!fb_helper->client.funcs) {
0530 ret = drm_client_init(dev, &fb_helper->client, "drm_fb_helper", NULL);
0531 if (ret)
0532 return ret;
0533 }
0534
0535 dev->fb_helper = fb_helper;
0536
0537 return 0;
0538 }
0539 EXPORT_SYMBOL(drm_fb_helper_init);
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554 struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
0555 {
0556 struct device *dev = fb_helper->dev->dev;
0557 struct fb_info *info;
0558 int ret;
0559
0560 info = framebuffer_alloc(0, dev);
0561 if (!info)
0562 return ERR_PTR(-ENOMEM);
0563
0564 ret = fb_alloc_cmap(&info->cmap, 256, 0);
0565 if (ret)
0566 goto err_release;
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576 info->apertures = alloc_apertures(1);
0577 if (!info->apertures) {
0578 ret = -ENOMEM;
0579 goto err_free_cmap;
0580 }
0581
0582 fb_helper->fbdev = info;
0583 info->skip_vt_switch = true;
0584
0585 return info;
0586
0587 err_free_cmap:
0588 fb_dealloc_cmap(&info->cmap);
0589 err_release:
0590 framebuffer_release(info);
0591 return ERR_PTR(ret);
0592 }
0593 EXPORT_SYMBOL(drm_fb_helper_alloc_fbi);
0594
0595
0596
0597
0598
0599
0600
0601
0602
0603 void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper)
0604 {
0605 if (fb_helper && fb_helper->fbdev)
0606 unregister_framebuffer(fb_helper->fbdev);
0607 }
0608 EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
0609
0610
0611
0612
0613
0614
0615
0616 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
0617 {
0618 struct fb_info *info;
0619
0620 if (!fb_helper)
0621 return;
0622
0623 fb_helper->dev->fb_helper = NULL;
0624
0625 if (!drm_fbdev_emulation)
0626 return;
0627
0628 cancel_work_sync(&fb_helper->resume_work);
0629 cancel_work_sync(&fb_helper->damage_work);
0630
0631 info = fb_helper->fbdev;
0632 if (info) {
0633 if (info->cmap.len)
0634 fb_dealloc_cmap(&info->cmap);
0635 framebuffer_release(info);
0636 }
0637 fb_helper->fbdev = NULL;
0638
0639 mutex_lock(&kernel_fb_helper_lock);
0640 if (!list_empty(&fb_helper->kernel_fb_list)) {
0641 list_del(&fb_helper->kernel_fb_list);
0642 if (list_empty(&kernel_fb_helper_list))
0643 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
0644 }
0645 mutex_unlock(&kernel_fb_helper_lock);
0646
0647 mutex_destroy(&fb_helper->lock);
0648
0649 if (!fb_helper->client.funcs)
0650 drm_client_release(&fb_helper->client);
0651 }
0652 EXPORT_SYMBOL(drm_fb_helper_fini);
0653
0654 static bool drm_fbdev_use_shadow_fb(struct drm_fb_helper *fb_helper)
0655 {
0656 struct drm_device *dev = fb_helper->dev;
0657 struct drm_framebuffer *fb = fb_helper->fb;
0658
0659 return dev->mode_config.prefer_shadow_fbdev ||
0660 dev->mode_config.prefer_shadow ||
0661 fb->funcs->dirty;
0662 }
0663
0664 static void drm_fb_helper_damage(struct fb_info *info, u32 x, u32 y,
0665 u32 width, u32 height)
0666 {
0667 struct drm_fb_helper *helper = info->par;
0668 struct drm_clip_rect *clip = &helper->damage_clip;
0669 unsigned long flags;
0670
0671 if (!drm_fbdev_use_shadow_fb(helper))
0672 return;
0673
0674 spin_lock_irqsave(&helper->damage_lock, flags);
0675 clip->x1 = min_t(u32, clip->x1, x);
0676 clip->y1 = min_t(u32, clip->y1, y);
0677 clip->x2 = max_t(u32, clip->x2, x + width);
0678 clip->y2 = max_t(u32, clip->y2, y + height);
0679 spin_unlock_irqrestore(&helper->damage_lock, flags);
0680
0681 schedule_work(&helper->damage_work);
0682 }
0683
0684
0685
0686
0687
0688
0689 static void drm_fb_helper_memory_range_to_clip(struct fb_info *info, off_t off, size_t len,
0690 struct drm_rect *clip)
0691 {
0692 off_t end = off + len;
0693 u32 x1 = 0;
0694 u32 y1 = off / info->fix.line_length;
0695 u32 x2 = info->var.xres;
0696 u32 y2 = DIV_ROUND_UP(end, info->fix.line_length);
0697
0698 if ((y2 - y1) == 1) {
0699
0700
0701
0702
0703 off_t bit_off = (off % info->fix.line_length) * 8;
0704 off_t bit_end = (end % info->fix.line_length) * 8;
0705
0706 x1 = bit_off / info->var.bits_per_pixel;
0707 x2 = DIV_ROUND_UP(bit_end, info->var.bits_per_pixel);
0708 }
0709
0710 drm_rect_init(clip, x1, y1, x2 - x1, y2 - y1);
0711 }
0712
0713
0714
0715
0716
0717
0718
0719
0720
0721 void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagereflist)
0722 {
0723 unsigned long start, end, min_off, max_off;
0724 struct fb_deferred_io_pageref *pageref;
0725 struct drm_rect damage_area;
0726
0727 min_off = ULONG_MAX;
0728 max_off = 0;
0729 list_for_each_entry(pageref, pagereflist, list) {
0730 start = pageref->offset;
0731 end = start + PAGE_SIZE;
0732 min_off = min(min_off, start);
0733 max_off = max(max_off, end);
0734 }
0735 if (min_off >= max_off)
0736 return;
0737
0738
0739
0740
0741
0742
0743 max_off = min(max_off, info->screen_size);
0744
0745 drm_fb_helper_memory_range_to_clip(info, min_off, max_off - min_off, &damage_area);
0746 drm_fb_helper_damage(info, damage_area.x1, damage_area.y1,
0747 drm_rect_width(&damage_area),
0748 drm_rect_height(&damage_area));
0749 }
0750 EXPORT_SYMBOL(drm_fb_helper_deferred_io);
0751
0752
0753
0754
0755
0756
0757
0758
0759
0760
0761 ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
0762 size_t count, loff_t *ppos)
0763 {
0764 return fb_sys_read(info, buf, count, ppos);
0765 }
0766 EXPORT_SYMBOL(drm_fb_helper_sys_read);
0767
0768
0769
0770
0771
0772
0773
0774
0775
0776
0777 ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
0778 size_t count, loff_t *ppos)
0779 {
0780 loff_t pos = *ppos;
0781 ssize_t ret;
0782 struct drm_rect damage_area;
0783
0784 ret = fb_sys_write(info, buf, count, ppos);
0785 if (ret <= 0)
0786 return ret;
0787
0788 drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area);
0789 drm_fb_helper_damage(info, damage_area.x1, damage_area.y1,
0790 drm_rect_width(&damage_area),
0791 drm_rect_height(&damage_area));
0792
0793 return ret;
0794 }
0795 EXPORT_SYMBOL(drm_fb_helper_sys_write);
0796
0797
0798
0799
0800
0801
0802
0803
0804 void drm_fb_helper_sys_fillrect(struct fb_info *info,
0805 const struct fb_fillrect *rect)
0806 {
0807 sys_fillrect(info, rect);
0808 drm_fb_helper_damage(info, rect->dx, rect->dy, rect->width, rect->height);
0809 }
0810 EXPORT_SYMBOL(drm_fb_helper_sys_fillrect);
0811
0812
0813
0814
0815
0816
0817
0818
0819 void drm_fb_helper_sys_copyarea(struct fb_info *info,
0820 const struct fb_copyarea *area)
0821 {
0822 sys_copyarea(info, area);
0823 drm_fb_helper_damage(info, area->dx, area->dy, area->width, area->height);
0824 }
0825 EXPORT_SYMBOL(drm_fb_helper_sys_copyarea);
0826
0827
0828
0829
0830
0831
0832
0833
0834 void drm_fb_helper_sys_imageblit(struct fb_info *info,
0835 const struct fb_image *image)
0836 {
0837 sys_imageblit(info, image);
0838 drm_fb_helper_damage(info, image->dx, image->dy, image->width, image->height);
0839 }
0840 EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
0841
0842
0843
0844
0845
0846
0847
0848
0849 void drm_fb_helper_cfb_fillrect(struct fb_info *info,
0850 const struct fb_fillrect *rect)
0851 {
0852 cfb_fillrect(info, rect);
0853 drm_fb_helper_damage(info, rect->dx, rect->dy, rect->width, rect->height);
0854 }
0855 EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect);
0856
0857
0858
0859
0860
0861
0862
0863
0864 void drm_fb_helper_cfb_copyarea(struct fb_info *info,
0865 const struct fb_copyarea *area)
0866 {
0867 cfb_copyarea(info, area);
0868 drm_fb_helper_damage(info, area->dx, area->dy, area->width, area->height);
0869 }
0870 EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea);
0871
0872
0873
0874
0875
0876
0877
0878
0879 void drm_fb_helper_cfb_imageblit(struct fb_info *info,
0880 const struct fb_image *image)
0881 {
0882 cfb_imageblit(info, image);
0883 drm_fb_helper_damage(info, image->dx, image->dy, image->width, image->height);
0884 }
0885 EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896 void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend)
0897 {
0898 if (fb_helper && fb_helper->fbdev)
0899 fb_set_suspend(fb_helper->fbdev, suspend);
0900 }
0901 EXPORT_SYMBOL(drm_fb_helper_set_suspend);
0902
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919 void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
0920 bool suspend)
0921 {
0922 if (!fb_helper || !fb_helper->fbdev)
0923 return;
0924
0925
0926 flush_work(&fb_helper->resume_work);
0927
0928 if (suspend) {
0929 if (fb_helper->fbdev->state != FBINFO_STATE_RUNNING)
0930 return;
0931
0932 console_lock();
0933
0934 } else {
0935 if (fb_helper->fbdev->state == FBINFO_STATE_RUNNING)
0936 return;
0937
0938 if (!console_trylock()) {
0939 schedule_work(&fb_helper->resume_work);
0940 return;
0941 }
0942 }
0943
0944 fb_set_suspend(fb_helper->fbdev, suspend);
0945 console_unlock();
0946 }
0947 EXPORT_SYMBOL(drm_fb_helper_set_suspend_unlocked);
0948
0949 static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info)
0950 {
0951 u32 *palette = (u32 *)info->pseudo_palette;
0952 int i;
0953
0954 if (cmap->start + cmap->len > 16)
0955 return -EINVAL;
0956
0957 for (i = 0; i < cmap->len; ++i) {
0958 u16 red = cmap->red[i];
0959 u16 green = cmap->green[i];
0960 u16 blue = cmap->blue[i];
0961 u32 value;
0962
0963 red >>= 16 - info->var.red.length;
0964 green >>= 16 - info->var.green.length;
0965 blue >>= 16 - info->var.blue.length;
0966 value = (red << info->var.red.offset) |
0967 (green << info->var.green.offset) |
0968 (blue << info->var.blue.offset);
0969 if (info->var.transp.length > 0) {
0970 u32 mask = (1 << info->var.transp.length) - 1;
0971
0972 mask <<= info->var.transp.offset;
0973 value |= mask;
0974 }
0975 palette[cmap->start + i] = value;
0976 }
0977
0978 return 0;
0979 }
0980
0981 static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
0982 {
0983 struct drm_fb_helper *fb_helper = info->par;
0984 struct drm_mode_set *modeset;
0985 struct drm_crtc *crtc;
0986 u16 *r, *g, *b;
0987 int ret = 0;
0988
0989 drm_modeset_lock_all(fb_helper->dev);
0990 drm_client_for_each_modeset(modeset, &fb_helper->client) {
0991 crtc = modeset->crtc;
0992 if (!crtc->funcs->gamma_set || !crtc->gamma_size) {
0993 ret = -EINVAL;
0994 goto out;
0995 }
0996
0997 if (cmap->start + cmap->len > crtc->gamma_size) {
0998 ret = -EINVAL;
0999 goto out;
1000 }
1001
1002 r = crtc->gamma_store;
1003 g = r + crtc->gamma_size;
1004 b = g + crtc->gamma_size;
1005
1006 memcpy(r + cmap->start, cmap->red, cmap->len * sizeof(*r));
1007 memcpy(g + cmap->start, cmap->green, cmap->len * sizeof(*g));
1008 memcpy(b + cmap->start, cmap->blue, cmap->len * sizeof(*b));
1009
1010 ret = crtc->funcs->gamma_set(crtc, r, g, b,
1011 crtc->gamma_size, NULL);
1012 if (ret)
1013 goto out;
1014 }
1015 out:
1016 drm_modeset_unlock_all(fb_helper->dev);
1017
1018 return ret;
1019 }
1020
1021 static struct drm_property_blob *setcmap_new_gamma_lut(struct drm_crtc *crtc,
1022 struct fb_cmap *cmap)
1023 {
1024 struct drm_device *dev = crtc->dev;
1025 struct drm_property_blob *gamma_lut;
1026 struct drm_color_lut *lut;
1027 int size = crtc->gamma_size;
1028 int i;
1029
1030 if (!size || cmap->start + cmap->len > size)
1031 return ERR_PTR(-EINVAL);
1032
1033 gamma_lut = drm_property_create_blob(dev, sizeof(*lut) * size, NULL);
1034 if (IS_ERR(gamma_lut))
1035 return gamma_lut;
1036
1037 lut = gamma_lut->data;
1038 if (cmap->start || cmap->len != size) {
1039 u16 *r = crtc->gamma_store;
1040 u16 *g = r + crtc->gamma_size;
1041 u16 *b = g + crtc->gamma_size;
1042
1043 for (i = 0; i < cmap->start; i++) {
1044 lut[i].red = r[i];
1045 lut[i].green = g[i];
1046 lut[i].blue = b[i];
1047 }
1048 for (i = cmap->start + cmap->len; i < size; i++) {
1049 lut[i].red = r[i];
1050 lut[i].green = g[i];
1051 lut[i].blue = b[i];
1052 }
1053 }
1054
1055 for (i = 0; i < cmap->len; i++) {
1056 lut[cmap->start + i].red = cmap->red[i];
1057 lut[cmap->start + i].green = cmap->green[i];
1058 lut[cmap->start + i].blue = cmap->blue[i];
1059 }
1060
1061 return gamma_lut;
1062 }
1063
1064 static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
1065 {
1066 struct drm_fb_helper *fb_helper = info->par;
1067 struct drm_device *dev = fb_helper->dev;
1068 struct drm_property_blob *gamma_lut = NULL;
1069 struct drm_modeset_acquire_ctx ctx;
1070 struct drm_crtc_state *crtc_state;
1071 struct drm_atomic_state *state;
1072 struct drm_mode_set *modeset;
1073 struct drm_crtc *crtc;
1074 u16 *r, *g, *b;
1075 bool replaced;
1076 int ret = 0;
1077
1078 drm_modeset_acquire_init(&ctx, 0);
1079
1080 state = drm_atomic_state_alloc(dev);
1081 if (!state) {
1082 ret = -ENOMEM;
1083 goto out_ctx;
1084 }
1085
1086 state->acquire_ctx = &ctx;
1087 retry:
1088 drm_client_for_each_modeset(modeset, &fb_helper->client) {
1089 crtc = modeset->crtc;
1090
1091 if (!gamma_lut)
1092 gamma_lut = setcmap_new_gamma_lut(crtc, cmap);
1093 if (IS_ERR(gamma_lut)) {
1094 ret = PTR_ERR(gamma_lut);
1095 gamma_lut = NULL;
1096 goto out_state;
1097 }
1098
1099 crtc_state = drm_atomic_get_crtc_state(state, crtc);
1100 if (IS_ERR(crtc_state)) {
1101 ret = PTR_ERR(crtc_state);
1102 goto out_state;
1103 }
1104
1105
1106
1107
1108
1109
1110 replaced = drm_property_replace_blob(&crtc_state->degamma_lut,
1111 NULL);
1112 replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
1113 replaced |= drm_property_replace_blob(&crtc_state->gamma_lut,
1114 gamma_lut);
1115 crtc_state->color_mgmt_changed |= replaced;
1116 }
1117
1118 ret = drm_atomic_commit(state);
1119 if (ret)
1120 goto out_state;
1121
1122 drm_client_for_each_modeset(modeset, &fb_helper->client) {
1123 crtc = modeset->crtc;
1124
1125 r = crtc->gamma_store;
1126 g = r + crtc->gamma_size;
1127 b = g + crtc->gamma_size;
1128
1129 memcpy(r + cmap->start, cmap->red, cmap->len * sizeof(*r));
1130 memcpy(g + cmap->start, cmap->green, cmap->len * sizeof(*g));
1131 memcpy(b + cmap->start, cmap->blue, cmap->len * sizeof(*b));
1132 }
1133
1134 out_state:
1135 if (ret == -EDEADLK)
1136 goto backoff;
1137
1138 drm_property_blob_put(gamma_lut);
1139 drm_atomic_state_put(state);
1140 out_ctx:
1141 drm_modeset_drop_locks(&ctx);
1142 drm_modeset_acquire_fini(&ctx);
1143
1144 return ret;
1145
1146 backoff:
1147 drm_atomic_state_clear(state);
1148 drm_modeset_backoff(&ctx);
1149 goto retry;
1150 }
1151
1152
1153
1154
1155
1156
1157 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1158 {
1159 struct drm_fb_helper *fb_helper = info->par;
1160 struct drm_device *dev = fb_helper->dev;
1161 int ret;
1162
1163 if (oops_in_progress)
1164 return -EBUSY;
1165
1166 mutex_lock(&fb_helper->lock);
1167
1168 if (!drm_master_internal_acquire(dev)) {
1169 ret = -EBUSY;
1170 goto unlock;
1171 }
1172
1173 mutex_lock(&fb_helper->client.modeset_mutex);
1174 if (info->fix.visual == FB_VISUAL_TRUECOLOR)
1175 ret = setcmap_pseudo_palette(cmap, info);
1176 else if (drm_drv_uses_atomic_modeset(fb_helper->dev))
1177 ret = setcmap_atomic(cmap, info);
1178 else
1179 ret = setcmap_legacy(cmap, info);
1180 mutex_unlock(&fb_helper->client.modeset_mutex);
1181
1182 drm_master_internal_release(dev);
1183 unlock:
1184 mutex_unlock(&fb_helper->lock);
1185
1186 return ret;
1187 }
1188 EXPORT_SYMBOL(drm_fb_helper_setcmap);
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199 int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
1200 unsigned long arg)
1201 {
1202 struct drm_fb_helper *fb_helper = info->par;
1203 struct drm_device *dev = fb_helper->dev;
1204 struct drm_crtc *crtc;
1205 int ret = 0;
1206
1207 mutex_lock(&fb_helper->lock);
1208 if (!drm_master_internal_acquire(dev)) {
1209 ret = -EBUSY;
1210 goto unlock;
1211 }
1212
1213 switch (cmd) {
1214 case FBIO_WAITFORVSYNC:
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231 crtc = fb_helper->client.modesets[0].crtc;
1232
1233
1234
1235
1236
1237
1238 ret = drm_crtc_vblank_get(crtc);
1239 if (!ret) {
1240 drm_crtc_wait_one_vblank(crtc);
1241 drm_crtc_vblank_put(crtc);
1242 }
1243
1244 ret = 0;
1245 break;
1246 default:
1247 ret = -ENOTTY;
1248 }
1249
1250 drm_master_internal_release(dev);
1251 unlock:
1252 mutex_unlock(&fb_helper->lock);
1253 return ret;
1254 }
1255 EXPORT_SYMBOL(drm_fb_helper_ioctl);
1256
1257 static bool drm_fb_pixel_format_equal(const struct fb_var_screeninfo *var_1,
1258 const struct fb_var_screeninfo *var_2)
1259 {
1260 return var_1->bits_per_pixel == var_2->bits_per_pixel &&
1261 var_1->grayscale == var_2->grayscale &&
1262 var_1->red.offset == var_2->red.offset &&
1263 var_1->red.length == var_2->red.length &&
1264 var_1->red.msb_right == var_2->red.msb_right &&
1265 var_1->green.offset == var_2->green.offset &&
1266 var_1->green.length == var_2->green.length &&
1267 var_1->green.msb_right == var_2->green.msb_right &&
1268 var_1->blue.offset == var_2->blue.offset &&
1269 var_1->blue.length == var_2->blue.length &&
1270 var_1->blue.msb_right == var_2->blue.msb_right &&
1271 var_1->transp.offset == var_2->transp.offset &&
1272 var_1->transp.length == var_2->transp.length &&
1273 var_1->transp.msb_right == var_2->transp.msb_right;
1274 }
1275
1276 static void drm_fb_helper_fill_pixel_fmt(struct fb_var_screeninfo *var,
1277 u8 depth)
1278 {
1279 switch (depth) {
1280 case 8:
1281 var->red.offset = 0;
1282 var->green.offset = 0;
1283 var->blue.offset = 0;
1284 var->red.length = 8;
1285 var->green.length = 8;
1286 var->blue.length = 8;
1287 var->transp.offset = 0;
1288 var->transp.length = 0;
1289 break;
1290 case 15:
1291 var->red.offset = 10;
1292 var->green.offset = 5;
1293 var->blue.offset = 0;
1294 var->red.length = 5;
1295 var->green.length = 5;
1296 var->blue.length = 5;
1297 var->transp.offset = 15;
1298 var->transp.length = 1;
1299 break;
1300 case 16:
1301 var->red.offset = 11;
1302 var->green.offset = 5;
1303 var->blue.offset = 0;
1304 var->red.length = 5;
1305 var->green.length = 6;
1306 var->blue.length = 5;
1307 var->transp.offset = 0;
1308 break;
1309 case 24:
1310 var->red.offset = 16;
1311 var->green.offset = 8;
1312 var->blue.offset = 0;
1313 var->red.length = 8;
1314 var->green.length = 8;
1315 var->blue.length = 8;
1316 var->transp.offset = 0;
1317 var->transp.length = 0;
1318 break;
1319 case 32:
1320 var->red.offset = 16;
1321 var->green.offset = 8;
1322 var->blue.offset = 0;
1323 var->red.length = 8;
1324 var->green.length = 8;
1325 var->blue.length = 8;
1326 var->transp.offset = 24;
1327 var->transp.length = 8;
1328 break;
1329 default:
1330 break;
1331 }
1332 }
1333
1334
1335
1336
1337
1338
1339 int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
1340 struct fb_info *info)
1341 {
1342 struct drm_fb_helper *fb_helper = info->par;
1343 struct drm_framebuffer *fb = fb_helper->fb;
1344 struct drm_device *dev = fb_helper->dev;
1345
1346 if (in_dbg_master())
1347 return -EINVAL;
1348
1349 if (var->pixclock != 0) {
1350 drm_dbg_kms(dev, "fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n");
1351 var->pixclock = 0;
1352 }
1353
1354 if ((drm_format_info_block_width(fb->format, 0) > 1) ||
1355 (drm_format_info_block_height(fb->format, 0) > 1))
1356 return -EINVAL;
1357
1358
1359
1360
1361
1362 if (var->bits_per_pixel > fb->format->cpp[0] * 8 ||
1363 var->xres > fb->width || var->yres > fb->height ||
1364 var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
1365 drm_dbg_kms(dev, "fb requested width/height/bpp can't fit in current fb "
1366 "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
1367 var->xres, var->yres, var->bits_per_pixel,
1368 var->xres_virtual, var->yres_virtual,
1369 fb->width, fb->height, fb->format->cpp[0] * 8);
1370 return -EINVAL;
1371 }
1372
1373
1374
1375
1376
1377
1378 if (!var->red.offset && !var->green.offset &&
1379 !var->blue.offset && !var->transp.offset &&
1380 !var->red.length && !var->green.length &&
1381 !var->blue.length && !var->transp.length &&
1382 !var->red.msb_right && !var->green.msb_right &&
1383 !var->blue.msb_right && !var->transp.msb_right) {
1384 drm_fb_helper_fill_pixel_fmt(var, fb->format->depth);
1385 }
1386
1387
1388
1389
1390 var->bits_per_pixel = fb->format->cpp[0] * 8;
1391
1392
1393
1394
1395
1396 if (!drm_fb_pixel_format_equal(var, &info->var)) {
1397 drm_dbg_kms(dev, "fbdev emulation doesn't support changing the pixel format\n");
1398 return -EINVAL;
1399 }
1400
1401 return 0;
1402 }
1403 EXPORT_SYMBOL(drm_fb_helper_check_var);
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413 int drm_fb_helper_set_par(struct fb_info *info)
1414 {
1415 struct drm_fb_helper *fb_helper = info->par;
1416 struct fb_var_screeninfo *var = &info->var;
1417 bool force;
1418
1419 if (oops_in_progress)
1420 return -EBUSY;
1421
1422 if (var->pixclock != 0) {
1423 drm_err(fb_helper->dev, "PIXEL CLOCK SET\n");
1424 return -EINVAL;
1425 }
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443 force = var->activate & FB_ACTIVATE_KD_TEXT;
1444
1445 __drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper, force);
1446
1447 return 0;
1448 }
1449 EXPORT_SYMBOL(drm_fb_helper_set_par);
1450
1451 static void pan_set(struct drm_fb_helper *fb_helper, int x, int y)
1452 {
1453 struct drm_mode_set *mode_set;
1454
1455 mutex_lock(&fb_helper->client.modeset_mutex);
1456 drm_client_for_each_modeset(mode_set, &fb_helper->client) {
1457 mode_set->x = x;
1458 mode_set->y = y;
1459 }
1460 mutex_unlock(&fb_helper->client.modeset_mutex);
1461 }
1462
1463 static int pan_display_atomic(struct fb_var_screeninfo *var,
1464 struct fb_info *info)
1465 {
1466 struct drm_fb_helper *fb_helper = info->par;
1467 int ret;
1468
1469 pan_set(fb_helper, var->xoffset, var->yoffset);
1470
1471 ret = drm_client_modeset_commit_locked(&fb_helper->client);
1472 if (!ret) {
1473 info->var.xoffset = var->xoffset;
1474 info->var.yoffset = var->yoffset;
1475 } else
1476 pan_set(fb_helper, info->var.xoffset, info->var.yoffset);
1477
1478 return ret;
1479 }
1480
1481 static int pan_display_legacy(struct fb_var_screeninfo *var,
1482 struct fb_info *info)
1483 {
1484 struct drm_fb_helper *fb_helper = info->par;
1485 struct drm_client_dev *client = &fb_helper->client;
1486 struct drm_mode_set *modeset;
1487 int ret = 0;
1488
1489 mutex_lock(&client->modeset_mutex);
1490 drm_modeset_lock_all(fb_helper->dev);
1491 drm_client_for_each_modeset(modeset, client) {
1492 modeset->x = var->xoffset;
1493 modeset->y = var->yoffset;
1494
1495 if (modeset->num_connectors) {
1496 ret = drm_mode_set_config_internal(modeset);
1497 if (!ret) {
1498 info->var.xoffset = var->xoffset;
1499 info->var.yoffset = var->yoffset;
1500 }
1501 }
1502 }
1503 drm_modeset_unlock_all(fb_helper->dev);
1504 mutex_unlock(&client->modeset_mutex);
1505
1506 return ret;
1507 }
1508
1509
1510
1511
1512
1513
1514 int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
1515 struct fb_info *info)
1516 {
1517 struct drm_fb_helper *fb_helper = info->par;
1518 struct drm_device *dev = fb_helper->dev;
1519 int ret;
1520
1521 if (oops_in_progress)
1522 return -EBUSY;
1523
1524 mutex_lock(&fb_helper->lock);
1525 if (!drm_master_internal_acquire(dev)) {
1526 ret = -EBUSY;
1527 goto unlock;
1528 }
1529
1530 if (drm_drv_uses_atomic_modeset(dev))
1531 ret = pan_display_atomic(var, info);
1532 else
1533 ret = pan_display_legacy(var, info);
1534
1535 drm_master_internal_release(dev);
1536 unlock:
1537 mutex_unlock(&fb_helper->lock);
1538
1539 return ret;
1540 }
1541 EXPORT_SYMBOL(drm_fb_helper_pan_display);
1542
1543
1544
1545
1546
1547 static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
1548 int preferred_bpp)
1549 {
1550 struct drm_client_dev *client = &fb_helper->client;
1551 struct drm_device *dev = fb_helper->dev;
1552 struct drm_mode_config *config = &dev->mode_config;
1553 int ret = 0;
1554 int crtc_count = 0;
1555 struct drm_connector_list_iter conn_iter;
1556 struct drm_fb_helper_surface_size sizes;
1557 struct drm_connector *connector;
1558 struct drm_mode_set *mode_set;
1559 int best_depth = 0;
1560
1561 memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
1562 sizes.surface_depth = 24;
1563 sizes.surface_bpp = 32;
1564 sizes.fb_width = (u32)-1;
1565 sizes.fb_height = (u32)-1;
1566
1567
1568
1569
1570
1571 if (preferred_bpp != sizes.surface_bpp)
1572 sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
1573
1574 drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
1575 drm_client_for_each_connector_iter(connector, &conn_iter) {
1576 struct drm_cmdline_mode *cmdline_mode;
1577
1578 cmdline_mode = &connector->cmdline_mode;
1579
1580 if (cmdline_mode->bpp_specified) {
1581 switch (cmdline_mode->bpp) {
1582 case 8:
1583 sizes.surface_depth = sizes.surface_bpp = 8;
1584 break;
1585 case 15:
1586 sizes.surface_depth = 15;
1587 sizes.surface_bpp = 16;
1588 break;
1589 case 16:
1590 sizes.surface_depth = sizes.surface_bpp = 16;
1591 break;
1592 case 24:
1593 sizes.surface_depth = sizes.surface_bpp = 24;
1594 break;
1595 case 32:
1596 sizes.surface_depth = 24;
1597 sizes.surface_bpp = 32;
1598 break;
1599 }
1600 break;
1601 }
1602 }
1603 drm_connector_list_iter_end(&conn_iter);
1604
1605
1606
1607
1608
1609
1610 mutex_lock(&client->modeset_mutex);
1611 drm_client_for_each_modeset(mode_set, client) {
1612 struct drm_crtc *crtc = mode_set->crtc;
1613 struct drm_plane *plane = crtc->primary;
1614 int j;
1615
1616 drm_dbg_kms(dev, "test CRTC %u primary plane\n", drm_crtc_index(crtc));
1617
1618 for (j = 0; j < plane->format_count; j++) {
1619 const struct drm_format_info *fmt;
1620
1621 fmt = drm_format_info(plane->format_types[j]);
1622
1623
1624
1625
1626
1627
1628
1629
1630 if (fmt->depth == 0)
1631 continue;
1632
1633
1634 if (fmt->depth == sizes.surface_depth) {
1635 best_depth = fmt->depth;
1636 break;
1637 }
1638
1639
1640 if (fmt->depth > sizes.surface_depth)
1641 continue;
1642
1643
1644 if (fmt->depth > best_depth)
1645 best_depth = fmt->depth;
1646 }
1647 }
1648 if (sizes.surface_depth != best_depth && best_depth) {
1649 drm_info(dev, "requested bpp %d, scaled depth down to %d",
1650 sizes.surface_bpp, best_depth);
1651 sizes.surface_depth = best_depth;
1652 }
1653
1654
1655 crtc_count = 0;
1656 drm_client_for_each_modeset(mode_set, client) {
1657 struct drm_display_mode *desired_mode;
1658 int x, y, j;
1659
1660
1661
1662
1663 bool lastv = true, lasth = true;
1664
1665 desired_mode = mode_set->mode;
1666
1667 if (!desired_mode)
1668 continue;
1669
1670 crtc_count++;
1671
1672 x = mode_set->x;
1673 y = mode_set->y;
1674
1675 sizes.surface_width = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
1676 sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
1677
1678 for (j = 0; j < mode_set->num_connectors; j++) {
1679 struct drm_connector *connector = mode_set->connectors[j];
1680
1681 if (connector->has_tile &&
1682 desired_mode->hdisplay == connector->tile_h_size &&
1683 desired_mode->vdisplay == connector->tile_v_size) {
1684 lasth = (connector->tile_h_loc == (connector->num_h_tile - 1));
1685 lastv = (connector->tile_v_loc == (connector->num_v_tile - 1));
1686
1687 break;
1688 }
1689 }
1690
1691 if (lasth)
1692 sizes.fb_width = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width);
1693 if (lastv)
1694 sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
1695 }
1696 mutex_unlock(&client->modeset_mutex);
1697
1698 if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
1699 drm_info(dev, "Cannot find any crtc or sizes\n");
1700
1701
1702 if (!fb_helper->deferred_setup)
1703 drm_client_modeset_commit(client);
1704 return -EAGAIN;
1705 }
1706
1707
1708 sizes.surface_height *= drm_fbdev_overalloc;
1709 sizes.surface_height /= 100;
1710 if (sizes.surface_height > config->max_height) {
1711 drm_dbg_kms(dev, "Fbdev over-allocation too large; clamping height to %d\n",
1712 config->max_height);
1713 sizes.surface_height = config->max_height;
1714 }
1715
1716
1717 ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
1718 if (ret < 0)
1719 return ret;
1720
1721 strcpy(fb_helper->fb->comm, "[fbcon]");
1722 return 0;
1723 }
1724
1725 static void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
1726 uint32_t depth)
1727 {
1728 info->fix.type = FB_TYPE_PACKED_PIXELS;
1729 info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
1730 FB_VISUAL_TRUECOLOR;
1731 info->fix.mmio_start = 0;
1732 info->fix.mmio_len = 0;
1733 info->fix.type_aux = 0;
1734 info->fix.xpanstep = 1;
1735 info->fix.ypanstep = 1;
1736 info->fix.ywrapstep = 0;
1737 info->fix.accel = FB_ACCEL_NONE;
1738
1739 info->fix.line_length = pitch;
1740 }
1741
1742 static void drm_fb_helper_fill_var(struct fb_info *info,
1743 struct drm_fb_helper *fb_helper,
1744 uint32_t fb_width, uint32_t fb_height)
1745 {
1746 struct drm_framebuffer *fb = fb_helper->fb;
1747
1748 WARN_ON((drm_format_info_block_width(fb->format, 0) > 1) ||
1749 (drm_format_info_block_height(fb->format, 0) > 1));
1750 info->pseudo_palette = fb_helper->pseudo_palette;
1751 info->var.xres_virtual = fb->width;
1752 info->var.yres_virtual = fb->height;
1753 info->var.bits_per_pixel = fb->format->cpp[0] * 8;
1754 info->var.accel_flags = FB_ACCELF_TEXT;
1755 info->var.xoffset = 0;
1756 info->var.yoffset = 0;
1757 info->var.activate = FB_ACTIVATE_NOW;
1758
1759 drm_fb_helper_fill_pixel_fmt(&info->var, fb->format->depth);
1760
1761 info->var.xres = fb_width;
1762 info->var.yres = fb_height;
1763 }
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778 void drm_fb_helper_fill_info(struct fb_info *info,
1779 struct drm_fb_helper *fb_helper,
1780 struct drm_fb_helper_surface_size *sizes)
1781 {
1782 struct drm_framebuffer *fb = fb_helper->fb;
1783
1784 drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
1785 drm_fb_helper_fill_var(info, fb_helper,
1786 sizes->fb_width, sizes->fb_height);
1787
1788 info->par = fb_helper;
1789
1790
1791
1792
1793
1794
1795 snprintf(info->fix.id, sizeof(info->fix.id), "%sdrmfb",
1796 fb_helper->dev->driver->name);
1797
1798 }
1799 EXPORT_SYMBOL(drm_fb_helper_fill_info);
1800
1801
1802
1803
1804
1805
1806
1807
1808 static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
1809 {
1810 struct drm_client_dev *client = &fb_helper->client;
1811 struct drm_connector_list_iter conn_iter;
1812 struct fb_info *info = fb_helper->fbdev;
1813 unsigned int rotation, sw_rotations = 0;
1814 struct drm_connector *connector;
1815 struct drm_mode_set *modeset;
1816
1817 mutex_lock(&client->modeset_mutex);
1818 drm_client_for_each_modeset(modeset, client) {
1819 if (!modeset->num_connectors)
1820 continue;
1821
1822 modeset->fb = fb_helper->fb;
1823
1824 if (drm_client_rotation(modeset, &rotation))
1825
1826 sw_rotations |= DRM_MODE_ROTATE_0;
1827 else
1828 sw_rotations |= rotation;
1829 }
1830 mutex_unlock(&client->modeset_mutex);
1831
1832 drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
1833 drm_client_for_each_connector_iter(connector, &conn_iter) {
1834
1835
1836 if (connector->status == connector_status_connected) {
1837 info->var.width = connector->display_info.width_mm;
1838 info->var.height = connector->display_info.height_mm;
1839 break;
1840 }
1841 }
1842 drm_connector_list_iter_end(&conn_iter);
1843
1844 switch (sw_rotations) {
1845 case DRM_MODE_ROTATE_0:
1846 info->fbcon_rotate_hint = FB_ROTATE_UR;
1847 break;
1848 case DRM_MODE_ROTATE_90:
1849 info->fbcon_rotate_hint = FB_ROTATE_CCW;
1850 break;
1851 case DRM_MODE_ROTATE_180:
1852 info->fbcon_rotate_hint = FB_ROTATE_UD;
1853 break;
1854 case DRM_MODE_ROTATE_270:
1855 info->fbcon_rotate_hint = FB_ROTATE_CW;
1856 break;
1857 default:
1858
1859
1860
1861
1862
1863 info->fbcon_rotate_hint = FB_ROTATE_UR;
1864 }
1865 }
1866
1867
1868 static int
1869 __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
1870 int bpp_sel)
1871 {
1872 struct drm_device *dev = fb_helper->dev;
1873 struct fb_info *info;
1874 unsigned int width, height;
1875 int ret;
1876
1877 width = dev->mode_config.max_width;
1878 height = dev->mode_config.max_height;
1879
1880 drm_client_modeset_probe(&fb_helper->client, width, height);
1881 ret = drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1882 if (ret < 0) {
1883 if (ret == -EAGAIN) {
1884 fb_helper->preferred_bpp = bpp_sel;
1885 fb_helper->deferred_setup = true;
1886 ret = 0;
1887 }
1888 mutex_unlock(&fb_helper->lock);
1889
1890 return ret;
1891 }
1892 drm_setup_crtcs_fb(fb_helper);
1893
1894 fb_helper->deferred_setup = false;
1895
1896 info = fb_helper->fbdev;
1897 info->var.pixclock = 0;
1898
1899 #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
1900 if (!drm_leak_fbdev_smem)
1901 #endif
1902
1903 info->flags |= FBINFO_HIDE_SMEM_START;
1904
1905
1906
1907
1908 mutex_unlock(&fb_helper->lock);
1909
1910 ret = register_framebuffer(info);
1911 if (ret < 0)
1912 return ret;
1913
1914 drm_info(dev, "fb%d: %s frame buffer device\n",
1915 info->node, info->fix.id);
1916
1917 mutex_lock(&kernel_fb_helper_lock);
1918 if (list_empty(&kernel_fb_helper_list))
1919 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
1920
1921 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
1922 mutex_unlock(&kernel_fb_helper_lock);
1923
1924 return 0;
1925 }
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968 int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1969 {
1970 int ret;
1971
1972 if (!drm_fbdev_emulation)
1973 return 0;
1974
1975 mutex_lock(&fb_helper->lock);
1976 ret = __drm_fb_helper_initial_config_and_unlock(fb_helper, bpp_sel);
1977
1978 return ret;
1979 }
1980 EXPORT_SYMBOL(drm_fb_helper_initial_config);
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
2004 {
2005 int err = 0;
2006
2007 if (!drm_fbdev_emulation || !fb_helper)
2008 return 0;
2009
2010 mutex_lock(&fb_helper->lock);
2011 if (fb_helper->deferred_setup) {
2012 err = __drm_fb_helper_initial_config_and_unlock(fb_helper,
2013 fb_helper->preferred_bpp);
2014 return err;
2015 }
2016
2017 if (!fb_helper->fb || !drm_master_internal_acquire(fb_helper->dev)) {
2018 fb_helper->delayed_hotplug = true;
2019 mutex_unlock(&fb_helper->lock);
2020 return err;
2021 }
2022
2023 drm_master_internal_release(fb_helper->dev);
2024
2025 drm_dbg_kms(fb_helper->dev, "\n");
2026
2027 drm_client_modeset_probe(&fb_helper->client, fb_helper->fb->width, fb_helper->fb->height);
2028 drm_setup_crtcs_fb(fb_helper);
2029 mutex_unlock(&fb_helper->lock);
2030
2031 drm_fb_helper_set_par(fb_helper->fbdev);
2032
2033 return 0;
2034 }
2035 EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
2036
2037
2038
2039
2040
2041
2042
2043
2044 void drm_fb_helper_lastclose(struct drm_device *dev)
2045 {
2046 drm_fb_helper_restore_fbdev_mode_unlocked(dev->fb_helper);
2047 }
2048 EXPORT_SYMBOL(drm_fb_helper_lastclose);
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059 void drm_fb_helper_output_poll_changed(struct drm_device *dev)
2060 {
2061 drm_fb_helper_hotplug_event(dev->fb_helper);
2062 }
2063 EXPORT_SYMBOL(drm_fb_helper_output_poll_changed);
2064
2065
2066 static int drm_fbdev_fb_open(struct fb_info *info, int user)
2067 {
2068 struct drm_fb_helper *fb_helper = info->par;
2069
2070
2071 if (user && !try_module_get(fb_helper->dev->driver->fops->owner))
2072 return -ENODEV;
2073
2074 return 0;
2075 }
2076
2077 static int drm_fbdev_fb_release(struct fb_info *info, int user)
2078 {
2079 struct drm_fb_helper *fb_helper = info->par;
2080
2081 if (user)
2082 module_put(fb_helper->dev->driver->fops->owner);
2083
2084 return 0;
2085 }
2086
2087 static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper)
2088 {
2089 struct fb_info *fbi = fb_helper->fbdev;
2090 void *shadow = NULL;
2091
2092 if (!fb_helper->dev)
2093 return;
2094
2095 if (fbi) {
2096 if (fbi->fbdefio)
2097 fb_deferred_io_cleanup(fbi);
2098 if (drm_fbdev_use_shadow_fb(fb_helper))
2099 shadow = fbi->screen_buffer;
2100 }
2101
2102 drm_fb_helper_fini(fb_helper);
2103
2104 if (shadow)
2105 vfree(shadow);
2106 else if (fb_helper->buffer)
2107 drm_client_buffer_vunmap(fb_helper->buffer);
2108
2109 drm_client_framebuffer_delete(fb_helper->buffer);
2110 }
2111
2112 static void drm_fbdev_release(struct drm_fb_helper *fb_helper)
2113 {
2114 drm_fbdev_cleanup(fb_helper);
2115 drm_client_release(&fb_helper->client);
2116 kfree(fb_helper);
2117 }
2118
2119
2120
2121
2122
2123 static void drm_fbdev_fb_destroy(struct fb_info *info)
2124 {
2125 drm_fbdev_release(info->par);
2126 }
2127
2128 static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
2129 {
2130 struct drm_fb_helper *fb_helper = info->par;
2131
2132 if (drm_fbdev_use_shadow_fb(fb_helper))
2133 return fb_deferred_io_mmap(info, vma);
2134 else if (fb_helper->dev->driver->gem_prime_mmap)
2135 return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
2136 else
2137 return -ENODEV;
2138 }
2139
2140 static bool drm_fbdev_use_iomem(struct fb_info *info)
2141 {
2142 struct drm_fb_helper *fb_helper = info->par;
2143 struct drm_client_buffer *buffer = fb_helper->buffer;
2144
2145 return !drm_fbdev_use_shadow_fb(fb_helper) && buffer->map.is_iomem;
2146 }
2147
2148 static ssize_t fb_read_screen_base(struct fb_info *info, char __user *buf, size_t count,
2149 loff_t pos)
2150 {
2151 const char __iomem *src = info->screen_base + pos;
2152 size_t alloc_size = min_t(size_t, count, PAGE_SIZE);
2153 ssize_t ret = 0;
2154 int err = 0;
2155 char *tmp;
2156
2157 tmp = kmalloc(alloc_size, GFP_KERNEL);
2158 if (!tmp)
2159 return -ENOMEM;
2160
2161 while (count) {
2162 size_t c = min_t(size_t, count, alloc_size);
2163
2164 memcpy_fromio(tmp, src, c);
2165 if (copy_to_user(buf, tmp, c)) {
2166 err = -EFAULT;
2167 break;
2168 }
2169
2170 src += c;
2171 buf += c;
2172 ret += c;
2173 count -= c;
2174 }
2175
2176 kfree(tmp);
2177
2178 return ret ? ret : err;
2179 }
2180
2181 static ssize_t fb_read_screen_buffer(struct fb_info *info, char __user *buf, size_t count,
2182 loff_t pos)
2183 {
2184 const char *src = info->screen_buffer + pos;
2185
2186 if (copy_to_user(buf, src, count))
2187 return -EFAULT;
2188
2189 return count;
2190 }
2191
2192 static ssize_t drm_fbdev_fb_read(struct fb_info *info, char __user *buf,
2193 size_t count, loff_t *ppos)
2194 {
2195 loff_t pos = *ppos;
2196 size_t total_size;
2197 ssize_t ret;
2198
2199 if (info->screen_size)
2200 total_size = info->screen_size;
2201 else
2202 total_size = info->fix.smem_len;
2203
2204 if (pos >= total_size)
2205 return 0;
2206 if (count >= total_size)
2207 count = total_size;
2208 if (total_size - count < pos)
2209 count = total_size - pos;
2210
2211 if (drm_fbdev_use_iomem(info))
2212 ret = fb_read_screen_base(info, buf, count, pos);
2213 else
2214 ret = fb_read_screen_buffer(info, buf, count, pos);
2215
2216 if (ret > 0)
2217 *ppos += ret;
2218
2219 return ret;
2220 }
2221
2222 static ssize_t fb_write_screen_base(struct fb_info *info, const char __user *buf, size_t count,
2223 loff_t pos)
2224 {
2225 char __iomem *dst = info->screen_base + pos;
2226 size_t alloc_size = min_t(size_t, count, PAGE_SIZE);
2227 ssize_t ret = 0;
2228 int err = 0;
2229 u8 *tmp;
2230
2231 tmp = kmalloc(alloc_size, GFP_KERNEL);
2232 if (!tmp)
2233 return -ENOMEM;
2234
2235 while (count) {
2236 size_t c = min_t(size_t, count, alloc_size);
2237
2238 if (copy_from_user(tmp, buf, c)) {
2239 err = -EFAULT;
2240 break;
2241 }
2242 memcpy_toio(dst, tmp, c);
2243
2244 dst += c;
2245 buf += c;
2246 ret += c;
2247 count -= c;
2248 }
2249
2250 kfree(tmp);
2251
2252 return ret ? ret : err;
2253 }
2254
2255 static ssize_t fb_write_screen_buffer(struct fb_info *info, const char __user *buf, size_t count,
2256 loff_t pos)
2257 {
2258 char *dst = info->screen_buffer + pos;
2259
2260 if (copy_from_user(dst, buf, count))
2261 return -EFAULT;
2262
2263 return count;
2264 }
2265
2266 static ssize_t drm_fbdev_fb_write(struct fb_info *info, const char __user *buf,
2267 size_t count, loff_t *ppos)
2268 {
2269 loff_t pos = *ppos;
2270 size_t total_size;
2271 ssize_t ret;
2272 struct drm_rect damage_area;
2273 int err = 0;
2274
2275 if (info->screen_size)
2276 total_size = info->screen_size;
2277 else
2278 total_size = info->fix.smem_len;
2279
2280 if (pos > total_size)
2281 return -EFBIG;
2282 if (count > total_size) {
2283 err = -EFBIG;
2284 count = total_size;
2285 }
2286 if (total_size - count < pos) {
2287 if (!err)
2288 err = -ENOSPC;
2289 count = total_size - pos;
2290 }
2291
2292
2293
2294
2295
2296 if (drm_fbdev_use_iomem(info))
2297 ret = fb_write_screen_base(info, buf, count, pos);
2298 else
2299 ret = fb_write_screen_buffer(info, buf, count, pos);
2300
2301 if (ret < 0)
2302 return ret;
2303 else if (!ret)
2304 return err;
2305
2306 *ppos += ret;
2307
2308 drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area);
2309 drm_fb_helper_damage(info, damage_area.x1, damage_area.y1,
2310 drm_rect_width(&damage_area),
2311 drm_rect_height(&damage_area));
2312
2313 return ret;
2314 }
2315
2316 static void drm_fbdev_fb_fillrect(struct fb_info *info,
2317 const struct fb_fillrect *rect)
2318 {
2319 if (drm_fbdev_use_iomem(info))
2320 drm_fb_helper_cfb_fillrect(info, rect);
2321 else
2322 drm_fb_helper_sys_fillrect(info, rect);
2323 }
2324
2325 static void drm_fbdev_fb_copyarea(struct fb_info *info,
2326 const struct fb_copyarea *area)
2327 {
2328 if (drm_fbdev_use_iomem(info))
2329 drm_fb_helper_cfb_copyarea(info, area);
2330 else
2331 drm_fb_helper_sys_copyarea(info, area);
2332 }
2333
2334 static void drm_fbdev_fb_imageblit(struct fb_info *info,
2335 const struct fb_image *image)
2336 {
2337 if (drm_fbdev_use_iomem(info))
2338 drm_fb_helper_cfb_imageblit(info, image);
2339 else
2340 drm_fb_helper_sys_imageblit(info, image);
2341 }
2342
2343 static const struct fb_ops drm_fbdev_fb_ops = {
2344 .owner = THIS_MODULE,
2345 DRM_FB_HELPER_DEFAULT_OPS,
2346 .fb_open = drm_fbdev_fb_open,
2347 .fb_release = drm_fbdev_fb_release,
2348 .fb_destroy = drm_fbdev_fb_destroy,
2349 .fb_mmap = drm_fbdev_fb_mmap,
2350 .fb_read = drm_fbdev_fb_read,
2351 .fb_write = drm_fbdev_fb_write,
2352 .fb_fillrect = drm_fbdev_fb_fillrect,
2353 .fb_copyarea = drm_fbdev_fb_copyarea,
2354 .fb_imageblit = drm_fbdev_fb_imageblit,
2355 };
2356
2357 static struct fb_deferred_io drm_fbdev_defio = {
2358 .delay = HZ / 20,
2359 .deferred_io = drm_fb_helper_deferred_io,
2360 };
2361
2362
2363
2364
2365
2366
2367
2368 static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
2369 struct drm_fb_helper_surface_size *sizes)
2370 {
2371 struct drm_client_dev *client = &fb_helper->client;
2372 struct drm_device *dev = fb_helper->dev;
2373 struct drm_client_buffer *buffer;
2374 struct drm_framebuffer *fb;
2375 struct fb_info *fbi;
2376 u32 format;
2377 struct iosys_map map;
2378 int ret;
2379
2380 drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n",
2381 sizes->surface_width, sizes->surface_height,
2382 sizes->surface_bpp);
2383
2384 format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
2385 buffer = drm_client_framebuffer_create(client, sizes->surface_width,
2386 sizes->surface_height, format);
2387 if (IS_ERR(buffer))
2388 return PTR_ERR(buffer);
2389
2390 fb_helper->buffer = buffer;
2391 fb_helper->fb = buffer->fb;
2392 fb = buffer->fb;
2393
2394 fbi = drm_fb_helper_alloc_fbi(fb_helper);
2395 if (IS_ERR(fbi))
2396 return PTR_ERR(fbi);
2397
2398 fbi->fbops = &drm_fbdev_fb_ops;
2399 fbi->screen_size = sizes->surface_height * fb->pitches[0];
2400 fbi->fix.smem_len = fbi->screen_size;
2401 fbi->flags = FBINFO_DEFAULT;
2402
2403 drm_fb_helper_fill_info(fbi, fb_helper, sizes);
2404
2405 if (drm_fbdev_use_shadow_fb(fb_helper)) {
2406 fbi->screen_buffer = vzalloc(fbi->screen_size);
2407 if (!fbi->screen_buffer)
2408 return -ENOMEM;
2409 fbi->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST;
2410
2411 fbi->fbdefio = &drm_fbdev_defio;
2412 fb_deferred_io_init(fbi);
2413 } else {
2414
2415 ret = drm_client_buffer_vmap(fb_helper->buffer, &map);
2416 if (ret)
2417 return ret;
2418 if (map.is_iomem) {
2419 fbi->screen_base = map.vaddr_iomem;
2420 } else {
2421 fbi->screen_buffer = map.vaddr;
2422 fbi->flags |= FBINFO_VIRTFB;
2423 }
2424
2425
2426
2427
2428
2429
2430 #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
2431 if (drm_leak_fbdev_smem && fbi->fix.smem_start == 0 &&
2432 !drm_WARN_ON_ONCE(dev, map.is_iomem))
2433 fbi->fix.smem_start =
2434 page_to_phys(virt_to_page(fbi->screen_buffer));
2435 #endif
2436 }
2437
2438 return 0;
2439 }
2440
2441 static const struct drm_fb_helper_funcs drm_fb_helper_generic_funcs = {
2442 .fb_probe = drm_fb_helper_generic_probe,
2443 };
2444
2445 static void drm_fbdev_client_unregister(struct drm_client_dev *client)
2446 {
2447 struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
2448
2449 if (fb_helper->fbdev)
2450
2451 drm_fb_helper_unregister_fbi(fb_helper);
2452 else
2453 drm_fbdev_release(fb_helper);
2454 }
2455
2456 static int drm_fbdev_client_restore(struct drm_client_dev *client)
2457 {
2458 drm_fb_helper_lastclose(client->dev);
2459
2460 return 0;
2461 }
2462
2463 static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
2464 {
2465 struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
2466 struct drm_device *dev = client->dev;
2467 int ret;
2468
2469
2470 if (!fb_helper->dev && fb_helper->funcs)
2471 return 0;
2472
2473 if (dev->fb_helper)
2474 return drm_fb_helper_hotplug_event(dev->fb_helper);
2475
2476 if (!dev->mode_config.num_connector) {
2477 drm_dbg_kms(dev, "No connectors found, will not create framebuffer!\n");
2478 return 0;
2479 }
2480
2481 drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
2482
2483 ret = drm_fb_helper_init(dev, fb_helper);
2484 if (ret)
2485 goto err;
2486
2487 if (!drm_drv_uses_atomic_modeset(dev))
2488 drm_helper_disable_unused_functions(dev);
2489
2490 ret = drm_fb_helper_initial_config(fb_helper, fb_helper->preferred_bpp);
2491 if (ret)
2492 goto err_cleanup;
2493
2494 return 0;
2495
2496 err_cleanup:
2497 drm_fbdev_cleanup(fb_helper);
2498 err:
2499 fb_helper->dev = NULL;
2500 fb_helper->fbdev = NULL;
2501
2502 drm_err(dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret);
2503
2504 return ret;
2505 }
2506
2507 static const struct drm_client_funcs drm_fbdev_client_funcs = {
2508 .owner = THIS_MODULE,
2509 .unregister = drm_fbdev_client_unregister,
2510 .restore = drm_fbdev_client_restore,
2511 .hotplug = drm_fbdev_client_hotplug,
2512 };
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541 void drm_fbdev_generic_setup(struct drm_device *dev,
2542 unsigned int preferred_bpp)
2543 {
2544 struct drm_fb_helper *fb_helper;
2545 int ret;
2546
2547 drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
2548 drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
2549
2550 if (!drm_fbdev_emulation)
2551 return;
2552
2553 fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
2554 if (!fb_helper) {
2555 drm_err(dev, "Failed to allocate fb_helper\n");
2556 return;
2557 }
2558
2559 ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
2560 if (ret) {
2561 kfree(fb_helper);
2562 drm_err(dev, "Failed to register client: %d\n", ret);
2563 return;
2564 }
2565
2566
2567
2568
2569
2570
2571 if (!preferred_bpp)
2572 preferred_bpp = dev->mode_config.preferred_depth;
2573 if (!preferred_bpp)
2574 preferred_bpp = 32;
2575 fb_helper->preferred_bpp = preferred_bpp;
2576
2577 ret = drm_fbdev_client_hotplug(&fb_helper->client);
2578 if (ret)
2579 drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
2580
2581 drm_client_register(&fb_helper->client);
2582 }
2583 EXPORT_SYMBOL(drm_fbdev_generic_setup);