Rev 1268 | Rev 1404 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1123 | serge | 1 | /* |
2 | * Copyright (c) 2006-2008 Intel Corporation |
||
3 | * Copyright (c) 2007 Dave Airlie |
||
4 | * |
||
5 | * DRM core CRTC related functions |
||
6 | * |
||
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 |
||
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 |
||
11 | * that the name of the copyright holders not be used in advertising or |
||
12 | * publicity pertaining to distribution of the software without specific, |
||
13 | * written prior permission. The copyright holders make no representations |
||
14 | * about the suitability of this software for any purpose. It is provided "as |
||
15 | * is" without express or implied warranty. |
||
16 | * |
||
17 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
||
18 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
||
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, |
||
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 |
||
23 | * OF THIS SOFTWARE. |
||
24 | * |
||
25 | * Authors: |
||
26 | * Keith Packard |
||
27 | * Eric Anholt |
||
28 | * Dave Airlie |
||
29 | * Jesse Barnes |
||
30 | */ |
||
31 | |||
32 | #include "drmP.h" |
||
33 | #include "drm_crtc.h" |
||
34 | #include "drm_crtc_helper.h" |
||
1221 | serge | 35 | #include "drm_fb_helper.h" |
1123 | serge | 36 | |
37 | static void drm_mode_validate_flag(struct drm_connector *connector, |
||
38 | int flags) |
||
39 | { |
||
40 | struct drm_display_mode *mode, *t; |
||
41 | |||
42 | if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE)) |
||
43 | return; |
||
44 | |||
45 | list_for_each_entry_safe(mode, t, &connector->modes, head) { |
||
46 | if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && |
||
47 | !(flags & DRM_MODE_FLAG_INTERLACE)) |
||
48 | mode->status = MODE_NO_INTERLACE; |
||
49 | if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && |
||
50 | !(flags & DRM_MODE_FLAG_DBLSCAN)) |
||
51 | mode->status = MODE_NO_DBLESCAN; |
||
52 | } |
||
53 | |||
54 | return; |
||
55 | } |
||
56 | |||
57 | /** |
||
58 | * drm_helper_probe_connector_modes - get complete set of display modes |
||
59 | * @dev: DRM device |
||
60 | * @maxX: max width for modes |
||
61 | * @maxY: max height for modes |
||
62 | * |
||
63 | * LOCKING: |
||
64 | * Caller must hold mode config lock. |
||
65 | * |
||
66 | * 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 |
||
68 | * list, then culled (based on validity and the @maxX, @maxY parameters) and |
||
69 | * put into the normal modes list. |
||
70 | * |
||
71 | * Intended to be used either at bootup time or when major configuration |
||
72 | * changes have occurred. |
||
73 | * |
||
74 | * FIXME: take into account monitor limits |
||
75 | * |
||
76 | * RETURNS: |
||
77 | * Number of modes found on @connector. |
||
78 | */ |
||
79 | int drm_helper_probe_single_connector_modes(struct drm_connector *connector, |
||
80 | uint32_t maxX, uint32_t maxY) |
||
81 | { |
||
82 | struct drm_device *dev = connector->dev; |
||
83 | struct drm_display_mode *mode, *t; |
||
84 | struct drm_connector_helper_funcs *connector_funcs = |
||
85 | connector->helper_private; |
||
86 | int count = 0; |
||
87 | int mode_flags = 0; |
||
88 | |||
1179 | serge | 89 | DRM_DEBUG_KMS("%s\n", drm_get_connector_name(connector)); |
1123 | serge | 90 | /* set all modes to the unverified state */ |
91 | list_for_each_entry_safe(mode, t, &connector->modes, head) |
||
92 | mode->status = MODE_UNVERIFIED; |
||
93 | |||
1221 | serge | 94 | if (connector->force) { |
95 | if (connector->force == DRM_FORCE_ON) |
||
96 | connector->status = connector_status_connected; |
||
97 | else |
||
98 | connector->status = connector_status_disconnected; |
||
99 | if (connector->funcs->force) |
||
100 | connector->funcs->force(connector); |
||
101 | } else |
||
1123 | serge | 102 | connector->status = connector->funcs->detect(connector); |
103 | |||
104 | if (connector->status == connector_status_disconnected) { |
||
1179 | serge | 105 | DRM_DEBUG_KMS("%s is disconnected\n", |
1123 | serge | 106 | drm_get_connector_name(connector)); |
1179 | serge | 107 | goto prune; |
1123 | serge | 108 | } |
109 | |||
110 | count = (*connector_funcs->get_modes)(connector); |
||
1179 | serge | 111 | if (!count) { |
1321 | serge | 112 | count = drm_add_modes_noedid(connector, 1024, 768); |
1123 | serge | 113 | if (!count) |
114 | return 0; |
||
1179 | serge | 115 | } |
1123 | serge | 116 | |
117 | drm_mode_connector_list_update(connector); |
||
118 | |||
119 | if (maxX && maxY) |
||
120 | drm_mode_validate_size(dev, &connector->modes, maxX, |
||
121 | maxY, 0); |
||
122 | |||
123 | if (connector->interlace_allowed) |
||
124 | mode_flags |= DRM_MODE_FLAG_INTERLACE; |
||
125 | if (connector->doublescan_allowed) |
||
126 | mode_flags |= DRM_MODE_FLAG_DBLSCAN; |
||
127 | drm_mode_validate_flag(connector, mode_flags); |
||
128 | |||
129 | list_for_each_entry_safe(mode, t, &connector->modes, head) { |
||
130 | if (mode->status == MODE_OK) |
||
131 | mode->status = connector_funcs->mode_valid(connector, |
||
132 | mode); |
||
133 | } |
||
134 | |||
1179 | serge | 135 | prune: |
1123 | serge | 136 | drm_mode_prune_invalid(dev, &connector->modes, true); |
137 | |||
138 | if (list_empty(&connector->modes)) |
||
139 | return 0; |
||
140 | |||
141 | drm_mode_sort(&connector->modes); |
||
142 | |||
1179 | serge | 143 | DRM_DEBUG_KMS("Probed modes for %s\n", |
144 | drm_get_connector_name(connector)); |
||
1123 | serge | 145 | list_for_each_entry_safe(mode, t, &connector->modes, head) { |
146 | mode->vrefresh = drm_mode_vrefresh(mode); |
||
147 | |||
148 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
||
149 | drm_mode_debug_printmodeline(mode); |
||
150 | } |
||
151 | |||
152 | return count; |
||
153 | } |
||
154 | 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 | |||
171 | /** |
||
172 | * drm_helper_encoder_in_use - check if a given encoder is in use |
||
173 | * @encoder: encoder to check |
||
174 | * |
||
175 | * LOCKING: |
||
176 | * Caller must hold mode config lock. |
||
177 | * |
||
178 | * Walk @encoders's DRM device's mode_config and see if it's in use. |
||
179 | * |
||
180 | * RETURNS: |
||
181 | * True if @encoder is part of the mode_config, false otherwise. |
||
182 | */ |
||
183 | bool drm_helper_encoder_in_use(struct drm_encoder *encoder) |
||
184 | { |
||
185 | struct drm_connector *connector; |
||
186 | struct drm_device *dev = encoder->dev; |
||
187 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
||
188 | if (connector->encoder == encoder) |
||
189 | return true; |
||
190 | return false; |
||
191 | } |
||
192 | EXPORT_SYMBOL(drm_helper_encoder_in_use); |
||
193 | |||
194 | /** |
||
195 | * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config |
||
196 | * @crtc: CRTC to check |
||
197 | * |
||
198 | * LOCKING: |
||
199 | * Caller must hold mode config lock. |
||
200 | * |
||
201 | * Walk @crtc's DRM device's mode_config and see if it's in use. |
||
202 | * |
||
203 | * RETURNS: |
||
204 | * True if @crtc is part of the mode_config, false otherwise. |
||
205 | */ |
||
206 | bool drm_helper_crtc_in_use(struct drm_crtc *crtc) |
||
207 | { |
||
208 | struct drm_encoder *encoder; |
||
209 | struct drm_device *dev = crtc->dev; |
||
210 | /* FIXME: Locking around list access? */ |
||
211 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) |
||
212 | if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder)) |
||
213 | return true; |
||
214 | return false; |
||
215 | } |
||
216 | EXPORT_SYMBOL(drm_helper_crtc_in_use); |
||
217 | |||
218 | /** |
||
219 | * drm_disable_unused_functions - disable unused objects |
||
220 | * @dev: DRM device |
||
221 | * |
||
222 | * LOCKING: |
||
223 | * Caller must hold mode config lock. |
||
224 | * |
||
225 | * 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 | */ |
||
228 | void drm_helper_disable_unused_functions(struct drm_device *dev) |
||
229 | { |
||
230 | struct drm_encoder *encoder; |
||
1179 | serge | 231 | struct drm_connector *connector; |
1123 | serge | 232 | struct drm_encoder_helper_funcs *encoder_funcs; |
233 | struct drm_crtc *crtc; |
||
234 | |||
1179 | serge | 235 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
236 | if (!connector->encoder) |
||
237 | continue; |
||
238 | if (connector->status == connector_status_disconnected) |
||
239 | connector->encoder = NULL; |
||
240 | } |
||
241 | |||
1123 | serge | 242 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
243 | encoder_funcs = encoder->helper_private; |
||
1179 | serge | 244 | if (!drm_helper_encoder_in_use(encoder)) { |
245 | if (encoder_funcs->disable) |
||
246 | (*encoder_funcs->disable)(encoder); |
||
247 | else |
||