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
27 #include <linux/crc32.h>
30 #include "qxl_object.h"
31 #include "drm_crtc_helper.h"
32 #include <drm/drm_plane_helper.h>
34 static bool qxl_head_enabled(struct qxl_head
*head
)
36 return head
->width
&& head
->height
;
39 void qxl_alloc_client_monitors_config(struct qxl_device
*qdev
, unsigned count
)
41 if (qdev
->client_monitors_config
&&
42 count
> qdev
->client_monitors_config
->count
) {
43 kfree(qdev
->client_monitors_config
);
44 qdev
->client_monitors_config
= NULL
;
46 if (!qdev
->client_monitors_config
) {
47 qdev
->client_monitors_config
= kzalloc(
48 sizeof(struct qxl_monitors_config
) +
49 sizeof(struct qxl_head
) * count
, GFP_KERNEL
);
50 if (!qdev
->client_monitors_config
) {
52 "%s: allocation failure for %u heads\n",
57 qdev
->client_monitors_config
->count
= count
;
60 static int qxl_display_copy_rom_client_monitors_config(struct qxl_device
*qdev
)
66 num_monitors
= qdev
->rom
->client_monitors_config
.count
;
67 crc
= crc32(0, (const uint8_t *)&qdev
->rom
->client_monitors_config
,
68 sizeof(qdev
->rom
->client_monitors_config
));
69 if (crc
!= qdev
->rom
->client_monitors_config_crc
) {
70 qxl_io_log(qdev
, "crc mismatch: have %X (%zd) != %X\n", crc
,
71 sizeof(qdev
->rom
->client_monitors_config
),
72 qdev
->rom
->client_monitors_config_crc
);
75 if (num_monitors
> qdev
->monitors_config
->max_allowed
) {
76 DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
77 qdev
->monitors_config
->max_allowed
, num_monitors
);
78 num_monitors
= qdev
->monitors_config
->max_allowed
;
80 num_monitors
= qdev
->rom
->client_monitors_config
.count
;
82 qxl_alloc_client_monitors_config(qdev
, num_monitors
);
83 /* we copy max from the client but it isn't used */
84 qdev
->client_monitors_config
->max_allowed
=
85 qdev
->monitors_config
->max_allowed
;
86 for (i
= 0 ; i
< qdev
->client_monitors_config
->count
; ++i
) {
87 struct qxl_urect
*c_rect
=
88 &qdev
->rom
->client_monitors_config
.heads
[i
];
89 struct qxl_head
*client_head
=
90 &qdev
->client_monitors_config
->heads
[i
];
91 client_head
->x
= c_rect
->left
;
92 client_head
->y
= c_rect
->top
;
93 client_head
->width
= c_rect
->right
- c_rect
->left
;
94 client_head
->height
= c_rect
->bottom
- c_rect
->top
;
95 client_head
->surface_id
= 0;
97 client_head
->flags
= 0;
98 DRM_DEBUG_KMS("read %dx%d+%d+%d\n", client_head
->width
, client_head
->height
,
99 client_head
->x
, client_head
->y
);
104 static void qxl_update_offset_props(struct qxl_device
*qdev
)
106 struct drm_device
*dev
= qdev
->ddev
;
107 struct drm_connector
*connector
;
108 struct qxl_output
*output
;
109 struct qxl_head
*head
;
111 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
112 output
= drm_connector_to_qxl_output(connector
);
114 head
= &qdev
->client_monitors_config
->heads
[output
->index
];
116 drm_object_property_set_value(&connector
->base
,
117 dev
->mode_config
.suggested_x_property
, head
->x
);
118 drm_object_property_set_value(&connector
->base
,
119 dev
->mode_config
.suggested_y_property
, head
->y
);
123 void qxl_display_read_client_monitors_config(struct qxl_device
*qdev
)
126 struct drm_device
*dev
= qdev
->ddev
;
127 while (qxl_display_copy_rom_client_monitors_config(qdev
)) {
128 qxl_io_log(qdev
, "failed crc check for client_monitors_config,"
132 drm_modeset_lock_all(dev
);
133 qxl_update_offset_props(qdev
);
134 drm_modeset_unlock_all(dev
);
135 if (!drm_helper_hpd_irq_event(qdev
->ddev
)) {
136 /* notify that the monitor configuration changed, to
137 adjust at the arbitrary resolution */
138 drm_kms_helper_hotplug_event(qdev
->ddev
);
142 static int qxl_add_monitors_config_modes(struct drm_connector
*connector
,
146 struct drm_device
*dev
= connector
->dev
;
147 struct qxl_device
*qdev
= dev
->dev_private
;
148 struct qxl_output
*output
= drm_connector_to_qxl_output(connector
);
149 int h
= output
->index
;
150 struct drm_display_mode
*mode
= NULL
;
151 struct qxl_head
*head
;
153 if (!qdev
->client_monitors_config
)
155 head
= &qdev
->client_monitors_config
->heads
[h
];
157 mode
= drm_cvt_mode(dev
, head
->width
, head
->height
, 60, false, false,
159 mode
->type
|= DRM_MODE_TYPE_PREFERRED
;
160 *pwidth
= head
->width
;
161 *pheight
= head
->height
;
162 drm_mode_probed_add(connector
, mode
);
163 /* remember the last custom size for mode validation */
164 qdev
->monitors_config_width
= mode
->hdisplay
;
165 qdev
->monitors_config_height
= mode
->vdisplay
;
169 static struct mode_size
{
192 static int qxl_add_common_modes(struct drm_connector
*connector
,
196 struct drm_device
*dev
= connector
->dev
;
197 struct drm_display_mode
*mode
= NULL
;
199 for (i
= 0; i
< ARRAY_SIZE(common_modes
); i
++) {
200 mode
= drm_cvt_mode(dev
, common_modes
[i
].w
, common_modes
[i
].h
,
201 60, false, false, false);
202 if (common_modes
[i
].w
== pwidth
&& common_modes
[i
].h
== pheight
)
203 mode
->type
|= DRM_MODE_TYPE_PREFERRED
;
204 drm_mode_probed_add(connector
, mode
);
209 static void qxl_crtc_destroy(struct drm_crtc
*crtc
)
211 struct qxl_crtc
*qxl_crtc
= to_qxl_crtc(crtc
);
213 drm_crtc_cleanup(crtc
);
214 qxl_bo_unref(&qxl_crtc
->cursor_bo
);
218 static int qxl_crtc_page_flip(struct drm_crtc
*crtc
,
219 struct drm_framebuffer
*fb
,
220 struct drm_pending_vblank_event
*event
,
221 uint32_t page_flip_flags
)
223 struct drm_device
*dev
= crtc
->dev
;
224 struct qxl_device
*qdev
= dev
->dev_private
;
225 struct qxl_framebuffer
*qfb_src
= to_qxl_framebuffer(fb
);
226 struct qxl_framebuffer
*qfb_old
= to_qxl_framebuffer(crtc
->primary
->fb
);
227 struct qxl_bo
*bo_old
= gem_to_qxl_bo(qfb_old
->obj
);
228 struct qxl_bo
*bo
= gem_to_qxl_bo(qfb_src
->obj
);
230 struct drm_clip_rect norect
= {
237 int one_clip_rect
= 1;
240 crtc
->primary
->fb
= fb
;
241 bo_old
->is_primary
= false;
242 bo
->is_primary
= true;
244 ret
= qxl_bo_reserve(bo
, false);
247 ret
= qxl_bo_pin(bo
, bo
->type
, NULL
);
248 qxl_bo_unreserve(bo
);
252 qxl_draw_dirty_fb(qdev
, qfb_src
, bo
, 0, 0,
253 &norect
, one_clip_rect
, inc
);
255 drm_crtc_vblank_get(crtc
);
258 spin_lock_irqsave(&dev
->event_lock
, flags
);
259 drm_crtc_send_vblank_event(crtc
, event
);
260 spin_unlock_irqrestore(&dev
->event_lock
, flags
);
262 drm_crtc_vblank_put(crtc
);
264 ret
= qxl_bo_reserve(bo
, false);
267 qxl_bo_unreserve(bo
);
274 qxl_hide_cursor(struct qxl_device
*qdev
)
276 struct qxl_release
*release
;
277 struct qxl_cursor_cmd
*cmd
;
280 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
), QXL_RELEASE_CURSOR_CMD
,
285 ret
= qxl_release_reserve_list(release
, true);
287 qxl_release_free(qdev
, release
);
291 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
292 cmd
->type
= QXL_CURSOR_HIDE
;
293 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
295 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
296 qxl_release_fence_buffer_objects(release
);
300 static int qxl_crtc_apply_cursor(struct drm_crtc
*crtc
)
302 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
303 struct drm_device
*dev
= crtc
->dev
;
304 struct qxl_device
*qdev
= dev
->dev_private
;
305 struct qxl_cursor_cmd
*cmd
;
306 struct qxl_release
*release
;
309 if (!qcrtc
->cursor_bo
)
312 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
313 QXL_RELEASE_CURSOR_CMD
,
318 ret
= qxl_release_list_add(release
, qcrtc
->cursor_bo
);
320 goto out_free_release
;
322 ret
= qxl_release_reserve_list(release
, false);
324 goto out_free_release
;
326 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
327 cmd
->type
= QXL_CURSOR_SET
;
328 cmd
->u
.set
.position
.x
= qcrtc
->cur_x
+ qcrtc
->hot_spot_x
;
329 cmd
->u
.set
.position
.y
= qcrtc
->cur_y
+ qcrtc
->hot_spot_y
;
331 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
, qcrtc
->cursor_bo
, 0);
333 cmd
->u
.set
.visible
= 1;
334 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
336 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
337 qxl_release_fence_buffer_objects(release
);
342 qxl_release_free(qdev
, release
);
346 static int qxl_crtc_cursor_set2(struct drm_crtc
*crtc
,
347 struct drm_file
*file_priv
,
350 uint32_t height
, int32_t hot_x
, int32_t hot_y
)
352 struct drm_device
*dev
= crtc
->dev
;
353 struct qxl_device
*qdev
= dev
->dev_private
;
354 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
355 struct drm_gem_object
*obj
;
356 struct qxl_cursor
*cursor
;
357 struct qxl_cursor_cmd
*cmd
;
358 struct qxl_bo
*cursor_bo
, *user_bo
;
359 struct qxl_release
*release
;
365 return qxl_hide_cursor(qdev
);
367 obj
= drm_gem_object_lookup(file_priv
, handle
);
369 DRM_ERROR("cannot find cursor object\n");
373 user_bo
= gem_to_qxl_bo(obj
);
375 ret
= qxl_bo_reserve(user_bo
, false);
379 ret
= qxl_bo_pin(user_bo
, QXL_GEM_DOMAIN_CPU
, NULL
);
380 qxl_bo_unreserve(user_bo
);
384 ret
= qxl_bo_kmap(user_bo
, &user_ptr
);
388 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
389 QXL_RELEASE_CURSOR_CMD
,
394 ret
= qxl_alloc_bo_reserved(qdev
, release
, sizeof(struct qxl_cursor
) + size
,
397 goto out_free_release
;
399 ret
= qxl_release_reserve_list(release
, false);
403 ret
= qxl_bo_kmap(cursor_bo
, (void **)&cursor
);
407 cursor
->header
.unique
= 0;
408 cursor
->header
.type
= SPICE_CURSOR_TYPE_ALPHA
;
409 cursor
->header
.width
= 64;
410 cursor
->header
.height
= 64;
411 cursor
->header
.hot_spot_x
= hot_x
;
412 cursor
->header
.hot_spot_y
= hot_y
;
413 cursor
->data_size
= size
;
414 cursor
->chunk
.next_chunk
= 0;
415 cursor
->chunk
.prev_chunk
= 0;
416 cursor
->chunk
.data_size
= size
;
418 memcpy(cursor
->chunk
.data
, user_ptr
, size
);
420 qxl_bo_kunmap(cursor_bo
);
422 qxl_bo_kunmap(user_bo
);
424 qcrtc
->cur_x
+= qcrtc
->hot_spot_x
- hot_x
;
425 qcrtc
->cur_y
+= qcrtc
->hot_spot_y
- hot_y
;
426 qcrtc
->hot_spot_x
= hot_x
;
427 qcrtc
->hot_spot_y
= hot_y
;
429 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
430 cmd
->type
= QXL_CURSOR_SET
;
431 cmd
->u
.set
.position
.x
= qcrtc
->cur_x
+ qcrtc
->hot_spot_x
;
432 cmd
->u
.set
.position
.y
= qcrtc
->cur_y
+ qcrtc
->hot_spot_y
;
434 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
, cursor_bo
, 0);
436 cmd
->u
.set
.visible
= 1;
437 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
439 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
440 qxl_release_fence_buffer_objects(release
);
442 /* finish with the userspace bo */
443 ret
= qxl_bo_reserve(user_bo
, false);
445 qxl_bo_unpin(user_bo
);
446 qxl_bo_unreserve(user_bo
);
448 drm_gem_object_unreference_unlocked(obj
);
450 qxl_bo_unref (&qcrtc
->cursor_bo
);
451 qcrtc
->cursor_bo
= cursor_bo
;
456 qxl_release_backoff_reserve_list(release
);
458 qxl_bo_unref(&cursor_bo
);
460 qxl_release_free(qdev
, release
);
462 qxl_bo_kunmap(user_bo
);
464 qxl_bo_unpin(user_bo
);
466 drm_gem_object_unreference_unlocked(obj
);
470 static int qxl_crtc_cursor_move(struct drm_crtc
*crtc
,
473 struct drm_device
*dev
= crtc
->dev
;
474 struct qxl_device
*qdev
= dev
->dev_private
;
475 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
476 struct qxl_release
*release
;
477 struct qxl_cursor_cmd
*cmd
;
480 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
), QXL_RELEASE_CURSOR_CMD
,
485 ret
= qxl_release_reserve_list(release
, true);
487 qxl_release_free(qdev
, release
);
494 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
495 cmd
->type
= QXL_CURSOR_MOVE
;
496 cmd
->u
.position
.x
= qcrtc
->cur_x
+ qcrtc
->hot_spot_x
;
497 cmd
->u
.position
.y
= qcrtc
->cur_y
+ qcrtc
->hot_spot_y
;
498 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
500 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
501 qxl_release_fence_buffer_objects(release
);
507 static const struct drm_crtc_funcs qxl_crtc_funcs
= {
508 .cursor_set2
= qxl_crtc_cursor_set2
,
509 .cursor_move
= qxl_crtc_cursor_move
,
510 .set_config
= drm_crtc_helper_set_config
,
511 .destroy
= qxl_crtc_destroy
,
512 .page_flip
= qxl_crtc_page_flip
,
515 void qxl_user_framebuffer_destroy(struct drm_framebuffer
*fb
)
517 struct qxl_framebuffer
*qxl_fb
= to_qxl_framebuffer(fb
);
519 drm_gem_object_unreference_unlocked(qxl_fb
->obj
);
520 drm_framebuffer_cleanup(fb
);
524 static int qxl_framebuffer_surface_dirty(struct drm_framebuffer
*fb
,
525 struct drm_file
*file_priv
,
526 unsigned flags
, unsigned color
,
527 struct drm_clip_rect
*clips
,
530 /* TODO: vmwgfx where this was cribbed from had locking. Why? */
531 struct qxl_framebuffer
*qxl_fb
= to_qxl_framebuffer(fb
);
532 struct qxl_device
*qdev
= qxl_fb
->base
.dev
->dev_private
;
533 struct drm_clip_rect norect
;
537 drm_modeset_lock_all(fb
->dev
);
539 qobj
= gem_to_qxl_bo(qxl_fb
->obj
);
540 /* if we aren't primary surface ignore this */
541 if (!qobj
->is_primary
) {
542 drm_modeset_unlock_all(fb
->dev
);
549 norect
.x1
= norect
.y1
= 0;
550 norect
.x2
= fb
->width
;
551 norect
.y2
= fb
->height
;
552 } else if (flags
& DRM_MODE_FB_DIRTY_ANNOTATE_COPY
) {
554 inc
= 2; /* skip source rects */
557 qxl_draw_dirty_fb(qdev
, qxl_fb
, qobj
, flags
, color
,
558 clips
, num_clips
, inc
);
560 drm_modeset_unlock_all(fb
->dev
);
565 static const struct drm_framebuffer_funcs qxl_fb_funcs
= {
566 .destroy
= qxl_user_framebuffer_destroy
,
567 .dirty
= qxl_framebuffer_surface_dirty
,
569 * .create_handle = qxl_user_framebuffer_create_handle, */
573 qxl_framebuffer_init(struct drm_device
*dev
,
574 struct qxl_framebuffer
*qfb
,
575 const struct drm_mode_fb_cmd2
*mode_cmd
,
576 struct drm_gem_object
*obj
,
577 const struct drm_framebuffer_funcs
*funcs
)
582 ret
= drm_framebuffer_init(dev
, &qfb
->base
, funcs
);
587 drm_helper_mode_fill_fb_struct(&qfb
->base
, mode_cmd
);
591 static void qxl_crtc_dpms(struct drm_crtc
*crtc
, int mode
)
595 static bool qxl_crtc_mode_fixup(struct drm_crtc
*crtc
,
596 const struct drm_display_mode
*mode
,
597 struct drm_display_mode
*adjusted_mode
)
599 struct drm_device
*dev
= crtc
->dev
;
600 struct qxl_device
*qdev
= dev
->dev_private
;
602 qxl_io_log(qdev
, "%s: (%d,%d) => (%d,%d)\n",
604 mode
->hdisplay
, mode
->vdisplay
,
605 adjusted_mode
->hdisplay
,
606 adjusted_mode
->vdisplay
);
611 qxl_send_monitors_config(struct qxl_device
*qdev
)
615 BUG_ON(!qdev
->ram_header
->monitors_config
);
617 if (qdev
->monitors_config
->count
== 0) {
618 qxl_io_log(qdev
, "%s: 0 monitors??\n", __func__
);
621 for (i
= 0 ; i
< qdev
->monitors_config
->count
; ++i
) {
622 struct qxl_head
*head
= &qdev
->monitors_config
->heads
[i
];
624 if (head
->y
> 8192 || head
->x
> 8192 ||
625 head
->width
> 8192 || head
->height
> 8192) {
626 DRM_ERROR("head %d wrong: %dx%d+%d+%d\n",
627 i
, head
->width
, head
->height
,
632 qxl_io_monitors_config(qdev
);
635 static void qxl_monitors_config_set(struct qxl_device
*qdev
,
637 unsigned x
, unsigned y
,
638 unsigned width
, unsigned height
,
641 DRM_DEBUG_KMS("%d:%dx%d+%d+%d\n", index
, width
, height
, x
, y
);
642 qdev
->monitors_config
->heads
[index
].x
= x
;
643 qdev
->monitors_config
->heads
[index
].y
= y
;
644 qdev
->monitors_config
->heads
[index
].width
= width
;
645 qdev
->monitors_config
->heads
[index
].height
= height
;
646 qdev
->monitors_config
->heads
[index
].surface_id
= surf_id
;
650 static int qxl_crtc_mode_set(struct drm_crtc
*crtc
,
651 struct drm_display_mode
*mode
,
652 struct drm_display_mode
*adjusted_mode
,
654 struct drm_framebuffer
*old_fb
)
656 struct drm_device
*dev
= crtc
->dev
;
657 struct qxl_device
*qdev
= dev
->dev_private
;
658 struct qxl_framebuffer
*qfb
;
659 struct qxl_bo
*bo
, *old_bo
= NULL
;
660 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
661 bool recreate_primary
= false;
664 if (!crtc
->primary
->fb
) {
665 DRM_DEBUG_KMS("No FB bound\n");
670 qfb
= to_qxl_framebuffer(old_fb
);
671 old_bo
= gem_to_qxl_bo(qfb
->obj
);
673 qfb
= to_qxl_framebuffer(crtc
->primary
->fb
);
674 bo
= gem_to_qxl_bo(qfb
->obj
);
675 DRM_DEBUG("+%d+%d (%d,%d) => (%d,%d)\n",
677 mode
->hdisplay
, mode
->vdisplay
,
678 adjusted_mode
->hdisplay
,
679 adjusted_mode
->vdisplay
);
681 if (bo
->is_primary
== false)
682 recreate_primary
= true;
684 if (bo
->surf
.stride
* bo
->surf
.height
> qdev
->vram_size
) {
685 DRM_ERROR("Mode doesn't fit in vram size (vgamem)");
689 ret
= qxl_bo_reserve(bo
, false);
692 ret
= qxl_bo_pin(bo
, bo
->type
, NULL
);
694 qxl_bo_unreserve(bo
);
697 qxl_bo_unreserve(bo
);
698 if (recreate_primary
) {
699 qxl_io_destroy_primary(qdev
);
701 "recreate primary: %dx%d,%d,%d\n",
702 bo
->surf
.width
, bo
->surf
.height
,
703 bo
->surf
.stride
, bo
->surf
.format
);
704 qxl_io_create_primary(qdev
, 0, bo
);
705 bo
->is_primary
= true;
707 ret
= qxl_crtc_apply_cursor(crtc
);
709 DRM_ERROR("could not set cursor after modeset");
714 if (bo
->is_primary
) {
715 DRM_DEBUG_KMS("setting surface_id to 0 for primary surface %d on crtc %d\n", bo
->surface_id
, qcrtc
->index
);
718 surf_id
= bo
->surface_id
;
721 if (old_bo
&& old_bo
!= bo
) {
722 old_bo
->is_primary
= false;
723 ret
= qxl_bo_reserve(old_bo
, false);
724 qxl_bo_unpin(old_bo
);
725 qxl_bo_unreserve(old_bo
);
728 qxl_monitors_config_set(qdev
, qcrtc
->index
, x
, y
,
730 mode
->vdisplay
, surf_id
);
734 static void qxl_crtc_prepare(struct drm_crtc
*crtc
)
736 DRM_DEBUG("current: %dx%d+%d+%d (%d).\n",
737 crtc
->mode
.hdisplay
, crtc
->mode
.vdisplay
,
738 crtc
->x
, crtc
->y
, crtc
->enabled
);
741 static void qxl_crtc_commit(struct drm_crtc
*crtc
)
746 static void qxl_crtc_disable(struct drm_crtc
*crtc
)
748 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
749 struct drm_device
*dev
= crtc
->dev
;
750 struct qxl_device
*qdev
= dev
->dev_private
;
751 if (crtc
->primary
->fb
) {
752 struct qxl_framebuffer
*qfb
= to_qxl_framebuffer(crtc
->primary
->fb
);
753 struct qxl_bo
*bo
= gem_to_qxl_bo(qfb
->obj
);
755 ret
= qxl_bo_reserve(bo
, false);
757 qxl_bo_unreserve(bo
);
758 crtc
->primary
->fb
= NULL
;
761 qxl_monitors_config_set(qdev
, qcrtc
->index
, 0, 0, 0, 0, 0);
763 qxl_send_monitors_config(qdev
);
766 static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs
= {
767 .dpms
= qxl_crtc_dpms
,
768 .disable
= qxl_crtc_disable
,
769 .mode_fixup
= qxl_crtc_mode_fixup
,
770 .mode_set
= qxl_crtc_mode_set
,
771 .prepare
= qxl_crtc_prepare
,
772 .commit
= qxl_crtc_commit
,
775 static int qdev_crtc_init(struct drm_device
*dev
, int crtc_id
)
777 struct qxl_crtc
*qxl_crtc
;
779 qxl_crtc
= kzalloc(sizeof(struct qxl_crtc
), GFP_KERNEL
);
783 drm_crtc_init(dev
, &qxl_crtc
->base
, &qxl_crtc_funcs
);
784 qxl_crtc
->index
= crtc_id
;
785 drm_crtc_helper_add(&qxl_crtc
->base
, &qxl_crtc_helper_funcs
);
789 static void qxl_enc_dpms(struct drm_encoder
*encoder
, int mode
)
794 static void qxl_enc_prepare(struct drm_encoder
*encoder
)
799 static void qxl_write_monitors_config_for_encoder(struct qxl_device
*qdev
,
800 struct drm_encoder
*encoder
)
803 struct qxl_output
*output
= drm_encoder_to_qxl_output(encoder
);
804 struct qxl_head
*head
;
805 struct drm_display_mode
*mode
;
808 /* TODO: ugly, do better */
810 if (!qdev
->monitors_config
||
811 qdev
->monitors_config
->max_allowed
<= i
) {
813 "head number too large or missing monitors config: %p, %d",
814 qdev
->monitors_config
,
815 qdev
->monitors_config
?
816 qdev
->monitors_config
->max_allowed
: -1);
819 if (!encoder
->crtc
) {
820 DRM_ERROR("missing crtc on encoder %p\n", encoder
);
824 DRM_DEBUG("missing for multiple monitors: no head holes\n");
825 head
= &qdev
->monitors_config
->heads
[i
];
827 if (encoder
->crtc
->enabled
) {
828 mode
= &encoder
->crtc
->mode
;
829 head
->width
= mode
->hdisplay
;
830 head
->height
= mode
->vdisplay
;
831 head
->x
= encoder
->crtc
->x
;
832 head
->y
= encoder
->crtc
->y
;
833 if (qdev
->monitors_config
->count
< i
+ 1)
834 qdev
->monitors_config
->count
= i
+ 1;
841 DRM_DEBUG_KMS("setting head %d to +%d+%d %dx%d out of %d\n",
842 i
, head
->x
, head
->y
, head
->width
, head
->height
, qdev
->monitors_config
->count
);
844 /* TODO - somewhere else to call this for multiple monitors
845 * (config_commit?) */
846 qxl_send_monitors_config(qdev
);
849 static void qxl_enc_commit(struct drm_encoder
*encoder
)
851 struct qxl_device
*qdev
= encoder
->dev
->dev_private
;
853 qxl_write_monitors_config_for_encoder(qdev
, encoder
);
857 static void qxl_enc_mode_set(struct drm_encoder
*encoder
,
858 struct drm_display_mode
*mode
,
859 struct drm_display_mode
*adjusted_mode
)
864 static int qxl_conn_get_modes(struct drm_connector
*connector
)
867 struct qxl_device
*qdev
= connector
->dev
->dev_private
;
868 unsigned pwidth
= 1024;
869 unsigned pheight
= 768;
871 DRM_DEBUG_KMS("monitors_config=%p\n", qdev
->monitors_config
);
872 /* TODO: what should we do here? only show the configured modes for the
873 * device, or allow the full list, or both? */
874 if (qdev
->monitors_config
&& qdev
->monitors_config
->count
) {
875 ret
= qxl_add_monitors_config_modes(connector
, &pwidth
, &pheight
);
879 ret
+= qxl_add_common_modes(connector
, pwidth
, pheight
);
883 static int qxl_conn_mode_valid(struct drm_connector
*connector
,
884 struct drm_display_mode
*mode
)
886 struct drm_device
*ddev
= connector
->dev
;
887 struct qxl_device
*qdev
= ddev
->dev_private
;
890 /* TODO: is this called for user defined modes? (xrandr --add-mode)
891 * TODO: check that the mode fits in the framebuffer */
893 if(qdev
->monitors_config_width
== mode
->hdisplay
&&
894 qdev
->monitors_config_height
== mode
->vdisplay
)
897 for (i
= 0; i
< ARRAY_SIZE(common_modes
); i
++) {
898 if (common_modes
[i
].w
== mode
->hdisplay
&& common_modes
[i
].h
== mode
->vdisplay
)
904 static struct drm_encoder
*qxl_best_encoder(struct drm_connector
*connector
)
906 struct qxl_output
*qxl_output
=
907 drm_connector_to_qxl_output(connector
);
910 return &qxl_output
->enc
;
914 static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs
= {
915 .dpms
= qxl_enc_dpms
,
916 .prepare
= qxl_enc_prepare
,
917 .mode_set
= qxl_enc_mode_set
,
918 .commit
= qxl_enc_commit
,
921 static const struct drm_connector_helper_funcs qxl_connector_helper_funcs
= {
922 .get_modes
= qxl_conn_get_modes
,
923 .mode_valid
= qxl_conn_mode_valid
,
924 .best_encoder
= qxl_best_encoder
,
927 static enum drm_connector_status
qxl_conn_detect(
928 struct drm_connector
*connector
,
931 struct qxl_output
*output
=
932 drm_connector_to_qxl_output(connector
);
933 struct drm_device
*ddev
= connector
->dev
;
934 struct qxl_device
*qdev
= ddev
->dev_private
;
935 bool connected
= false;
937 /* The first monitor is always connected */
938 if (!qdev
->client_monitors_config
) {
939 if (output
->index
== 0)
942 connected
= qdev
->client_monitors_config
->count
> output
->index
&&
943 qxl_head_enabled(&qdev
->client_monitors_config
->heads
[output
->index
]);
945 DRM_DEBUG("#%d connected: %d\n", output
->index
, connected
);
947 qxl_monitors_config_set(qdev
, output
->index
, 0, 0, 0, 0, 0);
949 return connected
? connector_status_connected
950 : connector_status_disconnected
;
953 static int qxl_conn_set_property(struct drm_connector
*connector
,
954 struct drm_property
*property
,
961 static void qxl_conn_destroy(struct drm_connector
*connector
)
963 struct qxl_output
*qxl_output
=
964 drm_connector_to_qxl_output(connector
);
966 drm_connector_unregister(connector
);
967 drm_connector_cleanup(connector
);
971 static const struct drm_connector_funcs qxl_connector_funcs
= {
972 .dpms
= drm_helper_connector_dpms
,
973 .detect
= qxl_conn_detect
,
974 .fill_modes
= drm_helper_probe_single_connector_modes
,
975 .set_property
= qxl_conn_set_property
,
976 .destroy
= qxl_conn_destroy
,
979 static void qxl_enc_destroy(struct drm_encoder
*encoder
)
981 drm_encoder_cleanup(encoder
);
984 static const struct drm_encoder_funcs qxl_enc_funcs
= {
985 .destroy
= qxl_enc_destroy
,
988 static int qxl_mode_create_hotplug_mode_update_property(struct qxl_device
*qdev
)
990 if (qdev
->hotplug_mode_update_property
)
993 qdev
->hotplug_mode_update_property
=
994 drm_property_create_range(qdev
->ddev
, DRM_MODE_PROP_IMMUTABLE
,
995 "hotplug_mode_update", 0, 1);
1000 static int qdev_output_init(struct drm_device
*dev
, int num_output
)
1002 struct qxl_device
*qdev
= dev
->dev_private
;
1003 struct qxl_output
*qxl_output
;
1004 struct drm_connector
*connector
;
1005 struct drm_encoder
*encoder
;
1007 qxl_output
= kzalloc(sizeof(struct qxl_output
), GFP_KERNEL
);
1011 qxl_output
->index
= num_output
;
1013 connector
= &qxl_output
->base
;
1014 encoder
= &qxl_output
->enc
;
1015 drm_connector_init(dev
, &qxl_output
->base
,
1016 &qxl_connector_funcs
, DRM_MODE_CONNECTOR_VIRTUAL
);
1018 drm_encoder_init(dev
, &qxl_output
->enc
, &qxl_enc_funcs
,
1019 DRM_MODE_ENCODER_VIRTUAL
, NULL
);
1021 /* we get HPD via client monitors config */
1022 connector
->polled
= DRM_CONNECTOR_POLL_HPD
;
1023 encoder
->possible_crtcs
= 1 << num_output
;
1024 drm_mode_connector_attach_encoder(&qxl_output
->base
,
1026 drm_encoder_helper_add(encoder
, &qxl_enc_helper_funcs
);
1027 drm_connector_helper_add(connector
, &qxl_connector_helper_funcs
);
1029 drm_object_attach_property(&connector
->base
,
1030 qdev
->hotplug_mode_update_property
, 0);
1031 drm_object_attach_property(&connector
->base
,
1032 dev
->mode_config
.suggested_x_property
, 0);
1033 drm_object_attach_property(&connector
->base
,
1034 dev
->mode_config
.suggested_y_property
, 0);
1035 drm_connector_register(connector
);
1039 static struct drm_framebuffer
*
1040 qxl_user_framebuffer_create(struct drm_device
*dev
,
1041 struct drm_file
*file_priv
,
1042 const struct drm_mode_fb_cmd2
*mode_cmd
)
1044 struct drm_gem_object
*obj
;
1045 struct qxl_framebuffer
*qxl_fb
;
1048 obj
= drm_gem_object_lookup(file_priv
, mode_cmd
->handles
[0]);
1052 qxl_fb
= kzalloc(sizeof(*qxl_fb
), GFP_KERNEL
);
1056 ret
= qxl_framebuffer_init(dev
, qxl_fb
, mode_cmd
, obj
, &qxl_fb_funcs
);
1059 drm_gem_object_unreference_unlocked(obj
);
1063 return &qxl_fb
->base
;
1066 static const struct drm_mode_config_funcs qxl_mode_funcs
= {
1067 .fb_create
= qxl_user_framebuffer_create
,
1070 int qxl_create_monitors_object(struct qxl_device
*qdev
)
1073 struct drm_gem_object
*gobj
;
1074 int max_allowed
= qxl_num_crtc
;
1075 int monitors_config_size
= sizeof(struct qxl_monitors_config
) +
1076 max_allowed
* sizeof(struct qxl_head
);
1078 ret
= qxl_gem_object_create(qdev
, monitors_config_size
, 0,
1079 QXL_GEM_DOMAIN_VRAM
,
1080 false, false, NULL
, &gobj
);
1082 DRM_ERROR("%s: failed to create gem ret=%d\n", __func__
, ret
);
1085 qdev
->monitors_config_bo
= gem_to_qxl_bo(gobj
);
1087 ret
= qxl_bo_reserve(qdev
->monitors_config_bo
, false);
1091 ret
= qxl_bo_pin(qdev
->monitors_config_bo
, QXL_GEM_DOMAIN_VRAM
, NULL
);
1093 qxl_bo_unreserve(qdev
->monitors_config_bo
);
1097 qxl_bo_unreserve(qdev
->monitors_config_bo
);
1099 qxl_bo_kmap(qdev
->monitors_config_bo
, NULL
);
1101 qdev
->monitors_config
= qdev
->monitors_config_bo
->kptr
;
1102 qdev
->ram_header
->monitors_config
=
1103 qxl_bo_physical_address(qdev
, qdev
->monitors_config_bo
, 0);
1105 memset(qdev
->monitors_config
, 0, monitors_config_size
);
1106 qdev
->monitors_config
->max_allowed
= max_allowed
;
1110 int qxl_destroy_monitors_object(struct qxl_device
*qdev
)
1114 qdev
->monitors_config
= NULL
;
1115 qdev
->ram_header
->monitors_config
= 0;
1117 qxl_bo_kunmap(qdev
->monitors_config_bo
);
1118 ret
= qxl_bo_reserve(qdev
->monitors_config_bo
, false);
1122 qxl_bo_unpin(qdev
->monitors_config_bo
);
1123 qxl_bo_unreserve(qdev
->monitors_config_bo
);
1125 qxl_bo_unref(&qdev
->monitors_config_bo
);
1129 int qxl_modeset_init(struct qxl_device
*qdev
)
1134 drm_mode_config_init(qdev
->ddev
);
1136 ret
= qxl_create_monitors_object(qdev
);
1140 qdev
->ddev
->mode_config
.funcs
= (void *)&qxl_mode_funcs
;
1142 /* modes will be validated against the framebuffer size */
1143 qdev
->ddev
->mode_config
.min_width
= 320;
1144 qdev
->ddev
->mode_config
.min_height
= 200;
1145 qdev
->ddev
->mode_config
.max_width
= 8192;
1146 qdev
->ddev
->mode_config
.max_height
= 8192;
1148 qdev
->ddev
->mode_config
.fb_base
= qdev
->vram_base
;
1150 drm_mode_create_suggested_offset_properties(qdev
->ddev
);
1151 qxl_mode_create_hotplug_mode_update_property(qdev
);
1153 for (i
= 0 ; i
< qxl_num_crtc
; ++i
) {
1154 qdev_crtc_init(qdev
->ddev
, i
);
1155 qdev_output_init(qdev
->ddev
, i
);
1158 qdev
->mode_info
.mode_config_initialized
= true;
1160 /* primary surface must be created by this point, to allow
1161 * issuing command queue commands and having them read by
1163 qxl_fbdev_init(qdev
);
1167 void qxl_modeset_fini(struct qxl_device
*qdev
)
1169 qxl_fbdev_fini(qdev
);
1171 qxl_destroy_monitors_object(qdev
);
1172 if (qdev
->mode_info
.mode_config_initialized
) {
1173 drm_mode_config_cleanup(qdev
->ddev
);
1174 qdev
->mode_info
.mode_config_initialized
= false;