aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-05-07 01:02:30 -0400
committerDave Airlie <airlied@redhat.com>2010-05-18 03:40:22 -0400
commit1d42bbc8f7f9ce4d852692ef7aa336b133b0830a (patch)
treea0ea2d17508104ab681c829f0552e7f13512c8e2
parenteb1f8e4f3be898df808e2dfc131099f5831d491d (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.c17
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c90
-rw-r--r--include/drm/drm_crtc.h2
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[] = {
658static const int drm_num_dmt_modes = 658static 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
661static struct drm_display_mode *drm_find_dmt(struct drm_device *dev, 661struct 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}
680EXPORT_SYMBOL(drm_mode_find_dmt);
680 681
681typedef void detailed_cb(struct detailed_timing *timing, void *closure); 682typedef 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
1073static 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
1073static bool drm_target_preferred(struct drm_fb_helper *fb_helper, 1146static 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
806extern bool drm_edid_is_valid(struct edid *edid); 806extern bool drm_edid_is_valid(struct edid *edid);
807struct 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__ */