Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2016 Intel Corporation
0003  *
0004  * Permission to use, copy, modify, distribute, and sell this software and its
0005  * documentation for any purpose is hereby granted without fee, provided that
0006  * the above copyright notice appear in all copies and that both that copyright
0007  * notice and this permission notice appear in supporting documentation, and
0008  * that the name of the copyright holders not be used in advertising or
0009  * publicity pertaining to distribution of the software without specific,
0010  * written prior permission.  The copyright holders make no representations
0011  * about the suitability of this software for any purpose.  It is provided "as
0012  * is" without express or implied warranty.
0013  *
0014  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
0015  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
0016  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
0017  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
0018  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
0019  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
0020  * OF THIS SOFTWARE.
0021  */
0022 
0023 #include <drm/drm_atomic_helper.h>
0024 #include <drm/drm_fb_helper.h>
0025 #include <drm/drm_fourcc.h>
0026 #include <drm/drm_framebuffer.h>
0027 #include <drm/drm_modeset_helper.h>
0028 #include <drm/drm_plane_helper.h>
0029 #include <drm/drm_print.h>
0030 #include <drm/drm_probe_helper.h>
0031 
0032 /**
0033  * DOC: aux kms helpers
0034  *
0035  * This helper library contains various one-off functions which don't really fit
0036  * anywhere else in the DRM modeset helper library.
0037  */
0038 
0039 /**
0040  * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
0041  *                      connector list
0042  * @dev: drm device to operate on
0043  *
0044  * Some userspace presumes that the first connected connector is the main
0045  * display, where it's supposed to display e.g. the login screen. For
0046  * laptops, this should be the main panel. Use this function to sort all
0047  * (eDP/LVDS/DSI) panels to the front of the connector list, instead of
0048  * painstakingly trying to initialize them in the right order.
0049  */
0050 void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
0051 {
0052     struct drm_connector *connector, *tmp;
0053     struct list_head panel_list;
0054 
0055     INIT_LIST_HEAD(&panel_list);
0056 
0057     spin_lock_irq(&dev->mode_config.connector_list_lock);
0058     list_for_each_entry_safe(connector, tmp,
0059                  &dev->mode_config.connector_list, head) {
0060         if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
0061             connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
0062             connector->connector_type == DRM_MODE_CONNECTOR_DSI)
0063             list_move_tail(&connector->head, &panel_list);
0064     }
0065 
0066     list_splice(&panel_list, &dev->mode_config.connector_list);
0067     spin_unlock_irq(&dev->mode_config.connector_list_lock);
0068 }
0069 EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
0070 
0071 /**
0072  * drm_helper_mode_fill_fb_struct - fill out framebuffer metadata
0073  * @dev: DRM device
0074  * @fb: drm_framebuffer object to fill out
0075  * @mode_cmd: metadata from the userspace fb creation request
0076  *
0077  * This helper can be used in a drivers fb_create callback to pre-fill the fb's
0078  * metadata fields.
0079  */
0080 void drm_helper_mode_fill_fb_struct(struct drm_device *dev,
0081                     struct drm_framebuffer *fb,
0082                     const struct drm_mode_fb_cmd2 *mode_cmd)
0083 {
0084     int i;
0085 
0086     fb->dev = dev;
0087     fb->format = drm_get_format_info(dev, mode_cmd);
0088     fb->width = mode_cmd->width;
0089     fb->height = mode_cmd->height;
0090     for (i = 0; i < 4; i++) {
0091         fb->pitches[i] = mode_cmd->pitches[i];
0092         fb->offsets[i] = mode_cmd->offsets[i];
0093     }
0094     fb->modifier = mode_cmd->modifier[0];
0095     fb->flags = mode_cmd->flags;
0096 }
0097 EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
0098 
0099 /*
0100  * This is the minimal list of formats that seem to be safe for modeset use
0101  * with all current DRM drivers.  Most hardware can actually support more
0102  * formats than this and drivers may specify a more accurate list when
0103  * creating the primary plane.  However drivers that still call
0104  * drm_plane_init() will use this minimal format list as the default.
0105  */
0106 static const uint32_t safe_modeset_formats[] = {
0107     DRM_FORMAT_XRGB8888,
0108     DRM_FORMAT_ARGB8888,
0109 };
0110 
0111 static struct drm_plane *create_primary_plane(struct drm_device *dev)
0112 {
0113     struct drm_plane *primary;
0114     int ret;
0115 
0116     primary = kzalloc(sizeof(*primary), GFP_KERNEL);
0117     if (primary == NULL) {
0118         DRM_DEBUG_KMS("Failed to allocate primary plane\n");
0119         return NULL;
0120     }
0121 
0122     /*
0123      * Remove the format_default field from drm_plane when dropping
0124      * this helper.
0125      */
0126     primary->format_default = true;
0127 
0128     /* possible_crtc's will be filled in later by crtc_init */
0129     ret = drm_universal_plane_init(dev, primary, 0,
0130                        &drm_primary_helper_funcs,
0131                        safe_modeset_formats,
0132                        ARRAY_SIZE(safe_modeset_formats),
0133                        NULL,
0134                        DRM_PLANE_TYPE_PRIMARY, NULL);
0135     if (ret) {
0136         kfree(primary);
0137         primary = NULL;
0138     }
0139 
0140     return primary;
0141 }
0142 
0143 /**
0144  * drm_crtc_init - Legacy CRTC initialization function
0145  * @dev: DRM device
0146  * @crtc: CRTC object to init
0147  * @funcs: callbacks for the new CRTC
0148  *
0149  * Initialize a CRTC object with a default helper-provided primary plane and no
0150  * cursor plane.
0151  *
0152  * Note that we make some assumptions about hardware limitations that may not be
0153  * true for all hardware:
0154  *
0155  * 1. Primary plane cannot be repositioned.
0156  * 2. Primary plane cannot be scaled.
0157  * 3. Primary plane must cover the entire CRTC.
0158  * 4. Subpixel positioning is not supported.
0159  * 5. The primary plane must always be on if the CRTC is enabled.
0160  *
0161  * This is purely a backwards compatibility helper for old drivers. Drivers
0162  * should instead implement their own primary plane. Atomic drivers must do so.
0163  * Drivers with the above hardware restriction can look into using &struct
0164  * drm_simple_display_pipe, which encapsulates the above limitations into a nice
0165  * interface.
0166  *
0167  * Returns:
0168  * Zero on success, error code on failure.
0169  */
0170 int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
0171           const struct drm_crtc_funcs *funcs)
0172 {
0173     struct drm_plane *primary;
0174 
0175     primary = create_primary_plane(dev);
0176     return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs,
0177                      NULL);
0178 }
0179 EXPORT_SYMBOL(drm_crtc_init);
0180 
0181 /**
0182  * drm_mode_config_helper_suspend - Modeset suspend helper
0183  * @dev: DRM device
0184  *
0185  * This helper function takes care of suspending the modeset side. It disables
0186  * output polling if initialized, suspends fbdev if used and finally calls
0187  * drm_atomic_helper_suspend().
0188  * If suspending fails, fbdev and polling is re-enabled.
0189  *
0190  * Returns:
0191  * Zero on success, negative error code on error.
0192  *
0193  * See also:
0194  * drm_kms_helper_poll_disable() and drm_fb_helper_set_suspend_unlocked().
0195  */
0196 int drm_mode_config_helper_suspend(struct drm_device *dev)
0197 {
0198     struct drm_atomic_state *state;
0199 
0200     if (!dev)
0201         return 0;
0202 
0203     drm_kms_helper_poll_disable(dev);
0204     drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 1);
0205     state = drm_atomic_helper_suspend(dev);
0206     if (IS_ERR(state)) {
0207         drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0);
0208         drm_kms_helper_poll_enable(dev);
0209         return PTR_ERR(state);
0210     }
0211 
0212     dev->mode_config.suspend_state = state;
0213 
0214     return 0;
0215 }
0216 EXPORT_SYMBOL(drm_mode_config_helper_suspend);
0217 
0218 /**
0219  * drm_mode_config_helper_resume - Modeset resume helper
0220  * @dev: DRM device
0221  *
0222  * This helper function takes care of resuming the modeset side. It calls
0223  * drm_atomic_helper_resume(), resumes fbdev if used and enables output polling
0224  * if initiaized.
0225  *
0226  * Returns:
0227  * Zero on success, negative error code on error.
0228  *
0229  * See also:
0230  * drm_fb_helper_set_suspend_unlocked() and drm_kms_helper_poll_enable().
0231  */
0232 int drm_mode_config_helper_resume(struct drm_device *dev)
0233 {
0234     int ret;
0235 
0236     if (!dev)
0237         return 0;
0238 
0239     if (WARN_ON(!dev->mode_config.suspend_state))
0240         return -EINVAL;
0241 
0242     ret = drm_atomic_helper_resume(dev, dev->mode_config.suspend_state);
0243     if (ret)
0244         DRM_ERROR("Failed to resume (%d)\n", ret);
0245     dev->mode_config.suspend_state = NULL;
0246 
0247     drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0);
0248     drm_kms_helper_poll_enable(dev);
0249 
0250     return ret;
0251 }
0252 EXPORT_SYMBOL(drm_mode_config_helper_resume);