xref: /openbmc/linux/drivers/gpu/drm/drm_client_modeset.c (revision 2e35facf82bcdd9b9eb9129f4fb31127b79249ec)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright 2018 Noralf Trønnes
4  * Copyright (c) 2006-2009 Red Hat Inc.
5  * Copyright (c) 2006-2008 Intel Corporation
6  *   Jesse Barnes <jesse.barnes@intel.com>
7  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
8  */
9 
10 #include <linux/module.h>
11 #include <linux/mutex.h>
12 #include <linux/slab.h>
13 
14 #include <drm/drm_client.h>
15 #include <drm/drm_crtc.h>
16 #include <drm/drm_device.h>
17 
18 int drm_client_modeset_create(struct drm_client_dev *client)
19 {
20 	struct drm_device *dev = client->dev;
21 	unsigned int num_crtc = dev->mode_config.num_crtc;
22 	unsigned int max_connector_count = 1;
23 	struct drm_mode_set *modeset;
24 	struct drm_crtc *crtc;
25 	unsigned int i = 0;
26 
27 	/* Add terminating zero entry to enable index less iteration */
28 	client->modesets = kcalloc(num_crtc + 1, sizeof(*client->modesets), GFP_KERNEL);
29 	if (!client->modesets)
30 		return -ENOMEM;
31 
32 	mutex_init(&client->modeset_mutex);
33 
34 	drm_for_each_crtc(crtc, dev)
35 		client->modesets[i++].crtc = crtc;
36 
37 	/* Cloning is only supported in the single crtc case. */
38 	if (num_crtc == 1)
39 		max_connector_count = DRM_CLIENT_MAX_CLONED_CONNECTORS;
40 
41 	for (modeset = client->modesets; modeset->crtc; modeset++) {
42 		modeset->connectors = kcalloc(max_connector_count,
43 					      sizeof(*modeset->connectors), GFP_KERNEL);
44 		if (!modeset->connectors)
45 			goto err_free;
46 	}
47 
48 	return 0;
49 
50 err_free:
51 	drm_client_modeset_free(client);
52 
53 	return -ENOMEM;
54 }
55 
56 void drm_client_modeset_release(struct drm_client_dev *client)
57 {
58 	struct drm_mode_set *modeset;
59 	unsigned int i;
60 
61 	drm_client_for_each_modeset(modeset, client) {
62 		drm_mode_destroy(client->dev, modeset->mode);
63 		modeset->mode = NULL;
64 		modeset->fb = NULL;
65 
66 		for (i = 0; i < modeset->num_connectors; i++) {
67 			drm_connector_put(modeset->connectors[i]);
68 			modeset->connectors[i] = NULL;
69 		}
70 		modeset->num_connectors = 0;
71 	}
72 }
73 /* TODO: Remove export when modeset code has been moved over */
74 EXPORT_SYMBOL(drm_client_modeset_release);
75 
76 void drm_client_modeset_free(struct drm_client_dev *client)
77 {
78 	struct drm_mode_set *modeset;
79 
80 	mutex_lock(&client->modeset_mutex);
81 
82 	drm_client_modeset_release(client);
83 
84 	drm_client_for_each_modeset(modeset, client)
85 		kfree(modeset->connectors);
86 
87 	mutex_unlock(&client->modeset_mutex);
88 
89 	mutex_destroy(&client->modeset_mutex);
90 	kfree(client->modesets);
91 }
92 
93 struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc)
94 {
95 	struct drm_mode_set *modeset;
96 
97 	drm_client_for_each_modeset(modeset, client)
98 		if (modeset->crtc == crtc)
99 			return modeset;
100 
101 	return NULL;
102 }
103 /* TODO: Remove export when modeset code has been moved over */
104 EXPORT_SYMBOL(drm_client_find_modeset);
105