Rev 4075 | Rev 4126 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4075 | Rev 4104 | ||
---|---|---|---|
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 |
32 | #include |
33 | #include |
33 | #include |
34 | 34 | ||
35 | #include |
35 | #include |
36 | #include |
36 | #include |
37 | #include |
37 | #include |
38 | #include |
38 | #include |
39 | #include |
39 | #include |
40 | #include |
40 | #include |
41 | 41 | ||
42 | /** |
42 | /** |
43 | * drm_helper_move_panel_connectors_to_head() - move panels to the front in the |
43 | * drm_helper_move_panel_connectors_to_head() - move panels to the front in the |
44 | * connector list |
44 | * connector list |
45 | * @dev: drm device to operate on |
45 | * @dev: drm device to operate on |
46 | * |
46 | * |
47 | * Some userspace presumes that the first connected connector is the main |
47 | * Some userspace presumes that the first connected connector is the main |
48 | * display, where it's supposed to display e.g. the login screen. For |
48 | * display, where it's supposed to display e.g. the login screen. For |
49 | * laptops, this should be the main panel. Use this function to sort all |
49 | * laptops, this should be the main panel. Use this function to sort all |
50 | * (eDP/LVDS) panels to the front of the connector list, instead of |
50 | * (eDP/LVDS) panels to the front of the connector list, instead of |
51 | * painstakingly trying to initialize them in the right order. |
51 | * painstakingly trying to initialize them in the right order. |
52 | */ |
52 | */ |
53 | void drm_helper_move_panel_connectors_to_head(struct drm_device *dev) |
53 | void drm_helper_move_panel_connectors_to_head(struct drm_device *dev) |
54 | { |
54 | { |
55 | struct drm_connector *connector, *tmp; |
55 | struct drm_connector *connector, *tmp; |
56 | struct list_head panel_list; |
56 | struct list_head panel_list; |
57 | 57 | ||
58 | INIT_LIST_HEAD(&panel_list); |
58 | INIT_LIST_HEAD(&panel_list); |
59 | 59 | ||
60 | list_for_each_entry_safe(connector, tmp, |
60 | list_for_each_entry_safe(connector, tmp, |
61 | &dev->mode_config.connector_list, head) { |
61 | &dev->mode_config.connector_list, head) { |
62 | if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || |
62 | if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || |
63 | connector->connector_type == DRM_MODE_CONNECTOR_eDP) |
63 | connector->connector_type == DRM_MODE_CONNECTOR_eDP) |
64 | list_move_tail(&connector->head, &panel_list); |
64 | list_move_tail(&connector->head, &panel_list); |
65 | } |
65 | } |
66 | 66 | ||
67 | list_splice(&panel_list, &dev->mode_config.connector_list); |
67 | list_splice(&panel_list, &dev->mode_config.connector_list); |
68 | } |
68 | } |
69 | EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head); |
69 | EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head); |
70 | 70 | ||
71 | static bool drm_kms_helper_poll = true; |
71 | static bool drm_kms_helper_poll = true; |
72 | module_param_named(poll, drm_kms_helper_poll, bool, 0600); |
72 | module_param_named(poll, drm_kms_helper_poll, bool, 0600); |
73 | 73 | ||
74 | static void drm_mode_validate_flag(struct drm_connector *connector, |
74 | static void drm_mode_validate_flag(struct drm_connector *connector, |
75 | int flags) |
75 | int flags) |
76 | { |
76 | { |
77 | struct drm_display_mode *mode; |
77 | struct drm_display_mode *mode; |
78 | 78 | ||
79 | if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE)) |
79 | if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE)) |
80 | return; |
80 | return; |
81 | 81 | ||
82 | list_for_each_entry(mode, &connector->modes, head) { |
82 | list_for_each_entry(mode, &connector->modes, head) { |
83 | if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && |
83 | if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && |
84 | !(flags & DRM_MODE_FLAG_INTERLACE)) |
84 | !(flags & DRM_MODE_FLAG_INTERLACE)) |
85 | mode->status = MODE_NO_INTERLACE; |
85 | mode->status = MODE_NO_INTERLACE; |
86 | if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && |
86 | if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && |
87 | !(flags & DRM_MODE_FLAG_DBLSCAN)) |
87 | !(flags & DRM_MODE_FLAG_DBLSCAN)) |
88 | mode->status = MODE_NO_DBLESCAN; |
88 | mode->status = MODE_NO_DBLESCAN; |
89 | } |
89 | } |
90 | 90 | ||
91 | return; |
91 | return; |
92 | } |
92 | } |
93 | 93 | ||
94 | /** |
94 | /** |
95 | * drm_helper_probe_single_connector_modes - get complete set of display modes |
95 | * drm_helper_probe_single_connector_modes - get complete set of display modes |
96 | * @connector: connector to probe |
96 | * @connector: connector to probe |
97 | * @maxX: max width for modes |
97 | * @maxX: max width for modes |
98 | * @maxY: max height for modes |
98 | * @maxY: max height for modes |
99 | * |
99 | * |
100 | * LOCKING: |
100 | * LOCKING: |
101 | * Caller must hold mode config lock. |
101 | * Caller must hold mode config lock. |
102 | * |
102 | * |
103 | * Based on the helper callbacks implemented by @connector try to detect all |
103 | * Based on the helper callbacks implemented by @connector try to detect all |
104 | * valid modes. Modes will first be added to the connector's probed_modes list, |
104 | * valid modes. Modes will first be added to the connector's probed_modes list, |
105 | * then culled (based on validity and the @maxX, @maxY parameters) and put into |
105 | * then culled (based on validity and the @maxX, @maxY parameters) and put into |
106 | * the normal modes list. |
106 | * the normal modes list. |
107 | * |
107 | * |
108 | * Intended to be use as a generic implementation of the ->probe() @connector |
108 | * Intended to be use as a generic implementation of the ->probe() @connector |
109 | * callback for drivers that use the crtc helpers for output mode filtering and |
109 | * callback for drivers that use the crtc helpers for output mode filtering and |
110 | * detection. |
110 | * detection. |
111 | * |
111 | * |
112 | * RETURNS: |
112 | * RETURNS: |
113 | * Number of modes found on @connector. |
113 | * Number of modes found on @connector. |
114 | */ |
114 | */ |
115 | int drm_helper_probe_single_connector_modes(struct drm_connector *connector, |
115 | int drm_helper_probe_single_connector_modes(struct drm_connector *connector, |
116 | uint32_t maxX, uint32_t maxY) |
116 | uint32_t maxX, uint32_t maxY) |
117 | { |
117 | { |
118 | struct drm_device *dev = connector->dev; |
118 | struct drm_device *dev = connector->dev; |
119 | struct drm_display_mode *mode; |
119 | struct drm_display_mode *mode; |
120 | struct drm_connector_helper_funcs *connector_funcs = |
120 | struct drm_connector_helper_funcs *connector_funcs = |
121 | connector->helper_private; |
121 | connector->helper_private; |
122 | int count = 0; |
122 | int count = 0; |
123 | int mode_flags = 0; |
123 | int mode_flags = 0; |
124 | bool verbose_prune = true; |
124 | bool verbose_prune = true; |
125 | 125 | ||
126 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, |
126 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, |
127 | drm_get_connector_name(connector)); |
127 | drm_get_connector_name(connector)); |
128 | /* set all modes to the unverified state */ |
128 | /* set all modes to the unverified state */ |
129 | list_for_each_entry(mode, &connector->modes, head) |
129 | list_for_each_entry(mode, &connector->modes, head) |
130 | mode->status = MODE_UNVERIFIED; |
130 | mode->status = MODE_UNVERIFIED; |
131 | 131 | ||
132 | if (connector->force) { |
132 | if (connector->force) { |
133 | if (connector->force == DRM_FORCE_ON) |
133 | if (connector->force == DRM_FORCE_ON) |
134 | connector->status = connector_status_connected; |
134 | connector->status = connector_status_connected; |
135 | else |
135 | else |
136 | connector->status = connector_status_disconnected; |
136 | connector->status = connector_status_disconnected; |
137 | if (connector->funcs->force) |
137 | if (connector->funcs->force) |
138 | connector->funcs->force(connector); |
138 | connector->funcs->force(connector); |
139 | } else { |
139 | } else { |
140 | connector->status = connector->funcs->detect(connector, true); |
140 | connector->status = connector->funcs->detect(connector, true); |
141 | } |
141 | } |
142 | 142 | ||
143 | /* Re-enable polling in case the global poll config changed. */ |
143 | /* Re-enable polling in case the global poll config changed. */ |
144 | if (drm_kms_helper_poll != dev->mode_config.poll_running) |
144 | if (drm_kms_helper_poll != dev->mode_config.poll_running) |
145 | drm_kms_helper_poll_enable(dev); |
145 | drm_kms_helper_poll_enable(dev); |
146 | 146 | ||
147 | dev->mode_config.poll_running = drm_kms_helper_poll; |
147 | dev->mode_config.poll_running = drm_kms_helper_poll; |
148 | 148 | ||
149 | if (connector->status == connector_status_disconnected) { |
149 | if (connector->status == connector_status_disconnected) { |
150 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", |
150 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", |
151 | connector->base.id, drm_get_connector_name(connector)); |
151 | connector->base.id, drm_get_connector_name(connector)); |
152 | drm_mode_connector_update_edid_property(connector, NULL); |
152 | drm_mode_connector_update_edid_property(connector, NULL); |
153 | verbose_prune = false; |
153 | verbose_prune = false; |
154 | goto prune; |
154 | goto prune; |
155 | } |
155 | } |
156 | 156 | ||
157 | #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE |
157 | #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE |
158 | count = drm_load_edid_firmware(connector); |
158 | count = drm_load_edid_firmware(connector); |
159 | if (count == 0) |
159 | if (count == 0) |
160 | #endif |
160 | #endif |
161 | count = (*connector_funcs->get_modes)(connector); |
161 | count = (*connector_funcs->get_modes)(connector); |
162 | 162 | ||
163 | if (count == 0 && connector->status == connector_status_connected) |
163 | if (count == 0 && connector->status == connector_status_connected) |
164 | count = drm_add_modes_noedid(connector, 1024, 768); |
164 | count = drm_add_modes_noedid(connector, 1024, 768); |
165 | if (count == 0) |
165 | if (count == 0) |
166 | goto prune; |
166 | goto prune; |
167 | 167 | ||
168 | drm_mode_connector_list_update(connector); |
168 | drm_mode_connector_list_update(connector); |
169 | 169 | ||
170 | if (maxX && maxY) |
170 | if (maxX && maxY) |
171 | drm_mode_validate_size(dev, &connector->modes, maxX, |
171 | drm_mode_validate_size(dev, &connector->modes, maxX, |
172 | maxY, 0); |
172 | maxY, 0); |
173 | 173 | ||
174 | if (connector->interlace_allowed) |
174 | if (connector->interlace_allowed) |
175 | mode_flags |= DRM_MODE_FLAG_INTERLACE; |
175 | mode_flags |= DRM_MODE_FLAG_INTERLACE; |
176 | if (connector->doublescan_allowed) |
176 | if (connector->doublescan_allowed) |
177 | mode_flags |= DRM_MODE_FLAG_DBLSCAN; |
177 | mode_flags |= DRM_MODE_FLAG_DBLSCAN; |
178 | drm_mode_validate_flag(connector, mode_flags); |
178 | drm_mode_validate_flag(connector, mode_flags); |
179 | 179 | ||
180 | list_for_each_entry(mode, &connector->modes, head) { |
180 | list_for_each_entry(mode, &connector->modes, head) { |
181 | if (mode->status == MODE_OK) |
181 | if (mode->status == MODE_OK) |
182 | mode->status = connector_funcs->mode_valid(connector, |
182 | mode->status = connector_funcs->mode_valid(connector, |
183 | mode); |
183 | mode); |
184 | } |
184 | } |
185 | 185 | ||
186 | prune: |
186 | prune: |
187 | drm_mode_prune_invalid(dev, &connector->modes, verbose_prune); |
187 | drm_mode_prune_invalid(dev, &connector->modes, verbose_prune); |
188 | 188 | ||
189 | if (list_empty(&connector->modes)) |
189 | if (list_empty(&connector->modes)) |
190 | return 0; |
190 | return 0; |
191 | 191 | ||
192 | list_for_each_entry(mode, &connector->modes, head) |
192 | list_for_each_entry(mode, &connector->modes, head) |
193 | mode->vrefresh = drm_mode_vrefresh(mode); |
193 | mode->vrefresh = drm_mode_vrefresh(mode); |
194 | 194 | ||
195 | drm_mode_sort(&connector->modes); |
195 | drm_mode_sort(&connector->modes); |
196 | 196 | ||
197 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id, |
197 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id, |
198 | drm_get_connector_name(connector)); |
198 | drm_get_connector_name(connector)); |
199 | list_for_each_entry(mode, &connector->modes, head) { |
199 | list_for_each_entry(mode, &connector->modes, head) { |
200 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
200 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
201 | drm_mode_debug_printmodeline(mode); |
201 | drm_mode_debug_printmodeline(mode); |
202 | } |
202 | } |
203 | 203 | ||
204 | return count; |
204 | return count; |
205 | } |
205 | } |
206 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); |
206 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); |
207 | 207 | ||
208 | /** |
208 | /** |
209 | * drm_helper_encoder_in_use - check if a given encoder is in use |
209 | * drm_helper_encoder_in_use - check if a given encoder is in use |
210 | * @encoder: encoder to check |
210 | * @encoder: encoder to check |
211 | * |
211 | * |
212 | * LOCKING: |
212 | * LOCKING: |
213 | * Caller must hold mode config lock. |
213 | * Caller must hold mode config lock. |
214 | * |
214 | * |
215 | * Walk @encoders's DRM device's mode_config and see if it's in use. |
215 | * Walk @encoders's DRM device's mode_config and see if it's in use. |
216 | * |
216 | * |
217 | * RETURNS: |
217 | * RETURNS: |
218 | * True if @encoder is part of the mode_config, false otherwise. |
218 | * True if @encoder is part of the mode_config, false otherwise. |
219 | */ |
219 | */ |
220 | bool drm_helper_encoder_in_use(struct drm_encoder *encoder) |
220 | bool drm_helper_encoder_in_use(struct drm_encoder *encoder) |
221 | { |
221 | { |
222 | struct drm_connector *connector; |
222 | struct drm_connector *connector; |
223 | struct drm_device *dev = encoder->dev; |
223 | struct drm_device *dev = encoder->dev; |
224 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
224 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
225 | if (connector->encoder == encoder) |
225 | if (connector->encoder == encoder) |
226 | return true; |
226 | return true; |
227 | return false; |
227 | return false; |
228 | } |
228 | } |
229 | EXPORT_SYMBOL(drm_helper_encoder_in_use); |
229 | EXPORT_SYMBOL(drm_helper_encoder_in_use); |
230 | 230 | ||
231 | /** |
231 | /** |
232 | * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config |
232 | * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config |
233 | * @crtc: CRTC to check |
233 | * @crtc: CRTC to check |
234 | * |
234 | * |
235 | * LOCKING: |
235 | * LOCKING: |
236 | * Caller must hold mode config lock. |
236 | * Caller must hold mode config lock. |
237 | * |
237 | * |
238 | * Walk @crtc's DRM device's mode_config and see if it's in use. |
238 | * Walk @crtc's DRM device's mode_config and see if it's in use. |
239 | * |
239 | * |
240 | * RETURNS: |
240 | * RETURNS: |
241 | * True if @crtc is part of the mode_config, false otherwise. |
241 | * True if @crtc is part of the mode_config, false otherwise. |
242 | */ |
242 | */ |
243 | bool drm_helper_crtc_in_use(struct drm_crtc *crtc) |
243 | bool drm_helper_crtc_in_use(struct drm_crtc *crtc) |
244 | { |
244 | { |
245 | struct drm_encoder *encoder; |
245 | struct drm_encoder *encoder; |
246 | struct drm_device *dev = crtc->dev; |
246 | struct drm_device *dev = crtc->dev; |
247 | /* FIXME: Locking around list access? */ |
247 | /* FIXME: Locking around list access? */ |
248 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) |
248 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) |
249 | if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder)) |
249 | if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder)) |
250 | return true; |
250 | return true; |
251 | return false; |
251 | return false; |
252 | } |
252 | } |
253 | EXPORT_SYMBOL(drm_helper_crtc_in_use); |
253 | EXPORT_SYMBOL(drm_helper_crtc_in_use); |
254 | 254 | ||
255 | static void |
255 | static void |
256 | drm_encoder_disable(struct drm_encoder *encoder) |
256 | drm_encoder_disable(struct drm_encoder *encoder) |
257 | { |
257 | { |
258 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
258 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
- | 259 | ||
- | 260 | if (encoder->bridge) |
|
- | 261 | encoder->bridge->funcs->disable(encoder->bridge); |
|
259 | 262 | ||
260 | if (encoder_funcs->disable) |
263 | if (encoder_funcs->disable) |
261 | (*encoder_funcs->disable)(encoder); |
264 | (*encoder_funcs->disable)(encoder); |
262 | else |
265 | else |
263 | (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); |
266 | (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); |
- | 267 | ||
- | 268 | if (encoder->bridge) |
|
- | 269 | encoder->bridge->funcs->post_disable(encoder->bridge); |
|
264 | } |
270 | } |
265 | 271 | ||
266 | /** |
272 | /** |
267 | * drm_helper_disable_unused_functions - disable unused objects |
273 | * drm_helper_disable_unused_functions - disable unused objects |
268 | * @dev: DRM device |
274 | * @dev: DRM device |
269 | * |
275 | * |
270 | * LOCKING: |
276 | * LOCKING: |
271 | * Caller must hold mode config lock. |
277 | * Caller must hold mode config lock. |
272 | * |
278 | * |
273 | * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled |
279 | * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled |
274 | * by calling its dpms function, which should power it off. |
280 | * by calling its dpms function, which should power it off. |
275 | */ |
281 | */ |
276 | void drm_helper_disable_unused_functions(struct drm_device *dev) |
282 | void drm_helper_disable_unused_functions(struct drm_device *dev) |
277 | { |
283 | { |
278 | struct drm_encoder *encoder; |
284 | struct drm_encoder *encoder; |
279 | struct drm_connector *connector; |
285 | struct drm_connector *connector; |
280 | struct drm_crtc *crtc; |
286 | struct drm_crtc *crtc; |
281 | 287 | ||
282 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
288 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
283 | if (!connector->encoder) |
289 | if (!connector->encoder) |
284 | continue; |
290 | continue; |
285 | if (connector->status == connector_status_disconnected) |
291 | if (connector->status == connector_status_disconnected) |
286 | connector->encoder = NULL; |
292 | connector->encoder = NULL; |
287 | } |
293 | } |
288 | 294 | ||
289 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
295 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
290 | if (!drm_helper_encoder_in_use(encoder)) { |
296 | if (!drm_helper_encoder_in_use(encoder)) { |
291 | drm_encoder_disable(encoder); |
297 | drm_encoder_disable(encoder); |
292 | /* disconnector encoder from any connector */ |
298 | /* disconnector encoder from any connector */ |
293 | encoder->crtc = NULL; |
299 | encoder->crtc = NULL; |
294 | } |
300 | } |
295 | } |
301 | } |
296 | 302 | ||
297 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
303 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
298 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
304 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
299 | crtc->enabled = drm_helper_crtc_in_use(crtc); |
305 | crtc->enabled = drm_helper_crtc_in_use(crtc); |
300 | if (!crtc->enabled) { |
306 | if (!crtc->enabled) { |
301 | if (crtc_funcs->disable) |
307 | if (crtc_funcs->disable) |
302 | (*crtc_funcs->disable)(crtc); |
308 | (*crtc_funcs->disable)(crtc); |
303 | else |
309 | else |
304 | (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF); |
310 | (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF); |
305 | crtc->fb = NULL; |
311 | crtc->fb = NULL; |
306 | } |
312 | } |
307 | } |
313 | } |
308 | } |
314 | } |
309 | EXPORT_SYMBOL(drm_helper_disable_unused_functions); |
315 | EXPORT_SYMBOL(drm_helper_disable_unused_functions); |
310 | 316 | ||
311 | /** |
317 | /** |
312 | * drm_encoder_crtc_ok - can a given crtc drive a given encoder? |
318 | * drm_encoder_crtc_ok - can a given crtc drive a given encoder? |
313 | * @encoder: encoder to test |
319 | * @encoder: encoder to test |
314 | * @crtc: crtc to test |
320 | * @crtc: crtc to test |
315 | * |
321 | * |
316 | * Return false if @encoder can't be driven by @crtc, true otherwise. |
322 | * Return false if @encoder can't be driven by @crtc, true otherwise. |
317 | */ |
323 | */ |
318 | static bool drm_encoder_crtc_ok(struct drm_encoder *encoder, |
324 | static bool drm_encoder_crtc_ok(struct drm_encoder *encoder, |
319 | struct drm_crtc *crtc) |
325 | struct drm_crtc *crtc) |
320 | { |
326 | { |
321 | struct drm_device *dev; |
327 | struct drm_device *dev; |
322 | struct drm_crtc *tmp; |
328 | struct drm_crtc *tmp; |
323 | int crtc_mask = 1; |
329 | int crtc_mask = 1; |
324 | 330 | ||
325 | WARN(!crtc, "checking null crtc?\n"); |
331 | WARN(!crtc, "checking null crtc?\n"); |
326 | 332 | ||
327 | dev = crtc->dev; |
333 | dev = crtc->dev; |
328 | 334 | ||
329 | list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { |
335 | list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { |
330 | if (tmp == crtc) |
336 | if (tmp == crtc) |
331 | break; |
337 | break; |
332 | crtc_mask <<= 1; |
338 | crtc_mask <<= 1; |
333 | } |
339 | } |
334 | 340 | ||
335 | if (encoder->possible_crtcs & crtc_mask) |
341 | if (encoder->possible_crtcs & crtc_mask) |
336 | return true; |
342 | return true; |
337 | return false; |
343 | return false; |
338 | } |
344 | } |
339 | 345 | ||
340 | /* |
346 | /* |
341 | * Check the CRTC we're going to map each output to vs. its current |
347 | * Check the CRTC we're going to map each output to vs. its current |
342 | * CRTC. If they don't match, we have to disable the output and the CRTC |
348 | * CRTC. If they don't match, we have to disable the output and the CRTC |
343 | * since the driver will have to re-route things. |
349 | * since the driver will have to re-route things. |
344 | */ |
350 | */ |
345 | static void |
351 | static void |
346 | drm_crtc_prepare_encoders(struct drm_device *dev) |
352 | drm_crtc_prepare_encoders(struct drm_device *dev) |
347 | { |
353 | { |
348 | struct drm_encoder_helper_funcs *encoder_funcs; |
354 | struct drm_encoder_helper_funcs *encoder_funcs; |
349 | struct drm_encoder *encoder; |
355 | struct drm_encoder *encoder; |
350 | 356 | ||
351 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
357 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
352 | encoder_funcs = encoder->helper_private; |
358 | encoder_funcs = encoder->helper_private; |
353 | /* Disable unused encoders */ |
359 | /* Disable unused encoders */ |
354 | if (encoder->crtc == NULL) |
360 | if (encoder->crtc == NULL) |
355 | drm_encoder_disable(encoder); |
361 | drm_encoder_disable(encoder); |
356 | /* Disable encoders whose CRTC is about to change */ |
362 | /* Disable encoders whose CRTC is about to change */ |
357 | if (encoder_funcs->get_crtc && |
363 | if (encoder_funcs->get_crtc && |
358 | encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) |
364 | encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) |
359 | drm_encoder_disable(encoder); |
365 | drm_encoder_disable(encoder); |
360 | } |
366 | } |
361 | } |
367 | } |
362 | 368 | ||
363 | /** |
369 | /** |
364 | * drm_crtc_helper_set_mode - internal helper to set a mode |
370 | * drm_crtc_helper_set_mode - internal helper to set a mode |
365 | * @crtc: CRTC to program |
371 | * @crtc: CRTC to program |
366 | * @mode: mode to use |
372 | * @mode: mode to use |
367 | * @x: horizontal offset into the surface |
373 | * @x: horizontal offset into the surface |
368 | * @y: vertical offset into the surface |
374 | * @y: vertical offset into the surface |
369 | * @old_fb: old framebuffer, for cleanup |
375 | * @old_fb: old framebuffer, for cleanup |
370 | * |
376 | * |
371 | * LOCKING: |
377 | * LOCKING: |
372 | * Caller must hold mode config lock. |
378 | * Caller must hold mode config lock. |
373 | * |
379 | * |
374 | * Try to set @mode on @crtc. Give @crtc and its associated connectors a chance |
380 | * Try to set @mode on @crtc. Give @crtc and its associated connectors a chance |
375 | * to fixup or reject the mode prior to trying to set it. This is an internal |
381 | * to fixup or reject the mode prior to trying to set it. This is an internal |
376 | * helper that drivers could e.g. use to update properties that require the |
382 | * helper that drivers could e.g. use to update properties that require the |
377 | * entire output pipe to be disabled and re-enabled in a new configuration. For |
383 | * entire output pipe to be disabled and re-enabled in a new configuration. For |
378 | * example for changing whether audio is enabled on a hdmi link or for changing |
384 | * example for changing whether audio is enabled on a hdmi link or for changing |
379 | * panel fitter or dither attributes. It is also called by the |
385 | * panel fitter or dither attributes. It is also called by the |
380 | * drm_crtc_helper_set_config() helper function to drive the mode setting |
386 | * drm_crtc_helper_set_config() helper function to drive the mode setting |
381 | * sequence. |
387 | * sequence. |
382 | * |
388 | * |
383 | * RETURNS: |
389 | * RETURNS: |
384 | * True if the mode was set successfully, or false otherwise. |
390 | * True if the mode was set successfully, or false otherwise. |
385 | */ |
391 | */ |
386 | bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, |
392 | bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, |
387 | struct drm_display_mode *mode, |
393 | struct drm_display_mode *mode, |
388 | int x, int y, |
394 | int x, int y, |
389 | struct drm_framebuffer *old_fb) |
395 | struct drm_framebuffer *old_fb) |
390 | { |
396 | { |
391 | struct drm_device *dev = crtc->dev; |
397 | struct drm_device *dev = crtc->dev; |
392 | struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; |
398 | struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; |
393 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
399 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
394 | struct drm_encoder_helper_funcs *encoder_funcs; |
400 | struct drm_encoder_helper_funcs *encoder_funcs; |
395 | int saved_x, saved_y; |
401 | int saved_x, saved_y; |
396 | struct drm_encoder *encoder; |
402 | struct drm_encoder *encoder; |
397 | bool ret = true; |
403 | bool ret = true; |
398 | 404 | ||
399 | crtc->enabled = drm_helper_crtc_in_use(crtc); |
405 | crtc->enabled = drm_helper_crtc_in_use(crtc); |
400 | if (!crtc->enabled) |
406 | if (!crtc->enabled) |
401 | return true; |
407 | return true; |
402 | 408 | ||
403 | adjusted_mode = drm_mode_duplicate(dev, mode); |
409 | adjusted_mode = drm_mode_duplicate(dev, mode); |
404 | if (!adjusted_mode) |
410 | if (!adjusted_mode) |
405 | return false; |
411 | return false; |
406 | 412 | ||
407 | saved_hwmode = crtc->hwmode; |
413 | saved_hwmode = crtc->hwmode; |
408 | saved_mode = crtc->mode; |
414 | saved_mode = crtc->mode; |
409 | saved_x = crtc->x; |
415 | saved_x = crtc->x; |
410 | saved_y = crtc->y; |
416 | saved_y = crtc->y; |
411 | 417 | ||
412 | /* Update crtc values up front so the driver can rely on them for mode |
418 | /* Update crtc values up front so the driver can rely on them for mode |
413 | * setting. |
419 | * setting. |
414 | */ |
420 | */ |
415 | crtc->mode = *mode; |
421 | crtc->mode = *mode; |
416 | crtc->x = x; |
422 | crtc->x = x; |
417 | crtc->y = y; |
423 | crtc->y = y; |
418 | 424 | ||
419 | /* Pass our mode to the connectors and the CRTC to give them a chance to |
425 | /* Pass our mode to the connectors and the CRTC to give them a chance to |
420 | * adjust it according to limitations or connector properties, and also |
426 | * adjust it according to limitations or connector properties, and also |
421 | * a chance to reject the mode entirely. |
427 | * a chance to reject the mode entirely. |
422 | */ |
428 | */ |
423 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
429 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
424 | 430 | ||
425 | if (encoder->crtc != crtc) |
431 | if (encoder->crtc != crtc) |
426 | continue; |
432 | continue; |
- | 433 | ||
- | 434 | if (encoder->bridge && encoder->bridge->funcs->mode_fixup) { |
|
- | 435 | ret = encoder->bridge->funcs->mode_fixup( |
|
- | 436 | encoder->bridge, mode, adjusted_mode); |
|
- | 437 | if (!ret) { |
|
- | 438 | DRM_DEBUG_KMS("Bridge fixup failed\n"); |
|
- | 439 | goto done; |
|
- | 440 | } |
|
- | 441 | } |
|
- | 442 | ||
427 | encoder_funcs = encoder->helper_private; |
443 | encoder_funcs = encoder->helper_private; |
428 | if (!(ret = encoder_funcs->mode_fixup(encoder, mode, |
444 | if (!(ret = encoder_funcs->mode_fixup(encoder, mode, |
429 | adjusted_mode))) { |
445 | adjusted_mode))) { |
430 | DRM_DEBUG_KMS("Encoder fixup failed\n"); |
446 | DRM_DEBUG_KMS("Encoder fixup failed\n"); |
431 | goto done; |
447 | goto done; |
432 | } |
448 | } |
433 | } |
449 | } |
434 | 450 | ||
435 | if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { |
451 | if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { |
436 | DRM_DEBUG_KMS("CRTC fixup failed\n"); |
452 | DRM_DEBUG_KMS("CRTC fixup failed\n"); |
437 | goto done; |
453 | goto done; |
438 | } |
454 | } |
439 | DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); |
455 | DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); |
440 | 456 | ||
441 | /* Prepare the encoders and CRTCs before setting the mode. */ |
457 | /* Prepare the encoders and CRTCs before setting the mode. */ |
442 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
458 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
443 | 459 | ||
444 | if (encoder->crtc != crtc) |
460 | if (encoder->crtc != crtc) |
445 | continue; |
461 | continue; |
- | 462 | ||
- | 463 | if (encoder->bridge) |
|
- | 464 | encoder->bridge->funcs->disable(encoder->bridge); |
|
- | 465 | ||
446 | encoder_funcs = encoder->helper_private; |
466 | encoder_funcs = encoder->helper_private; |
447 | /* Disable the encoders as the first thing we do. */ |
467 | /* Disable the encoders as the first thing we do. */ |
448 | encoder_funcs->prepare(encoder); |
468 | encoder_funcs->prepare(encoder); |
- | 469 | ||
- | 470 | if (encoder->bridge) |
|
- | 471 | encoder->bridge->funcs->post_disable(encoder->bridge); |
|
449 | } |
472 | } |
450 | 473 | ||
451 | drm_crtc_prepare_encoders(dev); |
474 | drm_crtc_prepare_encoders(dev); |
452 | 475 | ||
453 | crtc_funcs->prepare(crtc); |
476 | crtc_funcs->prepare(crtc); |
454 | 477 | ||
455 | /* Set up the DPLL and any encoders state that needs to adjust or depend |
478 | /* Set up the DPLL and any encoders state that needs to adjust or depend |
456 | * on the DPLL. |
479 | * on the DPLL. |
457 | */ |
480 | */ |
458 | ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb); |
481 | ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb); |
459 | if (!ret) |
482 | if (!ret) |
460 | goto done; |
483 | goto done; |
461 | 484 | ||
462 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
485 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
463 | 486 | ||
464 | if (encoder->crtc != crtc) |
487 | if (encoder->crtc != crtc) |
465 | continue; |
488 | continue; |
466 | 489 | ||
467 | DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", |
490 | DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", |
468 | encoder->base.id, drm_get_encoder_name(encoder), |
491 | encoder->base.id, drm_get_encoder_name(encoder), |
469 | mode->base.id, mode->name); |
492 | mode->base.id, mode->name); |
470 | encoder_funcs = encoder->helper_private; |
493 | encoder_funcs = encoder->helper_private; |
471 | encoder_funcs->mode_set(encoder, mode, adjusted_mode); |
494 | encoder_funcs->mode_set(encoder, mode, adjusted_mode); |
- | 495 | ||
- | 496 | if (encoder->bridge && encoder->bridge->funcs->mode_set) |
|
- | 497 | encoder->bridge->funcs->mode_set(encoder->bridge, mode, |
|
- | 498 | adjusted_mode); |
|
472 | } |
499 | } |
473 | 500 | ||
474 | /* Now enable the clocks, plane, pipe, and connectors that we set up. */ |
501 | /* Now enable the clocks, plane, pipe, and connectors that we set up. */ |
475 | crtc_funcs->commit(crtc); |
502 | crtc_funcs->commit(crtc); |
476 | 503 | ||
477 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
504 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
478 | 505 | ||
479 | if (encoder->crtc != crtc) |
506 | if (encoder->crtc != crtc) |
480 | continue; |
507 | continue; |
- | 508 | ||
- | 509 | if (encoder->bridge) |
|
- | 510 | encoder->bridge->funcs->pre_enable(encoder->bridge); |
|
481 | 511 | ||
482 | encoder_funcs = encoder->helper_private; |
512 | encoder_funcs = encoder->helper_private; |
483 | encoder_funcs->commit(encoder); |
513 | encoder_funcs->commit(encoder); |
- | 514 | ||
- | 515 | if (encoder->bridge) |
|
484 | 516 | encoder->bridge->funcs->enable(encoder->bridge); |
|
485 | } |
517 | } |
486 | 518 | ||
487 | /* Store real post-adjustment hardware mode. */ |
519 | /* Store real post-adjustment hardware mode. */ |
488 | crtc->hwmode = *adjusted_mode; |
520 | crtc->hwmode = *adjusted_mode; |
489 | 521 | ||
490 | /* Calculate and store various constants which |
522 | /* Calculate and store various constants which |
491 | * are later needed by vblank and swap-completion |
523 | * are later needed by vblank and swap-completion |
492 | * timestamping. They are derived from true hwmode. |
524 | * timestamping. They are derived from true hwmode. |
493 | */ |
525 | */ |
494 | drm_calc_timestamping_constants(crtc); |
526 | drm_calc_timestamping_constants(crtc); |
495 | 527 | ||
496 | /* FIXME: add subpixel order */ |
528 | /* FIXME: add subpixel order */ |
497 | done: |
529 | done: |
498 | drm_mode_destroy(dev, adjusted_mode); |
530 | drm_mode_destroy(dev, adjusted_mode); |
499 | if (!ret) { |
531 | if (!ret) { |
500 | crtc->hwmode = saved_hwmode; |
532 | crtc->hwmode = saved_hwmode; |
501 | crtc->mode = saved_mode; |
533 | crtc->mode = saved_mode; |
502 | crtc->x = saved_x; |
534 | crtc->x = saved_x; |
503 | crtc->y = saved_y; |
535 | crtc->y = saved_y; |
504 | } |
536 | } |
505 | 537 | ||
506 | return ret; |
538 | return ret; |
507 | } |
539 | } |
508 | EXPORT_SYMBOL(drm_crtc_helper_set_mode); |
540 | EXPORT_SYMBOL(drm_crtc_helper_set_mode); |
509 | 541 | ||
510 | 542 | ||
511 | static int |
543 | static int |
512 | drm_crtc_helper_disable(struct drm_crtc *crtc) |
544 | drm_crtc_helper_disable(struct drm_crtc *crtc) |
513 | { |
545 | { |
514 | struct drm_device *dev = crtc->dev; |
546 | struct drm_device *dev = crtc->dev; |
515 | struct drm_connector *connector; |
547 | struct drm_connector *connector; |
516 | struct drm_encoder *encoder; |
548 | struct drm_encoder *encoder; |
517 | 549 | ||
518 | /* Decouple all encoders and their attached connectors from this crtc */ |
550 | /* Decouple all encoders and their attached connectors from this crtc */ |
519 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
551 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
520 | if (encoder->crtc != crtc) |
552 | if (encoder->crtc != crtc) |
521 | continue; |
553 | continue; |
522 | 554 | ||
523 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
555 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
524 | if (connector->encoder != encoder) |
556 | if (connector->encoder != encoder) |
525 | continue; |
557 | continue; |
526 | 558 | ||
527 | connector->encoder = NULL; |
559 | connector->encoder = NULL; |
528 | } |
560 | } |
529 | } |
561 | } |
530 | 562 | ||
531 | drm_helper_disable_unused_functions(dev); |
563 | drm_helper_disable_unused_functions(dev); |
532 | return 0; |
564 | return 0; |
533 | } |
565 | } |
534 | 566 | ||
535 | /** |
567 | /** |
536 | * drm_crtc_helper_set_config - set a new config from userspace |
568 | * drm_crtc_helper_set_config - set a new config from userspace |
537 | * @set: mode set configuration |
569 | * @set: mode set configuration |
538 | * |
570 | * |
539 | * LOCKING: |
571 | * LOCKING: |
540 | * Caller must hold mode config lock. |
572 | * Caller must hold mode config lock. |
541 | * |
573 | * |
542 | * Setup a new configuration, provided by the upper layers (either an ioctl call |
574 | * Setup a new configuration, provided by the upper layers (either an ioctl call |
543 | * from userspace or internally e.g. from the fbdev suppport code) in @set, and |
575 | * from userspace or internally e.g. from the fbdev suppport code) in @set, and |
544 | * enable it. This is the main helper functions for drivers that implement |
576 | * enable it. This is the main helper functions for drivers that implement |
545 | * kernel mode setting with the crtc helper functions and the assorted |
577 | * kernel mode setting with the crtc helper functions and the assorted |
546 | * ->prepare(), ->modeset() and ->commit() helper callbacks. |
578 | * ->prepare(), ->modeset() and ->commit() helper callbacks. |
547 | * |
579 | * |
548 | * RETURNS: |
580 | * RETURNS: |
549 | * Returns 0 on success, -ERRNO on failure. |
581 | * Returns 0 on success, -ERRNO on failure. |
550 | */ |
582 | */ |
551 | int drm_crtc_helper_set_config(struct drm_mode_set *set) |
583 | int drm_crtc_helper_set_config(struct drm_mode_set *set) |
552 | { |
584 | { |
553 | struct drm_device *dev; |
585 | struct drm_device *dev; |
554 | struct drm_crtc *save_crtcs, *new_crtc, *crtc; |
586 | struct drm_crtc *save_crtcs, *new_crtc, *crtc; |
555 | struct drm_encoder *save_encoders, *new_encoder, *encoder; |
587 | struct drm_encoder *save_encoders, *new_encoder, *encoder; |
556 | struct drm_framebuffer *old_fb = NULL; |
588 | struct drm_framebuffer *old_fb = NULL; |
557 | bool mode_changed = false; /* if true do a full mode set */ |
589 | bool mode_changed = false; /* if true do a full mode set */ |
558 | bool fb_changed = false; /* if true and !mode_changed just do a flip */ |
590 | bool fb_changed = false; /* if true and !mode_changed just do a flip */ |
559 | struct drm_connector *save_connectors, *connector; |
591 | struct drm_connector *save_connectors, *connector; |
560 | int count = 0, ro, fail = 0; |
592 | int count = 0, ro, fail = 0; |
561 | struct drm_crtc_helper_funcs *crtc_funcs; |
593 | struct drm_crtc_helper_funcs *crtc_funcs; |
562 | struct drm_mode_set save_set; |
594 | struct drm_mode_set save_set; |
563 | int ret; |
595 | int ret; |
564 | int i; |
596 | int i; |
565 | 597 | ||
566 | DRM_DEBUG_KMS("\n"); |
598 | DRM_DEBUG_KMS("\n"); |
567 | 599 | ||
568 | BUG_ON(!set); |
600 | BUG_ON(!set); |
569 | BUG_ON(!set->crtc); |
601 | BUG_ON(!set->crtc); |
570 | BUG_ON(!set->crtc->helper_private); |
602 | BUG_ON(!set->crtc->helper_private); |
571 | 603 | ||
572 | /* Enforce sane interface api - has been abused by the fb helper. */ |
604 | /* Enforce sane interface api - has been abused by the fb helper. */ |
573 | BUG_ON(!set->mode && set->fb); |
605 | BUG_ON(!set->mode && set->fb); |
574 | BUG_ON(set->fb && set->num_connectors == 0); |
606 | BUG_ON(set->fb && set->num_connectors == 0); |
575 | 607 | ||
576 | crtc_funcs = set->crtc->helper_private; |
608 | crtc_funcs = set->crtc->helper_private; |
577 | 609 | ||
578 | if (!set->mode) |
610 | if (!set->mode) |
579 | set->fb = NULL; |
611 | set->fb = NULL; |
580 | 612 | ||
581 | if (set->fb) { |
613 | if (set->fb) { |
582 | DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", |
614 | DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", |
583 | set->crtc->base.id, set->fb->base.id, |
615 | set->crtc->base.id, set->fb->base.id, |
584 | (int)set->num_connectors, set->x, set->y); |
616 | (int)set->num_connectors, set->x, set->y); |
585 | } else { |
617 | } else { |
586 | DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); |
618 | DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); |
587 | return drm_crtc_helper_disable(set->crtc); |
619 | return drm_crtc_helper_disable(set->crtc); |
588 | } |
620 | } |
589 | 621 | ||
590 | dev = set->crtc->dev; |
622 | dev = set->crtc->dev; |
591 | 623 | ||
592 | /* Allocate space for the backup of all (non-pointer) crtc, encoder and |
624 | /* Allocate space for the backup of all (non-pointer) crtc, encoder and |
593 | * connector data. */ |
625 | * connector data. */ |
594 | save_crtcs = kzalloc(dev->mode_config.num_crtc * |
626 | save_crtcs = kzalloc(dev->mode_config.num_crtc * |
595 | sizeof(struct drm_crtc), GFP_KERNEL); |
627 | sizeof(struct drm_crtc), GFP_KERNEL); |
596 | if (!save_crtcs) |
628 | if (!save_crtcs) |
597 | return -ENOMEM; |
629 | return -ENOMEM; |
598 | 630 | ||
599 | save_encoders = kzalloc(dev->mode_config.num_encoder * |
631 | save_encoders = kzalloc(dev->mode_config.num_encoder * |
600 | sizeof(struct drm_encoder), GFP_KERNEL); |
632 | sizeof(struct drm_encoder), GFP_KERNEL); |
601 | if (!save_encoders) { |
633 | if (!save_encoders) { |
602 | kfree(save_crtcs); |
634 | kfree(save_crtcs); |
603 | return -ENOMEM; |
635 | return -ENOMEM; |
604 | } |
636 | } |
605 | 637 | ||
606 | save_connectors = kzalloc(dev->mode_config.num_connector * |
638 | save_connectors = kzalloc(dev->mode_config.num_connector * |
607 | sizeof(struct drm_connector), GFP_KERNEL); |
639 | sizeof(struct drm_connector), GFP_KERNEL); |
608 | if (!save_connectors) { |
640 | if (!save_connectors) { |
609 | kfree(save_crtcs); |
641 | kfree(save_crtcs); |
610 | kfree(save_encoders); |
642 | kfree(save_encoders); |
611 | return -ENOMEM; |
643 | return -ENOMEM; |
612 | } |
644 | } |
613 | 645 | ||
614 | /* Copy data. Note that driver private data is not affected. |
646 | /* Copy data. Note that driver private data is not affected. |
615 | * Should anything bad happen only the expected state is |
647 | * Should anything bad happen only the expected state is |
616 | * restored, not the drivers personal bookkeeping. |
648 | * restored, not the drivers personal bookkeeping. |
617 | */ |
649 | */ |
618 | count = 0; |
650 | count = 0; |
619 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
651 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
620 | save_crtcs[count++] = *crtc; |
652 | save_crtcs[count++] = *crtc; |
621 | } |
653 | } |
622 | 654 | ||
623 | count = 0; |
655 | count = 0; |
624 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
656 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
625 | save_encoders[count++] = *encoder; |
657 | save_encoders[count++] = *encoder; |
626 | } |
658 | } |
627 | 659 | ||
628 | count = 0; |
660 | count = 0; |
629 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
661 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
630 | save_connectors[count++] = *connector; |
662 | save_connectors[count++] = *connector; |
631 | } |
663 | } |
632 | 664 | ||
633 | save_set.crtc = set->crtc; |
665 | save_set.crtc = set->crtc; |
634 | save_set.mode = &set->crtc->mode; |
666 | save_set.mode = &set->crtc->mode; |
635 | save_set.x = set->crtc->x; |
667 | save_set.x = set->crtc->x; |
636 | save_set.y = set->crtc->y; |
668 | save_set.y = set->crtc->y; |
637 | save_set.fb = set->crtc->fb; |
669 | save_set.fb = set->crtc->fb; |
638 | 670 | ||
639 | /* We should be able to check here if the fb has the same properties |
671 | /* We should be able to check here if the fb has the same properties |
640 | * and then just flip_or_move it */ |
672 | * and then just flip_or_move it */ |
641 | if (set->crtc->fb != set->fb) { |
673 | if (set->crtc->fb != set->fb) { |
642 | /* If we have no fb then treat it as a full mode set */ |
674 | /* If we have no fb then treat it as a full mode set */ |
643 | if (set->crtc->fb == NULL) { |
675 | if (set->crtc->fb == NULL) { |
644 | DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); |
676 | DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); |
645 | mode_changed = true; |
677 | mode_changed = true; |
646 | } else if (set->fb == NULL) { |
678 | } else if (set->fb == NULL) { |
647 | mode_changed = true; |
679 | mode_changed = true; |
648 | } else if (set->fb->pixel_format != |
680 | } else if (set->fb->pixel_format != |
649 | set->crtc->fb->pixel_format) { |
681 | set->crtc->fb->pixel_format) { |
650 | mode_changed = true; |
682 | mode_changed = true; |
651 | } else |
683 | } else |
652 | fb_changed = true; |
684 | fb_changed = true; |
653 | } |
685 | } |
654 | 686 | ||
655 | if (set->x != set->crtc->x || set->y != set->crtc->y) |
687 | if (set->x != set->crtc->x || set->y != set->crtc->y) |
656 | fb_changed = true; |
688 | fb_changed = true; |
657 | 689 | ||
658 | if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { |
690 | if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { |
659 | DRM_DEBUG_KMS("modes are different, full mode set\n"); |
691 | DRM_DEBUG_KMS("modes are different, full mode set\n"); |
660 | drm_mode_debug_printmodeline(&set->crtc->mode); |
692 | drm_mode_debug_printmodeline(&set->crtc->mode); |
661 | drm_mode_debug_printmodeline(set->mode); |
693 | drm_mode_debug_printmodeline(set->mode); |
662 | mode_changed = true; |
694 | mode_changed = true; |
663 | } |
695 | } |
664 | 696 | ||
665 | /* a) traverse passed in connector list and get encoders for them */ |
697 | /* a) traverse passed in connector list and get encoders for them */ |
666 | count = 0; |
698 | count = 0; |
667 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
699 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
668 | struct drm_connector_helper_funcs *connector_funcs = |
700 | struct drm_connector_helper_funcs *connector_funcs = |
669 | connector->helper_private; |
701 | connector->helper_private; |
670 | new_encoder = connector->encoder; |
702 | new_encoder = connector->encoder; |
671 | for (ro = 0; ro < set->num_connectors; ro++) { |
703 | for (ro = 0; ro < set->num_connectors; ro++) { |
672 | if (set->connectors[ro] == connector) { |
704 | if (set->connectors[ro] == connector) { |
673 | new_encoder = connector_funcs->best_encoder(connector); |
705 | new_encoder = connector_funcs->best_encoder(connector); |
674 | /* if we can't get an encoder for a connector |
706 | /* if we can't get an encoder for a connector |
675 | we are setting now - then fail */ |
707 | we are setting now - then fail */ |
676 | if (new_encoder == NULL) |
708 | if (new_encoder == NULL) |
677 | /* don't break so fail path works correct */ |
709 | /* don't break so fail path works correct */ |
678 | fail = 1; |
710 | fail = 1; |
679 | break; |
711 | break; |
680 | 712 | ||
681 | if (connector->dpms != DRM_MODE_DPMS_ON) { |
713 | if (connector->dpms != DRM_MODE_DPMS_ON) { |
682 | DRM_DEBUG_KMS("connector dpms not on, full mode switch\n"); |
714 | DRM_DEBUG_KMS("connector dpms not on, full mode switch\n"); |
683 | mode_changed = true; |
715 | mode_changed = true; |
684 | } |
716 | } |
685 | } |
717 | } |
686 | } |
718 | } |
687 | 719 | ||
688 | if (new_encoder != connector->encoder) { |
720 | if (new_encoder != connector->encoder) { |
689 | DRM_DEBUG_KMS("encoder changed, full mode switch\n"); |
721 | DRM_DEBUG_KMS("encoder changed, full mode switch\n"); |
690 | mode_changed = true; |
722 | mode_changed = true; |
691 | /* If the encoder is reused for another connector, then |
723 | /* If the encoder is reused for another connector, then |
692 | * the appropriate crtc will be set later. |
724 | * the appropriate crtc will be set later. |
693 | */ |
725 | */ |
694 | if (connector->encoder) |
726 | if (connector->encoder) |
695 | connector->encoder->crtc = NULL; |
727 | connector->encoder->crtc = NULL; |
696 | connector->encoder = new_encoder; |
728 | connector->encoder = new_encoder; |
697 | } |
729 | } |
698 | } |
730 | } |
699 | 731 | ||
700 | if (fail) { |
732 | if (fail) { |
701 | ret = -EINVAL; |
733 | ret = -EINVAL; |
702 | goto fail; |
734 | goto fail; |
703 | } |
735 | } |
704 | 736 | ||
705 | count = 0; |
737 | count = 0; |
706 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
738 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
707 | if (!connector->encoder) |
739 | if (!connector->encoder) |
708 | continue; |
740 | continue; |
709 | 741 | ||
710 | if (connector->encoder->crtc == set->crtc) |
742 | if (connector->encoder->crtc == set->crtc) |
711 | new_crtc = NULL; |
743 | new_crtc = NULL; |
712 | else |
744 | else |
713 | new_crtc = connector->encoder->crtc; |
745 | new_crtc = connector->encoder->crtc; |
714 | 746 | ||
715 | for (ro = 0; ro < set->num_connectors; ro++) { |
747 | for (ro = 0; ro < set->num_connectors; ro++) { |
716 | if (set->connectors[ro] == connector) |
748 | if (set->connectors[ro] == connector) |
717 | new_crtc = set->crtc; |
749 | new_crtc = set->crtc; |
718 | } |
750 | } |
719 | 751 | ||
720 | /* Make sure the new CRTC will work with the encoder */ |
752 | /* Make sure the new CRTC will work with the encoder */ |
721 | if (new_crtc && |
753 | if (new_crtc && |
722 | !drm_encoder_crtc_ok(connector->encoder, new_crtc)) { |
754 | !drm_encoder_crtc_ok(connector->encoder, new_crtc)) { |
723 | ret = -EINVAL; |
755 | ret = -EINVAL; |
724 | goto fail; |
756 | goto fail; |
725 | } |
757 | } |
726 | if (new_crtc != connector->encoder->crtc) { |
758 | if (new_crtc != connector->encoder->crtc) { |
727 | DRM_DEBUG_KMS("crtc changed, full mode switch\n"); |
759 | DRM_DEBUG_KMS("crtc changed, full mode switch\n"); |
728 | mode_changed = true; |
760 | mode_changed = true; |
729 | connector->encoder->crtc = new_crtc; |
761 | connector->encoder->crtc = new_crtc; |
730 | } |
762 | } |
731 | if (new_crtc) { |
763 | if (new_crtc) { |
732 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", |
764 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", |
733 | connector->base.id, drm_get_connector_name(connector), |
765 | connector->base.id, drm_get_connector_name(connector), |
734 | new_crtc->base.id); |
766 | new_crtc->base.id); |
735 | } else { |
767 | } else { |
736 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", |
768 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", |
737 | connector->base.id, drm_get_connector_name(connector)); |
769 | connector->base.id, drm_get_connector_name(connector)); |
738 | } |
770 | } |
739 | } |
771 | } |
740 | 772 | ||
741 | /* mode_set_base is not a required function */ |
773 | /* mode_set_base is not a required function */ |
742 | if (fb_changed && !crtc_funcs->mode_set_base) |
774 | if (fb_changed && !crtc_funcs->mode_set_base) |
743 | mode_changed = true; |
775 | mode_changed = true; |
744 | 776 | ||
745 | if (mode_changed) { |
777 | if (mode_changed) { |
746 | set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); |
778 | set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); |
747 | if (set->crtc->enabled) { |
779 | if (set->crtc->enabled) { |
748 | DRM_DEBUG_KMS("attempting to set mode from" |
780 | DRM_DEBUG_KMS("attempting to set mode from" |
749 | " userspace\n"); |
781 | " userspace\n"); |
750 | drm_mode_debug_printmodeline(set->mode); |
782 | drm_mode_debug_printmodeline(set->mode); |
751 | old_fb = set->crtc->fb; |
783 | old_fb = set->crtc->fb; |
752 | set->crtc->fb = set->fb; |
784 | set->crtc->fb = set->fb; |
753 | if (!drm_crtc_helper_set_mode(set->crtc, set->mode, |
785 | if (!drm_crtc_helper_set_mode(set->crtc, set->mode, |
754 | set->x, set->y, |
786 | set->x, set->y, |
755 | old_fb)) { |
787 | old_fb)) { |
756 | DRM_ERROR("failed to set mode on [CRTC:%d]\n", |
788 | DRM_ERROR("failed to set mode on [CRTC:%d]\n", |
757 | set->crtc->base.id); |
789 | set->crtc->base.id); |
758 | set->crtc->fb = old_fb; |
790 | set->crtc->fb = old_fb; |
759 | ret = -EINVAL; |
791 | ret = -EINVAL; |
760 | goto fail; |
792 | goto fail; |
761 | } |
793 | } |
762 | DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); |
794 | DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); |
763 | for (i = 0; i < set->num_connectors; i++) { |
795 | for (i = 0; i < set->num_connectors; i++) { |
764 | DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, |
796 | DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, |
765 | drm_get_connector_name(set->connectors[i])); |
797 | drm_get_connector_name(set->connectors[i])); |
766 | set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); |
798 | set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); |
767 | } |
799 | } |
768 | } |
800 | } |
769 | drm_helper_disable_unused_functions(dev); |
801 | drm_helper_disable_unused_functions(dev); |
770 | } else if (fb_changed) { |
802 | } else if (fb_changed) { |
771 | set->crtc->x = set->x; |
803 | set->crtc->x = set->x; |
772 | set->crtc->y = set->y; |
804 | set->crtc->y = set->y; |
773 | 805 | ||
774 | old_fb = set->crtc->fb; |
806 | old_fb = set->crtc->fb; |
775 | if (set->crtc->fb != set->fb) |
807 | if (set->crtc->fb != set->fb) |
776 | set->crtc->fb = set->fb; |
808 | set->crtc->fb = set->fb; |
777 | ret = crtc_funcs->mode_set_base(set->crtc, |
809 | ret = crtc_funcs->mode_set_base(set->crtc, |
778 | set->x, set->y, old_fb); |
810 | set->x, set->y, old_fb); |
779 | if (ret != 0) { |
811 | if (ret != 0) { |
780 | set->crtc->fb = old_fb; |
812 | set->crtc->fb = old_fb; |
781 | goto fail; |
813 | goto fail; |
782 | } |
814 | } |
783 | } |
815 | } |
784 | 816 | ||
785 | kfree(save_connectors); |
817 | kfree(save_connectors); |
786 | kfree(save_encoders); |
818 | kfree(save_encoders); |
787 | kfree(save_crtcs); |
819 | kfree(save_crtcs); |
788 | return 0; |
820 | return 0; |
789 | 821 | ||
790 | fail: |
822 | fail: |
791 | /* Restore all previous data. */ |
823 | /* Restore all previous data. */ |
792 | count = 0; |
824 | count = 0; |
793 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
825 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
794 | *crtc = save_crtcs[count++]; |
826 | *crtc = save_crtcs[count++]; |
795 | } |
827 | } |
796 | 828 | ||
797 | count = 0; |
829 | count = 0; |
798 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
830 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
799 | *encoder = save_encoders[count++]; |
831 | *encoder = save_encoders[count++]; |
800 | } |
832 | } |
801 | 833 | ||
802 | count = 0; |
834 | count = 0; |
803 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
835 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
804 | *connector = save_connectors[count++]; |
836 | *connector = save_connectors[count++]; |
805 | } |
837 | } |
806 | 838 | ||
807 | /* Try to restore the config */ |
839 | /* Try to restore the config */ |
808 | if (mode_changed && |
840 | if (mode_changed && |
809 | !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x, |
841 | !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x, |
810 | save_set.y, save_set.fb)) |
842 | save_set.y, save_set.fb)) |
811 | DRM_ERROR("failed to restore config after modeset failure\n"); |
843 | DRM_ERROR("failed to restore config after modeset failure\n"); |
812 | 844 | ||
813 | kfree(save_connectors); |
845 | kfree(save_connectors); |
814 | kfree(save_encoders); |
846 | kfree(save_encoders); |
815 | kfree(save_crtcs); |
847 | kfree(save_crtcs); |
816 | return ret; |
848 | return ret; |
817 | } |
849 | } |
818 | EXPORT_SYMBOL(drm_crtc_helper_set_config); |
850 | EXPORT_SYMBOL(drm_crtc_helper_set_config); |
819 | 851 | ||
820 | static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) |
852 | static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) |
821 | { |
853 | { |
822 | int dpms = DRM_MODE_DPMS_OFF; |
854 | int dpms = DRM_MODE_DPMS_OFF; |
823 | struct drm_connector *connector; |
855 | struct drm_connector *connector; |
824 | struct drm_device *dev = encoder->dev; |
856 | struct drm_device *dev = encoder->dev; |
825 | 857 | ||
826 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
858 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
827 | if (connector->encoder == encoder) |
859 | if (connector->encoder == encoder) |
828 | if (connector->dpms < dpms) |
860 | if (connector->dpms < dpms) |
829 | dpms = connector->dpms; |
861 | dpms = connector->dpms; |
830 | return dpms; |
862 | return dpms; |
831 | } |
863 | } |
- | 864 | ||
- | 865 | /* Helper which handles bridge ordering around encoder dpms */ |
|
- | 866 | static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode) |
|
- | 867 | { |
|
- | 868 | struct drm_bridge *bridge = encoder->bridge; |
|
- | 869 | struct drm_encoder_helper_funcs *encoder_funcs; |
|
- | 870 | ||
- | 871 | if (bridge) { |
|
- | 872 | if (mode == DRM_MODE_DPMS_ON) |
|
- | 873 | bridge->funcs->pre_enable(bridge); |
|
- | 874 | else |
|
- | 875 | bridge->funcs->disable(bridge); |
|
- | 876 | } |
|
- | 877 | ||
- | 878 | encoder_funcs = encoder->helper_private; |
|
- | 879 | if (encoder_funcs->dpms) |
|
- | 880 | encoder_funcs->dpms(encoder, mode); |
|
- | 881 | ||
- | 882 | if (bridge) { |
|
- | 883 | if (mode == DRM_MODE_DPMS_ON) |
|
- | 884 | bridge->funcs->enable(bridge); |
|
- | 885 | else |
|
- | 886 | bridge->funcs->post_disable(bridge); |
|
- | 887 | } |
|
- | 888 | } |
|
832 | 889 | ||
833 | static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc) |
890 | static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc) |
834 | { |
891 | { |
835 | int dpms = DRM_MODE_DPMS_OFF; |
892 | int dpms = DRM_MODE_DPMS_OFF; |
836 | struct drm_connector *connector; |
893 | struct drm_connector *connector; |
837 | struct drm_device *dev = crtc->dev; |
894 | struct drm_device *dev = crtc->dev; |
838 | 895 | ||
839 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
896 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
840 | if (connector->encoder && connector->encoder->crtc == crtc) |
897 | if (connector->encoder && connector->encoder->crtc == crtc) |
841 | if (connector->dpms < dpms) |
898 | if (connector->dpms < dpms) |
842 | dpms = connector->dpms; |
899 | dpms = connector->dpms; |
843 | return dpms; |
900 | return dpms; |
844 | } |
901 | } |
845 | 902 | ||
846 | /** |
903 | /** |
847 | * drm_helper_connector_dpms() - connector dpms helper implementation |
904 | * drm_helper_connector_dpms() - connector dpms helper implementation |
848 | * @connector: affected connector |
905 | * @connector: affected connector |
849 | * @mode: DPMS mode |
906 | * @mode: DPMS mode |
850 | * |
907 | * |
851 | * This is the main helper function provided by the crtc helper framework for |
908 | * This is the main helper function provided by the crtc helper framework for |
852 | * implementing the DPMS connector attribute. It computes the new desired DPMS |
909 | * implementing the DPMS connector attribute. It computes the new desired DPMS |
853 | * state for all encoders and crtcs in the output mesh and calls the ->dpms() |
910 | * state for all encoders and crtcs in the output mesh and calls the ->dpms() |
854 | * callback provided by the driver appropriately. |
911 | * callback provided by the driver appropriately. |
855 | */ |
912 | */ |
856 | void drm_helper_connector_dpms(struct drm_connector *connector, int mode) |
913 | void drm_helper_connector_dpms(struct drm_connector *connector, int mode) |
857 | { |
914 | { |
858 | struct drm_encoder *encoder = connector->encoder; |
915 | struct drm_encoder *encoder = connector->encoder; |
859 | struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; |
916 | struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; |
860 | int old_dpms; |
917 | int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF; |
861 | 918 | ||
862 | if (mode == connector->dpms) |
919 | if (mode == connector->dpms) |
863 | return; |
920 | return; |
864 | 921 | ||
865 | old_dpms = connector->dpms; |
922 | old_dpms = connector->dpms; |
866 | connector->dpms = mode; |
923 | connector->dpms = mode; |
- | 924 | ||
- | 925 | if (encoder) |
|
- | 926 | encoder_dpms = drm_helper_choose_encoder_dpms(encoder); |
|
867 | 927 | ||
868 | /* from off to on, do crtc then encoder */ |
928 | /* from off to on, do crtc then encoder */ |
869 | if (mode < old_dpms) { |
929 | if (mode < old_dpms) { |
870 | if (crtc) { |
930 | if (crtc) { |
871 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
931 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
872 | if (crtc_funcs->dpms) |
932 | if (crtc_funcs->dpms) |
873 | (*crtc_funcs->dpms) (crtc, |
933 | (*crtc_funcs->dpms) (crtc, |
874 | drm_helper_choose_crtc_dpms(crtc)); |
934 | drm_helper_choose_crtc_dpms(crtc)); |
875 | } |
935 | } |
876 | if (encoder) { |
936 | if (encoder) |
877 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
- | |
878 | if (encoder_funcs->dpms) |
- | |
879 | (*encoder_funcs->dpms) (encoder, |
- | |
880 | drm_helper_choose_encoder_dpms(encoder)); |
937 | drm_helper_encoder_dpms(encoder, encoder_dpms); |
881 | } |
- | |
882 | } |
938 | } |
883 | 939 | ||
884 | /* from on to off, do encoder then crtc */ |
940 | /* from on to off, do encoder then crtc */ |
885 | if (mode > old_dpms) { |
941 | if (mode > old_dpms) { |
886 | if (encoder) { |
942 | if (encoder) |
887 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
- | |
888 | if (encoder_funcs->dpms) |
- | |
889 | (*encoder_funcs->dpms) (encoder, |
- | |
890 | drm_helper_choose_encoder_dpms(encoder)); |
943 | drm_helper_encoder_dpms(encoder, encoder_dpms); |
891 | } |
- | |
892 | if (crtc) { |
944 | if (crtc) { |
893 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
945 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
894 | if (crtc_funcs->dpms) |
946 | if (crtc_funcs->dpms) |
895 | (*crtc_funcs->dpms) (crtc, |
947 | (*crtc_funcs->dpms) (crtc, |
896 | drm_helper_choose_crtc_dpms(crtc)); |
948 | drm_helper_choose_crtc_dpms(crtc)); |
897 | } |
949 | } |
898 | } |
950 | } |
899 | 951 | ||
900 | return; |
952 | return; |
901 | } |
953 | } |
902 | EXPORT_SYMBOL(drm_helper_connector_dpms); |
954 | EXPORT_SYMBOL(drm_helper_connector_dpms); |
903 | 955 | ||
904 | int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, |
956 | int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, |
905 | struct drm_mode_fb_cmd2 *mode_cmd) |
957 | struct drm_mode_fb_cmd2 *mode_cmd) |
906 | { |
958 | { |
907 | int i; |
959 | int i; |
908 | 960 | ||
909 | fb->width = mode_cmd->width; |
961 | fb->width = mode_cmd->width; |
910 | fb->height = mode_cmd->height; |
962 | fb->height = mode_cmd->height; |
911 | for (i = 0; i < 4; i++) { |
963 | for (i = 0; i < 4; i++) { |
912 | fb->pitches[i] = mode_cmd->pitches[i]; |
964 | fb->pitches[i] = mode_cmd->pitches[i]; |
913 | fb->offsets[i] = mode_cmd->offsets[i]; |
965 | fb->offsets[i] = mode_cmd->offsets[i]; |
914 | } |
966 | } |
915 | drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth, |
967 | drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth, |
916 | &fb->bits_per_pixel); |
968 | &fb->bits_per_pixel); |
917 | fb->pixel_format = mode_cmd->pixel_format; |
969 | fb->pixel_format = mode_cmd->pixel_format; |
918 | 970 | ||
919 | return 0; |
971 | return 0; |
920 | } |
972 | } |
921 | EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); |
973 | EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); |
922 | 974 | ||
923 | int drm_helper_resume_force_mode(struct drm_device *dev) |
975 | int drm_helper_resume_force_mode(struct drm_device *dev) |
924 | { |
976 | { |
925 | struct drm_crtc *crtc; |
977 | struct drm_crtc *crtc; |
926 | struct drm_encoder *encoder; |
978 | struct drm_encoder *encoder; |
927 | struct drm_encoder_helper_funcs *encoder_funcs; |
- | |
928 | struct drm_crtc_helper_funcs *crtc_funcs; |
979 | struct drm_crtc_helper_funcs *crtc_funcs; |
929 | int ret; |
980 | int ret, encoder_dpms; |
930 | 981 | ||
931 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
982 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
932 | 983 | ||
933 | if (!crtc->enabled) |
984 | if (!crtc->enabled) |
934 | continue; |
985 | continue; |
935 | 986 | ||
936 | ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, |
987 | ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, |
937 | crtc->x, crtc->y, crtc->fb); |
988 | crtc->x, crtc->y, crtc->fb); |
938 | 989 | ||
939 | if (ret == false) |
990 | if (ret == false) |
940 | DRM_ERROR("failed to set mode on crtc %p\n", crtc); |
991 | DRM_ERROR("failed to set mode on crtc %p\n", crtc); |
941 | 992 | ||
942 | /* Turn off outputs that were already powered off */ |
993 | /* Turn off outputs that were already powered off */ |
943 | if (drm_helper_choose_crtc_dpms(crtc)) { |
994 | if (drm_helper_choose_crtc_dpms(crtc)) { |
944 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
995 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
945 | 996 | ||
946 | if(encoder->crtc != crtc) |
997 | if(encoder->crtc != crtc) |
947 | continue; |
998 | continue; |
948 | 999 | ||
949 | encoder_funcs = encoder->helper_private; |
1000 | encoder_dpms = drm_helper_choose_encoder_dpms( |
950 | if (encoder_funcs->dpms) |
- | |
- | 1001 | encoder); |
|
951 | (*encoder_funcs->dpms) (encoder, |
1002 | |
952 | drm_helper_choose_encoder_dpms(encoder)); |
1003 | drm_helper_encoder_dpms(encoder, encoder_dpms); |
953 | } |
1004 | } |
954 | 1005 | ||
955 | crtc_funcs = crtc->helper_private; |
1006 | crtc_funcs = crtc->helper_private; |
956 | if (crtc_funcs->dpms) |
1007 | if (crtc_funcs->dpms) |
957 | (*crtc_funcs->dpms) (crtc, |
1008 | (*crtc_funcs->dpms) (crtc, |
958 | drm_helper_choose_crtc_dpms(crtc)); |
1009 | drm_helper_choose_crtc_dpms(crtc)); |
959 | } |
1010 | } |
960 | } |
1011 | } |
961 | /* disable the unused connectors while restoring the modesetting */ |
1012 | /* disable the unused connectors while restoring the modesetting */ |
962 | drm_helper_disable_unused_functions(dev); |
1013 | drm_helper_disable_unused_functions(dev); |
963 | return 0; |
1014 | return 0; |
964 | } |
1015 | } |
965 | EXPORT_SYMBOL(drm_helper_resume_force_mode); |
1016 | EXPORT_SYMBOL(drm_helper_resume_force_mode); |
966 | 1017 | ||
967 | void drm_kms_helper_hotplug_event(struct drm_device *dev) |
1018 | void drm_kms_helper_hotplug_event(struct drm_device *dev) |
968 | { |
1019 | { |
969 | /* send a uevent + call fbdev */ |
1020 | /* send a uevent + call fbdev */ |
970 | if (dev->mode_config.funcs->output_poll_changed) |
1021 | if (dev->mode_config.funcs->output_poll_changed) |
971 | dev->mode_config.funcs->output_poll_changed(dev); |
1022 | dev->mode_config.funcs->output_poll_changed(dev); |
972 | } |
1023 | } |
973 | EXPORT_SYMBOL(drm_kms_helper_hotplug_event); |
1024 | EXPORT_SYMBOL(drm_kms_helper_hotplug_event); |
974 | 1025 | ||
975 | #define DRM_OUTPUT_POLL_PERIOD (10*HZ) |
1026 | #define DRM_OUTPUT_POLL_PERIOD (10*HZ) |
976 | static void output_poll_execute(struct work_struct *work) |
1027 | static void output_poll_execute(struct work_struct *work) |
977 | { |
1028 | { |
978 | struct delayed_work *delayed_work = to_delayed_work(work); |
1029 | struct delayed_work *delayed_work = to_delayed_work(work); |
979 | struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); |
1030 | struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); |
980 | struct drm_connector *connector; |
1031 | struct drm_connector *connector; |
981 | enum drm_connector_status old_status; |
1032 | enum drm_connector_status old_status; |
982 | bool repoll = false, changed = false; |
1033 | bool repoll = false, changed = false; |
983 | 1034 | ||
984 | if (!drm_kms_helper_poll) |
1035 | if (!drm_kms_helper_poll) |
985 | return; |
1036 | return; |
986 | 1037 | ||
987 | mutex_lock(&dev->mode_config.mutex); |
1038 | mutex_lock(&dev->mode_config.mutex); |
988 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
1039 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
989 | 1040 | ||
990 | /* Ignore forced connectors. */ |
1041 | /* Ignore forced connectors. */ |
991 | if (connector->force) |
1042 | if (connector->force) |
992 | continue; |
1043 | continue; |
993 | 1044 | ||
994 | /* Ignore HPD capable connectors and connectors where we don't |
1045 | /* Ignore HPD capable connectors and connectors where we don't |
995 | * want any hotplug detection at all for polling. */ |
1046 | * want any hotplug detection at all for polling. */ |
996 | if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD) |
1047 | if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD) |
997 | continue; |
1048 | continue; |
998 | 1049 | ||
999 | repoll = true; |
1050 | repoll = true; |
1000 | 1051 | ||
1001 | old_status = connector->status; |
1052 | old_status = connector->status; |
1002 | /* if we are connected and don't want to poll for disconnect |
1053 | /* if we are connected and don't want to poll for disconnect |
1003 | skip it */ |
1054 | skip it */ |
1004 | if (old_status == connector_status_connected && |
1055 | if (old_status == connector_status_connected && |
1005 | !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT)) |
1056 | !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT)) |
1006 | continue; |
1057 | continue; |
1007 | 1058 | ||
1008 | connector->status = connector->funcs->detect(connector, false); |
1059 | connector->status = connector->funcs->detect(connector, false); |
1009 | if (old_status != connector->status) { |
1060 | if (old_status != connector->status) { |
1010 | const char *old, *new; |
1061 | const char *old, *new; |
1011 | 1062 | ||
1012 | old = drm_get_connector_status_name(old_status); |
1063 | old = drm_get_connector_status_name(old_status); |
1013 | new = drm_get_connector_status_name(connector->status); |
1064 | new = drm_get_connector_status_name(connector->status); |
1014 | 1065 | ||
1015 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] " |
1066 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] " |
1016 | "status updated from %s to %s\n", |
1067 | "status updated from %s to %s\n", |
1017 | connector->base.id, |
1068 | connector->base.id, |
1018 | drm_get_connector_name(connector), |
1069 | drm_get_connector_name(connector), |
1019 | old, new); |
1070 | old, new); |
1020 | 1071 | ||
1021 | changed = true; |
1072 | changed = true; |
1022 | } |
1073 | } |
1023 | } |
1074 | } |
1024 | 1075 | ||
1025 | mutex_unlock(&dev->mode_config.mutex); |
1076 | mutex_unlock(&dev->mode_config.mutex); |
1026 | 1077 | ||
1027 | if (changed) |
1078 | if (changed) |
1028 | drm_kms_helper_hotplug_event(dev); |
1079 | drm_kms_helper_hotplug_event(dev); |
1029 | 1080 | ||
1030 | // if (repoll) |
1081 | // if (repoll) |
1031 | // schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); |
1082 | // schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); |
1032 | } |
1083 | } |
1033 | 1084 | ||
1034 | void drm_kms_helper_poll_disable(struct drm_device *dev) |
1085 | void drm_kms_helper_poll_disable(struct drm_device *dev) |
1035 | { |
1086 | { |
1036 | if (!dev->mode_config.poll_enabled) |
1087 | if (!dev->mode_config.poll_enabled) |
1037 | return; |
1088 | return; |
1038 | // cancel_delayed_work_sync(&dev->mode_config.output_poll_work); |
1089 | // cancel_delayed_work_sync(&dev->mode_config.output_poll_work); |
1039 | } |
1090 | } |
1040 | EXPORT_SYMBOL(drm_kms_helper_poll_disable); |
1091 | EXPORT_SYMBOL(drm_kms_helper_poll_disable); |
1041 | 1092 | ||
1042 | void drm_kms_helper_poll_enable(struct drm_device *dev) |
1093 | void drm_kms_helper_poll_enable(struct drm_device *dev) |
1043 | { |
1094 | { |
1044 | bool poll = false; |
1095 | bool poll = false; |
1045 | struct drm_connector *connector; |
1096 | struct drm_connector *connector; |
1046 | 1097 | ||
1047 | if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) |
1098 | if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) |
1048 | return; |
1099 | return; |
1049 | 1100 | ||
1050 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
1101 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
1051 | if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | |
1102 | if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | |
1052 | DRM_CONNECTOR_POLL_DISCONNECT)) |
1103 | DRM_CONNECTOR_POLL_DISCONNECT)) |
1053 | poll = true; |
1104 | poll = true; |
1054 | } |
1105 | } |
1055 | 1106 | ||
1056 | // if (poll) |
1107 | // if (poll) |
1057 | // schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); |
1108 | // schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); |
1058 | } |
1109 | } |
1059 | EXPORT_SYMBOL(drm_kms_helper_poll_enable); |
1110 | EXPORT_SYMBOL(drm_kms_helper_poll_enable); |
1060 | 1111 | ||
1061 | void drm_kms_helper_poll_init(struct drm_device *dev) |
1112 | void drm_kms_helper_poll_init(struct drm_device *dev) |
1062 | { |
1113 | { |
1063 | INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute); |
1114 | INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute); |
1064 | dev->mode_config.poll_enabled = true; |
1115 | dev->mode_config.poll_enabled = true; |
1065 | 1116 | ||
1066 | drm_kms_helper_poll_enable(dev); |
1117 | drm_kms_helper_poll_enable(dev); |
1067 | } |
1118 | } |
1068 | EXPORT_SYMBOL(drm_kms_helper_poll_init); |
1119 | EXPORT_SYMBOL(drm_kms_helper_poll_init); |
1069 | 1120 | ||
1070 | void drm_kms_helper_poll_fini(struct drm_device *dev) |
1121 | void drm_kms_helper_poll_fini(struct drm_device *dev) |
1071 | { |
1122 | { |
1072 | drm_kms_helper_poll_disable(dev); |
1123 | drm_kms_helper_poll_disable(dev); |
1073 | } |
1124 | } |
1074 | EXPORT_SYMBOL(drm_kms_helper_poll_fini); |
1125 | EXPORT_SYMBOL(drm_kms_helper_poll_fini); |
1075 | 1126 | ||
1076 | void drm_helper_hpd_irq_event(struct drm_device *dev) |
1127 | void drm_helper_hpd_irq_event(struct drm_device *dev) |
1077 | { |
1128 | { |
1078 | struct drm_connector *connector; |
1129 | struct drm_connector *connector; |
1079 | enum drm_connector_status old_status; |
1130 | enum drm_connector_status old_status; |
1080 | bool changed = false; |
1131 | bool changed = false; |
1081 | 1132 | ||
1082 | if (!dev->mode_config.poll_enabled) |
1133 | if (!dev->mode_config.poll_enabled) |
1083 | return; |
1134 | return; |
1084 | 1135 | ||
1085 | mutex_lock(&dev->mode_config.mutex); |
1136 | mutex_lock(&dev->mode_config.mutex); |
1086 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
1137 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
1087 | 1138 | ||
1088 | /* Only handle HPD capable connectors. */ |
1139 | /* Only handle HPD capable connectors. */ |
1089 | if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) |
1140 | if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) |
1090 | continue; |
1141 | continue; |
1091 | 1142 | ||
1092 | old_status = connector->status; |
1143 | old_status = connector->status; |
1093 | 1144 | ||
1094 | connector->status = connector->funcs->detect(connector, false); |
1145 | connector->status = connector->funcs->detect(connector, false); |
1095 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", |
1146 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", |
1096 | connector->base.id, |
1147 | connector->base.id, |
1097 | drm_get_connector_name(connector), |
1148 | drm_get_connector_name(connector), |
1098 | drm_get_connector_status_name(old_status), |
1149 | drm_get_connector_status_name(old_status), |
1099 | drm_get_connector_status_name(connector->status)); |
1150 | drm_get_connector_status_name(connector->status)); |
1100 | if (old_status != connector->status) |
1151 | if (old_status != connector->status) |
1101 | changed = true; |
1152 | changed = true; |
1102 | } |
1153 | } |
1103 | 1154 | ||
1104 | mutex_unlock(&dev->mode_config.mutex); |
1155 | mutex_unlock(&dev->mode_config.mutex); |
1105 | 1156 | ||
1106 | if (changed) |
1157 | if (changed) |
1107 | drm_kms_helper_hotplug_event(dev); |
1158 | drm_kms_helper_hotplug_event(dev); |
1108 | } |
1159 | } |
1109 | EXPORT_SYMBOL(drm_helper_hpd_irq_event);>>>>>>>=><=> |
1160 | EXPORT_SYMBOL(drm_helper_hpd_irq_event);>>>>>>>=><=> |