linux/drivers/gpu/drm/vkms/vkms_plane.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2
   3#include <drm/drm_atomic.h>
   4#include <drm/drm_atomic_helper.h>
   5#include <drm/drm_fourcc.h>
   6#include <drm/drm_gem_framebuffer_helper.h>
   7#include <drm/drm_plane_helper.h>
   8
   9#include "vkms_drv.h"
  10
  11static const u32 vkms_formats[] = {
  12        DRM_FORMAT_XRGB8888,
  13};
  14
  15static const u32 vkms_cursor_formats[] = {
  16        DRM_FORMAT_ARGB8888,
  17};
  18
  19static struct drm_plane_state *
  20vkms_plane_duplicate_state(struct drm_plane *plane)
  21{
  22        struct vkms_plane_state *vkms_state;
  23        struct vkms_composer *composer;
  24
  25        vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
  26        if (!vkms_state)
  27                return NULL;
  28
  29        composer = kzalloc(sizeof(*composer), GFP_KERNEL);
  30        if (!composer) {
  31                DRM_DEBUG_KMS("Couldn't allocate composer\n");
  32                kfree(vkms_state);
  33                return NULL;
  34        }
  35
  36        vkms_state->composer = composer;
  37
  38        __drm_atomic_helper_plane_duplicate_state(plane,
  39                                                  &vkms_state->base);
  40
  41        return &vkms_state->base;
  42}
  43
  44static void vkms_plane_destroy_state(struct drm_plane *plane,
  45                                     struct drm_plane_state *old_state)
  46{
  47        struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state);
  48        struct drm_crtc *crtc = vkms_state->base.crtc;
  49
  50        if (crtc) {
  51                /* dropping the reference we acquired in
  52                 * vkms_primary_plane_update()
  53                 */
  54                if (drm_framebuffer_read_refcount(&vkms_state->composer->fb))
  55                        drm_framebuffer_put(&vkms_state->composer->fb);
  56        }
  57
  58        kfree(vkms_state->composer);
  59        vkms_state->composer = NULL;
  60
  61        __drm_atomic_helper_plane_destroy_state(old_state);
  62        kfree(vkms_state);
  63}
  64
  65static void vkms_plane_reset(struct drm_plane *plane)
  66{
  67        struct vkms_plane_state *vkms_state;
  68
  69        if (plane->state)
  70                vkms_plane_destroy_state(plane, plane->state);
  71
  72        vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
  73        if (!vkms_state) {
  74                DRM_ERROR("Cannot allocate vkms_plane_state\n");
  75                return;
  76        }
  77
  78        plane->state = &vkms_state->base;
  79        plane->state->plane = plane;
  80}
  81
  82static const struct drm_plane_funcs vkms_plane_funcs = {
  83        .update_plane           = drm_atomic_helper_update_plane,
  84        .disable_plane          = drm_atomic_helper_disable_plane,
  85        .destroy                = drm_plane_cleanup,
  86        .reset                  = vkms_plane_reset,
  87        .atomic_duplicate_state = vkms_plane_duplicate_state,
  88        .atomic_destroy_state   = vkms_plane_destroy_state,
  89};
  90
  91static void vkms_plane_atomic_update(struct drm_plane *plane,
  92                                     struct drm_plane_state *old_state)
  93{
  94        struct vkms_plane_state *vkms_plane_state;
  95        struct drm_framebuffer *fb = plane->state->fb;
  96        struct vkms_composer *composer;
  97
  98        if (!plane->state->crtc || !fb)
  99                return;
 100
 101        vkms_plane_state = to_vkms_plane_state(plane->state);
 102
 103        composer = vkms_plane_state->composer;
 104        memcpy(&composer->src, &plane->state->src, sizeof(struct drm_rect));
 105        memcpy(&composer->dst, &plane->state->dst, sizeof(struct drm_rect));
 106        memcpy(&composer->fb, fb, sizeof(struct drm_framebuffer));
 107        drm_framebuffer_get(&composer->fb);
 108        composer->offset = fb->offsets[0];
 109        composer->pitch = fb->pitches[0];
 110        composer->cpp = fb->format->cpp[0];
 111}
 112
 113static int vkms_plane_atomic_check(struct drm_plane *plane,
 114                                   struct drm_plane_state *state)
 115{
 116        struct drm_crtc_state *crtc_state;
 117        bool can_position = false;
 118        int ret;
 119
 120        if (!state->fb || WARN_ON(!state->crtc))
 121                return 0;
 122
 123        crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
 124        if (IS_ERR(crtc_state))
 125                return PTR_ERR(crtc_state);
 126
 127        if (plane->type == DRM_PLANE_TYPE_CURSOR)
 128                can_position = true;
 129
 130        ret = drm_atomic_helper_check_plane_state(state, crtc_state,
 131                                                  DRM_PLANE_HELPER_NO_SCALING,
 132                                                  DRM_PLANE_HELPER_NO_SCALING,
 133                                                  can_position, true);
 134        if (ret != 0)
 135                return ret;
 136
 137        /* for now primary plane must be visible and full screen */
 138        if (!state->visible && !can_position)
 139                return -EINVAL;
 140
 141        return 0;
 142}
 143
 144static int vkms_prepare_fb(struct drm_plane *plane,
 145                           struct drm_plane_state *state)
 146{
 147        struct drm_gem_object *gem_obj;
 148        int ret;
 149
 150        if (!state->fb)
 151                return 0;
 152
 153        gem_obj = drm_gem_fb_get_obj(state->fb, 0);
 154        ret = vkms_gem_vmap(gem_obj);
 155        if (ret)
 156                DRM_ERROR("vmap failed: %d\n", ret);
 157
 158        return drm_gem_fb_prepare_fb(plane, state);
 159}
 160
 161static void vkms_cleanup_fb(struct drm_plane *plane,
 162                            struct drm_plane_state *old_state)
 163{
 164        struct drm_gem_object *gem_obj;
 165
 166        if (!old_state->fb)
 167                return;
 168
 169        gem_obj = drm_gem_fb_get_obj(old_state->fb, 0);
 170        vkms_gem_vunmap(gem_obj);
 171}
 172
 173static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = {
 174        .atomic_update          = vkms_plane_atomic_update,
 175        .atomic_check           = vkms_plane_atomic_check,
 176        .prepare_fb             = vkms_prepare_fb,
 177        .cleanup_fb             = vkms_cleanup_fb,
 178};
 179
 180struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev,
 181                                  enum drm_plane_type type, int index)
 182{
 183        struct drm_device *dev = &vkmsdev->drm;
 184        const struct drm_plane_helper_funcs *funcs;
 185        struct drm_plane *plane;
 186        const u32 *formats;
 187        int ret, nformats;
 188
 189        plane = kzalloc(sizeof(*plane), GFP_KERNEL);
 190        if (!plane)
 191                return ERR_PTR(-ENOMEM);
 192
 193        if (type == DRM_PLANE_TYPE_CURSOR) {
 194                formats = vkms_cursor_formats;
 195                nformats = ARRAY_SIZE(vkms_cursor_formats);
 196                funcs = &vkms_primary_helper_funcs;
 197        } else {
 198                formats = vkms_formats;
 199                nformats = ARRAY_SIZE(vkms_formats);
 200                funcs = &vkms_primary_helper_funcs;
 201        }
 202
 203        ret = drm_universal_plane_init(dev, plane, 1 << index,
 204                                       &vkms_plane_funcs,
 205                                       formats, nformats,
 206                                       NULL, type, NULL);
 207        if (ret) {
 208                kfree(plane);
 209                return ERR_PTR(ret);
 210        }
 211
 212        drm_plane_helper_add(plane, funcs);
 213
 214        return plane;
 215}
 216