xref: /linux/drivers/gpu/drm/vkms/vkms_output.c (revision 5b5a56d9a2d64e8395dfbaddecb3e5149d7ecae8)
1 // SPDX-License-Identifier: GPL-2.0+
2 
3 #include "vkms_connector.h"
4 #include "vkms_drv.h"
5 #include <drm/drm_managed.h>
6 
7 int vkms_output_init(struct vkms_device *vkmsdev)
8 {
9 	struct drm_device *dev = &vkmsdev->drm;
10 	struct vkms_connector *connector;
11 	struct drm_encoder *encoder;
12 	struct vkms_output *output;
13 	struct vkms_plane *primary, *overlay, *cursor = NULL;
14 	int ret;
15 	int writeback;
16 	unsigned int n;
17 
18 	/*
19 	 * Initialize used plane. One primary plane is required to perform the composition.
20 	 *
21 	 * The overlay and cursor planes are not mandatory, but can be used to perform complex
22 	 * composition.
23 	 */
24 	primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY);
25 	if (IS_ERR(primary))
26 		return PTR_ERR(primary);
27 
28 	if (vkmsdev->config->cursor) {
29 		cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR);
30 		if (IS_ERR(cursor))
31 			return PTR_ERR(cursor);
32 	}
33 
34 	output = vkms_crtc_init(dev, &primary->base,
35 				cursor ? &cursor->base : NULL);
36 	if (IS_ERR(output)) {
37 		DRM_ERROR("Failed to allocate CRTC\n");
38 		return PTR_ERR(output);
39 	}
40 
41 	if (vkmsdev->config->overlay) {
42 		for (n = 0; n < NUM_OVERLAY_PLANES; n++) {
43 			overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY);
44 			if (IS_ERR(overlay)) {
45 				DRM_DEV_ERROR(dev->dev, "Failed to init vkms plane\n");
46 				return PTR_ERR(overlay);
47 			}
48 			overlay->base.possible_crtcs = drm_crtc_mask(&output->crtc);
49 		}
50 	}
51 
52 	connector = vkms_connector_init(vkmsdev);
53 	if (IS_ERR(connector)) {
54 		DRM_ERROR("Failed to init connector\n");
55 		return PTR_ERR(connector);
56 	}
57 
58 	encoder = drmm_kzalloc(dev, sizeof(*encoder), GFP_KERNEL);
59 	if (!encoder) {
60 		DRM_ERROR("Failed to allocate encoder\n");
61 		return -ENOMEM;
62 	}
63 	ret = drmm_encoder_init(dev, encoder, NULL,
64 				DRM_MODE_ENCODER_VIRTUAL, NULL);
65 	if (ret) {
66 		DRM_ERROR("Failed to init encoder\n");
67 		return ret;
68 	}
69 	encoder->possible_crtcs = drm_crtc_mask(&output->crtc);
70 
71 	/* Attach the encoder and the connector */
72 	ret = drm_connector_attach_encoder(&connector->base, encoder);
73 	if (ret) {
74 		DRM_ERROR("Failed to attach connector to encoder\n");
75 		return ret;
76 	}
77 
78 	/* Initialize the writeback component */
79 	if (vkmsdev->config->writeback) {
80 		writeback = vkms_enable_writeback_connector(vkmsdev, output);
81 		if (writeback)
82 			DRM_ERROR("Failed to init writeback connector\n");
83 	}
84 
85 	drm_mode_config_reset(dev);
86 
87 	return ret;
88 }
89