linux/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
<<
>>
Prefs
   1/* Hisilicon Hibmc SoC drm driver
   2 *
   3 * Based on the bochs drm driver.
   4 *
   5 * Copyright (c) 2016 Huawei Limited.
   6 *
   7 * Author:
   8 *      Rongrong Zou <zourongrong@huawei.com>
   9 *      Rongrong Zou <zourongrong@gmail.com>
  10 *      Jianhua Li <lijianhua@huawei.com>
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License as published by
  14 * the Free Software Foundation; either version 2 of the License, or
  15 * (at your option) any later version.
  16 *
  17 */
  18
  19#include <drm/drm_crtc.h>
  20#include <drm/drm_crtc_helper.h>
  21#include <drm/drm_fb_helper.h>
  22
  23#include "hibmc_drm_drv.h"
  24
  25static int hibmcfb_create_object(
  26                                struct hibmc_drm_private *priv,
  27                                const struct drm_mode_fb_cmd2 *mode_cmd,
  28                                struct drm_gem_object **gobj_p)
  29{
  30        struct drm_gem_object *gobj;
  31        struct drm_device *dev = priv->dev;
  32        u32 size;
  33        int ret = 0;
  34
  35        size = mode_cmd->pitches[0] * mode_cmd->height;
  36        ret = hibmc_gem_create(dev, size, true, &gobj);
  37        if (ret)
  38                return ret;
  39
  40        *gobj_p = gobj;
  41        return ret;
  42}
  43
  44static struct fb_ops hibmc_drm_fb_ops = {
  45        .owner = THIS_MODULE,
  46        .fb_check_var = drm_fb_helper_check_var,
  47        .fb_set_par = drm_fb_helper_set_par,
  48        .fb_fillrect = drm_fb_helper_sys_fillrect,
  49        .fb_copyarea = drm_fb_helper_sys_copyarea,
  50        .fb_imageblit = drm_fb_helper_sys_imageblit,
  51        .fb_pan_display = drm_fb_helper_pan_display,
  52        .fb_blank = drm_fb_helper_blank,
  53        .fb_setcmap = drm_fb_helper_setcmap,
  54};
  55
  56static int hibmc_drm_fb_create(struct drm_fb_helper *helper,
  57                               struct drm_fb_helper_surface_size *sizes)
  58{
  59        struct hibmc_fbdev *hi_fbdev =
  60                container_of(helper, struct hibmc_fbdev, helper);
  61        struct hibmc_drm_private *priv = helper->dev->dev_private;
  62        struct fb_info *info;
  63        struct drm_mode_fb_cmd2 mode_cmd;
  64        struct drm_gem_object *gobj = NULL;
  65        int ret = 0;
  66        int ret1;
  67        size_t size;
  68        unsigned int bytes_per_pixel;
  69        struct hibmc_bo *bo = NULL;
  70
  71        DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n",
  72                         sizes->surface_width, sizes->surface_height,
  73                         sizes->surface_bpp);
  74        sizes->surface_depth = 32;
  75
  76        bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
  77
  78        mode_cmd.width = sizes->surface_width;
  79        mode_cmd.height = sizes->surface_height;
  80        mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel;
  81        mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
  82                                                          sizes->surface_depth);
  83
  84        size = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height);
  85
  86        ret = hibmcfb_create_object(priv, &mode_cmd, &gobj);
  87        if (ret) {
  88                DRM_ERROR("failed to create fbcon backing object: %d\n", ret);
  89                return -ENOMEM;
  90        }
  91
  92        bo = gem_to_hibmc_bo(gobj);
  93
  94        ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
  95        if (ret) {
  96                DRM_ERROR("failed to reserve ttm_bo: %d\n", ret);
  97                goto out_unref_gem;
  98        }
  99
 100        ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
 101        if (ret) {
 102                DRM_ERROR("failed to pin fbcon: %d\n", ret);
 103                goto out_unreserve_ttm_bo;
 104        }
 105
 106        ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
 107        if (ret) {
 108                DRM_ERROR("failed to kmap fbcon: %d\n", ret);
 109                goto out_unpin_bo;
 110        }
 111        ttm_bo_unreserve(&bo->bo);
 112
 113        info = drm_fb_helper_alloc_fbi(helper);
 114        if (IS_ERR(info)) {
 115                ret = PTR_ERR(info);
 116                DRM_ERROR("failed to allocate fbi: %d\n", ret);
 117                goto out_release_fbi;
 118        }
 119
 120        info->par = hi_fbdev;
 121
 122        hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj);
 123        if (IS_ERR(hi_fbdev->fb)) {
 124                ret = PTR_ERR(hi_fbdev->fb);
 125                DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
 126                goto out_release_fbi;
 127        }
 128
 129        priv->fbdev->size = size;
 130        hi_fbdev->helper.fb = &hi_fbdev->fb->fb;
 131
 132        strcpy(info->fix.id, "hibmcdrmfb");
 133
 134        info->fbops = &hibmc_drm_fb_ops;
 135
 136        drm_fb_helper_fill_fix(info, hi_fbdev->fb->fb.pitches[0],
 137                               hi_fbdev->fb->fb.format->depth);
 138        drm_fb_helper_fill_var(info, &priv->fbdev->helper, sizes->fb_width,
 139                               sizes->fb_height);
 140
 141        info->screen_base = bo->kmap.virtual;
 142        info->screen_size = size;
 143
 144        info->fix.smem_start = bo->bo.mem.bus.offset + bo->bo.mem.bus.base;
 145        info->fix.smem_len = size;
 146        return 0;
 147
 148out_release_fbi:
 149        ret1 = ttm_bo_reserve(&bo->bo, true, false, NULL);
 150        if (ret1) {
 151                DRM_ERROR("failed to rsv ttm_bo when release fbi: %d\n", ret1);
 152                goto out_unref_gem;
 153        }
 154        ttm_bo_kunmap(&bo->kmap);
 155out_unpin_bo:
 156        hibmc_bo_unpin(bo);
 157out_unreserve_ttm_bo:
 158        ttm_bo_unreserve(&bo->bo);
 159out_unref_gem:
 160        drm_gem_object_put_unlocked(gobj);
 161
 162        return ret;
 163}
 164
 165static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
 166{
 167        struct hibmc_framebuffer *gfb = fbdev->fb;
 168        struct drm_fb_helper *fbh = &fbdev->helper;
 169
 170        drm_fb_helper_unregister_fbi(fbh);
 171
 172        drm_fb_helper_fini(fbh);
 173
 174        if (gfb)
 175                drm_framebuffer_put(&gfb->fb);
 176}
 177
 178static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
 179        .fb_probe = hibmc_drm_fb_create,
 180};
 181
 182int hibmc_fbdev_init(struct hibmc_drm_private *priv)
 183{
 184        int ret;
 185        struct fb_var_screeninfo *var;
 186        struct fb_fix_screeninfo *fix;
 187        struct hibmc_fbdev *hifbdev;
 188
 189        hifbdev = devm_kzalloc(priv->dev->dev, sizeof(*hifbdev), GFP_KERNEL);
 190        if (!hifbdev) {
 191                DRM_ERROR("failed to allocate hibmc_fbdev\n");
 192                return -ENOMEM;
 193        }
 194
 195        priv->fbdev = hifbdev;
 196        drm_fb_helper_prepare(priv->dev, &hifbdev->helper,
 197                              &hibmc_fbdev_helper_funcs);
 198
 199        /* Now just one crtc and one channel */
 200        ret = drm_fb_helper_init(priv->dev, &hifbdev->helper, 1);
 201        if (ret) {
 202                DRM_ERROR("failed to initialize fb helper: %d\n", ret);
 203                return ret;
 204        }
 205
 206        ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
 207        if (ret) {
 208                DRM_ERROR("failed to add all connectors: %d\n", ret);
 209                goto fini;
 210        }
 211
 212        ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
 213        if (ret) {
 214                DRM_ERROR("failed to setup initial conn config: %d\n", ret);
 215                goto fini;
 216        }
 217
 218        var = &hifbdev->helper.fbdev->var;
 219        fix = &hifbdev->helper.fbdev->fix;
 220
 221        DRM_DEBUG_DRIVER("Member of info->var is :\n"
 222                         "xres=%d\n"
 223                         "yres=%d\n"
 224                         "xres_virtual=%d\n"
 225                         "yres_virtual=%d\n"
 226                         "xoffset=%d\n"
 227                         "yoffset=%d\n"
 228                         "bits_per_pixel=%d\n"
 229                         "...\n", var->xres, var->yres, var->xres_virtual,
 230                         var->yres_virtual, var->xoffset, var->yoffset,
 231                         var->bits_per_pixel);
 232        DRM_DEBUG_DRIVER("Member of info->fix is :\n"
 233                         "smem_start=%lx\n"
 234                         "smem_len=%d\n"
 235                         "type=%d\n"
 236                         "type_aux=%d\n"
 237                         "visual=%d\n"
 238                         "xpanstep=%d\n"
 239                         "ypanstep=%d\n"
 240                         "ywrapstep=%d\n"
 241                         "line_length=%d\n"
 242                         "accel=%d\n"
 243                         "capabilities=%d\n"
 244                         "...\n", fix->smem_start, fix->smem_len, fix->type,
 245                         fix->type_aux, fix->visual, fix->xpanstep,
 246                         fix->ypanstep, fix->ywrapstep, fix->line_length,
 247                         fix->accel, fix->capabilities);
 248
 249        return 0;
 250
 251fini:
 252        drm_fb_helper_fini(&hifbdev->helper);
 253        return ret;
 254}
 255
 256void hibmc_fbdev_fini(struct hibmc_drm_private *priv)
 257{
 258        if (!priv->fbdev)
 259                return;
 260
 261        hibmc_fbdev_destroy(priv->fbdev);
 262        priv->fbdev = NULL;
 263}
 264