drm/virtio: add edid support
linux guest driver implementation of the VIRTIO_GPU_F_EDID feature. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Daniel Vetter <daniel@ffwll.ch> Link: http://patchwork.freedesktop.org/patch/msgid/20181030063206.19528-3-kraxel@redhat.com
This commit is contained in:
parent
610c0c2b28
commit
b4b01b4995
|
@ -169,6 +169,12 @@ static int virtio_gpu_conn_get_modes(struct drm_connector *connector)
|
|||
struct drm_display_mode *mode = NULL;
|
||||
int count, width, height;
|
||||
|
||||
if (output->edid) {
|
||||
count = drm_add_edid_modes(connector, output->edid);
|
||||
if (count)
|
||||
return count;
|
||||
}
|
||||
|
||||
width = le32_to_cpu(output->info.r.width);
|
||||
height = le32_to_cpu(output->info.r.height);
|
||||
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)
|
|||
drm_connector_init(dev, connector, &virtio_gpu_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_VIRTUAL);
|
||||
drm_connector_helper_add(connector, &virtio_gpu_conn_helper_funcs);
|
||||
if (vgdev->has_edid)
|
||||
drm_connector_attach_edid_property(connector);
|
||||
|
||||
drm_encoder_init(dev, encoder, &virtio_gpu_enc_funcs,
|
||||
DRM_MODE_ENCODER_VIRTUAL, NULL);
|
||||
|
@ -378,6 +386,10 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev)
|
|||
|
||||
void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < vgdev->num_scanouts; ++i)
|
||||
kfree(vgdev->outputs[i].edid);
|
||||
virtio_gpu_fbdev_fini(vgdev);
|
||||
drm_mode_config_cleanup(vgdev->ddev);
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ static unsigned int features[] = {
|
|||
*/
|
||||
VIRTIO_GPU_F_VIRGL,
|
||||
#endif
|
||||
VIRTIO_GPU_F_EDID,
|
||||
};
|
||||
static struct virtio_driver virtio_gpu_driver = {
|
||||
.feature_table = features,
|
||||
|
|
|
@ -115,6 +115,7 @@ struct virtio_gpu_output {
|
|||
struct drm_encoder enc;
|
||||
struct virtio_gpu_display_one info;
|
||||
struct virtio_gpu_update_cursor cursor;
|
||||
struct edid *edid;
|
||||
int cur_x;
|
||||
int cur_y;
|
||||
bool enabled;
|
||||
|
@ -204,6 +205,7 @@ struct virtio_gpu_device {
|
|||
struct ida ctx_id_ida;
|
||||
|
||||
bool has_virgl_3d;
|
||||
bool has_edid;
|
||||
|
||||
struct work_struct config_changed_work;
|
||||
|
||||
|
@ -294,6 +296,7 @@ int virtio_gpu_cmd_get_capset_info(struct virtio_gpu_device *vgdev, int idx);
|
|||
int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,
|
||||
int idx, int version,
|
||||
struct virtio_gpu_drv_cap_cache **cache_p);
|
||||
int virtio_gpu_cmd_get_edids(struct virtio_gpu_device *vgdev);
|
||||
void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,
|
||||
uint32_t nlen, const char *name);
|
||||
void virtio_gpu_cmd_context_destroy(struct virtio_gpu_device *vgdev,
|
||||
|
|
|
@ -44,6 +44,8 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
|
|||
virtio_cread(vgdev->vdev, struct virtio_gpu_config,
|
||||
events_read, &events_read);
|
||||
if (events_read & VIRTIO_GPU_EVENT_DISPLAY) {
|
||||
if (vgdev->has_edid)
|
||||
virtio_gpu_cmd_get_edids(vgdev);
|
||||
virtio_gpu_cmd_get_display_info(vgdev);
|
||||
drm_helper_hpd_irq_event(vgdev->ddev);
|
||||
events_clear |= VIRTIO_GPU_EVENT_DISPLAY;
|
||||
|
@ -156,6 +158,10 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
#else
|
||||
DRM_INFO("virgl 3d acceleration not supported by guest\n");
|
||||
#endif
|
||||
if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_EDID)) {
|
||||
vgdev->has_edid = true;
|
||||
DRM_INFO("EDID support available.\n");
|
||||
}
|
||||
|
||||
ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL);
|
||||
if (ret) {
|
||||
|
@ -201,6 +207,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
|
||||
if (num_capsets)
|
||||
virtio_gpu_get_capsets(vgdev, num_capsets);
|
||||
if (vgdev->has_edid)
|
||||
virtio_gpu_cmd_get_edids(vgdev);
|
||||
virtio_gpu_cmd_get_display_info(vgdev);
|
||||
wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending,
|
||||
5 * HZ);
|
||||
|
|
|
@ -584,6 +584,45 @@ static void virtio_gpu_cmd_capset_cb(struct virtio_gpu_device *vgdev,
|
|||
wake_up(&vgdev->resp_wq);
|
||||
}
|
||||
|
||||
static int virtio_get_edid_block(void *data, u8 *buf,
|
||||
unsigned int block, size_t len)
|
||||
{
|
||||
struct virtio_gpu_resp_edid *resp = data;
|
||||
size_t start = block * EDID_LENGTH;
|
||||
|
||||
if (start + len > le32_to_cpu(resp->size))
|
||||
return -1;
|
||||
memcpy(buf, resp->edid + start, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtio_gpu_cmd_get_edid_cb(struct virtio_gpu_device *vgdev,
|
||||
struct virtio_gpu_vbuffer *vbuf)
|
||||
{
|
||||
struct virtio_gpu_cmd_get_edid *cmd =
|
||||
(struct virtio_gpu_cmd_get_edid *)vbuf->buf;
|
||||
struct virtio_gpu_resp_edid *resp =
|
||||
(struct virtio_gpu_resp_edid *)vbuf->resp_buf;
|
||||
uint32_t scanout = le32_to_cpu(cmd->scanout);
|
||||
struct virtio_gpu_output *output;
|
||||
struct edid *new_edid, *old_edid;
|
||||
|
||||
if (scanout >= vgdev->num_scanouts)
|
||||
return;
|
||||
output = vgdev->outputs + scanout;
|
||||
|
||||
new_edid = drm_do_get_edid(&output->conn, virtio_get_edid_block, resp);
|
||||
|
||||
spin_lock(&vgdev->display_info_lock);
|
||||
old_edid = output->edid;
|
||||
output->edid = new_edid;
|
||||
drm_connector_update_edid_property(&output->conn, output->edid);
|
||||
spin_unlock(&vgdev->display_info_lock);
|
||||
|
||||
kfree(old_edid);
|
||||
wake_up(&vgdev->resp_wq);
|
||||
}
|
||||
|
||||
int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev)
|
||||
{
|
||||
struct virtio_gpu_ctrl_hdr *cmd_p;
|
||||
|
@ -686,6 +725,34 @@ int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int virtio_gpu_cmd_get_edids(struct virtio_gpu_device *vgdev)
|
||||
{
|
||||
struct virtio_gpu_cmd_get_edid *cmd_p;
|
||||
struct virtio_gpu_vbuffer *vbuf;
|
||||
void *resp_buf;
|
||||
int scanout;
|
||||
|
||||
if (WARN_ON(!vgdev->has_edid))
|
||||
return -EINVAL;
|
||||
|
||||
for (scanout = 0; scanout < vgdev->num_scanouts; scanout++) {
|
||||
resp_buf = kzalloc(sizeof(struct virtio_gpu_resp_edid),
|
||||
GFP_KERNEL);
|
||||
if (!resp_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd_p = virtio_gpu_alloc_cmd_resp
|
||||
(vgdev, &virtio_gpu_cmd_get_edid_cb, &vbuf,
|
||||
sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_edid),
|
||||
resp_buf);
|
||||
cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_GET_EDID);
|
||||
cmd_p->scanout = cpu_to_le32(scanout);
|
||||
virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,
|
||||
uint32_t nlen, const char *name)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue