Line data Source code
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 <drm/drm_atomic_helper.h>
24 : #include <drm/drm_fb_helper.h>
25 : #include <drm/drm_fourcc.h>
26 : #include <drm/drm_framebuffer.h>
27 : #include <drm/drm_modeset_helper.h>
28 : #include <drm/drm_plane_helper.h>
29 : #include <drm/drm_print.h>
30 : #include <drm/drm_probe_helper.h>
31 :
32 : /**
33 : * DOC: aux kms helpers
34 : *
35 : * This helper library contains various one-off functions which don't really fit
36 : * anywhere else in the DRM modeset helper library.
37 : */
38 :
39 : /**
40 : * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
41 : * connector list
42 : * @dev: drm device to operate on
43 : *
44 : * Some userspace presumes that the first connected connector is the main
45 : * display, where it's supposed to display e.g. the login screen. For
46 : * laptops, this should be the main panel. Use this function to sort all
47 : * (eDP/LVDS/DSI) panels to the front of the connector list, instead of
48 : * painstakingly trying to initialize them in the right order.
49 : */
50 0 : void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
51 : {
52 : struct drm_connector *connector, *tmp;
53 : struct list_head panel_list;
54 :
55 0 : INIT_LIST_HEAD(&panel_list);
56 :
57 0 : spin_lock_irq(&dev->mode_config.connector_list_lock);
58 0 : list_for_each_entry_safe(connector, tmp,
59 : &dev->mode_config.connector_list, head) {
60 0 : if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
61 0 : connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
62 : connector->connector_type == DRM_MODE_CONNECTOR_DSI)
63 0 : list_move_tail(&connector->head, &panel_list);
64 : }
65 :
66 0 : list_splice(&panel_list, &dev->mode_config.connector_list);
67 0 : spin_unlock_irq(&dev->mode_config.connector_list_lock);
68 0 : }
69 : EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
70 :
71 : /**
72 : * drm_helper_mode_fill_fb_struct - fill out framebuffer metadata
73 : * @dev: DRM device
74 : * @fb: drm_framebuffer object to fill out
75 : * @mode_cmd: metadata from the userspace fb creation request
76 : *
77 : * This helper can be used in a drivers fb_create callback to pre-fill the fb's
78 : * metadata fields.
79 : */
80 0 : void drm_helper_mode_fill_fb_struct(struct drm_device *dev,
81 : struct drm_framebuffer *fb,
82 : const struct drm_mode_fb_cmd2 *mode_cmd)
83 : {
84 : int i;
85 :
86 0 : fb->dev = dev;
87 0 : fb->format = drm_get_format_info(dev, mode_cmd);
88 0 : fb->width = mode_cmd->width;
89 0 : fb->height = mode_cmd->height;
90 0 : for (i = 0; i < 4; i++) {
91 0 : fb->pitches[i] = mode_cmd->pitches[i];
92 0 : fb->offsets[i] = mode_cmd->offsets[i];
93 : }
94 0 : fb->modifier = mode_cmd->modifier[0];
95 0 : fb->flags = mode_cmd->flags;
96 0 : }
97 : EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
98 :
99 : /*
100 : * This is the minimal list of formats that seem to be safe for modeset use
101 : * with all current DRM drivers. Most hardware can actually support more
102 : * formats than this and drivers may specify a more accurate list when
103 : * creating the primary plane.
104 : */
105 : static const uint32_t safe_modeset_formats[] = {
106 : DRM_FORMAT_XRGB8888,
107 : DRM_FORMAT_ARGB8888,
108 : };
109 :
110 : static const struct drm_plane_funcs primary_plane_funcs = {
111 : DRM_PLANE_NON_ATOMIC_FUNCS,
112 : };
113 :
114 : /**
115 : * drm_crtc_init - Legacy CRTC initialization function
116 : * @dev: DRM device
117 : * @crtc: CRTC object to init
118 : * @funcs: callbacks for the new CRTC
119 : *
120 : * Initialize a CRTC object with a default helper-provided primary plane and no
121 : * cursor plane.
122 : *
123 : * Note that we make some assumptions about hardware limitations that may not be
124 : * true for all hardware:
125 : *
126 : * 1. Primary plane cannot be repositioned.
127 : * 2. Primary plane cannot be scaled.
128 : * 3. Primary plane must cover the entire CRTC.
129 : * 4. Subpixel positioning is not supported.
130 : * 5. The primary plane must always be on if the CRTC is enabled.
131 : *
132 : * This is purely a backwards compatibility helper for old drivers. Drivers
133 : * should instead implement their own primary plane. Atomic drivers must do so.
134 : * Drivers with the above hardware restriction can look into using &struct
135 : * drm_simple_display_pipe, which encapsulates the above limitations into a nice
136 : * interface.
137 : *
138 : * Returns:
139 : * Zero on success, error code on failure.
140 : */
141 0 : int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
142 : const struct drm_crtc_funcs *funcs)
143 : {
144 : struct drm_plane *primary;
145 : int ret;
146 :
147 : /* possible_crtc's will be filled in later by crtc_init */
148 0 : primary = __drm_universal_plane_alloc(dev, sizeof(*primary), 0, 0,
149 : &primary_plane_funcs,
150 : safe_modeset_formats,
151 : ARRAY_SIZE(safe_modeset_formats),
152 : NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
153 0 : if (IS_ERR(primary))
154 0 : return PTR_ERR(primary);
155 :
156 : /*
157 : * Remove the format_default field from drm_plane when dropping
158 : * this helper.
159 : */
160 0 : primary->format_default = true;
161 :
162 0 : ret = drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs, NULL);
163 0 : if (ret)
164 : goto err_drm_plane_cleanup;
165 :
166 : return 0;
167 :
168 : err_drm_plane_cleanup:
169 0 : drm_plane_cleanup(primary);
170 0 : kfree(primary);
171 0 : return ret;
172 : }
173 : EXPORT_SYMBOL(drm_crtc_init);
174 :
175 : /**
176 : * drm_mode_config_helper_suspend - Modeset suspend helper
177 : * @dev: DRM device
178 : *
179 : * This helper function takes care of suspending the modeset side. It disables
180 : * output polling if initialized, suspends fbdev if used and finally calls
181 : * drm_atomic_helper_suspend().
182 : * If suspending fails, fbdev and polling is re-enabled.
183 : *
184 : * Returns:
185 : * Zero on success, negative error code on error.
186 : *
187 : * See also:
188 : * drm_kms_helper_poll_disable() and drm_fb_helper_set_suspend_unlocked().
189 : */
190 0 : int drm_mode_config_helper_suspend(struct drm_device *dev)
191 : {
192 : struct drm_atomic_state *state;
193 :
194 0 : if (!dev)
195 : return 0;
196 :
197 0 : drm_kms_helper_poll_disable(dev);
198 0 : drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 1);
199 0 : state = drm_atomic_helper_suspend(dev);
200 0 : if (IS_ERR(state)) {
201 0 : drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0);
202 0 : drm_kms_helper_poll_enable(dev);
203 0 : return PTR_ERR(state);
204 : }
205 :
206 0 : dev->mode_config.suspend_state = state;
207 :
208 0 : return 0;
209 : }
210 : EXPORT_SYMBOL(drm_mode_config_helper_suspend);
211 :
212 : /**
213 : * drm_mode_config_helper_resume - Modeset resume helper
214 : * @dev: DRM device
215 : *
216 : * This helper function takes care of resuming the modeset side. It calls
217 : * drm_atomic_helper_resume(), resumes fbdev if used and enables output polling
218 : * if initiaized.
219 : *
220 : * Returns:
221 : * Zero on success, negative error code on error.
222 : *
223 : * See also:
224 : * drm_fb_helper_set_suspend_unlocked() and drm_kms_helper_poll_enable().
225 : */
226 0 : int drm_mode_config_helper_resume(struct drm_device *dev)
227 : {
228 : int ret;
229 :
230 0 : if (!dev)
231 : return 0;
232 :
233 0 : if (WARN_ON(!dev->mode_config.suspend_state))
234 : return -EINVAL;
235 :
236 0 : ret = drm_atomic_helper_resume(dev, dev->mode_config.suspend_state);
237 0 : if (ret)
238 0 : DRM_ERROR("Failed to resume (%d)\n", ret);
239 0 : dev->mode_config.suspend_state = NULL;
240 :
241 0 : drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0);
242 0 : drm_kms_helper_poll_enable(dev);
243 :
244 0 : return ret;
245 : }
246 : EXPORT_SYMBOL(drm_mode_config_helper_resume);
|