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 <drm/drm_crtc_helper.h>
28 #include <drm/drm_plane_helper.h>
29 #include <drm/drm_atomic_helper.h>
30 #include <drm/drm_atomic.h>
33 #include "qxl_object.h"
35 static bool qxl_head_enabled(struct qxl_head
*head
)
37 return head
->width
&& head
->height
;
40 static void qxl_alloc_client_monitors_config(struct qxl_device
*qdev
, unsigned count
)
42 if (qdev
->client_monitors_config
&&
43 count
> qdev
->client_monitors_config
->count
) {
44 kfree(qdev
->client_monitors_config
);
45 qdev
->client_monitors_config
= NULL
;
47 if (!qdev
->client_monitors_config
) {
48 qdev
->client_monitors_config
= kzalloc(
49 sizeof(struct qxl_monitors_config
) +
50 sizeof(struct qxl_head
) * count
, GFP_KERNEL
);
51 if (!qdev
->client_monitors_config
) {
53 "%s: allocation failure for %u heads\n",
58 qdev
->client_monitors_config
->count
= count
;
62 MONITORS_CONFIG_MODIFIED
,
63 MONITORS_CONFIG_UNCHANGED
,
64 MONITORS_CONFIG_BAD_CRC
,
67 static int qxl_display_copy_rom_client_monitors_config(struct qxl_device
*qdev
)
72 int status
= MONITORS_CONFIG_UNCHANGED
;
74 num_monitors
= qdev
->rom
->client_monitors_config
.count
;
75 crc
= crc32(0, (const uint8_t *)&qdev
->rom
->client_monitors_config
,
76 sizeof(qdev
->rom
->client_monitors_config
));
77 if (crc
!= qdev
->rom
->client_monitors_config_crc
) {
78 qxl_io_log(qdev
, "crc mismatch: have %X (%zd) != %X\n", crc
,
79 sizeof(qdev
->rom
->client_monitors_config
),
80 qdev
->rom
->client_monitors_config_crc
);
81 return MONITORS_CONFIG_BAD_CRC
;
84 DRM_DEBUG_KMS("no client monitors configured\n");
87 if (num_monitors
> qdev
->monitors_config
->max_allowed
) {
88 DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
89 qdev
->monitors_config
->max_allowed
, num_monitors
);
90 num_monitors
= qdev
->monitors_config
->max_allowed
;
92 num_monitors
= qdev
->rom
->client_monitors_config
.count
;
94 if (qdev
->client_monitors_config
95 && (num_monitors
!= qdev
->client_monitors_config
->count
)) {
96 status
= MONITORS_CONFIG_MODIFIED
;
98 qxl_alloc_client_monitors_config(qdev
, num_monitors
);
99 /* we copy max from the client but it isn't used */
100 qdev
->client_monitors_config
->max_allowed
=
101 qdev
->monitors_config
->max_allowed
;
102 for (i
= 0 ; i
< qdev
->client_monitors_config
->count
; ++i
) {
103 struct qxl_urect
*c_rect
=
104 &qdev
->rom
->client_monitors_config
.heads
[i
];
105 struct qxl_head
*client_head
=
106 &qdev
->client_monitors_config
->heads
[i
];
107 if (client_head
->x
!= c_rect
->left
) {
108 client_head
->x
= c_rect
->left
;
109 status
= MONITORS_CONFIG_MODIFIED
;
111 if (client_head
->y
!= c_rect
->top
) {
112 client_head
->y
= c_rect
->top
;
113 status
= MONITORS_CONFIG_MODIFIED
;
115 if (client_head
->width
!= c_rect
->right
- c_rect
->left
) {
116 client_head
->width
= c_rect
->right
- c_rect
->left
;
117 status
= MONITORS_CONFIG_MODIFIED
;
119 if (client_head
->height
!= c_rect
->bottom
- c_rect
->top
) {
120 client_head
->height
= c_rect
->bottom
- c_rect
->top
;
121 status
= MONITORS_CONFIG_MODIFIED
;
123 if (client_head
->surface_id
!= 0) {
124 client_head
->surface_id
= 0;
125 status
= MONITORS_CONFIG_MODIFIED
;
127 if (client_head
->id
!= i
) {
129 status
= MONITORS_CONFIG_MODIFIED
;
131 if (client_head
->flags
!= 0) {
132 client_head
->flags
= 0;
133 status
= MONITORS_CONFIG_MODIFIED
;
135 DRM_DEBUG_KMS("read %dx%d+%d+%d\n", client_head
->width
, client_head
->height
,
136 client_head
->x
, client_head
->y
);
142 static void qxl_update_offset_props(struct qxl_device
*qdev
)
144 struct drm_device
*dev
= &qdev
->ddev
;
145 struct drm_connector
*connector
;
146 struct qxl_output
*output
;
147 struct qxl_head
*head
;
149 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
150 output
= drm_connector_to_qxl_output(connector
);
152 head
= &qdev
->client_monitors_config
->heads
[output
->index
];
154 drm_object_property_set_value(&connector
->base
,
155 dev
->mode_config
.suggested_x_property
, head
->x
);
156 drm_object_property_set_value(&connector
->base
,
157 dev
->mode_config
.suggested_y_property
, head
->y
);
161 void qxl_display_read_client_monitors_config(struct qxl_device
*qdev
)
163 struct drm_device
*dev
= &qdev
->ddev
;
166 for (retries
= 0; retries
< 10; retries
++) {
167 status
= qxl_display_copy_rom_client_monitors_config(qdev
);
168 if (status
!= MONITORS_CONFIG_BAD_CRC
)
172 if (status
== MONITORS_CONFIG_BAD_CRC
) {
173 qxl_io_log(qdev
, "config: bad crc\n");
174 DRM_DEBUG_KMS("ignoring client monitors config: bad crc");
177 if (status
== MONITORS_CONFIG_UNCHANGED
) {
178 qxl_io_log(qdev
, "config: unchanged\n");
179 DRM_DEBUG_KMS("ignoring client monitors config: unchanged");
183 drm_modeset_lock_all(dev
);
184 qxl_update_offset_props(qdev
);
185 drm_modeset_unlock_all(dev
);
186 if (!drm_helper_hpd_irq_event(dev
)) {
187 /* notify that the monitor configuration changed, to
188 adjust at the arbitrary resolution */
189 drm_kms_helper_hotplug_event(dev
);
193 static int qxl_add_monitors_config_modes(struct drm_connector
*connector
,
197 struct drm_device
*dev
= connector
->dev
;
198 struct qxl_device
*qdev
= dev
->dev_private
;
199 struct qxl_output
*output
= drm_connector_to_qxl_output(connector
);
200 int h
= output
->index
;
201 struct drm_display_mode
*mode
= NULL
;
202 struct qxl_head
*head
;
204 if (!qdev
->monitors_config
)
206 if (h
>= qdev
->monitors_config
->max_allowed
)
208 if (!qdev
->client_monitors_config
)
210 if (h
>= qdev
->client_monitors_config
->count
)
213 head
= &qdev
->client_monitors_config
->heads
[h
];
214 DRM_DEBUG_KMS("head %d is %dx%d\n", h
, head
->width
, head
->height
);
216 mode
= drm_cvt_mode(dev
, head
->width
, head
->height
, 60, false, false,
218 mode
->type
|= DRM_MODE_TYPE_PREFERRED
;
219 mode
->hdisplay
= head
->width
;
220 mode
->vdisplay
= head
->height
;
221 drm_mode_set_name(mode
);
222 *pwidth
= head
->width
;
223 *pheight
= head
->height
;
224 drm_mode_probed_add(connector
, mode
);
225 /* remember the last custom size for mode validation */
226 qdev
->monitors_config_width
= mode
->hdisplay
;
227 qdev
->monitors_config_height
= mode
->vdisplay
;
231 static struct mode_size
{
254 static int qxl_add_common_modes(struct drm_connector
*connector
,
258 struct drm_device
*dev
= connector
->dev
;
259 struct drm_display_mode
*mode
= NULL
;
261 for (i
= 0; i
< ARRAY_SIZE(common_modes
); i
++) {
262 mode
= drm_cvt_mode(dev
, common_modes
[i
].w
, common_modes
[i
].h
,
263 60, false, false, false);
264 if (common_modes
[i
].w
== pwidth
&& common_modes
[i
].h
== pheight
)
265 mode
->type
|= DRM_MODE_TYPE_PREFERRED
;
266 drm_mode_probed_add(connector
, mode
);
271 static void qxl_crtc_atomic_flush(struct drm_crtc
*crtc
,
272 struct drm_crtc_state
*old_crtc_state
)
274 struct drm_device
*dev
= crtc
->dev
;
275 struct drm_pending_vblank_event
*event
;
278 if (crtc
->state
&& crtc
->state
->event
) {
279 event
= crtc
->state
->event
;
280 crtc
->state
->event
= NULL
;
282 spin_lock_irqsave(&dev
->event_lock
, flags
);
283 drm_crtc_send_vblank_event(crtc
, event
);
284 spin_unlock_irqrestore(&dev
->event_lock
, flags
);
288 static void qxl_crtc_destroy(struct drm_crtc
*crtc
)
290 struct qxl_crtc
*qxl_crtc
= to_qxl_crtc(crtc
);
292 qxl_bo_unref(&qxl_crtc
->cursor_bo
);
293 drm_crtc_cleanup(crtc
);
297 static const struct drm_crtc_funcs qxl_crtc_funcs
= {
298 .set_config
= drm_atomic_helper_set_config
,
299 .destroy
= qxl_crtc_destroy
,
300 .page_flip
= drm_atomic_helper_page_flip
,
301 .reset
= drm_atomic_helper_crtc_reset
,
302 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
303 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
306 void qxl_user_framebuffer_destroy(struct drm_framebuffer
*fb
)
308 struct qxl_framebuffer
*qxl_fb
= to_qxl_framebuffer(fb
);
309 struct qxl_bo
*bo
= gem_to_qxl_bo(qxl_fb
->obj
);
312 drm_gem_object_unreference_unlocked(qxl_fb
->obj
);
313 drm_framebuffer_cleanup(fb
);
317 static int qxl_framebuffer_surface_dirty(struct drm_framebuffer
*fb
,
318 struct drm_file
*file_priv
,
319 unsigned flags
, unsigned color
,
320 struct drm_clip_rect
*clips
,
323 /* TODO: vmwgfx where this was cribbed from had locking. Why? */
324 struct qxl_framebuffer
*qxl_fb
= to_qxl_framebuffer(fb
);
325 struct qxl_device
*qdev
= qxl_fb
->base
.dev
->dev_private
;
326 struct drm_clip_rect norect
;
330 drm_modeset_lock_all(fb
->dev
);
332 qobj
= gem_to_qxl_bo(qxl_fb
->obj
);
333 /* if we aren't primary surface ignore this */
334 if (!qobj
->is_primary
) {
335 drm_modeset_unlock_all(fb
->dev
);
342 norect
.x1
= norect
.y1
= 0;
343 norect
.x2
= fb
->width
;
344 norect
.y2
= fb
->height
;
345 } else if (flags
& DRM_MODE_FB_DIRTY_ANNOTATE_COPY
) {
347 inc
= 2; /* skip source rects */
350 qxl_draw_dirty_fb(qdev
, qxl_fb
, qobj
, flags
, color
,
351 clips
, num_clips
, inc
);
353 drm_modeset_unlock_all(fb
->dev
);
358 static const struct drm_framebuffer_funcs qxl_fb_funcs
= {
359 .destroy
= qxl_user_framebuffer_destroy
,
360 .dirty
= qxl_framebuffer_surface_dirty
,
362 * .create_handle = qxl_user_framebuffer_create_handle, */
366 qxl_framebuffer_init(struct drm_device
*dev
,
367 struct qxl_framebuffer
*qfb
,
368 const struct drm_mode_fb_cmd2
*mode_cmd
,
369 struct drm_gem_object
*obj
,
370 const struct drm_framebuffer_funcs
*funcs
)
375 drm_helper_mode_fill_fb_struct(dev
, &qfb
->base
, mode_cmd
);
376 ret
= drm_framebuffer_init(dev
, &qfb
->base
, funcs
);
384 static bool qxl_crtc_mode_fixup(struct drm_crtc
*crtc
,
385 const struct drm_display_mode
*mode
,
386 struct drm_display_mode
*adjusted_mode
)
388 struct drm_device
*dev
= crtc
->dev
;
389 struct qxl_device
*qdev
= dev
->dev_private
;
391 qxl_io_log(qdev
, "%s: (%d,%d) => (%d,%d)\n",
393 mode
->hdisplay
, mode
->vdisplay
,
394 adjusted_mode
->hdisplay
,
395 adjusted_mode
->vdisplay
);
400 qxl_send_monitors_config(struct qxl_device
*qdev
)
404 BUG_ON(!qdev
->ram_header
->monitors_config
);
406 if (qdev
->monitors_config
->count
== 0) {
407 qxl_io_log(qdev
, "%s: 0 monitors??\n", __func__
);
410 for (i
= 0 ; i
< qdev
->monitors_config
->count
; ++i
) {
411 struct qxl_head
*head
= &qdev
->monitors_config
->heads
[i
];
413 if (head
->y
> 8192 || head
->x
> 8192 ||
414 head
->width
> 8192 || head
->height
> 8192) {
415 DRM_ERROR("head %d wrong: %dx%d+%d+%d\n",
416 i
, head
->width
, head
->height
,
421 qxl_io_monitors_config(qdev
);
424 static void qxl_monitors_config_set(struct qxl_device
*qdev
,
426 unsigned x
, unsigned y
,
427 unsigned width
, unsigned height
,
430 DRM_DEBUG_KMS("%d:%dx%d+%d+%d\n", index
, width
, height
, x
, y
);
431 qdev
->monitors_config
->heads
[index
].x
= x
;
432 qdev
->monitors_config
->heads
[index
].y
= y
;
433 qdev
->monitors_config
->heads
[index
].width
= width
;
434 qdev
->monitors_config
->heads
[index
].height
= height
;
435 qdev
->monitors_config
->heads
[index
].surface_id
= surf_id
;
439 static void qxl_mode_set_nofb(struct drm_crtc
*crtc
)
441 struct qxl_device
*qdev
= crtc
->dev
->dev_private
;
442 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
443 struct drm_display_mode
*mode
= &crtc
->mode
;
445 DRM_DEBUG("Mode set (%d,%d)\n",
446 mode
->hdisplay
, mode
->vdisplay
);
448 qxl_monitors_config_set(qdev
, qcrtc
->index
, 0, 0,
449 mode
->hdisplay
, mode
->vdisplay
, 0);
453 static void qxl_crtc_atomic_enable(struct drm_crtc
*crtc
,
454 struct drm_crtc_state
*old_state
)
459 static void qxl_crtc_atomic_disable(struct drm_crtc
*crtc
,
460 struct drm_crtc_state
*old_state
)
462 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
463 struct qxl_device
*qdev
= crtc
->dev
->dev_private
;
465 qxl_monitors_config_set(qdev
, qcrtc
->index
, 0, 0, 0, 0, 0);
467 qxl_send_monitors_config(qdev
);
470 static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs
= {
471 .mode_fixup
= qxl_crtc_mode_fixup
,
472 .mode_set_nofb
= qxl_mode_set_nofb
,
473 .atomic_flush
= qxl_crtc_atomic_flush
,
474 .atomic_enable
= qxl_crtc_atomic_enable
,
475 .atomic_disable
= qxl_crtc_atomic_disable
,
478 static int qxl_primary_atomic_check(struct drm_plane
*plane
,
479 struct drm_plane_state
*state
)
481 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
482 struct qxl_framebuffer
*qfb
;
485 if (!state
->crtc
|| !state
->fb
)
488 qfb
= to_qxl_framebuffer(state
->fb
);
489 bo
= gem_to_qxl_bo(qfb
->obj
);
491 if (bo
->surf
.stride
* bo
->surf
.height
> qdev
->vram_size
) {
492 DRM_ERROR("Mode doesn't fit in vram size (vgamem)");
499 static int qxl_primary_apply_cursor(struct drm_plane
*plane
)
501 struct drm_device
*dev
= plane
->dev
;
502 struct qxl_device
*qdev
= dev
->dev_private
;
503 struct drm_framebuffer
*fb
= plane
->state
->fb
;
504 struct qxl_crtc
*qcrtc
= to_qxl_crtc(plane
->state
->crtc
);
505 struct qxl_cursor_cmd
*cmd
;
506 struct qxl_release
*release
;
509 if (!qcrtc
->cursor_bo
)
512 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
513 QXL_RELEASE_CURSOR_CMD
,
518 ret
= qxl_release_list_add(release
, qcrtc
->cursor_bo
);
520 goto out_free_release
;
522 ret
= qxl_release_reserve_list(release
, false);
524 goto out_free_release
;
526 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
527 cmd
->type
= QXL_CURSOR_SET
;
528 cmd
->u
.set
.position
.x
= plane
->state
->crtc_x
+ fb
->hot_x
;
529 cmd
->u
.set
.position
.y
= plane
->state
->crtc_y
+ fb
->hot_y
;
531 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
, qcrtc
->cursor_bo
, 0);
533 cmd
->u
.set
.visible
= 1;
534 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
536 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
537 qxl_release_fence_buffer_objects(release
);
542 qxl_release_free(qdev
, release
);
546 static void qxl_primary_atomic_update(struct drm_plane
*plane
,
547 struct drm_plane_state
*old_state
)
549 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
550 struct qxl_framebuffer
*qfb
=
551 to_qxl_framebuffer(plane
->state
->fb
);
552 struct qxl_framebuffer
*qfb_old
;
553 struct qxl_bo
*bo
= gem_to_qxl_bo(qfb
->obj
);
554 struct qxl_bo
*bo_old
;
555 struct drm_clip_rect norect
= {
558 .x2
= qfb
->base
.width
,
559 .y2
= qfb
->base
.height
562 bool same_shadow
= false;
565 qfb_old
= to_qxl_framebuffer(old_state
->fb
);
566 bo_old
= gem_to_qxl_bo(qfb_old
->obj
);
574 if (bo_old
&& bo_old
->shadow
&& bo
->shadow
&&
575 bo_old
->shadow
== bo
->shadow
) {
579 if (bo_old
&& bo_old
->is_primary
) {
581 qxl_io_destroy_primary(qdev
);
582 bo_old
->is_primary
= false;
584 ret
= qxl_primary_apply_cursor(plane
);
587 "could not set cursor after creating primary");
590 if (!bo
->is_primary
) {
592 qxl_io_create_primary(qdev
, 0, bo
);
593 bo
->is_primary
= true;
596 qxl_draw_dirty_fb(qdev
, qfb
, bo
, 0, 0, &norect
, 1, 1);
599 static void qxl_primary_atomic_disable(struct drm_plane
*plane
,
600 struct drm_plane_state
*old_state
)
602 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
605 struct qxl_framebuffer
*qfb
=
606 to_qxl_framebuffer(old_state
->fb
);
607 struct qxl_bo
*bo
= gem_to_qxl_bo(qfb
->obj
);
609 if (bo
->is_primary
) {
610 qxl_io_destroy_primary(qdev
);
611 bo
->is_primary
= false;
616 static int qxl_plane_atomic_check(struct drm_plane
*plane
,
617 struct drm_plane_state
*state
)
622 static void qxl_cursor_atomic_update(struct drm_plane
*plane
,
623 struct drm_plane_state
*old_state
)
625 struct drm_device
*dev
= plane
->dev
;
626 struct qxl_device
*qdev
= dev
->dev_private
;
627 struct drm_framebuffer
*fb
= plane
->state
->fb
;
628 struct qxl_crtc
*qcrtc
= to_qxl_crtc(plane
->state
->crtc
);
629 struct qxl_release
*release
;
630 struct qxl_cursor_cmd
*cmd
;
631 struct qxl_cursor
*cursor
;
632 struct drm_gem_object
*obj
;
633 struct qxl_bo
*cursor_bo
= NULL
, *user_bo
= NULL
;
638 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
639 QXL_RELEASE_CURSOR_CMD
,
644 if (fb
!= old_state
->fb
) {
645 obj
= to_qxl_framebuffer(fb
)->obj
;
646 user_bo
= gem_to_qxl_bo(obj
);
648 /* pinning is done in the prepare/cleanup framevbuffer */
649 ret
= qxl_bo_kmap(user_bo
, &user_ptr
);
651 goto out_free_release
;
653 ret
= qxl_alloc_bo_reserved(qdev
, release
,
654 sizeof(struct qxl_cursor
) + size
,
659 ret
= qxl_release_reserve_list(release
, true);
663 ret
= qxl_bo_kmap(cursor_bo
, (void **)&cursor
);
667 cursor
->header
.unique
= 0;
668 cursor
->header
.type
= SPICE_CURSOR_TYPE_ALPHA
;
669 cursor
->header
.width
= 64;
670 cursor
->header
.height
= 64;
671 cursor
->header
.hot_spot_x
= fb
->hot_x
;
672 cursor
->header
.hot_spot_y
= fb
->hot_y
;
673 cursor
->data_size
= size
;
674 cursor
->chunk
.next_chunk
= 0;
675 cursor
->chunk
.prev_chunk
= 0;
676 cursor
->chunk
.data_size
= size
;
677 memcpy(cursor
->chunk
.data
, user_ptr
, size
);
678 qxl_bo_kunmap(cursor_bo
);
679 qxl_bo_kunmap(user_bo
);
681 cmd
= (struct qxl_cursor_cmd
*) qxl_release_map(qdev
, release
);
682 cmd
->u
.set
.visible
= 1;
683 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
,
685 cmd
->type
= QXL_CURSOR_SET
;
687 qxl_bo_unref(&qcrtc
->cursor_bo
);
688 qcrtc
->cursor_bo
= cursor_bo
;
692 ret
= qxl_release_reserve_list(release
, true);
694 goto out_free_release
;
696 cmd
= (struct qxl_cursor_cmd
*) qxl_release_map(qdev
, release
);
697 cmd
->type
= QXL_CURSOR_MOVE
;
700 cmd
->u
.position
.x
= plane
->state
->crtc_x
+ fb
->hot_x
;
701 cmd
->u
.position
.y
= plane
->state
->crtc_y
+ fb
->hot_y
;
703 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
704 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
705 qxl_release_fence_buffer_objects(release
);
707 qxl_bo_unref(&cursor_bo
);
712 qxl_release_backoff_reserve_list(release
);
714 qxl_bo_unref(&cursor_bo
);
716 qxl_bo_kunmap(user_bo
);
718 qxl_release_free(qdev
, release
);
723 static void qxl_cursor_atomic_disable(struct drm_plane
*plane
,
724 struct drm_plane_state
*old_state
)
726 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
727 struct qxl_release
*release
;
728 struct qxl_cursor_cmd
*cmd
;
731 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
732 QXL_RELEASE_CURSOR_CMD
,
737 ret
= qxl_release_reserve_list(release
, true);
739 qxl_release_free(qdev
, release
);
743 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
744 cmd
->type
= QXL_CURSOR_HIDE
;
745 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
747 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
748 qxl_release_fence_buffer_objects(release
);
751 static int qxl_plane_prepare_fb(struct drm_plane
*plane
,
752 struct drm_plane_state
*new_state
)
754 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
755 struct drm_gem_object
*obj
;
756 struct qxl_bo
*user_bo
, *old_bo
= NULL
;
762 obj
= to_qxl_framebuffer(new_state
->fb
)->obj
;
763 user_bo
= gem_to_qxl_bo(obj
);
765 if (plane
->type
== DRM_PLANE_TYPE_PRIMARY
&&
766 user_bo
->is_dumb
&& !user_bo
->shadow
) {
767 if (plane
->state
->fb
) {
768 obj
= to_qxl_framebuffer(plane
->state
->fb
)->obj
;
769 old_bo
= gem_to_qxl_bo(obj
);
771 if (old_bo
&& old_bo
->shadow
&&
772 user_bo
->gem_base
.size
== old_bo
->gem_base
.size
&&
773 plane
->state
->crtc
== new_state
->crtc
&&
774 plane
->state
->crtc_w
== new_state
->crtc_w
&&
775 plane
->state
->crtc_h
== new_state
->crtc_h
&&
776 plane
->state
->src_x
== new_state
->src_x
&&
777 plane
->state
->src_y
== new_state
->src_y
&&
778 plane
->state
->src_w
== new_state
->src_w
&&
779 plane
->state
->src_h
== new_state
->src_h
&&
780 plane
->state
->rotation
== new_state
->rotation
&&
781 plane
->state
->zpos
== new_state
->zpos
) {
782 drm_gem_object_get(&old_bo
->shadow
->gem_base
);
783 user_bo
->shadow
= old_bo
->shadow
;
785 qxl_bo_create(qdev
, user_bo
->gem_base
.size
,
786 true, true, QXL_GEM_DOMAIN_VRAM
, NULL
,
791 ret
= qxl_bo_pin(user_bo
, QXL_GEM_DOMAIN_CPU
, NULL
);
798 static void qxl_plane_cleanup_fb(struct drm_plane
*plane
,
799 struct drm_plane_state
*old_state
)
801 struct drm_gem_object
*obj
;
802 struct qxl_bo
*user_bo
;
804 if (!old_state
->fb
) {
806 * we never executed prepare_fb, so there's nothing to
812 obj
= to_qxl_framebuffer(old_state
->fb
)->obj
;
813 user_bo
= gem_to_qxl_bo(obj
);
814 qxl_bo_unpin(user_bo
);
816 if (user_bo
->shadow
&& !user_bo
->is_primary
) {
817 drm_gem_object_put_unlocked(&user_bo
->shadow
->gem_base
);
818 user_bo
->shadow
= NULL
;
822 static const uint32_t qxl_cursor_plane_formats
[] = {
826 static const struct drm_plane_helper_funcs qxl_cursor_helper_funcs
= {
827 .atomic_check
= qxl_plane_atomic_check
,
828 .atomic_update
= qxl_cursor_atomic_update
,
829 .atomic_disable
= qxl_cursor_atomic_disable
,
830 .prepare_fb
= qxl_plane_prepare_fb
,
831 .cleanup_fb
= qxl_plane_cleanup_fb
,
834 static const struct drm_plane_funcs qxl_cursor_plane_funcs
= {
835 .update_plane
= drm_atomic_helper_update_plane
,
836 .disable_plane
= drm_atomic_helper_disable_plane
,
837 .destroy
= drm_primary_helper_destroy
,
838 .reset
= drm_atomic_helper_plane_reset
,
839 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
840 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
843 static const uint32_t qxl_primary_plane_formats
[] = {
848 static const struct drm_plane_helper_funcs primary_helper_funcs
= {
849 .atomic_check
= qxl_primary_atomic_check
,
850 .atomic_update
= qxl_primary_atomic_update
,
851 .atomic_disable
= qxl_primary_atomic_disable
,
852 .prepare_fb
= qxl_plane_prepare_fb
,
853 .cleanup_fb
= qxl_plane_cleanup_fb
,
856 static const struct drm_plane_funcs qxl_primary_plane_funcs
= {
857 .update_plane
= drm_atomic_helper_update_plane
,
858 .disable_plane
= drm_atomic_helper_disable_plane
,
859 .destroy
= drm_primary_helper_destroy
,
860 .reset
= drm_atomic_helper_plane_reset
,
861 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
862 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
865 static struct drm_plane
*qxl_create_plane(struct qxl_device
*qdev
,
866 unsigned int possible_crtcs
,
867 enum drm_plane_type type
)
869 const struct drm_plane_helper_funcs
*helper_funcs
= NULL
;
870 struct drm_plane
*plane
;
871 const struct drm_plane_funcs
*funcs
;
872 const uint32_t *formats
;
876 if (type
== DRM_PLANE_TYPE_PRIMARY
) {
877 funcs
= &qxl_primary_plane_funcs
;
878 formats
= qxl_primary_plane_formats
;
879 num_formats
= ARRAY_SIZE(qxl_primary_plane_formats
);
880 helper_funcs
= &primary_helper_funcs
;
881 } else if (type
== DRM_PLANE_TYPE_CURSOR
) {
882 funcs
= &qxl_cursor_plane_funcs
;
883 formats
= qxl_cursor_plane_formats
;
884 helper_funcs
= &qxl_cursor_helper_funcs
;
885 num_formats
= ARRAY_SIZE(qxl_cursor_plane_formats
);
887 return ERR_PTR(-EINVAL
);
890 plane
= kzalloc(sizeof(*plane
), GFP_KERNEL
);
892 return ERR_PTR(-ENOMEM
);
894 err
= drm_universal_plane_init(&qdev
->ddev
, plane
, possible_crtcs
,
895 funcs
, formats
, num_formats
,
900 drm_plane_helper_add(plane
, helper_funcs
);
906 return ERR_PTR(-EINVAL
);
909 static int qdev_crtc_init(struct drm_device
*dev
, int crtc_id
)
911 struct qxl_crtc
*qxl_crtc
;
912 struct drm_plane
*primary
, *cursor
;
913 struct qxl_device
*qdev
= dev
->dev_private
;
916 qxl_crtc
= kzalloc(sizeof(struct qxl_crtc
), GFP_KERNEL
);
920 primary
= qxl_create_plane(qdev
, 1 << crtc_id
, DRM_PLANE_TYPE_PRIMARY
);
921 if (IS_ERR(primary
)) {
926 cursor
= qxl_create_plane(qdev
, 1 << crtc_id
, DRM_PLANE_TYPE_CURSOR
);
927 if (IS_ERR(cursor
)) {
932 r
= drm_crtc_init_with_planes(dev
, &qxl_crtc
->base
, primary
, cursor
,
933 &qxl_crtc_funcs
, NULL
);
937 qxl_crtc
->index
= crtc_id
;
938 drm_crtc_helper_add(&qxl_crtc
->base
, &qxl_crtc_helper_funcs
);
942 drm_plane_cleanup(cursor
);
945 drm_plane_cleanup(primary
);
952 static void qxl_enc_dpms(struct drm_encoder
*encoder
, int mode
)
957 static void qxl_enc_prepare(struct drm_encoder
*encoder
)
962 static void qxl_write_monitors_config_for_encoder(struct qxl_device
*qdev
,
963 struct drm_encoder
*encoder
)
966 struct qxl_output
*output
= drm_encoder_to_qxl_output(encoder
);
967 struct qxl_head
*head
;
968 struct drm_display_mode
*mode
;
971 /* TODO: ugly, do better */
973 if (!qdev
->monitors_config
||
974 qdev
->monitors_config
->max_allowed
<= i
) {
976 "head number too large or missing monitors config: %p, %d",
977 qdev
->monitors_config
,
978 qdev
->monitors_config
?
979 qdev
->monitors_config
->max_allowed
: -1);
982 if (!encoder
->crtc
) {
983 DRM_ERROR("missing crtc on encoder %p\n", encoder
);
987 DRM_DEBUG("missing for multiple monitors: no head holes\n");
988 head
= &qdev
->monitors_config
->heads
[i
];
990 if (encoder
->crtc
->enabled
) {
991 mode
= &encoder
->crtc
->mode
;
992 head
->width
= mode
->hdisplay
;
993 head
->height
= mode
->vdisplay
;
994 head
->x
= encoder
->crtc
->x
;
995 head
->y
= encoder
->crtc
->y
;
996 if (qdev
->monitors_config
->count
< i
+ 1)
997 qdev
->monitors_config
->count
= i
+ 1;
1004 DRM_DEBUG_KMS("setting head %d to +%d+%d %dx%d out of %d\n",
1005 i
, head
->x
, head
->y
, head
->width
, head
->height
, qdev
->monitors_config
->count
);
1007 /* TODO - somewhere else to call this for multiple monitors
1008 * (config_commit?) */
1009 qxl_send_monitors_config(qdev
);
1012 static void qxl_enc_commit(struct drm_encoder
*encoder
)
1014 struct qxl_device
*qdev
= encoder
->dev
->dev_private
;
1016 qxl_write_monitors_config_for_encoder(qdev
, encoder
);
1020 static void qxl_enc_mode_set(struct drm_encoder
*encoder
,
1021 struct drm_display_mode
*mode
,
1022 struct drm_display_mode
*adjusted_mode
)
1027 static int qxl_conn_get_modes(struct drm_connector
*connector
)
1029 unsigned pwidth
= 1024;
1030 unsigned pheight
= 768;
1033 ret
= qxl_add_monitors_config_modes(connector
, &pwidth
, &pheight
);
1036 ret
+= qxl_add_common_modes(connector
, pwidth
, pheight
);
1040 static int qxl_conn_mode_valid(struct drm_connector
*connector
,
1041 struct drm_display_mode
*mode
)
1043 struct drm_device
*ddev
= connector
->dev
;
1044 struct qxl_device
*qdev
= ddev
->dev_private
;
1047 /* TODO: is this called for user defined modes? (xrandr --add-mode)
1048 * TODO: check that the mode fits in the framebuffer */
1050 if(qdev
->monitors_config_width
== mode
->hdisplay
&&
1051 qdev
->monitors_config_height
== mode
->vdisplay
)
1054 for (i
= 0; i
< ARRAY_SIZE(common_modes
); i
++) {
1055 if (common_modes
[i
].w
== mode
->hdisplay
&& common_modes
[i
].h
== mode
->vdisplay
)
1061 static struct drm_encoder
*qxl_best_encoder(struct drm_connector
*connector
)
1063 struct qxl_output
*qxl_output
=
1064 drm_connector_to_qxl_output(connector
);
1067 return &qxl_output
->enc
;
1071 static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs
= {
1072 .dpms
= qxl_enc_dpms
,
1073 .prepare
= qxl_enc_prepare
,
1074 .mode_set
= qxl_enc_mode_set
,
1075 .commit
= qxl_enc_commit
,
1078 static const struct drm_connector_helper_funcs qxl_connector_helper_funcs
= {
1079 .get_modes
= qxl_conn_get_modes
,
1080 .mode_valid
= qxl_conn_mode_valid
,
1081 .best_encoder
= qxl_best_encoder
,
1084 static enum drm_connector_status
qxl_conn_detect(
1085 struct drm_connector
*connector
,
1088 struct qxl_output
*output
=
1089 drm_connector_to_qxl_output(connector
);
1090 struct drm_device
*ddev
= connector
->dev
;
1091 struct qxl_device
*qdev
= ddev
->dev_private
;
1092 bool connected
= false;
1094 /* The first monitor is always connected */
1095 if (!qdev
->client_monitors_config
) {
1096 if (output
->index
== 0)
1099 connected
= qdev
->client_monitors_config
->count
> output
->index
&&
1100 qxl_head_enabled(&qdev
->client_monitors_config
->heads
[output
->index
]);
1102 DRM_DEBUG("#%d connected: %d\n", output
->index
, connected
);
1104 qxl_monitors_config_set(qdev
, output
->index
, 0, 0, 0, 0, 0);
1106 return connected
? connector_status_connected
1107 : connector_status_disconnected
;
1110 static int qxl_conn_set_property(struct drm_connector
*connector
,
1111 struct drm_property
*property
,
1118 static void qxl_conn_destroy(struct drm_connector
*connector
)
1120 struct qxl_output
*qxl_output
=
1121 drm_connector_to_qxl_output(connector
);
1123 drm_connector_unregister(connector
);
1124 drm_connector_cleanup(connector
);
1128 static const struct drm_connector_funcs qxl_connector_funcs
= {
1129 .dpms
= drm_helper_connector_dpms
,
1130 .detect
= qxl_conn_detect
,
1131 .fill_modes
= drm_helper_probe_single_connector_modes
,
1132 .set_property
= qxl_conn_set_property
,
1133 .destroy
= qxl_conn_destroy
,
1134 .reset
= drm_atomic_helper_connector_reset
,
1135 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
1136 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
1139 static void qxl_enc_destroy(struct drm_encoder
*encoder
)
1141 drm_encoder_cleanup(encoder
);
1144 static const struct drm_encoder_funcs qxl_enc_funcs
= {
1145 .destroy
= qxl_enc_destroy
,
1148 static int qxl_mode_create_hotplug_mode_update_property(struct qxl_device
*qdev
)
1150 if (qdev
->hotplug_mode_update_property
)
1153 qdev
->hotplug_mode_update_property
=
1154 drm_property_create_range(&qdev
->ddev
, DRM_MODE_PROP_IMMUTABLE
,
1155 "hotplug_mode_update", 0, 1);
1160 static int qdev_output_init(struct drm_device
*dev
, int num_output
)
1162 struct qxl_device
*qdev
= dev
->dev_private
;
1163 struct qxl_output
*qxl_output
;
1164 struct drm_connector
*connector
;
1165 struct drm_encoder
*encoder
;
1167 qxl_output
= kzalloc(sizeof(struct qxl_output
), GFP_KERNEL
);
1171 qxl_output
->index
= num_output
;
1173 connector
= &qxl_output
->base
;
1174 encoder
= &qxl_output
->enc
;
1175 drm_connector_init(dev
, &qxl_output
->base
,
1176 &qxl_connector_funcs
, DRM_MODE_CONNECTOR_VIRTUAL
);
1178 drm_encoder_init(dev
, &qxl_output
->enc
, &qxl_enc_funcs
,
1179 DRM_MODE_ENCODER_VIRTUAL
, NULL
);
1181 /* we get HPD via client monitors config */
1182 connector
->polled
= DRM_CONNECTOR_POLL_HPD
;
1183 encoder
->possible_crtcs
= 1 << num_output
;
1184 drm_mode_connector_attach_encoder(&qxl_output
->base
,
1186 drm_encoder_helper_add(encoder
, &qxl_enc_helper_funcs
);
1187 drm_connector_helper_add(connector
, &qxl_connector_helper_funcs
);
1189 drm_object_attach_property(&connector
->base
,
1190 qdev
->hotplug_mode_update_property
, 0);
1191 drm_object_attach_property(&connector
->base
,
1192 dev
->mode_config
.suggested_x_property
, 0);
1193 drm_object_attach_property(&connector
->base
,
1194 dev
->mode_config
.suggested_y_property
, 0);
1198 static struct drm_framebuffer
*
1199 qxl_user_framebuffer_create(struct drm_device
*dev
,
1200 struct drm_file
*file_priv
,
1201 const struct drm_mode_fb_cmd2
*mode_cmd
)
1203 struct drm_gem_object
*obj
;
1204 struct qxl_framebuffer
*qxl_fb
;
1207 obj
= drm_gem_object_lookup(file_priv
, mode_cmd
->handles
[0]);
1211 qxl_fb
= kzalloc(sizeof(*qxl_fb
), GFP_KERNEL
);
1215 ret
= qxl_framebuffer_init(dev
, qxl_fb
, mode_cmd
, obj
, &qxl_fb_funcs
);
1218 drm_gem_object_unreference_unlocked(obj
);
1222 return &qxl_fb
->base
;
1225 static const struct drm_mode_config_funcs qxl_mode_funcs
= {
1226 .fb_create
= qxl_user_framebuffer_create
,
1227 .atomic_check
= drm_atomic_helper_check
,
1228 .atomic_commit
= drm_atomic_helper_commit
,
1231 int qxl_create_monitors_object(struct qxl_device
*qdev
)
1234 struct drm_gem_object
*gobj
;
1235 int max_allowed
= qxl_num_crtc
;
1236 int monitors_config_size
= sizeof(struct qxl_monitors_config
) +
1237 max_allowed
* sizeof(struct qxl_head
);
1239 ret
= qxl_gem_object_create(qdev
, monitors_config_size
, 0,
1240 QXL_GEM_DOMAIN_VRAM
,
1241 false, false, NULL
, &gobj
);
1243 DRM_ERROR("%s: failed to create gem ret=%d\n", __func__
, ret
);
1246 qdev
->monitors_config_bo
= gem_to_qxl_bo(gobj
);
1248 ret
= qxl_bo_pin(qdev
->monitors_config_bo
, QXL_GEM_DOMAIN_VRAM
, NULL
);
1252 qxl_bo_kmap(qdev
->monitors_config_bo
, NULL
);
1254 qdev
->monitors_config
= qdev
->monitors_config_bo
->kptr
;
1255 qdev
->ram_header
->monitors_config
=
1256 qxl_bo_physical_address(qdev
, qdev
->monitors_config_bo
, 0);
1258 memset(qdev
->monitors_config
, 0, monitors_config_size
);
1259 qdev
->monitors_config
->max_allowed
= max_allowed
;
1263 int qxl_destroy_monitors_object(struct qxl_device
*qdev
)
1267 qdev
->monitors_config
= NULL
;
1268 qdev
->ram_header
->monitors_config
= 0;
1270 qxl_bo_kunmap(qdev
->monitors_config_bo
);
1271 ret
= qxl_bo_unpin(qdev
->monitors_config_bo
);
1275 qxl_bo_unref(&qdev
->monitors_config_bo
);
1279 int qxl_modeset_init(struct qxl_device
*qdev
)
1284 drm_mode_config_init(&qdev
->ddev
);
1286 ret
= qxl_create_monitors_object(qdev
);
1290 qdev
->ddev
.mode_config
.funcs
= (void *)&qxl_mode_funcs
;
1292 /* modes will be validated against the framebuffer size */
1293 qdev
->ddev
.mode_config
.min_width
= 0;
1294 qdev
->ddev
.mode_config
.min_height
= 0;
1295 qdev
->ddev
.mode_config
.max_width
= 8192;
1296 qdev
->ddev
.mode_config
.max_height
= 8192;
1298 qdev
->ddev
.mode_config
.fb_base
= qdev
->vram_base
;
1300 drm_mode_create_suggested_offset_properties(&qdev
->ddev
);
1301 qxl_mode_create_hotplug_mode_update_property(qdev
);
1303 for (i
= 0 ; i
< qxl_num_crtc
; ++i
) {
1304 qdev_crtc_init(&qdev
->ddev
, i
);
1305 qdev_output_init(&qdev
->ddev
, i
);
1308 qxl_display_read_client_monitors_config(qdev
);
1309 qdev
->mode_info
.mode_config_initialized
= true;
1311 drm_mode_config_reset(&qdev
->ddev
);
1313 /* primary surface must be created by this point, to allow
1314 * issuing command queue commands and having them read by
1316 qxl_fbdev_init(qdev
);
1320 void qxl_modeset_fini(struct qxl_device
*qdev
)
1322 qxl_fbdev_fini(qdev
);
1324 qxl_destroy_monitors_object(qdev
);
1325 if (qdev
->mode_info
.mode_config_initialized
) {
1326 drm_mode_config_cleanup(&qdev
->ddev
);
1327 qdev
->mode_info
.mode_config_initialized
= false;