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_managed.h> 7 #include <drm/drm_probe_helper.h> 8 9 static const struct drm_connector_funcs vkms_connector_funcs = { 10 .fill_modes = drm_helper_probe_single_connector_modes, 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 int vkms_conn_get_modes(struct drm_connector *connector) 17 { 18 int count; 19 20 /* Use the default modes list from DRM */ 21 count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); 22 drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF); 23 24 return count; 25 } 26 27 static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = { 28 .get_modes = vkms_conn_get_modes, 29 }; 30 31 int vkms_output_init(struct vkms_device *vkmsdev) 32 { 33 struct drm_device *dev = &vkmsdev->drm; 34 struct drm_connector *connector; 35 struct drm_encoder *encoder; 36 struct vkms_output *output; 37 struct vkms_plane *primary, *overlay, *cursor = NULL; 38 int ret; 39 int writeback; 40 unsigned int n; 41 42 /* 43 * Initialize used plane. One primary plane is required to perform the composition. 44 * 45 * The overlay and cursor planes are not mandatory, but can be used to perform complex 46 * composition. 47 */ 48 primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY); 49 if (IS_ERR(primary)) 50 return PTR_ERR(primary); 51 52 if (vkmsdev->config->cursor) { 53 cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR); 54 if (IS_ERR(cursor)) 55 return PTR_ERR(cursor); 56 } 57 58 output = vkms_crtc_init(dev, &primary->base, 59 cursor ? &cursor->base : NULL); 60 if (IS_ERR(output)) { 61 DRM_ERROR("Failed to allocate CRTC\n"); 62 return PTR_ERR(output); 63 } 64 65 if (vkmsdev->config->overlay) { 66 for (n = 0; n < NUM_OVERLAY_PLANES; n++) { 67 overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY); 68 if (IS_ERR(overlay)) { 69 DRM_DEV_ERROR(dev->dev, "Failed to init vkms plane\n"); 70 return PTR_ERR(overlay); 71 } 72 overlay->base.possible_crtcs = drm_crtc_mask(&output->crtc); 73 } 74 } 75 76 connector = drmm_kzalloc(dev, sizeof(*connector), GFP_KERNEL); 77 if (!connector) { 78 DRM_ERROR("Failed to allocate connector\n"); 79 return -ENOMEM; 80 } 81 82 ret = drmm_connector_init(dev, connector, &vkms_connector_funcs, 83 DRM_MODE_CONNECTOR_VIRTUAL, NULL); 84 if (ret) { 85 DRM_ERROR("Failed to init connector\n"); 86 return ret; 87 } 88 89 drm_connector_helper_add(connector, &vkms_conn_helper_funcs); 90 91 encoder = drmm_kzalloc(dev, sizeof(*encoder), GFP_KERNEL); 92 if (!encoder) { 93 DRM_ERROR("Failed to allocate encoder\n"); 94 return -ENOMEM; 95 } 96 ret = drmm_encoder_init(dev, encoder, NULL, 97 DRM_MODE_ENCODER_VIRTUAL, NULL); 98 if (ret) { 99 DRM_ERROR("Failed to init encoder\n"); 100 return ret; 101 } 102 encoder->possible_crtcs = drm_crtc_mask(&output->crtc); 103 104 /* Attach the encoder and the connector */ 105 ret = drm_connector_attach_encoder(connector, encoder); 106 if (ret) { 107 DRM_ERROR("Failed to attach connector to encoder\n"); 108 return ret; 109 } 110 111 /* Initialize the writeback component */ 112 if (vkmsdev->config->writeback) { 113 writeback = vkms_enable_writeback_connector(vkmsdev, output); 114 if (writeback) 115 DRM_ERROR("Failed to init writeback connector\n"); 116 } 117 118 drm_mode_config_reset(dev); 119 120 return ret; 121 } 122