root/drivers/gpu/drm/virtio/virtgpu_display.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. virtio_gpu_framebuffer_init
  2. virtio_gpu_crtc_mode_set_nofb
  3. virtio_gpu_crtc_atomic_enable
  4. virtio_gpu_crtc_atomic_disable
  5. virtio_gpu_crtc_atomic_check
  6. virtio_gpu_crtc_atomic_flush
  7. virtio_gpu_enc_mode_set
  8. virtio_gpu_enc_enable
  9. virtio_gpu_enc_disable
  10. virtio_gpu_conn_get_modes
  11. virtio_gpu_conn_mode_valid
  12. virtio_gpu_conn_detect
  13. virtio_gpu_conn_destroy
  14. vgdev_output_init
  15. virtio_gpu_user_framebuffer_create
  16. vgdev_atomic_commit_tail
  17. virtio_gpu_modeset_init
  18. virtio_gpu_modeset_fini

   1 /*
   2  * Copyright (C) 2015 Red Hat, Inc.
   3  * All Rights Reserved.
   4  *
   5  * Authors:
   6  *    Dave Airlie
   7  *    Alon Levy
   8  *
   9  * Permission is hereby granted, free of charge, to any person obtaining a
  10  * copy of this software and associated documentation files (the "Software"),
  11  * to deal in the Software without restriction, including without limitation
  12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  13  * and/or sell copies of the Software, and to permit persons to whom the
  14  * Software is furnished to do so, subject to the following conditions:
  15  *
  16  * The above copyright notice and this permission notice shall be included in
  17  * all copies or substantial portions of the Software.
  18  *
  19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  22  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  23  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  24  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  25  * OTHER DEALINGS IN THE SOFTWARE.
  26  */
  27 
  28 #include <drm/drm_atomic_helper.h>
  29 #include <drm/drm_damage_helper.h>
  30 #include <drm/drm_fourcc.h>
  31 #include <drm/drm_gem_framebuffer_helper.h>
  32 #include <drm/drm_probe_helper.h>
  33 #include <drm/drm_vblank.h>
  34 
  35 #include "virtgpu_drv.h"
  36 
  37 #define XRES_MIN    32
  38 #define YRES_MIN    32
  39 
  40 #define XRES_DEF  1024
  41 #define YRES_DEF   768
  42 
  43 #define XRES_MAX  8192
  44 #define YRES_MAX  8192
  45 
  46 static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = {
  47         .set_config             = drm_atomic_helper_set_config,
  48         .destroy                = drm_crtc_cleanup,
  49 
  50         .page_flip              = drm_atomic_helper_page_flip,
  51         .reset                  = drm_atomic_helper_crtc_reset,
  52         .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
  53         .atomic_destroy_state   = drm_atomic_helper_crtc_destroy_state,
  54 };
  55 
  56 static const struct drm_framebuffer_funcs virtio_gpu_fb_funcs = {
  57         .create_handle = drm_gem_fb_create_handle,
  58         .destroy = drm_gem_fb_destroy,
  59         .dirty = drm_atomic_helper_dirtyfb,
  60 };
  61 
  62 int
  63 virtio_gpu_framebuffer_init(struct drm_device *dev,
  64                             struct virtio_gpu_framebuffer *vgfb,
  65                             const struct drm_mode_fb_cmd2 *mode_cmd,
  66                             struct drm_gem_object *obj)
  67 {
  68         int ret;
  69 
  70         vgfb->base.obj[0] = obj;
  71 
  72         drm_helper_mode_fill_fb_struct(dev, &vgfb->base, mode_cmd);
  73 
  74         ret = drm_framebuffer_init(dev, &vgfb->base, &virtio_gpu_fb_funcs);
  75         if (ret) {
  76                 vgfb->base.obj[0] = NULL;
  77                 return ret;
  78         }
  79         return 0;
  80 }
  81 
  82 static void virtio_gpu_crtc_mode_set_nofb(struct drm_crtc *crtc)
  83 {
  84         struct drm_device *dev = crtc->dev;
  85         struct virtio_gpu_device *vgdev = dev->dev_private;
  86         struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(crtc);
  87 
  88         virtio_gpu_cmd_set_scanout(vgdev, output->index, 0,
  89                                    crtc->mode.hdisplay,
  90                                    crtc->mode.vdisplay, 0, 0);
  91 }
  92 
  93 static void virtio_gpu_crtc_atomic_enable(struct drm_crtc *crtc,
  94                                           struct drm_crtc_state *old_state)
  95 {
  96         struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(crtc);
  97 
  98         output->enabled = true;
  99 }
 100 
 101 static void virtio_gpu_crtc_atomic_disable(struct drm_crtc *crtc,
 102                                            struct drm_crtc_state *old_state)
 103 {
 104         struct drm_device *dev = crtc->dev;
 105         struct virtio_gpu_device *vgdev = dev->dev_private;
 106         struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(crtc);
 107 
 108         virtio_gpu_cmd_set_scanout(vgdev, output->index, 0, 0, 0, 0, 0);
 109         output->enabled = false;
 110 }
 111 
 112 static int virtio_gpu_crtc_atomic_check(struct drm_crtc *crtc,
 113                                         struct drm_crtc_state *state)
 114 {
 115         return 0;
 116 }
 117 
 118 static void virtio_gpu_crtc_atomic_flush(struct drm_crtc *crtc,
 119                                          struct drm_crtc_state *old_state)
 120 {
 121         unsigned long flags;
 122 
 123         spin_lock_irqsave(&crtc->dev->event_lock, flags);
 124         if (crtc->state->event)
 125                 drm_crtc_send_vblank_event(crtc, crtc->state->event);
 126         crtc->state->event = NULL;
 127         spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 128 }
 129 
 130 static const struct drm_crtc_helper_funcs virtio_gpu_crtc_helper_funcs = {
 131         .mode_set_nofb = virtio_gpu_crtc_mode_set_nofb,
 132         .atomic_check  = virtio_gpu_crtc_atomic_check,
 133         .atomic_flush  = virtio_gpu_crtc_atomic_flush,
 134         .atomic_enable = virtio_gpu_crtc_atomic_enable,
 135         .atomic_disable = virtio_gpu_crtc_atomic_disable,
 136 };
 137 
 138 static void virtio_gpu_enc_mode_set(struct drm_encoder *encoder,
 139                                     struct drm_display_mode *mode,
 140                                     struct drm_display_mode *adjusted_mode)
 141 {
 142 }
 143 
 144 static void virtio_gpu_enc_enable(struct drm_encoder *encoder)
 145 {
 146 }
 147 
 148 static void virtio_gpu_enc_disable(struct drm_encoder *encoder)
 149 {
 150 }
 151 
 152 static int virtio_gpu_conn_get_modes(struct drm_connector *connector)
 153 {
 154         struct virtio_gpu_output *output =
 155                 drm_connector_to_virtio_gpu_output(connector);
 156         struct drm_display_mode *mode = NULL;
 157         int count, width, height;
 158 
 159         if (output->edid) {
 160                 count = drm_add_edid_modes(connector, output->edid);
 161                 if (count)
 162                         return count;
 163         }
 164 
 165         width  = le32_to_cpu(output->info.r.width);
 166         height = le32_to_cpu(output->info.r.height);
 167         count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
 168 
 169         if (width == 0 || height == 0) {
 170                 width = XRES_DEF;
 171                 height = YRES_DEF;
 172                 drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);
 173         } else {
 174                 DRM_DEBUG("add mode: %dx%d\n", width, height);
 175                 mode = drm_cvt_mode(connector->dev, width, height, 60,
 176                                     false, false, false);
 177                 mode->type |= DRM_MODE_TYPE_PREFERRED;
 178                 drm_mode_probed_add(connector, mode);
 179                 count++;
 180         }
 181 
 182         return count;
 183 }
 184 
 185 static enum drm_mode_status virtio_gpu_conn_mode_valid(struct drm_connector *connector,
 186                                       struct drm_display_mode *mode)
 187 {
 188         struct virtio_gpu_output *output =
 189                 drm_connector_to_virtio_gpu_output(connector);
 190         int width, height;
 191 
 192         width  = le32_to_cpu(output->info.r.width);
 193         height = le32_to_cpu(output->info.r.height);
 194 
 195         if (!(mode->type & DRM_MODE_TYPE_PREFERRED))
 196                 return MODE_OK;
 197         if (mode->hdisplay == XRES_DEF && mode->vdisplay == YRES_DEF)
 198                 return MODE_OK;
 199         if (mode->hdisplay <= width  && mode->hdisplay >= width - 16 &&
 200             mode->vdisplay <= height && mode->vdisplay >= height - 16)
 201                 return MODE_OK;
 202 
 203         DRM_DEBUG("del mode: %dx%d\n", mode->hdisplay, mode->vdisplay);
 204         return MODE_BAD;
 205 }
 206 
 207 static const struct drm_encoder_helper_funcs virtio_gpu_enc_helper_funcs = {
 208         .mode_set   = virtio_gpu_enc_mode_set,
 209         .enable     = virtio_gpu_enc_enable,
 210         .disable    = virtio_gpu_enc_disable,
 211 };
 212 
 213 static const struct drm_connector_helper_funcs virtio_gpu_conn_helper_funcs = {
 214         .get_modes    = virtio_gpu_conn_get_modes,
 215         .mode_valid   = virtio_gpu_conn_mode_valid,
 216 };
 217 
 218 static enum drm_connector_status virtio_gpu_conn_detect(
 219                         struct drm_connector *connector,
 220                         bool force)
 221 {
 222         struct virtio_gpu_output *output =
 223                 drm_connector_to_virtio_gpu_output(connector);
 224 
 225         if (output->info.enabled)
 226                 return connector_status_connected;
 227         else
 228                 return connector_status_disconnected;
 229 }
 230 
 231 static void virtio_gpu_conn_destroy(struct drm_connector *connector)
 232 {
 233         drm_connector_unregister(connector);
 234         drm_connector_cleanup(connector);
 235 }
 236 
 237 static const struct drm_connector_funcs virtio_gpu_connector_funcs = {
 238         .detect = virtio_gpu_conn_detect,
 239         .fill_modes = drm_helper_probe_single_connector_modes,
 240         .destroy = virtio_gpu_conn_destroy,
 241         .reset = drm_atomic_helper_connector_reset,
 242         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 243         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 244 };
 245 
 246 static const struct drm_encoder_funcs virtio_gpu_enc_funcs = {
 247         .destroy = drm_encoder_cleanup,
 248 };
 249 
 250 static int vgdev_output_init(struct virtio_gpu_device *vgdev, int index)
 251 {
 252         struct drm_device *dev = vgdev->ddev;
 253         struct virtio_gpu_output *output = vgdev->outputs + index;
 254         struct drm_connector *connector = &output->conn;
 255         struct drm_encoder *encoder = &output->enc;
 256         struct drm_crtc *crtc = &output->crtc;
 257         struct drm_plane *primary, *cursor;
 258 
 259         output->index = index;
 260         if (index == 0) {
 261                 output->info.enabled = cpu_to_le32(true);
 262                 output->info.r.width = cpu_to_le32(XRES_DEF);
 263                 output->info.r.height = cpu_to_le32(YRES_DEF);
 264         }
 265 
 266         primary = virtio_gpu_plane_init(vgdev, DRM_PLANE_TYPE_PRIMARY, index);
 267         if (IS_ERR(primary))
 268                 return PTR_ERR(primary);
 269         cursor = virtio_gpu_plane_init(vgdev, DRM_PLANE_TYPE_CURSOR, index);
 270         if (IS_ERR(cursor))
 271                 return PTR_ERR(cursor);
 272         drm_crtc_init_with_planes(dev, crtc, primary, cursor,
 273                                   &virtio_gpu_crtc_funcs, NULL);
 274         drm_crtc_helper_add(crtc, &virtio_gpu_crtc_helper_funcs);
 275 
 276         drm_connector_init(dev, connector, &virtio_gpu_connector_funcs,
 277                            DRM_MODE_CONNECTOR_VIRTUAL);
 278         drm_connector_helper_add(connector, &virtio_gpu_conn_helper_funcs);
 279         if (vgdev->has_edid)
 280                 drm_connector_attach_edid_property(connector);
 281 
 282         drm_encoder_init(dev, encoder, &virtio_gpu_enc_funcs,
 283                          DRM_MODE_ENCODER_VIRTUAL, NULL);
 284         drm_encoder_helper_add(encoder, &virtio_gpu_enc_helper_funcs);
 285         encoder->possible_crtcs = 1 << index;
 286 
 287         drm_connector_attach_encoder(connector, encoder);
 288         drm_connector_register(connector);
 289         return 0;
 290 }
 291 
 292 static struct drm_framebuffer *
 293 virtio_gpu_user_framebuffer_create(struct drm_device *dev,
 294                                    struct drm_file *file_priv,
 295                                    const struct drm_mode_fb_cmd2 *mode_cmd)
 296 {
 297         struct drm_gem_object *obj = NULL;
 298         struct virtio_gpu_framebuffer *virtio_gpu_fb;
 299         int ret;
 300 
 301         if (mode_cmd->pixel_format != DRM_FORMAT_HOST_XRGB8888 &&
 302             mode_cmd->pixel_format != DRM_FORMAT_HOST_ARGB8888)
 303                 return ERR_PTR(-ENOENT);
 304 
 305         /* lookup object associated with res handle */
 306         obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[0]);
 307         if (!obj)
 308                 return ERR_PTR(-EINVAL);
 309 
 310         virtio_gpu_fb = kzalloc(sizeof(*virtio_gpu_fb), GFP_KERNEL);
 311         if (virtio_gpu_fb == NULL)
 312                 return ERR_PTR(-ENOMEM);
 313 
 314         ret = virtio_gpu_framebuffer_init(dev, virtio_gpu_fb, mode_cmd, obj);
 315         if (ret) {
 316                 kfree(virtio_gpu_fb);
 317                 drm_gem_object_put_unlocked(obj);
 318                 return NULL;
 319         }
 320 
 321         return &virtio_gpu_fb->base;
 322 }
 323 
 324 static void vgdev_atomic_commit_tail(struct drm_atomic_state *state)
 325 {
 326         struct drm_device *dev = state->dev;
 327 
 328         drm_atomic_helper_commit_modeset_disables(dev, state);
 329         drm_atomic_helper_commit_modeset_enables(dev, state);
 330         drm_atomic_helper_commit_planes(dev, state, 0);
 331 
 332         drm_atomic_helper_commit_hw_done(state);
 333 
 334         drm_atomic_helper_wait_for_vblanks(dev, state);
 335         drm_atomic_helper_cleanup_planes(dev, state);
 336 }
 337 
 338 static const struct drm_mode_config_helper_funcs virtio_mode_config_helpers = {
 339         .atomic_commit_tail = vgdev_atomic_commit_tail,
 340 };
 341 
 342 static const struct drm_mode_config_funcs virtio_gpu_mode_funcs = {
 343         .fb_create = virtio_gpu_user_framebuffer_create,
 344         .atomic_check = drm_atomic_helper_check,
 345         .atomic_commit = drm_atomic_helper_commit,
 346 };
 347 
 348 void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev)
 349 {
 350         int i;
 351 
 352         drm_mode_config_init(vgdev->ddev);
 353         vgdev->ddev->mode_config.quirk_addfb_prefer_host_byte_order = true;
 354         vgdev->ddev->mode_config.funcs = &virtio_gpu_mode_funcs;
 355         vgdev->ddev->mode_config.helper_private = &virtio_mode_config_helpers;
 356 
 357         /* modes will be validated against the framebuffer size */
 358         vgdev->ddev->mode_config.min_width = XRES_MIN;
 359         vgdev->ddev->mode_config.min_height = YRES_MIN;
 360         vgdev->ddev->mode_config.max_width = XRES_MAX;
 361         vgdev->ddev->mode_config.max_height = YRES_MAX;
 362 
 363         for (i = 0 ; i < vgdev->num_scanouts; ++i)
 364                 vgdev_output_init(vgdev, i);
 365 
 366         drm_mode_config_reset(vgdev->ddev);
 367 }
 368 
 369 void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev)
 370 {
 371         int i;
 372 
 373         for (i = 0 ; i < vgdev->num_scanouts; ++i)
 374                 kfree(vgdev->outputs[i].edid);
 375         drm_atomic_helper_shutdown(vgdev->ddev);
 376         drm_mode_config_cleanup(vgdev->ddev);
 377 }

/* [<][>][^][v][top][bottom][index][help] */