linux/drivers/gpu/drm/armada/armada_fb.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012 Russell King
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8#include <drm/drmP.h>
   9#include <drm/drm_crtc_helper.h>
  10#include <drm/drm_fb_helper.h>
  11#include "armada_drm.h"
  12#include "armada_fb.h"
  13#include "armada_gem.h"
  14#include "armada_hw.h"
  15
  16static void armada_fb_destroy(struct drm_framebuffer *fb)
  17{
  18        struct armada_framebuffer *dfb = drm_fb_to_armada_fb(fb);
  19
  20        drm_framebuffer_cleanup(&dfb->fb);
  21        drm_gem_object_unreference_unlocked(&dfb->obj->obj);
  22        kfree(dfb);
  23}
  24
  25static int armada_fb_create_handle(struct drm_framebuffer *fb,
  26        struct drm_file *dfile, unsigned int *handle)
  27{
  28        struct armada_framebuffer *dfb = drm_fb_to_armada_fb(fb);
  29        return drm_gem_handle_create(dfile, &dfb->obj->obj, handle);
  30}
  31
  32static const struct drm_framebuffer_funcs armada_fb_funcs = {
  33        .destroy        = armada_fb_destroy,
  34        .create_handle  = armada_fb_create_handle,
  35};
  36
  37struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev,
  38        const struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj)
  39{
  40        struct armada_framebuffer *dfb;
  41        uint8_t format, config;
  42        int ret;
  43
  44        switch (mode->pixel_format) {
  45#define FMT(drm, fmt, mod)              \
  46        case DRM_FORMAT_##drm:          \
  47                format = CFG_##fmt;     \
  48                config = mod;           \
  49                break
  50        FMT(RGB565,     565,            CFG_SWAPRB);
  51        FMT(BGR565,     565,            0);
  52        FMT(ARGB1555,   1555,           CFG_SWAPRB);
  53        FMT(ABGR1555,   1555,           0);
  54        FMT(RGB888,     888PACK,        CFG_SWAPRB);
  55        FMT(BGR888,     888PACK,        0);
  56        FMT(XRGB8888,   X888,           CFG_SWAPRB);
  57        FMT(XBGR8888,   X888,           0);
  58        FMT(ARGB8888,   8888,           CFG_SWAPRB);
  59        FMT(ABGR8888,   8888,           0);
  60        FMT(YUYV,       422PACK,        CFG_YUV2RGB | CFG_SWAPYU | CFG_SWAPUV);
  61        FMT(UYVY,       422PACK,        CFG_YUV2RGB);
  62        FMT(VYUY,       422PACK,        CFG_YUV2RGB | CFG_SWAPUV);
  63        FMT(YVYU,       422PACK,        CFG_YUV2RGB | CFG_SWAPYU);
  64        FMT(YUV422,     422,            CFG_YUV2RGB);
  65        FMT(YVU422,     422,            CFG_YUV2RGB | CFG_SWAPUV);
  66        FMT(YUV420,     420,            CFG_YUV2RGB);
  67        FMT(YVU420,     420,            CFG_YUV2RGB | CFG_SWAPUV);
  68        FMT(C8,         PSEUDO8,        0);
  69#undef FMT
  70        default:
  71                return ERR_PTR(-EINVAL);
  72        }
  73
  74        dfb = kzalloc(sizeof(*dfb), GFP_KERNEL);
  75        if (!dfb) {
  76                DRM_ERROR("failed to allocate Armada fb object\n");
  77                return ERR_PTR(-ENOMEM);
  78        }
  79
  80        dfb->fmt = format;
  81        dfb->mod = config;
  82        dfb->obj = obj;
  83
  84        drm_helper_mode_fill_fb_struct(&dfb->fb, mode);
  85
  86        ret = drm_framebuffer_init(dev, &dfb->fb, &armada_fb_funcs);
  87        if (ret) {
  88                kfree(dfb);
  89                return ERR_PTR(ret);
  90        }
  91
  92        /*
  93         * Take a reference on our object as we're successful - the
  94         * caller already holds a reference, which keeps us safe for
  95         * the above call, but the caller will drop their reference
  96         * to it.  Hence we need to take our own reference.
  97         */
  98        drm_gem_object_reference(&obj->obj);
  99
 100        return dfb;
 101}
 102
 103static struct drm_framebuffer *armada_fb_create(struct drm_device *dev,
 104        struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode)
 105{
 106        struct armada_gem_object *obj;
 107        struct armada_framebuffer *dfb;
 108        int ret;
 109
 110        DRM_DEBUG_DRIVER("w%u h%u pf%08x f%u p%u,%u,%u\n",
 111                mode->width, mode->height, mode->pixel_format,
 112                mode->flags, mode->pitches[0], mode->pitches[1],
 113                mode->pitches[2]);
 114
 115        /* We can only handle a single plane at the moment */
 116        if (drm_format_num_planes(mode->pixel_format) > 1 &&
 117            (mode->handles[0] != mode->handles[1] ||
 118             mode->handles[0] != mode->handles[2])) {
 119                ret = -EINVAL;
 120                goto err;
 121        }
 122
 123        obj = armada_gem_object_lookup(dev, dfile, mode->handles[0]);
 124        if (!obj) {
 125                ret = -ENOENT;
 126                goto err;
 127        }
 128
 129        if (obj->obj.import_attach && !obj->sgt) {
 130                ret = armada_gem_map_import(obj);
 131                if (ret)
 132                        goto err_unref;
 133        }
 134
 135        /* Framebuffer objects must have a valid device address for scanout */
 136        if (obj->dev_addr == DMA_ERROR_CODE) {
 137                ret = -EINVAL;
 138                goto err_unref;
 139        }
 140
 141        dfb = armada_framebuffer_create(dev, mode, obj);
 142        if (IS_ERR(dfb)) {
 143                ret = PTR_ERR(dfb);
 144                goto err;
 145        }
 146
 147        drm_gem_object_unreference_unlocked(&obj->obj);
 148
 149        return &dfb->fb;
 150
 151 err_unref:
 152        drm_gem_object_unreference_unlocked(&obj->obj);
 153 err:
 154        DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
 155        return ERR_PTR(ret);
 156}
 157
 158static void armada_output_poll_changed(struct drm_device *dev)
 159{
 160        struct armada_private *priv = dev->dev_private;
 161        struct drm_fb_helper *fbh = priv->fbdev;
 162
 163        if (fbh)
 164                drm_fb_helper_hotplug_event(fbh);
 165}
 166
 167const struct drm_mode_config_funcs armada_drm_mode_config_funcs = {
 168        .fb_create              = armada_fb_create,
 169        .output_poll_changed    = armada_output_poll_changed,
 170};
 171