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_simple_kms_helper.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
= to_qxl(dev
);
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
= to_qxl(dev
);
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
= to_qxl(dev
);
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 qxl_crtc_update_monitors_config(crtc
, "flush");
378 static void qxl_crtc_destroy(struct drm_crtc
*crtc
)
380 struct qxl_crtc
*qxl_crtc
= to_qxl_crtc(crtc
);
382 qxl_bo_unref(&qxl_crtc
->cursor_bo
);
383 drm_crtc_cleanup(crtc
);
387 static const struct drm_crtc_funcs qxl_crtc_funcs
= {
388 .set_config
= drm_atomic_helper_set_config
,
389 .destroy
= qxl_crtc_destroy
,
390 .page_flip
= drm_atomic_helper_page_flip
,
391 .reset
= drm_atomic_helper_crtc_reset
,
392 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
393 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
396 static int qxl_framebuffer_surface_dirty(struct drm_framebuffer
*fb
,
397 struct drm_file
*file_priv
,
398 unsigned int flags
, unsigned int color
,
399 struct drm_clip_rect
*clips
,
400 unsigned int num_clips
)
402 /* TODO: vmwgfx where this was cribbed from had locking. Why? */
403 struct qxl_device
*qdev
= to_qxl(fb
->dev
);
404 struct drm_clip_rect norect
;
409 drm_modeset_lock_all(fb
->dev
);
411 qobj
= gem_to_qxl_bo(fb
->obj
[0]);
412 /* if we aren't primary surface ignore this */
413 is_primary
= qobj
->shadow
? qobj
->shadow
->is_primary
: qobj
->is_primary
;
415 drm_modeset_unlock_all(fb
->dev
);
422 norect
.x1
= norect
.y1
= 0;
423 norect
.x2
= fb
->width
;
424 norect
.y2
= fb
->height
;
425 } else if (flags
& DRM_MODE_FB_DIRTY_ANNOTATE_COPY
) {
427 inc
= 2; /* skip source rects */
430 qxl_draw_dirty_fb(qdev
, fb
, qobj
, flags
, color
,
431 clips
, num_clips
, inc
, 0);
433 drm_modeset_unlock_all(fb
->dev
);
438 static const struct drm_framebuffer_funcs qxl_fb_funcs
= {
439 .destroy
= drm_gem_fb_destroy
,
440 .dirty
= qxl_framebuffer_surface_dirty
,
441 .create_handle
= drm_gem_fb_create_handle
,
444 static void qxl_crtc_atomic_enable(struct drm_crtc
*crtc
,
445 struct drm_crtc_state
*old_state
)
447 qxl_crtc_update_monitors_config(crtc
, "enable");
450 static void qxl_crtc_atomic_disable(struct drm_crtc
*crtc
,
451 struct drm_crtc_state
*old_state
)
453 qxl_crtc_update_monitors_config(crtc
, "disable");
456 static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs
= {
457 .atomic_flush
= qxl_crtc_atomic_flush
,
458 .atomic_enable
= qxl_crtc_atomic_enable
,
459 .atomic_disable
= qxl_crtc_atomic_disable
,
462 static int qxl_primary_atomic_check(struct drm_plane
*plane
,
463 struct drm_plane_state
*state
)
465 struct qxl_device
*qdev
= to_qxl(plane
->dev
);
468 if (!state
->crtc
|| !state
->fb
)
471 bo
= gem_to_qxl_bo(state
->fb
->obj
[0]);
473 return qxl_check_framebuffer(qdev
, bo
);
476 static int qxl_primary_apply_cursor(struct drm_plane
*plane
)
478 struct drm_device
*dev
= plane
->dev
;
479 struct qxl_device
*qdev
= to_qxl(dev
);
480 struct drm_framebuffer
*fb
= plane
->state
->fb
;
481 struct qxl_crtc
*qcrtc
= to_qxl_crtc(plane
->state
->crtc
);
482 struct qxl_cursor_cmd
*cmd
;
483 struct qxl_release
*release
;
486 if (!qcrtc
->cursor_bo
)
489 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
490 QXL_RELEASE_CURSOR_CMD
,
495 ret
= qxl_release_list_add(release
, qcrtc
->cursor_bo
);
497 goto out_free_release
;
499 ret
= qxl_release_reserve_list(release
, false);
501 goto out_free_release
;
503 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
504 cmd
->type
= QXL_CURSOR_SET
;
505 cmd
->u
.set
.position
.x
= plane
->state
->crtc_x
+ fb
->hot_x
;
506 cmd
->u
.set
.position
.y
= plane
->state
->crtc_y
+ fb
->hot_y
;
508 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
, qcrtc
->cursor_bo
, 0);
510 cmd
->u
.set
.visible
= 1;
511 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
513 qxl_release_fence_buffer_objects(release
);
514 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
519 qxl_release_free(qdev
, release
);
523 static void qxl_primary_atomic_update(struct drm_plane
*plane
,
524 struct drm_plane_state
*old_state
)
526 struct qxl_device
*qdev
= to_qxl(plane
->dev
);
527 struct qxl_bo
*bo
= gem_to_qxl_bo(plane
->state
->fb
->obj
[0]);
528 struct qxl_bo
*primary
;
529 struct drm_clip_rect norect
= {
532 .x2
= plane
->state
->fb
->width
,
533 .y2
= plane
->state
->fb
->height
535 uint32_t dumb_shadow_offset
= 0;
537 primary
= bo
->shadow
? bo
->shadow
: bo
;
539 if (!primary
->is_primary
) {
540 if (qdev
->primary_bo
)
541 qxl_io_destroy_primary(qdev
);
542 qxl_io_create_primary(qdev
, primary
);
543 qxl_primary_apply_cursor(plane
);
548 qdev
->dumb_heads
[plane
->state
->crtc
->index
].x
;
550 qxl_draw_dirty_fb(qdev
, plane
->state
->fb
, bo
, 0, 0, &norect
, 1, 1,
554 static void qxl_primary_atomic_disable(struct drm_plane
*plane
,
555 struct drm_plane_state
*old_state
)
557 struct qxl_device
*qdev
= to_qxl(plane
->dev
);
560 struct qxl_bo
*bo
= gem_to_qxl_bo(old_state
->fb
->obj
[0]);
562 if (bo
->is_primary
) {
563 qxl_io_destroy_primary(qdev
);
564 bo
->is_primary
= false;
569 static void qxl_cursor_atomic_update(struct drm_plane
*plane
,
570 struct drm_plane_state
*old_state
)
572 struct drm_device
*dev
= plane
->dev
;
573 struct qxl_device
*qdev
= to_qxl(dev
);
574 struct drm_framebuffer
*fb
= plane
->state
->fb
;
575 struct qxl_crtc
*qcrtc
= to_qxl_crtc(plane
->state
->crtc
);
576 struct qxl_release
*release
;
577 struct qxl_cursor_cmd
*cmd
;
578 struct qxl_cursor
*cursor
;
579 struct drm_gem_object
*obj
;
580 struct qxl_bo
*cursor_bo
= NULL
, *user_bo
= NULL
, *old_cursor_bo
= NULL
;
585 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
586 QXL_RELEASE_CURSOR_CMD
,
591 if (fb
!= old_state
->fb
) {
593 user_bo
= gem_to_qxl_bo(obj
);
595 /* pinning is done in the prepare/cleanup framevbuffer */
596 ret
= qxl_bo_kmap(user_bo
, &user_ptr
);
598 goto out_free_release
;
600 ret
= qxl_alloc_bo_reserved(qdev
, release
,
601 sizeof(struct qxl_cursor
) + size
,
606 ret
= qxl_bo_pin(cursor_bo
);
610 ret
= qxl_release_reserve_list(release
, true);
614 ret
= qxl_bo_kmap(cursor_bo
, (void **)&cursor
);
618 cursor
->header
.unique
= 0;
619 cursor
->header
.type
= SPICE_CURSOR_TYPE_ALPHA
;
620 cursor
->header
.width
= 64;
621 cursor
->header
.height
= 64;
622 cursor
->header
.hot_spot_x
= fb
->hot_x
;
623 cursor
->header
.hot_spot_y
= fb
->hot_y
;
624 cursor
->data_size
= size
;
625 cursor
->chunk
.next_chunk
= 0;
626 cursor
->chunk
.prev_chunk
= 0;
627 cursor
->chunk
.data_size
= size
;
628 memcpy(cursor
->chunk
.data
, user_ptr
, size
);
629 qxl_bo_kunmap(cursor_bo
);
630 qxl_bo_kunmap(user_bo
);
632 cmd
= (struct qxl_cursor_cmd
*) qxl_release_map(qdev
, release
);
633 cmd
->u
.set
.visible
= 1;
634 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
,
636 cmd
->type
= QXL_CURSOR_SET
;
638 old_cursor_bo
= qcrtc
->cursor_bo
;
639 qcrtc
->cursor_bo
= cursor_bo
;
643 ret
= qxl_release_reserve_list(release
, true);
645 goto out_free_release
;
647 cmd
= (struct qxl_cursor_cmd
*) qxl_release_map(qdev
, release
);
648 cmd
->type
= QXL_CURSOR_MOVE
;
651 cmd
->u
.position
.x
= plane
->state
->crtc_x
+ fb
->hot_x
;
652 cmd
->u
.position
.y
= plane
->state
->crtc_y
+ fb
->hot_y
;
654 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
655 qxl_release_fence_buffer_objects(release
);
656 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
658 if (old_cursor_bo
!= NULL
)
659 qxl_bo_unpin(old_cursor_bo
);
660 qxl_bo_unref(&old_cursor_bo
);
661 qxl_bo_unref(&cursor_bo
);
666 qxl_release_backoff_reserve_list(release
);
668 qxl_bo_unpin(cursor_bo
);
670 qxl_bo_unref(&cursor_bo
);
672 qxl_bo_kunmap(user_bo
);
674 qxl_release_free(qdev
, release
);
679 static void qxl_cursor_atomic_disable(struct drm_plane
*plane
,
680 struct drm_plane_state
*old_state
)
682 struct qxl_device
*qdev
= to_qxl(plane
->dev
);
683 struct qxl_release
*release
;
684 struct qxl_cursor_cmd
*cmd
;
687 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
688 QXL_RELEASE_CURSOR_CMD
,
693 ret
= qxl_release_reserve_list(release
, true);
695 qxl_release_free(qdev
, release
);
699 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
700 cmd
->type
= QXL_CURSOR_HIDE
;
701 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
703 qxl_release_fence_buffer_objects(release
);
704 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
707 static void qxl_update_dumb_head(struct qxl_device
*qdev
,
708 int index
, struct qxl_bo
*bo
)
710 uint32_t width
, height
;
712 if (index
>= qdev
->monitors_config
->max_allowed
)
715 if (bo
&& bo
->is_dumb
) {
716 width
= bo
->surf
.width
;
717 height
= bo
->surf
.height
;
723 if (qdev
->dumb_heads
[index
].width
== width
&&
724 qdev
->dumb_heads
[index
].height
== height
)
727 DRM_DEBUG("#%d: %dx%d -> %dx%d\n", index
,
728 qdev
->dumb_heads
[index
].width
,
729 qdev
->dumb_heads
[index
].height
,
731 qdev
->dumb_heads
[index
].width
= width
;
732 qdev
->dumb_heads
[index
].height
= height
;
735 static void qxl_calc_dumb_shadow(struct qxl_device
*qdev
,
736 struct qxl_surface
*surf
)
738 struct qxl_head
*head
;
741 memset(surf
, 0, sizeof(*surf
));
742 for (i
= 0; i
< qdev
->monitors_config
->max_allowed
; i
++) {
743 head
= qdev
->dumb_heads
+ i
;
744 head
->x
= surf
->width
;
745 surf
->width
+= head
->width
;
746 if (surf
->height
< head
->height
)
747 surf
->height
= head
->height
;
749 if (surf
->width
< 64)
751 if (surf
->height
< 64)
753 surf
->format
= SPICE_SURFACE_FMT_32_xRGB
;
754 surf
->stride
= surf
->width
* 4;
756 if (!qdev
->dumb_shadow_bo
||
757 qdev
->dumb_shadow_bo
->surf
.width
!= surf
->width
||
758 qdev
->dumb_shadow_bo
->surf
.height
!= surf
->height
)
759 DRM_DEBUG("%dx%d\n", surf
->width
, surf
->height
);
762 static int qxl_plane_prepare_fb(struct drm_plane
*plane
,
763 struct drm_plane_state
*new_state
)
765 struct qxl_device
*qdev
= to_qxl(plane
->dev
);
766 struct drm_gem_object
*obj
;
767 struct qxl_bo
*user_bo
;
768 struct qxl_surface surf
;
774 obj
= new_state
->fb
->obj
[0];
775 user_bo
= gem_to_qxl_bo(obj
);
777 if (plane
->type
== DRM_PLANE_TYPE_PRIMARY
&&
779 qxl_update_dumb_head(qdev
, new_state
->crtc
->index
,
781 qxl_calc_dumb_shadow(qdev
, &surf
);
782 if (!qdev
->dumb_shadow_bo
||
783 qdev
->dumb_shadow_bo
->surf
.width
!= surf
.width
||
784 qdev
->dumb_shadow_bo
->surf
.height
!= surf
.height
) {
785 if (qdev
->dumb_shadow_bo
) {
786 drm_gem_object_put_unlocked
787 (&qdev
->dumb_shadow_bo
->tbo
.base
);
788 qdev
->dumb_shadow_bo
= NULL
;
790 qxl_bo_create(qdev
, surf
.height
* surf
.stride
,
791 true, true, QXL_GEM_DOMAIN_SURFACE
, &surf
,
792 &qdev
->dumb_shadow_bo
);
794 if (user_bo
->shadow
!= qdev
->dumb_shadow_bo
) {
795 if (user_bo
->shadow
) {
796 drm_gem_object_put_unlocked
797 (&user_bo
->shadow
->tbo
.base
);
798 user_bo
->shadow
= NULL
;
800 drm_gem_object_get(&qdev
->dumb_shadow_bo
->tbo
.base
);
801 user_bo
->shadow
= qdev
->dumb_shadow_bo
;
805 ret
= qxl_bo_pin(user_bo
);
812 static void qxl_plane_cleanup_fb(struct drm_plane
*plane
,
813 struct drm_plane_state
*old_state
)
815 struct drm_gem_object
*obj
;
816 struct qxl_bo
*user_bo
;
818 if (!old_state
->fb
) {
820 * we never executed prepare_fb, so there's nothing to
826 obj
= old_state
->fb
->obj
[0];
827 user_bo
= gem_to_qxl_bo(obj
);
828 qxl_bo_unpin(user_bo
);
830 if (old_state
->fb
!= plane
->state
->fb
&& user_bo
->shadow
) {
831 drm_gem_object_put_unlocked(&user_bo
->shadow
->tbo
.base
);
832 user_bo
->shadow
= NULL
;
836 static const uint32_t qxl_cursor_plane_formats
[] = {
840 static const struct drm_plane_helper_funcs qxl_cursor_helper_funcs
= {
841 .atomic_update
= qxl_cursor_atomic_update
,
842 .atomic_disable
= qxl_cursor_atomic_disable
,
843 .prepare_fb
= qxl_plane_prepare_fb
,
844 .cleanup_fb
= qxl_plane_cleanup_fb
,
847 static const struct drm_plane_funcs qxl_cursor_plane_funcs
= {
848 .update_plane
= drm_atomic_helper_update_plane
,
849 .disable_plane
= drm_atomic_helper_disable_plane
,
850 .destroy
= drm_primary_helper_destroy
,
851 .reset
= drm_atomic_helper_plane_reset
,
852 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
853 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
856 static const uint32_t qxl_primary_plane_formats
[] = {
861 static const struct drm_plane_helper_funcs primary_helper_funcs
= {
862 .atomic_check
= qxl_primary_atomic_check
,
863 .atomic_update
= qxl_primary_atomic_update
,
864 .atomic_disable
= qxl_primary_atomic_disable
,
865 .prepare_fb
= qxl_plane_prepare_fb
,
866 .cleanup_fb
= qxl_plane_cleanup_fb
,
869 static const struct drm_plane_funcs qxl_primary_plane_funcs
= {
870 .update_plane
= drm_atomic_helper_update_plane
,
871 .disable_plane
= drm_atomic_helper_disable_plane
,
872 .destroy
= drm_primary_helper_destroy
,
873 .reset
= drm_atomic_helper_plane_reset
,
874 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
875 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
878 static struct drm_plane
*qxl_create_plane(struct qxl_device
*qdev
,
879 unsigned int possible_crtcs
,
880 enum drm_plane_type type
)
882 const struct drm_plane_helper_funcs
*helper_funcs
= NULL
;
883 struct drm_plane
*plane
;
884 const struct drm_plane_funcs
*funcs
;
885 const uint32_t *formats
;
889 if (type
== DRM_PLANE_TYPE_PRIMARY
) {
890 funcs
= &qxl_primary_plane_funcs
;
891 formats
= qxl_primary_plane_formats
;
892 num_formats
= ARRAY_SIZE(qxl_primary_plane_formats
);
893 helper_funcs
= &primary_helper_funcs
;
894 } else if (type
== DRM_PLANE_TYPE_CURSOR
) {
895 funcs
= &qxl_cursor_plane_funcs
;
896 formats
= qxl_cursor_plane_formats
;
897 helper_funcs
= &qxl_cursor_helper_funcs
;
898 num_formats
= ARRAY_SIZE(qxl_cursor_plane_formats
);
900 return ERR_PTR(-EINVAL
);
903 plane
= kzalloc(sizeof(*plane
), GFP_KERNEL
);
905 return ERR_PTR(-ENOMEM
);
907 err
= drm_universal_plane_init(&qdev
->ddev
, plane
, possible_crtcs
,
908 funcs
, formats
, num_formats
,
913 drm_plane_helper_add(plane
, helper_funcs
);
919 return ERR_PTR(-EINVAL
);
922 static int qdev_crtc_init(struct drm_device
*dev
, int crtc_id
)
924 struct qxl_crtc
*qxl_crtc
;
925 struct drm_plane
*primary
, *cursor
;
926 struct qxl_device
*qdev
= to_qxl(dev
);
929 qxl_crtc
= kzalloc(sizeof(struct qxl_crtc
), GFP_KERNEL
);
933 primary
= qxl_create_plane(qdev
, 1 << crtc_id
, DRM_PLANE_TYPE_PRIMARY
);
934 if (IS_ERR(primary
)) {
939 cursor
= qxl_create_plane(qdev
, 1 << crtc_id
, DRM_PLANE_TYPE_CURSOR
);
940 if (IS_ERR(cursor
)) {
945 r
= drm_crtc_init_with_planes(dev
, &qxl_crtc
->base
, primary
, cursor
,
946 &qxl_crtc_funcs
, NULL
);
950 qxl_crtc
->index
= crtc_id
;
951 drm_crtc_helper_add(&qxl_crtc
->base
, &qxl_crtc_helper_funcs
);
955 drm_plane_cleanup(cursor
);
958 drm_plane_cleanup(primary
);
965 static int qxl_conn_get_modes(struct drm_connector
*connector
)
967 struct drm_device
*dev
= connector
->dev
;
968 struct qxl_device
*qdev
= to_qxl(dev
);
969 struct qxl_output
*output
= drm_connector_to_qxl_output(connector
);
970 unsigned int pwidth
= 1024;
971 unsigned int pheight
= 768;
974 if (qdev
->client_monitors_config
) {
975 struct qxl_head
*head
;
976 head
= &qdev
->client_monitors_config
->heads
[output
->index
];
978 pwidth
= head
->width
;
980 pheight
= head
->height
;
983 ret
+= drm_add_modes_noedid(connector
, 8192, 8192);
984 ret
+= qxl_add_extra_modes(connector
);
985 ret
+= qxl_add_monitors_config_modes(connector
);
986 drm_set_preferred_mode(connector
, pwidth
, pheight
);
990 static enum drm_mode_status
qxl_conn_mode_valid(struct drm_connector
*connector
,
991 struct drm_display_mode
*mode
)
993 struct drm_device
*ddev
= connector
->dev
;
994 struct qxl_device
*qdev
= to_qxl(ddev
);
996 if (qxl_check_mode(qdev
, mode
->hdisplay
, mode
->vdisplay
) != 0)
1002 static struct drm_encoder
*qxl_best_encoder(struct drm_connector
*connector
)
1004 struct qxl_output
*qxl_output
=
1005 drm_connector_to_qxl_output(connector
);
1008 return &qxl_output
->enc
;
1011 static const struct drm_connector_helper_funcs qxl_connector_helper_funcs
= {
1012 .get_modes
= qxl_conn_get_modes
,
1013 .mode_valid
= qxl_conn_mode_valid
,
1014 .best_encoder
= qxl_best_encoder
,
1017 static enum drm_connector_status
qxl_conn_detect(
1018 struct drm_connector
*connector
,
1021 struct qxl_output
*output
=
1022 drm_connector_to_qxl_output(connector
);
1023 struct drm_device
*ddev
= connector
->dev
;
1024 struct qxl_device
*qdev
= to_qxl(ddev
);
1025 bool connected
= false;
1027 /* The first monitor is always connected */
1028 if (!qdev
->client_monitors_config
) {
1029 if (output
->index
== 0)
1032 connected
= qdev
->client_monitors_config
->count
> output
->index
&&
1033 qxl_head_enabled(&qdev
->client_monitors_config
->heads
[output
->index
]);
1035 DRM_DEBUG("#%d connected: %d\n", output
->index
, connected
);
1037 return connected
? connector_status_connected
1038 : connector_status_disconnected
;
1041 static void qxl_conn_destroy(struct drm_connector
*connector
)
1043 struct qxl_output
*qxl_output
=
1044 drm_connector_to_qxl_output(connector
);
1046 drm_connector_unregister(connector
);
1047 drm_connector_cleanup(connector
);
1051 static const struct drm_connector_funcs qxl_connector_funcs
= {
1052 .detect
= qxl_conn_detect
,
1053 .fill_modes
= drm_helper_probe_single_connector_modes
,
1054 .destroy
= qxl_conn_destroy
,
1055 .reset
= drm_atomic_helper_connector_reset
,
1056 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
1057 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
1060 static int qxl_mode_create_hotplug_mode_update_property(struct qxl_device
*qdev
)
1062 if (qdev
->hotplug_mode_update_property
)
1065 qdev
->hotplug_mode_update_property
=
1066 drm_property_create_range(&qdev
->ddev
, DRM_MODE_PROP_IMMUTABLE
,
1067 "hotplug_mode_update", 0, 1);
1072 static int qdev_output_init(struct drm_device
*dev
, int num_output
)
1074 struct qxl_device
*qdev
= to_qxl(dev
);
1075 struct qxl_output
*qxl_output
;
1076 struct drm_connector
*connector
;
1077 struct drm_encoder
*encoder
;
1080 qxl_output
= kzalloc(sizeof(struct qxl_output
), GFP_KERNEL
);
1084 qxl_output
->index
= num_output
;
1086 connector
= &qxl_output
->base
;
1087 encoder
= &qxl_output
->enc
;
1088 drm_connector_init(dev
, &qxl_output
->base
,
1089 &qxl_connector_funcs
, DRM_MODE_CONNECTOR_VIRTUAL
);
1091 ret
= drm_simple_encoder_init(dev
, &qxl_output
->enc
,
1092 DRM_MODE_ENCODER_VIRTUAL
);
1094 drm_err(dev
, "drm_simple_encoder_init() failed, error %d\n",
1096 goto err_drm_connector_cleanup
;
1099 /* we get HPD via client monitors config */
1100 connector
->polled
= DRM_CONNECTOR_POLL_HPD
;
1101 encoder
->possible_crtcs
= 1 << num_output
;
1102 drm_connector_attach_encoder(&qxl_output
->base
,
1104 drm_connector_helper_add(connector
, &qxl_connector_helper_funcs
);
1106 drm_object_attach_property(&connector
->base
,
1107 qdev
->hotplug_mode_update_property
, 0);
1108 drm_object_attach_property(&connector
->base
,
1109 dev
->mode_config
.suggested_x_property
, 0);
1110 drm_object_attach_property(&connector
->base
,
1111 dev
->mode_config
.suggested_y_property
, 0);
1114 err_drm_connector_cleanup
:
1115 drm_connector_cleanup(&qxl_output
->base
);
1120 static struct drm_framebuffer
*
1121 qxl_user_framebuffer_create(struct drm_device
*dev
,
1122 struct drm_file
*file_priv
,
1123 const struct drm_mode_fb_cmd2
*mode_cmd
)
1125 return drm_gem_fb_create_with_funcs(dev
, file_priv
, mode_cmd
,
1129 static const struct drm_mode_config_funcs qxl_mode_funcs
= {
1130 .fb_create
= qxl_user_framebuffer_create
,
1131 .atomic_check
= drm_atomic_helper_check
,
1132 .atomic_commit
= drm_atomic_helper_commit
,
1135 int qxl_create_monitors_object(struct qxl_device
*qdev
)
1138 struct drm_gem_object
*gobj
;
1139 int monitors_config_size
= sizeof(struct qxl_monitors_config
) +
1140 qxl_num_crtc
* sizeof(struct qxl_head
);
1142 ret
= qxl_gem_object_create(qdev
, monitors_config_size
, 0,
1143 QXL_GEM_DOMAIN_VRAM
,
1144 false, false, NULL
, &gobj
);
1146 DRM_ERROR("%s: failed to create gem ret=%d\n", __func__
, ret
);
1149 qdev
->monitors_config_bo
= gem_to_qxl_bo(gobj
);
1151 ret
= qxl_bo_pin(qdev
->monitors_config_bo
);
1155 qxl_bo_kmap(qdev
->monitors_config_bo
, NULL
);
1157 qdev
->monitors_config
= qdev
->monitors_config_bo
->kptr
;
1158 qdev
->ram_header
->monitors_config
=
1159 qxl_bo_physical_address(qdev
, qdev
->monitors_config_bo
, 0);
1161 memset(qdev
->monitors_config
, 0, monitors_config_size
);
1162 qdev
->dumb_heads
= kcalloc(qxl_num_crtc
, sizeof(qdev
->dumb_heads
[0]),
1164 if (!qdev
->dumb_heads
) {
1165 qxl_destroy_monitors_object(qdev
);
1171 int qxl_destroy_monitors_object(struct qxl_device
*qdev
)
1175 qdev
->monitors_config
= NULL
;
1176 qdev
->ram_header
->monitors_config
= 0;
1178 qxl_bo_kunmap(qdev
->monitors_config_bo
);
1179 ret
= qxl_bo_unpin(qdev
->monitors_config_bo
);
1183 qxl_bo_unref(&qdev
->monitors_config_bo
);
1187 int qxl_modeset_init(struct qxl_device
*qdev
)
1192 drm_mode_config_init(&qdev
->ddev
);
1194 ret
= qxl_create_monitors_object(qdev
);
1198 qdev
->ddev
.mode_config
.funcs
= (void *)&qxl_mode_funcs
;
1200 /* modes will be validated against the framebuffer size */
1201 qdev
->ddev
.mode_config
.min_width
= 0;
1202 qdev
->ddev
.mode_config
.min_height
= 0;
1203 qdev
->ddev
.mode_config
.max_width
= 8192;
1204 qdev
->ddev
.mode_config
.max_height
= 8192;
1206 qdev
->ddev
.mode_config
.fb_base
= qdev
->vram_base
;
1208 drm_mode_create_suggested_offset_properties(&qdev
->ddev
);
1209 qxl_mode_create_hotplug_mode_update_property(qdev
);
1211 for (i
= 0 ; i
< qxl_num_crtc
; ++i
) {
1212 qdev_crtc_init(&qdev
->ddev
, i
);
1213 qdev_output_init(&qdev
->ddev
, i
);
1216 qxl_display_read_client_monitors_config(qdev
);
1218 drm_mode_config_reset(&qdev
->ddev
);
1222 void qxl_modeset_fini(struct qxl_device
*qdev
)
1224 qxl_destroy_monitors_object(qdev
);
1225 drm_mode_config_cleanup(&qdev
->ddev
);