xref: /dragonfly/sys/dev/drm/drm_modeset_helper.c (revision 3f2dd94a)
11dedbd3bSFrançois Tigeot /*
21dedbd3bSFrançois Tigeot  * Copyright (c) 2016 Intel Corporation
31dedbd3bSFrançois Tigeot  *
41dedbd3bSFrançois Tigeot  * Permission to use, copy, modify, distribute, and sell this software and its
51dedbd3bSFrançois Tigeot  * documentation for any purpose is hereby granted without fee, provided that
61dedbd3bSFrançois Tigeot  * the above copyright notice appear in all copies and that both that copyright
71dedbd3bSFrançois Tigeot  * notice and this permission notice appear in supporting documentation, and
81dedbd3bSFrançois Tigeot  * that the name of the copyright holders not be used in advertising or
91dedbd3bSFrançois Tigeot  * publicity pertaining to distribution of the software without specific,
101dedbd3bSFrançois Tigeot  * written prior permission.  The copyright holders make no representations
111dedbd3bSFrançois Tigeot  * about the suitability of this software for any purpose.  It is provided "as
121dedbd3bSFrançois Tigeot  * is" without express or implied warranty.
131dedbd3bSFrançois Tigeot  *
141dedbd3bSFrançois Tigeot  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
151dedbd3bSFrançois Tigeot  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
161dedbd3bSFrançois Tigeot  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
171dedbd3bSFrançois Tigeot  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
181dedbd3bSFrançois Tigeot  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
191dedbd3bSFrançois Tigeot  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
201dedbd3bSFrançois Tigeot  * OF THIS SOFTWARE.
211dedbd3bSFrançois Tigeot  */
221dedbd3bSFrançois Tigeot 
231dedbd3bSFrançois Tigeot #include <drm/drm_modeset_helper.h>
241dedbd3bSFrançois Tigeot #include <drm/drm_plane_helper.h>
251dedbd3bSFrançois Tigeot 
261dedbd3bSFrançois Tigeot /**
271dedbd3bSFrançois Tigeot  * DOC: aux kms helpers
281dedbd3bSFrançois Tigeot  *
291dedbd3bSFrançois Tigeot  * This helper library contains various one-off functions which don't really fit
301dedbd3bSFrançois Tigeot  * anywhere else in the DRM modeset helper library.
311dedbd3bSFrançois Tigeot  */
321dedbd3bSFrançois Tigeot 
331dedbd3bSFrançois Tigeot /**
341dedbd3bSFrançois Tigeot  * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
351dedbd3bSFrançois Tigeot  * 						connector list
361dedbd3bSFrançois Tigeot  * @dev: drm device to operate on
371dedbd3bSFrançois Tigeot  *
381dedbd3bSFrançois Tigeot  * Some userspace presumes that the first connected connector is the main
391dedbd3bSFrançois Tigeot  * display, where it's supposed to display e.g. the login screen. For
401dedbd3bSFrançois Tigeot  * laptops, this should be the main panel. Use this function to sort all
414be47400SFrançois Tigeot  * (eDP/LVDS/DSI) panels to the front of the connector list, instead of
421dedbd3bSFrançois Tigeot  * painstakingly trying to initialize them in the right order.
431dedbd3bSFrançois Tigeot  */
drm_helper_move_panel_connectors_to_head(struct drm_device * dev)441dedbd3bSFrançois Tigeot void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
451dedbd3bSFrançois Tigeot {
461dedbd3bSFrançois Tigeot 	struct drm_connector *connector, *tmp;
471dedbd3bSFrançois Tigeot 	struct list_head panel_list;
481dedbd3bSFrançois Tigeot 
491dedbd3bSFrançois Tigeot 	INIT_LIST_HEAD(&panel_list);
501dedbd3bSFrançois Tigeot 
51a85cb24fSFrançois Tigeot 	spin_lock_irq(&dev->mode_config.connector_list_lock);
521dedbd3bSFrançois Tigeot 	list_for_each_entry_safe(connector, tmp,
531dedbd3bSFrançois Tigeot 				 &dev->mode_config.connector_list, head) {
541dedbd3bSFrançois Tigeot 		if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
554be47400SFrançois Tigeot 		    connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
564be47400SFrançois Tigeot 		    connector->connector_type == DRM_MODE_CONNECTOR_DSI)
571dedbd3bSFrançois Tigeot 			list_move_tail(&connector->head, &panel_list);
581dedbd3bSFrançois Tigeot 	}
591dedbd3bSFrançois Tigeot 
601dedbd3bSFrançois Tigeot 	list_splice(&panel_list, &dev->mode_config.connector_list);
61a85cb24fSFrançois Tigeot 	spin_unlock_irq(&dev->mode_config.connector_list_lock);
621dedbd3bSFrançois Tigeot }
631dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
641dedbd3bSFrançois Tigeot 
651dedbd3bSFrançois Tigeot /**
661dedbd3bSFrançois Tigeot  * drm_helper_mode_fill_fb_struct - fill out framebuffer metadata
67a85cb24fSFrançois Tigeot  * @dev: DRM device
681dedbd3bSFrançois Tigeot  * @fb: drm_framebuffer object to fill out
691dedbd3bSFrançois Tigeot  * @mode_cmd: metadata from the userspace fb creation request
701dedbd3bSFrançois Tigeot  *
711dedbd3bSFrançois Tigeot  * This helper can be used in a drivers fb_create callback to pre-fill the fb's
721dedbd3bSFrançois Tigeot  * metadata fields.
731dedbd3bSFrançois Tigeot  */
drm_helper_mode_fill_fb_struct(struct drm_device * dev,struct drm_framebuffer * fb,const struct drm_mode_fb_cmd2 * mode_cmd)74a85cb24fSFrançois Tigeot void drm_helper_mode_fill_fb_struct(struct drm_device *dev,
75a85cb24fSFrançois Tigeot 				    struct drm_framebuffer *fb,
761dedbd3bSFrançois Tigeot 				    const struct drm_mode_fb_cmd2 *mode_cmd)
771dedbd3bSFrançois Tigeot {
781dedbd3bSFrançois Tigeot 	int i;
791dedbd3bSFrançois Tigeot 
80a85cb24fSFrançois Tigeot 	fb->dev = dev;
81a85cb24fSFrançois Tigeot 	fb->format = drm_get_format_info(dev, mode_cmd);
821dedbd3bSFrançois Tigeot 	fb->width = mode_cmd->width;
831dedbd3bSFrançois Tigeot 	fb->height = mode_cmd->height;
841dedbd3bSFrançois Tigeot 	for (i = 0; i < 4; i++) {
851dedbd3bSFrançois Tigeot 		fb->pitches[i] = mode_cmd->pitches[i];
861dedbd3bSFrançois Tigeot 		fb->offsets[i] = mode_cmd->offsets[i];
871dedbd3bSFrançois Tigeot 	}
884be47400SFrançois Tigeot 	fb->modifier = mode_cmd->modifier[0];
891dedbd3bSFrançois Tigeot 	fb->flags = mode_cmd->flags;
901dedbd3bSFrançois Tigeot }
911dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
921dedbd3bSFrançois Tigeot 
931dedbd3bSFrançois Tigeot /*
941dedbd3bSFrançois Tigeot  * This is the minimal list of formats that seem to be safe for modeset use
951dedbd3bSFrançois Tigeot  * with all current DRM drivers.  Most hardware can actually support more
961dedbd3bSFrançois Tigeot  * formats than this and drivers may specify a more accurate list when
971dedbd3bSFrançois Tigeot  * creating the primary plane.  However drivers that still call
981dedbd3bSFrançois Tigeot  * drm_plane_init() will use this minimal format list as the default.
991dedbd3bSFrançois Tigeot  */
1001dedbd3bSFrançois Tigeot static const uint32_t safe_modeset_formats[] = {
1011dedbd3bSFrançois Tigeot 	DRM_FORMAT_XRGB8888,
1021dedbd3bSFrançois Tigeot 	DRM_FORMAT_ARGB8888,
1031dedbd3bSFrançois Tigeot };
1041dedbd3bSFrançois Tigeot 
create_primary_plane(struct drm_device * dev)1051dedbd3bSFrançois Tigeot static struct drm_plane *create_primary_plane(struct drm_device *dev)
1061dedbd3bSFrançois Tigeot {
1071dedbd3bSFrançois Tigeot 	struct drm_plane *primary;
1081dedbd3bSFrançois Tigeot 	int ret;
1091dedbd3bSFrançois Tigeot 
1101dedbd3bSFrançois Tigeot 	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
1111dedbd3bSFrançois Tigeot 	if (primary == NULL) {
1121dedbd3bSFrançois Tigeot 		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
1131dedbd3bSFrançois Tigeot 		return NULL;
1141dedbd3bSFrançois Tigeot 	}
1151dedbd3bSFrançois Tigeot 
1161dedbd3bSFrançois Tigeot 	/*
1171dedbd3bSFrançois Tigeot 	 * Remove the format_default field from drm_plane when dropping
1181dedbd3bSFrançois Tigeot 	 * this helper.
1191dedbd3bSFrançois Tigeot 	 */
1201dedbd3bSFrançois Tigeot 	primary->format_default = true;
1211dedbd3bSFrançois Tigeot 
1221dedbd3bSFrançois Tigeot 	/* possible_crtc's will be filled in later by crtc_init */
1231dedbd3bSFrançois Tigeot 	ret = drm_universal_plane_init(dev, primary, 0,
1241dedbd3bSFrançois Tigeot 				       &drm_primary_helper_funcs,
1251dedbd3bSFrançois Tigeot 				       safe_modeset_formats,
1261dedbd3bSFrançois Tigeot 				       ARRAY_SIZE(safe_modeset_formats),
127*3f2dd94aSFrançois Tigeot 				       NULL,
1281dedbd3bSFrançois Tigeot 				       DRM_PLANE_TYPE_PRIMARY, NULL);
1291dedbd3bSFrançois Tigeot 	if (ret) {
1301dedbd3bSFrançois Tigeot 		kfree(primary);
1311dedbd3bSFrançois Tigeot 		primary = NULL;
1321dedbd3bSFrançois Tigeot 	}
1331dedbd3bSFrançois Tigeot 
1341dedbd3bSFrançois Tigeot 	return primary;
1351dedbd3bSFrançois Tigeot }
1361dedbd3bSFrançois Tigeot 
1371dedbd3bSFrançois Tigeot /**
1381dedbd3bSFrançois Tigeot  * drm_crtc_init - Legacy CRTC initialization function
1391dedbd3bSFrançois Tigeot  * @dev: DRM device
1401dedbd3bSFrançois Tigeot  * @crtc: CRTC object to init
1411dedbd3bSFrançois Tigeot  * @funcs: callbacks for the new CRTC
1421dedbd3bSFrançois Tigeot  *
1431dedbd3bSFrançois Tigeot  * Initialize a CRTC object with a default helper-provided primary plane and no
1441dedbd3bSFrançois Tigeot  * cursor plane.
1451dedbd3bSFrançois Tigeot  *
1461dedbd3bSFrançois Tigeot  * Returns:
1471dedbd3bSFrançois Tigeot  * Zero on success, error code on failure.
1481dedbd3bSFrançois Tigeot  */
drm_crtc_init(struct drm_device * dev,struct drm_crtc * crtc,const struct drm_crtc_funcs * funcs)1491dedbd3bSFrançois Tigeot int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
1501dedbd3bSFrançois Tigeot 		  const struct drm_crtc_funcs *funcs)
1511dedbd3bSFrançois Tigeot {
1521dedbd3bSFrançois Tigeot 	struct drm_plane *primary;
1531dedbd3bSFrançois Tigeot 
1541dedbd3bSFrançois Tigeot 	primary = create_primary_plane(dev);
1551dedbd3bSFrançois Tigeot 	return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs,
1561dedbd3bSFrançois Tigeot 					 NULL);
1571dedbd3bSFrançois Tigeot }
1581dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_crtc_init);
159