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
)
54 qdev
->client_monitors_config
->count
= count
;
58 MONITORS_CONFIG_MODIFIED
,
59 MONITORS_CONFIG_UNCHANGED
,
60 MONITORS_CONFIG_BAD_CRC
,
63 static int qxl_display_copy_rom_client_monitors_config(struct qxl_device
*qdev
)
68 int status
= MONITORS_CONFIG_UNCHANGED
;
70 num_monitors
= qdev
->rom
->client_monitors_config
.count
;
71 crc
= crc32(0, (const uint8_t *)&qdev
->rom
->client_monitors_config
,
72 sizeof(qdev
->rom
->client_monitors_config
));
73 if (crc
!= qdev
->rom
->client_monitors_config_crc
)
74 return MONITORS_CONFIG_BAD_CRC
;
76 DRM_DEBUG_KMS("no client monitors configured\n");
79 if (num_monitors
> qdev
->monitors_config
->max_allowed
) {
80 DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
81 qdev
->monitors_config
->max_allowed
, num_monitors
);
82 num_monitors
= qdev
->monitors_config
->max_allowed
;
84 num_monitors
= qdev
->rom
->client_monitors_config
.count
;
86 if (qdev
->client_monitors_config
87 && (num_monitors
!= qdev
->client_monitors_config
->count
)) {
88 status
= MONITORS_CONFIG_MODIFIED
;
90 qxl_alloc_client_monitors_config(qdev
, num_monitors
);
91 /* we copy max from the client but it isn't used */
92 qdev
->client_monitors_config
->max_allowed
=
93 qdev
->monitors_config
->max_allowed
;
94 for (i
= 0 ; i
< qdev
->client_monitors_config
->count
; ++i
) {
95 struct qxl_urect
*c_rect
=
96 &qdev
->rom
->client_monitors_config
.heads
[i
];
97 struct qxl_head
*client_head
=
98 &qdev
->client_monitors_config
->heads
[i
];
99 if (client_head
->x
!= c_rect
->left
) {
100 client_head
->x
= c_rect
->left
;
101 status
= MONITORS_CONFIG_MODIFIED
;
103 if (client_head
->y
!= c_rect
->top
) {
104 client_head
->y
= c_rect
->top
;
105 status
= MONITORS_CONFIG_MODIFIED
;
107 if (client_head
->width
!= c_rect
->right
- c_rect
->left
) {
108 client_head
->width
= c_rect
->right
- c_rect
->left
;
109 status
= MONITORS_CONFIG_MODIFIED
;
111 if (client_head
->height
!= c_rect
->bottom
- c_rect
->top
) {
112 client_head
->height
= c_rect
->bottom
- c_rect
->top
;
113 status
= MONITORS_CONFIG_MODIFIED
;
115 if (client_head
->surface_id
!= 0) {
116 client_head
->surface_id
= 0;
117 status
= MONITORS_CONFIG_MODIFIED
;
119 if (client_head
->id
!= i
) {
121 status
= MONITORS_CONFIG_MODIFIED
;
123 if (client_head
->flags
!= 0) {
124 client_head
->flags
= 0;
125 status
= MONITORS_CONFIG_MODIFIED
;
127 DRM_DEBUG_KMS("read %dx%d+%d+%d\n", client_head
->width
, client_head
->height
,
128 client_head
->x
, client_head
->y
);
134 static void qxl_update_offset_props(struct qxl_device
*qdev
)
136 struct drm_device
*dev
= &qdev
->ddev
;
137 struct drm_connector
*connector
;
138 struct qxl_output
*output
;
139 struct qxl_head
*head
;
141 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
142 output
= drm_connector_to_qxl_output(connector
);
144 head
= &qdev
->client_monitors_config
->heads
[output
->index
];
146 drm_object_property_set_value(&connector
->base
,
147 dev
->mode_config
.suggested_x_property
, head
->x
);
148 drm_object_property_set_value(&connector
->base
,
149 dev
->mode_config
.suggested_y_property
, head
->y
);
153 void qxl_display_read_client_monitors_config(struct qxl_device
*qdev
)
155 struct drm_device
*dev
= &qdev
->ddev
;
158 for (retries
= 0; retries
< 10; retries
++) {
159 status
= qxl_display_copy_rom_client_monitors_config(qdev
);
160 if (status
!= MONITORS_CONFIG_BAD_CRC
)
164 if (status
== MONITORS_CONFIG_BAD_CRC
) {
165 DRM_DEBUG_KMS("ignoring client monitors config: bad crc");
168 if (status
== MONITORS_CONFIG_UNCHANGED
) {
169 DRM_DEBUG_KMS("ignoring client monitors config: unchanged");
173 drm_modeset_lock_all(dev
);
174 qxl_update_offset_props(qdev
);
175 drm_modeset_unlock_all(dev
);
176 if (!drm_helper_hpd_irq_event(dev
)) {
177 /* notify that the monitor configuration changed, to
178 adjust at the arbitrary resolution */
179 drm_kms_helper_hotplug_event(dev
);
183 static int qxl_add_monitors_config_modes(struct drm_connector
*connector
,
187 struct drm_device
*dev
= connector
->dev
;
188 struct qxl_device
*qdev
= dev
->dev_private
;
189 struct qxl_output
*output
= drm_connector_to_qxl_output(connector
);
190 int h
= output
->index
;
191 struct drm_display_mode
*mode
= NULL
;
192 struct qxl_head
*head
;
194 if (!qdev
->monitors_config
)
196 if (h
>= qdev
->monitors_config
->max_allowed
)
198 if (!qdev
->client_monitors_config
)
200 if (h
>= qdev
->client_monitors_config
->count
)
203 head
= &qdev
->client_monitors_config
->heads
[h
];
204 DRM_DEBUG_KMS("head %d is %dx%d\n", h
, head
->width
, head
->height
);
206 mode
= drm_cvt_mode(dev
, head
->width
, head
->height
, 60, false, false,
208 mode
->type
|= DRM_MODE_TYPE_PREFERRED
;
209 mode
->hdisplay
= head
->width
;
210 mode
->vdisplay
= head
->height
;
211 drm_mode_set_name(mode
);
212 *pwidth
= head
->width
;
213 *pheight
= head
->height
;
214 drm_mode_probed_add(connector
, mode
);
215 /* remember the last custom size for mode validation */
216 qdev
->monitors_config_width
= mode
->hdisplay
;
217 qdev
->monitors_config_height
= mode
->vdisplay
;
221 static struct mode_size
{
244 static int qxl_add_common_modes(struct drm_connector
*connector
,
248 struct drm_device
*dev
= connector
->dev
;
249 struct drm_display_mode
*mode
= NULL
;
251 for (i
= 0; i
< ARRAY_SIZE(common_modes
); i
++) {
252 mode
= drm_cvt_mode(dev
, common_modes
[i
].w
, common_modes
[i
].h
,
253 60, false, false, false);
254 if (common_modes
[i
].w
== pwidth
&& common_modes
[i
].h
== pheight
)
255 mode
->type
|= DRM_MODE_TYPE_PREFERRED
;
256 drm_mode_probed_add(connector
, mode
);
261 static void qxl_send_monitors_config(struct qxl_device
*qdev
)
265 BUG_ON(!qdev
->ram_header
->monitors_config
);
267 if (qdev
->monitors_config
->count
== 0)
270 for (i
= 0 ; i
< qdev
->monitors_config
->count
; ++i
) {
271 struct qxl_head
*head
= &qdev
->monitors_config
->heads
[i
];
273 if (head
->y
> 8192 || head
->x
> 8192 ||
274 head
->width
> 8192 || head
->height
> 8192) {
275 DRM_ERROR("head %d wrong: %dx%d+%d+%d\n",
276 i
, head
->width
, head
->height
,
281 qxl_io_monitors_config(qdev
);
284 static void qxl_crtc_update_monitors_config(struct drm_crtc
*crtc
,
287 struct drm_device
*dev
= crtc
->dev
;
288 struct qxl_device
*qdev
= dev
->dev_private
;
289 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
290 struct qxl_head head
;
291 int oldcount
, i
= qcrtc
->index
;
293 if (!qdev
->primary_created
) {
294 DRM_DEBUG_KMS("no primary surface, skip (%s)\n", reason
);
298 if (!qdev
->monitors_config
||
299 qdev
->monitors_config
->max_allowed
<= i
)
304 oldcount
= qdev
->monitors_config
->count
;
305 if (crtc
->state
->active
) {
306 struct drm_display_mode
*mode
= &crtc
->mode
;
307 head
.width
= mode
->hdisplay
;
308 head
.height
= mode
->vdisplay
;
311 if (qdev
->monitors_config
->count
< i
+ 1)
312 qdev
->monitors_config
->count
= i
+ 1;
318 if (qdev
->monitors_config
->count
== i
+ 1)
319 qdev
->monitors_config
->count
= i
;
321 DRM_DEBUG_KMS("inactive head 0, skip (%s)\n", reason
);
325 if (head
.width
== qdev
->monitors_config
->heads
[i
].width
&&
326 head
.height
== qdev
->monitors_config
->heads
[i
].height
&&
327 head
.x
== qdev
->monitors_config
->heads
[i
].x
&&
328 head
.y
== qdev
->monitors_config
->heads
[i
].y
&&
329 oldcount
== qdev
->monitors_config
->count
)
332 DRM_DEBUG_KMS("head %d, %dx%d, at +%d+%d, %s (%s)\n",
333 i
, head
.width
, head
.height
, head
.x
, head
.y
,
334 crtc
->state
->active
? "on" : "off", reason
);
335 if (oldcount
!= qdev
->monitors_config
->count
)
336 DRM_DEBUG_KMS("active heads %d -> %d (%d total)\n",
337 oldcount
, qdev
->monitors_config
->count
,
338 qdev
->monitors_config
->max_allowed
);
340 qdev
->monitors_config
->heads
[i
] = head
;
341 qxl_send_monitors_config(qdev
);
344 static void qxl_crtc_atomic_flush(struct drm_crtc
*crtc
,
345 struct drm_crtc_state
*old_crtc_state
)
347 struct drm_device
*dev
= crtc
->dev
;
348 struct drm_pending_vblank_event
*event
;
351 if (crtc
->state
&& crtc
->state
->event
) {
352 event
= crtc
->state
->event
;
353 crtc
->state
->event
= NULL
;
355 spin_lock_irqsave(&dev
->event_lock
, flags
);
356 drm_crtc_send_vblank_event(crtc
, event
);
357 spin_unlock_irqrestore(&dev
->event_lock
, flags
);
360 qxl_crtc_update_monitors_config(crtc
, "flush");
363 static void qxl_crtc_destroy(struct drm_crtc
*crtc
)
365 struct qxl_crtc
*qxl_crtc
= to_qxl_crtc(crtc
);
367 qxl_bo_unref(&qxl_crtc
->cursor_bo
);
368 drm_crtc_cleanup(crtc
);
372 static const struct drm_crtc_funcs qxl_crtc_funcs
= {
373 .set_config
= drm_atomic_helper_set_config
,
374 .destroy
= qxl_crtc_destroy
,
375 .page_flip
= drm_atomic_helper_page_flip
,
376 .reset
= drm_atomic_helper_crtc_reset
,
377 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
378 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
381 void qxl_user_framebuffer_destroy(struct drm_framebuffer
*fb
)
383 struct qxl_framebuffer
*qxl_fb
= to_qxl_framebuffer(fb
);
384 struct qxl_bo
*bo
= gem_to_qxl_bo(qxl_fb
->obj
);
387 drm_gem_object_put_unlocked(qxl_fb
->obj
);
388 drm_framebuffer_cleanup(fb
);
392 static int qxl_framebuffer_surface_dirty(struct drm_framebuffer
*fb
,
393 struct drm_file
*file_priv
,
394 unsigned flags
, unsigned color
,
395 struct drm_clip_rect
*clips
,
398 /* TODO: vmwgfx where this was cribbed from had locking. Why? */
399 struct qxl_framebuffer
*qxl_fb
= to_qxl_framebuffer(fb
);
400 struct qxl_device
*qdev
= qxl_fb
->base
.dev
->dev_private
;
401 struct drm_clip_rect norect
;
405 drm_modeset_lock_all(fb
->dev
);
407 qobj
= gem_to_qxl_bo(qxl_fb
->obj
);
408 /* if we aren't primary surface ignore this */
409 if (!qobj
->is_primary
) {
410 drm_modeset_unlock_all(fb
->dev
);
417 norect
.x1
= norect
.y1
= 0;
418 norect
.x2
= fb
->width
;
419 norect
.y2
= fb
->height
;
420 } else if (flags
& DRM_MODE_FB_DIRTY_ANNOTATE_COPY
) {
422 inc
= 2; /* skip source rects */
425 qxl_draw_dirty_fb(qdev
, qxl_fb
, qobj
, flags
, color
,
426 clips
, num_clips
, inc
);
428 drm_modeset_unlock_all(fb
->dev
);
433 static const struct drm_framebuffer_funcs qxl_fb_funcs
= {
434 .destroy
= qxl_user_framebuffer_destroy
,
435 .dirty
= qxl_framebuffer_surface_dirty
,
437 * .create_handle = qxl_user_framebuffer_create_handle, */
441 qxl_framebuffer_init(struct drm_device
*dev
,
442 struct qxl_framebuffer
*qfb
,
443 const struct drm_mode_fb_cmd2
*mode_cmd
,
444 struct drm_gem_object
*obj
,
445 const struct drm_framebuffer_funcs
*funcs
)
450 drm_helper_mode_fill_fb_struct(dev
, &qfb
->base
, mode_cmd
);
451 ret
= drm_framebuffer_init(dev
, &qfb
->base
, funcs
);
459 static void qxl_crtc_atomic_enable(struct drm_crtc
*crtc
,
460 struct drm_crtc_state
*old_state
)
462 qxl_crtc_update_monitors_config(crtc
, "enable");
465 static void qxl_crtc_atomic_disable(struct drm_crtc
*crtc
,
466 struct drm_crtc_state
*old_state
)
468 qxl_crtc_update_monitors_config(crtc
, "disable");
471 static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs
= {
472 .atomic_flush
= qxl_crtc_atomic_flush
,
473 .atomic_enable
= qxl_crtc_atomic_enable
,
474 .atomic_disable
= qxl_crtc_atomic_disable
,
477 static int qxl_primary_atomic_check(struct drm_plane
*plane
,
478 struct drm_plane_state
*state
)
480 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
481 struct qxl_framebuffer
*qfb
;
484 if (!state
->crtc
|| !state
->fb
)
487 qfb
= to_qxl_framebuffer(state
->fb
);
488 bo
= gem_to_qxl_bo(qfb
->obj
);
490 if (bo
->surf
.stride
* bo
->surf
.height
> qdev
->vram_size
) {
491 DRM_ERROR("Mode doesn't fit in vram size (vgamem)");
498 static int qxl_primary_apply_cursor(struct drm_plane
*plane
)
500 struct drm_device
*dev
= plane
->dev
;
501 struct qxl_device
*qdev
= dev
->dev_private
;
502 struct drm_framebuffer
*fb
= plane
->state
->fb
;
503 struct qxl_crtc
*qcrtc
= to_qxl_crtc(plane
->state
->crtc
);
504 struct qxl_cursor_cmd
*cmd
;
505 struct qxl_release
*release
;
508 if (!qcrtc
->cursor_bo
)
511 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
512 QXL_RELEASE_CURSOR_CMD
,
517 ret
= qxl_release_list_add(release
, qcrtc
->cursor_bo
);
519 goto out_free_release
;
521 ret
= qxl_release_reserve_list(release
, false);
523 goto out_free_release
;
525 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
526 cmd
->type
= QXL_CURSOR_SET
;
527 cmd
->u
.set
.position
.x
= plane
->state
->crtc_x
+ fb
->hot_x
;
528 cmd
->u
.set
.position
.y
= plane
->state
->crtc_y
+ fb
->hot_y
;
530 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
, qcrtc
->cursor_bo
, 0);
532 cmd
->u
.set
.visible
= 1;
533 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
535 qxl_release_fence_buffer_objects(release
);
536 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
541 qxl_release_free(qdev
, release
);
545 static void qxl_primary_atomic_update(struct drm_plane
*plane
,
546 struct drm_plane_state
*old_state
)
548 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
549 struct qxl_framebuffer
*qfb
=
550 to_qxl_framebuffer(plane
->state
->fb
);
551 struct qxl_framebuffer
*qfb_old
;
552 struct qxl_bo
*bo
= gem_to_qxl_bo(qfb
->obj
);
553 struct qxl_bo
*bo_old
;
554 struct drm_clip_rect norect
= {
557 .x2
= qfb
->base
.width
,
558 .y2
= qfb
->base
.height
561 bool same_shadow
= false;
564 qfb_old
= to_qxl_framebuffer(old_state
->fb
);
565 bo_old
= gem_to_qxl_bo(qfb_old
->obj
);
573 if (bo_old
&& bo_old
->shadow
&& bo
->shadow
&&
574 bo_old
->shadow
== bo
->shadow
) {
578 if (bo_old
&& bo_old
->is_primary
) {
580 qxl_io_destroy_primary(qdev
);
581 bo_old
->is_primary
= false;
583 ret
= qxl_primary_apply_cursor(plane
);
586 "could not set cursor after creating primary");
589 if (!bo
->is_primary
) {
591 qxl_io_create_primary(qdev
, 0, bo
);
592 bo
->is_primary
= true;
595 qxl_draw_dirty_fb(qdev
, qfb
, bo
, 0, 0, &norect
, 1, 1);
598 static void qxl_primary_atomic_disable(struct drm_plane
*plane
,
599 struct drm_plane_state
*old_state
)
601 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
604 struct qxl_framebuffer
*qfb
=
605 to_qxl_framebuffer(old_state
->fb
);
606 struct qxl_bo
*bo
= gem_to_qxl_bo(qfb
->obj
);
608 if (bo
->is_primary
) {
609 qxl_io_destroy_primary(qdev
);
610 bo
->is_primary
= false;
615 static void qxl_cursor_atomic_update(struct drm_plane
*plane
,
616 struct drm_plane_state
*old_state
)
618 struct drm_device
*dev
= plane
->dev
;
619 struct qxl_device
*qdev
= dev
->dev_private
;
620 struct drm_framebuffer
*fb
= plane
->state
->fb
;
621 struct qxl_crtc
*qcrtc
= to_qxl_crtc(plane
->state
->crtc
);
622 struct qxl_release
*release
;
623 struct qxl_cursor_cmd
*cmd
;
624 struct qxl_cursor
*cursor
;
625 struct drm_gem_object
*obj
;
626 struct qxl_bo
*cursor_bo
= NULL
, *user_bo
= NULL
, *old_cursor_bo
= NULL
;
631 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
632 QXL_RELEASE_CURSOR_CMD
,
637 if (fb
!= old_state
->fb
) {
638 obj
= to_qxl_framebuffer(fb
)->obj
;
639 user_bo
= gem_to_qxl_bo(obj
);
641 /* pinning is done in the prepare/cleanup framevbuffer */
642 ret
= qxl_bo_kmap(user_bo
, &user_ptr
);
644 goto out_free_release
;
646 ret
= qxl_alloc_bo_reserved(qdev
, release
,
647 sizeof(struct qxl_cursor
) + size
,
652 ret
= qxl_release_reserve_list(release
, true);
656 ret
= qxl_bo_kmap(cursor_bo
, (void **)&cursor
);
660 cursor
->header
.unique
= 0;
661 cursor
->header
.type
= SPICE_CURSOR_TYPE_ALPHA
;
662 cursor
->header
.width
= 64;
663 cursor
->header
.height
= 64;
664 cursor
->header
.hot_spot_x
= fb
->hot_x
;
665 cursor
->header
.hot_spot_y
= fb
->hot_y
;
666 cursor
->data_size
= size
;
667 cursor
->chunk
.next_chunk
= 0;
668 cursor
->chunk
.prev_chunk
= 0;
669 cursor
->chunk
.data_size
= size
;
670 memcpy(cursor
->chunk
.data
, user_ptr
, size
);
671 qxl_bo_kunmap(cursor_bo
);
672 qxl_bo_kunmap(user_bo
);
674 cmd
= (struct qxl_cursor_cmd
*) qxl_release_map(qdev
, release
);
675 cmd
->u
.set
.visible
= 1;
676 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
,
678 cmd
->type
= QXL_CURSOR_SET
;
680 old_cursor_bo
= qcrtc
->cursor_bo
;
681 qcrtc
->cursor_bo
= cursor_bo
;
685 ret
= qxl_release_reserve_list(release
, true);
687 goto out_free_release
;
689 cmd
= (struct qxl_cursor_cmd
*) qxl_release_map(qdev
, release
);
690 cmd
->type
= QXL_CURSOR_MOVE
;
693 cmd
->u
.position
.x
= plane
->state
->crtc_x
+ fb
->hot_x
;
694 cmd
->u
.position
.y
= plane
->state
->crtc_y
+ fb
->hot_y
;
696 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
697 qxl_release_fence_buffer_objects(release
);
698 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
701 qxl_bo_unref(&old_cursor_bo
);
703 qxl_bo_unref(&cursor_bo
);
708 qxl_release_backoff_reserve_list(release
);
710 qxl_bo_unref(&cursor_bo
);
712 qxl_bo_kunmap(user_bo
);
714 qxl_release_free(qdev
, release
);
719 static void qxl_cursor_atomic_disable(struct drm_plane
*plane
,
720 struct drm_plane_state
*old_state
)
722 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
723 struct qxl_release
*release
;
724 struct qxl_cursor_cmd
*cmd
;
727 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
728 QXL_RELEASE_CURSOR_CMD
,
733 ret
= qxl_release_reserve_list(release
, true);
735 qxl_release_free(qdev
, release
);
739 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
740 cmd
->type
= QXL_CURSOR_HIDE
;
741 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
743 qxl_release_fence_buffer_objects(release
);
744 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
747 static int qxl_plane_prepare_fb(struct drm_plane
*plane
,
748 struct drm_plane_state
*new_state
)
750 struct qxl_device
*qdev
= plane
->dev
->dev_private
;
751 struct drm_gem_object
*obj
;
752 struct qxl_bo
*user_bo
, *old_bo
= NULL
;
758 obj
= to_qxl_framebuffer(new_state
->fb
)->obj
;
759 user_bo
= gem_to_qxl_bo(obj
);
761 if (plane
->type
== DRM_PLANE_TYPE_PRIMARY
&&
762 user_bo
->is_dumb
&& !user_bo
->shadow
) {
763 if (plane
->state
->fb
) {
764 obj
= to_qxl_framebuffer(plane
->state
->fb
)->obj
;
765 old_bo
= gem_to_qxl_bo(obj
);
767 if (old_bo
&& old_bo
->shadow
&&
768 user_bo
->gem_base
.size
== old_bo
->gem_base
.size
&&
769 plane
->state
->crtc
== new_state
->crtc
&&
770 plane
->state
->crtc_w
== new_state
->crtc_w
&&
771 plane
->state
->crtc_h
== new_state
->crtc_h
&&
772 plane
->state
->src_x
== new_state
->src_x
&&
773 plane
->state
->src_y
== new_state
->src_y
&&
774 plane
->state
->src_w
== new_state
->src_w
&&
775 plane
->state
->src_h
== new_state
->src_h
&&
776 plane
->state
->rotation
== new_state
->rotation
&&
777 plane
->state
->zpos
== new_state
->zpos
) {
778 drm_gem_object_get(&old_bo
->shadow
->gem_base
);
779 user_bo
->shadow
= old_bo
->shadow
;
781 qxl_bo_create(qdev
, user_bo
->gem_base
.size
,
782 true, true, QXL_GEM_DOMAIN_VRAM
, NULL
,
787 ret
= qxl_bo_pin(user_bo
, QXL_GEM_DOMAIN_CPU
, NULL
);
794 static void qxl_plane_cleanup_fb(struct drm_plane
*plane
,
795 struct drm_plane_state
*old_state
)
797 struct drm_gem_object
*obj
;
798 struct qxl_bo
*user_bo
;
800 if (!old_state
->fb
) {
802 * we never executed prepare_fb, so there's nothing to
808 obj
= to_qxl_framebuffer(old_state
->fb
)->obj
;
809 user_bo
= gem_to_qxl_bo(obj
);
810 qxl_bo_unpin(user_bo
);
812 if (user_bo
->shadow
&& !user_bo
->is_primary
) {
813 drm_gem_object_put_unlocked(&user_bo
->shadow
->gem_base
);
814 user_bo
->shadow
= NULL
;
818 static const uint32_t qxl_cursor_plane_formats
[] = {
822 static const struct drm_plane_helper_funcs qxl_cursor_helper_funcs
= {
823 .atomic_update
= qxl_cursor_atomic_update
,
824 .atomic_disable
= qxl_cursor_atomic_disable
,
825 .prepare_fb
= qxl_plane_prepare_fb
,
826 .cleanup_fb
= qxl_plane_cleanup_fb
,
829 static const struct drm_plane_funcs qxl_cursor_plane_funcs
= {
830 .update_plane
= drm_atomic_helper_update_plane
,
831 .disable_plane
= drm_atomic_helper_disable_plane
,
832 .destroy
= drm_primary_helper_destroy
,
833 .reset
= drm_atomic_helper_plane_reset
,
834 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
835 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
838 static const uint32_t qxl_primary_plane_formats
[] = {
843 static const struct drm_plane_helper_funcs primary_helper_funcs
= {
844 .atomic_check
= qxl_primary_atomic_check
,
845 .atomic_update
= qxl_primary_atomic_update
,
846 .atomic_disable
= qxl_primary_atomic_disable
,
847 .prepare_fb
= qxl_plane_prepare_fb
,
848 .cleanup_fb
= qxl_plane_cleanup_fb
,
851 static const struct drm_plane_funcs qxl_primary_plane_funcs
= {
852 .update_plane
= drm_atomic_helper_update_plane
,
853 .disable_plane
= drm_atomic_helper_disable_plane
,
854 .destroy
= drm_primary_helper_destroy
,
855 .reset
= drm_atomic_helper_plane_reset
,
856 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
857 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
860 static struct drm_plane
*qxl_create_plane(struct qxl_device
*qdev
,
861 unsigned int possible_crtcs
,
862 enum drm_plane_type type
)
864 const struct drm_plane_helper_funcs
*helper_funcs
= NULL
;
865 struct drm_plane
*plane
;
866 const struct drm_plane_funcs
*funcs
;
867 const uint32_t *formats
;
871 if (type
== DRM_PLANE_TYPE_PRIMARY
) {
872 funcs
= &qxl_primary_plane_funcs
;
873 formats
= qxl_primary_plane_formats
;
874 num_formats
= ARRAY_SIZE(qxl_primary_plane_formats
);
875 helper_funcs
= &primary_helper_funcs
;
876 } else if (type
== DRM_PLANE_TYPE_CURSOR
) {
877 funcs
= &qxl_cursor_plane_funcs
;
878 formats
= qxl_cursor_plane_formats
;
879 helper_funcs
= &qxl_cursor_helper_funcs
;
880 num_formats
= ARRAY_SIZE(qxl_cursor_plane_formats
);
882 return ERR_PTR(-EINVAL
);
885 plane
= kzalloc(sizeof(*plane
), GFP_KERNEL
);
887 return ERR_PTR(-ENOMEM
);
889 err
= drm_universal_plane_init(&qdev
->ddev
, plane
, possible_crtcs
,
890 funcs
, formats
, num_formats
,
895 drm_plane_helper_add(plane
, helper_funcs
);
901 return ERR_PTR(-EINVAL
);
904 static int qdev_crtc_init(struct drm_device
*dev
, int crtc_id
)
906 struct qxl_crtc
*qxl_crtc
;
907 struct drm_plane
*primary
, *cursor
;
908 struct qxl_device
*qdev
= dev
->dev_private
;
911 qxl_crtc
= kzalloc(sizeof(struct qxl_crtc
), GFP_KERNEL
);
915 primary
= qxl_create_plane(qdev
, 1 << crtc_id
, DRM_PLANE_TYPE_PRIMARY
);
916 if (IS_ERR(primary
)) {
921 cursor
= qxl_create_plane(qdev
, 1 << crtc_id
, DRM_PLANE_TYPE_CURSOR
);
922 if (IS_ERR(cursor
)) {
927 r
= drm_crtc_init_with_planes(dev
, &qxl_crtc
->base
, primary
, cursor
,
928 &qxl_crtc_funcs
, NULL
);
932 qxl_crtc
->index
= crtc_id
;
933 drm_crtc_helper_add(&qxl_crtc
->base
, &qxl_crtc_helper_funcs
);
937 drm_plane_cleanup(cursor
);
940 drm_plane_cleanup(primary
);
947 static int qxl_conn_get_modes(struct drm_connector
*connector
)
949 unsigned pwidth
= 1024;
950 unsigned pheight
= 768;
953 ret
= qxl_add_monitors_config_modes(connector
, &pwidth
, &pheight
);
956 ret
+= qxl_add_common_modes(connector
, pwidth
, pheight
);
960 static enum drm_mode_status
qxl_conn_mode_valid(struct drm_connector
*connector
,
961 struct drm_display_mode
*mode
)
963 struct drm_device
*ddev
= connector
->dev
;
964 struct qxl_device
*qdev
= ddev
->dev_private
;
967 /* TODO: is this called for user defined modes? (xrandr --add-mode)
968 * TODO: check that the mode fits in the framebuffer */
970 if(qdev
->monitors_config_width
== mode
->hdisplay
&&
971 qdev
->monitors_config_height
== mode
->vdisplay
)
974 for (i
= 0; i
< ARRAY_SIZE(common_modes
); i
++) {
975 if (common_modes
[i
].w
== mode
->hdisplay
&& common_modes
[i
].h
== mode
->vdisplay
)
981 static struct drm_encoder
*qxl_best_encoder(struct drm_connector
*connector
)
983 struct qxl_output
*qxl_output
=
984 drm_connector_to_qxl_output(connector
);
987 return &qxl_output
->enc
;
991 static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs
= {
994 static const struct drm_connector_helper_funcs qxl_connector_helper_funcs
= {
995 .get_modes
= qxl_conn_get_modes
,
996 .mode_valid
= qxl_conn_mode_valid
,
997 .best_encoder
= qxl_best_encoder
,
1000 static enum drm_connector_status
qxl_conn_detect(
1001 struct drm_connector
*connector
,
1004 struct qxl_output
*output
=
1005 drm_connector_to_qxl_output(connector
);
1006 struct drm_device
*ddev
= connector
->dev
;
1007 struct qxl_device
*qdev
= ddev
->dev_private
;
1008 bool connected
= false;
1010 /* The first monitor is always connected */
1011 if (!qdev
->client_monitors_config
) {
1012 if (output
->index
== 0)
1015 connected
= qdev
->client_monitors_config
->count
> output
->index
&&
1016 qxl_head_enabled(&qdev
->client_monitors_config
->heads
[output
->index
]);
1018 DRM_DEBUG("#%d connected: %d\n", output
->index
, connected
);
1020 return connected
? connector_status_connected
1021 : connector_status_disconnected
;
1024 static void qxl_conn_destroy(struct drm_connector
*connector
)
1026 struct qxl_output
*qxl_output
=
1027 drm_connector_to_qxl_output(connector
);
1029 drm_connector_unregister(connector
);
1030 drm_connector_cleanup(connector
);
1034 static const struct drm_connector_funcs qxl_connector_funcs
= {
1035 .dpms
= drm_helper_connector_dpms
,
1036 .detect
= qxl_conn_detect
,
1037 .fill_modes
= drm_helper_probe_single_connector_modes
,
1038 .destroy
= qxl_conn_destroy
,
1039 .reset
= drm_atomic_helper_connector_reset
,
1040 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
1041 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
1044 static void qxl_enc_destroy(struct drm_encoder
*encoder
)
1046 drm_encoder_cleanup(encoder
);
1049 static const struct drm_encoder_funcs qxl_enc_funcs
= {
1050 .destroy
= qxl_enc_destroy
,
1053 static int qxl_mode_create_hotplug_mode_update_property(struct qxl_device
*qdev
)
1055 if (qdev
->hotplug_mode_update_property
)
1058 qdev
->hotplug_mode_update_property
=
1059 drm_property_create_range(&qdev
->ddev
, DRM_MODE_PROP_IMMUTABLE
,
1060 "hotplug_mode_update", 0, 1);
1065 static int qdev_output_init(struct drm_device
*dev
, int num_output
)
1067 struct qxl_device
*qdev
= dev
->dev_private
;
1068 struct qxl_output
*qxl_output
;
1069 struct drm_connector
*connector
;
1070 struct drm_encoder
*encoder
;
1072 qxl_output
= kzalloc(sizeof(struct qxl_output
), GFP_KERNEL
);
1076 qxl_output
->index
= num_output
;
1078 connector
= &qxl_output
->base
;
1079 encoder
= &qxl_output
->enc
;
1080 drm_connector_init(dev
, &qxl_output
->base
,
1081 &qxl_connector_funcs
, DRM_MODE_CONNECTOR_VIRTUAL
);
1083 drm_encoder_init(dev
, &qxl_output
->enc
, &qxl_enc_funcs
,
1084 DRM_MODE_ENCODER_VIRTUAL
, NULL
);
1086 /* we get HPD via client monitors config */
1087 connector
->polled
= DRM_CONNECTOR_POLL_HPD
;
1088 encoder
->possible_crtcs
= 1 << num_output
;
1089 drm_connector_attach_encoder(&qxl_output
->base
,
1091 drm_encoder_helper_add(encoder
, &qxl_enc_helper_funcs
);
1092 drm_connector_helper_add(connector
, &qxl_connector_helper_funcs
);
1094 drm_object_attach_property(&connector
->base
,
1095 qdev
->hotplug_mode_update_property
, 0);
1096 drm_object_attach_property(&connector
->base
,
1097 dev
->mode_config
.suggested_x_property
, 0);
1098 drm_object_attach_property(&connector
->base
,
1099 dev
->mode_config
.suggested_y_property
, 0);
1103 static struct drm_framebuffer
*
1104 qxl_user_framebuffer_create(struct drm_device
*dev
,
1105 struct drm_file
*file_priv
,
1106 const struct drm_mode_fb_cmd2
*mode_cmd
)
1108 struct drm_gem_object
*obj
;
1109 struct qxl_framebuffer
*qxl_fb
;
1112 obj
= drm_gem_object_lookup(file_priv
, mode_cmd
->handles
[0]);
1116 qxl_fb
= kzalloc(sizeof(*qxl_fb
), GFP_KERNEL
);
1120 ret
= qxl_framebuffer_init(dev
, qxl_fb
, mode_cmd
, obj
, &qxl_fb_funcs
);
1123 drm_gem_object_put_unlocked(obj
);
1127 return &qxl_fb
->base
;
1130 static const struct drm_mode_config_funcs qxl_mode_funcs
= {
1131 .fb_create
= qxl_user_framebuffer_create
,
1132 .atomic_check
= drm_atomic_helper_check
,
1133 .atomic_commit
= drm_atomic_helper_commit
,
1136 int qxl_create_monitors_object(struct qxl_device
*qdev
)
1139 struct drm_gem_object
*gobj
;
1140 int max_allowed
= qxl_num_crtc
;
1141 int monitors_config_size
= sizeof(struct qxl_monitors_config
) +
1142 max_allowed
* sizeof(struct qxl_head
);
1144 ret
= qxl_gem_object_create(qdev
, monitors_config_size
, 0,
1145 QXL_GEM_DOMAIN_VRAM
,
1146 false, false, NULL
, &gobj
);
1148 DRM_ERROR("%s: failed to create gem ret=%d\n", __func__
, ret
);
1151 qdev
->monitors_config_bo
= gem_to_qxl_bo(gobj
);
1153 ret
= qxl_bo_pin(qdev
->monitors_config_bo
, QXL_GEM_DOMAIN_VRAM
, NULL
);
1157 qxl_bo_kmap(qdev
->monitors_config_bo
, NULL
);
1159 qdev
->monitors_config
= qdev
->monitors_config_bo
->kptr
;
1160 qdev
->ram_header
->monitors_config
=
1161 qxl_bo_physical_address(qdev
, qdev
->monitors_config_bo
, 0);
1163 memset(qdev
->monitors_config
, 0, monitors_config_size
);
1164 qdev
->monitors_config
->max_allowed
= max_allowed
;
1168 int qxl_destroy_monitors_object(struct qxl_device
*qdev
)
1172 qdev
->monitors_config
= NULL
;
1173 qdev
->ram_header
->monitors_config
= 0;
1175 qxl_bo_kunmap(qdev
->monitors_config_bo
);
1176 ret
= qxl_bo_unpin(qdev
->monitors_config_bo
);
1180 qxl_bo_unref(&qdev
->monitors_config_bo
);
1184 int qxl_modeset_init(struct qxl_device
*qdev
)
1189 drm_mode_config_init(&qdev
->ddev
);
1191 ret
= qxl_create_monitors_object(qdev
);
1195 qdev
->ddev
.mode_config
.funcs
= (void *)&qxl_mode_funcs
;
1197 /* modes will be validated against the framebuffer size */
1198 qdev
->ddev
.mode_config
.min_width
= 0;
1199 qdev
->ddev
.mode_config
.min_height
= 0;
1200 qdev
->ddev
.mode_config
.max_width
= 8192;
1201 qdev
->ddev
.mode_config
.max_height
= 8192;
1203 qdev
->ddev
.mode_config
.fb_base
= qdev
->vram_base
;
1205 drm_mode_create_suggested_offset_properties(&qdev
->ddev
);
1206 qxl_mode_create_hotplug_mode_update_property(qdev
);
1208 for (i
= 0 ; i
< qxl_num_crtc
; ++i
) {
1209 qdev_crtc_init(&qdev
->ddev
, i
);
1210 qdev_output_init(&qdev
->ddev
, i
);
1213 qxl_display_read_client_monitors_config(qdev
);
1214 qdev
->mode_info
.mode_config_initialized
= true;
1216 drm_mode_config_reset(&qdev
->ddev
);
1218 /* primary surface must be created by this point, to allow
1219 * issuing command queue commands and having them read by
1221 qxl_fbdev_init(qdev
);
1225 void qxl_modeset_fini(struct qxl_device
*qdev
)
1227 qxl_fbdev_fini(qdev
);
1229 qxl_destroy_monitors_object(qdev
);
1230 if (qdev
->mode_info
.mode_config_initialized
) {
1231 drm_mode_config_cleanup(&qdev
->ddev
);
1232 qdev
->mode_info
.mode_config_initialized
= false;