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