1 // SPDX-License-Identifier: GPL-2.0+ 2 3 #include "vkms_drv.h" 4 #include <drm/drm_atomic_helper.h> 5 #include <drm/drm_edid.h> 6 #include <drm/drm_probe_helper.h> 7 8 static const struct drm_connector_funcs vkms_connector_funcs = { 9 .fill_modes = drm_helper_probe_single_connector_modes, 10 .destroy = drm_connector_cleanup, 11 .reset = drm_atomic_helper_connector_reset, 12 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 13 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 14 }; 15 16 static const struct drm_encoder_funcs vkms_encoder_funcs = { 17 .destroy = drm_encoder_cleanup, 18 }; 19 20 static int vkms_conn_get_modes(struct drm_connector *connector) 21 { 22 int count; 23 24 count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); 25 drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF); 26 27 return count; 28 } 29 30 static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = { 31 .get_modes = vkms_conn_get_modes, 32 }; 33 34 static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index, 35 struct drm_crtc *crtc) 36 { 37 struct vkms_plane *overlay; 38 39 overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, index); 40 if (IS_ERR(overlay)) 41 return PTR_ERR(overlay); 42 43 if (!overlay->base.possible_crtcs) 44 overlay->base.possible_crtcs = drm_crtc_mask(crtc); 45 46 return 0; 47 } 48 49 int vkms_output_init(struct vkms_device *vkmsdev, int index) 50 { 51 struct vkms_output *output = &vkmsdev->output; 52 struct drm_device *dev = &vkmsdev->drm; 53 struct drm_connector *connector = &output->connector; 54 struct drm_encoder *encoder = &output->encoder; 55 struct drm_crtc *crtc = &output->crtc; 56 struct vkms_plane *primary, *cursor = NULL; 57 int ret; 58 int writeback; 59 unsigned int n; 60 61 primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY, index); 62 if (IS_ERR(primary)) 63 return PTR_ERR(primary); 64 65 if (vkmsdev->config->overlay) { 66 for (n = 0; n < NUM_OVERLAY_PLANES; n++) { 67 ret = vkms_add_overlay_plane(vkmsdev, index, crtc); 68 if (ret) 69 return ret; 70 } 71 } 72 73 if (vkmsdev->config->cursor) { 74 cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR, index); 75 if (IS_ERR(cursor)) 76 return PTR_ERR(cursor); 77 } 78 79 ret = vkms_crtc_init(dev, crtc, &primary->base, &cursor->base); 80 if (ret) 81 return ret; 82 83 ret = drm_connector_init(dev, connector, &vkms_connector_funcs, 84 DRM_MODE_CONNECTOR_VIRTUAL); 85 if (ret) { 86 DRM_ERROR("Failed to init connector\n"); 87 goto err_connector; 88 } 89 90 drm_connector_helper_add(connector, &vkms_conn_helper_funcs); 91 92 ret = drm_encoder_init(dev, encoder, &vkms_encoder_funcs, 93 DRM_MODE_ENCODER_VIRTUAL, NULL); 94 if (ret) { 95 DRM_ERROR("Failed to init encoder\n"); 96 goto err_encoder; 97 } 98 encoder->possible_crtcs = 1; 99 100 ret = drm_connector_attach_encoder(connector, encoder); 101 if (ret) { 102 DRM_ERROR("Failed to attach connector to encoder\n"); 103 goto err_attach; 104 } 105 106 if (vkmsdev->config->writeback) { 107 writeback = vkms_enable_writeback_connector(vkmsdev); 108 if (writeback) 109 DRM_ERROR("Failed to init writeback connector\n"); 110 } 111 112 drm_mode_config_reset(dev); 113 114 return 0; 115 116 err_attach: 117 drm_encoder_cleanup(encoder); 118 119 err_encoder: 120 drm_connector_cleanup(connector); 121 122 err_connector: 123 drm_crtc_cleanup(crtc); 124 125 return ret; 126 } 127