linux/drivers/gpu/drm/bochs/bochs_fbdev.c
<<
>>
Prefs
   1/*
   2 * This program is free software; you can redistribute it and/or modify
   3 * it under the terms of the GNU General Public License as published by
   4 * the Free Software Foundation; either version 2 of the License, or
   5 * (at your option) any later version.
   6 */
   7
   8#include "bochs.h"
   9
  10/* ---------------------------------------------------------------------- */
  11
  12static struct fb_ops bochsfb_ops = {
  13        .owner = THIS_MODULE,
  14        .fb_check_var = drm_fb_helper_check_var,
  15        .fb_set_par = drm_fb_helper_set_par,
  16        .fb_fillrect = sys_fillrect,
  17        .fb_copyarea = sys_copyarea,
  18        .fb_imageblit = sys_imageblit,
  19        .fb_pan_display = drm_fb_helper_pan_display,
  20        .fb_blank = drm_fb_helper_blank,
  21        .fb_setcmap = drm_fb_helper_setcmap,
  22};
  23
  24static int bochsfb_create_object(struct bochs_device *bochs,
  25                                 struct drm_mode_fb_cmd2 *mode_cmd,
  26                                 struct drm_gem_object **gobj_p)
  27{
  28        struct drm_device *dev = bochs->dev;
  29        struct drm_gem_object *gobj;
  30        u32 size;
  31        int ret = 0;
  32
  33        size = mode_cmd->pitches[0] * mode_cmd->height;
  34        ret = bochs_gem_create(dev, size, true, &gobj);
  35        if (ret)
  36                return ret;
  37
  38        *gobj_p = gobj;
  39        return ret;
  40}
  41
  42static int bochsfb_create(struct drm_fb_helper *helper,
  43                          struct drm_fb_helper_surface_size *sizes)
  44{
  45        struct bochs_device *bochs =
  46                container_of(helper, struct bochs_device, fb.helper);
  47        struct drm_device *dev = bochs->dev;
  48        struct fb_info *info;
  49        struct drm_framebuffer *fb;
  50        struct drm_mode_fb_cmd2 mode_cmd;
  51        struct device *device = &dev->pdev->dev;
  52        struct drm_gem_object *gobj = NULL;
  53        struct bochs_bo *bo = NULL;
  54        int size, ret;
  55
  56        if (sizes->surface_bpp != 32)
  57                return -EINVAL;
  58
  59        mode_cmd.width = sizes->surface_width;
  60        mode_cmd.height = sizes->surface_height;
  61        mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
  62        mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
  63                                                          sizes->surface_depth);
  64        size = mode_cmd.pitches[0] * mode_cmd.height;
  65
  66        /* alloc, pin & map bo */
  67        ret = bochsfb_create_object(bochs, &mode_cmd, &gobj);
  68        if (ret) {
  69                DRM_ERROR("failed to create fbcon backing object %d\n", ret);
  70                return ret;
  71        }
  72
  73        bo = gem_to_bochs_bo(gobj);
  74
  75        ret = ttm_bo_reserve(&bo->bo, true, false, false, 0);
  76        if (ret)
  77                return ret;
  78
  79        ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
  80        if (ret) {
  81                DRM_ERROR("failed to pin fbcon\n");
  82                ttm_bo_unreserve(&bo->bo);
  83                return ret;
  84        }
  85
  86        ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages,
  87                          &bo->kmap);
  88        if (ret) {
  89                DRM_ERROR("failed to kmap fbcon\n");
  90                ttm_bo_unreserve(&bo->bo);
  91                return ret;
  92        }
  93
  94        ttm_bo_unreserve(&bo->bo);
  95
  96        /* init fb device */
  97        info = framebuffer_alloc(0, device);
  98        if (info == NULL)
  99                return -ENOMEM;
 100
 101        info->par = &bochs->fb.helper;
 102
 103        ret = bochs_framebuffer_init(bochs->dev, &bochs->fb.gfb, &mode_cmd, gobj);
 104        if (ret)
 105                return ret;
 106
 107        bochs->fb.size = size;
 108
 109        /* setup helper */
 110        fb = &bochs->fb.gfb.base;
 111        bochs->fb.helper.fb = fb;
 112        bochs->fb.helper.fbdev = info;
 113
 114        strcpy(info->fix.id, "bochsdrmfb");
 115
 116        info->flags = FBINFO_DEFAULT;
 117        info->fbops = &bochsfb_ops;
 118
 119        drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
 120        drm_fb_helper_fill_var(info, &bochs->fb.helper, sizes->fb_width,
 121                               sizes->fb_height);
 122
 123        info->screen_base = bo->kmap.virtual;
 124        info->screen_size = size;
 125
 126#if 0
 127        /* FIXME: get this right for mmap(/dev/fb0) */
 128        info->fix.smem_start = bochs_bo_mmap_offset(bo);
 129        info->fix.smem_len = size;
 130#endif
 131
 132        ret = fb_alloc_cmap(&info->cmap, 256, 0);
 133        if (ret) {
 134                DRM_ERROR("%s: can't allocate color map\n", info->fix.id);
 135                return -ENOMEM;
 136        }
 137
 138        return 0;
 139}
 140
 141static int bochs_fbdev_destroy(struct bochs_device *bochs)
 142{
 143        struct bochs_framebuffer *gfb = &bochs->fb.gfb;
 144        struct fb_info *info;
 145
 146        DRM_DEBUG_DRIVER("\n");
 147
 148        if (bochs->fb.helper.fbdev) {
 149                info = bochs->fb.helper.fbdev;
 150
 151                unregister_framebuffer(info);
 152                if (info->cmap.len)
 153                        fb_dealloc_cmap(&info->cmap);
 154                framebuffer_release(info);
 155        }
 156
 157        if (gfb->obj) {
 158                drm_gem_object_unreference_unlocked(gfb->obj);
 159                gfb->obj = NULL;
 160        }
 161
 162        drm_fb_helper_fini(&bochs->fb.helper);
 163        drm_framebuffer_unregister_private(&gfb->base);
 164        drm_framebuffer_cleanup(&gfb->base);
 165
 166        return 0;
 167}
 168
 169void bochs_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
 170                        u16 blue, int regno)
 171{
 172}
 173
 174void bochs_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
 175                        u16 *blue, int regno)
 176{
 177        *red   = regno;
 178        *green = regno;
 179        *blue  = regno;
 180}
 181
 182static struct drm_fb_helper_funcs bochs_fb_helper_funcs = {
 183        .gamma_set = bochs_fb_gamma_set,
 184        .gamma_get = bochs_fb_gamma_get,
 185        .fb_probe = bochsfb_create,
 186};
 187
 188int bochs_fbdev_init(struct bochs_device *bochs)
 189{
 190        int ret;
 191
 192        bochs->fb.helper.funcs = &bochs_fb_helper_funcs;
 193
 194        ret = drm_fb_helper_init(bochs->dev, &bochs->fb.helper,
 195                                 1, 1);
 196        if (ret)
 197                return ret;
 198
 199        drm_fb_helper_single_add_all_connectors(&bochs->fb.helper);
 200        drm_helper_disable_unused_functions(bochs->dev);
 201        drm_fb_helper_initial_config(&bochs->fb.helper, 32);
 202
 203        bochs->fb.initialized = true;
 204        return 0;
 205}
 206
 207void bochs_fbdev_fini(struct bochs_device *bochs)
 208{
 209        if (!bochs->fb.initialized)
 210                return;
 211
 212        bochs_fbdev_destroy(bochs);
 213        bochs->fb.initialized = false;
 214}
 215