diff options
Diffstat (limited to 'drivers/gpu/drm/virtio/virtgpu_vq.c')
-rw-r--r-- | drivers/gpu/drm/virtio/virtgpu_vq.c | 67 |
1 files changed, 67 insertions, 0 deletions
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 | { |