11c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae/* exynos_drm_fbdev.c 21c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * 31c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Copyright (c) 2011 Samsung Electronics Co., Ltd. 41c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Authors: 51c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Inki Dae <inki.dae@samsung.com> 61c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Joonyoung Shim <jy0922.shim@samsung.com> 71c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Seung-Woo Kim <sw0312.kim@samsung.com> 81c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * 91c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Permission is hereby granted, free of charge, to any person obtaining a 101c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * copy of this software and associated documentation files (the "Software"), 111c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * to deal in the Software without restriction, including without limitation 121c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * the rights to use, copy, modify, merge, publish, distribute, sublicense, 131c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * and/or sell copies of the Software, and to permit persons to whom the 141c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Software is furnished to do so, subject to the following conditions: 151c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * 161c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * The above copyright notice and this permission notice (including the next 171c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * paragraph) shall be included in all copies or substantial portions of the 181c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Software. 191c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * 201c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 211c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 221c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 231c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 241c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 251c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 261c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * OTHER DEALINGS IN THE SOFTWARE. 271c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae */ 281c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 291c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#include "drmP.h" 301c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#include "drm_crtc.h" 311c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#include "drm_fb_helper.h" 321c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#include "drm_crtc_helper.h" 331c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 341c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#include "exynos_drm_drv.h" 351c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#include "exynos_drm_fb.h" 362c871127e994a678b82104a4110eb7fcc87f05adInki Dae#include "exynos_drm_gem.h" 371c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 381c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#define MAX_CONNECTOR 4 391c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#define PREFERRED_BPP 32 401c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 411c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#define to_exynos_fbdev(x) container_of(x, struct exynos_drm_fbdev,\ 421c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_fb_helper) 431c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 441c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestruct exynos_drm_fbdev { 45e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim struct drm_fb_helper drm_fb_helper; 46e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 471c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae}; 481c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 491c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic struct fb_ops exynos_drm_fb_ops = { 501c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .owner = THIS_MODULE, 511c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .fb_fillrect = cfb_fillrect, 521c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .fb_copyarea = cfb_copyarea, 531c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .fb_imageblit = cfb_imageblit, 541c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .fb_check_var = drm_fb_helper_check_var, 5583b316fdafcc37e3e65b4a650afb7aab5cc2d271Sascha Hauer .fb_set_par = drm_fb_helper_set_par, 561c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .fb_blank = drm_fb_helper_blank, 571c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .fb_pan_display = drm_fb_helper_pan_display, 581c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .fb_setcmap = drm_fb_helper_setcmap, 591c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae}; 601c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 6119c8b8343d9cb9674fa47103bf2a4abb43757e65Inki Daestatic int exynos_drm_fbdev_update(struct drm_fb_helper *helper, 62aa6b2b6cd43e4a23c2a220382a8b385b087d8bcaSeung-Woo Kim struct drm_framebuffer *fb) 631c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 641c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct fb_info *fbi = helper->fbdev; 651c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_device *dev = helper->dev; 662c871127e994a678b82104a4110eb7fcc87f05adInki Dae struct exynos_drm_gem_buf *buffer; 67aa6b2b6cd43e4a23c2a220382a8b385b087d8bcaSeung-Woo Kim unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3); 6819c8b8343d9cb9674fa47103bf2a4abb43757e65Inki Dae unsigned long offset; 691c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 701c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 711c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 7201f2c7730e188077026c5f766f85f329c7000c54Ville Syrjälä drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); 73aa6b2b6cd43e4a23c2a220382a8b385b087d8bcaSeung-Woo Kim drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height); 741c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 75229d3534f5bd73fe6247a9e2a92ab0ef69fbc980Seung-Woo Kim /* RGB formats use only one buffer */ 76229d3534f5bd73fe6247a9e2a92ab0ef69fbc980Seung-Woo Kim buffer = exynos_drm_fb_buffer(fb, 0); 772c871127e994a678b82104a4110eb7fcc87f05adInki Dae if (!buffer) { 782c871127e994a678b82104a4110eb7fcc87f05adInki Dae DRM_LOG_KMS("buffer is null.\n"); 7919c8b8343d9cb9674fa47103bf2a4abb43757e65Inki Dae return -EFAULT; 8019c8b8343d9cb9674fa47103bf2a4abb43757e65Inki Dae } 811c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 8219c8b8343d9cb9674fa47103bf2a4abb43757e65Inki Dae offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); 8301f2c7730e188077026c5f766f85f329c7000c54Ville Syrjälä offset += fbi->var.yoffset * fb->pitches[0]; 841c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 852c871127e994a678b82104a4110eb7fcc87f05adInki Dae dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr; 862c871127e994a678b82104a4110eb7fcc87f05adInki Dae fbi->screen_base = buffer->kvaddr + offset; 872c871127e994a678b82104a4110eb7fcc87f05adInki Dae fbi->fix.smem_start = (unsigned long)(buffer->dma_addr + offset); 881c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae fbi->screen_size = size; 891c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae fbi->fix.smem_len = size; 9019c8b8343d9cb9674fa47103bf2a4abb43757e65Inki Dae 9119c8b8343d9cb9674fa47103bf2a4abb43757e65Inki Dae return 0; 921c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 931c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 941c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic int exynos_drm_fbdev_create(struct drm_fb_helper *helper, 951c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_fb_helper_surface_size *sizes) 961c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 971c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper); 98e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 991c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_device *dev = helper->dev; 1001c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct fb_info *fbi; 101a794d57da8031a45fed4e4cb71a999694ba02f7eJoonyoung Shim struct drm_mode_fb_cmd2 mode_cmd = { 0 }; 1021c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct platform_device *pdev = dev->platformdev; 103e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim unsigned long size; 1041c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae int ret; 1051c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1061c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 1071c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1081c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d\n", 1091c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae sizes->surface_width, sizes->surface_height, 1101c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae sizes->surface_bpp); 1111c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1121c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mode_cmd.width = sizes->surface_width; 1131c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mode_cmd.height = sizes->surface_height; 114a794d57da8031a45fed4e4cb71a999694ba02f7eJoonyoung Shim mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3); 115a794d57da8031a45fed4e4cb71a999694ba02f7eJoonyoung Shim mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, 116a794d57da8031a45fed4e4cb71a999694ba02f7eJoonyoung Shim sizes->surface_depth); 1171c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1181c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mutex_lock(&dev->struct_mutex); 1191c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1201c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae fbi = framebuffer_alloc(0, &pdev->dev); 1211c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (!fbi) { 1221c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_ERROR("failed to allocate fb info.\n"); 1231c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae ret = -ENOMEM; 1241c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae goto out; 1251c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 1261c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 127e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim size = mode_cmd.pitches[0] * mode_cmd.height; 1282b35892e9da672df40ce890bffc4f9f6119c57e0Inki Dae 1292b35892e9da672df40ce890bffc4f9f6119c57e0Inki Dae /* 0 means to allocate physically continuous memory */ 1302b35892e9da672df40ce890bffc4f9f6119c57e0Inki Dae exynos_gem_obj = exynos_drm_gem_create(dev, 0, size); 131e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim if (IS_ERR(exynos_gem_obj)) { 132e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim ret = PTR_ERR(exynos_gem_obj); 133e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim goto out; 134e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim } 135e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim 136e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim exynos_fbdev->exynos_gem_obj = exynos_gem_obj; 137e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim 138e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, 139e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim &exynos_gem_obj->base); 140e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim if (IS_ERR_OR_NULL(helper->fb)) { 1411c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_ERROR("failed to create drm framebuffer.\n"); 142e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim ret = PTR_ERR(helper->fb); 1431c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae goto out; 1441c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 1451c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1461c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae helper->fbdev = fbi; 1471c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1481c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae fbi->par = helper; 1491c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae fbi->flags = FBINFO_FLAG_DEFAULT; 1501c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae fbi->fbops = &exynos_drm_fb_ops; 1511c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1521c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae ret = fb_alloc_cmap(&fbi->cmap, 256, 0); 1531c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (ret) { 1541c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_ERROR("failed to allocate cmap.\n"); 1551c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae goto out; 1561c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 1571c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 158aa6b2b6cd43e4a23c2a220382a8b385b087d8bcaSeung-Woo Kim ret = exynos_drm_fbdev_update(helper, helper->fb); 159e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim if (ret < 0) { 16019c8b8343d9cb9674fa47103bf2a4abb43757e65Inki Dae fb_dealloc_cmap(&fbi->cmap); 161e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim goto out; 162e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim } 1631c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1641c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae/* 1651c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * if failed, all resources allocated above would be released by 1661c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * drm_mode_config_cleanup() when drm_load() had been called prior 1671c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * to any specific driver such as fimd or hdmi driver. 1681c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae */ 1691c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daeout: 1701c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mutex_unlock(&dev->struct_mutex); 1711c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return ret; 1721c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 1731c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1741c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic int exynos_drm_fbdev_probe(struct drm_fb_helper *helper, 1751c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_fb_helper_surface_size *sizes) 1761c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 1771c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae int ret = 0; 1781c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1791c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 1801c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 181bc41eae2c84694667c1d7747fa28db8e75948ac4Inki Dae /* 182bc41eae2c84694667c1d7747fa28db8e75948ac4Inki Dae * with !helper->fb, it means that this funcion is called first time 183bc41eae2c84694667c1d7747fa28db8e75948ac4Inki Dae * and after that, the helper->fb would be used as clone mode. 184bc41eae2c84694667c1d7747fa28db8e75948ac4Inki Dae */ 1851c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (!helper->fb) { 1861c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae ret = exynos_drm_fbdev_create(helper, sizes); 1871c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (ret < 0) { 1881c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_ERROR("failed to create fbdev.\n"); 1891c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return ret; 1901c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 1911c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1921c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae /* 1931c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * fb_helper expects a value more than 1 if succeed 1941c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * because register_framebuffer() should be called. 1951c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae */ 1961c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae ret = 1; 1971c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 1981c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1991c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return ret; 2001c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 2011c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2021c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = { 2031c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .fb_probe = exynos_drm_fbdev_probe, 2041c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae}; 2051c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2061c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daeint exynos_drm_fbdev_init(struct drm_device *dev) 2071c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 2081c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct exynos_drm_fbdev *fbdev; 2091c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct exynos_drm_private *private = dev->dev_private; 2101c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_fb_helper *helper; 2111c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae unsigned int num_crtc; 2121c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae int ret; 2131c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2141c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2151c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2161c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector) 2171c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return 0; 2181c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2191c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); 2201c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (!fbdev) { 2211c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_ERROR("failed to allocate drm fbdev.\n"); 2221c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return -ENOMEM; 2231c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 2241c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2251c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae private->fb_helper = helper = &fbdev->drm_fb_helper; 2261c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae helper->funcs = &exynos_drm_fb_helper_funcs; 2271c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2281c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae num_crtc = dev->mode_config.num_crtc; 2291c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2301c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae ret = drm_fb_helper_init(dev, helper, num_crtc, MAX_CONNECTOR); 2311c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (ret < 0) { 2321c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_ERROR("failed to initialize drm fb helper.\n"); 2331c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae goto err_init; 2341c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 2351c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2361c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae ret = drm_fb_helper_single_add_all_connectors(helper); 2371c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (ret < 0) { 2381c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_ERROR("failed to register drm_fb_helper_connector.\n"); 2391c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae goto err_setup; 2401c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2411c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 2421c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2431c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); 2441c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (ret < 0) { 2451c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_ERROR("failed to set up hw configuration.\n"); 2461c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae goto err_setup; 2471c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 2481c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2491c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return 0; 2501c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2511c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daeerr_setup: 2521c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_fb_helper_fini(helper); 2531c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2541c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daeerr_init: 2551c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae private->fb_helper = NULL; 2561c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae kfree(fbdev); 2571c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2581c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return ret; 2591c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 2601c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2611c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic void exynos_drm_fbdev_destroy(struct drm_device *dev, 2621c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_fb_helper *fb_helper) 2631c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 2641c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_framebuffer *fb; 2651c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2661c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae /* release drm framebuffer and real buffer */ 2671c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (fb_helper->fb && fb_helper->fb->funcs) { 2681c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae fb = fb_helper->fb; 2691c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (fb && fb->funcs->destroy) 2701c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae fb->funcs->destroy(fb); 2711c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 2721c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2731c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae /* release linux framebuffer */ 2741c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (fb_helper->fbdev) { 2751c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct fb_info *info; 2761c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae int ret; 2771c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2781c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae info = fb_helper->fbdev; 2791c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae ret = unregister_framebuffer(info); 2801c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (ret < 0) 2811c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("failed unregister_framebuffer()\n"); 2821c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2831c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (info->cmap.len) 2841c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae fb_dealloc_cmap(&info->cmap); 2851c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2861c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae framebuffer_release(info); 2871c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 2881c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2891c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_fb_helper_fini(fb_helper); 2901c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 2911c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2921c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daevoid exynos_drm_fbdev_fini(struct drm_device *dev) 2931c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 2941c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct exynos_drm_private *private = dev->dev_private; 2951c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct exynos_drm_fbdev *fbdev; 2961c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2971c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (!private || !private->fb_helper) 2981c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return; 2991c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 3001c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae fbdev = to_exynos_fbdev(private->fb_helper); 3011c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 302e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim if (fbdev->exynos_gem_obj) 303e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim exynos_drm_gem_destroy(fbdev->exynos_gem_obj); 304e1533c086fc882474fb339953082072bec8c4e71Joonyoung Shim 3051c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae exynos_drm_fbdev_destroy(dev, private->fb_helper); 3061c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae kfree(fbdev); 3071c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae private->fb_helper = NULL; 3081c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 3091c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 3101c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daevoid exynos_drm_fbdev_restore_mode(struct drm_device *dev) 3111c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 3121c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct exynos_drm_private *private = dev->dev_private; 3131c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 3141c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (!private || !private->fb_helper) 3151c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return; 3161c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 3171c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_fb_helper_restore_fbdev_mode(private->fb_helper); 3181c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 319