File Index
Files and directories
Sign in
FILE

drm_modeset_helper.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/drm_modeset_helper.c C
  1/*
  2 * Copyright (c) 2016 Intel Corporation
  3 *
  4 * Permission to use, copy, modify, distribute, and sell this software and its
  5 * documentation for any purpose is hereby granted without fee, provided that
  6 * the above copyright notice appear in all copies and that both that copyright
  7 * notice and this permission notice appear in supporting documentation, and
  8 * that the name of the copyright holders not be used in advertising or
  9 * publicity pertaining to distribution of the software without specific,
 10 * written prior permission.  The copyright holders make no representations
 11 * about the suitability of this software for any purpose.  It is provided "as
 12 * is" without express or implied warranty.
 13 *
 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 20 * OF THIS SOFTWARE.
 21 */
 22
 23#include <linux/export.h>
 24
 25#include <drm/drm_atomic_helper.h>
 26#include <drm/drm_client_event.h>
 27#include <drm/drm_fourcc.h>
 28#include <drm/drm_framebuffer.h>
 29#include <drm/drm_modeset_helper.h>
 30#include <drm/drm_plane_helper.h>
 31#include <drm/drm_print.h>
 32#include <drm/drm_probe_helper.h>
 33
 34/**
 35 * DOC: aux kms helpers
 36 *
 37 * This helper library contains various one-off functions which don't really fit
 38 * anywhere else in the DRM modeset helper library.
 39 */
 40
 41/**
 42 * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
 43 * 						connector list
 44 * @dev: drm device to operate on
 45 *
 46 * Some userspace presumes that the first connected connector is the main
 47 * display, where it's supposed to display e.g. the login screen. For
 48 * laptops, this should be the main panel. Use this function to sort all
 49 * (eDP/LVDS/DSI) panels to the front of the connector list, instead of
 50 * painstakingly trying to initialize them in the right order.
 51 */
 52void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
 53{
 54	struct drm_connector *connector, *tmp;
 55	struct list_head panel_list;
 56
 57	INIT_LIST_HEAD(&panel_list);
 58
 59	spin_lock_irq(&dev->mode_config.connector_list_lock);
 60	list_for_each_entry_safe(connector, tmp,
 61				 &dev->mode_config.connector_list, head) {
 62		if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
 63		    connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
 64		    connector->connector_type == DRM_MODE_CONNECTOR_DSI)
 65			list_move_tail(&connector->head, &panel_list);
 66	}
 67
 68	list_splice(&panel_list, &dev->mode_config.connector_list);
 69	spin_unlock_irq(&dev->mode_config.connector_list_lock);
 70}
 71EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
 72
 73/**
 74 * drm_helper_mode_fill_fb_struct - fill out framebuffer metadata
 75 * @dev: DRM device
 76 * @fb: drm_framebuffer object to fill out
 77 * @info: pixel format information
 78 * @mode_cmd: metadata from the userspace fb creation request
 79 *
 80 * This helper can be used in a drivers fb_create callback to pre-fill the fb's
 81 * metadata fields.
 82 */
 83void drm_helper_mode_fill_fb_struct(struct drm_device *dev,
 84				    struct drm_framebuffer *fb,
 85				    const struct drm_format_info *info,
 86				    const struct drm_mode_fb_cmd2 *mode_cmd)
 87{
 88	int i;
 89
 90	fb->dev = dev;
 91	fb->format = info;
 92	fb->width = mode_cmd->width;
 93	fb->height = mode_cmd->height;
 94	for (i = 0; i < 4; i++) {
 95		fb->pitches[i] = mode_cmd->pitches[i];
 96		fb->offsets[i] = mode_cmd->offsets[i];
 97	}
 98	fb->modifier = mode_cmd->modifier[0];
 99	fb->flags = mode_cmd->flags;
100}
101EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
102
103/*
104 * This is the minimal list of formats that seem to be safe for modeset use
105 * with all current DRM drivers.  Most hardware can actually support more
106 * formats than this and drivers may specify a more accurate list when
107 * creating the primary plane.
108 */
109static const uint32_t safe_modeset_formats[] = {
110	DRM_FORMAT_XRGB8888,
111	DRM_FORMAT_ARGB8888,
112};
113
114static const struct drm_plane_funcs primary_plane_funcs = {
115	DRM_PLANE_NON_ATOMIC_FUNCS,
116};
117
118/**
119 * drm_crtc_init - Legacy CRTC initialization function
120 * @dev: DRM device
121 * @crtc: CRTC object to init
122 * @funcs: callbacks for the new CRTC
123 *
124 * Initialize a CRTC object with a default helper-provided primary plane and no
125 * cursor plane.
126 *
127 * Note that we make some assumptions about hardware limitations that may not be
128 * true for all hardware:
129 *
130 * 1. Primary plane cannot be repositioned.
131 * 2. Primary plane cannot be scaled.
132 * 3. Primary plane must cover the entire CRTC.
133 * 4. Subpixel positioning is not supported.
134 * 5. The primary plane must always be on if the CRTC is enabled.
135 *
136 * This is purely a backwards compatibility helper for old drivers. Drivers
137 * should instead implement their own primary plane. Atomic drivers must do so.
138 * Drivers with the above hardware restriction can look into using &struct
139 * drm_simple_display_pipe, which encapsulates the above limitations into a nice
140 * interface.
141 *
142 * Returns:
143 * Zero on success, error code on failure.
144 */
145int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
146		  const struct drm_crtc_funcs *funcs)
147{
148	struct drm_plane *primary;
149	int ret;
150
151	/* possible_crtc's will be filled in later by crtc_init */
152	primary = __drm_universal_plane_alloc(dev, sizeof(*primary), 0, 0,
153					      &primary_plane_funcs,
154					      safe_modeset_formats,
155					      ARRAY_SIZE(safe_modeset_formats),
156					      NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
157	if (IS_ERR(primary))
158		return PTR_ERR(primary);
159
160	/*
161	 * Remove the format_default field from drm_plane when dropping
162	 * this helper.
163	 */
164	primary->format_default = true;
165
166	ret = drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs, NULL);
167	if (ret)
168		goto err_drm_plane_cleanup;
169
170	return 0;
171
172err_drm_plane_cleanup:
173	drm_plane_cleanup(primary);
174	kfree(primary);
175	return ret;
176}
177EXPORT_SYMBOL(drm_crtc_init);
178
179/**
180 * drm_mode_config_helper_suspend - Modeset suspend helper
181 * @dev: DRM device
182 *
183 * This helper function takes care of suspending the modeset side. It disables
184 * output polling if initialized, suspends fbdev if used and finally calls
185 * drm_atomic_helper_suspend().
186 * If suspending fails, fbdev and polling is re-enabled.
187 *
188 * Returns:
189 * Zero on success, negative error code on error.
190 *
191 * See also:
192 * drm_kms_helper_poll_disable() and drm_client_dev_suspend().
193 */
194int drm_mode_config_helper_suspend(struct drm_device *dev)
195{
196	struct drm_atomic_state *state;
197
198	if (!dev)
199		return 0;
200	/*
201	 * Don't disable polling if it was never initialized
202	 */
203	if (dev->mode_config.poll_enabled)
204		drm_kms_helper_poll_disable(dev);
205
206	drm_client_dev_suspend(dev);
207	state = drm_atomic_helper_suspend(dev);
208	if (IS_ERR(state)) {
209		drm_client_dev_resume(dev);
210
211		/*
212		 * Don't enable polling if it was never initialized
213		 */
214		if (dev->mode_config.poll_enabled)
215			drm_kms_helper_poll_enable(dev);
216
217		return PTR_ERR(state);
218	}
219
220	dev->mode_config.suspend_state = state;
221
222	return 0;
223}
224EXPORT_SYMBOL(drm_mode_config_helper_suspend);
225
226/**
227 * drm_mode_config_helper_resume - Modeset resume helper
228 * @dev: DRM device
229 *
230 * This helper function takes care of resuming the modeset side. It calls
231 * drm_atomic_helper_resume(), resumes fbdev if used and enables output polling
232 * if initiaized.
233 *
234 * Returns:
235 * Zero on success, negative error code on error.
236 *
237 * See also:
238 * drm_client_dev_resume() and drm_kms_helper_poll_enable().
239 */
240int drm_mode_config_helper_resume(struct drm_device *dev)
241{
242	int ret;
243
244	if (!dev)
245		return 0;
246
247	if (WARN_ON(!dev->mode_config.suspend_state))
248		return -EINVAL;
249
250	ret = drm_atomic_helper_resume(dev, dev->mode_config.suspend_state);
251	if (ret)
252		DRM_ERROR("Failed to resume (%d)\n", ret);
253	dev->mode_config.suspend_state = NULL;
254
255	drm_client_dev_resume(dev);
256
257	/*
258	 * Don't enable polling if it is not initialized
259	 */
260	if (dev->mode_config.poll_enabled)
261		drm_kms_helper_poll_enable(dev);
262
263	return ret;
264}
265EXPORT_SYMBOL(drm_mode_config_helper_resume);
~/ Read-only file preview.