xref: /linux/drivers/gpu/drm/vkms/vkms_output.c (revision d16489307a52f028dcb072addf681f9280f585c6)
1854502faSRodrigo Siqueira // SPDX-License-Identifier: GPL-2.0
2854502faSRodrigo Siqueira /*
3854502faSRodrigo Siqueira  * This program is free software; you can redistribute it and/or modify
4854502faSRodrigo Siqueira  * it under the terms of the GNU General Public License as published by
5854502faSRodrigo Siqueira  * the Free Software Foundation; either version 2 of the License, or
6854502faSRodrigo Siqueira  * (at your option) any later version.
7854502faSRodrigo Siqueira  */
8854502faSRodrigo Siqueira 
9854502faSRodrigo Siqueira #include "vkms_drv.h"
10854502faSRodrigo Siqueira #include <drm/drm_crtc_helper.h>
11*d1648930SRodrigo Siqueira #include <drm/drm_atomic_helper.h>
12854502faSRodrigo Siqueira 
13854502faSRodrigo Siqueira static void vkms_connector_destroy(struct drm_connector *connector)
14854502faSRodrigo Siqueira {
15854502faSRodrigo Siqueira 	drm_connector_unregister(connector);
16854502faSRodrigo Siqueira 	drm_connector_cleanup(connector);
17854502faSRodrigo Siqueira }
18854502faSRodrigo Siqueira 
19854502faSRodrigo Siqueira static const struct drm_connector_funcs vkms_connector_funcs = {
20854502faSRodrigo Siqueira 	.fill_modes = drm_helper_probe_single_connector_modes,
21854502faSRodrigo Siqueira 	.destroy = vkms_connector_destroy,
22*d1648930SRodrigo Siqueira 	.reset = drm_atomic_helper_connector_reset,
23*d1648930SRodrigo Siqueira 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
24*d1648930SRodrigo Siqueira 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
25854502faSRodrigo Siqueira };
26854502faSRodrigo Siqueira 
27854502faSRodrigo Siqueira static const struct drm_encoder_funcs vkms_encoder_funcs = {
28854502faSRodrigo Siqueira 	.destroy = drm_encoder_cleanup,
29854502faSRodrigo Siqueira };
30854502faSRodrigo Siqueira 
31*d1648930SRodrigo Siqueira static int vkms_conn_get_modes(struct drm_connector *connector)
32*d1648930SRodrigo Siqueira {
33*d1648930SRodrigo Siqueira 	int count;
34*d1648930SRodrigo Siqueira 
35*d1648930SRodrigo Siqueira 	count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
36*d1648930SRodrigo Siqueira 	drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);
37*d1648930SRodrigo Siqueira 
38*d1648930SRodrigo Siqueira 	return count;
39*d1648930SRodrigo Siqueira }
40*d1648930SRodrigo Siqueira 
41*d1648930SRodrigo Siqueira static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
42*d1648930SRodrigo Siqueira 	.get_modes    = vkms_conn_get_modes,
43*d1648930SRodrigo Siqueira };
44*d1648930SRodrigo Siqueira 
45854502faSRodrigo Siqueira int vkms_output_init(struct vkms_device *vkmsdev)
46854502faSRodrigo Siqueira {
47854502faSRodrigo Siqueira 	struct vkms_output *output = &vkmsdev->output;
48854502faSRodrigo Siqueira 	struct drm_device *dev = &vkmsdev->drm;
49854502faSRodrigo Siqueira 	struct drm_connector *connector = &output->connector;
50854502faSRodrigo Siqueira 	struct drm_encoder *encoder = &output->encoder;
51854502faSRodrigo Siqueira 	struct drm_crtc *crtc = &output->crtc;
52854502faSRodrigo Siqueira 	struct drm_plane *primary;
53854502faSRodrigo Siqueira 	int ret;
54854502faSRodrigo Siqueira 
55854502faSRodrigo Siqueira 	primary = vkms_plane_init(vkmsdev);
56854502faSRodrigo Siqueira 	if (IS_ERR(primary))
57854502faSRodrigo Siqueira 		return PTR_ERR(primary);
58854502faSRodrigo Siqueira 
59854502faSRodrigo Siqueira 	ret = vkms_crtc_init(dev, crtc, primary, NULL);
60854502faSRodrigo Siqueira 	if (ret)
61854502faSRodrigo Siqueira 		goto err_crtc;
62854502faSRodrigo Siqueira 
63854502faSRodrigo Siqueira 	ret = drm_connector_init(dev, connector, &vkms_connector_funcs,
64854502faSRodrigo Siqueira 				 DRM_MODE_CONNECTOR_VIRTUAL);
65854502faSRodrigo Siqueira 	if (ret) {
66854502faSRodrigo Siqueira 		DRM_ERROR("Failed to init connector\n");
67854502faSRodrigo Siqueira 		goto err_connector;
68854502faSRodrigo Siqueira 	}
69854502faSRodrigo Siqueira 
70*d1648930SRodrigo Siqueira 	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
71*d1648930SRodrigo Siqueira 
72854502faSRodrigo Siqueira 	ret = drm_connector_register(connector);
73854502faSRodrigo Siqueira 	if (ret) {
74854502faSRodrigo Siqueira 		DRM_ERROR("Failed to register connector\n");
75854502faSRodrigo Siqueira 		goto err_connector_register;
76854502faSRodrigo Siqueira 	}
77854502faSRodrigo Siqueira 
78854502faSRodrigo Siqueira 	ret = drm_encoder_init(dev, encoder, &vkms_encoder_funcs,
79854502faSRodrigo Siqueira 			       DRM_MODE_ENCODER_VIRTUAL, NULL);
80854502faSRodrigo Siqueira 	if (ret) {
81854502faSRodrigo Siqueira 		DRM_ERROR("Failed to init encoder\n");
82854502faSRodrigo Siqueira 		goto err_encoder;
83854502faSRodrigo Siqueira 	}
84854502faSRodrigo Siqueira 	encoder->possible_crtcs = 1;
85854502faSRodrigo Siqueira 
86854502faSRodrigo Siqueira 	ret = drm_mode_connector_attach_encoder(connector, encoder);
87854502faSRodrigo Siqueira 	if (ret) {
88854502faSRodrigo Siqueira 		DRM_ERROR("Failed to attach connector to encoder\n");
89854502faSRodrigo Siqueira 		goto err_attach;
90854502faSRodrigo Siqueira 	}
91854502faSRodrigo Siqueira 
92854502faSRodrigo Siqueira 	drm_mode_config_reset(dev);
93854502faSRodrigo Siqueira 
94854502faSRodrigo Siqueira 	return 0;
95854502faSRodrigo Siqueira 
96854502faSRodrigo Siqueira err_attach:
97854502faSRodrigo Siqueira 	drm_encoder_cleanup(encoder);
98854502faSRodrigo Siqueira 
99854502faSRodrigo Siqueira err_encoder:
100854502faSRodrigo Siqueira 	drm_connector_unregister(connector);
101854502faSRodrigo Siqueira 
102854502faSRodrigo Siqueira err_connector_register:
103854502faSRodrigo Siqueira 	drm_connector_cleanup(connector);
104854502faSRodrigo Siqueira 
105854502faSRodrigo Siqueira err_connector:
106854502faSRodrigo Siqueira 	drm_crtc_cleanup(crtc);
107854502faSRodrigo Siqueira 
108854502faSRodrigo Siqueira err_crtc:
109854502faSRodrigo Siqueira 	drm_plane_cleanup(primary);
110854502faSRodrigo Siqueira 	return ret;
111854502faSRodrigo Siqueira }
112