mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									eb1f8e4f3b
								
							
						
					
					
						commit
						1d42bbc8f7
					
				
					 3 changed files with 96 additions and 13 deletions
				
			
		| 
						 | 
				
			
			@ -658,7 +658,7 @@ static struct drm_display_mode drm_dmt_modes[] = {
 | 
			
		|||
static const int drm_num_dmt_modes =
 | 
			
		||||
	sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
 | 
			
		||||
 | 
			
		||||
static struct drm_display_mode *drm_find_dmt(struct drm_device *dev,
 | 
			
		||||
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
 | 
			
		||||
					   int hsize, int vsize, int fresh)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
| 
						 | 
				
			
			@ -677,6 +677,7 @@ static struct drm_display_mode *drm_find_dmt(struct drm_device *dev,
 | 
			
		|||
	}
 | 
			
		||||
	return mode;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(drm_mode_find_dmt);
 | 
			
		||||
 | 
			
		||||
typedef void detailed_cb(struct detailed_timing *timing, void *closure);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -866,7 +867,7 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/* check whether it can be found in default mode table */
 | 
			
		||||
	mode = drm_find_dmt(dev, hsize, vsize, vrefresh_rate);
 | 
			
		||||
	mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate);
 | 
			
		||||
	if (mode)
 | 
			
		||||
		return mode;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1386,7 +1387,7 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
 | 
			
		|||
			if (m >= num_est3_modes)
 | 
			
		||||
				break;
 | 
			
		||||
			if (est[i] & (1 << j)) {
 | 
			
		||||
				mode = drm_find_dmt(connector->dev,
 | 
			
		||||
				mode = drm_mode_find_dmt(connector->dev,
 | 
			
		||||
							 est3_modes[m].w,
 | 
			
		||||
							 est3_modes[m].h,
 | 
			
		||||
							 est3_modes[m].r
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1070,6 +1070,79 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 | 
			
		||||
			      struct drm_display_mode **modes,
 | 
			
		||||
			      bool *enabled, int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	int count, i, j;
 | 
			
		||||
	bool can_clone = false;
 | 
			
		||||
	struct drm_fb_helper_connector *fb_helper_conn;
 | 
			
		||||
	struct drm_display_mode *dmt_mode, *mode;
 | 
			
		||||
 | 
			
		||||
	/* only contemplate cloning in the single crtc case */
 | 
			
		||||
	if (fb_helper->crtc_count > 1)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	count = 0;
 | 
			
		||||
	for (i = 0; i < fb_helper->connector_count; i++) {
 | 
			
		||||
		if (enabled[i])
 | 
			
		||||
			count++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* only contemplate cloning if more than one connector is enabled */
 | 
			
		||||
	if (count <= 1)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	/* check the command line or if nothing common pick 1024x768 */
 | 
			
		||||
	can_clone = true;
 | 
			
		||||
	for (i = 0; i < fb_helper->connector_count; i++) {
 | 
			
		||||
		if (!enabled[i])
 | 
			
		||||
			continue;
 | 
			
		||||
		fb_helper_conn = fb_helper->connector_info[i];
 | 
			
		||||
		modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
 | 
			
		||||
		if (!modes[i]) {
 | 
			
		||||
			can_clone = false;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		for (j = 0; j < i; j++) {
 | 
			
		||||
			if (!enabled[j])
 | 
			
		||||
				continue;
 | 
			
		||||
			if (!drm_mode_equal(modes[j], modes[i]))
 | 
			
		||||
				can_clone = false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (can_clone) {
 | 
			
		||||
		DRM_DEBUG_KMS("can clone using command line\n");
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* try and find a 1024x768 mode on each connector */
 | 
			
		||||
	can_clone = true;
 | 
			
		||||
	dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < fb_helper->connector_count; i++) {
 | 
			
		||||
 | 
			
		||||
		if (!enabled[i])
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		fb_helper_conn = fb_helper->connector_info[i];
 | 
			
		||||
		list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
 | 
			
		||||
			if (drm_mode_equal(mode, dmt_mode))
 | 
			
		||||
				modes[i] = mode;
 | 
			
		||||
		}
 | 
			
		||||
		if (!modes[i])
 | 
			
		||||
			can_clone = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (can_clone) {
 | 
			
		||||
		DRM_DEBUG_KMS("can clone using 1024x768\n");
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
 | 
			
		||||
				 struct drm_display_mode **modes,
 | 
			
		||||
				 bool *enabled, int width, int height)
 | 
			
		||||
| 
						 | 
				
			
			@ -1163,7 +1236,11 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 | 
			
		|||
				break;
 | 
			
		||||
 | 
			
		||||
		if (o < n) {
 | 
			
		||||
			/* ignore cloning for now */
 | 
			
		||||
			/* ignore cloning unless only a single crtc */
 | 
			
		||||
			if (fb_helper->crtc_count > 1)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			if (!drm_mode_equal(modes[o], modes[n]))
 | 
			
		||||
				continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1214,9 +1291,12 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
 | 
			
		|||
 | 
			
		||||
	drm_enable_connectors(fb_helper, enabled);
 | 
			
		||||
 | 
			
		||||
	ret = drm_target_cloned(fb_helper, modes, enabled, width, height);
 | 
			
		||||
	if (!ret) {
 | 
			
		||||
		ret = drm_target_preferred(fb_helper, modes, enabled, width, height);
 | 
			
		||||
		if (!ret)
 | 
			
		||||
			DRM_ERROR("Unable to find initial modes\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -804,4 +804,6 @@ extern int drm_add_modes_noedid(struct drm_connector *connector,
 | 
			
		|||
				int hdisplay, int vdisplay);
 | 
			
		||||
 | 
			
		||||
extern bool drm_edid_is_valid(struct edid *edid);
 | 
			
		||||
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
 | 
			
		||||
					   int hsize, int vsize, int fresh);
 | 
			
		||||
#endif /* __DRM_CRTC_H__ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue