diff options
Diffstat (limited to 'drivers/gpu/drm/virtio')
-rw-r--r-- | drivers/gpu/drm/virtio/virtgpu_display.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/virtio/virtgpu_drv.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/virtio/virtgpu_drv.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/virtio/virtgpu_kms.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/virtio/virtgpu_vq.c | 67 |
5 files changed, 91 insertions, 0 deletions
diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 8f8fed471e34..b5580b11a063 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c | |||
@@ -169,6 +169,12 @@ static int virtio_gpu_conn_get_modes(struct drm_connector *connector) | |||
169 | struct drm_display_mode *mode = NULL; | 169 | struct drm_display_mode *mode = NULL; |
170 | int count, width, height; | 170 | int count, width, height; |
171 | 171 | ||
172 | if (output->edid) { | ||
173 | count = drm_add_edid_modes(connector, output->edid); | ||
174 | if (count) | ||
175 | return count; | ||
176 | } | ||
177 | |||
172 | width = le32_to_cpu(output->info.r.width); | 178 | width = le32_to_cpu(output->info.r.width); |
173 | height = le32_to_cpu(output->info.r.height); | 179 | height = le32_to_cpu(output->info.r.height); |
174 | count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); | 180 | count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); |
@@ -287,6 +293,8 @@ static int vgdev_output_init(struct virtio_gpu_device *vgdev, int index) | |||
287 | drm_connector_init(dev, connector, &virtio_gpu_connector_funcs, | 293 | drm_connector_init(dev, connector, &virtio_gpu_connector_funcs, |
288 | DRM_MODE_CONNECTOR_VIRTUAL); | 294 | DRM_MODE_CONNECTOR_VIRTUAL); |
289 | drm_connector_helper_add(connector, &virtio_gpu_conn_helper_funcs); | 295 | drm_connector_helper_add(connector, &virtio_gpu_conn_helper_funcs); |
296 | if (vgdev->has_edid) | ||
297 | drm_connector_attach_edid_property(connector); | ||
290 | 298 | ||
291 | drm_encoder_init(dev, encoder, &virtio_gpu_enc_funcs, | 299 | drm_encoder_init(dev, encoder, &virtio_gpu_enc_funcs, |
292 | DRM_MODE_ENCODER_VIRTUAL, NULL); | 300 | DRM_MODE_ENCODER_VIRTUAL, NULL); |
@@ -378,6 +386,10 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) | |||
378 | 386 | ||
379 | void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev) | 387 | void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev) |
380 | { | 388 | { |
389 | int i; | ||
390 | |||
391 | for (i = 0 ; i < vgdev->num_scanouts; ++i) | ||
392 | kfree(vgdev->outputs[i].edid); | ||
381 | virtio_gpu_fbdev_fini(vgdev); | 393 | virtio_gpu_fbdev_fini(vgdev); |
382 | drm_mode_config_cleanup(vgdev->ddev); | 394 | drm_mode_config_cleanup(vgdev->ddev); |
383 | } | 395 | } |
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index d9287c144fe5..f7f32a885af7 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c | |||
@@ -80,6 +80,7 @@ static unsigned int features[] = { | |||
80 | */ | 80 | */ |
81 | VIRTIO_GPU_F_VIRGL, | 81 | VIRTIO_GPU_F_VIRGL, |
82 | #endif | 82 | #endif |
83 | VIRTIO_GPU_F_EDID, | ||
83 | }; | 84 | }; |
84 | static struct virtio_driver virtio_gpu_driver = { | 85 | static struct virtio_driver virtio_gpu_driver = { |
85 | .feature_table = features, | 86 | .feature_table = features, |
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 9db568054d66..f7e877857c1f 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h | |||
@@ -115,6 +115,7 @@ struct virtio_gpu_output { | |||
115 | struct drm_encoder enc; | 115 | struct drm_encoder enc; |
116 | struct virtio_gpu_display_one info; | 116 | struct virtio_gpu_display_one info; |
117 | struct virtio_gpu_update_cursor cursor; | 117 | struct virtio_gpu_update_cursor cursor; |
118 | struct edid *edid; | ||
118 | int cur_x; | 119 | int cur_x; |
119 | int cur_y; | 120 | int cur_y; |
120 | bool enabled; | 121 | bool enabled; |
@@ -201,6 +202,7 @@ struct virtio_gpu_device { | |||
201 | struct ida ctx_id_ida; | 202 | struct ida ctx_id_ida; |
202 | 203 | ||
203 | bool has_virgl_3d; | 204 | bool has_virgl_3d; |
205 | bool has_edid; | ||
204 | 206 | ||
205 | struct work_struct config_changed_work; | 207 | struct work_struct config_changed_work; |
206 | 208 | ||
@@ -291,6 +293,7 @@ int virtio_gpu_cmd_get_capset_info(struct virtio_gpu_device *vgdev, int idx); | |||
291 | int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev, | 293 | int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev, |
292 | int idx, int version, | 294 | int idx, int version, |
293 | struct virtio_gpu_drv_cap_cache **cache_p); | 295 | struct virtio_gpu_drv_cap_cache **cache_p); |
296 | int virtio_gpu_cmd_get_edids(struct virtio_gpu_device *vgdev); | ||
294 | void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id, | 297 | void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id, |
295 | uint32_t nlen, const char *name); | 298 | uint32_t nlen, const char *name); |
296 | void virtio_gpu_cmd_context_destroy(struct virtio_gpu_device *vgdev, | 299 | void virtio_gpu_cmd_context_destroy(struct virtio_gpu_device *vgdev, |
diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 691b842d5f3a..3af6181c05a8 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c | |||
@@ -44,6 +44,8 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work) | |||
44 | virtio_cread(vgdev->vdev, struct virtio_gpu_config, | 44 | virtio_cread(vgdev->vdev, struct virtio_gpu_config, |
45 | events_read, &events_read); | 45 | events_read, &events_read); |
46 | if (events_read & VIRTIO_GPU_EVENT_DISPLAY) { | 46 | if (events_read & VIRTIO_GPU_EVENT_DISPLAY) { |
47 | if (vgdev->has_edid) | ||
48 | virtio_gpu_cmd_get_edids(vgdev); | ||
47 | virtio_gpu_cmd_get_display_info(vgdev); | 49 | virtio_gpu_cmd_get_display_info(vgdev); |
48 | drm_helper_hpd_irq_event(vgdev->ddev); | 50 | drm_helper_hpd_irq_event(vgdev->ddev); |
49 | events_clear |= VIRTIO_GPU_EVENT_DISPLAY; | 51 | events_clear |= VIRTIO_GPU_EVENT_DISPLAY; |
@@ -156,6 +158,10 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) | |||
156 | #else | 158 | #else |
157 | DRM_INFO("virgl 3d acceleration not supported by guest\n"); | 159 | DRM_INFO("virgl 3d acceleration not supported by guest\n"); |
158 | #endif | 160 | #endif |
161 | if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_EDID)) { | ||
162 | vgdev->has_edid = true; | ||
163 | DRM_INFO("EDID support available.\n"); | ||
164 | } | ||
159 | 165 | ||
160 | ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL); | 166 | ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL); |
161 | if (ret) { | 167 | if (ret) { |
@@ -201,6 +207,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) | |||
201 | 207 | ||
202 | if (num_capsets) | 208 | if (num_capsets) |
203 | virtio_gpu_get_capsets(vgdev, num_capsets); | 209 | virtio_gpu_get_capsets(vgdev, num_capsets); |
210 | if (vgdev->has_edid) | ||
211 | virtio_gpu_cmd_get_edids(vgdev); | ||
204 | virtio_gpu_cmd_get_display_info(vgdev); | 212 | virtio_gpu_cmd_get_display_info(vgdev); |
205 | wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending, | 213 | wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending, |
206 | 5 * HZ); | 214 | 5 * HZ); |
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 93f2c3a51ee8..2c6764f08f18 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c | |||
@@ -584,6 +584,45 @@ static void virtio_gpu_cmd_capset_cb(struct virtio_gpu_device *vgdev, | |||
584 | wake_up(&vgdev->resp_wq); | 584 | wake_up(&vgdev->resp_wq); |
585 | } | 585 | } |
586 | 586 | ||
587 | static int virtio_get_edid_block(void *data, u8 *buf, | ||
588 | unsigned int block, size_t len) | ||
589 | { | ||
590 | struct virtio_gpu_resp_edid *resp = data; | ||
591 | size_t start = block * EDID_LENGTH; | ||
592 | |||
593 | if (start + len > le32_to_cpu(resp->size)) | ||
594 | return -1; | ||
595 | memcpy(buf, resp->edid + start, len); | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static void virtio_gpu_cmd_get_edid_cb(struct virtio_gpu_device *vgdev, | ||
600 | struct virtio_gpu_vbuffer *vbuf) | ||
601 | { | ||
602 | struct virtio_gpu_cmd_get_edid *cmd = | ||
603 | (struct virtio_gpu_cmd_get_edid *)vbuf->buf; | ||
604 | struct virtio_gpu_resp_edid *resp = | ||
605 | (struct virtio_gpu_resp_edid *)vbuf->resp_buf; | ||
606 | uint32_t scanout = le32_to_cpu(cmd->scanout); | ||
607 | struct virtio_gpu_output *output; | ||
608 | struct edid *new_edid, *old_edid; | ||
609 | |||
610 | if (scanout >= vgdev->num_scanouts) | ||
611 | return; | ||
612 | output = vgdev->outputs + scanout; | ||
613 | |||
614 | new_edid = drm_do_get_edid(&output->conn, virtio_get_edid_block, resp); | ||
615 | |||
616 | spin_lock(&vgdev->display_info_lock); | ||
617 | old_edid = output->edid; | ||
618 | output->edid = new_edid; | ||
619 | drm_connector_update_edid_property(&output->conn, output->edid); | ||
620 | spin_unlock(&vgdev->display_info_lock); | ||
621 | |||
622 | kfree(old_edid); | ||
623 | wake_up(&vgdev->resp_wq); | ||
624 | } | ||
625 | |||
587 | int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev) | 626 | int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev) |
588 | { | 627 | { |
589 | struct virtio_gpu_ctrl_hdr *cmd_p; | 628 | struct virtio_gpu_ctrl_hdr *cmd_p; |
@@ -686,6 +725,34 @@ int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev, | |||
686 | return 0; | 725 | return 0; |
687 | } | 726 | } |
688 | 727 | ||
728 | int virtio_gpu_cmd_get_edids(struct virtio_gpu_device *vgdev) | ||
729 | { | ||
730 | struct virtio_gpu_cmd_get_edid *cmd_p; | ||
731 | struct virtio_gpu_vbuffer *vbuf; | ||
732 | void *resp_buf; | ||
733 | int scanout; | ||
734 | |||
735 | if (WARN_ON(!vgdev->has_edid)) | ||
736 | return -EINVAL; | ||
737 | |||
738 | for (scanout = 0; scanout < vgdev->num_scanouts; scanout++) { | ||
739 | resp_buf = kzalloc(sizeof(struct virtio_gpu_resp_edid), | ||
740 | GFP_KERNEL); | ||
741 | if (!resp_buf) | ||
742 | return -ENOMEM; | ||
743 | |||
744 | cmd_p = virtio_gpu_alloc_cmd_resp | ||
745 | (vgdev, &virtio_gpu_cmd_get_edid_cb, &vbuf, | ||
746 | sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_edid), | ||
747 | resp_buf); | ||
748 | cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_GET_EDID); | ||
749 | cmd_p->scanout = cpu_to_le32(scanout); | ||
750 | virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); | ||
751 | } | ||
752 | |||
753 | return 0; | ||
754 | } | ||
755 | |||
689 | void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id, | 756 | void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id, |
690 | uint32_t nlen, const char *name) | 757 | uint32_t nlen, const char *name) |
691 | { | 758 | { |