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