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