162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include "vkms_drv.h" 462306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h> 562306a36Sopenharmony_ci#include <drm/drm_edid.h> 662306a36Sopenharmony_ci#include <drm/drm_probe_helper.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_cistatic const struct drm_connector_funcs vkms_connector_funcs = { 962306a36Sopenharmony_ci .fill_modes = drm_helper_probe_single_connector_modes, 1062306a36Sopenharmony_ci .destroy = drm_connector_cleanup, 1162306a36Sopenharmony_ci .reset = drm_atomic_helper_connector_reset, 1262306a36Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 1362306a36Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 1462306a36Sopenharmony_ci}; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic const struct drm_encoder_funcs vkms_encoder_funcs = { 1762306a36Sopenharmony_ci .destroy = drm_encoder_cleanup, 1862306a36Sopenharmony_ci}; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic int vkms_conn_get_modes(struct drm_connector *connector) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci int count; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); 2562306a36Sopenharmony_ci drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci return count; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic const struct drm_connector_helper_funcs vkms_conn_helper_funcs = { 3162306a36Sopenharmony_ci .get_modes = vkms_conn_get_modes, 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index, 3562306a36Sopenharmony_ci struct drm_crtc *crtc) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct vkms_plane *overlay; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, index); 4062306a36Sopenharmony_ci if (IS_ERR(overlay)) 4162306a36Sopenharmony_ci return PTR_ERR(overlay); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (!overlay->base.possible_crtcs) 4462306a36Sopenharmony_ci overlay->base.possible_crtcs = drm_crtc_mask(crtc); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci return 0; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ciint vkms_output_init(struct vkms_device *vkmsdev, int index) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct vkms_output *output = &vkmsdev->output; 5262306a36Sopenharmony_ci struct drm_device *dev = &vkmsdev->drm; 5362306a36Sopenharmony_ci struct drm_connector *connector = &output->connector; 5462306a36Sopenharmony_ci struct drm_encoder *encoder = &output->encoder; 5562306a36Sopenharmony_ci struct drm_crtc *crtc = &output->crtc; 5662306a36Sopenharmony_ci struct vkms_plane *primary, *cursor = NULL; 5762306a36Sopenharmony_ci int ret; 5862306a36Sopenharmony_ci int writeback; 5962306a36Sopenharmony_ci unsigned int n; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY, index); 6262306a36Sopenharmony_ci if (IS_ERR(primary)) 6362306a36Sopenharmony_ci return PTR_ERR(primary); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (vkmsdev->config->overlay) { 6662306a36Sopenharmony_ci for (n = 0; n < NUM_OVERLAY_PLANES; n++) { 6762306a36Sopenharmony_ci ret = vkms_add_overlay_plane(vkmsdev, index, crtc); 6862306a36Sopenharmony_ci if (ret) 6962306a36Sopenharmony_ci return ret; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (vkmsdev->config->cursor) { 7462306a36Sopenharmony_ci cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR, index); 7562306a36Sopenharmony_ci if (IS_ERR(cursor)) 7662306a36Sopenharmony_ci return PTR_ERR(cursor); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci ret = vkms_crtc_init(dev, crtc, &primary->base, &cursor->base); 8062306a36Sopenharmony_ci if (ret) 8162306a36Sopenharmony_ci return ret; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci ret = drm_connector_init(dev, connector, &vkms_connector_funcs, 8462306a36Sopenharmony_ci DRM_MODE_CONNECTOR_VIRTUAL); 8562306a36Sopenharmony_ci if (ret) { 8662306a36Sopenharmony_ci DRM_ERROR("Failed to init connector\n"); 8762306a36Sopenharmony_ci goto err_connector; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci drm_connector_helper_add(connector, &vkms_conn_helper_funcs); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci ret = drm_encoder_init(dev, encoder, &vkms_encoder_funcs, 9362306a36Sopenharmony_ci DRM_MODE_ENCODER_VIRTUAL, NULL); 9462306a36Sopenharmony_ci if (ret) { 9562306a36Sopenharmony_ci DRM_ERROR("Failed to init encoder\n"); 9662306a36Sopenharmony_ci goto err_encoder; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci encoder->possible_crtcs = 1; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci ret = drm_connector_attach_encoder(connector, encoder); 10162306a36Sopenharmony_ci if (ret) { 10262306a36Sopenharmony_ci DRM_ERROR("Failed to attach connector to encoder\n"); 10362306a36Sopenharmony_ci goto err_attach; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (vkmsdev->config->writeback) { 10762306a36Sopenharmony_ci writeback = vkms_enable_writeback_connector(vkmsdev); 10862306a36Sopenharmony_ci if (writeback) 10962306a36Sopenharmony_ci DRM_ERROR("Failed to init writeback connector\n"); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci drm_mode_config_reset(dev); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return 0; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cierr_attach: 11762306a36Sopenharmony_ci drm_encoder_cleanup(encoder); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cierr_encoder: 12062306a36Sopenharmony_ci drm_connector_cleanup(connector); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cierr_connector: 12362306a36Sopenharmony_ci drm_crtc_cleanup(crtc); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return ret; 12662306a36Sopenharmony_ci} 127