Rev 1430 | Rev 2160 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1430 | Rev 1963 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright (c) 2006-2008 Intel Corporation |
2 | * Copyright (c) 2006-2008 Intel Corporation |
3 | * Copyright (c) 2007 Dave Airlie |
3 | * Copyright (c) 2007 Dave Airlie |
4 | * |
4 | * |
5 | * DRM core CRTC related functions |
5 | * DRM core CRTC related functions |
6 | * |
6 | * |
7 | * Permission to use, copy, modify, distribute, and sell this software and its |
7 | * Permission to use, copy, modify, distribute, and sell this software and its |
8 | * documentation for any purpose is hereby granted without fee, provided that |
8 | * documentation for any purpose is hereby granted without fee, provided that |
9 | * the above copyright notice appear in all copies and that both that copyright |
9 | * the above copyright notice appear in all copies and that both that copyright |
10 | * notice and this permission notice appear in supporting documentation, and |
10 | * notice and this permission notice appear in supporting documentation, and |
11 | * that the name of the copyright holders not be used in advertising or |
11 | * that the name of the copyright holders not be used in advertising or |
12 | * publicity pertaining to distribution of the software without specific, |
12 | * publicity pertaining to distribution of the software without specific, |
13 | * written prior permission. The copyright holders make no representations |
13 | * written prior permission. The copyright holders make no representations |
14 | * about the suitability of this software for any purpose. It is provided "as |
14 | * about the suitability of this software for any purpose. It is provided "as |
15 | * is" without express or implied warranty. |
15 | * is" without express or implied warranty. |
16 | * |
16 | * |
17 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
17 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
18 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
18 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
19 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
19 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
20 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
20 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
21 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
21 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
22 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
22 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
23 | * OF THIS SOFTWARE. |
23 | * OF THIS SOFTWARE. |
24 | * |
24 | * |
25 | * Authors: |
25 | * Authors: |
26 | * Keith Packard |
26 | * Keith Packard |
27 | * Eric Anholt |
27 | * Eric Anholt |
28 | * Dave Airlie |
28 | * Dave Airlie |
29 | * Jesse Barnes |
29 | * Jesse Barnes |
30 | */ |
30 | */ |
31 | 31 | ||
32 | #include "drmP.h" |
32 | #include "drmP.h" |
33 | #include "drm_crtc.h" |
33 | #include "drm_crtc.h" |
34 | #include "drm_crtc_helper.h" |
34 | #include "drm_crtc_helper.h" |
35 | #include "drm_fb_helper.h" |
35 | #include "drm_fb_helper.h" |
- | 36 | ||
- | 37 | static bool drm_kms_helper_poll = true; |
|
36 | 38 | ||
37 | static void drm_mode_validate_flag(struct drm_connector *connector, |
39 | static void drm_mode_validate_flag(struct drm_connector *connector, |
38 | int flags) |
40 | int flags) |
39 | { |
41 | { |
40 | struct drm_display_mode *mode, *t; |
42 | struct drm_display_mode *mode, *t; |
41 | 43 | ||
42 | if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE)) |
44 | if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE)) |
43 | return; |
45 | return; |
44 | 46 | ||
45 | list_for_each_entry_safe(mode, t, &connector->modes, head) { |
47 | list_for_each_entry_safe(mode, t, &connector->modes, head) { |
46 | if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && |
48 | if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && |
47 | !(flags & DRM_MODE_FLAG_INTERLACE)) |
49 | !(flags & DRM_MODE_FLAG_INTERLACE)) |
48 | mode->status = MODE_NO_INTERLACE; |
50 | mode->status = MODE_NO_INTERLACE; |
49 | if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && |
51 | if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && |
50 | !(flags & DRM_MODE_FLAG_DBLSCAN)) |
52 | !(flags & DRM_MODE_FLAG_DBLSCAN)) |
51 | mode->status = MODE_NO_DBLESCAN; |
53 | mode->status = MODE_NO_DBLESCAN; |
52 | } |
54 | } |
53 | 55 | ||
54 | return; |
56 | return; |
55 | } |
57 | } |
56 | 58 | ||
57 | /** |
59 | /** |
58 | * drm_helper_probe_connector_modes - get complete set of display modes |
60 | * drm_helper_probe_single_connector_modes - get complete set of display modes |
59 | * @dev: DRM device |
61 | * @dev: DRM device |
60 | * @maxX: max width for modes |
62 | * @maxX: max width for modes |
61 | * @maxY: max height for modes |
63 | * @maxY: max height for modes |
62 | * |
64 | * |
63 | * LOCKING: |
65 | * LOCKING: |
64 | * Caller must hold mode config lock. |
66 | * Caller must hold mode config lock. |
65 | * |
67 | * |
66 | * Based on @dev's mode_config layout, scan all the connectors and try to detect |
68 | * Based on @dev's mode_config layout, scan all the connectors and try to detect |
67 | * modes on them. Modes will first be added to the connector's probed_modes |
69 | * modes on them. Modes will first be added to the connector's probed_modes |
68 | * list, then culled (based on validity and the @maxX, @maxY parameters) and |
70 | * list, then culled (based on validity and the @maxX, @maxY parameters) and |
69 | * put into the normal modes list. |
71 | * put into the normal modes list. |
70 | * |
72 | * |
71 | * Intended to be used either at bootup time or when major configuration |
73 | * Intended to be used either at bootup time or when major configuration |
72 | * changes have occurred. |
74 | * changes have occurred. |
73 | * |
75 | * |
74 | * FIXME: take into account monitor limits |
76 | * FIXME: take into account monitor limits |
75 | * |
77 | * |
76 | * RETURNS: |
78 | * RETURNS: |
77 | * Number of modes found on @connector. |
79 | * Number of modes found on @connector. |
78 | */ |
80 | */ |
79 | int drm_helper_probe_single_connector_modes(struct drm_connector *connector, |
81 | int drm_helper_probe_single_connector_modes(struct drm_connector *connector, |
80 | uint32_t maxX, uint32_t maxY) |
82 | uint32_t maxX, uint32_t maxY) |
81 | { |
83 | { |
82 | struct drm_device *dev = connector->dev; |
84 | struct drm_device *dev = connector->dev; |
83 | struct drm_display_mode *mode, *t; |
85 | struct drm_display_mode *mode, *t; |
84 | struct drm_connector_helper_funcs *connector_funcs = |
86 | struct drm_connector_helper_funcs *connector_funcs = |
85 | connector->helper_private; |
87 | connector->helper_private; |
86 | int count = 0; |
88 | int count = 0; |
87 | int mode_flags = 0; |
89 | int mode_flags = 0; |
- | 90 | ||
88 | 91 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, |
|
89 | DRM_DEBUG_KMS("%s\n", drm_get_connector_name(connector)); |
92 | drm_get_connector_name(connector)); |
90 | /* set all modes to the unverified state */ |
93 | /* set all modes to the unverified state */ |
91 | list_for_each_entry_safe(mode, t, &connector->modes, head) |
94 | list_for_each_entry_safe(mode, t, &connector->modes, head) |
92 | mode->status = MODE_UNVERIFIED; |
95 | mode->status = MODE_UNVERIFIED; |
93 | 96 | ||
94 | if (connector->force) { |
97 | if (connector->force) { |
95 | if (connector->force == DRM_FORCE_ON) |
98 | if (connector->force == DRM_FORCE_ON) |
96 | connector->status = connector_status_connected; |
99 | connector->status = connector_status_connected; |
97 | else |
100 | else |
98 | connector->status = connector_status_disconnected; |
101 | connector->status = connector_status_disconnected; |
99 | if (connector->funcs->force) |
102 | if (connector->funcs->force) |
100 | connector->funcs->force(connector); |
103 | connector->funcs->force(connector); |
101 | } else |
104 | } else { |
102 | connector->status = connector->funcs->detect(connector); |
105 | connector->status = connector->funcs->detect(connector, true); |
- | 106 | // drm_kms_helper_poll_enable(dev); |
|
- | 107 | } |
|
103 | 108 | ||
104 | if (connector->status == connector_status_disconnected) { |
109 | if (connector->status == connector_status_disconnected) { |
105 | DRM_DEBUG_KMS("%s is disconnected\n", |
110 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", |
- | 111 | connector->base.id, drm_get_connector_name(connector)); |
|
106 | drm_get_connector_name(connector)); |
112 | drm_mode_connector_update_edid_property(connector, NULL); |
107 | goto prune; |
113 | goto prune; |
108 | } |
114 | } |
109 | 115 | ||
110 | count = (*connector_funcs->get_modes)(connector); |
116 | count = (*connector_funcs->get_modes)(connector); |
111 | if (!count) { |
117 | if (count == 0 && connector->status == connector_status_connected) |
112 | count = drm_add_modes_noedid(connector, 1024, 768); |
118 | count = drm_add_modes_noedid(connector, 1024, 768); |
113 | if (!count) |
119 | if (count == 0) |
114 | return 0; |
120 | goto prune; |
115 | } |
- | |
116 | 121 | ||
117 | drm_mode_connector_list_update(connector); |
122 | drm_mode_connector_list_update(connector); |
118 | 123 | ||
119 | if (maxX && maxY) |
124 | if (maxX && maxY) |
120 | drm_mode_validate_size(dev, &connector->modes, maxX, |
125 | drm_mode_validate_size(dev, &connector->modes, maxX, |
121 | maxY, 0); |
126 | maxY, 0); |
122 | 127 | ||
123 | if (connector->interlace_allowed) |
128 | if (connector->interlace_allowed) |
124 | mode_flags |= DRM_MODE_FLAG_INTERLACE; |
129 | mode_flags |= DRM_MODE_FLAG_INTERLACE; |
125 | if (connector->doublescan_allowed) |
130 | if (connector->doublescan_allowed) |
126 | mode_flags |= DRM_MODE_FLAG_DBLSCAN; |
131 | mode_flags |= DRM_MODE_FLAG_DBLSCAN; |
127 | drm_mode_validate_flag(connector, mode_flags); |
132 | drm_mode_validate_flag(connector, mode_flags); |
128 | 133 | ||
129 | list_for_each_entry_safe(mode, t, &connector->modes, head) { |
134 | list_for_each_entry_safe(mode, t, &connector->modes, head) { |
130 | if (mode->status == MODE_OK) |
135 | if (mode->status == MODE_OK) |
131 | mode->status = connector_funcs->mode_valid(connector, |
136 | mode->status = connector_funcs->mode_valid(connector, |
132 | mode); |
137 | mode); |
133 | } |
138 | } |
134 | 139 | ||
135 | prune: |
140 | prune: |
136 | drm_mode_prune_invalid(dev, &connector->modes, true); |
141 | drm_mode_prune_invalid(dev, &connector->modes, true); |
137 | 142 | ||
138 | if (list_empty(&connector->modes)) |
143 | if (list_empty(&connector->modes)) |
139 | return 0; |
144 | return 0; |
140 | 145 | ||
141 | drm_mode_sort(&connector->modes); |
146 | drm_mode_sort(&connector->modes); |
142 | 147 | ||
143 | DRM_DEBUG_KMS("Probed modes for %s\n", |
148 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id, |
144 | drm_get_connector_name(connector)); |
149 | drm_get_connector_name(connector)); |
145 | list_for_each_entry_safe(mode, t, &connector->modes, head) { |
150 | list_for_each_entry_safe(mode, t, &connector->modes, head) { |
146 | mode->vrefresh = drm_mode_vrefresh(mode); |
151 | mode->vrefresh = drm_mode_vrefresh(mode); |
147 | 152 | ||
148 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
153 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
149 | drm_mode_debug_printmodeline(mode); |
154 | drm_mode_debug_printmodeline(mode); |
150 | } |
155 | } |
151 | 156 | ||
152 | return count; |
157 | return count; |
153 | } |
158 | } |
154 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); |
159 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); |
155 | - | ||
156 | int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX, |
- | |
157 | uint32_t maxY) |
- | |
158 | { |
- | |
159 | struct drm_connector *connector; |
- | |
160 | int count = 0; |
- | |
161 | - | ||
162 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
- | |
163 | count += drm_helper_probe_single_connector_modes(connector, |
- | |
164 | maxX, maxY); |
- | |
165 | } |
- | |
166 | - | ||
167 | return count; |
- | |
168 | } |
- | |
169 | EXPORT_SYMBOL(drm_helper_probe_connector_modes); |
- | |
170 | 160 | ||
171 | /** |
161 | /** |
172 | * drm_helper_encoder_in_use - check if a given encoder is in use |
162 | * drm_helper_encoder_in_use - check if a given encoder is in use |
173 | * @encoder: encoder to check |
163 | * @encoder: encoder to check |
174 | * |
164 | * |
175 | * LOCKING: |
165 | * LOCKING: |
176 | * Caller must hold mode config lock. |
166 | * Caller must hold mode config lock. |
177 | * |
167 | * |
178 | * Walk @encoders's DRM device's mode_config and see if it's in use. |
168 | * Walk @encoders's DRM device's mode_config and see if it's in use. |
179 | * |
169 | * |
180 | * RETURNS: |
170 | * RETURNS: |
181 | * True if @encoder is part of the mode_config, false otherwise. |
171 | * True if @encoder is part of the mode_config, false otherwise. |
182 | */ |
172 | */ |
183 | bool drm_helper_encoder_in_use(struct drm_encoder *encoder) |
173 | bool drm_helper_encoder_in_use(struct drm_encoder *encoder) |
184 | { |
174 | { |
185 | struct drm_connector *connector; |
175 | struct drm_connector *connector; |
186 | struct drm_device *dev = encoder->dev; |
176 | struct drm_device *dev = encoder->dev; |
187 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
177 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
188 | if (connector->encoder == encoder) |
178 | if (connector->encoder == encoder) |
189 | return true; |
179 | return true; |
190 | return false; |
180 | return false; |
191 | } |
181 | } |
192 | EXPORT_SYMBOL(drm_helper_encoder_in_use); |
182 | EXPORT_SYMBOL(drm_helper_encoder_in_use); |
193 | 183 | ||
194 | /** |
184 | /** |
195 | * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config |
185 | * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config |
196 | * @crtc: CRTC to check |
186 | * @crtc: CRTC to check |
197 | * |
187 | * |
198 | * LOCKING: |
188 | * LOCKING: |
199 | * Caller must hold mode config lock. |
189 | * Caller must hold mode config lock. |
200 | * |
190 | * |
201 | * Walk @crtc's DRM device's mode_config and see if it's in use. |
191 | * Walk @crtc's DRM device's mode_config and see if it's in use. |
202 | * |
192 | * |
203 | * RETURNS: |
193 | * RETURNS: |
204 | * True if @crtc is part of the mode_config, false otherwise. |
194 | * True if @crtc is part of the mode_config, false otherwise. |
205 | */ |
195 | */ |
206 | bool drm_helper_crtc_in_use(struct drm_crtc *crtc) |
196 | bool drm_helper_crtc_in_use(struct drm_crtc *crtc) |
207 | { |
197 | { |
208 | struct drm_encoder *encoder; |
198 | struct drm_encoder *encoder; |
209 | struct drm_device *dev = crtc->dev; |
199 | struct drm_device *dev = crtc->dev; |
210 | /* FIXME: Locking around list access? */ |
200 | /* FIXME: Locking around list access? */ |
211 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) |
201 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) |
212 | if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder)) |
202 | if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder)) |
213 | return true; |
203 | return true; |
214 | return false; |
204 | return false; |
215 | } |
205 | } |
216 | EXPORT_SYMBOL(drm_helper_crtc_in_use); |
206 | EXPORT_SYMBOL(drm_helper_crtc_in_use); |
- | 207 | ||
- | 208 | static void |
|
- | 209 | drm_encoder_disable(struct drm_encoder *encoder) |
|
- | 210 | { |
|
- | 211 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
|
- | 212 | ||
- | 213 | if (encoder_funcs->disable) |
|
- | 214 | (*encoder_funcs->disable)(encoder); |
|
- | 215 | else |
|
- | 216 | (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); |
|
- | 217 | } |
|
217 | 218 | ||
218 | /** |
219 | /** |
219 | * drm_helper_disable_unused_functions - disable unused objects |
220 | * drm_helper_disable_unused_functions - disable unused objects |
220 | * @dev: DRM device |
221 | * @dev: DRM device |
221 | * |
222 | * |
222 | * LOCKING: |
223 | * LOCKING: |
223 | * Caller must hold mode config lock. |
224 | * Caller must hold mode config lock. |
224 | * |
225 | * |
225 | * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled |
226 | * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled |
226 | * by calling its dpms function, which should power it off. |
227 | * by calling its dpms function, which should power it off. |
227 | */ |
228 | */ |
228 | void drm_helper_disable_unused_functions(struct drm_device *dev) |
229 | void drm_helper_disable_unused_functions(struct drm_device *dev) |
229 | { |
230 | { |
230 | struct drm_encoder *encoder; |
231 | struct drm_encoder *encoder; |
231 | struct drm_connector *connector; |
232 | struct drm_connector *connector; |
232 | struct drm_encoder_helper_funcs *encoder_funcs; |
- | |
233 | struct drm_crtc *crtc; |
233 | struct drm_crtc *crtc; |
234 | 234 | ||
235 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
235 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
236 | if (!connector->encoder) |
236 | if (!connector->encoder) |
237 | continue; |
237 | continue; |
238 | if (connector->status == connector_status_disconnected) |
238 | if (connector->status == connector_status_disconnected) |
239 | connector->encoder = NULL; |
239 | connector->encoder = NULL; |
240 | } |
240 | } |
241 | 241 | ||
242 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
242 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
243 | encoder_funcs = encoder->helper_private; |
- | |
244 | if (!drm_helper_encoder_in_use(encoder)) { |
243 | if (!drm_helper_encoder_in_use(encoder)) { |
245 | if (encoder_funcs->disable) |
- | |
246 | (*encoder_funcs->disable)(encoder); |
244 | drm_encoder_disable(encoder); |
247 | else |
- | |
248 | (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); |
- | |
249 | /* disconnector encoder from any connector */ |
245 | /* disconnector encoder from any connector */ |
250 | encoder->crtc = NULL; |
246 | encoder->crtc = NULL; |
251 | } |
247 | } |
252 | } |
248 | } |
253 | 249 | ||
254 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
250 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
255 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
251 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
256 | crtc->enabled = drm_helper_crtc_in_use(crtc); |
252 | crtc->enabled = drm_helper_crtc_in_use(crtc); |
257 | if (!crtc->enabled) { |
253 | if (!crtc->enabled) { |
- | 254 | if (crtc_funcs->disable) |
|
- | 255 | (*crtc_funcs->disable)(crtc); |
|
- | 256 | else |
|
258 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); |
257 | (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF); |
259 | crtc->fb = NULL; |
258 | crtc->fb = NULL; |
260 | } |
259 | } |
261 | } |
260 | } |
262 | } |
261 | } |
263 | EXPORT_SYMBOL(drm_helper_disable_unused_functions); |
262 | EXPORT_SYMBOL(drm_helper_disable_unused_functions); |
264 | - | ||
265 | static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height) |
- | |
266 | { |
- | |
267 | struct drm_display_mode *mode; |
- | |
268 | - | ||
269 | list_for_each_entry(mode, &connector->modes, head) { |
- | |
270 | if (drm_mode_width(mode) > width || |
- | |
271 | drm_mode_height(mode) > height) |
- | |
272 | continue; |
- | |
273 | if (mode->type & DRM_MODE_TYPE_PREFERRED) |
- | |
274 | return mode; |
- | |
275 | } |
- | |
276 | return NULL; |
- | |
277 | } |
- | |
278 | - | ||
279 | static bool drm_has_cmdline_mode(struct drm_connector *connector) |
- | |
280 | { |
- | |
281 | struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; |
- | |
282 | struct drm_fb_helper_cmdline_mode *cmdline_mode; |
- | |
283 | - | ||
284 | if (!fb_help_conn) |
- | |
285 | return false; |
- | |
286 | - | ||
287 | cmdline_mode = &fb_help_conn->cmdline_mode; |
- | |
288 | return cmdline_mode->specified; |
- | |
289 | } |
- | |
290 | - | ||
291 | static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *connector, int width, int height) |
- | |
292 | { |
- | |
293 | struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; |
- | |
294 | struct drm_fb_helper_cmdline_mode *cmdline_mode; |
- | |
295 | struct drm_display_mode *mode = NULL; |
- | |
296 | - | ||
297 | if (!fb_help_conn) |
- | |
298 | return mode; |
- | |
299 | - | ||
300 | cmdline_mode = &fb_help_conn->cmdline_mode; |
- | |
301 | if (cmdline_mode->specified == false) |
- | |
302 | return mode; |
- | |
303 | - | ||
304 | /* attempt to find a matching mode in the list of modes |
- | |
305 | * we have gotten so far, if not add a CVT mode that conforms |
- | |
306 | */ |
- | |
307 | if (cmdline_mode->rb || cmdline_mode->margins) |
- | |
308 | goto create_mode; |
- | |
309 | - | ||
310 | list_for_each_entry(mode, &connector->modes, head) { |
- | |
311 | /* check width/height */ |
- | |
312 | if (mode->hdisplay != cmdline_mode->xres || |
- | |
313 | mode->vdisplay != cmdline_mode->yres) |
- | |
314 | continue; |
- | |
315 | - | ||
316 | if (cmdline_mode->refresh_specified) { |
- | |
317 | if (mode->vrefresh != cmdline_mode->refresh) |
- | |
318 | continue; |
- | |
319 | } |
- | |
320 | - | ||
321 | if (cmdline_mode->interlace) { |
- | |
322 | if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) |
- | |
323 | continue; |
- | |
324 | } |
- | |
325 | return mode; |
- | |
326 | } |
- | |
327 | - | ||
328 | create_mode: |
- | |
329 | mode = drm_cvt_mode(connector->dev, cmdline_mode->xres, |
- | |
330 | cmdline_mode->yres, |
- | |
331 | cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60, |
- | |
332 | cmdline_mode->rb, cmdline_mode->interlace, |
- | |
333 | cmdline_mode->margins); |
- | |
334 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
- | |
335 | list_add(&mode->head, &connector->modes); |
- | |
336 | return mode; |
- | |
337 | } |
- | |
338 | - | ||
339 | static bool drm_connector_enabled(struct drm_connector *connector, bool strict) |
- | |
340 | { |
- | |
341 | bool enable; |
- | |
342 | - | ||
343 | if (strict) { |
- | |
344 | enable = connector->status == connector_status_connected; |
- | |
345 | } else { |
- | |
346 | enable = connector->status != connector_status_disconnected; |
- | |
347 | } |
- | |
348 | return enable; |
- | |
349 | } |
- | |
350 | - | ||
351 | static void drm_enable_connectors(struct drm_device *dev, bool *enabled) |
- | |
352 | { |
- | |
353 | bool any_enabled = false; |
- | |
354 | struct drm_connector *connector; |
- | |
355 | int i = 0; |
- | |
356 | - | ||
357 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
- | |
358 | enabled[i] = drm_connector_enabled(connector, true); |
- | |
359 | DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id, |
- | |
360 | enabled[i] ? "yes" : "no"); |
- | |
361 | any_enabled |= enabled[i]; |
- | |
362 | i++; |
- | |
363 | } |
- | |
364 | - | ||
365 | if (any_enabled) |
- | |
366 | return; |
- | |
367 | - | ||
368 | i = 0; |
- | |
369 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
- | |
370 | enabled[i] = drm_connector_enabled(connector, false); |
- | |
371 | i++; |
- | |
372 | } |
- | |
373 | } |
- | |
374 | - | ||
375 | static bool drm_target_preferred(struct drm_device *dev, |
- | |
376 | struct drm_display_mode **modes, |
- | |
377 | bool *enabled, int width, int height) |
- | |
378 | { |
- | |
379 | struct drm_connector *connector; |
- | |
380 | int i = 0; |
- | |
381 | - | ||
382 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
- | |
383 | - | ||
384 | if (enabled[i] == false) { |
- | |
385 | i++; |
- | |
386 | continue; |
- | |
387 | } |
- | |
388 | - | ||
389 | DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", |
- | |
390 | connector->base.id); |
- | |
391 | - | ||
392 | /* got for command line mode first */ |
- | |
393 | modes[i] = drm_pick_cmdline_mode(connector, width, height); |
- | |
394 | if (!modes[i]) { |
- | |
395 | DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", |
- | |
396 | connector->base.id); |
- | |
397 | modes[i] = drm_has_preferred_mode(connector, width, height); |
- | |
398 | } |
- | |
399 | /* No preferred modes, pick one off the list */ |
- | |
400 | if (!modes[i] && !list_empty(&connector->modes)) { |
- | |
401 | list_for_each_entry(modes[i], &connector->modes, head) |
- | |
402 | break; |
- | |
403 | } |
- | |
404 | DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : |
- | |
405 | "none"); |
- | |
406 | i++; |
- | |
407 | } |
- | |
408 | return true; |
- | |
409 | } |
- | |
410 | - | ||
411 | static int drm_pick_crtcs(struct drm_device *dev, |
- | |
412 | struct drm_crtc **best_crtcs, |
- | |
413 | struct drm_display_mode **modes, |
- | |
414 | int n, int width, int height) |
- | |
415 | { |
- | |
416 | int c, o; |
- | |
417 | struct drm_connector *connector; |
- | |
418 | struct drm_connector_helper_funcs *connector_funcs; |
- | |
419 | struct drm_encoder *encoder; |
- | |
420 | struct drm_crtc *best_crtc; |
- | |
421 | int my_score, best_score, score; |
- | |
422 | struct drm_crtc **crtcs, *crtc; |
- | |
423 | - | ||
424 | if (n == dev->mode_config.num_connector) |
- | |
425 | return 0; |
- | |
426 | c = 0; |
- | |
427 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
- | |
428 | if (c == n) |
- | |
429 | break; |
- | |
430 | c++; |
- | |
431 | } |
- | |
432 | - | ||
433 | best_crtcs[n] = NULL; |
- | |
434 | best_crtc = NULL; |
- | |
435 | best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); |
- | |
436 | if (modes[n] == NULL) |
- | |
437 | return best_score; |
- | |
438 | - | ||
439 | crtcs = kmalloc(dev->mode_config.num_connector * |
- | |
440 | sizeof(struct drm_crtc *), GFP_KERNEL); |
- | |
441 | if (!crtcs) |
- | |
442 | return best_score; |
- | |
443 | - | ||
444 | my_score = 1; |
- | |
445 | if (connector->status == connector_status_connected) |
- | |
446 | my_score++; |
- | |
447 | if (drm_has_cmdline_mode(connector)) |
- | |
448 | my_score++; |
- | |
449 | if (drm_has_preferred_mode(connector, width, height)) |
- | |
450 | my_score++; |
- | |
451 | - | ||
452 | connector_funcs = connector->helper_private; |
- | |
453 | encoder = connector_funcs->best_encoder(connector); |
- | |
454 | if (!encoder) |
- | |
455 | goto out; |
- | |
456 | - | ||
457 | connector->encoder = encoder; |
- | |
458 | - | ||
459 | /* select a crtc for this connector and then attempt to configure |
- | |
460 | remaining connectors */ |
- | |
461 | c = 0; |
- | |
462 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
- | |
463 | - | ||
464 | if ((encoder->possible_crtcs & (1 << c)) == 0) { |
- | |
465 | c++; |
- | |
466 | continue; |
- | |
467 | } |
- | |
468 | - | ||
469 | for (o = 0; o < n; o++) |
- | |
470 | if (best_crtcs[o] == crtc) |
- | |
471 | break; |
- | |
472 | - | ||
473 | if (o < n) { |
- | |
474 | /* ignore cloning for now */ |
- | |
475 | c++; |
- | |
476 | continue; |
- | |
477 | } |
- | |
478 | - | ||
479 | crtcs[n] = crtc; |
- | |
480 | memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *)); |
- | |
481 | score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1, |
- | |
482 | width, height); |
- | |
483 | if (score > best_score) { |
- | |
484 | best_crtc = crtc; |
- | |
485 | best_score = score; |
- | |
486 | memcpy(best_crtcs, crtcs, |
- | |
487 | dev->mode_config.num_connector * |
- | |
488 | sizeof(struct drm_crtc *)); |
- | |
489 | } |
- | |
490 | c++; |
- | |
491 | } |
- | |
492 | out: |
- | |
493 | kfree(crtcs); |
- | |
494 | return best_score; |
- | |
495 | } |
- | |
496 | - | ||
497 | static void drm_setup_crtcs(struct drm_device *dev) |
- | |
498 | { |
- | |
499 | struct drm_crtc **crtcs; |
- | |
500 | struct drm_display_mode **modes; |
- | |
501 | struct drm_encoder *encoder; |
- | |
502 | struct drm_connector *connector; |
- | |
503 | bool *enabled; |
- | |
504 | int width, height; |
- | |
505 | int i, ret; |
- | |
506 | - | ||
507 | DRM_DEBUG_KMS("\n"); |
- | |
508 | - | ||
509 | width = dev->mode_config.max_width; |
- | |
510 | height = dev->mode_config.max_height; |
- | |
511 | - | ||
512 | /* clean out all the encoder/crtc combos */ |
- | |
513 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
- | |
514 | encoder->crtc = NULL; |
- | |
515 | } |
- | |
516 | - | ||
517 | crtcs = kcalloc(dev->mode_config.num_connector, |
- | |
518 | sizeof(struct drm_crtc *), GFP_KERNEL); |
- | |
519 | modes = kcalloc(dev->mode_config.num_connector, |
- | |
520 | sizeof(struct drm_display_mode *), GFP_KERNEL); |
- | |
521 | enabled = kcalloc(dev->mode_config.num_connector, |
- | |
522 | sizeof(bool), GFP_KERNEL); |
- | |
523 | - | ||
524 | drm_enable_connectors(dev, enabled); |
- | |
525 | - | ||
526 | ret = drm_target_preferred(dev, modes, enabled, width, height); |
- | |
527 | if (!ret) |
- | |
528 | DRM_ERROR("Unable to find initial modes\n"); |
- | |
529 | - | ||
530 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); |
- | |
531 | - | ||
532 | drm_pick_crtcs(dev, crtcs, modes, 0, width, height); |
- | |
533 | - | ||
534 | i = 0; |
- | |
535 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
- | |
536 | struct drm_display_mode *mode = modes[i]; |
- | |
537 | struct drm_crtc *crtc = crtcs[i]; |
- | |
538 | - | ||
539 | if (connector->encoder == NULL) { |
- | |
540 | i++; |
- | |
541 | continue; |
- | |
542 | } |
- | |
543 | - | ||
544 | if (mode && crtc) { |
- | |
545 | DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", |
- | |
546 | mode->name, crtc->base.id); |
- | |
547 | crtc->desired_mode = mode; |
- | |
548 | connector->encoder->crtc = crtc; |
- | |
549 | } else { |
- | |
550 | connector->encoder->crtc = NULL; |
- | |
551 | connector->encoder = NULL; |
- | |
552 | } |
- | |
553 | i++; |
- | |
554 | } |
- | |
555 | - | ||
556 | kfree(crtcs); |
- | |
557 | kfree(modes); |
- | |
558 | kfree(enabled); |
- | |
559 | } |
- | |
560 | 263 | ||
561 | /** |
264 | /** |
562 | * drm_encoder_crtc_ok - can a given crtc drive a given encoder? |
265 | * drm_encoder_crtc_ok - can a given crtc drive a given encoder? |
563 | * @encoder: encoder to test |
266 | * @encoder: encoder to test |
564 | * @crtc: crtc to test |
267 | * @crtc: crtc to test |
565 | * |
268 | * |
566 | * Return false if @encoder can't be driven by @crtc, true otherwise. |
269 | * Return false if @encoder can't be driven by @crtc, true otherwise. |
567 | */ |
270 | */ |
568 | static bool drm_encoder_crtc_ok(struct drm_encoder *encoder, |
271 | static bool drm_encoder_crtc_ok(struct drm_encoder *encoder, |
569 | struct drm_crtc *crtc) |
272 | struct drm_crtc *crtc) |
570 | { |
273 | { |
571 | struct drm_device *dev; |
274 | struct drm_device *dev; |
572 | struct drm_crtc *tmp; |
275 | struct drm_crtc *tmp; |
573 | int crtc_mask = 1; |
276 | int crtc_mask = 1; |
574 | 277 | ||
575 | WARN(!crtc, "checking null crtc?"); |
278 | WARN(!crtc, "checking null crtc?\n"); |
576 | 279 | ||
577 | dev = crtc->dev; |
280 | dev = crtc->dev; |
578 | 281 | ||
579 | list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { |
282 | list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { |
580 | if (tmp == crtc) |
283 | if (tmp == crtc) |
581 | break; |
284 | break; |
582 | crtc_mask <<= 1; |
285 | crtc_mask <<= 1; |
583 | } |
286 | } |
584 | 287 | ||
585 | if (encoder->possible_crtcs & crtc_mask) |
288 | if (encoder->possible_crtcs & crtc_mask) |
586 | return true; |
289 | return true; |
587 | return false; |
290 | return false; |
588 | } |
291 | } |
589 | 292 | ||
590 | /* |
293 | /* |
591 | * Check the CRTC we're going to map each output to vs. its current |
294 | * Check the CRTC we're going to map each output to vs. its current |
592 | * CRTC. If they don't match, we have to disable the output and the CRTC |
295 | * CRTC. If they don't match, we have to disable the output and the CRTC |
593 | * since the driver will have to re-route things. |
296 | * since the driver will have to re-route things. |
594 | */ |
297 | */ |
595 | static void |
298 | static void |
596 | drm_crtc_prepare_encoders(struct drm_device *dev) |
299 | drm_crtc_prepare_encoders(struct drm_device *dev) |
597 | { |
300 | { |
598 | struct drm_encoder_helper_funcs *encoder_funcs; |
301 | struct drm_encoder_helper_funcs *encoder_funcs; |
599 | struct drm_encoder *encoder; |
302 | struct drm_encoder *encoder; |
600 | 303 | ||
601 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
304 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
602 | encoder_funcs = encoder->helper_private; |
305 | encoder_funcs = encoder->helper_private; |
603 | /* Disable unused encoders */ |
306 | /* Disable unused encoders */ |
604 | if (encoder->crtc == NULL) |
307 | if (encoder->crtc == NULL) |
605 | (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); |
308 | drm_encoder_disable(encoder); |
606 | /* Disable encoders whose CRTC is about to change */ |
309 | /* Disable encoders whose CRTC is about to change */ |
607 | if (encoder_funcs->get_crtc && |
310 | if (encoder_funcs->get_crtc && |
608 | encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) |
311 | encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) |
609 | (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); |
312 | drm_encoder_disable(encoder); |
610 | } |
313 | } |
611 | } |
314 | } |
612 | 315 | ||
613 | /** |
316 | /** |
614 | * drm_crtc_set_mode - set a mode |
317 | * drm_crtc_set_mode - set a mode |
615 | * @crtc: CRTC to program |
318 | * @crtc: CRTC to program |
616 | * @mode: mode to use |
319 | * @mode: mode to use |
617 | * @x: width of mode |
320 | * @x: width of mode |
618 | * @y: height of mode |
321 | * @y: height of mode |
619 | * |
322 | * |
620 | * LOCKING: |
323 | * LOCKING: |
621 | * Caller must hold mode config lock. |
324 | * Caller must hold mode config lock. |
622 | * |
325 | * |
623 | * Try to set @mode on @crtc. Give @crtc and its associated connectors a chance |
326 | * Try to set @mode on @crtc. Give @crtc and its associated connectors a chance |
624 | * to fixup or reject the mode prior to trying to set it. |
327 | * to fixup or reject the mode prior to trying to set it. |
625 | * |
328 | * |
626 | * RETURNS: |
329 | * RETURNS: |
627 | * True if the mode was set successfully, or false otherwise. |
330 | * True if the mode was set successfully, or false otherwise. |
628 | */ |
331 | */ |
629 | bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, |
332 | bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, |
630 | struct drm_display_mode *mode, |
333 | struct drm_display_mode *mode, |
631 | int x, int y, |
334 | int x, int y, |
632 | struct drm_framebuffer *old_fb) |
335 | struct drm_framebuffer *old_fb) |
633 | { |
336 | { |
634 | struct drm_device *dev = crtc->dev; |
337 | struct drm_device *dev = crtc->dev; |
635 | struct drm_display_mode *adjusted_mode, saved_mode; |
338 | struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; |
636 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
339 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
637 | struct drm_encoder_helper_funcs *encoder_funcs; |
340 | struct drm_encoder_helper_funcs *encoder_funcs; |
638 | int saved_x, saved_y; |
341 | int saved_x, saved_y; |
639 | struct drm_encoder *encoder; |
342 | struct drm_encoder *encoder; |
640 | bool ret = true; |
343 | bool ret = true; |
641 | - | ||
642 | adjusted_mode = drm_mode_duplicate(dev, mode); |
- | |
643 | 344 | ||
644 | crtc->enabled = drm_helper_crtc_in_use(crtc); |
- | |
645 | 345 | crtc->enabled = drm_helper_crtc_in_use(crtc); |
|
646 | if (!crtc->enabled) |
346 | if (!crtc->enabled) |
647 | return true; |
347 | return true; |
- | 348 | ||
- | 349 | adjusted_mode = drm_mode_duplicate(dev, mode); |
|
- | 350 | ||
648 | 351 | saved_hwmode = crtc->hwmode; |
|
649 | saved_mode = crtc->mode; |
352 | saved_mode = crtc->mode; |
650 | saved_x = crtc->x; |
353 | saved_x = crtc->x; |
651 | saved_y = crtc->y; |
354 | saved_y = crtc->y; |
652 | 355 | ||
653 | /* Update crtc values up front so the driver can rely on them for mode |
356 | /* Update crtc values up front so the driver can rely on them for mode |
654 | * setting. |
357 | * setting. |
655 | */ |
358 | */ |
656 | crtc->mode = *mode; |
359 | crtc->mode = *mode; |
657 | crtc->x = x; |
360 | crtc->x = x; |
658 | crtc->y = y; |
361 | crtc->y = y; |
659 | 362 | ||
660 | /* Pass our mode to the connectors and the CRTC to give them a chance to |
363 | /* Pass our mode to the connectors and the CRTC to give them a chance to |
661 | * adjust it according to limitations or connector properties, and also |
364 | * adjust it according to limitations or connector properties, and also |
662 | * a chance to reject the mode entirely. |
365 | * a chance to reject the mode entirely. |
663 | */ |
366 | */ |
664 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
367 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
665 | 368 | ||
666 | if (encoder->crtc != crtc) |
369 | if (encoder->crtc != crtc) |
667 | continue; |
370 | continue; |
668 | encoder_funcs = encoder->helper_private; |
371 | encoder_funcs = encoder->helper_private; |
669 | if (!(ret = encoder_funcs->mode_fixup(encoder, mode, |
372 | if (!(ret = encoder_funcs->mode_fixup(encoder, mode, |
670 | adjusted_mode))) { |
373 | adjusted_mode))) { |
671 | goto done; |
374 | goto done; |
672 | } |
375 | } |
673 | } |
376 | } |
674 | 377 | ||
675 | if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { |
378 | if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { |
676 | goto done; |
379 | goto done; |
677 | } |
380 | } |
- | 381 | DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); |
|
678 | 382 | ||
679 | /* Prepare the encoders and CRTCs before setting the mode. */ |
383 | /* Prepare the encoders and CRTCs before setting the mode. */ |
680 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
384 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
681 | 385 | ||
682 | if (encoder->crtc != crtc) |
386 | if (encoder->crtc != crtc) |
683 | continue; |
387 | continue; |
684 | encoder_funcs = encoder->helper_private; |
388 | encoder_funcs = encoder->helper_private; |
685 | /* Disable the encoders as the first thing we do. */ |
389 | /* Disable the encoders as the first thing we do. */ |
686 | encoder_funcs->prepare(encoder); |
390 | encoder_funcs->prepare(encoder); |
687 | } |
391 | } |
688 | 392 | ||
689 | drm_crtc_prepare_encoders(dev); |
393 | drm_crtc_prepare_encoders(dev); |
690 | 394 | ||
691 | crtc_funcs->prepare(crtc); |
395 | crtc_funcs->prepare(crtc); |
692 | 396 | ||
693 | /* Set up the DPLL and any encoders state that needs to adjust or depend |
397 | /* Set up the DPLL and any encoders state that needs to adjust or depend |
694 | * on the DPLL. |
398 | * on the DPLL. |
695 | */ |
399 | */ |
696 | ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb); |
400 | ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb); |
697 | if (!ret) |
401 | if (!ret) |
698 | goto done; |
402 | goto done; |
699 | 403 | ||
700 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
404 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
701 | 405 | ||
702 | if (encoder->crtc != crtc) |
406 | if (encoder->crtc != crtc) |
703 | continue; |
407 | continue; |
- | 408 | ||
704 | 409 | DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", |
|
705 | DRM_DEBUG("%s: set mode %s %x\n", drm_get_encoder_name(encoder), |
410 | encoder->base.id, drm_get_encoder_name(encoder), |
706 | mode->name, mode->base.id); |
411 | mode->base.id, mode->name); |
707 | encoder_funcs = encoder->helper_private; |
412 | encoder_funcs = encoder->helper_private; |
708 | encoder_funcs->mode_set(encoder, mode, adjusted_mode); |
413 | encoder_funcs->mode_set(encoder, mode, adjusted_mode); |
709 | } |
414 | } |
710 | 415 | ||
711 | /* Now enable the clocks, plane, pipe, and connectors that we set up. */ |
416 | /* Now enable the clocks, plane, pipe, and connectors that we set up. */ |
712 | crtc_funcs->commit(crtc); |
417 | crtc_funcs->commit(crtc); |
713 | 418 | ||
714 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
419 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
715 | 420 | ||
716 | if (encoder->crtc != crtc) |
421 | if (encoder->crtc != crtc) |
717 | continue; |
422 | continue; |
718 | 423 | ||
719 | encoder_funcs = encoder->helper_private; |
424 | encoder_funcs = encoder->helper_private; |
720 | encoder_funcs->commit(encoder); |
425 | encoder_funcs->commit(encoder); |
721 | 426 | ||
722 | } |
427 | } |
723 | 428 | ||
724 | /* XXX free adjustedmode */ |
429 | /* Store real post-adjustment hardware mode. */ |
- | 430 | crtc->hwmode = *adjusted_mode; |
|
- | 431 | ||
- | 432 | /* Calculate and store various constants which |
|
- | 433 | * are later needed by vblank and swap-completion |
|
- | 434 | * timestamping. They are derived from true hwmode. |
|
- | 435 | */ |
|
- | 436 | drm_calc_timestamping_constants(crtc); |
|
725 | drm_mode_destroy(dev, adjusted_mode); |
437 | |
726 | /* FIXME: add subpixel order */ |
438 | /* FIXME: add subpixel order */ |
- | 439 | done: |
|
727 | done: |
440 | drm_mode_destroy(dev, adjusted_mode); |
- | 441 | if (!ret) { |
|
728 | if (!ret) { |
442 | crtc->hwmode = saved_hwmode; |
729 | crtc->mode = saved_mode; |
443 | crtc->mode = saved_mode; |
730 | crtc->x = saved_x; |
444 | crtc->x = saved_x; |
731 | crtc->y = saved_y; |
445 | crtc->y = saved_y; |
732 | } |
446 | } |
733 | 447 | ||
734 | return ret; |
448 | return ret; |
735 | } |
449 | } |
736 | EXPORT_SYMBOL(drm_crtc_helper_set_mode); |
450 | EXPORT_SYMBOL(drm_crtc_helper_set_mode); |
737 | 451 | ||
738 | 452 | ||
739 | /** |
453 | /** |
740 | * drm_crtc_helper_set_config - set a new config from userspace |
454 | * drm_crtc_helper_set_config - set a new config from userspace |
741 | * @crtc: CRTC to setup |
455 | * @crtc: CRTC to setup |
742 | * @crtc_info: user provided configuration |
456 | * @crtc_info: user provided configuration |
743 | * @new_mode: new mode to set |
457 | * @new_mode: new mode to set |
744 | * @connector_set: set of connectors for the new config |
458 | * @connector_set: set of connectors for the new config |
745 | * @fb: new framebuffer |
459 | * @fb: new framebuffer |
746 | * |
460 | * |
747 | * LOCKING: |
461 | * LOCKING: |
748 | * Caller must hold mode config lock. |
462 | * Caller must hold mode config lock. |
749 | * |
463 | * |
750 | * Setup a new configuration, provided by the user in @crtc_info, and enable |
464 | * Setup a new configuration, provided by the user in @crtc_info, and enable |
751 | * it. |
465 | * it. |
752 | * |
466 | * |
753 | * RETURNS: |
467 | * RETURNS: |
754 | * Zero. (FIXME) |
468 | * Zero. (FIXME) |
755 | */ |
469 | */ |
756 | int drm_crtc_helper_set_config(struct drm_mode_set *set) |
470 | int drm_crtc_helper_set_config(struct drm_mode_set *set) |
757 | { |
471 | { |
758 | struct drm_device *dev; |
472 | struct drm_device *dev; |
759 | struct drm_crtc *save_crtcs, *new_crtc, *crtc; |
473 | struct drm_crtc *save_crtcs, *new_crtc, *crtc; |
760 | struct drm_encoder *save_encoders, *new_encoder, *encoder; |
474 | struct drm_encoder *save_encoders, *new_encoder, *encoder; |
761 | struct drm_framebuffer *old_fb = NULL; |
475 | struct drm_framebuffer *old_fb = NULL; |
762 | bool mode_changed = false; /* if true do a full mode set */ |
476 | bool mode_changed = false; /* if true do a full mode set */ |
763 | bool fb_changed = false; /* if true and !mode_changed just do a flip */ |
477 | bool fb_changed = false; /* if true and !mode_changed just do a flip */ |
764 | struct drm_connector *save_connectors, *connector; |
478 | struct drm_connector *save_connectors, *connector; |
765 | int count = 0, ro, fail = 0; |
479 | int count = 0, ro, fail = 0; |
766 | struct drm_crtc_helper_funcs *crtc_funcs; |
480 | struct drm_crtc_helper_funcs *crtc_funcs; |
767 | int ret = 0; |
481 | int ret = 0; |
- | 482 | int i; |
|
768 | 483 | ||
769 | DRM_DEBUG_KMS("\n"); |
484 | DRM_DEBUG_KMS("\n"); |
770 | 485 | ||
771 | if (!set) |
486 | if (!set) |
772 | return -EINVAL; |
487 | return -EINVAL; |
773 | 488 | ||
774 | if (!set->crtc) |
489 | if (!set->crtc) |
775 | return -EINVAL; |
490 | return -EINVAL; |
776 | 491 | ||
777 | if (!set->crtc->helper_private) |
492 | if (!set->crtc->helper_private) |
778 | return -EINVAL; |
493 | return -EINVAL; |
779 | 494 | ||
780 | crtc_funcs = set->crtc->helper_private; |
495 | crtc_funcs = set->crtc->helper_private; |
- | 496 | ||
- | 497 | if (!set->mode) |
|
- | 498 | set->fb = NULL; |
|
- | 499 | ||
781 | 500 | if (set->fb) { |
|
782 | DRM_DEBUG_KMS("crtc: %p %d fb: %p connectors: %p num_connectors:" |
- | |
783 | " %d (x, y) (%i, %i)\n", |
501 | DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", |
784 | set->crtc, set->crtc->base.id, set->fb, set->connectors, |
502 | set->crtc->base.id, set->fb->base.id, |
- | 503 | (int)set->num_connectors, set->x, set->y); |
|
- | 504 | } else { |
|
- | 505 | DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); |
|
- | 506 | set->mode = NULL; |
|
- | 507 | set->num_connectors = 0; |
|
785 | (int)set->num_connectors, set->x, set->y); |
508 | } |
786 | 509 | ||
787 | dev = set->crtc->dev; |
510 | dev = set->crtc->dev; |
788 | 511 | ||
789 | /* Allocate space for the backup of all (non-pointer) crtc, encoder and |
512 | /* Allocate space for the backup of all (non-pointer) crtc, encoder and |
790 | * connector data. */ |
513 | * connector data. */ |
791 | save_crtcs = kzalloc(dev->mode_config.num_crtc * |
514 | save_crtcs = kzalloc(dev->mode_config.num_crtc * |
792 | sizeof(struct drm_crtc), GFP_KERNEL); |
515 | sizeof(struct drm_crtc), GFP_KERNEL); |
793 | if (!save_crtcs) |
516 | if (!save_crtcs) |
794 | return -ENOMEM; |
517 | return -ENOMEM; |
795 | 518 | ||
796 | save_encoders = kzalloc(dev->mode_config.num_encoder * |
519 | save_encoders = kzalloc(dev->mode_config.num_encoder * |
797 | sizeof(struct drm_encoder), GFP_KERNEL); |
520 | sizeof(struct drm_encoder), GFP_KERNEL); |
798 | if (!save_encoders) { |
521 | if (!save_encoders) { |
799 | kfree(save_crtcs); |
522 | kfree(save_crtcs); |
800 | return -ENOMEM; |
523 | return -ENOMEM; |
801 | } |
524 | } |
802 | 525 | ||
803 | save_connectors = kzalloc(dev->mode_config.num_connector * |
526 | save_connectors = kzalloc(dev->mode_config.num_connector * |
804 | sizeof(struct drm_connector), GFP_KERNEL); |
527 | sizeof(struct drm_connector), GFP_KERNEL); |
805 | if (!save_connectors) { |
528 | if (!save_connectors) { |
806 | kfree(save_crtcs); |
529 | kfree(save_crtcs); |
807 | kfree(save_encoders); |
530 | kfree(save_encoders); |
808 | return -ENOMEM; |
531 | return -ENOMEM; |
809 | } |
532 | } |
810 | 533 | ||
811 | /* Copy data. Note that driver private data is not affected. |
534 | /* Copy data. Note that driver private data is not affected. |
812 | * Should anything bad happen only the expected state is |
535 | * Should anything bad happen only the expected state is |
813 | * restored, not the drivers personal bookkeeping. |
536 | * restored, not the drivers personal bookkeeping. |
814 | */ |
537 | */ |
815 | count = 0; |
538 | count = 0; |
816 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
539 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
817 | save_crtcs[count++] = *crtc; |
540 | save_crtcs[count++] = *crtc; |
818 | } |
541 | } |
819 | 542 | ||
820 | count = 0; |
543 | count = 0; |
821 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
544 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
822 | save_encoders[count++] = *encoder; |
545 | save_encoders[count++] = *encoder; |
823 | } |
546 | } |
824 | 547 | ||
825 | count = 0; |
548 | count = 0; |
826 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
549 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
827 | save_connectors[count++] = *connector; |
550 | save_connectors[count++] = *connector; |
828 | } |
551 | } |
829 | 552 | ||
830 | /* We should be able to check here if the fb has the same properties |
553 | /* We should be able to check here if the fb has the same properties |
831 | * and then just flip_or_move it */ |
554 | * and then just flip_or_move it */ |
832 | if (set->crtc->fb != set->fb) { |
555 | if (set->crtc->fb != set->fb) { |
833 | /* If we have no fb then treat it as a full mode set */ |
556 | /* If we have no fb then treat it as a full mode set */ |
834 | if (set->crtc->fb == NULL) { |
557 | if (set->crtc->fb == NULL) { |
835 | DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); |
558 | DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); |
836 | mode_changed = true; |
559 | mode_changed = true; |
837 | } else if (set->fb == NULL) { |
560 | } else if (set->fb == NULL) { |
838 | mode_changed = true; |
561 | mode_changed = true; |
839 | } else |
562 | } else |
840 | fb_changed = true; |
563 | fb_changed = true; |
841 | } |
564 | } |
842 | 565 | ||
843 | if (set->x != set->crtc->x || set->y != set->crtc->y) |
566 | if (set->x != set->crtc->x || set->y != set->crtc->y) |
844 | fb_changed = true; |
567 | fb_changed = true; |
845 | 568 | ||
846 | if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { |
569 | if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { |
847 | DRM_DEBUG_KMS("modes are different, full mode set\n"); |
570 | DRM_DEBUG_KMS("modes are different, full mode set\n"); |
848 | drm_mode_debug_printmodeline(&set->crtc->mode); |
571 | drm_mode_debug_printmodeline(&set->crtc->mode); |
849 | drm_mode_debug_printmodeline(set->mode); |
572 | drm_mode_debug_printmodeline(set->mode); |
850 | mode_changed = true; |
573 | mode_changed = true; |
851 | } |
574 | } |
852 | 575 | ||
853 | /* a) traverse passed in connector list and get encoders for them */ |
576 | /* a) traverse passed in connector list and get encoders for them */ |
854 | count = 0; |
577 | count = 0; |
855 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
578 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
856 | struct drm_connector_helper_funcs *connector_funcs = |
579 | struct drm_connector_helper_funcs *connector_funcs = |
857 | connector->helper_private; |
580 | connector->helper_private; |
858 | new_encoder = connector->encoder; |
581 | new_encoder = connector->encoder; |
859 | for (ro = 0; ro < set->num_connectors; ro++) { |
582 | for (ro = 0; ro < set->num_connectors; ro++) { |
860 | if (set->connectors[ro] == connector) { |
583 | if (set->connectors[ro] == connector) { |
861 | new_encoder = connector_funcs->best_encoder(connector); |
584 | new_encoder = connector_funcs->best_encoder(connector); |
862 | /* if we can't get an encoder for a connector |
585 | /* if we can't get an encoder for a connector |
863 | we are setting now - then fail */ |
586 | we are setting now - then fail */ |
864 | if (new_encoder == NULL) |
587 | if (new_encoder == NULL) |
865 | /* don't break so fail path works correct */ |
588 | /* don't break so fail path works correct */ |
866 | fail = 1; |
589 | fail = 1; |
867 | break; |
590 | break; |
868 | } |
591 | } |
869 | } |
592 | } |
870 | 593 | ||
871 | if (new_encoder != connector->encoder) { |
594 | if (new_encoder != connector->encoder) { |
872 | DRM_DEBUG_KMS("encoder changed, full mode switch\n"); |
595 | DRM_DEBUG_KMS("encoder changed, full mode switch\n"); |
873 | mode_changed = true; |
596 | mode_changed = true; |
874 | /* If the encoder is reused for another connector, then |
597 | /* If the encoder is reused for another connector, then |
875 | * the appropriate crtc will be set later. |
598 | * the appropriate crtc will be set later. |
876 | */ |
599 | */ |
877 | if (connector->encoder) |
600 | if (connector->encoder) |
878 | connector->encoder->crtc = NULL; |
601 | connector->encoder->crtc = NULL; |
879 | connector->encoder = new_encoder; |
602 | connector->encoder = new_encoder; |
880 | } |
603 | } |
881 | } |
604 | } |
882 | 605 | ||
883 | if (fail) { |
606 | if (fail) { |
884 | ret = -EINVAL; |
607 | ret = -EINVAL; |
885 | goto fail; |
608 | goto fail; |
886 | } |
609 | } |
887 | 610 | ||
888 | count = 0; |
611 | count = 0; |
889 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
612 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
890 | if (!connector->encoder) |
613 | if (!connector->encoder) |
891 | continue; |
614 | continue; |
892 | 615 | ||
893 | if (connector->encoder->crtc == set->crtc) |
616 | if (connector->encoder->crtc == set->crtc) |
894 | new_crtc = NULL; |
617 | new_crtc = NULL; |
895 | else |
618 | else |
896 | new_crtc = connector->encoder->crtc; |
619 | new_crtc = connector->encoder->crtc; |
897 | 620 | ||
898 | for (ro = 0; ro < set->num_connectors; ro++) { |
621 | for (ro = 0; ro < set->num_connectors; ro++) { |
899 | if (set->connectors[ro] == connector) |
622 | if (set->connectors[ro] == connector) |
900 | new_crtc = set->crtc; |
623 | new_crtc = set->crtc; |
901 | } |
624 | } |
902 | 625 | ||
903 | /* Make sure the new CRTC will work with the encoder */ |
626 | /* Make sure the new CRTC will work with the encoder */ |
904 | if (new_crtc && |
627 | if (new_crtc && |
905 | !drm_encoder_crtc_ok(connector->encoder, new_crtc)) { |
628 | !drm_encoder_crtc_ok(connector->encoder, new_crtc)) { |
906 | ret = -EINVAL; |
629 | ret = -EINVAL; |
907 | goto fail; |
630 | goto fail; |
908 | } |
631 | } |
909 | if (new_crtc != connector->encoder->crtc) { |
632 | if (new_crtc != connector->encoder->crtc) { |
910 | DRM_DEBUG_KMS("crtc changed, full mode switch\n"); |
633 | DRM_DEBUG_KMS("crtc changed, full mode switch\n"); |
911 | mode_changed = true; |
634 | mode_changed = true; |
912 | connector->encoder->crtc = new_crtc; |
635 | connector->encoder->crtc = new_crtc; |
913 | } |
636 | } |
- | 637 | if (new_crtc) { |
|
914 | DRM_DEBUG_KMS("setting connector %d crtc to %p\n", |
638 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", |
- | 639 | connector->base.id, drm_get_connector_name(connector), |
|
- | 640 | new_crtc->base.id); |
|
- | 641 | } else { |
|
- | 642 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", |
|
915 | connector->base.id, new_crtc); |
643 | connector->base.id, drm_get_connector_name(connector)); |
- | 644 | } |
|
916 | } |
645 | } |
917 | 646 | ||
918 | /* mode_set_base is not a required function */ |
647 | /* mode_set_base is not a required function */ |
919 | if (fb_changed && !crtc_funcs->mode_set_base) |
648 | if (fb_changed && !crtc_funcs->mode_set_base) |
920 | mode_changed = true; |
649 | mode_changed = true; |
921 | 650 | ||
922 | if (mode_changed) { |
651 | if (mode_changed) { |
923 | old_fb = set->crtc->fb; |
- | |
924 | set->crtc->fb = set->fb; |
- | |
925 | set->crtc->enabled = (set->mode != NULL); |
652 | set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); |
926 | if (set->mode != NULL) { |
653 | if (set->crtc->enabled) { |
927 | DRM_DEBUG_KMS("attempting to set mode from" |
654 | DRM_DEBUG_KMS("attempting to set mode from" |
928 | " userspace\n"); |
655 | " userspace\n"); |
929 | drm_mode_debug_printmodeline(set->mode); |
656 | drm_mode_debug_printmodeline(set->mode); |
- | 657 | old_fb = set->crtc->fb; |
|
- | 658 | set->crtc->fb = set->fb; |
|
930 | if (!drm_crtc_helper_set_mode(set->crtc, set->mode, |
659 | if (!drm_crtc_helper_set_mode(set->crtc, set->mode, |
931 | set->x, set->y, |
660 | set->x, set->y, |
932 | old_fb)) { |
661 | old_fb)) { |
933 | DRM_ERROR("failed to set mode on crtc %p\n", |
662 | DRM_ERROR("failed to set mode on [CRTC:%d]\n", |
934 | set->crtc); |
663 | set->crtc->base.id); |
- | 664 | set->crtc->fb = old_fb; |
|
935 | ret = -EINVAL; |
665 | ret = -EINVAL; |
936 | goto fail; |
666 | goto fail; |
937 | } |
667 | } |
938 | /* TODO are these needed? */ |
668 | DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); |
939 | set->crtc->desired_x = set->x; |
669 | for (i = 0; i < set->num_connectors; i++) { |
- | 670 | DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, |
|
940 | set->crtc->desired_y = set->y; |
671 | drm_get_connector_name(set->connectors[i])); |
941 | set->crtc->desired_mode = set->mode; |
672 | set->connectors[i]->dpms = DRM_MODE_DPMS_ON; |
- | 673 | } |
|
942 | } |
674 | } |
943 | drm_helper_disable_unused_functions(dev); |
675 | drm_helper_disable_unused_functions(dev); |
944 | } else if (fb_changed) { |
676 | } else if (fb_changed) { |
945 | set->crtc->x = set->x; |
677 | set->crtc->x = set->x; |
946 | set->crtc->y = set->y; |
678 | set->crtc->y = set->y; |
947 | 679 | ||
948 | old_fb = set->crtc->fb; |
680 | old_fb = set->crtc->fb; |
949 | if (set->crtc->fb != set->fb) |
681 | if (set->crtc->fb != set->fb) |
950 | set->crtc->fb = set->fb; |
682 | set->crtc->fb = set->fb; |
951 | ret = crtc_funcs->mode_set_base(set->crtc, |
683 | ret = crtc_funcs->mode_set_base(set->crtc, |
952 | set->x, set->y, old_fb); |
684 | set->x, set->y, old_fb); |
953 | if (ret != 0) |
685 | if (ret != 0) { |
- | 686 | set->crtc->fb = old_fb; |
|
954 | goto fail; |
687 | goto fail; |
955 | } |
688 | } |
- | 689 | } |
|
956 | 690 | ||
957 | kfree(save_connectors); |
691 | kfree(save_connectors); |
958 | kfree(save_encoders); |
692 | kfree(save_encoders); |
959 | kfree(save_crtcs); |
693 | kfree(save_crtcs); |
960 | return 0; |
694 | return 0; |
961 | 695 | ||
962 | fail: |
696 | fail: |
963 | /* Restore all previous data. */ |
697 | /* Restore all previous data. */ |
964 | count = 0; |
698 | count = 0; |
965 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
699 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
966 | *crtc = save_crtcs[count++]; |
700 | *crtc = save_crtcs[count++]; |
967 | } |
701 | } |
968 | 702 | ||
969 | count = 0; |
703 | count = 0; |
970 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
704 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
971 | *encoder = save_encoders[count++]; |
705 | *encoder = save_encoders[count++]; |
972 | } |
706 | } |
973 | 707 | ||
974 | count = 0; |
708 | count = 0; |
975 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
709 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
976 | *connector = save_connectors[count++]; |
710 | *connector = save_connectors[count++]; |
977 | } |
711 | } |
978 | 712 | ||
979 | kfree(save_connectors); |
713 | kfree(save_connectors); |
980 | kfree(save_encoders); |
714 | kfree(save_encoders); |
981 | kfree(save_crtcs); |
715 | kfree(save_crtcs); |
982 | return ret; |
716 | return ret; |
983 | } |
717 | } |
984 | EXPORT_SYMBOL(drm_crtc_helper_set_config); |
718 | EXPORT_SYMBOL(drm_crtc_helper_set_config); |
985 | - | ||
986 | bool drm_helper_plugged_event(struct drm_device *dev) |
- | |
987 | { |
- | |
988 | DRM_DEBUG_KMS("\n"); |
- | |
989 | - | ||
990 | drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, |
- | |
991 | dev->mode_config.max_height); |
- | |
992 | - | ||
993 | drm_setup_crtcs(dev); |
- | |
994 | - | ||
995 | /* alert the driver fb layer */ |
- | |
996 | dev->mode_config.funcs->fb_changed(dev); |
- | |
997 | - | ||
998 | /* FIXME: send hotplug event */ |
- | |
999 | return true; |
- | |
1000 | } |
- | |
1001 | /** |
- | |
1002 | * drm_initial_config - setup a sane initial connector configuration |
- | |
1003 | * @dev: DRM device |
- | |
1004 | * |
- | |
1005 | * LOCKING: |
- | |
1006 | * Called at init time, must take mode config lock. |
- | |
1007 | * |
- | |
1008 | * Scan the CRTCs and connectors and try to put together an initial setup. |
- | |
1009 | * At the moment, this is a cloned configuration across all heads with |
- | |
1010 | * a new framebuffer object as the backing store. |
- | |
1011 | * |
- | |
1012 | * RETURNS: |
- | |
1013 | * Zero if everything went ok, nonzero otherwise. |
- | |
1014 | */ |
- | |
1015 | bool drm_helper_initial_config(struct drm_device *dev) |
- | |
1016 | { |
- | |
1017 | int count = 0; |
- | |
1018 | - | ||
1019 | /* disable all the possible outputs/crtcs before entering KMS mode */ |
- | |
1020 | // drm_helper_disable_unused_functions(dev); |
- | |
1021 | - | ||
1022 | // drm_fb_helper_parse_command_line(dev); |
- | |
1023 | - | ||
1024 | count = drm_helper_probe_connector_modes(dev, |
- | |
1025 | dev->mode_config.max_width, |
- | |
1026 | dev->mode_config.max_height); |
- | |
1027 | - | ||
1028 | /* |
- | |
1029 | * we shouldn't end up with no modes here. |
- | |
1030 | */ |
- | |
1031 | if (count == 0) |
- | |
1032 | printk(KERN_INFO "No connectors reported connected with modes\n"); |
- | |
1033 | - | ||
1034 | drm_setup_crtcs(dev); |
- | |
1035 | - | ||
1036 | /* alert the driver fb layer */ |
- | |
1037 | dev->mode_config.funcs->fb_changed(dev); |
- | |
1038 | - | ||
1039 | return 0; |
- | |
1040 | } |
- | |
1041 | EXPORT_SYMBOL(drm_helper_initial_config); |
- | |
1042 | 719 | ||
1043 | static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) |
720 | static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) |
1044 | { |
721 | { |
1045 | int dpms = DRM_MODE_DPMS_OFF; |
722 | int dpms = DRM_MODE_DPMS_OFF; |
1046 | struct drm_connector *connector; |
723 | struct drm_connector *connector; |
1047 | struct drm_device *dev = encoder->dev; |
724 | struct drm_device *dev = encoder->dev; |
1048 | 725 | ||
1049 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
726 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
1050 | if (connector->encoder == encoder) |
727 | if (connector->encoder == encoder) |
1051 | if (connector->dpms < dpms) |
728 | if (connector->dpms < dpms) |
1052 | dpms = connector->dpms; |
729 | dpms = connector->dpms; |
1053 | return dpms; |
730 | return dpms; |
1054 | } |
731 | } |
1055 | 732 | ||
1056 | static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc) |
733 | static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc) |
1057 | { |
734 | { |
1058 | int dpms = DRM_MODE_DPMS_OFF; |
735 | int dpms = DRM_MODE_DPMS_OFF; |
1059 | struct drm_connector *connector; |
736 | struct drm_connector *connector; |
1060 | struct drm_device *dev = crtc->dev; |
737 | struct drm_device *dev = crtc->dev; |
1061 | 738 | ||
1062 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
739 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
1063 | if (connector->encoder && connector->encoder->crtc == crtc) |
740 | if (connector->encoder && connector->encoder->crtc == crtc) |
1064 | if (connector->dpms < dpms) |
741 | if (connector->dpms < dpms) |
1065 | dpms = connector->dpms; |
742 | dpms = connector->dpms; |
1066 | return dpms; |
743 | return dpms; |
1067 | } |
744 | } |
1068 | 745 | ||
1069 | /** |
746 | /** |
1070 | * drm_helper_connector_dpms |
747 | * drm_helper_connector_dpms |
1071 | * @connector affected connector |
748 | * @connector affected connector |
1072 | * @mode DPMS mode |
749 | * @mode DPMS mode |
1073 | * |
750 | * |
1074 | * Calls the low-level connector DPMS function, then |
751 | * Calls the low-level connector DPMS function, then |
1075 | * calls appropriate encoder and crtc DPMS functions as well |
752 | * calls appropriate encoder and crtc DPMS functions as well |
1076 | */ |
753 | */ |
1077 | void drm_helper_connector_dpms(struct drm_connector *connector, int mode) |
754 | void drm_helper_connector_dpms(struct drm_connector *connector, int mode) |
1078 | { |
755 | { |
1079 | struct drm_encoder *encoder = connector->encoder; |
756 | struct drm_encoder *encoder = connector->encoder; |
1080 | struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; |
757 | struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; |
1081 | int old_dpms; |
758 | int old_dpms; |
1082 | 759 | ||
1083 | if (mode == connector->dpms) |
760 | if (mode == connector->dpms) |
1084 | return; |
761 | return; |
1085 | 762 | ||
1086 | old_dpms = connector->dpms; |
763 | old_dpms = connector->dpms; |
1087 | connector->dpms = mode; |
764 | connector->dpms = mode; |
1088 | 765 | ||
1089 | /* from off to on, do crtc then encoder */ |
766 | /* from off to on, do crtc then encoder */ |
1090 | if (mode < old_dpms) { |
767 | if (mode < old_dpms) { |
1091 | if (crtc) { |
768 | if (crtc) { |
1092 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
769 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
1093 | if (crtc_funcs->dpms) |
770 | if (crtc_funcs->dpms) |
1094 | (*crtc_funcs->dpms) (crtc, |
771 | (*crtc_funcs->dpms) (crtc, |
1095 | drm_helper_choose_crtc_dpms(crtc)); |
772 | drm_helper_choose_crtc_dpms(crtc)); |
1096 | } |
773 | } |
1097 | if (encoder) { |
774 | if (encoder) { |
1098 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
775 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
1099 | if (encoder_funcs->dpms) |
776 | if (encoder_funcs->dpms) |
1100 | (*encoder_funcs->dpms) (encoder, |
777 | (*encoder_funcs->dpms) (encoder, |
1101 | drm_helper_choose_encoder_dpms(encoder)); |
778 | drm_helper_choose_encoder_dpms(encoder)); |
1102 | } |
779 | } |
1103 | } |
780 | } |
1104 | 781 | ||
1105 | /* from on to off, do encoder then crtc */ |
782 | /* from on to off, do encoder then crtc */ |
1106 | if (mode > old_dpms) { |
783 | if (mode > old_dpms) { |
1107 | if (encoder) { |
784 | if (encoder) { |
1108 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
785 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
1109 | if (encoder_funcs->dpms) |
786 | if (encoder_funcs->dpms) |
1110 | (*encoder_funcs->dpms) (encoder, |
787 | (*encoder_funcs->dpms) (encoder, |
1111 | drm_helper_choose_encoder_dpms(encoder)); |
788 | drm_helper_choose_encoder_dpms(encoder)); |
1112 | } |
789 | } |
1113 | if (crtc) { |
790 | if (crtc) { |
1114 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
791 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
1115 | if (crtc_funcs->dpms) |
792 | if (crtc_funcs->dpms) |
1116 | (*crtc_funcs->dpms) (crtc, |
793 | (*crtc_funcs->dpms) (crtc, |
1117 | drm_helper_choose_crtc_dpms(crtc)); |
794 | drm_helper_choose_crtc_dpms(crtc)); |
1118 | } |
795 | } |
1119 | } |
796 | } |
1120 | 797 | ||
1121 | return; |
798 | return; |
1122 | } |
799 | } |
1123 | EXPORT_SYMBOL(drm_helper_connector_dpms); |
800 | EXPORT_SYMBOL(drm_helper_connector_dpms); |
1124 | - | ||
1125 | /** |
- | |
1126 | * drm_hotplug_stage_two |
- | |
1127 | * @dev DRM device |
- | |
1128 | * @connector hotpluged connector |
- | |
1129 | * |
- | |
1130 | * LOCKING. |
- | |
1131 | * Caller must hold mode config lock, function might grab struct lock. |
- | |
1132 | * |
- | |
1133 | * Stage two of a hotplug. |
- | |
1134 | * |
- | |
1135 | * RETURNS: |
- | |
1136 | * Zero on success, errno on failure. |
- | |
1137 | */ |
- | |
1138 | int drm_helper_hotplug_stage_two(struct drm_device *dev) |
- | |
1139 | { |
- | |
1140 | drm_helper_plugged_event(dev); |
- | |
1141 | - | ||
1142 | return 0; |
- | |
1143 | } |
- | |
1144 | EXPORT_SYMBOL(drm_helper_hotplug_stage_two); |
- | |
1145 | 801 | ||
1146 | int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, |
802 | int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, |
1147 | struct drm_mode_fb_cmd *mode_cmd) |
803 | struct drm_mode_fb_cmd *mode_cmd) |
1148 | { |
804 | { |
1149 | fb->width = mode_cmd->width; |
805 | fb->width = mode_cmd->width; |
1150 | fb->height = mode_cmd->height; |
806 | fb->height = mode_cmd->height; |
1151 | fb->pitch = mode_cmd->pitch; |
807 | fb->pitch = mode_cmd->pitch; |
1152 | fb->bits_per_pixel = mode_cmd->bpp; |
808 | fb->bits_per_pixel = mode_cmd->bpp; |
1153 | fb->depth = mode_cmd->depth; |
809 | fb->depth = mode_cmd->depth; |
1154 | 810 | ||
1155 | return 0; |
811 | return 0; |
1156 | } |
812 | } |
1157 | EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); |
813 | EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); |
1158 | 814 | ||
1159 | int drm_helper_resume_force_mode(struct drm_device *dev) |
815 | int drm_helper_resume_force_mode(struct drm_device *dev) |
1160 | { |
816 | { |
1161 | struct drm_crtc *crtc; |
817 | struct drm_crtc *crtc; |
1162 | struct drm_encoder *encoder; |
818 | struct drm_encoder *encoder; |
1163 | struct drm_encoder_helper_funcs *encoder_funcs; |
819 | struct drm_encoder_helper_funcs *encoder_funcs; |
1164 | struct drm_crtc_helper_funcs *crtc_funcs; |
820 | struct drm_crtc_helper_funcs *crtc_funcs; |
1165 | int ret; |
821 | int ret; |
1166 | 822 | ||
1167 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
823 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
1168 | 824 | ||
1169 | if (!crtc->enabled) |
825 | if (!crtc->enabled) |
1170 | continue; |
826 | continue; |
1171 | 827 | ||
1172 | ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, |
828 | ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, |
1173 | crtc->x, crtc->y, crtc->fb); |
829 | crtc->x, crtc->y, crtc->fb); |
1174 | 830 | ||
1175 | if (ret == false) |
831 | if (ret == false) |
1176 | DRM_ERROR("failed to set mode on crtc %p\n", crtc); |
832 | DRM_ERROR("failed to set mode on crtc %p\n", crtc); |
1177 | 833 | ||
1178 | /* Turn off outputs that were already powered off */ |
834 | /* Turn off outputs that were already powered off */ |
1179 | if (drm_helper_choose_crtc_dpms(crtc)) { |
835 | if (drm_helper_choose_crtc_dpms(crtc)) { |
1180 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
836 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
1181 | 837 | ||
1182 | if(encoder->crtc != crtc) |
838 | if(encoder->crtc != crtc) |
1183 | continue; |
839 | continue; |
1184 | 840 | ||
1185 | encoder_funcs = encoder->helper_private; |
841 | encoder_funcs = encoder->helper_private; |
1186 | if (encoder_funcs->dpms) |
842 | if (encoder_funcs->dpms) |
1187 | (*encoder_funcs->dpms) (encoder, |
843 | (*encoder_funcs->dpms) (encoder, |
1188 | drm_helper_choose_encoder_dpms(encoder)); |
844 | drm_helper_choose_encoder_dpms(encoder)); |
- | 845 | } |
|
1189 | 846 | ||
1190 | crtc_funcs = crtc->helper_private; |
847 | crtc_funcs = crtc->helper_private; |
1191 | if (crtc_funcs->dpms) |
848 | if (crtc_funcs->dpms) |
1192 | (*crtc_funcs->dpms) (crtc, |
849 | (*crtc_funcs->dpms) (crtc, |
1193 | drm_helper_choose_crtc_dpms(crtc)); |
850 | drm_helper_choose_crtc_dpms(crtc)); |
1194 | } |
851 | } |
1195 | } |
852 | } |
1196 | } |
- | |
1197 | /* disable the unused connectors while restoring the modesetting */ |
853 | /* disable the unused connectors while restoring the modesetting */ |
1198 | drm_helper_disable_unused_functions(dev); |
854 | drm_helper_disable_unused_functions(dev); |
1199 | return 0; |
855 | return 0; |
1200 | } |
856 | } |
1201 | EXPORT_SYMBOL(drm_helper_resume_force_mode);>>>>>=><=>>>><> |
857 | EXPORT_SYMBOL(drm_helper_resume_force_mode); |
- | 858 | ||
- | 859 | #if 0 |
|
- | 860 | ||
- | 861 | #define DRM_OUTPUT_POLL_PERIOD (10*HZ) |
|
- | 862 | static void output_poll_execute(struct work_struct *work) |
|
- | 863 | { |
|
- | 864 | struct delayed_work *delayed_work = to_delayed_work(work); |
|
- | 865 | struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); |
|
- | 866 | struct drm_connector *connector; |
|
- | 867 | enum drm_connector_status old_status; |
|
- | 868 | bool repoll = false, changed = false; |
|
- | 869 | ||
- | 870 | if (!drm_kms_helper_poll) |
|
- | 871 | return; |
|
- | 872 | ||
- | 873 | mutex_lock(&dev->mode_config.mutex); |
|
- | 874 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
|
- | 875 | ||
- | 876 | /* if this is HPD or polled don't check it - |
|
- | 877 | TV out for instance */ |
|
- | 878 | if (!connector->polled) |
|
- | 879 | continue; |
|
- | 880 | ||
- | 881 | else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT)) |
|
- | 882 | repoll = true; |
|
- | 883 | ||
- | 884 | old_status = connector->status; |
|
- | 885 | /* if we are connected and don't want to poll for disconnect |
|
- | 886 | skip it */ |
|
- | 887 | if (old_status == connector_status_connected && |
|
- | 888 | !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) && |
|
- | 889 | !(connector->polled & DRM_CONNECTOR_POLL_HPD)) |
|
- | 890 | continue; |
|
- | 891 | ||
- | 892 | connector->status = connector->funcs->detect(connector, false); |
|
- | 893 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", |
|
- | 894 | connector->base.id, |
|
- | 895 | drm_get_connector_name(connector), |
|
- | 896 | old_status, connector->status); |
|
- | 897 | if (old_status != connector->status) |
|
- | 898 | changed = true; |
|
- | 899 | } |
|
- | 900 | ||
- | 901 | mutex_unlock(&dev->mode_config.mutex); |
|
- | 902 | ||
- | 903 | if (changed) { |
|
- | 904 | /* send a uevent + call fbdev */ |
|
- | 905 | drm_sysfs_hotplug_event(dev); |
|
- | 906 | if (dev->mode_config.funcs->output_poll_changed) |
|
- | 907 | dev->mode_config.funcs->output_poll_changed(dev); |
|
- | 908 | } |
|
- | 909 | ||
- | 910 | if (repoll) |
|
- | 911 | queue_delayed_work(system_nrt_wq, delayed_work, DRM_OUTPUT_POLL_PERIOD); |
|
- | 912 | } |
|
- | 913 | ||
- | 914 | void drm_kms_helper_poll_disable(struct drm_device *dev) |
|
- | 915 | { |
|
- | 916 | if (!dev->mode_config.poll_enabled) |
|
- | 917 | return; |
|
- | 918 | cancel_delayed_work_sync(&dev->mode_config.output_poll_work); |
|
- | 919 | } |
|
- | 920 | EXPORT_SYMBOL(drm_kms_helper_poll_disable); |
|
- | 921 | ||
- | 922 | void drm_kms_helper_poll_enable(struct drm_device *dev) |
|
- | 923 | { |
|
- | 924 | bool poll = false; |
|
- | 925 | struct drm_connector *connector; |
|
- | 926 | ||
- | 927 | if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) |
|
- | 928 | return; |
|
- | 929 | ||
- | 930 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
|
- | 931 | if (connector->polled) |
|
- | 932 | poll = true; |
|
- | 933 | } |
|
- | 934 | ||
- | 935 | if (poll) |
|
- | 936 | queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); |
|
- | 937 | } |
|
- | 938 | EXPORT_SYMBOL(drm_kms_helper_poll_enable); |
|
- | 939 | ||
- | 940 | void drm_kms_helper_poll_init(struct drm_device *dev) |
|
- | 941 | { |
|
- | 942 | INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute); |
|
- | 943 | dev->mode_config.poll_enabled = true; |
|
- | 944 | ||
- | 945 | drm_kms_helper_poll_enable(dev); |
|
- | 946 | } |
|
- | 947 | EXPORT_SYMBOL(drm_kms_helper_poll_init); |
|
- | 948 | ||
- | 949 | void drm_kms_helper_poll_fini(struct drm_device *dev) |
|
- | 950 | { |
|
- | 951 | drm_kms_helper_poll_disable(dev); |
|
- | 952 | } |
|
- | 953 | EXPORT_SYMBOL(drm_kms_helper_poll_fini); |
|
- | 954 | ||
- | 955 | void drm_helper_hpd_irq_event(struct drm_device *dev) |
|
- | 956 | { |
|
- | 957 | if (!dev->mode_config.poll_enabled) |
|
- | 958 | return; |
|
- | 959 | ||
- | 960 | /* kill timer and schedule immediate execution, this doesn't block */ |
|
- | 961 | cancel_delayed_work(&dev->mode_config.output_poll_work); |
|
- | 962 | if (drm_kms_helper_poll) |
|
- | 963 | queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0); |
|
- | 964 | } |
|
- | 965 | EXPORT_SYMBOL(drm_helper_hpd_irq_event); |
|
- | 966 | ||
- | 967 | ||
- | 968 | #endif>>>>>>=><=> |