diff options
author | Dave Airlie <airlied@redhat.com> | 2010-05-07 01:02:30 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-05-18 03:40:22 -0400 |
commit | 1d42bbc8f7f9ce4d852692ef7aa336b133b0830a (patch) | |
tree | a0ea2d17508104ab681c829f0552e7f13512c8e2 | |
parent | eb1f8e4f3be898df808e2dfc131099f5831d491d (diff) |
drm/fbdev: fix cloning on fbcon
Simple cloning rules compared to server:
(a) single crtc
(b) > 1 connector active
(c) check command line mode
(d) try and find 1024x768 DMT mode if no command line.
(e) fail to clone
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 90 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 2 |
3 files changed, 96 insertions, 13 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 0acb83a63727..dfd4f3677f3b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -658,8 +658,8 @@ static struct drm_display_mode drm_dmt_modes[] = { | |||
658 | static const int drm_num_dmt_modes = | 658 | static const int drm_num_dmt_modes = |
659 | sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); | 659 | sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); |
660 | 660 | ||
661 | static struct drm_display_mode *drm_find_dmt(struct drm_device *dev, | 661 | struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, |
662 | int hsize, int vsize, int fresh) | 662 | int hsize, int vsize, int fresh) |
663 | { | 663 | { |
664 | int i; | 664 | int i; |
665 | struct drm_display_mode *ptr, *mode; | 665 | struct drm_display_mode *ptr, *mode; |
@@ -677,6 +677,7 @@ static struct drm_display_mode *drm_find_dmt(struct drm_device *dev, | |||
677 | } | 677 | } |
678 | return mode; | 678 | return mode; |
679 | } | 679 | } |
680 | EXPORT_SYMBOL(drm_mode_find_dmt); | ||
680 | 681 | ||
681 | typedef void detailed_cb(struct detailed_timing *timing, void *closure); | 682 | typedef void detailed_cb(struct detailed_timing *timing, void *closure); |
682 | 683 | ||
@@ -866,7 +867,7 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid, | |||
866 | } | 867 | } |
867 | 868 | ||
868 | /* check whether it can be found in default mode table */ | 869 | /* check whether it can be found in default mode table */ |
869 | mode = drm_find_dmt(dev, hsize, vsize, vrefresh_rate); | 870 | mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate); |
870 | if (mode) | 871 | if (mode) |
871 | return mode; | 872 | return mode; |
872 | 873 | ||
@@ -1386,11 +1387,11 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing) | |||
1386 | if (m >= num_est3_modes) | 1387 | if (m >= num_est3_modes) |
1387 | break; | 1388 | break; |
1388 | if (est[i] & (1 << j)) { | 1389 | if (est[i] & (1 << j)) { |
1389 | mode = drm_find_dmt(connector->dev, | 1390 | mode = drm_mode_find_dmt(connector->dev, |
1390 | est3_modes[m].w, | 1391 | est3_modes[m].w, |
1391 | est3_modes[m].h, | 1392 | est3_modes[m].h, |
1392 | est3_modes[m].r | 1393 | est3_modes[m].r |
1393 | /*, est3_modes[m].rb */); | 1394 | /*, est3_modes[m].rb */); |
1394 | if (mode) { | 1395 | if (mode) { |
1395 | drm_mode_probed_add(connector, mode); | 1396 | drm_mode_probed_add(connector, mode); |
1396 | modes++; | 1397 | modes++; |
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index f7b8fca4bbbc..b3779d243aef 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -1070,6 +1070,79 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper, | |||
1070 | } | 1070 | } |
1071 | } | 1071 | } |
1072 | 1072 | ||
1073 | static bool drm_target_cloned(struct drm_fb_helper *fb_helper, | ||
1074 | struct drm_display_mode **modes, | ||
1075 | bool *enabled, int width, int height) | ||
1076 | { | ||
1077 | int count, i, j; | ||
1078 | bool can_clone = false; | ||
1079 | struct drm_fb_helper_connector *fb_helper_conn; | ||
1080 | struct drm_display_mode *dmt_mode, *mode; | ||
1081 | |||
1082 | /* only contemplate cloning in the single crtc case */ | ||
1083 | if (fb_helper->crtc_count > 1) | ||
1084 | return false; | ||
1085 | |||
1086 | count = 0; | ||
1087 | for (i = 0; i < fb_helper->connector_count; i++) { | ||
1088 | if (enabled[i]) | ||
1089 | count++; | ||
1090 | } | ||
1091 | |||
1092 | /* only contemplate cloning if more than one connector is enabled */ | ||
1093 | if (count <= 1) | ||
1094 | return false; | ||
1095 | |||
1096 | /* check the command line or if nothing common pick 1024x768 */ | ||
1097 | can_clone = true; | ||
1098 | for (i = 0; i < fb_helper->connector_count; i++) { | ||
1099 | if (!enabled[i]) | ||
1100 | continue; | ||
1101 | fb_helper_conn = fb_helper->connector_info[i]; | ||
1102 | modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); | ||
1103 | if (!modes[i]) { | ||
1104 | can_clone = false; | ||
1105 | break; | ||
1106 | } | ||
1107 | for (j = 0; j < i; j++) { | ||
1108 | if (!enabled[j]) | ||
1109 | continue; | ||
1110 | if (!drm_mode_equal(modes[j], modes[i])) | ||
1111 | can_clone = false; | ||
1112 | } | ||
1113 | } | ||
1114 | |||
1115 | if (can_clone) { | ||
1116 | DRM_DEBUG_KMS("can clone using command line\n"); | ||
1117 | return true; | ||
1118 | } | ||
1119 | |||
1120 | /* try and find a 1024x768 mode on each connector */ | ||
1121 | can_clone = true; | ||
1122 | dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60); | ||
1123 | |||
1124 | for (i = 0; i < fb_helper->connector_count; i++) { | ||
1125 | |||
1126 | if (!enabled[i]) | ||
1127 | continue; | ||
1128 | |||
1129 | fb_helper_conn = fb_helper->connector_info[i]; | ||
1130 | list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) { | ||
1131 | if (drm_mode_equal(mode, dmt_mode)) | ||
1132 | modes[i] = mode; | ||
1133 | } | ||
1134 | if (!modes[i]) | ||
1135 | can_clone = false; | ||
1136 | } | ||
1137 | |||
1138 | if (can_clone) { | ||
1139 | DRM_DEBUG_KMS("can clone using 1024x768\n"); | ||
1140 | return true; | ||
1141 | } | ||
1142 | DRM_INFO("kms: can't enable cloning when we probably wanted to.\n"); | ||
1143 | return false; | ||
1144 | } | ||
1145 | |||
1073 | static bool drm_target_preferred(struct drm_fb_helper *fb_helper, | 1146 | static bool drm_target_preferred(struct drm_fb_helper *fb_helper, |
1074 | struct drm_display_mode **modes, | 1147 | struct drm_display_mode **modes, |
1075 | bool *enabled, int width, int height) | 1148 | bool *enabled, int width, int height) |
@@ -1163,8 +1236,12 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, | |||
1163 | break; | 1236 | break; |
1164 | 1237 | ||
1165 | if (o < n) { | 1238 | if (o < n) { |
1166 | /* ignore cloning for now */ | 1239 | /* ignore cloning unless only a single crtc */ |
1167 | continue; | 1240 | if (fb_helper->crtc_count > 1) |
1241 | continue; | ||
1242 | |||
1243 | if (!drm_mode_equal(modes[o], modes[n])) | ||
1244 | continue; | ||
1168 | } | 1245 | } |
1169 | 1246 | ||
1170 | crtcs[n] = crtc; | 1247 | crtcs[n] = crtc; |
@@ -1214,9 +1291,12 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
1214 | 1291 | ||
1215 | drm_enable_connectors(fb_helper, enabled); | 1292 | drm_enable_connectors(fb_helper, enabled); |
1216 | 1293 | ||
1217 | ret = drm_target_preferred(fb_helper, modes, enabled, width, height); | 1294 | ret = drm_target_cloned(fb_helper, modes, enabled, width, height); |
1218 | if (!ret) | 1295 | if (!ret) { |
1219 | DRM_ERROR("Unable to find initial modes\n"); | 1296 | ret = drm_target_preferred(fb_helper, modes, enabled, width, height); |
1297 | if (!ret) | ||
1298 | DRM_ERROR("Unable to find initial modes\n"); | ||
1299 | } | ||
1220 | 1300 | ||
1221 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); | 1301 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); |
1222 | 1302 | ||
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 2e4bf92faa85..93a1a31b9c2d 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -804,4 +804,6 @@ extern int drm_add_modes_noedid(struct drm_connector *connector, | |||
804 | int hdisplay, int vdisplay); | 804 | int hdisplay, int vdisplay); |
805 | 805 | ||
806 | extern bool drm_edid_is_valid(struct edid *edid); | 806 | extern bool drm_edid_is_valid(struct edid *edid); |
807 | struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, | ||
808 | int hsize, int vsize, int fresh); | ||
807 | #endif /* __DRM_CRTC_H__ */ | 809 | #endif /* __DRM_CRTC_H__ */ |