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"
33 static bool qxl_head_enabled(struct qxl_head
*head
)
35 return head
->width
&& head
->height
;
38 void qxl_alloc_client_monitors_config(struct qxl_device
*qdev
, unsigned count
)
40 if (qdev
->client_monitors_config
&&
41 count
> qdev
->client_monitors_config
->count
) {
42 kfree(qdev
->client_monitors_config
);
43 qdev
->client_monitors_config
= NULL
;
45 if (!qdev
->client_monitors_config
) {
46 qdev
->client_monitors_config
= kzalloc(
47 sizeof(struct qxl_monitors_config
) +
48 sizeof(struct qxl_head
) * count
, GFP_KERNEL
);
49 if (!qdev
->client_monitors_config
) {
51 "%s: allocation failure for %u heads\n",
56 qdev
->client_monitors_config
->count
= count
;
59 static int qxl_display_copy_rom_client_monitors_config(struct qxl_device
*qdev
)
65 num_monitors
= qdev
->rom
->client_monitors_config
.count
;
66 crc
= crc32(0, (const uint8_t *)&qdev
->rom
->client_monitors_config
,
67 sizeof(qdev
->rom
->client_monitors_config
));
68 if (crc
!= qdev
->rom
->client_monitors_config_crc
) {
69 qxl_io_log(qdev
, "crc mismatch: have %X (%d) != %X\n", crc
,
70 sizeof(qdev
->rom
->client_monitors_config
),
71 qdev
->rom
->client_monitors_config_crc
);
74 if (num_monitors
> qdev
->monitors_config
->max_allowed
) {
75 DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
76 qdev
->monitors_config
->max_allowed
, num_monitors
);
77 num_monitors
= qdev
->monitors_config
->max_allowed
;
79 num_monitors
= qdev
->rom
->client_monitors_config
.count
;
81 qxl_alloc_client_monitors_config(qdev
, num_monitors
);
82 /* we copy max from the client but it isn't used */
83 qdev
->client_monitors_config
->max_allowed
=
84 qdev
->monitors_config
->max_allowed
;
85 for (i
= 0 ; i
< qdev
->client_monitors_config
->count
; ++i
) {
86 struct qxl_urect
*c_rect
=
87 &qdev
->rom
->client_monitors_config
.heads
[i
];
88 struct qxl_head
*client_head
=
89 &qdev
->client_monitors_config
->heads
[i
];
90 client_head
->x
= c_rect
->left
;
91 client_head
->y
= c_rect
->top
;
92 client_head
->width
= c_rect
->right
- c_rect
->left
;
93 client_head
->height
= c_rect
->bottom
- c_rect
->top
;
94 client_head
->surface_id
= 0;
96 client_head
->flags
= 0;
97 DRM_DEBUG_KMS("read %dx%d+%d+%d\n", client_head
->width
, client_head
->height
,
98 client_head
->x
, client_head
->y
);
103 void qxl_display_read_client_monitors_config(struct qxl_device
*qdev
)
106 while (qxl_display_copy_rom_client_monitors_config(qdev
)) {
107 qxl_io_log(qdev
, "failed crc check for client_monitors_config,"
111 if (!drm_helper_hpd_irq_event(qdev
->ddev
)) {
112 /* notify that the monitor configuration changed, to
113 adjust at the arbitrary resolution */
114 drm_kms_helper_hotplug_event(qdev
->ddev
);
118 static int qxl_add_monitors_config_modes(struct drm_connector
*connector
,
122 struct drm_device
*dev
= connector
->dev
;
123 struct qxl_device
*qdev
= dev
->dev_private
;
124 struct qxl_output
*output
= drm_connector_to_qxl_output(connector
);
125 int h
= output
->index
;
126 struct drm_display_mode
*mode
= NULL
;
127 struct qxl_head
*head
;
129 if (!qdev
->client_monitors_config
)
131 head
= &qdev
->client_monitors_config
->heads
[h
];
133 mode
= drm_cvt_mode(dev
, head
->width
, head
->height
, 60, false, false,
135 mode
->type
|= DRM_MODE_TYPE_PREFERRED
;
136 *pwidth
= head
->width
;
137 *pheight
= head
->height
;
138 drm_mode_probed_add(connector
, mode
);
142 static int qxl_add_common_modes(struct drm_connector
*connector
,
146 struct drm_device
*dev
= connector
->dev
;
147 struct drm_display_mode
*mode
= NULL
;
172 for (i
= 0; i
< ARRAY_SIZE(common_modes
); i
++) {
173 if (common_modes
[i
].w
< 320 || common_modes
[i
].h
< 200)
176 mode
= drm_cvt_mode(dev
, common_modes
[i
].w
, common_modes
[i
].h
,
177 60, false, false, false);
178 if (common_modes
[i
].w
== pwidth
&& common_modes
[i
].h
== pheight
)
179 mode
->type
|= DRM_MODE_TYPE_PREFERRED
;
180 drm_mode_probed_add(connector
, mode
);
185 static void qxl_crtc_destroy(struct drm_crtc
*crtc
)
187 struct qxl_crtc
*qxl_crtc
= to_qxl_crtc(crtc
);
189 drm_crtc_cleanup(crtc
);
194 qxl_hide_cursor(struct qxl_device
*qdev
)
196 struct qxl_release
*release
;
197 struct qxl_cursor_cmd
*cmd
;
200 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
), QXL_RELEASE_CURSOR_CMD
,
205 ret
= qxl_release_reserve_list(release
, true);
207 qxl_release_free(qdev
, release
);
211 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
212 cmd
->type
= QXL_CURSOR_HIDE
;
213 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
215 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
216 qxl_release_fence_buffer_objects(release
);
220 static int qxl_crtc_cursor_set2(struct drm_crtc
*crtc
,
221 struct drm_file
*file_priv
,
224 uint32_t height
, int32_t hot_x
, int32_t hot_y
)
226 struct drm_device
*dev
= crtc
->dev
;
227 struct qxl_device
*qdev
= dev
->dev_private
;
228 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
229 struct drm_gem_object
*obj
;
230 struct qxl_cursor
*cursor
;
231 struct qxl_cursor_cmd
*cmd
;
232 struct qxl_bo
*cursor_bo
, *user_bo
;
233 struct qxl_release
*release
;
239 return qxl_hide_cursor(qdev
);
241 obj
= drm_gem_object_lookup(crtc
->dev
, file_priv
, handle
);
243 DRM_ERROR("cannot find cursor object\n");
247 user_bo
= gem_to_qxl_bo(obj
);
249 ret
= qxl_bo_reserve(user_bo
, false);
253 ret
= qxl_bo_pin(user_bo
, QXL_GEM_DOMAIN_CPU
, NULL
);
254 qxl_bo_unreserve(user_bo
);
258 ret
= qxl_bo_kmap(user_bo
, &user_ptr
);
262 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
),
263 QXL_RELEASE_CURSOR_CMD
,
268 ret
= qxl_alloc_bo_reserved(qdev
, release
, sizeof(struct qxl_cursor
) + size
,
271 goto out_free_release
;
273 ret
= qxl_release_reserve_list(release
, false);
277 ret
= qxl_bo_kmap(cursor_bo
, (void **)&cursor
);
281 cursor
->header
.unique
= 0;
282 cursor
->header
.type
= SPICE_CURSOR_TYPE_ALPHA
;
283 cursor
->header
.width
= 64;
284 cursor
->header
.height
= 64;
285 cursor
->header
.hot_spot_x
= hot_x
;
286 cursor
->header
.hot_spot_y
= hot_y
;
287 cursor
->data_size
= size
;
288 cursor
->chunk
.next_chunk
= 0;
289 cursor
->chunk
.prev_chunk
= 0;
290 cursor
->chunk
.data_size
= size
;
292 memcpy(cursor
->chunk
.data
, user_ptr
, size
);
294 qxl_bo_kunmap(cursor_bo
);
296 qxl_bo_kunmap(user_bo
);
298 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
299 cmd
->type
= QXL_CURSOR_SET
;
300 cmd
->u
.set
.position
.x
= qcrtc
->cur_x
;
301 cmd
->u
.set
.position
.y
= qcrtc
->cur_y
;
303 cmd
->u
.set
.shape
= qxl_bo_physical_address(qdev
, cursor_bo
, 0);
305 cmd
->u
.set
.visible
= 1;
306 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
308 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
309 qxl_release_fence_buffer_objects(release
);
311 /* finish with the userspace bo */
312 ret
= qxl_bo_reserve(user_bo
, false);
314 qxl_bo_unpin(user_bo
);
315 qxl_bo_unreserve(user_bo
);
317 drm_gem_object_unreference_unlocked(obj
);
319 qxl_bo_unref(&cursor_bo
);
324 qxl_release_backoff_reserve_list(release
);
326 qxl_bo_unref(&cursor_bo
);
328 qxl_release_free(qdev
, release
);
330 qxl_bo_kunmap(user_bo
);
332 qxl_bo_unpin(user_bo
);
334 drm_gem_object_unreference_unlocked(obj
);
338 static int qxl_crtc_cursor_move(struct drm_crtc
*crtc
,
341 struct drm_device
*dev
= crtc
->dev
;
342 struct qxl_device
*qdev
= dev
->dev_private
;
343 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
344 struct qxl_release
*release
;
345 struct qxl_cursor_cmd
*cmd
;
348 ret
= qxl_alloc_release_reserved(qdev
, sizeof(*cmd
), QXL_RELEASE_CURSOR_CMD
,
353 ret
= qxl_release_reserve_list(release
, true);
355 qxl_release_free(qdev
, release
);
362 cmd
= (struct qxl_cursor_cmd
*)qxl_release_map(qdev
, release
);
363 cmd
->type
= QXL_CURSOR_MOVE
;
364 cmd
->u
.position
.x
= qcrtc
->cur_x
;
365 cmd
->u
.position
.y
= qcrtc
->cur_y
;
366 qxl_release_unmap(qdev
, release
, &cmd
->release_info
);
368 qxl_push_cursor_ring_release(qdev
, release
, QXL_CMD_CURSOR
, false);
369 qxl_release_fence_buffer_objects(release
);
375 static const struct drm_crtc_funcs qxl_crtc_funcs
= {
376 .cursor_set2
= qxl_crtc_cursor_set2
,
377 .cursor_move
= qxl_crtc_cursor_move
,
378 .set_config
= drm_crtc_helper_set_config
,
379 .destroy
= qxl_crtc_destroy
,
382 static void qxl_user_framebuffer_destroy(struct drm_framebuffer
*fb
)
384 struct qxl_framebuffer
*qxl_fb
= to_qxl_framebuffer(fb
);
387 drm_gem_object_unreference_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 qobj
= gem_to_qxl_bo(qxl_fb
->obj
);
406 /* if we aren't primary surface ignore this */
407 if (!qobj
->is_primary
)
413 norect
.x1
= norect
.y1
= 0;
414 norect
.x2
= fb
->width
;
415 norect
.y2
= fb
->height
;
416 } else if (flags
& DRM_MODE_FB_DIRTY_ANNOTATE_COPY
) {
418 inc
= 2; /* skip source rects */
421 qxl_draw_dirty_fb(qdev
, qxl_fb
, qobj
, flags
, color
,
422 clips
, num_clips
, inc
);
426 static const struct drm_framebuffer_funcs qxl_fb_funcs
= {
427 .destroy
= qxl_user_framebuffer_destroy
,
428 .dirty
= qxl_framebuffer_surface_dirty
,
430 * .create_handle = qxl_user_framebuffer_create_handle, */
434 qxl_framebuffer_init(struct drm_device
*dev
,
435 struct qxl_framebuffer
*qfb
,
436 struct drm_mode_fb_cmd2
*mode_cmd
,
437 struct drm_gem_object
*obj
)
442 ret
= drm_framebuffer_init(dev
, &qfb
->base
, &qxl_fb_funcs
);
447 drm_helper_mode_fill_fb_struct(&qfb
->base
, mode_cmd
);
451 static void qxl_crtc_dpms(struct drm_crtc
*crtc
, int mode
)
455 static bool qxl_crtc_mode_fixup(struct drm_crtc
*crtc
,
456 const struct drm_display_mode
*mode
,
457 struct drm_display_mode
*adjusted_mode
)
459 struct drm_device
*dev
= crtc
->dev
;
460 struct qxl_device
*qdev
= dev
->dev_private
;
462 qxl_io_log(qdev
, "%s: (%d,%d) => (%d,%d)\n",
464 mode
->hdisplay
, mode
->vdisplay
,
465 adjusted_mode
->hdisplay
,
466 adjusted_mode
->vdisplay
);
471 qxl_send_monitors_config(struct qxl_device
*qdev
)
475 BUG_ON(!qdev
->ram_header
->monitors_config
);
477 if (qdev
->monitors_config
->count
== 0) {
478 qxl_io_log(qdev
, "%s: 0 monitors??\n", __func__
);
481 for (i
= 0 ; i
< qdev
->monitors_config
->count
; ++i
) {
482 struct qxl_head
*head
= &qdev
->monitors_config
->heads
[i
];
484 if (head
->y
> 8192 || head
->x
> 8192 ||
485 head
->width
> 8192 || head
->height
> 8192) {
486 DRM_ERROR("head %d wrong: %dx%d+%d+%d\n",
487 i
, head
->width
, head
->height
,
492 qxl_io_monitors_config(qdev
);
495 static void qxl_monitors_config_set(struct qxl_device
*qdev
,
497 unsigned x
, unsigned y
,
498 unsigned width
, unsigned height
,
501 DRM_DEBUG_KMS("%d:%dx%d+%d+%d\n", index
, width
, height
, x
, y
);
502 qdev
->monitors_config
->heads
[index
].x
= x
;
503 qdev
->monitors_config
->heads
[index
].y
= y
;
504 qdev
->monitors_config
->heads
[index
].width
= width
;
505 qdev
->monitors_config
->heads
[index
].height
= height
;
506 qdev
->monitors_config
->heads
[index
].surface_id
= surf_id
;
510 static int qxl_crtc_mode_set(struct drm_crtc
*crtc
,
511 struct drm_display_mode
*mode
,
512 struct drm_display_mode
*adjusted_mode
,
514 struct drm_framebuffer
*old_fb
)
516 struct drm_device
*dev
= crtc
->dev
;
517 struct qxl_device
*qdev
= dev
->dev_private
;
518 struct qxl_mode
*m
= (void *)mode
->private;
519 struct qxl_framebuffer
*qfb
;
520 struct qxl_bo
*bo
, *old_bo
= NULL
;
521 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
522 uint32_t width
, height
, base_offset
;
523 bool recreate_primary
= false;
527 DRM_DEBUG_KMS("No FB bound\n");
532 qfb
= to_qxl_framebuffer(old_fb
);
533 old_bo
= gem_to_qxl_bo(qfb
->obj
);
535 qfb
= to_qxl_framebuffer(crtc
->fb
);
536 bo
= gem_to_qxl_bo(qfb
->obj
);
538 /* and do we care? */
539 DRM_DEBUG("%dx%d: not a native mode\n", x
, y
);
541 DRM_DEBUG("%dx%d: qxl id %d\n",
542 mode
->hdisplay
, mode
->vdisplay
, m
->id
);
543 DRM_DEBUG("+%d+%d (%d,%d) => (%d,%d)\n",
545 mode
->hdisplay
, mode
->vdisplay
,
546 adjusted_mode
->hdisplay
,
547 adjusted_mode
->vdisplay
);
549 if (qcrtc
->index
== 0)
550 recreate_primary
= true;
552 width
= mode
->hdisplay
;
553 height
= mode
->vdisplay
;
556 ret
= qxl_bo_reserve(bo
, false);
559 ret
= qxl_bo_pin(bo
, bo
->type
, NULL
);
561 qxl_bo_unreserve(bo
);
564 qxl_bo_unreserve(bo
);
565 if (recreate_primary
) {
566 qxl_io_destroy_primary(qdev
);
568 "recreate primary: %dx%d (was %dx%d,%d,%d)\n",
569 width
, height
, bo
->surf
.width
,
570 bo
->surf
.height
, bo
->surf
.stride
, bo
->surf
.format
);
571 qxl_io_create_primary(qdev
, base_offset
, bo
);
572 bo
->is_primary
= true;
575 surf_id
= bo
->surface_id
;
578 if (old_bo
&& old_bo
!= bo
) {
579 old_bo
->is_primary
= false;
580 ret
= qxl_bo_reserve(old_bo
, false);
581 qxl_bo_unpin(old_bo
);
582 qxl_bo_unreserve(old_bo
);
585 qxl_monitors_config_set(qdev
, qcrtc
->index
, x
, y
,
587 mode
->vdisplay
, surf_id
);
591 static void qxl_crtc_prepare(struct drm_crtc
*crtc
)
593 DRM_DEBUG("current: %dx%d+%d+%d (%d).\n",
594 crtc
->mode
.hdisplay
, crtc
->mode
.vdisplay
,
595 crtc
->x
, crtc
->y
, crtc
->enabled
);
598 static void qxl_crtc_commit(struct drm_crtc
*crtc
)
603 static void qxl_crtc_disable(struct drm_crtc
*crtc
)
605 struct qxl_crtc
*qcrtc
= to_qxl_crtc(crtc
);
606 struct drm_device
*dev
= crtc
->dev
;
607 struct qxl_device
*qdev
= dev
->dev_private
;
609 struct qxl_framebuffer
*qfb
= to_qxl_framebuffer(crtc
->fb
);
610 struct qxl_bo
*bo
= gem_to_qxl_bo(qfb
->obj
);
612 ret
= qxl_bo_reserve(bo
, false);
614 qxl_bo_unreserve(bo
);
618 qxl_monitors_config_set(qdev
, qcrtc
->index
, 0, 0, 0, 0, 0);
620 qxl_send_monitors_config(qdev
);
623 static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs
= {
624 .dpms
= qxl_crtc_dpms
,
625 .disable
= qxl_crtc_disable
,
626 .mode_fixup
= qxl_crtc_mode_fixup
,
627 .mode_set
= qxl_crtc_mode_set
,
628 .prepare
= qxl_crtc_prepare
,
629 .commit
= qxl_crtc_commit
,
632 static int qdev_crtc_init(struct drm_device
*dev
, int crtc_id
)
634 struct qxl_crtc
*qxl_crtc
;
636 qxl_crtc
= kzalloc(sizeof(struct qxl_crtc
), GFP_KERNEL
);
640 drm_crtc_init(dev
, &qxl_crtc
->base
, &qxl_crtc_funcs
);
641 qxl_crtc
->index
= crtc_id
;
642 drm_mode_crtc_set_gamma_size(&qxl_crtc
->base
, 256);
643 drm_crtc_helper_add(&qxl_crtc
->base
, &qxl_crtc_helper_funcs
);
647 static void qxl_enc_dpms(struct drm_encoder
*encoder
, int mode
)
652 static bool qxl_enc_mode_fixup(struct drm_encoder
*encoder
,
653 const struct drm_display_mode
*mode
,
654 struct drm_display_mode
*adjusted_mode
)
660 static void qxl_enc_prepare(struct drm_encoder
*encoder
)
665 static void qxl_write_monitors_config_for_encoder(struct qxl_device
*qdev
,
666 struct drm_encoder
*encoder
)
669 struct qxl_output
*output
= drm_encoder_to_qxl_output(encoder
);
670 struct qxl_head
*head
;
671 struct drm_display_mode
*mode
;
674 /* TODO: ugly, do better */
676 if (!qdev
->monitors_config
||
677 qdev
->monitors_config
->max_allowed
<= i
) {
679 "head number too large or missing monitors config: %p, %d",
680 qdev
->monitors_config
,
681 qdev
->monitors_config
?
682 qdev
->monitors_config
->max_allowed
: -1);
685 if (!encoder
->crtc
) {
686 DRM_ERROR("missing crtc on encoder %p\n", encoder
);
690 DRM_DEBUG("missing for multiple monitors: no head holes\n");
691 head
= &qdev
->monitors_config
->heads
[i
];
693 if (encoder
->crtc
->enabled
) {
694 mode
= &encoder
->crtc
->mode
;
695 head
->width
= mode
->hdisplay
;
696 head
->height
= mode
->vdisplay
;
697 head
->x
= encoder
->crtc
->x
;
698 head
->y
= encoder
->crtc
->y
;
699 if (qdev
->monitors_config
->count
< i
+ 1)
700 qdev
->monitors_config
->count
= i
+ 1;
707 DRM_DEBUG_KMS("setting head %d to +%d+%d %dx%d out of %d\n",
708 i
, head
->x
, head
->y
, head
->width
, head
->height
, qdev
->monitors_config
->count
);
710 /* TODO - somewhere else to call this for multiple monitors
711 * (config_commit?) */
712 qxl_send_monitors_config(qdev
);
715 static void qxl_enc_commit(struct drm_encoder
*encoder
)
717 struct qxl_device
*qdev
= encoder
->dev
->dev_private
;
719 qxl_write_monitors_config_for_encoder(qdev
, encoder
);
723 static void qxl_enc_mode_set(struct drm_encoder
*encoder
,
724 struct drm_display_mode
*mode
,
725 struct drm_display_mode
*adjusted_mode
)
730 static int qxl_conn_get_modes(struct drm_connector
*connector
)
733 struct qxl_device
*qdev
= connector
->dev
->dev_private
;
734 unsigned pwidth
= 1024;
735 unsigned pheight
= 768;
737 DRM_DEBUG_KMS("monitors_config=%p\n", qdev
->monitors_config
);
738 /* TODO: what should we do here? only show the configured modes for the
739 * device, or allow the full list, or both? */
740 if (qdev
->monitors_config
&& qdev
->monitors_config
->count
) {
741 ret
= qxl_add_monitors_config_modes(connector
, &pwidth
, &pheight
);
745 ret
+= qxl_add_common_modes(connector
, pwidth
, pheight
);
749 static int qxl_conn_mode_valid(struct drm_connector
*connector
,
750 struct drm_display_mode
*mode
)
752 /* TODO: is this called for user defined modes? (xrandr --add-mode)
753 * TODO: check that the mode fits in the framebuffer */
754 DRM_DEBUG("%s: %dx%d status=%d\n", mode
->name
, mode
->hdisplay
,
755 mode
->vdisplay
, mode
->status
);
759 static struct drm_encoder
*qxl_best_encoder(struct drm_connector
*connector
)
761 struct qxl_output
*qxl_output
=
762 drm_connector_to_qxl_output(connector
);
765 return &qxl_output
->enc
;
769 static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs
= {
770 .dpms
= qxl_enc_dpms
,
771 .mode_fixup
= qxl_enc_mode_fixup
,
772 .prepare
= qxl_enc_prepare
,
773 .mode_set
= qxl_enc_mode_set
,
774 .commit
= qxl_enc_commit
,
777 static const struct drm_connector_helper_funcs qxl_connector_helper_funcs
= {
778 .get_modes
= qxl_conn_get_modes
,
779 .mode_valid
= qxl_conn_mode_valid
,
780 .best_encoder
= qxl_best_encoder
,
783 static void qxl_conn_save(struct drm_connector
*connector
)
788 static void qxl_conn_restore(struct drm_connector
*connector
)
793 static enum drm_connector_status
qxl_conn_detect(
794 struct drm_connector
*connector
,
797 struct qxl_output
*output
=
798 drm_connector_to_qxl_output(connector
);
799 struct drm_device
*ddev
= connector
->dev
;
800 struct qxl_device
*qdev
= ddev
->dev_private
;
803 /* The first monitor is always connected */
804 connected
= (output
->index
== 0) ||
805 (qdev
->client_monitors_config
&&
806 qdev
->client_monitors_config
->count
> output
->index
&&
807 qxl_head_enabled(&qdev
->client_monitors_config
->heads
[output
->index
]));
810 return connected
? connector_status_connected
811 : connector_status_disconnected
;
814 static int qxl_conn_set_property(struct drm_connector
*connector
,
815 struct drm_property
*property
,
822 static void qxl_conn_destroy(struct drm_connector
*connector
)
824 struct qxl_output
*qxl_output
=
825 drm_connector_to_qxl_output(connector
);
827 drm_sysfs_connector_remove(connector
);
828 drm_connector_cleanup(connector
);
832 static const struct drm_connector_funcs qxl_connector_funcs
= {
833 .dpms
= drm_helper_connector_dpms
,
834 .save
= qxl_conn_save
,
835 .restore
= qxl_conn_restore
,
836 .detect
= qxl_conn_detect
,
837 .fill_modes
= drm_helper_probe_single_connector_modes
,
838 .set_property
= qxl_conn_set_property
,
839 .destroy
= qxl_conn_destroy
,
842 static void qxl_enc_destroy(struct drm_encoder
*encoder
)
844 drm_encoder_cleanup(encoder
);
847 static const struct drm_encoder_funcs qxl_enc_funcs
= {
848 .destroy
= qxl_enc_destroy
,
851 static int qdev_output_init(struct drm_device
*dev
, int num_output
)
853 struct qxl_output
*qxl_output
;
854 struct drm_connector
*connector
;
855 struct drm_encoder
*encoder
;
857 qxl_output
= kzalloc(sizeof(struct qxl_output
), GFP_KERNEL
);
861 qxl_output
->index
= num_output
;
863 connector
= &qxl_output
->base
;
864 encoder
= &qxl_output
->enc
;
865 drm_connector_init(dev
, &qxl_output
->base
,
866 &qxl_connector_funcs
, DRM_MODE_CONNECTOR_VIRTUAL
);
868 drm_encoder_init(dev
, &qxl_output
->enc
, &qxl_enc_funcs
,
869 DRM_MODE_ENCODER_VIRTUAL
);
871 /* we get HPD via client monitors config */
872 connector
->polled
= DRM_CONNECTOR_POLL_HPD
;
873 encoder
->possible_crtcs
= 1 << num_output
;
874 drm_mode_connector_attach_encoder(&qxl_output
->base
,
876 drm_encoder_helper_add(encoder
, &qxl_enc_helper_funcs
);
877 drm_connector_helper_add(connector
, &qxl_connector_helper_funcs
);
879 drm_sysfs_connector_add(connector
);
883 static struct drm_framebuffer
*
884 qxl_user_framebuffer_create(struct drm_device
*dev
,
885 struct drm_file
*file_priv
,
886 struct drm_mode_fb_cmd2
*mode_cmd
)
888 struct drm_gem_object
*obj
;
889 struct qxl_framebuffer
*qxl_fb
;
892 obj
= drm_gem_object_lookup(dev
, file_priv
, mode_cmd
->handles
[0]);
894 qxl_fb
= kzalloc(sizeof(*qxl_fb
), GFP_KERNEL
);
898 ret
= qxl_framebuffer_init(dev
, qxl_fb
, mode_cmd
, obj
);
901 drm_gem_object_unreference_unlocked(obj
);
905 return &qxl_fb
->base
;
908 static const struct drm_mode_config_funcs qxl_mode_funcs
= {
909 .fb_create
= qxl_user_framebuffer_create
,
912 int qxl_create_monitors_object(struct qxl_device
*qdev
)
915 struct drm_gem_object
*gobj
;
916 int max_allowed
= qxl_num_crtc
;
917 int monitors_config_size
= sizeof(struct qxl_monitors_config
) +
918 max_allowed
* sizeof(struct qxl_head
);
920 ret
= qxl_gem_object_create(qdev
, monitors_config_size
, 0,
922 false, false, NULL
, &gobj
);
924 DRM_ERROR("%s: failed to create gem ret=%d\n", __func__
, ret
);
927 qdev
->monitors_config_bo
= gem_to_qxl_bo(gobj
);
929 ret
= qxl_bo_reserve(qdev
->monitors_config_bo
, false);
933 ret
= qxl_bo_pin(qdev
->monitors_config_bo
, QXL_GEM_DOMAIN_VRAM
, NULL
);
935 qxl_bo_unreserve(qdev
->monitors_config_bo
);
939 qxl_bo_unreserve(qdev
->monitors_config_bo
);
941 qxl_bo_kmap(qdev
->monitors_config_bo
, NULL
);
943 qdev
->monitors_config
= qdev
->monitors_config_bo
->kptr
;
944 qdev
->ram_header
->monitors_config
=
945 qxl_bo_physical_address(qdev
, qdev
->monitors_config_bo
, 0);
947 memset(qdev
->monitors_config
, 0, monitors_config_size
);
948 qdev
->monitors_config
->max_allowed
= max_allowed
;
952 int qxl_destroy_monitors_object(struct qxl_device
*qdev
)
956 qdev
->monitors_config
= NULL
;
957 qdev
->ram_header
->monitors_config
= 0;
959 qxl_bo_kunmap(qdev
->monitors_config_bo
);
960 ret
= qxl_bo_reserve(qdev
->monitors_config_bo
, false);
964 qxl_bo_unpin(qdev
->monitors_config_bo
);
965 qxl_bo_unreserve(qdev
->monitors_config_bo
);
967 qxl_bo_unref(&qdev
->monitors_config_bo
);
971 int qxl_modeset_init(struct qxl_device
*qdev
)
976 drm_mode_config_init(qdev
->ddev
);
978 ret
= qxl_create_monitors_object(qdev
);
982 qdev
->ddev
->mode_config
.funcs
= (void *)&qxl_mode_funcs
;
984 /* modes will be validated against the framebuffer size */
985 qdev
->ddev
->mode_config
.min_width
= 320;
986 qdev
->ddev
->mode_config
.min_height
= 200;
987 qdev
->ddev
->mode_config
.max_width
= 8192;
988 qdev
->ddev
->mode_config
.max_height
= 8192;
990 qdev
->ddev
->mode_config
.fb_base
= qdev
->vram_base
;
991 for (i
= 0 ; i
< qxl_num_crtc
; ++i
) {
992 qdev_crtc_init(qdev
->ddev
, i
);
993 qdev_output_init(qdev
->ddev
, i
);
996 qdev
->mode_info
.mode_config_initialized
= true;
998 /* primary surface must be created by this point, to allow
999 * issuing command queue commands and having them read by
1001 qxl_fbdev_init(qdev
);
1005 void qxl_modeset_fini(struct qxl_device
*qdev
)
1007 qxl_fbdev_fini(qdev
);
1009 qxl_destroy_monitors_object(qdev
);
1010 if (qdev
->mode_info
.mode_config_initialized
) {
1011 drm_mode_config_cleanup(qdev
->ddev
);
1012 qdev
->mode_info
.mode_config_initialized
= false;