11c248b7dSInki Dae /* exynos_drm_fbdev.c 21c248b7dSInki Dae * 31c248b7dSInki Dae * Copyright (c) 2011 Samsung Electronics Co., Ltd. 41c248b7dSInki Dae * Authors: 51c248b7dSInki Dae * Inki Dae <inki.dae@samsung.com> 61c248b7dSInki Dae * Joonyoung Shim <jy0922.shim@samsung.com> 71c248b7dSInki Dae * Seung-Woo Kim <sw0312.kim@samsung.com> 81c248b7dSInki Dae * 9d81aecb5SInki Dae * This program is free software; you can redistribute it and/or modify it 10d81aecb5SInki Dae * under the terms of the GNU General Public License as published by the 11d81aecb5SInki Dae * Free Software Foundation; either version 2 of the License, or (at your 12d81aecb5SInki Dae * option) any later version. 131c248b7dSInki Dae */ 141c248b7dSInki Dae 15760285e7SDavid Howells #include <drm/drmP.h> 16760285e7SDavid Howells #include <drm/drm_crtc.h> 17760285e7SDavid Howells #include <drm/drm_fb_helper.h> 18760285e7SDavid Howells #include <drm/drm_crtc_helper.h> 19a1bfacf4SVikas Sajjan #include <drm/exynos_drm.h> 201c248b7dSInki Dae 211c248b7dSInki Dae #include "exynos_drm_drv.h" 221c248b7dSInki Dae #include "exynos_drm_fb.h" 23e30655d0SMark Brown #include "exynos_drm_fbdev.h" 242c871127SInki Dae #include "exynos_drm_gem.h" 25c704f1b4SInki Dae #include "exynos_drm_iommu.h" 261c248b7dSInki Dae 271c248b7dSInki Dae #define MAX_CONNECTOR 4 281c248b7dSInki Dae #define PREFERRED_BPP 32 291c248b7dSInki Dae 301c248b7dSInki Dae #define to_exynos_fbdev(x) container_of(x, struct exynos_drm_fbdev,\ 311c248b7dSInki Dae drm_fb_helper) 321c248b7dSInki Dae 331c248b7dSInki Dae struct exynos_drm_fbdev { 341c248b7dSInki Dae struct drm_fb_helper drm_fb_helper; 35e1533c08SJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 361c248b7dSInki Dae }; 371c248b7dSInki Dae 38dd265850SPrathyush K static int exynos_drm_fb_mmap(struct fb_info *info, 39dd265850SPrathyush K struct vm_area_struct *vma) 40dd265850SPrathyush K { 41dd265850SPrathyush K struct drm_fb_helper *helper = info->par; 42dd265850SPrathyush K struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper); 43dd265850SPrathyush K struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj; 44dd265850SPrathyush K struct exynos_drm_gem_buf *buffer = exynos_gem_obj->buffer; 45dd265850SPrathyush K unsigned long vm_size; 46dd265850SPrathyush K int ret; 47dd265850SPrathyush K 48dd265850SPrathyush K vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; 49dd265850SPrathyush K 50dd265850SPrathyush K vm_size = vma->vm_end - vma->vm_start; 51dd265850SPrathyush K 52dd265850SPrathyush K if (vm_size > buffer->size) 53dd265850SPrathyush K return -EINVAL; 54dd265850SPrathyush K 554744ad24SInki Dae ret = dma_mmap_attrs(helper->dev->dev, vma, buffer->pages, 56dd265850SPrathyush K buffer->dma_addr, buffer->size, &buffer->dma_attrs); 57dd265850SPrathyush K if (ret < 0) { 58dd265850SPrathyush K DRM_ERROR("failed to mmap.\n"); 59dd265850SPrathyush K return ret; 60dd265850SPrathyush K } 61dd265850SPrathyush K 62dd265850SPrathyush K return 0; 63dd265850SPrathyush K } 64dd265850SPrathyush K 651c248b7dSInki Dae static struct fb_ops exynos_drm_fb_ops = { 661c248b7dSInki Dae .owner = THIS_MODULE, 67dd265850SPrathyush K .fb_mmap = exynos_drm_fb_mmap, 681c248b7dSInki Dae .fb_fillrect = cfb_fillrect, 691c248b7dSInki Dae .fb_copyarea = cfb_copyarea, 701c248b7dSInki Dae .fb_imageblit = cfb_imageblit, 711c248b7dSInki Dae .fb_check_var = drm_fb_helper_check_var, 7283b316fdSSascha Hauer .fb_set_par = drm_fb_helper_set_par, 731c248b7dSInki Dae .fb_blank = drm_fb_helper_blank, 741c248b7dSInki Dae .fb_pan_display = drm_fb_helper_pan_display, 751c248b7dSInki Dae .fb_setcmap = drm_fb_helper_setcmap, 761c248b7dSInki Dae }; 771c248b7dSInki Dae 7819c8b834SInki Dae static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, 79aa6b2b6cSSeung-Woo Kim struct drm_framebuffer *fb) 801c248b7dSInki Dae { 811c248b7dSInki Dae struct fb_info *fbi = helper->fbdev; 821c248b7dSInki Dae struct drm_device *dev = helper->dev; 832c871127SInki Dae struct exynos_drm_gem_buf *buffer; 84aa6b2b6cSSeung-Woo Kim unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3); 8519c8b834SInki Dae unsigned long offset; 861c248b7dSInki Dae 8701f2c773SVille Syrjälä drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); 88aa6b2b6cSSeung-Woo Kim drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height); 891c248b7dSInki Dae 90229d3534SSeung-Woo Kim /* RGB formats use only one buffer */ 91229d3534SSeung-Woo Kim buffer = exynos_drm_fb_buffer(fb, 0); 922c871127SInki Dae if (!buffer) { 93133dcdebSLespiau, Damien DRM_DEBUG_KMS("buffer is null.\n"); 9419c8b834SInki Dae return -EFAULT; 9519c8b834SInki Dae } 961c248b7dSInki Dae 974744ad24SInki Dae /* map pages with kernel virtual space. */ 984744ad24SInki Dae if (!buffer->kvaddr) { 99c704f1b4SInki Dae if (is_drm_iommu_supported(dev)) { 1004744ad24SInki Dae unsigned int nr_pages = buffer->size >> PAGE_SHIFT; 101c704f1b4SInki Dae 102fafb3837SSachin Kamat buffer->kvaddr = (void __iomem *) vmap(buffer->pages, 103fafb3837SSachin Kamat nr_pages, VM_MAP, 1044744ad24SInki Dae pgprot_writecombine(PAGE_KERNEL)); 105c704f1b4SInki Dae } else { 106c704f1b4SInki Dae phys_addr_t dma_addr = buffer->dma_addr; 107c704f1b4SInki Dae if (dma_addr) 108fafb3837SSachin Kamat buffer->kvaddr = (void __iomem *)phys_to_virt(dma_addr); 109c704f1b4SInki Dae else 110c704f1b4SInki Dae buffer->kvaddr = (void __iomem *)NULL; 111c704f1b4SInki Dae } 1124744ad24SInki Dae if (!buffer->kvaddr) { 1134744ad24SInki Dae DRM_ERROR("failed to map pages to kernel space.\n"); 1144744ad24SInki Dae return -EIO; 1154744ad24SInki Dae } 1164744ad24SInki Dae } 1174744ad24SInki Dae 11801ed8126SInki Dae /* buffer count to framebuffer always is 1 at booting time. */ 11901ed8126SInki Dae exynos_drm_fb_set_buf_cnt(fb, 1); 12001ed8126SInki Dae 12119c8b834SInki Dae offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); 12201f2c773SVille Syrjälä offset += fbi->var.yoffset * fb->pitches[0]; 1231c248b7dSInki Dae 1242c871127SInki Dae dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr; 1252c871127SInki Dae fbi->screen_base = buffer->kvaddr + offset; 126c704f1b4SInki Dae if (is_drm_iommu_supported(dev)) 127640631d0SPrathyush K fbi->fix.smem_start = (unsigned long) 128640631d0SPrathyush K (page_to_phys(sg_page(buffer->sgt->sgl)) + offset); 129c704f1b4SInki Dae else 130c704f1b4SInki Dae fbi->fix.smem_start = (unsigned long)buffer->dma_addr; 131c704f1b4SInki Dae 1321c248b7dSInki Dae fbi->screen_size = size; 1331c248b7dSInki Dae fbi->fix.smem_len = size; 13419c8b834SInki Dae 13519c8b834SInki Dae return 0; 1361c248b7dSInki Dae } 1371c248b7dSInki Dae 1381c248b7dSInki Dae static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, 1391c248b7dSInki Dae struct drm_fb_helper_surface_size *sizes) 1401c248b7dSInki Dae { 1411c248b7dSInki Dae struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper); 142e1533c08SJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 1431c248b7dSInki Dae struct drm_device *dev = helper->dev; 1441c248b7dSInki Dae struct fb_info *fbi; 145a794d57dSJoonyoung Shim struct drm_mode_fb_cmd2 mode_cmd = { 0 }; 1461c248b7dSInki Dae struct platform_device *pdev = dev->platformdev; 147e1533c08SJoonyoung Shim unsigned long size; 1481c248b7dSInki Dae int ret; 1491c248b7dSInki Dae 1501c248b7dSInki Dae DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d\n", 1511c248b7dSInki Dae sizes->surface_width, sizes->surface_height, 1521c248b7dSInki Dae sizes->surface_bpp); 1531c248b7dSInki Dae 1541c248b7dSInki Dae mode_cmd.width = sizes->surface_width; 1551c248b7dSInki Dae mode_cmd.height = sizes->surface_height; 156a794d57dSJoonyoung Shim mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3); 157a794d57dSJoonyoung Shim mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, 158a794d57dSJoonyoung Shim sizes->surface_depth); 1591c248b7dSInki Dae 1601c248b7dSInki Dae mutex_lock(&dev->struct_mutex); 1611c248b7dSInki Dae 1621c248b7dSInki Dae fbi = framebuffer_alloc(0, &pdev->dev); 1631c248b7dSInki Dae if (!fbi) { 1641c248b7dSInki Dae DRM_ERROR("failed to allocate fb info.\n"); 1651c248b7dSInki Dae ret = -ENOMEM; 1661c248b7dSInki Dae goto out; 1671c248b7dSInki Dae } 1681c248b7dSInki Dae 169e1533c08SJoonyoung Shim size = mode_cmd.pitches[0] * mode_cmd.height; 1702b35892eSInki Dae 171a1bfacf4SVikas Sajjan exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size); 172a1bfacf4SVikas Sajjan /* 173a1bfacf4SVikas Sajjan * If physically contiguous memory allocation fails and if IOMMU is 174a1bfacf4SVikas Sajjan * supported then try to get buffer from non physically contiguous 175a1bfacf4SVikas Sajjan * memory area. 176a1bfacf4SVikas Sajjan */ 177a1bfacf4SVikas Sajjan if (IS_ERR(exynos_gem_obj) && is_drm_iommu_supported(dev)) { 178a1bfacf4SVikas Sajjan dev_warn(&pdev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n"); 179a1bfacf4SVikas Sajjan exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG, 180a1bfacf4SVikas Sajjan size); 181a1bfacf4SVikas Sajjan } 182a1bfacf4SVikas Sajjan 183e1533c08SJoonyoung Shim if (IS_ERR(exynos_gem_obj)) { 184e1533c08SJoonyoung Shim ret = PTR_ERR(exynos_gem_obj); 185662aa6d7SInki Dae goto err_release_framebuffer; 1861c248b7dSInki Dae } 1871c248b7dSInki Dae 188e1533c08SJoonyoung Shim exynos_fbdev->exynos_gem_obj = exynos_gem_obj; 189e1533c08SJoonyoung Shim 190e1533c08SJoonyoung Shim helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, 191e1533c08SJoonyoung Shim &exynos_gem_obj->base); 19241eab402SSachin Kamat if (IS_ERR(helper->fb)) { 193e1533c08SJoonyoung Shim DRM_ERROR("failed to create drm framebuffer.\n"); 194e1533c08SJoonyoung Shim ret = PTR_ERR(helper->fb); 195662aa6d7SInki Dae goto err_destroy_gem; 196e1533c08SJoonyoung Shim } 197e1533c08SJoonyoung Shim 1981c248b7dSInki Dae helper->fbdev = fbi; 1991c248b7dSInki Dae 2001c248b7dSInki Dae fbi->par = helper; 2011c248b7dSInki Dae fbi->flags = FBINFO_FLAG_DEFAULT; 2021c248b7dSInki Dae fbi->fbops = &exynos_drm_fb_ops; 2031c248b7dSInki Dae 2041c248b7dSInki Dae ret = fb_alloc_cmap(&fbi->cmap, 256, 0); 2051c248b7dSInki Dae if (ret) { 2061c248b7dSInki Dae DRM_ERROR("failed to allocate cmap.\n"); 207662aa6d7SInki Dae goto err_destroy_framebuffer; 2081c248b7dSInki Dae } 2091c248b7dSInki Dae 210aa6b2b6cSSeung-Woo Kim ret = exynos_drm_fbdev_update(helper, helper->fb); 211662aa6d7SInki Dae if (ret < 0) 212662aa6d7SInki Dae goto err_dealloc_cmap; 213662aa6d7SInki Dae 214662aa6d7SInki Dae mutex_unlock(&dev->struct_mutex); 215662aa6d7SInki Dae return ret; 216662aa6d7SInki Dae 217662aa6d7SInki Dae err_dealloc_cmap: 21819c8b834SInki Dae fb_dealloc_cmap(&fbi->cmap); 219662aa6d7SInki Dae err_destroy_framebuffer: 220662aa6d7SInki Dae drm_framebuffer_cleanup(helper->fb); 221662aa6d7SInki Dae err_destroy_gem: 222662aa6d7SInki Dae exynos_drm_gem_destroy(exynos_gem_obj); 223662aa6d7SInki Dae err_release_framebuffer: 224662aa6d7SInki Dae framebuffer_release(fbi); 2251c248b7dSInki Dae 2261c248b7dSInki Dae /* 2271c248b7dSInki Dae * if failed, all resources allocated above would be released by 2281c248b7dSInki Dae * drm_mode_config_cleanup() when drm_load() had been called prior 2291c248b7dSInki Dae * to any specific driver such as fimd or hdmi driver. 2301c248b7dSInki Dae */ 2311c248b7dSInki Dae out: 2321c248b7dSInki Dae mutex_unlock(&dev->struct_mutex); 2331c248b7dSInki Dae return ret; 2341c248b7dSInki Dae } 2351c248b7dSInki Dae 2361c248b7dSInki Dae static struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = { 237cd5428a5SDaniel Vetter .fb_probe = exynos_drm_fbdev_create, 2381c248b7dSInki Dae }; 2391c248b7dSInki Dae 240*3eb578e2SAndrzej Hajda bool exynos_drm_fbdev_is_anything_connected(struct drm_device *dev) 241*3eb578e2SAndrzej Hajda { 242*3eb578e2SAndrzej Hajda struct drm_connector *connector; 243*3eb578e2SAndrzej Hajda bool ret = false; 244*3eb578e2SAndrzej Hajda 245*3eb578e2SAndrzej Hajda mutex_lock(&dev->mode_config.mutex); 246*3eb578e2SAndrzej Hajda list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 247*3eb578e2SAndrzej Hajda if (connector->status != connector_status_connected) 248*3eb578e2SAndrzej Hajda continue; 249*3eb578e2SAndrzej Hajda 250*3eb578e2SAndrzej Hajda ret = true; 251*3eb578e2SAndrzej Hajda break; 252*3eb578e2SAndrzej Hajda } 253*3eb578e2SAndrzej Hajda mutex_unlock(&dev->mode_config.mutex); 254*3eb578e2SAndrzej Hajda 255*3eb578e2SAndrzej Hajda return ret; 256*3eb578e2SAndrzej Hajda } 257*3eb578e2SAndrzej Hajda 2581c248b7dSInki Dae int exynos_drm_fbdev_init(struct drm_device *dev) 2591c248b7dSInki Dae { 2601c248b7dSInki Dae struct exynos_drm_fbdev *fbdev; 2611c248b7dSInki Dae struct exynos_drm_private *private = dev->dev_private; 2621c248b7dSInki Dae struct drm_fb_helper *helper; 2631c248b7dSInki Dae unsigned int num_crtc; 2641c248b7dSInki Dae int ret; 2651c248b7dSInki Dae 2661c248b7dSInki Dae if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector) 2671c248b7dSInki Dae return 0; 2681c248b7dSInki Dae 269*3eb578e2SAndrzej Hajda if (!exynos_drm_fbdev_is_anything_connected(dev)) 270*3eb578e2SAndrzej Hajda return 0; 271*3eb578e2SAndrzej Hajda 2721c248b7dSInki Dae fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); 27338bb5253SSachin Kamat if (!fbdev) 2741c248b7dSInki Dae return -ENOMEM; 2751c248b7dSInki Dae 2761c248b7dSInki Dae private->fb_helper = helper = &fbdev->drm_fb_helper; 2771c248b7dSInki Dae helper->funcs = &exynos_drm_fb_helper_funcs; 2781c248b7dSInki Dae 2791c248b7dSInki Dae num_crtc = dev->mode_config.num_crtc; 2801c248b7dSInki Dae 2811c248b7dSInki Dae ret = drm_fb_helper_init(dev, helper, num_crtc, MAX_CONNECTOR); 2821c248b7dSInki Dae if (ret < 0) { 2831c248b7dSInki Dae DRM_ERROR("failed to initialize drm fb helper.\n"); 2841c248b7dSInki Dae goto err_init; 2851c248b7dSInki Dae } 2861c248b7dSInki Dae 2871c248b7dSInki Dae ret = drm_fb_helper_single_add_all_connectors(helper); 2881c248b7dSInki Dae if (ret < 0) { 2891c248b7dSInki Dae DRM_ERROR("failed to register drm_fb_helper_connector.\n"); 2901c248b7dSInki Dae goto err_setup; 2911c248b7dSInki Dae 2921c248b7dSInki Dae } 2931c248b7dSInki Dae 29476a39dbfSDaniel Vetter /* disable all the possible outputs/crtcs before entering KMS mode */ 29576a39dbfSDaniel Vetter drm_helper_disable_unused_functions(dev); 29676a39dbfSDaniel Vetter 2971c248b7dSInki Dae ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); 2981c248b7dSInki Dae if (ret < 0) { 2991c248b7dSInki Dae DRM_ERROR("failed to set up hw configuration.\n"); 3001c248b7dSInki Dae goto err_setup; 3011c248b7dSInki Dae } 3021c248b7dSInki Dae 3031c248b7dSInki Dae return 0; 3041c248b7dSInki Dae 3051c248b7dSInki Dae err_setup: 3061c248b7dSInki Dae drm_fb_helper_fini(helper); 3071c248b7dSInki Dae 3081c248b7dSInki Dae err_init: 3091c248b7dSInki Dae private->fb_helper = NULL; 3101c248b7dSInki Dae kfree(fbdev); 3111c248b7dSInki Dae 3121c248b7dSInki Dae return ret; 3131c248b7dSInki Dae } 3141c248b7dSInki Dae 3151c248b7dSInki Dae static void exynos_drm_fbdev_destroy(struct drm_device *dev, 3161c248b7dSInki Dae struct drm_fb_helper *fb_helper) 3171c248b7dSInki Dae { 3184744ad24SInki Dae struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(fb_helper); 3194744ad24SInki Dae struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj; 3201c248b7dSInki Dae struct drm_framebuffer *fb; 3211c248b7dSInki Dae 322c704f1b4SInki Dae if (is_drm_iommu_supported(dev) && exynos_gem_obj->buffer->kvaddr) 3234744ad24SInki Dae vunmap(exynos_gem_obj->buffer->kvaddr); 3244744ad24SInki Dae 3251c248b7dSInki Dae /* release drm framebuffer and real buffer */ 3261c248b7dSInki Dae if (fb_helper->fb && fb_helper->fb->funcs) { 3271c248b7dSInki Dae fb = fb_helper->fb; 32836206361SDaniel Vetter if (fb) { 32936206361SDaniel Vetter drm_framebuffer_unregister_private(fb); 330f7eff60eSRob Clark drm_framebuffer_remove(fb); 3311c248b7dSInki Dae } 33236206361SDaniel Vetter } 3331c248b7dSInki Dae 3341c248b7dSInki Dae /* release linux framebuffer */ 3351c248b7dSInki Dae if (fb_helper->fbdev) { 3361c248b7dSInki Dae struct fb_info *info; 3371c248b7dSInki Dae int ret; 3381c248b7dSInki Dae 3391c248b7dSInki Dae info = fb_helper->fbdev; 3401c248b7dSInki Dae ret = unregister_framebuffer(info); 3411c248b7dSInki Dae if (ret < 0) 3421c248b7dSInki Dae DRM_DEBUG_KMS("failed unregister_framebuffer()\n"); 3431c248b7dSInki Dae 3441c248b7dSInki Dae if (info->cmap.len) 3451c248b7dSInki Dae fb_dealloc_cmap(&info->cmap); 3461c248b7dSInki Dae 3471c248b7dSInki Dae framebuffer_release(info); 3481c248b7dSInki Dae } 3491c248b7dSInki Dae 3501c248b7dSInki Dae drm_fb_helper_fini(fb_helper); 3511c248b7dSInki Dae } 3521c248b7dSInki Dae 3531c248b7dSInki Dae void exynos_drm_fbdev_fini(struct drm_device *dev) 3541c248b7dSInki Dae { 3551c248b7dSInki Dae struct exynos_drm_private *private = dev->dev_private; 3561c248b7dSInki Dae struct exynos_drm_fbdev *fbdev; 3571c248b7dSInki Dae 3581c248b7dSInki Dae if (!private || !private->fb_helper) 3591c248b7dSInki Dae return; 3601c248b7dSInki Dae 3611c248b7dSInki Dae fbdev = to_exynos_fbdev(private->fb_helper); 3621c248b7dSInki Dae 363e1533c08SJoonyoung Shim if (fbdev->exynos_gem_obj) 364e1533c08SJoonyoung Shim exynos_drm_gem_destroy(fbdev->exynos_gem_obj); 365e1533c08SJoonyoung Shim 3661c248b7dSInki Dae exynos_drm_fbdev_destroy(dev, private->fb_helper); 3671c248b7dSInki Dae kfree(fbdev); 3681c248b7dSInki Dae private->fb_helper = NULL; 3691c248b7dSInki Dae } 3701c248b7dSInki Dae 3711c248b7dSInki Dae void exynos_drm_fbdev_restore_mode(struct drm_device *dev) 3721c248b7dSInki Dae { 3731c248b7dSInki Dae struct exynos_drm_private *private = dev->dev_private; 3741c248b7dSInki Dae 3751c248b7dSInki Dae if (!private || !private->fb_helper) 3761c248b7dSInki Dae return; 3771c248b7dSInki Dae 3786aed8ec3SDaniel Vetter drm_modeset_lock_all(dev); 3791c248b7dSInki Dae drm_fb_helper_restore_fbdev_mode(private->fb_helper); 3806aed8ec3SDaniel Vetter drm_modeset_unlock_all(dev); 3811c248b7dSInki Dae } 382