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