2 * Copyright 2013 Red Hat Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
22 * Authors: Dave Airlie
26 #include <linux/crc32.h>
27 #include <linux/delay.h>
28 #include <linux/dma-buf-map.h>
30 #include <drm/drm_drv.h>
31 #include <drm/drm_atomic.h>
32 #include <drm/drm_atomic_helper.h>
33 #include <drm/drm_gem_framebuffer_helper.h>
34 #include <drm/drm_plane_helper.h>
35 #include <drm/drm_probe_helper.h>
36 #include <drm/drm_simple_kms_helper.h>
39 #include "qxl_object.h"
41 static bool qxl_head_enabled(struct qxl_head
*head
)
43 return head
->width
&& head
->height
;
46 static int qxl_alloc_client_monitors_config(struct qxl_device
*qdev
,
49 if (qdev
->client_monitors_config
&&
50 count
> qdev
->client_monitors_config
->count
) {
51 kfree(qdev
->client_monitors_config
);
52 qdev
->client_monitors_config
= NULL
;
54 if (!qdev
->client_monitors_config
) {
55 qdev
->client_monitors_config
= kzalloc(
56 struct_size(qdev
->client_monitors_config
,
57 heads
, count
), GFP_KERNEL
);
58 if (!qdev
->client_monitors_config
)
61 qdev
->client_monitors_config
->count
= count
;
66 MONITORS_CONFIG_MODIFIED
,
67 MONITORS_CONFIG_UNCHANGED
,
68 MONITORS_CONFIG_BAD_CRC
,
69 MONITORS_CONFIG_ERROR
,
72 static int qxl_display_copy_rom_client_monitors_config(struct qxl_device
*qdev
)
77 int status
= MONITORS_CONFIG_UNCHANGED
;
79 num_monitors
= qdev
->rom
->client_monitors_config
.count
;
80 crc
= crc32(0, (const uint8_t *)&qdev
->rom
->client_monitors_config
,
81 sizeof(qdev
->rom
->client_monitors_config
));
82 if (crc
!= qdev
->rom
->client_monitors_config_crc
)
83 return MONITORS_CONFIG_BAD_CRC
;
85 DRM_DEBUG_KMS("no client monitors configured\n");
88 if (num_monitors
> qxl_num_crtc
) {
89 DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
90 qxl_num_crtc
, num_monitors
);
91 num_monitors
= qxl_num_crtc
;
93 num_monitors
= qdev
->rom
->client_monitors_config
.count
;
95 if (qdev
->client_monitors_config
96 && (num_monitors
!= qdev
->client_monitors_config
->count
)) {
97 status
= MONITORS_CONFIG_MODIFIED
;
99 if (qxl_alloc_client_monitors_config(qdev
, num_monitors
)) {
100 status
= MONITORS_CONFIG_ERROR
;
103 /* we copy max from the client but it isn't used */
104 qdev
->client_monitors_config
->max_allowed
= qxl_num_crtc
;
105 for (i
= 0 ; i
< qdev
->client_monitors_config
->count
; ++i
) {
106 struct qxl_urect
*c_rect
=
107 &qdev
->rom
->client_monitors_config
.heads
[i
];
108 struct qxl_head
*client_head
=
109 &qdev
->client_monitors_config
->heads
[i
];
110 if (client_head
->x
!= c_rect
->left
) {
111 client_head
->x
= c_rect
->left
;
112 status
= MONITORS_CONFIG_MODIFIED
;
114 if (client_head
->y
!= c_rect
->top
) {
115 client_head
->y
= c_rect
->top
;
116 status
= MONITORS_CONFIG_MODIFIED
;
118 if (client_head
->width
!= c_rect
->right
- c_rect
->left
) {
119 client_head
->width
= c_rect
->right
- c_rect
->left
;
120 status
= MONITORS_CONFIG_MODIFIED
;
122 if (client_head
->height
!= c_rect
->bottom
- c_rect
->top
) {
123 client_head
->height
= c_rect
->bottom
- c_rect
->top
;
124 status
= MONITORS_CONFIG_MODIFIED
;
126 if (client_head
->surface_id
!= 0) {
127 client_head
->surface_id
= 0;
128 status
= MONITORS_CONFIG_MODIFIED
;
130 if (client_head
->id
!= i
) {
132 status
= MONITORS_CONFIG_MODIFIED
;
134 if (client_head
->flags
!= 0) {
135 client_head
->flags
= 0;
136 status
= MONITORS_CONFIG_MODIFIED
;
138 DRM_DEBUG_KMS("read %dx%d+%d+%d\n", client_head
->width
, client_head
->height
,
139 client_head
->x
, client_head
->y
);
145 static void qxl_update_offset_props(struct qxl_device
*qdev
)
147 struct drm_device
*dev
= &qdev
->ddev
;
148 struct drm_connector
*connector
;
149 struct qxl_output
*output
;
150 struct qxl_head
*head
;
152 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
153 output
= drm_connector_to_qxl_output(connector
);
155 head
= &qdev
->client_monitors_config
->heads
[output
->index
];
157 drm_object_property_set_value(&connector
->base
,
158 dev
->mode_config
.suggested_x_property
, head
->x
);
159 drm_object_property_set_value(&connector
->base
,
160 dev
->mode_config
.suggested_y_property
, head
->y
);
164 void qxl_display_read_client_monitors_config(struct qxl_device
*qdev
)
166 struct drm_device
*dev
= &qdev
->ddev
;
167 struct drm_modeset_acquire_ctx ctx
;
168 int status
, retries
, ret
;
170 for (retries
= 0; retries
< 10; retries
++) {
171 status
= qxl_display_copy_rom_client_monitors_config(qdev
);
172 if (status
!= MONITORS_CONFIG_BAD_CRC
)
176 if (status
== MONITORS_CONFIG_ERROR
) {
177 DRM_DEBUG_KMS("ignoring client monitors config: error");
180 if (status
== MONITORS_CONFIG_BAD_CRC
) {
181 DRM_DEBUG_KMS("ignoring client monitors config: bad crc");
184 if (status
== MONITORS_CONFIG_UNCHANGED
) {
185 DRM_DEBUG_KMS("ignoring client monitors config: unchanged");
189 DRM_MODESET_LOCK_ALL_BEGIN(dev
, ctx
, DRM_MODESET_ACQUIRE_INTERRUPTIBLE
, ret
);
190 qxl_update_offset_props(qdev
);
191 DRM_MODESET_LOCK_ALL_END(dev
, ctx
, ret
);
192 if (!drm_helper_hpd_irq_event(dev
)) {
193 /* notify that the monitor configuration changed, to
194 adjust at the arbitrary resolution */
195 drm_kms_helper_hotplug_event(dev
);
199 static int qxl_check_mode(struct qxl_device
*qdev
,
206 if (check_mul_overflow(width
, 4u, &stride
))
208 if (check_mul_overflow(stride
, height
, &size
))
210 if (size
> qdev
->vram_size
)
215 static int qxl_check_framebuffer(struct qxl_device
*qdev
,
218 return qxl_check_mode(qdev
, bo
->surf
.width
, bo
->surf
.height
);
221 static int qxl_add_mode(struct drm_connector
*connector
,
226 struct drm_device
*dev
= connector
->dev
;
227 struct qxl_device
*qdev
= to_qxl(dev
);
228 struct drm_display_mode
*mode
= NULL
;
231 rc
= qxl_check_mode(qdev
, width
, height
);
235 mode
= drm_cvt_mode(dev
, width
, height
, 60, false, false, false);
237 mode
->type
|= DRM_MODE_TYPE_PREFERRED
;
238 mode
->hdisplay
= width
;
239 mode
->vdisplay
= height
;
240 drm_mode_set_name(mode
);
241 drm_mode_probed_add(connector
, mode
);
245 static int qxl_add_monitors_config_modes(struct drm_connector
*connector
)
247 struct drm_device
*dev
= connector
->dev
;
248 struct qxl_device
*qdev
= to_qxl(dev
);
249 struct qxl_output
*output
= drm_connector_to_qxl_output(connector
);
250 int h
= output
->index
;
251 struct qxl_head
*head
;
253 if (!qdev
->monitors_config
)
255 if (h
>= qxl_num_crtc
)
257 if (!qdev
->client_monitors_config
)
259 if (h
>= qdev
->client_monitors_config
->count
)
262 head
= &qdev
->client_monitors_config
->heads
[h
];
263 DRM_DEBUG_KMS("head %d is %dx%d\n", h
, head
->width
, head
->height
);
265 return qxl_add_mode(connector
, head
->width
, head
->height
, true);
268 static struct mode_size
{
277 static int qxl_add_extra_modes(struct drm_connector
*connector
)
281 for (i
= 0; i
< ARRAY_SIZE(extra_modes
); i
++)
282 ret
+= qxl_add_mode(connector
,
289 static void qxl_send_monitors_config(struct qxl_device
*qdev
)
293 BUG_ON(!qdev
->ram_header
->monitors_config
);
295 if (qdev
->monitors_config
->count
== 0)
298 for (i
= 0 ; i
< qdev
->monitors_config
->count
; ++i
) {
299 struct qxl_head
*head
= &qdev
->monitors_config
->heads
[i
];
301 if (head
->y
> 8192 || head
->x
> 8192 ||
302 head
->width
> 8192 || head
->height
> 8192) {
303 DRM_ERROR("head %d wrong: %dx%d+%d+%d\n",
304 i
, head
->width
, head
->height
,
309 qxl_io_monitors_config(qdev
);
312 static void qxl_crtc_update_monitors_config(struct drm_crtc
*crtc
,
315 struct drm_device
*dev
= crtc
->dev
;
316 struct qxl_device
*qdev
= to_qxl(dev
);
317 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
318 struct qxl_head head
;
319 int oldcount
, i
= qcrtc
->index
;
321 if (!qdev
->primary_bo
) {
322 DRM_DEBUG_KMS("no primary surface, skip (%s)\n", reason
);
326 if (!qdev
->monitors_config
|| qxl_num_crtc
<= i
)
331 oldcount
= qdev
->monitors_config
->count
;
332 if (crtc
->state
->active
) {
333 struct drm_display_mode
*mode
= &crtc
->mode
;
335 head
.width
= mode
->hdisplay
;
336 head
.height
= mode
->vdisplay
;
339 if (qdev
->monitors_config
->count
< i
+ 1)
340 qdev
->monitors_config
->count
= i
+ 1;
341 if (qdev
->primary_bo
== qdev
->dumb_shadow_bo
)
342 head
.x
+= qdev
->dumb_heads
[i
].x
;
348 if (qdev
->monitors_config
->count
== i
+ 1)
349 qdev
->monitors_config
->count
= i
;
351 DRM_DEBUG_KMS("inactive head 0, skip (%s)\n", reason
);
355 if (head
.width
== qdev
->monitors_config
->heads
[i
].width
&&
356 head
.height
== qdev
->monitors_config
->heads
[i
].height
&&
357 head
.x
== qdev
->monitors_config
->heads
[i
].x
&&
358 head
.y
== qdev
->monitors_config
->heads
[i
].y
&&
359 oldcount
== qdev
->monitors_config
->count
)
362 DRM_DEBUG_KMS("head %d, %dx%d, at +%d+%d, %s (%s)\n",
363 i
, head
.width
, head
.height
, head
.x
, head
.y
,
364 crtc
->state
->active
? "on" : "off", reason
);
365 if (oldcount
!= qdev
->monitors_config
->count
)
366 DRM_DEBUG_KMS("active heads %d -> %d (%d total)\n",
367 oldcount
, qdev
->monitors_config
->count
,
370 qdev
->monitors_config
->heads
[i
] = head
;
371 qdev
->monitors_config
->max_allowed
= qxl_num_crtc
;
372 qxl_send_monitors_config(qdev
);
375 static void qxl_crtc_atomic_flush(struct drm_crtc
*crtc
,
376 struct drm_atomic_state
*state
)
378 qxl_crtc_update_monitors_config(crtc
, "flush");
381 static void qxl_crtc_destroy(struct drm_crtc
*crtc
)
383 struct qxl_crtc
*qxl_crtc
= to_qxl_crtc(crtc
);
385 qxl_bo_unref(&qxl_crtc
->cursor_bo
);
386 drm_crtc_cleanup(crtc
);
390 static const struct drm_crtc_funcs qxl_crtc_funcs
= {
391 .set_config
= drm_atomic_helper_set_config
,
392 .destroy
= qxl_crtc_destroy
,
393 .page_flip
= drm_atomic_helper_page_flip
,
394 .reset
= drm_atomic_helper_crtc_reset
,
395 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
396 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
399 static int qxl_framebuffer_surface_dirty(struct drm_framebuffer
*fb
,
400 struct drm_file
*file_priv
,
401 unsigned int flags
, unsigned int color
,
402 struct drm_clip_rect
*clips
,
403 unsigned int num_clips
)
405 /* TODO: vmwgfx where this was cribbed from had locking. Why? */
406 struct qxl_device
*qdev
= to_qxl(fb
->dev
);
407 struct drm_clip_rect norect
;
409 struct drm_modeset_acquire_ctx ctx
;
413 DRM_MODESET_LOCK_ALL_BEGIN(fb
->dev
, ctx
, DRM_MODESET_ACQUIRE_INTERRUPTIBLE
, ret
);
415 qobj
= gem_to_qxl_bo(fb
->obj
[0]);
416 /* if we aren't primary surface ignore this */
417 is_primary
= qobj
->shadow
? qobj
->shadow
->is_primary
: qobj
->is_primary
;
424 norect
.x1
= norect
.y1
= 0;
425 norect
.x2
= fb
->width
;
426 norect
.y2
= fb
->height
;
427 } else if (flags
& DRM_MODE_FB_DIRTY_ANNOTATE_COPY
) {
429 inc
= 2; /* skip source rects */
432 qxl_draw_dirty_fb(qdev
, fb
, qobj
, flags
, color
,
433 clips
, num_clips
, inc
, 0);
436 DRM_MODESET_LOCK_ALL_END(fb
->dev
, ctx
, ret
);
441 static const struct drm_framebuffer_funcs qxl_fb_funcs
= {
442 .destroy
= drm_gem_fb_destroy
,
443 .dirty
= qxl_framebuffer_surface_dirty
,
444 .create_handle
= drm_gem_fb_create_handle
,
447 static void qxl_crtc_atomic_enable(struct drm_crtc
*crtc
,
448 struct drm_atomic_state
*state
)
450 qxl_crtc_update_monitors_config(crtc
, "enable");
453 static void qxl_crtc_atomic_disable(struct drm_crtc
*crtc
,
454 struct drm_atomic_state
*state
)
456 qxl_crtc_update_monitors_config(crtc
, "disable");
459 static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs
= {
460 .atomic_flush
= qxl_crtc_atomic_flush
,
461 .atomic_enable
= qxl_crtc_atomic_enable
,
462 .atomic_disable
= qxl_crtc_atomic_disable
,
465 static int qxl_primary_atomic_check(struct drm_plane
*plane
,
466 struct drm_plane_state
*state
)
468 struct qxl_device
*qdev
= to_qxl(plane
->dev
);
471 if (!state
->crtc
|| !state
->fb
)
474 bo
= gem_to_qxl_bo(state
->fb
->obj
[0]);
476 return qxl_check_framebuffer(qdev
, bo
);
479 static int qxl_primary_apply_cursor(struct drm_plane
*plane
)
481 struct drm_device
*dev
= plane
->dev
;
482 struct qxl_device
*qdev
= to_qxl(dev
);
483 struct drm_framebuffer
*fb
= plane
->state
->fb
;
484 struct qxl_crtc
*qcrtc
= to_qxl_crtc(plane
->state
->crtc
);
485 struct qxl_cursor_cmd
*cmd
;
486 struct qxl_release
*release
;
489 if (!qcrtc
->cursor_bo
)
492 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
493 QXL_RELEASE_CURSOR_CMD
,
498 ret
= qxl_release_list_add(release
, qcrtc
->cursor_bo
);
500 goto out_free_release
;
502 ret
= qxl_release_reserve_list(release
, false);
504 goto out_free_release
;
506 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
507 cmd
->type
= QXL_CURSOR_SET
;
508 cmd
->u
.set
.position
.x
= plane
->state
->crtc_x
+ fb
->hot_x
;
509 cmd
->u
.set
.position
.y
= plane
->state
->crtc_y
+ fb
->hot_y
;
511 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
, qcrtc
->cursor_bo
, 0);
513 cmd
->u
.set
.visible
= 1;
514 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
516 qxl_release_fence_buffer_objects(release
);
517 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
522 qxl_release_free(qdev
, release
);
526 static void qxl_primary_atomic_update(struct drm_plane
*plane
,
527 struct drm_plane_state
*old_state
)
529 struct qxl_device
*qdev
= to_qxl(plane
->dev
);
530 struct qxl_bo
*bo
= gem_to_qxl_bo(plane
->state
->fb
->obj
[0]);
531 struct qxl_bo
*primary
;
532 struct drm_clip_rect norect
= {
535 .x2
= plane
->state
->fb
->width
,
536 .y2
= plane
->state
->fb
->height
538 uint32_t dumb_shadow_offset
= 0;
540 primary
= bo
->shadow
? bo
->shadow
: bo
;
542 if (!primary
->is_primary
) {
543 if (qdev
->primary_bo
)
544 qxl_io_destroy_primary(qdev
);
545 qxl_io_create_primary(qdev
, primary
);
546 qxl_primary_apply_cursor(plane
);
551 qdev
->dumb_heads
[plane
->state
->crtc
->index
].x
;
553 qxl_draw_dirty_fb(qdev
, plane
->state
->fb
, bo
, 0, 0, &norect
, 1, 1,
557 static void qxl_primary_atomic_disable(struct drm_plane
*plane
,
558 struct drm_plane_state
*old_state
)
560 struct qxl_device
*qdev
= to_qxl(plane
->dev
);
563 struct qxl_bo
*bo
= gem_to_qxl_bo(old_state
->fb
->obj
[0]);
565 if (bo
->is_primary
) {
566 qxl_io_destroy_primary(qdev
);
567 bo
->is_primary
= false;
572 static void qxl_cursor_atomic_update(struct drm_plane
*plane
,
573 struct drm_plane_state
*old_state
)
575 struct drm_device
*dev
= plane
->dev
;
576 struct qxl_device
*qdev
= to_qxl(dev
);
577 struct drm_framebuffer
*fb
= plane
->state
->fb
;
578 struct qxl_crtc
*qcrtc
= to_qxl_crtc(plane
->state
->crtc
);
579 struct qxl_release
*release
;
580 struct qxl_cursor_cmd
*cmd
;
581 struct qxl_cursor
*cursor
;
582 struct drm_gem_object
*obj
;
583 struct qxl_bo
*cursor_bo
= NULL
, *user_bo
= NULL
, *old_cursor_bo
= NULL
;
585 struct dma_buf_map user_map
;
586 struct dma_buf_map cursor_map
;
590 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
591 QXL_RELEASE_CURSOR_CMD
,
596 if (fb
!= old_state
->fb
) {
598 user_bo
= gem_to_qxl_bo(obj
);
600 /* pinning is done in the prepare/cleanup framevbuffer */
601 ret
= qxl_bo_kmap(user_bo
, &user_map
);
603 goto out_free_release
;
604 user_ptr
= user_map
.vaddr
; /* TODO: Use mapping abstraction properly */
606 ret
= qxl_alloc_bo_reserved(qdev
, release
,
607 sizeof(struct qxl_cursor
) + size
,
612 ret
= qxl_bo_pin(cursor_bo
);
616 ret
= qxl_release_reserve_list(release
, true);
620 ret
= qxl_bo_kmap(cursor_bo
, &cursor_map
);
623 if (cursor_map
.is_iomem
) /* TODO: Use mapping abstraction properly */
624 cursor
= (struct qxl_cursor __force
*)cursor_map
.vaddr_iomem
;
626 cursor
= (struct qxl_cursor
*)cursor_map
.vaddr
;
628 cursor
->header
.unique
= 0;
629 cursor
->header
.type
= SPICE_CURSOR_TYPE_ALPHA
;
630 cursor
->header
.width
= 64;
631 cursor
->header
.height
= 64;
632 cursor
->header
.hot_spot_x
= fb
->hot_x
;
633 cursor
->header
.hot_spot_y
= fb
->hot_y
;
634 cursor
->data_size
= size
;
635 cursor
->chunk
.next_chunk
= 0;
636 cursor
->chunk
.prev_chunk
= 0;
637 cursor
->chunk
.data_size
= size
;
638 memcpy(cursor
->chunk
.data
, user_ptr
, size
);
639 qxl_bo_kunmap(cursor_bo
);
640 qxl_bo_kunmap(user_bo
);
642 cmd
= (struct qxl_cursor_cmd
*) qxl_release_map(qdev
, release
);
643 cmd
->u
.set
.visible
= 1;
644 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
,
646 cmd
->type
= QXL_CURSOR_SET
;
648 old_cursor_bo
= qcrtc
->cursor_bo
;
649 qcrtc
->cursor_bo
= cursor_bo
;
653 ret
= qxl_release_reserve_list(release
, true);
655 goto out_free_release
;
657 cmd
= (struct qxl_cursor_cmd
*) qxl_release_map(qdev
, release
);
658 cmd
->type
= QXL_CURSOR_MOVE
;
661 cmd
->u
.position
.x
= plane
->state
->crtc_x
+ fb
->hot_x
;
662 cmd
->u
.position
.y
= plane
->state
->crtc_y
+ fb
->hot_y
;
664 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
665 qxl_release_fence_buffer_objects(release
);
666 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
668 if (old_cursor_bo
!= NULL
)
669 qxl_bo_unpin(old_cursor_bo
);
670 qxl_bo_unref(&old_cursor_bo
);
671 qxl_bo_unref(&cursor_bo
);
676 qxl_release_backoff_reserve_list(release
);
678 qxl_bo_unpin(cursor_bo
);
680 qxl_bo_unref(&cursor_bo
);
682 qxl_bo_kunmap(user_bo
);
684 qxl_release_free(qdev
, release
);
689 static void qxl_cursor_atomic_disable(struct drm_plane
*plane
,
690 struct drm_plane_state
*old_state
)
692 struct qxl_device
*qdev
= to_qxl(plane
->dev
);
693 struct qxl_release
*release
;
694 struct qxl_cursor_cmd
*cmd
;
697 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
698 QXL_RELEASE_CURSOR_CMD
,
703 ret
= qxl_release_reserve_list(release
, true);
705 qxl_release_free(qdev
, release
);
709 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
710 cmd
->type
= QXL_CURSOR_HIDE
;
711 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
713 qxl_release_fence_buffer_objects(release
);
714 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
717 static void qxl_update_dumb_head(struct qxl_device
*qdev
,
718 int index
, struct qxl_bo
*bo
)
720 uint32_t width
, height
;
722 if (index
>= qdev
->monitors_config
->max_allowed
)
725 if (bo
&& bo
->is_dumb
) {
726 width
= bo
->surf
.width
;
727 height
= bo
->surf
.height
;
733 if (qdev
->dumb_heads
[index
].width
== width
&&
734 qdev
->dumb_heads
[index
].height
== height
)
737 DRM_DEBUG("#%d: %dx%d -> %dx%d\n", index
,
738 qdev
->dumb_heads
[index
].width
,
739 qdev
->dumb_heads
[index
].height
,
741 qdev
->dumb_heads
[index
].width
= width
;
742 qdev
->dumb_heads
[index
].height
= height
;
745 static void qxl_calc_dumb_shadow(struct qxl_device
*qdev
,
746 struct qxl_surface
*surf
)
748 struct qxl_head
*head
;
751 memset(surf
, 0, sizeof(*surf
));
752 for (i
= 0; i
< qdev
->monitors_config
->max_allowed
; i
++) {
753 head
= qdev
->dumb_heads
+ i
;
754 head
->x
= surf
->width
;
755 surf
->width
+= head
->width
;
756 if (surf
->height
< head
->height
)
757 surf
->height
= head
->height
;
759 if (surf
->width
< 64)
761 if (surf
->height
< 64)
763 surf
->format
= SPICE_SURFACE_FMT_32_xRGB
;
764 surf
->stride
= surf
->width
* 4;
766 if (!qdev
->dumb_shadow_bo
||
767 qdev
->dumb_shadow_bo
->surf
.width
!= surf
->width
||
768 qdev
->dumb_shadow_bo
->surf
.height
!= surf
->height
)
769 DRM_DEBUG("%dx%d\n", surf
->width
, surf
->height
);
772 static int qxl_plane_prepare_fb(struct drm_plane
*plane
,
773 struct drm_plane_state
*new_state
)
775 struct qxl_device
*qdev
= to_qxl(plane
->dev
);
776 struct drm_gem_object
*obj
;
777 struct qxl_bo
*user_bo
;
778 struct qxl_surface surf
;
783 obj
= new_state
->fb
->obj
[0];
784 user_bo
= gem_to_qxl_bo(obj
);
786 if (plane
->type
== DRM_PLANE_TYPE_PRIMARY
&&
788 qxl_update_dumb_head(qdev
, new_state
->crtc
->index
,
790 qxl_calc_dumb_shadow(qdev
, &surf
);
791 if (!qdev
->dumb_shadow_bo
||
792 qdev
->dumb_shadow_bo
->surf
.width
!= surf
.width
||
793 qdev
->dumb_shadow_bo
->surf
.height
!= surf
.height
) {
794 if (qdev
->dumb_shadow_bo
) {
796 (&qdev
->dumb_shadow_bo
->tbo
.base
);
797 qdev
->dumb_shadow_bo
= NULL
;
799 qxl_bo_create(qdev
, surf
.height
* surf
.stride
,
800 true, true, QXL_GEM_DOMAIN_SURFACE
, &surf
,
801 &qdev
->dumb_shadow_bo
);
803 if (user_bo
->shadow
!= qdev
->dumb_shadow_bo
) {
804 if (user_bo
->shadow
) {
806 (&user_bo
->shadow
->tbo
.base
);
807 user_bo
->shadow
= NULL
;
809 drm_gem_object_get(&qdev
->dumb_shadow_bo
->tbo
.base
);
810 user_bo
->shadow
= qdev
->dumb_shadow_bo
;
814 return qxl_bo_pin(user_bo
);
817 static void qxl_plane_cleanup_fb(struct drm_plane
*plane
,
818 struct drm_plane_state
*old_state
)
820 struct drm_gem_object
*obj
;
821 struct qxl_bo
*user_bo
;
823 if (!old_state
->fb
) {
825 * we never executed prepare_fb, so there's nothing to
831 obj
= old_state
->fb
->obj
[0];
832 user_bo
= gem_to_qxl_bo(obj
);
833 qxl_bo_unpin(user_bo
);
835 if (old_state
->fb
!= plane
->state
->fb
&& user_bo
->shadow
) {
836 drm_gem_object_put(&user_bo
->shadow
->tbo
.base
);
837 user_bo
->shadow
= NULL
;
841 static const uint32_t qxl_cursor_plane_formats
[] = {
845 static const struct drm_plane_helper_funcs qxl_cursor_helper_funcs
= {
846 .atomic_update
= qxl_cursor_atomic_update
,
847 .atomic_disable
= qxl_cursor_atomic_disable
,
848 .prepare_fb
= qxl_plane_prepare_fb
,
849 .cleanup_fb
= qxl_plane_cleanup_fb
,
852 static const struct drm_plane_funcs qxl_cursor_plane_funcs
= {
853 .update_plane
= drm_atomic_helper_update_plane
,
854 .disable_plane
= drm_atomic_helper_disable_plane
,
855 .destroy
= drm_primary_helper_destroy
,
856 .reset
= drm_atomic_helper_plane_reset
,
857 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
858 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
861 static const uint32_t qxl_primary_plane_formats
[] = {
866 static const struct drm_plane_helper_funcs primary_helper_funcs
= {
867 .atomic_check
= qxl_primary_atomic_check
,
868 .atomic_update
= qxl_primary_atomic_update
,
869 .atomic_disable
= qxl_primary_atomic_disable
,
870 .prepare_fb
= qxl_plane_prepare_fb
,
871 .cleanup_fb
= qxl_plane_cleanup_fb
,
874 static const struct drm_plane_funcs qxl_primary_plane_funcs
= {
875 .update_plane
= drm_atomic_helper_update_plane
,
876 .disable_plane
= drm_atomic_helper_disable_plane
,
877 .destroy
= drm_primary_helper_destroy
,
878 .reset
= drm_atomic_helper_plane_reset
,
879 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
880 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
883 static struct drm_plane
*qxl_create_plane(struct qxl_device
*qdev
,
884 unsigned int possible_crtcs
,
885 enum drm_plane_type type
)
887 const struct drm_plane_helper_funcs
*helper_funcs
= NULL
;
888 struct drm_plane
*plane
;
889 const struct drm_plane_funcs
*funcs
;
890 const uint32_t *formats
;
894 if (type
== DRM_PLANE_TYPE_PRIMARY
) {
895 funcs
= &qxl_primary_plane_funcs
;
896 formats
= qxl_primary_plane_formats
;
897 num_formats
= ARRAY_SIZE(qxl_primary_plane_formats
);
898 helper_funcs
= &primary_helper_funcs
;
899 } else if (type
== DRM_PLANE_TYPE_CURSOR
) {
900 funcs
= &qxl_cursor_plane_funcs
;
901 formats
= qxl_cursor_plane_formats
;
902 helper_funcs
= &qxl_cursor_helper_funcs
;
903 num_formats
= ARRAY_SIZE(qxl_cursor_plane_formats
);
905 return ERR_PTR(-EINVAL
);
908 plane
= kzalloc(sizeof(*plane
), GFP_KERNEL
);
910 return ERR_PTR(-ENOMEM
);
912 err
= drm_universal_plane_init(&qdev
->ddev
, plane
, possible_crtcs
,
913 funcs
, formats
, num_formats
,
918 drm_plane_helper_add(plane
, helper_funcs
);
924 return ERR_PTR(-EINVAL
);
927 static int qdev_crtc_init(struct drm_device
*dev
, int crtc_id
)
929 struct qxl_crtc
*qxl_crtc
;
930 struct drm_plane
*primary
, *cursor
;
931 struct qxl_device
*qdev
= to_qxl(dev
);
934 qxl_crtc
= kzalloc(sizeof(struct qxl_crtc
), GFP_KERNEL
);
938 primary
= qxl_create_plane(qdev
, 1 << crtc_id
, DRM_PLANE_TYPE_PRIMARY
);
939 if (IS_ERR(primary
)) {
944 cursor
= qxl_create_plane(qdev
, 1 << crtc_id
, DRM_PLANE_TYPE_CURSOR
);
945 if (IS_ERR(cursor
)) {
950 r
= drm_crtc_init_with_planes(dev
, &qxl_crtc
->base
, primary
, cursor
,
951 &qxl_crtc_funcs
, NULL
);
955 qxl_crtc
->index
= crtc_id
;
956 drm_crtc_helper_add(&qxl_crtc
->base
, &qxl_crtc_helper_funcs
);
960 drm_plane_cleanup(cursor
);
963 drm_plane_cleanup(primary
);
970 static int qxl_conn_get_modes(struct drm_connector
*connector
)
972 struct drm_device
*dev
= connector
->dev
;
973 struct qxl_device
*qdev
= to_qxl(dev
);
974 struct qxl_output
*output
= drm_connector_to_qxl_output(connector
);
975 unsigned int pwidth
= 1024;
976 unsigned int pheight
= 768;
979 if (qdev
->client_monitors_config
) {
980 struct qxl_head
*head
;
981 head
= &qdev
->client_monitors_config
->heads
[output
->index
];
983 pwidth
= head
->width
;
985 pheight
= head
->height
;
988 ret
+= drm_add_modes_noedid(connector
, 8192, 8192);
989 ret
+= qxl_add_extra_modes(connector
);
990 ret
+= qxl_add_monitors_config_modes(connector
);
991 drm_set_preferred_mode(connector
, pwidth
, pheight
);
995 static enum drm_mode_status
qxl_conn_mode_valid(struct drm_connector
*connector
,
996 struct drm_display_mode
*mode
)
998 struct drm_device
*ddev
= connector
->dev
;
999 struct qxl_device
*qdev
= to_qxl(ddev
);
1001 if (qxl_check_mode(qdev
, mode
->hdisplay
, mode
->vdisplay
) != 0)
1007 static struct drm_encoder
*qxl_best_encoder(struct drm_connector
*connector
)
1009 struct qxl_output
*qxl_output
=
1010 drm_connector_to_qxl_output(connector
);
1013 return &qxl_output
->enc
;
1016 static const struct drm_connector_helper_funcs qxl_connector_helper_funcs
= {
1017 .get_modes
= qxl_conn_get_modes
,
1018 .mode_valid
= qxl_conn_mode_valid
,
1019 .best_encoder
= qxl_best_encoder
,
1022 static enum drm_connector_status
qxl_conn_detect(
1023 struct drm_connector
*connector
,
1026 struct qxl_output
*output
=
1027 drm_connector_to_qxl_output(connector
);
1028 struct drm_device
*ddev
= connector
->dev
;
1029 struct qxl_device
*qdev
= to_qxl(ddev
);
1030 bool connected
= false;
1032 /* The first monitor is always connected */
1033 if (!qdev
->client_monitors_config
) {
1034 if (output
->index
== 0)
1037 connected
= qdev
->client_monitors_config
->count
> output
->index
&&
1038 qxl_head_enabled(&qdev
->client_monitors_config
->heads
[output
->index
]);
1040 DRM_DEBUG("#%d connected: %d\n", output
->index
, connected
);
1042 return connected
? connector_status_connected
1043 : connector_status_disconnected
;
1046 static void qxl_conn_destroy(struct drm_connector
*connector
)
1048 struct qxl_output
*qxl_output
=
1049 drm_connector_to_qxl_output(connector
);
1051 drm_connector_unregister(connector
);
1052 drm_connector_cleanup(connector
);
1056 static const struct drm_connector_funcs qxl_connector_funcs
= {
1057 .detect
= qxl_conn_detect
,
1058 .fill_modes
= drm_helper_probe_single_connector_modes
,
1059 .destroy
= qxl_conn_destroy
,
1060 .reset
= drm_atomic_helper_connector_reset
,
1061 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
1062 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
1065 static int qxl_mode_create_hotplug_mode_update_property(struct qxl_device
*qdev
)
1067 if (qdev
->hotplug_mode_update_property
)
1070 qdev
->hotplug_mode_update_property
=
1071 drm_property_create_range(&qdev
->ddev
, DRM_MODE_PROP_IMMUTABLE
,
1072 "hotplug_mode_update", 0, 1);
1077 static int qdev_output_init(struct drm_device
*dev
, int num_output
)
1079 struct qxl_device
*qdev
= to_qxl(dev
);
1080 struct qxl_output
*qxl_output
;
1081 struct drm_connector
*connector
;
1082 struct drm_encoder
*encoder
;
1085 qxl_output
= kzalloc(sizeof(struct qxl_output
), GFP_KERNEL
);
1089 qxl_output
->index
= num_output
;
1091 connector
= &qxl_output
->base
;
1092 encoder
= &qxl_output
->enc
;
1093 drm_connector_init(dev
, &qxl_output
->base
,
1094 &qxl_connector_funcs
, DRM_MODE_CONNECTOR_VIRTUAL
);
1096 ret
= drm_simple_encoder_init(dev
, &qxl_output
->enc
,
1097 DRM_MODE_ENCODER_VIRTUAL
);
1099 drm_err(dev
, "drm_simple_encoder_init() failed, error %d\n",
1101 goto err_drm_connector_cleanup
;
1104 /* we get HPD via client monitors config */
1105 connector
->polled
= DRM_CONNECTOR_POLL_HPD
;
1106 encoder
->possible_crtcs
= 1 << num_output
;
1107 drm_connector_attach_encoder(&qxl_output
->base
,
1109 drm_connector_helper_add(connector
, &qxl_connector_helper_funcs
);
1111 drm_object_attach_property(&connector
->base
,
1112 qdev
->hotplug_mode_update_property
, 0);
1113 drm_object_attach_property(&connector
->base
,
1114 dev
->mode_config
.suggested_x_property
, 0);
1115 drm_object_attach_property(&connector
->base
,
1116 dev
->mode_config
.suggested_y_property
, 0);
1119 err_drm_connector_cleanup
:
1120 drm_connector_cleanup(&qxl_output
->base
);
1125 static struct drm_framebuffer
*
1126 qxl_user_framebuffer_create(struct drm_device
*dev
,
1127 struct drm_file
*file_priv
,
1128 const struct drm_mode_fb_cmd2
*mode_cmd
)
1130 return drm_gem_fb_create_with_funcs(dev
, file_priv
, mode_cmd
,
1134 static const struct drm_mode_config_funcs qxl_mode_funcs
= {
1135 .fb_create
= qxl_user_framebuffer_create
,
1136 .atomic_check
= drm_atomic_helper_check
,
1137 .atomic_commit
= drm_atomic_helper_commit
,
1140 int qxl_create_monitors_object(struct qxl_device
*qdev
)
1143 struct drm_gem_object
*gobj
;
1144 struct dma_buf_map map
;
1145 int monitors_config_size
= sizeof(struct qxl_monitors_config
) +
1146 qxl_num_crtc
* sizeof(struct qxl_head
);
1148 ret
= qxl_gem_object_create(qdev
, monitors_config_size
, 0,
1149 QXL_GEM_DOMAIN_VRAM
,
1150 false, false, NULL
, &gobj
);
1152 DRM_ERROR("%s: failed to create gem ret=%d\n", __func__
, ret
);
1155 qdev
->monitors_config_bo
= gem_to_qxl_bo(gobj
);
1157 ret
= qxl_bo_pin(qdev
->monitors_config_bo
);
1161 qxl_bo_kmap(qdev
->monitors_config_bo
, &map
);
1163 qdev
->monitors_config
= qdev
->monitors_config_bo
->kptr
;
1164 qdev
->ram_header
->monitors_config
=
1165 qxl_bo_physical_address(qdev
, qdev
->monitors_config_bo
, 0);
1167 memset(qdev
->monitors_config
, 0, monitors_config_size
);
1168 qdev
->dumb_heads
= kcalloc(qxl_num_crtc
, sizeof(qdev
->dumb_heads
[0]),
1170 if (!qdev
->dumb_heads
) {
1171 qxl_destroy_monitors_object(qdev
);
1177 int qxl_destroy_monitors_object(struct qxl_device
*qdev
)
1181 qdev
->monitors_config
= NULL
;
1182 qdev
->ram_header
->monitors_config
= 0;
1184 qxl_bo_kunmap(qdev
->monitors_config_bo
);
1185 ret
= qxl_bo_unpin(qdev
->monitors_config_bo
);
1189 qxl_bo_unref(&qdev
->monitors_config_bo
);
1193 int qxl_modeset_init(struct qxl_device
*qdev
)
1198 drm_mode_config_init(&qdev
->ddev
);
1200 ret
= qxl_create_monitors_object(qdev
);
1204 qdev
->ddev
.mode_config
.funcs
= (void *)&qxl_mode_funcs
;
1206 /* modes will be validated against the framebuffer size */
1207 qdev
->ddev
.mode_config
.min_width
= 0;
1208 qdev
->ddev
.mode_config
.min_height
= 0;
1209 qdev
->ddev
.mode_config
.max_width
= 8192;
1210 qdev
->ddev
.mode_config
.max_height
= 8192;
1212 qdev
->ddev
.mode_config
.fb_base
= qdev
->vram_base
;
1214 drm_mode_create_suggested_offset_properties(&qdev
->ddev
);
1215 qxl_mode_create_hotplug_mode_update_property(qdev
);
1217 for (i
= 0 ; i
< qxl_num_crtc
; ++i
) {
1218 qdev_crtc_init(&qdev
->ddev
, i
);
1219 qdev_output_init(&qdev
->ddev
, i
);
1222 qxl_display_read_client_monitors_config(qdev
);
1224 drm_mode_config_reset(&qdev
->ddev
);
1228 void qxl_modeset_fini(struct qxl_device
*qdev
)
1230 qxl_destroy_monitors_object(qdev
);
1231 drm_mode_config_cleanup(&qdev
->ddev
);