diff options
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 127 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 2 | ||||
-rw-r--r-- | include/drm/drm_crtc_helper.h | 2 |
3 files changed, 95 insertions, 36 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index d8a982b71296..e490e69db21e 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -36,7 +36,7 @@ | |||
36 | /* | 36 | /* |
37 | * Detailed mode info for 800x600@60Hz | 37 | * Detailed mode info for 800x600@60Hz |
38 | */ | 38 | */ |
39 | static struct drm_display_mode std_mode[] = { | 39 | static struct drm_display_mode std_modes[] = { |
40 | { DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840, | 40 | { DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840, |
41 | 968, 1056, 0, 600, 601, 605, 628, 0, | 41 | 968, 1056, 0, 600, 601, 605, 628, 0, |
42 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 42 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
@@ -60,15 +60,18 @@ static struct drm_display_mode std_mode[] = { | |||
60 | * changes have occurred. | 60 | * changes have occurred. |
61 | * | 61 | * |
62 | * FIXME: take into account monitor limits | 62 | * FIXME: take into account monitor limits |
63 | * | ||
64 | * RETURNS: | ||
65 | * Number of modes found on @connector. | ||
63 | */ | 66 | */ |
64 | void drm_helper_probe_single_connector_modes(struct drm_connector *connector, | 67 | int drm_helper_probe_single_connector_modes(struct drm_connector *connector, |
65 | uint32_t maxX, uint32_t maxY) | 68 | uint32_t maxX, uint32_t maxY) |
66 | { | 69 | { |
67 | struct drm_device *dev = connector->dev; | 70 | struct drm_device *dev = connector->dev; |
68 | struct drm_display_mode *mode, *t; | 71 | struct drm_display_mode *mode, *t; |
69 | struct drm_connector_helper_funcs *connector_funcs = | 72 | struct drm_connector_helper_funcs *connector_funcs = |
70 | connector->helper_private; | 73 | connector->helper_private; |
71 | int ret; | 74 | int count = 0; |
72 | 75 | ||
73 | DRM_DEBUG("%s\n", drm_get_connector_name(connector)); | 76 | DRM_DEBUG("%s\n", drm_get_connector_name(connector)); |
74 | /* set all modes to the unverified state */ | 77 | /* set all modes to the unverified state */ |
@@ -81,14 +84,14 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector, | |||
81 | DRM_DEBUG("%s is disconnected\n", | 84 | DRM_DEBUG("%s is disconnected\n", |
82 | drm_get_connector_name(connector)); | 85 | drm_get_connector_name(connector)); |
83 | /* TODO set EDID to NULL */ | 86 | /* TODO set EDID to NULL */ |
84 | return; | 87 | return 0; |
85 | } | 88 | } |
86 | 89 | ||
87 | ret = (*connector_funcs->get_modes)(connector); | 90 | count = (*connector_funcs->get_modes)(connector); |
91 | if (!count) | ||
92 | return 0; | ||
88 | 93 | ||
89 | if (ret) { | 94 | drm_mode_connector_list_update(connector); |
90 | drm_mode_connector_list_update(connector); | ||
91 | } | ||
92 | 95 | ||
93 | if (maxX && maxY) | 96 | if (maxX && maxY) |
94 | drm_mode_validate_size(dev, &connector->modes, maxX, | 97 | drm_mode_validate_size(dev, &connector->modes, maxX, |
@@ -102,25 +105,8 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector, | |||
102 | 105 | ||
103 | drm_mode_prune_invalid(dev, &connector->modes, true); | 106 | drm_mode_prune_invalid(dev, &connector->modes, true); |
104 | 107 | ||
105 | if (list_empty(&connector->modes)) { | 108 | if (list_empty(&connector->modes)) |
106 | struct drm_display_mode *stdmode; | 109 | return 0; |
107 | |||
108 | DRM_DEBUG("No valid modes on %s\n", | ||
109 | drm_get_connector_name(connector)); | ||
110 | |||
111 | /* Should we do this here ??? | ||
112 | * When no valid EDID modes are available we end up | ||
113 | * here and bailed in the past, now we add a standard | ||
114 | * 640x480@60Hz mode and carry on. | ||
115 | */ | ||
116 | stdmode = drm_mode_duplicate(dev, &std_mode[0]); | ||
117 | drm_mode_probed_add(connector, stdmode); | ||
118 | drm_mode_list_concat(&connector->probed_modes, | ||
119 | &connector->modes); | ||
120 | |||
121 | DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", | ||
122 | drm_get_connector_name(connector)); | ||
123 | } | ||
124 | 110 | ||
125 | drm_mode_sort(&connector->modes); | 111 | drm_mode_sort(&connector->modes); |
126 | 112 | ||
@@ -131,20 +117,58 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector, | |||
131 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); | 117 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
132 | drm_mode_debug_printmodeline(mode); | 118 | drm_mode_debug_printmodeline(mode); |
133 | } | 119 | } |
120 | |||
121 | return count; | ||
134 | } | 122 | } |
135 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); | 123 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); |
136 | 124 | ||
137 | void drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX, | 125 | int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX, |
138 | uint32_t maxY) | 126 | uint32_t maxY) |
139 | { | 127 | { |
140 | struct drm_connector *connector; | 128 | struct drm_connector *connector; |
129 | int count = 0; | ||
141 | 130 | ||
142 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 131 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
143 | drm_helper_probe_single_connector_modes(connector, maxX, maxY); | 132 | count += drm_helper_probe_single_connector_modes(connector, |
133 | maxX, maxY); | ||
144 | } | 134 | } |
135 | |||
136 | return count; | ||
145 | } | 137 | } |
146 | EXPORT_SYMBOL(drm_helper_probe_connector_modes); | 138 | EXPORT_SYMBOL(drm_helper_probe_connector_modes); |
147 | 139 | ||
140 | static void drm_helper_add_std_modes(struct drm_device *dev, | ||
141 | struct drm_connector *connector) | ||
142 | { | ||
143 | struct drm_display_mode *mode, *t; | ||
144 | int i; | ||
145 | |||
146 | for (i = 0; i < ARRAY_SIZE(std_modes); i++) { | ||
147 | struct drm_display_mode *stdmode; | ||
148 | |||
149 | /* | ||
150 | * When no valid EDID modes are available we end up | ||
151 | * here and bailed in the past, now we add some standard | ||
152 | * modes and move on. | ||
153 | */ | ||
154 | stdmode = drm_mode_duplicate(dev, &std_modes[i]); | ||
155 | drm_mode_probed_add(connector, stdmode); | ||
156 | drm_mode_list_concat(&connector->probed_modes, | ||
157 | &connector->modes); | ||
158 | |||
159 | DRM_DEBUG("Adding mode %s to %s\n", stdmode->name, | ||
160 | drm_get_connector_name(connector)); | ||
161 | } | ||
162 | drm_mode_sort(&connector->modes); | ||
163 | |||
164 | DRM_DEBUG("Added std modes on %s\n", drm_get_connector_name(connector)); | ||
165 | list_for_each_entry_safe(mode, t, &connector->modes, head) { | ||
166 | mode->vrefresh = drm_mode_vrefresh(mode); | ||
167 | |||
168 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); | ||
169 | drm_mode_debug_printmodeline(mode); | ||
170 | } | ||
171 | } | ||
148 | 172 | ||
149 | /** | 173 | /** |
150 | * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config | 174 | * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config |
@@ -237,6 +261,8 @@ static void drm_enable_connectors(struct drm_device *dev, bool *enabled) | |||
237 | 261 | ||
238 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 262 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
239 | enabled[i] = drm_connector_enabled(connector, true); | 263 | enabled[i] = drm_connector_enabled(connector, true); |
264 | DRM_DEBUG("connector %d enabled? %s\n", connector->base.id, | ||
265 | enabled[i] ? "yes" : "no"); | ||
240 | any_enabled |= enabled[i]; | 266 | any_enabled |= enabled[i]; |
241 | i++; | 267 | i++; |
242 | } | 268 | } |
@@ -265,11 +291,17 @@ static bool drm_target_preferred(struct drm_device *dev, | |||
265 | continue; | 291 | continue; |
266 | } | 292 | } |
267 | 293 | ||
294 | DRM_DEBUG("looking for preferred mode on connector %d\n", | ||
295 | connector->base.id); | ||
296 | |||
268 | modes[i] = drm_has_preferred_mode(connector, width, height); | 297 | modes[i] = drm_has_preferred_mode(connector, width, height); |
269 | if (!modes[i]) { | 298 | /* No preferred modes, pick one off the list */ |
299 | if (!modes[i] && !list_empty(&connector->modes)) { | ||
270 | list_for_each_entry(modes[i], &connector->modes, head) | 300 | list_for_each_entry(modes[i], &connector->modes, head) |
271 | break; | 301 | break; |
272 | } | 302 | } |
303 | DRM_DEBUG("found mode %s\n", modes[i] ? modes[i]->name : | ||
304 | "none"); | ||
273 | i++; | 305 | i++; |
274 | } | 306 | } |
275 | return true; | 307 | return true; |
@@ -369,6 +401,8 @@ static void drm_setup_crtcs(struct drm_device *dev) | |||
369 | int width, height; | 401 | int width, height; |
370 | int i, ret; | 402 | int i, ret; |
371 | 403 | ||
404 | DRM_DEBUG("\n"); | ||
405 | |||
372 | width = dev->mode_config.max_width; | 406 | width = dev->mode_config.max_width; |
373 | height = dev->mode_config.max_height; | 407 | height = dev->mode_config.max_height; |
374 | 408 | ||
@@ -390,6 +424,8 @@ static void drm_setup_crtcs(struct drm_device *dev) | |||
390 | if (!ret) | 424 | if (!ret) |
391 | DRM_ERROR("Unable to find initial modes\n"); | 425 | DRM_ERROR("Unable to find initial modes\n"); |
392 | 426 | ||
427 | DRM_DEBUG("picking CRTCs for %dx%d config\n", width, height); | ||
428 | |||
393 | drm_pick_crtcs(dev, crtcs, modes, 0, width, height); | 429 | drm_pick_crtcs(dev, crtcs, modes, 0, width, height); |
394 | 430 | ||
395 | i = 0; | 431 | i = 0; |
@@ -403,6 +439,8 @@ static void drm_setup_crtcs(struct drm_device *dev) | |||
403 | } | 439 | } |
404 | 440 | ||
405 | if (mode && crtc) { | 441 | if (mode && crtc) { |
442 | DRM_DEBUG("desired mode %s set on crtc %d\n", | ||
443 | mode->name, crtc->base.id); | ||
406 | crtc->desired_mode = mode; | 444 | crtc->desired_mode = mode; |
407 | connector->encoder->crtc = crtc; | 445 | connector->encoder->crtc = crtc; |
408 | } else | 446 | } else |
@@ -764,10 +802,31 @@ bool drm_helper_plugged_event(struct drm_device *dev) | |||
764 | */ | 802 | */ |
765 | bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) | 803 | bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) |
766 | { | 804 | { |
767 | int ret = false; | 805 | struct drm_connector *connector; |
806 | int count = 0; | ||
768 | 807 | ||
769 | drm_helper_plugged_event(dev); | 808 | count = drm_helper_probe_connector_modes(dev, |
770 | return ret; | 809 | dev->mode_config.max_width, |
810 | dev->mode_config.max_height); | ||
811 | |||
812 | /* | ||
813 | * None of the available connectors had any modes, so add some | ||
814 | * and try to light them up anyway | ||
815 | */ | ||
816 | if (!count) { | ||
817 | DRM_ERROR("connectors have no modes, using standard modes\n"); | ||
818 | list_for_each_entry(connector, | ||
819 | &dev->mode_config.connector_list, | ||
820 | head) | ||
821 | drm_helper_add_std_modes(dev, connector); | ||
822 | } | ||
823 | |||
824 | drm_setup_crtcs(dev); | ||
825 | |||
826 | /* alert the driver fb layer */ | ||
827 | dev->mode_config.funcs->fb_changed(dev); | ||
828 | |||
829 | return 0; | ||
771 | } | 830 | } |
772 | EXPORT_SYMBOL(drm_helper_initial_config); | 831 | EXPORT_SYMBOL(drm_helper_initial_config); |
773 | 832 | ||
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 0acb07f31fa4..47809ac94bc3 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -395,7 +395,7 @@ struct drm_connector_funcs { | |||
395 | void (*save)(struct drm_connector *connector); | 395 | void (*save)(struct drm_connector *connector); |
396 | void (*restore)(struct drm_connector *connector); | 396 | void (*restore)(struct drm_connector *connector); |
397 | enum drm_connector_status (*detect)(struct drm_connector *connector); | 397 | enum drm_connector_status (*detect)(struct drm_connector *connector); |
398 | void (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); | 398 | int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); |
399 | int (*set_property)(struct drm_connector *connector, struct drm_property *property, | 399 | int (*set_property)(struct drm_connector *connector, struct drm_property *property, |
400 | uint64_t val); | 400 | uint64_t val); |
401 | void (*destroy)(struct drm_connector *connector); | 401 | void (*destroy)(struct drm_connector *connector); |
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 4bc04cf460a7..0c6f0e11b41b 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h | |||
@@ -88,7 +88,7 @@ struct drm_connector_helper_funcs { | |||
88 | struct drm_encoder *(*best_encoder)(struct drm_connector *connector); | 88 | struct drm_encoder *(*best_encoder)(struct drm_connector *connector); |
89 | }; | 89 | }; |
90 | 90 | ||
91 | extern void drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); | 91 | extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); |
92 | extern void drm_helper_disable_unused_functions(struct drm_device *dev); | 92 | extern void drm_helper_disable_unused_functions(struct drm_device *dev); |
93 | extern int drm_helper_hotplug_stage_two(struct drm_device *dev); | 93 | extern int drm_helper_hotplug_stage_two(struct drm_device *dev); |
94 | extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); | 94 | extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); |