18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * ARC PGU DRM driver.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h>
98c2ecf20Sopenharmony_ci#include <drm/drm_device.h>
108c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "arcpgu.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define XRES_DEF	640
158c2ecf20Sopenharmony_ci#define YRES_DEF	480
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define XRES_MAX	8192
188c2ecf20Sopenharmony_ci#define YRES_MAX	8192
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistruct arcpgu_drm_connector {
228c2ecf20Sopenharmony_ci	struct drm_connector connector;
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic int arcpgu_drm_connector_get_modes(struct drm_connector *connector)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	int count;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
308c2ecf20Sopenharmony_ci	drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);
318c2ecf20Sopenharmony_ci	return count;
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic void arcpgu_drm_connector_destroy(struct drm_connector *connector)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	drm_connector_unregister(connector);
378c2ecf20Sopenharmony_ci	drm_connector_cleanup(connector);
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs
418c2ecf20Sopenharmony_ciarcpgu_drm_connector_helper_funcs = {
428c2ecf20Sopenharmony_ci	.get_modes = arcpgu_drm_connector_get_modes,
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs arcpgu_drm_connector_funcs = {
468c2ecf20Sopenharmony_ci	.reset = drm_atomic_helper_connector_reset,
478c2ecf20Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
488c2ecf20Sopenharmony_ci	.destroy = arcpgu_drm_connector_destroy,
498c2ecf20Sopenharmony_ci	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
508c2ecf20Sopenharmony_ci	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic struct drm_encoder_funcs arcpgu_drm_encoder_funcs = {
548c2ecf20Sopenharmony_ci	.destroy = drm_encoder_cleanup,
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ciint arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct arcpgu_drm_connector *arcpgu_connector;
608c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
618c2ecf20Sopenharmony_ci	struct drm_connector *connector;
628c2ecf20Sopenharmony_ci	int ret;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	encoder = devm_kzalloc(drm->dev, sizeof(*encoder), GFP_KERNEL);
658c2ecf20Sopenharmony_ci	if (encoder == NULL)
668c2ecf20Sopenharmony_ci		return -ENOMEM;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	encoder->possible_crtcs = 1;
698c2ecf20Sopenharmony_ci	encoder->possible_clones = 0;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	ret = drm_encoder_init(drm, encoder, &arcpgu_drm_encoder_funcs,
728c2ecf20Sopenharmony_ci			       DRM_MODE_ENCODER_VIRTUAL, NULL);
738c2ecf20Sopenharmony_ci	if (ret)
748c2ecf20Sopenharmony_ci		return ret;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	arcpgu_connector = devm_kzalloc(drm->dev, sizeof(*arcpgu_connector),
778c2ecf20Sopenharmony_ci					GFP_KERNEL);
788c2ecf20Sopenharmony_ci	if (!arcpgu_connector) {
798c2ecf20Sopenharmony_ci		ret = -ENOMEM;
808c2ecf20Sopenharmony_ci		goto error_encoder_cleanup;
818c2ecf20Sopenharmony_ci	}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	connector = &arcpgu_connector->connector;
848c2ecf20Sopenharmony_ci	drm_connector_helper_add(connector, &arcpgu_drm_connector_helper_funcs);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	ret = drm_connector_init(drm, connector, &arcpgu_drm_connector_funcs,
878c2ecf20Sopenharmony_ci			DRM_MODE_CONNECTOR_VIRTUAL);
888c2ecf20Sopenharmony_ci	if (ret < 0) {
898c2ecf20Sopenharmony_ci		dev_err(drm->dev, "failed to initialize drm connector\n");
908c2ecf20Sopenharmony_ci		goto error_encoder_cleanup;
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	ret = drm_connector_attach_encoder(connector, encoder);
948c2ecf20Sopenharmony_ci	if (ret < 0) {
958c2ecf20Sopenharmony_ci		dev_err(drm->dev, "could not attach connector to encoder\n");
968c2ecf20Sopenharmony_ci		drm_connector_unregister(connector);
978c2ecf20Sopenharmony_ci		goto error_connector_cleanup;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return 0;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cierror_connector_cleanup:
1038c2ecf20Sopenharmony_ci	drm_connector_cleanup(connector);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cierror_encoder_cleanup:
1068c2ecf20Sopenharmony_ci	drm_encoder_cleanup(encoder);
1078c2ecf20Sopenharmony_ci	return ret;
1088c2ecf20Sopenharmony_ci}
109