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