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>
29 #include <drm/drm_atomic.h>
30 #include <drm/drm_atomic_helper.h>
31 #include <drm/drm_gem_framebuffer_helper.h>
32 #include <drm/drm_plane_helper.h>
33 #include <drm/drm_probe_helper.h>
34 #include <drm/drm_vblank.h>
37 #include "qxl_object.h"
39 static bool qxl_head_enabled(struct qxl_head
*head
)
41 return head
->width
&& head
->height
;
44 static int qxl_alloc_client_monitors_config(struct qxl_device
*qdev
,
47 if (qdev
->client_monitors_config
&&
48 count
> qdev
->client_monitors_config
->count
) {
49 kfree(qdev
->client_monitors_config
);
50 qdev
->client_monitors_config
= NULL
;
52 if (!qdev
->client_monitors_config
) {
53 qdev
->client_monitors_config
= kzalloc(
54 struct_size(qdev
->client_monitors_config
,
55 heads
, count
), GFP_KERNEL
);
56 if (!qdev
->client_monitors_config
)
59 qdev
->client_monitors_config
->count
= count
;
64 MONITORS_CONFIG_MODIFIED
,
65 MONITORS_CONFIG_UNCHANGED
,
66 MONITORS_CONFIG_BAD_CRC
,
67 MONITORS_CONFIG_ERROR
,
70 static int qxl_display_copy_rom_client_monitors_config(struct qxl_device
*qdev
)
75 int status
= MONITORS_CONFIG_UNCHANGED
;
77 num_monitors
= qdev
->rom
->client_monitors_config
.count
;
78 crc
= crc32(0, (const uint8_t *)&qdev
->rom
->client_monitors_config
,
79 sizeof(qdev
->rom
->client_monitors_config
));
80 if (crc
!= qdev
->rom
->client_monitors_config_crc
)
81 return MONITORS_CONFIG_BAD_CRC
;
83 DRM_DEBUG_KMS("no client monitors configured\n");
86 if (num_monitors
> qxl_num_crtc
) {
87 DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
88 qxl_num_crtc
, num_monitors
);
89 num_monitors
= qxl_num_crtc
;
91 num_monitors
= qdev
->rom
->client_monitors_config
.count
;
93 if (qdev
->client_monitors_config
94 && (num_monitors
!= qdev
->client_monitors_config
->count
)) {
95 status
= MONITORS_CONFIG_MODIFIED
;
97 if (qxl_alloc_client_monitors_config(qdev
, num_monitors
)) {
98 status
= MONITORS_CONFIG_ERROR
;
101 /* we copy max from the client but it isn't used */
102 qdev
->client_monitors_config
->max_allowed
= qxl_num_crtc
;
103 for (i
= 0 ; i
< qdev
->client_monitors_config
->count
; ++i
) {
104 struct qxl_urect
*c_rect
=
105 &qdev
->rom
->client_monitors_config
.heads
[i
];
106 struct qxl_head
*client_head
=
107 &qdev
->client_monitors_config
->heads
[i
];
108 if (client_head
->x
!= c_rect
->left
) {
109 client_head
->x
= c_rect
->left
;
110 status
= MONITORS_CONFIG_MODIFIED
;
112 if (client_head
->y
!= c_rect
->top
) {
113 client_head
->y
= c_rect
->top
;
114 status
= MONITORS_CONFIG_MODIFIED
;
116 if (client_head
->width
!= c_rect
->right
- c_rect
->left
) {
117 client_head
->width
= c_rect
->right
- c_rect
->left
;
118 status
= MONITORS_CONFIG_MODIFIED
;
120 if (client_head
->height
!= c_rect
->bottom
- c_rect
->top
) {
121 client_head
->height
= c_rect
->bottom
- c_rect
->top
;
122 status
= MONITORS_CONFIG_MODIFIED
;
124 if (client_head
->surface_id
!= 0) {
125 client_head
->surface_id
= 0;
126 status
= MONITORS_CONFIG_MODIFIED
;
128 if (client_head
->id
!= i
) {
130 status
= MONITORS_CONFIG_MODIFIED
;
132 if (client_head
->flags
!= 0) {
133 client_head
->flags
= 0;
134 status
= MONITORS_CONFIG_MODIFIED
;
136 DRM_DEBUG_KMS("read %dx%d+%d+%d\n", client_head
->width
, client_head
->height
,
137 client_head
->x
, client_head
->y
);
143 static void qxl_update_offset_props(struct qxl_device
*qdev
)
145 struct drm_device
*dev
= &qdev
->ddev
;
146 struct drm_connector
*connector
;
147 struct qxl_output
*output
;
148 struct qxl_head
*head
;
150 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
151 output
= drm_connector_to_qxl_output(connector
);
153 head
= &qdev
->client_monitors_config
->heads
[output
->index
];
155 drm_object_property_set_value(&connector
->base
,
156 dev
->mode_config
.suggested_x_property
, head
->x
);
157 drm_object_property_set_value(&connector
->base
,
158 dev
->mode_config
.suggested_y_property
, head
->y
);
162 void qxl_display_read_client_monitors_config(struct qxl_device
*qdev
)
164 struct drm_device
*dev
= &qdev
->ddev
;
167 for (retries
= 0; retries
< 10; retries
++) {
168 status
= qxl_display_copy_rom_client_monitors_config(qdev
);
169 if (status
!= MONITORS_CONFIG_BAD_CRC
)
173 if (status
== MONITORS_CONFIG_ERROR
) {
174 DRM_DEBUG_KMS("ignoring client monitors config: error");
177 if (status
== MONITORS_CONFIG_BAD_CRC
) {
178 DRM_DEBUG_KMS("ignoring client monitors config: bad crc");
181 if (status
== MONITORS_CONFIG_UNCHANGED
) {
182 DRM_DEBUG_KMS("ignoring client monitors config: unchanged");
186 drm_modeset_lock_all(dev
);
187 qxl_update_offset_props(qdev
);
188 drm_modeset_unlock_all(dev
);
189 if (!drm_helper_hpd_irq_event(dev
)) {
190 /* notify that the monitor configuration changed, to
191 adjust at the arbitrary resolution */
192 drm_kms_helper_hotplug_event(dev
);
196 static int qxl_check_mode(struct qxl_device
*qdev
,
203 if (check_mul_overflow(width
, 4u, &stride
))
205 if (check_mul_overflow(stride
, height
, &size
))
207 if (size
> qdev
->vram_size
)
212 static int qxl_check_framebuffer(struct qxl_device
*qdev
,
215 return qxl_check_mode(qdev
, bo
->surf
.width
, bo
->surf
.height
);
218 static int qxl_add_mode(struct drm_connector
*connector
,
223 struct drm_device
*dev
= connector
->dev
;
224 struct qxl_device
*qdev
= dev
->dev_private
;
225 struct drm_display_mode
*mode
= NULL
;
228 rc
= qxl_check_mode(qdev
, width
, height
);
232 mode
= drm_cvt_mode(dev
, width
, height
, 60, false, false, false);
234 mode
->type
|= DRM_MODE_TYPE_PREFERRED
;
235 mode
->hdisplay
= width
;
236 mode
->vdisplay
= height
;
237 drm_mode_set_name(mode
);
238 drm_mode_probed_add(connector
, mode
);
242 static int qxl_add_monitors_config_modes(struct drm_connector
*connector
)
244 struct drm_device
*dev
= connector
->dev
;
245 struct qxl_device
*qdev
= dev
->dev_private
;
246 struct qxl_output
*output
= drm_connector_to_qxl_output(connector
);
247 int h
= output
->index
;
248 struct qxl_head
*head
;
250 if (!qdev
->monitors_config
)
252 if (h
>= qxl_num_crtc
)
254 if (!qdev
->client_monitors_config
)
256 if (h
>= qdev
->client_monitors_config
->count
)
259 head
= &qdev
->client_monitors_config
->heads
[h
];
260 DRM_DEBUG_KMS("head %d is %dx%d\n", h
, head
->width
, head
->height
);
262 return qxl_add_mode(connector
, head
->width
, head
->height
, true);
265 static struct mode_size
{
274 static int qxl_add_extra_modes(struct drm_connector
*connector
)
278 for (i
= 0; i
< ARRAY_SIZE(extra_modes
); i
++)
279 ret
+= qxl_add_mode(connector
,
286 static void qxl_send_monitors_config(struct qxl_device
*qdev
)
290 BUG_ON(!qdev
->ram_header
->monitors_config
);
292 if (qdev
->monitors_config
->count
== 0)
295 for (i
= 0 ; i
< qdev
->monitors_config
->count
; ++i
) {
296 struct qxl_head
*head
= &qdev
->monitors_config
->heads
[i
];
298 if (head
->y
> 8192 || head
->x
> 8192 ||
299 head
->width
> 8192 || head
->height
> 8192) {
300 DRM_ERROR("head %d wrong: %dx%d+%d+%d\n",
301 i
, head
->width
, head
->height
,
306 qxl_io_monitors_config(qdev
);
309 static void qxl_crtc_update_monitors_config(struct drm_crtc
*crtc
,
312 struct drm_device
*dev
= crtc
->dev
;
313 struct qxl_device
*qdev
= dev
->dev_private
;
314 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
315 struct qxl_head head
;
316 int oldcount
, i
= qcrtc
->index
;
318 if (!qdev
->primary_bo
) {
319 DRM_DEBUG_KMS("no primary surface, skip (%s)\n", reason
);
323 if (!qdev
->monitors_config
|| qxl_num_crtc
<= i
)
328 oldcount
= qdev
->monitors_config
->count
;
329 if (crtc
->state
->active
) {
330 struct drm_display_mode
*mode
= &crtc
->mode
;
332 head
.width
= mode
->hdisplay
;
333 head
.height
= mode
->vdisplay
;
336 if (qdev
->monitors_config
->count
< i
+ 1)
337 qdev
->monitors_config
->count
= i
+ 1;
338 if (qdev
->primary_bo
== qdev
->dumb_shadow_bo
)
339 head
.x
+= qdev
->dumb_heads
[i
].x
;
345 if (qdev
->monitors_config
->count
== i
+ 1)
346 qdev
->monitors_config
->count
= i
;
348 DRM_DEBUG_KMS("inactive head 0, skip (%s)\n", reason
);
352 if (head
.width
== qdev
->monitors_config
->heads
[i
].width
&&
353 head
.height
== qdev
->monitors_config
->heads
[i
].height
&&
354 head
.x
== qdev
->monitors_config
->heads
[i
].x
&&
355 head
.y
== qdev
->monitors_config
->heads
[i
].y
&&
356 oldcount
== qdev
->monitors_config
->count
)
359 DRM_DEBUG_KMS("head %d, %dx%d, at +%d+%d, %s (%s)\n",
360 i
, head
.width
, head
.height
, head
.x
, head
.y
,
361 crtc
->state
->active
? "on" : "off", reason
);
362 if (oldcount
!= qdev
->monitors_config
->count
)
363 DRM_DEBUG_KMS("active heads %d -> %d (%d total)\n",
364 oldcount
, qdev
->monitors_config
->count
,
367 qdev
->monitors_config
->heads
[i
] = head
;
368 qdev
->monitors_config
->max_allowed
= qxl_num_crtc
;
369 qxl_send_monitors_config(qdev
);
372 static void qxl_crtc_atomic_flush(struct drm_crtc
*crtc
,
373 struct drm_crtc_state
*old_crtc_state
)
375 struct drm_device
*dev
= crtc
->dev
;
376 struct drm_pending_vblank_event
*event
;
379 if (crtc
->state
&& crtc
->state
->event
) {
380 event
= crtc
->state
->event
;
381 crtc
->state
->event
= NULL
;
383 spin_lock_irqsave(&dev
->event_lock
, flags
);
384 drm_crtc_send_vblank_event(crtc
, event
);
385 spin_unlock_irqrestore(&dev
->event_lock
, flags
);
388 qxl_crtc_update_monitors_config(crtc
, "flush");
391 static void qxl_crtc_destroy(struct drm_crtc
*crtc
)
393 struct qxl_crtc
*qxl_crtc
= to_qxl_crtc(crtc
);
395 qxl_bo_unref(&qxl_crtc
->cursor_bo
);
396 drm_crtc_cleanup(crtc
);
400 static const struct drm_crtc_funcs qxl_crtc_funcs
= {
401 .set_config
= drm_atomic_helper_set_config
,
402 .destroy
= qxl_crtc_destroy
,
403 .page_flip
= drm_atomic_helper_page_flip
,
404 .reset
= drm_atomic_helper_crtc_reset
,
405 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
406 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
409 static int qxl_framebuffer_surface_dirty(struct drm_framebuffer
*fb
,
410 struct drm_file
*file_priv
,
411 unsigned int flags
, unsigned int color
,
412 struct drm_clip_rect
*clips
,
413 unsigned int num_clips
)
415 /* TODO: vmwgfx where this was cribbed from had locking. Why? */
416 struct qxl_device
*qdev
= fb
->dev
->dev_private
;
417 struct drm_clip_rect norect
;
422 drm_modeset_lock_all(fb
->dev
);
424 qobj
= gem_to_qxl_bo(fb
->obj
[0]);
425 /* if we aren't primary surface ignore this */
426 is_primary
= qobj
->shadow
? qobj
->shadow
->is_primary
: qobj
->is_primary
;
428 drm_modeset_unlock_all(fb
->dev
);
435 norect
.x1
= norect
.y1
= 0;
436 norect
.x2
= fb
->width
;
437 norect
.y2
= fb
->height
;
438 } else if (flags
& DRM_MODE_FB_DIRTY_ANNOTATE_COPY
) {
440 inc
= 2; /* skip source rects */
443 qxl_draw_dirty_fb(qdev
, fb
, qobj
, flags
, color
,
444 clips
, num_clips
, inc
, 0);
446 drm_modeset_unlock_all(fb
->dev
);
451 static const struct drm_framebuffer_funcs qxl_fb_funcs
= {
452 .destroy
= drm_gem_fb_destroy
,
453 .dirty
= qxl_framebuffer_surface_dirty
,
454 .create_handle
= drm_gem_fb_create_handle
,
457 static void qxl_crtc_atomic_enable(struct drm_crtc
*crtc
,
458 struct drm_crtc_state
*old_state
)
460 qxl_crtc_update_monitors_config(crtc
, "enable");
463 static void qxl_crtc_atomic_disable(struct drm_crtc
*crtc
,
464 struct drm_crtc_state
*old_state
)
466 qxl_crtc_update_monitors_config(crtc
, "disable");
469 static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs
= {
470 .atomic_flush
= qxl_crtc_atomic_flush
,
471 .atomic_enable
= qxl_crtc_atomic_enable
,
472 .atomic_disable
= qxl_crtc_atomic_disable
,
475 static int qxl_primary_atomic_check(struct drm_plane
*plane
,
476 struct drm_plane_state
*state
)
478 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
481 if (!state
->crtc
|| !state
->fb
)
484 bo
= gem_to_qxl_bo(state
->fb
->obj
[0]);
486 return qxl_check_framebuffer(qdev
, bo
);
489 static int qxl_primary_apply_cursor(struct drm_plane
*plane
)
491 struct drm_device
*dev
= plane
->dev
;
492 struct qxl_device
*qdev
= dev
->dev_private
;
493 struct drm_framebuffer
*fb
= plane
->state
->fb
;
494 struct qxl_crtc
*qcrtc
= to_qxl_crtc(plane
->state
->crtc
);
495 struct qxl_cursor_cmd
*cmd
;
496 struct qxl_release
*release
;
499 if (!qcrtc
->cursor_bo
)
502 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
503 QXL_RELEASE_CURSOR_CMD
,
508 ret
= qxl_release_list_add(release
, qcrtc
->cursor_bo
);
510 goto out_free_release
;
512 ret
= qxl_release_reserve_list(release
, false);
514 goto out_free_release
;
516 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
517 cmd
->type
= QXL_CURSOR_SET
;
518 cmd
->u
.set
.position
.x
= plane
->state
->crtc_x
+ fb
->hot_x
;
519 cmd
->u
.set
.position
.y
= plane
->state
->crtc_y
+ fb
->hot_y
;
521 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
, qcrtc
->cursor_bo
, 0);
523 cmd
->u
.set
.visible
= 1;
524 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
526 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
527 qxl_release_fence_buffer_objects(release
);
532 qxl_release_free(qdev
, release
);
536 static void qxl_primary_atomic_update(struct drm_plane
*plane
,
537 struct drm_plane_state
*old_state
)
539 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
540 struct qxl_bo
*bo
= gem_to_qxl_bo(plane
->state
->fb
->obj
[0]);
541 struct qxl_bo
*primary
;
542 struct drm_clip_rect norect
= {
545 .x2
= plane
->state
->fb
->width
,
546 .y2
= plane
->state
->fb
->height
548 uint32_t dumb_shadow_offset
= 0;
550 primary
= bo
->shadow
? bo
->shadow
: bo
;
552 if (!primary
->is_primary
) {
553 if (qdev
->primary_bo
)
554 qxl_io_destroy_primary(qdev
);
555 qxl_io_create_primary(qdev
, primary
);
556 qxl_primary_apply_cursor(plane
);
561 qdev
->dumb_heads
[plane
->state
->crtc
->index
].x
;
563 qxl_draw_dirty_fb(qdev
, plane
->state
->fb
, bo
, 0, 0, &norect
, 1, 1,
567 static void qxl_primary_atomic_disable(struct drm_plane
*plane
,
568 struct drm_plane_state
*old_state
)
570 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
573 struct qxl_bo
*bo
= gem_to_qxl_bo(old_state
->fb
->obj
[0]);
575 if (bo
->is_primary
) {
576 qxl_io_destroy_primary(qdev
);
577 bo
->is_primary
= false;
582 static void qxl_cursor_atomic_update(struct drm_plane
*plane
,
583 struct drm_plane_state
*old_state
)
585 struct drm_device
*dev
= plane
->dev
;
586 struct qxl_device
*qdev
= dev
->dev_private
;
587 struct drm_framebuffer
*fb
= plane
->state
->fb
;
588 struct qxl_crtc
*qcrtc
= to_qxl_crtc(plane
->state
->crtc
);
589 struct qxl_release
*release
;
590 struct qxl_cursor_cmd
*cmd
;
591 struct qxl_cursor
*cursor
;
592 struct drm_gem_object
*obj
;
593 struct qxl_bo
*cursor_bo
= NULL
, *user_bo
= NULL
, *old_cursor_bo
= NULL
;
598 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
599 QXL_RELEASE_CURSOR_CMD
,
604 if (fb
!= old_state
->fb
) {
606 user_bo
= gem_to_qxl_bo(obj
);
608 /* pinning is done in the prepare/cleanup framevbuffer */
609 ret
= qxl_bo_kmap(user_bo
, &user_ptr
);
611 goto out_free_release
;
613 ret
= qxl_alloc_bo_reserved(qdev
, release
,
614 sizeof(struct qxl_cursor
) + size
,
619 ret
= qxl_bo_pin(cursor_bo
);
623 ret
= qxl_release_reserve_list(release
, true);
627 ret
= qxl_bo_kmap(cursor_bo
, (void **)&cursor
);
631 cursor
->header
.unique
= 0;
632 cursor
->header
.type
= SPICE_CURSOR_TYPE_ALPHA
;
633 cursor
->header
.width
= 64;
634 cursor
->header
.height
= 64;
635 cursor
->header
.hot_spot_x
= fb
->hot_x
;
636 cursor
->header
.hot_spot_y
= fb
->hot_y
;
637 cursor
->data_size
= size
;
638 cursor
->chunk
.next_chunk
= 0;
639 cursor
->chunk
.prev_chunk
= 0;
640 cursor
->chunk
.data_size
= size
;
641 memcpy(cursor
->chunk
.data
, user_ptr
, size
);
642 qxl_bo_kunmap(cursor_bo
);
643 qxl_bo_kunmap(user_bo
);
645 cmd
= (struct qxl_cursor_cmd
*) qxl_release_map(qdev
, release
);
646 cmd
->u
.set
.visible
= 1;
647 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
,
649 cmd
->type
= QXL_CURSOR_SET
;
651 old_cursor_bo
= qcrtc
->cursor_bo
;
652 qcrtc
->cursor_bo
= cursor_bo
;
656 ret
= qxl_release_reserve_list(release
, true);
658 goto out_free_release
;
660 cmd
= (struct qxl_cursor_cmd
*) qxl_release_map(qdev
, release
);
661 cmd
->type
= QXL_CURSOR_MOVE
;
664 cmd
->u
.position
.x
= plane
->state
->crtc_x
+ fb
->hot_x
;
665 cmd
->u
.position
.y
= plane
->state
->crtc_y
+ fb
->hot_y
;
667 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
668 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
669 qxl_release_fence_buffer_objects(release
);
671 if (old_cursor_bo
!= NULL
)
672 qxl_bo_unpin(old_cursor_bo
);
673 qxl_bo_unref(&old_cursor_bo
);
674 qxl_bo_unref(&cursor_bo
);
679 qxl_release_backoff_reserve_list(release
);
681 qxl_bo_unpin(cursor_bo
);
683 qxl_bo_unref(&cursor_bo
);
685 qxl_bo_kunmap(user_bo
);
687 qxl_release_free(qdev
, release
);
692 static void qxl_cursor_atomic_disable(struct drm_plane
*plane
,
693 struct drm_plane_state
*old_state
)
695 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
696 struct qxl_release
*release
;
697 struct qxl_cursor_cmd
*cmd
;
700 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
701 QXL_RELEASE_CURSOR_CMD
,
706 ret
= qxl_release_reserve_list(release
, true);
708 qxl_release_free(qdev
, release
);
712 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
713 cmd
->type
= QXL_CURSOR_HIDE
;
714 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
716 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
717 qxl_release_fence_buffer_objects(release
);
720 static void qxl_update_dumb_head(struct qxl_device
*qdev
,
721 int index
, struct qxl_bo
*bo
)
723 uint32_t width
, height
;
725 if (index
>= qdev
->monitors_config
->max_allowed
)
728 if (bo
&& bo
->is_dumb
) {
729 width
= bo
->surf
.width
;
730 height
= bo
->surf
.height
;
736 if (qdev
->dumb_heads
[index
].width
== width
&&
737 qdev
->dumb_heads
[index
].height
== height
)
740 DRM_DEBUG("#%d: %dx%d -> %dx%d\n", index
,
741 qdev
->dumb_heads
[index
].width
,
742 qdev
->dumb_heads
[index
].height
,
744 qdev
->dumb_heads
[index
].width
= width
;
745 qdev
->dumb_heads
[index
].height
= height
;
748 static void qxl_calc_dumb_shadow(struct qxl_device
*qdev
,
749 struct qxl_surface
*surf
)
751 struct qxl_head
*head
;
754 memset(surf
, 0, sizeof(*surf
));
755 for (i
= 0; i
< qdev
->monitors_config
->max_allowed
; i
++) {
756 head
= qdev
->dumb_heads
+ i
;
757 head
->x
= surf
->width
;
758 surf
->width
+= head
->width
;
759 if (surf
->height
< head
->height
)
760 surf
->height
= head
->height
;
762 if (surf
->width
< 64)
764 if (surf
->height
< 64)
766 surf
->format
= SPICE_SURFACE_FMT_32_xRGB
;
767 surf
->stride
= surf
->width
* 4;
769 if (!qdev
->dumb_shadow_bo
||
770 qdev
->dumb_shadow_bo
->surf
.width
!= surf
->width
||
771 qdev
->dumb_shadow_bo
->surf
.height
!= surf
->height
)
772 DRM_DEBUG("%dx%d\n", surf
->width
, surf
->height
);
775 static int qxl_plane_prepare_fb(struct drm_plane
*plane
,
776 struct drm_plane_state
*new_state
)
778 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
779 struct drm_gem_object
*obj
;
780 struct qxl_bo
*user_bo
;
781 struct qxl_surface surf
;
787 obj
= new_state
->fb
->obj
[0];
788 user_bo
= gem_to_qxl_bo(obj
);
790 if (plane
->type
== DRM_PLANE_TYPE_PRIMARY
&&
792 qxl_update_dumb_head(qdev
, new_state
->crtc
->index
,
794 qxl_calc_dumb_shadow(qdev
, &surf
);
795 if (!qdev
->dumb_shadow_bo
||
796 qdev
->dumb_shadow_bo
->surf
.width
!= surf
.width
||
797 qdev
->dumb_shadow_bo
->surf
.height
!= surf
.height
) {
798 if (qdev
->dumb_shadow_bo
) {
799 drm_gem_object_put_unlocked
800 (&qdev
->dumb_shadow_bo
->tbo
.base
);
801 qdev
->dumb_shadow_bo
= NULL
;
803 qxl_bo_create(qdev
, surf
.height
* surf
.stride
,
804 true, true, QXL_GEM_DOMAIN_SURFACE
, &surf
,
805 &qdev
->dumb_shadow_bo
);
807 if (user_bo
->shadow
!= qdev
->dumb_shadow_bo
) {
808 if (user_bo
->shadow
) {
809 drm_gem_object_put_unlocked
810 (&user_bo
->shadow
->tbo
.base
);
811 user_bo
->shadow
= NULL
;
813 drm_gem_object_get(&qdev
->dumb_shadow_bo
->tbo
.base
);
814 user_bo
->shadow
= qdev
->dumb_shadow_bo
;
818 ret
= qxl_bo_pin(user_bo
);
825 static void qxl_plane_cleanup_fb(struct drm_plane
*plane
,
826 struct drm_plane_state
*old_state
)
828 struct drm_gem_object
*obj
;
829 struct qxl_bo
*user_bo
;
831 if (!old_state
->fb
) {
833 * we never executed prepare_fb, so there's nothing to
839 obj
= old_state
->fb
->obj
[0];
840 user_bo
= gem_to_qxl_bo(obj
);
841 qxl_bo_unpin(user_bo
);
843 if (old_state
->fb
!= plane
->state
->fb
&& user_bo
->shadow
) {
844 drm_gem_object_put_unlocked(&user_bo
->shadow
->tbo
.base
);
845 user_bo
->shadow
= NULL
;
849 static const uint32_t qxl_cursor_plane_formats
[] = {
853 static const struct drm_plane_helper_funcs qxl_cursor_helper_funcs
= {
854 .atomic_update
= qxl_cursor_atomic_update
,
855 .atomic_disable
= qxl_cursor_atomic_disable
,
856 .prepare_fb
= qxl_plane_prepare_fb
,
857 .cleanup_fb
= qxl_plane_cleanup_fb
,
860 static const struct drm_plane_funcs qxl_cursor_plane_funcs
= {
861 .update_plane
= drm_atomic_helper_update_plane
,
862 .disable_plane
= drm_atomic_helper_disable_plane
,
863 .destroy
= drm_primary_helper_destroy
,
864 .reset
= drm_atomic_helper_plane_reset
,
865 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
866 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
869 static const uint32_t qxl_primary_plane_formats
[] = {
874 static const struct drm_plane_helper_funcs primary_helper_funcs
= {
875 .atomic_check
= qxl_primary_atomic_check
,
876 .atomic_update
= qxl_primary_atomic_update
,
877 .atomic_disable
= qxl_primary_atomic_disable
,
878 .prepare_fb
= qxl_plane_prepare_fb
,
879 .cleanup_fb
= qxl_plane_cleanup_fb
,
882 static const struct drm_plane_funcs qxl_primary_plane_funcs
= {
883 .update_plane
= drm_atomic_helper_update_plane
,
884 .disable_plane
= drm_atomic_helper_disable_plane
,
885 .destroy
= drm_primary_helper_destroy
,
886 .reset
= drm_atomic_helper_plane_reset
,
887 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
888 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
891 static struct drm_plane
*qxl_create_plane(struct qxl_device
*qdev
,
892 unsigned int possible_crtcs
,
893 enum drm_plane_type type
)
895 const struct drm_plane_helper_funcs
*helper_funcs
= NULL
;
896 struct drm_plane
*plane
;
897 const struct drm_plane_funcs
*funcs
;
898 const uint32_t *formats
;
902 if (type
== DRM_PLANE_TYPE_PRIMARY
) {
903 funcs
= &qxl_primary_plane_funcs
;
904 formats
= qxl_primary_plane_formats
;
905 num_formats
= ARRAY_SIZE(qxl_primary_plane_formats
);
906 helper_funcs
= &primary_helper_funcs
;
907 } else if (type
== DRM_PLANE_TYPE_CURSOR
) {
908 funcs
= &qxl_cursor_plane_funcs
;
909 formats
= qxl_cursor_plane_formats
;
910 helper_funcs
= &qxl_cursor_helper_funcs
;
911 num_formats
= ARRAY_SIZE(qxl_cursor_plane_formats
);
913 return ERR_PTR(-EINVAL
);
916 plane
= kzalloc(sizeof(*plane
), GFP_KERNEL
);
918 return ERR_PTR(-ENOMEM
);
920 err
= drm_universal_plane_init(&qdev
->ddev
, plane
, possible_crtcs
,
921 funcs
, formats
, num_formats
,
926 drm_plane_helper_add(plane
, helper_funcs
);
932 return ERR_PTR(-EINVAL
);
935 static int qdev_crtc_init(struct drm_device
*dev
, int crtc_id
)
937 struct qxl_crtc
*qxl_crtc
;
938 struct drm_plane
*primary
, *cursor
;
939 struct qxl_device
*qdev
= dev
->dev_private
;
942 qxl_crtc
= kzalloc(sizeof(struct qxl_crtc
), GFP_KERNEL
);
946 primary
= qxl_create_plane(qdev
, 1 << crtc_id
, DRM_PLANE_TYPE_PRIMARY
);
947 if (IS_ERR(primary
)) {
952 cursor
= qxl_create_plane(qdev
, 1 << crtc_id
, DRM_PLANE_TYPE_CURSOR
);
953 if (IS_ERR(cursor
)) {
958 r
= drm_crtc_init_with_planes(dev
, &qxl_crtc
->base
, primary
, cursor
,
959 &qxl_crtc_funcs
, NULL
);
963 qxl_crtc
->index
= crtc_id
;
964 drm_crtc_helper_add(&qxl_crtc
->base
, &qxl_crtc_helper_funcs
);
968 drm_plane_cleanup(cursor
);
971 drm_plane_cleanup(primary
);
978 static int qxl_conn_get_modes(struct drm_connector
*connector
)
980 struct drm_device
*dev
= connector
->dev
;
981 struct qxl_device
*qdev
= dev
->dev_private
;
982 struct qxl_output
*output
= drm_connector_to_qxl_output(connector
);
983 unsigned int pwidth
= 1024;
984 unsigned int pheight
= 768;
987 if (qdev
->client_monitors_config
) {
988 struct qxl_head
*head
;
989 head
= &qdev
->client_monitors_config
->heads
[output
->index
];
991 pwidth
= head
->width
;
993 pheight
= head
->height
;
996 ret
+= drm_add_modes_noedid(connector
, 8192, 8192);
997 ret
+= qxl_add_extra_modes(connector
);
998 ret
+= qxl_add_monitors_config_modes(connector
);
999 drm_set_preferred_mode(connector
, pwidth
, pheight
);
1003 static enum drm_mode_status
qxl_conn_mode_valid(struct drm_connector
*connector
,
1004 struct drm_display_mode
*mode
)
1006 struct drm_device
*ddev
= connector
->dev
;
1007 struct qxl_device
*qdev
= ddev
->dev_private
;
1009 if (qxl_check_mode(qdev
, mode
->hdisplay
, mode
->vdisplay
) != 0)
1015 static struct drm_encoder
*qxl_best_encoder(struct drm_connector
*connector
)
1017 struct qxl_output
*qxl_output
=
1018 drm_connector_to_qxl_output(connector
);
1021 return &qxl_output
->enc
;
1024 static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs
= {
1027 static const struct drm_connector_helper_funcs qxl_connector_helper_funcs
= {
1028 .get_modes
= qxl_conn_get_modes
,
1029 .mode_valid
= qxl_conn_mode_valid
,
1030 .best_encoder
= qxl_best_encoder
,
1033 static enum drm_connector_status
qxl_conn_detect(
1034 struct drm_connector
*connector
,
1037 struct qxl_output
*output
=
1038 drm_connector_to_qxl_output(connector
);
1039 struct drm_device
*ddev
= connector
->dev
;
1040 struct qxl_device
*qdev
= ddev
->dev_private
;
1041 bool connected
= false;
1043 /* The first monitor is always connected */
1044 if (!qdev
->client_monitors_config
) {
1045 if (output
->index
== 0)
1048 connected
= qdev
->client_monitors_config
->count
> output
->index
&&
1049 qxl_head_enabled(&qdev
->client_monitors_config
->heads
[output
->index
]);
1051 DRM_DEBUG("#%d connected: %d\n", output
->index
, connected
);
1053 return connected
? connector_status_connected
1054 : connector_status_disconnected
;
1057 static void qxl_conn_destroy(struct drm_connector
*connector
)
1059 struct qxl_output
*qxl_output
=
1060 drm_connector_to_qxl_output(connector
);
1062 drm_connector_unregister(connector
);
1063 drm_connector_cleanup(connector
);
1067 static const struct drm_connector_funcs qxl_connector_funcs
= {
1068 .detect
= qxl_conn_detect
,
1069 .fill_modes
= drm_helper_probe_single_connector_modes
,
1070 .destroy
= qxl_conn_destroy
,
1071 .reset
= drm_atomic_helper_connector_reset
,
1072 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
1073 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
1076 static void qxl_enc_destroy(struct drm_encoder
*encoder
)
1078 drm_encoder_cleanup(encoder
);
1081 static const struct drm_encoder_funcs qxl_enc_funcs
= {
1082 .destroy
= qxl_enc_destroy
,
1085 static int qxl_mode_create_hotplug_mode_update_property(struct qxl_device
*qdev
)
1087 if (qdev
->hotplug_mode_update_property
)
1090 qdev
->hotplug_mode_update_property
=
1091 drm_property_create_range(&qdev
->ddev
, DRM_MODE_PROP_IMMUTABLE
,
1092 "hotplug_mode_update", 0, 1);
1097 static int qdev_output_init(struct drm_device
*dev
, int num_output
)
1099 struct qxl_device
*qdev
= dev
->dev_private
;
1100 struct qxl_output
*qxl_output
;
1101 struct drm_connector
*connector
;
1102 struct drm_encoder
*encoder
;
1104 qxl_output
= kzalloc(sizeof(struct qxl_output
), GFP_KERNEL
);
1108 qxl_output
->index
= num_output
;
1110 connector
= &qxl_output
->base
;
1111 encoder
= &qxl_output
->enc
;
1112 drm_connector_init(dev
, &qxl_output
->base
,
1113 &qxl_connector_funcs
, DRM_MODE_CONNECTOR_VIRTUAL
);
1115 drm_encoder_init(dev
, &qxl_output
->enc
, &qxl_enc_funcs
,
1116 DRM_MODE_ENCODER_VIRTUAL
, NULL
);
1118 /* we get HPD via client monitors config */
1119 connector
->polled
= DRM_CONNECTOR_POLL_HPD
;
1120 encoder
->possible_crtcs
= 1 << num_output
;
1121 drm_connector_attach_encoder(&qxl_output
->base
,
1123 drm_encoder_helper_add(encoder
, &qxl_enc_helper_funcs
);
1124 drm_connector_helper_add(connector
, &qxl_connector_helper_funcs
);
1126 drm_object_attach_property(&connector
->base
,
1127 qdev
->hotplug_mode_update_property
, 0);
1128 drm_object_attach_property(&connector
->base
,
1129 dev
->mode_config
.suggested_x_property
, 0);
1130 drm_object_attach_property(&connector
->base
,
1131 dev
->mode_config
.suggested_y_property
, 0);
1135 static struct drm_framebuffer
*
1136 qxl_user_framebuffer_create(struct drm_device
*dev
,
1137 struct drm_file
*file_priv
,
1138 const struct drm_mode_fb_cmd2
*mode_cmd
)
1140 return drm_gem_fb_create_with_funcs(dev
, file_priv
, mode_cmd
,
1144 static const struct drm_mode_config_funcs qxl_mode_funcs
= {
1145 .fb_create
= qxl_user_framebuffer_create
,
1146 .atomic_check
= drm_atomic_helper_check
,
1147 .atomic_commit
= drm_atomic_helper_commit
,
1150 int qxl_create_monitors_object(struct qxl_device
*qdev
)
1153 struct drm_gem_object
*gobj
;
1154 int monitors_config_size
= sizeof(struct qxl_monitors_config
) +
1155 qxl_num_crtc
* sizeof(struct qxl_head
);
1157 ret
= qxl_gem_object_create(qdev
, monitors_config_size
, 0,
1158 QXL_GEM_DOMAIN_VRAM
,
1159 false, false, NULL
, &gobj
);
1161 DRM_ERROR("%s: failed to create gem ret=%d\n", __func__
, ret
);
1164 qdev
->monitors_config_bo
= gem_to_qxl_bo(gobj
);
1166 ret
= qxl_bo_pin(qdev
->monitors_config_bo
);
1170 qxl_bo_kmap(qdev
->monitors_config_bo
, NULL
);
1172 qdev
->monitors_config
= qdev
->monitors_config_bo
->kptr
;
1173 qdev
->ram_header
->monitors_config
=
1174 qxl_bo_physical_address(qdev
, qdev
->monitors_config_bo
, 0);
1176 memset(qdev
->monitors_config
, 0, monitors_config_size
);
1177 qdev
->dumb_heads
= kcalloc(qxl_num_crtc
, sizeof(qdev
->dumb_heads
[0]),
1179 if (!qdev
->dumb_heads
) {
1180 qxl_destroy_monitors_object(qdev
);
1186 int qxl_destroy_monitors_object(struct qxl_device
*qdev
)
1190 qdev
->monitors_config
= NULL
;
1191 qdev
->ram_header
->monitors_config
= 0;
1193 qxl_bo_kunmap(qdev
->monitors_config_bo
);
1194 ret
= qxl_bo_unpin(qdev
->monitors_config_bo
);
1198 qxl_bo_unref(&qdev
->monitors_config_bo
);
1202 int qxl_modeset_init(struct qxl_device
*qdev
)
1207 drm_mode_config_init(&qdev
->ddev
);
1209 ret
= qxl_create_monitors_object(qdev
);
1213 qdev
->ddev
.mode_config
.funcs
= (void *)&qxl_mode_funcs
;
1215 /* modes will be validated against the framebuffer size */
1216 qdev
->ddev
.mode_config
.min_width
= 0;
1217 qdev
->ddev
.mode_config
.min_height
= 0;
1218 qdev
->ddev
.mode_config
.max_width
= 8192;
1219 qdev
->ddev
.mode_config
.max_height
= 8192;
1221 qdev
->ddev
.mode_config
.fb_base
= qdev
->vram_base
;
1223 drm_mode_create_suggested_offset_properties(&qdev
->ddev
);
1224 qxl_mode_create_hotplug_mode_update_property(qdev
);
1226 for (i
= 0 ; i
< qxl_num_crtc
; ++i
) {
1227 qdev_crtc_init(&qdev
->ddev
, i
);
1228 qdev_output_init(&qdev
->ddev
, i
);
1231 qxl_display_read_client_monitors_config(qdev
);
1233 drm_mode_config_reset(&qdev
->ddev
);
1237 void qxl_modeset_fini(struct qxl_device
*qdev
)
1239 qxl_destroy_monitors_object(qdev
);
1240 drm_mode_config_cleanup(&qdev
->ddev
);