diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 88 |
1 files changed, 83 insertions, 5 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index fe8697447f32..1fe4e1d344fd 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -32,6 +32,7 @@ | |||
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 | 36 | ||
36 | static void drm_mode_validate_flag(struct drm_connector *connector, | 37 | static void drm_mode_validate_flag(struct drm_connector *connector, |
37 | int flags) | 38 | int flags) |
@@ -90,7 +91,15 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, | |||
90 | list_for_each_entry_safe(mode, t, &connector->modes, head) | 91 | list_for_each_entry_safe(mode, t, &connector->modes, head) |
91 | mode->status = MODE_UNVERIFIED; | 92 | mode->status = MODE_UNVERIFIED; |
92 | 93 | ||
93 | connector->status = connector->funcs->detect(connector); | 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 | ||
102 | connector->status = connector->funcs->detect(connector); | ||
94 | 103 | ||
95 | if (connector->status == connector_status_disconnected) { | 104 | if (connector->status == connector_status_disconnected) { |
96 | DRM_DEBUG_KMS("%s is disconnected\n", | 105 | DRM_DEBUG_KMS("%s is disconnected\n", |
@@ -267,6 +276,65 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *con | |||
267 | return NULL; | 276 | return NULL; |
268 | } | 277 | } |
269 | 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 | list_add(&mode->head, &connector->modes); | ||
335 | return mode; | ||
336 | } | ||
337 | |||
270 | static bool drm_connector_enabled(struct drm_connector *connector, bool strict) | 338 | static bool drm_connector_enabled(struct drm_connector *connector, bool strict) |
271 | { | 339 | { |
272 | bool enable; | 340 | bool enable; |
@@ -317,10 +385,16 @@ static bool drm_target_preferred(struct drm_device *dev, | |||
317 | continue; | 385 | continue; |
318 | } | 386 | } |
319 | 387 | ||
320 | DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", | 388 | DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", |
321 | connector->base.id); | 389 | connector->base.id); |
322 | 390 | ||
323 | modes[i] = drm_has_preferred_mode(connector, width, height); | 391 | /* got for command line mode first */ |
392 | modes[i] = drm_pick_cmdline_mode(connector, width, height); | ||
393 | if (!modes[i]) { | ||
394 | DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", | ||
395 | connector->base.id); | ||
396 | modes[i] = drm_has_preferred_mode(connector, width, height); | ||
397 | } | ||
324 | /* No preferred modes, pick one off the list */ | 398 | /* No preferred modes, pick one off the list */ |
325 | if (!modes[i] && !list_empty(&connector->modes)) { | 399 | if (!modes[i] && !list_empty(&connector->modes)) { |
326 | list_for_each_entry(modes[i], &connector->modes, head) | 400 | list_for_each_entry(modes[i], &connector->modes, head) |
@@ -369,6 +443,8 @@ static int drm_pick_crtcs(struct drm_device *dev, | |||
369 | my_score = 1; | 443 | my_score = 1; |
370 | if (connector->status == connector_status_connected) | 444 | if (connector->status == connector_status_connected) |
371 | my_score++; | 445 | my_score++; |
446 | if (drm_has_cmdline_mode(connector)) | ||
447 | my_score++; | ||
372 | if (drm_has_preferred_mode(connector, width, height)) | 448 | if (drm_has_preferred_mode(connector, width, height)) |
373 | my_score++; | 449 | my_score++; |
374 | 450 | ||
@@ -943,6 +1019,8 @@ bool drm_helper_initial_config(struct drm_device *dev) | |||
943 | { | 1019 | { |
944 | int count = 0; | 1020 | int count = 0; |
945 | 1021 | ||
1022 | drm_fb_helper_parse_command_line(dev); | ||
1023 | |||
946 | count = drm_helper_probe_connector_modes(dev, | 1024 | count = drm_helper_probe_connector_modes(dev, |
947 | dev->mode_config.max_width, | 1025 | dev->mode_config.max_width, |
948 | dev->mode_config.max_height); | 1026 | dev->mode_config.max_height); |
@@ -950,7 +1028,7 @@ bool drm_helper_initial_config(struct drm_device *dev) | |||
950 | /* | 1028 | /* |
951 | * we shouldn't end up with no modes here. | 1029 | * we shouldn't end up with no modes here. |
952 | */ | 1030 | */ |
953 | WARN(!count, "Connected connector with 0 modes\n"); | 1031 | WARN(!count, "No connectors reported connected with modes\n"); |
954 | 1032 | ||
955 | drm_setup_crtcs(dev); | 1033 | drm_setup_crtcs(dev); |
956 | 1034 | ||