xref: /linux/drivers/gpu/drm/vkms/vkms_output.c (revision 6dfafbd0299a60bfb5d5e277fdf100037c7ded07)
1 // SPDX-License-Identifier: GPL-2.0+
2 
3 #include "vkms_config.h"
4 #include "vkms_connector.h"
5 #include "vkms_drv.h"
6 #include <drm/drm_managed.h>
7 #include <drm/drm_print.h>
8 
9 int vkms_output_init(struct vkms_device *vkmsdev)
10 {
11 	struct drm_device *dev = &vkmsdev->drm;
12 	struct vkms_config_plane *plane_cfg;
13 	struct vkms_config_crtc *crtc_cfg;
14 	struct vkms_config_encoder *encoder_cfg;
15 	struct vkms_config_connector *connector_cfg;
16 	int ret;
17 	int writeback;
18 
19 	if (!vkms_config_is_valid(vkmsdev->config))
20 		return -EINVAL;
21 
22 	vkms_config_for_each_plane(vkmsdev->config, plane_cfg) {
23 		plane_cfg->plane = vkms_plane_init(vkmsdev, plane_cfg);
24 		if (IS_ERR(plane_cfg->plane)) {
25 			DRM_DEV_ERROR(dev->dev, "Failed to init vkms plane\n");
26 			return PTR_ERR(plane_cfg->plane);
27 		}
28 	}
29 
30 	vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) {
31 		struct vkms_config_plane *primary, *cursor;
32 
33 		primary = vkms_config_crtc_primary_plane(vkmsdev->config, crtc_cfg);
34 		cursor = vkms_config_crtc_cursor_plane(vkmsdev->config, crtc_cfg);
35 
36 		crtc_cfg->crtc = vkms_crtc_init(dev, &primary->plane->base,
37 						cursor ? &cursor->plane->base : NULL);
38 		if (IS_ERR(crtc_cfg->crtc)) {
39 			DRM_ERROR("Failed to allocate CRTC\n");
40 			return PTR_ERR(crtc_cfg->crtc);
41 		}
42 
43 		/* Initialize the writeback component */
44 		if (vkms_config_crtc_get_writeback(crtc_cfg)) {
45 			writeback = vkms_enable_writeback_connector(vkmsdev, crtc_cfg->crtc);
46 			if (writeback)
47 				DRM_ERROR("Failed to init writeback connector\n");
48 		}
49 	}
50 
51 	vkms_config_for_each_plane(vkmsdev->config, plane_cfg) {
52 		struct vkms_config_crtc *possible_crtc;
53 		unsigned long idx = 0;
54 
55 		vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) {
56 			plane_cfg->plane->base.possible_crtcs |=
57 				drm_crtc_mask(&possible_crtc->crtc->crtc);
58 		}
59 	}
60 
61 	vkms_config_for_each_encoder(vkmsdev->config, encoder_cfg) {
62 		struct vkms_config_crtc *possible_crtc;
63 		unsigned long idx = 0;
64 
65 		encoder_cfg->encoder = drmm_kzalloc(dev, sizeof(*encoder_cfg->encoder), GFP_KERNEL);
66 		if (!encoder_cfg->encoder) {
67 			DRM_ERROR("Failed to allocate encoder\n");
68 			return -ENOMEM;
69 		}
70 		ret = drmm_encoder_init(dev, encoder_cfg->encoder, NULL,
71 					DRM_MODE_ENCODER_VIRTUAL, NULL);
72 		if (ret) {
73 			DRM_ERROR("Failed to init encoder\n");
74 			return ret;
75 		}
76 
77 		encoder_cfg->encoder->possible_clones |=
78 			drm_encoder_mask(encoder_cfg->encoder);
79 
80 		vkms_config_encoder_for_each_possible_crtc(encoder_cfg, idx, possible_crtc) {
81 			encoder_cfg->encoder->possible_crtcs |=
82 				drm_crtc_mask(&possible_crtc->crtc->crtc);
83 
84 			if (vkms_config_crtc_get_writeback(possible_crtc)) {
85 				struct drm_encoder *wb_encoder =
86 					&possible_crtc->crtc->wb_encoder;
87 
88 				encoder_cfg->encoder->possible_clones |=
89 					drm_encoder_mask(wb_encoder);
90 				wb_encoder->possible_clones |=
91 					drm_encoder_mask(encoder_cfg->encoder);
92 			}
93 		}
94 	}
95 
96 	vkms_config_for_each_connector(vkmsdev->config, connector_cfg) {
97 		struct vkms_config_encoder *possible_encoder;
98 		unsigned long idx = 0;
99 
100 		connector_cfg->connector = vkms_connector_init(vkmsdev);
101 		if (IS_ERR(connector_cfg->connector)) {
102 			DRM_ERROR("Failed to init connector\n");
103 			return PTR_ERR(connector_cfg->connector);
104 		}
105 
106 		vkms_config_connector_for_each_possible_encoder(connector_cfg,
107 								idx,
108 								possible_encoder) {
109 			ret = drm_connector_attach_encoder(&connector_cfg->connector->base,
110 							   possible_encoder->encoder);
111 			if (ret) {
112 				DRM_ERROR("Failed to attach connector to encoder\n");
113 				return ret;
114 			}
115 		}
116 	}
117 
118 	drm_mode_config_reset(dev);
119 
120 	return 0;
121 }
122