2 * Copyright (C) 2015 Red Hat, Inc.
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:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
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.
28 #include "virtgpu_drv.h"
29 #include <drm/drm_crtc_helper.h>
30 #include <drm/drm_atomic_helper.h>
41 static int virtio_gpu_page_flip(struct drm_crtc
*crtc
,
42 struct drm_framebuffer
*fb
,
43 struct drm_pending_vblank_event
*event
,
46 struct virtio_gpu_device
*vgdev
= crtc
->dev
->dev_private
;
47 struct virtio_gpu_output
*output
=
48 container_of(crtc
, struct virtio_gpu_output
, crtc
);
49 struct drm_plane
*plane
= crtc
->primary
;
50 struct virtio_gpu_framebuffer
*vgfb
;
51 struct virtio_gpu_object
*bo
;
52 unsigned long irqflags
;
56 vgfb
= to_virtio_gpu_framebuffer(plane
->fb
);
57 bo
= gem_to_virtio_gpu_obj(vgfb
->obj
);
58 handle
= bo
->hw_res_handle
;
60 DRM_DEBUG("handle 0x%x%s, crtc %dx%d\n", handle
,
61 bo
->dumb
? ", dumb" : "",
62 crtc
->mode
.hdisplay
, crtc
->mode
.vdisplay
);
64 virtio_gpu_cmd_transfer_to_host_2d
66 cpu_to_le32(crtc
->mode
.hdisplay
),
67 cpu_to_le32(crtc
->mode
.vdisplay
),
70 virtio_gpu_cmd_set_scanout(vgdev
, output
->index
, handle
,
72 crtc
->mode
.vdisplay
, 0, 0);
73 virtio_gpu_cmd_resource_flush(vgdev
, handle
, 0, 0,
78 spin_lock_irqsave(&crtc
->dev
->event_lock
, irqflags
);
79 drm_crtc_send_vblank_event(crtc
, event
);
80 spin_unlock_irqrestore(&crtc
->dev
->event_lock
, irqflags
);
86 static const struct drm_crtc_funcs virtio_gpu_crtc_funcs
= {
87 .set_config
= drm_atomic_helper_set_config
,
88 .destroy
= drm_crtc_cleanup
,
90 .page_flip
= virtio_gpu_page_flip
,
91 .reset
= drm_atomic_helper_crtc_reset
,
92 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
93 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
96 static void virtio_gpu_user_framebuffer_destroy(struct drm_framebuffer
*fb
)
98 struct virtio_gpu_framebuffer
*virtio_gpu_fb
99 = to_virtio_gpu_framebuffer(fb
);
101 if (virtio_gpu_fb
->obj
)
102 drm_gem_object_unreference_unlocked(virtio_gpu_fb
->obj
);
103 drm_framebuffer_cleanup(fb
);
104 kfree(virtio_gpu_fb
);
108 virtio_gpu_framebuffer_surface_dirty(struct drm_framebuffer
*fb
,
109 struct drm_file
*file_priv
,
110 unsigned flags
, unsigned color
,
111 struct drm_clip_rect
*clips
,
114 struct virtio_gpu_framebuffer
*virtio_gpu_fb
115 = to_virtio_gpu_framebuffer(fb
);
117 return virtio_gpu_surface_dirty(virtio_gpu_fb
, clips
, num_clips
);
120 static const struct drm_framebuffer_funcs virtio_gpu_fb_funcs
= {
121 .destroy
= virtio_gpu_user_framebuffer_destroy
,
122 .dirty
= virtio_gpu_framebuffer_surface_dirty
,
126 virtio_gpu_framebuffer_init(struct drm_device
*dev
,
127 struct virtio_gpu_framebuffer
*vgfb
,
128 const struct drm_mode_fb_cmd2
*mode_cmd
,
129 struct drm_gem_object
*obj
)
132 struct virtio_gpu_object
*bo
;
135 bo
= gem_to_virtio_gpu_obj(obj
);
137 ret
= drm_framebuffer_init(dev
, &vgfb
->base
, &virtio_gpu_fb_funcs
);
142 drm_helper_mode_fill_fb_struct(&vgfb
->base
, mode_cmd
);
144 spin_lock_init(&vgfb
->dirty_lock
);
145 vgfb
->x1
= vgfb
->y1
= INT_MAX
;
146 vgfb
->x2
= vgfb
->y2
= 0;
150 static void virtio_gpu_crtc_mode_set_nofb(struct drm_crtc
*crtc
)
152 struct drm_device
*dev
= crtc
->dev
;
153 struct virtio_gpu_device
*vgdev
= dev
->dev_private
;
154 struct virtio_gpu_output
*output
= drm_crtc_to_virtio_gpu_output(crtc
);
156 virtio_gpu_cmd_set_scanout(vgdev
, output
->index
, 0,
158 crtc
->mode
.vdisplay
, 0, 0);
161 static void virtio_gpu_crtc_enable(struct drm_crtc
*crtc
)
165 static void virtio_gpu_crtc_disable(struct drm_crtc
*crtc
)
167 struct drm_device
*dev
= crtc
->dev
;
168 struct virtio_gpu_device
*vgdev
= dev
->dev_private
;
169 struct virtio_gpu_output
*output
= drm_crtc_to_virtio_gpu_output(crtc
);
171 virtio_gpu_cmd_set_scanout(vgdev
, output
->index
, 0, 0, 0, 0, 0);
174 static int virtio_gpu_crtc_atomic_check(struct drm_crtc
*crtc
,
175 struct drm_crtc_state
*state
)
180 static void virtio_gpu_crtc_atomic_flush(struct drm_crtc
*crtc
,
181 struct drm_crtc_state
*old_state
)
185 spin_lock_irqsave(&crtc
->dev
->event_lock
, flags
);
186 if (crtc
->state
->event
)
187 drm_crtc_send_vblank_event(crtc
, crtc
->state
->event
);
188 spin_unlock_irqrestore(&crtc
->dev
->event_lock
, flags
);
191 static const struct drm_crtc_helper_funcs virtio_gpu_crtc_helper_funcs
= {
192 .enable
= virtio_gpu_crtc_enable
,
193 .disable
= virtio_gpu_crtc_disable
,
194 .mode_set_nofb
= virtio_gpu_crtc_mode_set_nofb
,
195 .atomic_check
= virtio_gpu_crtc_atomic_check
,
196 .atomic_flush
= virtio_gpu_crtc_atomic_flush
,
199 static void virtio_gpu_enc_mode_set(struct drm_encoder
*encoder
,
200 struct drm_display_mode
*mode
,
201 struct drm_display_mode
*adjusted_mode
)
205 static void virtio_gpu_enc_enable(struct drm_encoder
*encoder
)
209 static void virtio_gpu_enc_disable(struct drm_encoder
*encoder
)
213 static int virtio_gpu_conn_get_modes(struct drm_connector
*connector
)
215 struct virtio_gpu_output
*output
=
216 drm_connector_to_virtio_gpu_output(connector
);
217 struct drm_display_mode
*mode
= NULL
;
218 int count
, width
, height
;
220 width
= le32_to_cpu(output
->info
.r
.width
);
221 height
= le32_to_cpu(output
->info
.r
.height
);
222 count
= drm_add_modes_noedid(connector
, XRES_MAX
, YRES_MAX
);
224 if (width
== 0 || height
== 0) {
227 drm_set_preferred_mode(connector
, XRES_DEF
, YRES_DEF
);
229 DRM_DEBUG("add mode: %dx%d\n", width
, height
);
230 mode
= drm_cvt_mode(connector
->dev
, width
, height
, 60,
231 false, false, false);
232 mode
->type
|= DRM_MODE_TYPE_PREFERRED
;
233 drm_mode_probed_add(connector
, mode
);
240 static int virtio_gpu_conn_mode_valid(struct drm_connector
*connector
,
241 struct drm_display_mode
*mode
)
243 struct virtio_gpu_output
*output
=
244 drm_connector_to_virtio_gpu_output(connector
);
247 width
= le32_to_cpu(output
->info
.r
.width
);
248 height
= le32_to_cpu(output
->info
.r
.height
);
250 if (!(mode
->type
& DRM_MODE_TYPE_PREFERRED
))
252 if (mode
->hdisplay
== XRES_DEF
&& mode
->vdisplay
== YRES_DEF
)
254 if (mode
->hdisplay
<= width
&& mode
->hdisplay
>= width
- 16 &&
255 mode
->vdisplay
<= height
&& mode
->vdisplay
>= height
- 16)
258 DRM_DEBUG("del mode: %dx%d\n", mode
->hdisplay
, mode
->vdisplay
);
262 static const struct drm_encoder_helper_funcs virtio_gpu_enc_helper_funcs
= {
263 .mode_set
= virtio_gpu_enc_mode_set
,
264 .enable
= virtio_gpu_enc_enable
,
265 .disable
= virtio_gpu_enc_disable
,
268 static const struct drm_connector_helper_funcs virtio_gpu_conn_helper_funcs
= {
269 .get_modes
= virtio_gpu_conn_get_modes
,
270 .mode_valid
= virtio_gpu_conn_mode_valid
,
273 static enum drm_connector_status
virtio_gpu_conn_detect(
274 struct drm_connector
*connector
,
277 struct virtio_gpu_output
*output
=
278 drm_connector_to_virtio_gpu_output(connector
);
280 if (output
->info
.enabled
)
281 return connector_status_connected
;
283 return connector_status_disconnected
;
286 static void virtio_gpu_conn_destroy(struct drm_connector
*connector
)
288 struct virtio_gpu_output
*virtio_gpu_output
=
289 drm_connector_to_virtio_gpu_output(connector
);
291 drm_connector_unregister(connector
);
292 drm_connector_cleanup(connector
);
293 kfree(virtio_gpu_output
);
296 static const struct drm_connector_funcs virtio_gpu_connector_funcs
= {
297 .dpms
= drm_atomic_helper_connector_dpms
,
298 .detect
= virtio_gpu_conn_detect
,
299 .fill_modes
= drm_helper_probe_single_connector_modes
,
300 .destroy
= virtio_gpu_conn_destroy
,
301 .reset
= drm_atomic_helper_connector_reset
,
302 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
303 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
306 static const struct drm_encoder_funcs virtio_gpu_enc_funcs
= {
307 .destroy
= drm_encoder_cleanup
,
310 static int vgdev_output_init(struct virtio_gpu_device
*vgdev
, int index
)
312 struct drm_device
*dev
= vgdev
->ddev
;
313 struct virtio_gpu_output
*output
= vgdev
->outputs
+ index
;
314 struct drm_connector
*connector
= &output
->conn
;
315 struct drm_encoder
*encoder
= &output
->enc
;
316 struct drm_crtc
*crtc
= &output
->crtc
;
317 struct drm_plane
*primary
, *cursor
;
319 output
->index
= index
;
321 output
->info
.enabled
= cpu_to_le32(true);
322 output
->info
.r
.width
= cpu_to_le32(XRES_DEF
);
323 output
->info
.r
.height
= cpu_to_le32(YRES_DEF
);
326 primary
= virtio_gpu_plane_init(vgdev
, DRM_PLANE_TYPE_PRIMARY
, index
);
328 return PTR_ERR(primary
);
329 cursor
= virtio_gpu_plane_init(vgdev
, DRM_PLANE_TYPE_CURSOR
, index
);
331 return PTR_ERR(cursor
);
332 drm_crtc_init_with_planes(dev
, crtc
, primary
, cursor
,
333 &virtio_gpu_crtc_funcs
, NULL
);
334 drm_crtc_helper_add(crtc
, &virtio_gpu_crtc_helper_funcs
);
335 primary
->crtc
= crtc
;
338 drm_connector_init(dev
, connector
, &virtio_gpu_connector_funcs
,
339 DRM_MODE_CONNECTOR_VIRTUAL
);
340 drm_connector_helper_add(connector
, &virtio_gpu_conn_helper_funcs
);
342 drm_encoder_init(dev
, encoder
, &virtio_gpu_enc_funcs
,
343 DRM_MODE_ENCODER_VIRTUAL
, NULL
);
344 drm_encoder_helper_add(encoder
, &virtio_gpu_enc_helper_funcs
);
345 encoder
->possible_crtcs
= 1 << index
;
347 drm_mode_connector_attach_encoder(connector
, encoder
);
348 drm_connector_register(connector
);
352 static struct drm_framebuffer
*
353 virtio_gpu_user_framebuffer_create(struct drm_device
*dev
,
354 struct drm_file
*file_priv
,
355 const struct drm_mode_fb_cmd2
*mode_cmd
)
357 struct drm_gem_object
*obj
= NULL
;
358 struct virtio_gpu_framebuffer
*virtio_gpu_fb
;
361 /* lookup object associated with res handle */
362 obj
= drm_gem_object_lookup(file_priv
, mode_cmd
->handles
[0]);
364 return ERR_PTR(-EINVAL
);
366 virtio_gpu_fb
= kzalloc(sizeof(*virtio_gpu_fb
), GFP_KERNEL
);
367 if (virtio_gpu_fb
== NULL
)
368 return ERR_PTR(-ENOMEM
);
370 ret
= virtio_gpu_framebuffer_init(dev
, virtio_gpu_fb
, mode_cmd
, obj
);
372 kfree(virtio_gpu_fb
);
374 drm_gem_object_unreference_unlocked(obj
);
378 return &virtio_gpu_fb
->base
;
381 static int vgdev_atomic_commit(struct drm_device
*dev
,
382 struct drm_atomic_state
*state
,
388 drm_atomic_helper_swap_state(state
, true);
389 drm_atomic_helper_wait_for_fences(dev
, state
);
391 drm_atomic_helper_commit_modeset_disables(dev
, state
);
392 drm_atomic_helper_commit_modeset_enables(dev
, state
);
393 drm_atomic_helper_commit_planes(dev
, state
, true);
395 drm_atomic_helper_wait_for_vblanks(dev
, state
);
396 drm_atomic_helper_cleanup_planes(dev
, state
);
397 drm_atomic_state_free(state
);
401 static const struct drm_mode_config_funcs virtio_gpu_mode_funcs
= {
402 .fb_create
= virtio_gpu_user_framebuffer_create
,
403 .atomic_check
= drm_atomic_helper_check
,
404 .atomic_commit
= vgdev_atomic_commit
,
407 int virtio_gpu_modeset_init(struct virtio_gpu_device
*vgdev
)
411 drm_mode_config_init(vgdev
->ddev
);
412 vgdev
->ddev
->mode_config
.funcs
= (void *)&virtio_gpu_mode_funcs
;
414 /* modes will be validated against the framebuffer size */
415 vgdev
->ddev
->mode_config
.min_width
= XRES_MIN
;
416 vgdev
->ddev
->mode_config
.min_height
= YRES_MIN
;
417 vgdev
->ddev
->mode_config
.max_width
= XRES_MAX
;
418 vgdev
->ddev
->mode_config
.max_height
= YRES_MAX
;
420 for (i
= 0 ; i
< vgdev
->num_scanouts
; ++i
)
421 vgdev_output_init(vgdev
, i
);
423 drm_mode_config_reset(vgdev
->ddev
);
427 void virtio_gpu_modeset_fini(struct virtio_gpu_device
*vgdev
)
429 virtio_gpu_fbdev_fini(vgdev
);
430 drm_mode_config_cleanup(vgdev
->ddev
);