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