diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-05-01 08:47:44 -0700 | 
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-05-01 08:47:44 -0700 | 
| commit | bf61c8840efe60fd8f91446860b63338fb424158 (patch) | |
| tree | 7a71832407a4f0d6346db773343f4c3ae2257b19 /drivers/gpu/drm/i915/intel_sdvo.c | |
| parent | 5846115b30f3a881e542c8bfde59a699c1c13740 (diff) | |
| parent | 0c6a61657da78098472fd0eb71cc01f2387fa1bb (diff) | |
| download | olio-linux-3.10-bf61c8840efe60fd8f91446860b63338fb424158.tar.xz olio-linux-3.10-bf61c8840efe60fd8f91446860b63338fb424158.zip  | |
Merge branch 'next' into for-linus
Prepare first set of updates for 3.10 merge window.
Diffstat (limited to 'drivers/gpu/drm/i915/intel_sdvo.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_sdvo.c | 234 | 
1 files changed, 169 insertions, 65 deletions
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 79d308da29f..d07a8cdf998 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -103,6 +103,7 @@ struct intel_sdvo {  	 * It is only valid when using TMDS encoding and 8 bit per color mode.  	 */  	uint32_t color_range; +	bool color_range_auto;  	/**  	 * This is set if we're going to treat the device as TV-out. @@ -125,6 +126,7 @@ struct intel_sdvo {  	bool is_hdmi;  	bool has_hdmi_monitor;  	bool has_hdmi_audio; +	bool rgb_quant_range_selectable;  	/**  	 * This is set if we detect output of sdvo device as LVDS and @@ -509,7 +511,7 @@ out:  static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,  				     void *response, int response_len)  { -	u8 retry = 5; +	u8 retry = 15; /* 5 quick checks, followed by 10 long checks */  	u8 status;  	int i; @@ -522,14 +524,27 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,  	 * command to be complete.  	 *  	 * Check 5 times in case the hardware failed to read the docs. +	 * +	 * Also beware that the first response by many devices is to +	 * reply PENDING and stall for time. TVs are notorious for +	 * requiring longer than specified to complete their replies. +	 * Originally (in the DDX long ago), the delay was only ever 15ms +	 * with an additional delay of 30ms applied for TVs added later after +	 * many experiments. To accommodate both sets of delays, we do a +	 * sequence of slow checks if the device is falling behind and fails +	 * to reply within 5*15µs.  	 */  	if (!intel_sdvo_read_byte(intel_sdvo,  				  SDVO_I2C_CMD_STATUS,  				  &status))  		goto log_fail; -	while (status == SDVO_CMD_STATUS_PENDING && retry--) { -		udelay(15); +	while (status == SDVO_CMD_STATUS_PENDING && --retry) { +		if (retry < 10) +			msleep(15); +		else +			udelay(15); +  		if (!intel_sdvo_read_byte(intel_sdvo,  					  SDVO_I2C_CMD_STATUS,  					  &status)) @@ -933,7 +948,8 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,  				    &tx_rate, 1);  } -static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) +static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, +					 const struct drm_display_mode *adjusted_mode)  {  	struct dip_infoframe avi_if = {  		.type = DIP_TYPE_AVI, @@ -942,6 +958,13 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)  	};  	uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; +	if (intel_sdvo->rgb_quant_range_selectable) { +		if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) +			avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; +		else +			avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; +	} +  	intel_dip_infoframe_csum(&avi_if);  	/* sdvo spec says that the ecc is handled by the hw, and it looks like @@ -1051,6 +1074,18 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,  	multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode);  	intel_mode_set_pixel_multiplier(adjusted_mode, multiplier); +	if (intel_sdvo->color_range_auto) { +		/* See CEA-861-E - 5.1 Default Encoding Parameters */ +		if (intel_sdvo->has_hdmi_monitor && +		    drm_match_cea_mode(adjusted_mode) > 1) +			intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; +		else +			intel_sdvo->color_range = 0; +	} + +	if (intel_sdvo->color_range) +		adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; +  	return true;  } @@ -1108,7 +1143,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,  		intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);  		intel_sdvo_set_colorimetry(intel_sdvo,  					   SDVO_COLORIMETRY_RGB256); -		intel_sdvo_set_avi_infoframe(intel_sdvo); +		intel_sdvo_set_avi_infoframe(intel_sdvo, adjusted_mode);  	} else  		intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI); @@ -1140,7 +1175,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,  		/* The real mode polarity is set by the SDVO commands, using  		 * struct intel_sdvo_dtd. */  		sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH; -		if (intel_sdvo->is_hdmi) +		if (!HAS_PCH_SPLIT(dev) && intel_sdvo->is_hdmi)  			sdvox |= intel_sdvo->color_range;  		if (INTEL_INFO(dev)->gen < 5)  			sdvox |= SDVO_BORDER_ENABLE; @@ -1228,6 +1263,30 @@ static void intel_disable_sdvo(struct intel_encoder *encoder)  	temp = I915_READ(intel_sdvo->sdvo_reg);  	if ((temp & SDVO_ENABLE) != 0) { +		/* HW workaround for IBX, we need to move the port to +		 * transcoder A before disabling it. */ +		if (HAS_PCH_IBX(encoder->base.dev)) { +			struct drm_crtc *crtc = encoder->base.crtc; +			int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; + +			if (temp & SDVO_PIPE_B_SELECT) { +				temp &= ~SDVO_PIPE_B_SELECT; +				I915_WRITE(intel_sdvo->sdvo_reg, temp); +				POSTING_READ(intel_sdvo->sdvo_reg); + +				/* Again we need to write this twice. */ +				I915_WRITE(intel_sdvo->sdvo_reg, temp); +				POSTING_READ(intel_sdvo->sdvo_reg); + +				/* Transcoder selection bits only update +				 * effectively on vblank. */ +				if (crtc) +					intel_wait_for_vblank(encoder->base.dev, pipe); +				else +					msleep(50); +			} +		} +  		intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);  	}  } @@ -1244,8 +1303,20 @@ static void intel_enable_sdvo(struct intel_encoder *encoder)  	u8 status;  	temp = I915_READ(intel_sdvo->sdvo_reg); -	if ((temp & SDVO_ENABLE) == 0) +	if ((temp & SDVO_ENABLE) == 0) { +		/* HW workaround for IBX, we need to move the port +		 * to transcoder A before disabling it. */ +		if (HAS_PCH_IBX(dev)) { +			struct drm_crtc *crtc = encoder->base.crtc; +			int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; + +			/* Restore the transcoder select bit. */ +			if (pipe == PIPE_B) +				temp |= SDVO_PIPE_B_SELECT; +		} +  		intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE); +	}  	for (i = 0; i < 2; i++)  		intel_wait_for_vblank(dev, intel_crtc->pipe); @@ -1464,6 +1535,8 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector)  			if (intel_sdvo->is_hdmi) {  				intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);  				intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); +				intel_sdvo->rgb_quant_range_selectable = +					drm_rgb_quant_range_selectable(edid);  			}  		} else  			status = connector_status_disconnected; @@ -1499,15 +1572,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)  	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);  	enum drm_connector_status ret; -	if (!intel_sdvo_write_cmd(intel_sdvo, -				  SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0)) -		return connector_status_unknown; - -	/* add 30ms delay when the output type might be TV */ -	if (intel_sdvo->caps.output_flags & SDVO_TV_MASK) -		msleep(30); - -	if (!intel_sdvo_read_response(intel_sdvo, &response, 2)) +	if (!intel_sdvo_get_value(intel_sdvo, +				  SDVO_CMD_GET_ATTACHED_DISPLAYS, +				  &response, 2))  		return connector_status_unknown;  	DRM_DEBUG_KMS("SDVO response %d %d [%x]\n", @@ -1521,6 +1588,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)  	intel_sdvo->has_hdmi_monitor = false;  	intel_sdvo->has_hdmi_audio = false; +	intel_sdvo->rgb_quant_range_selectable = false;  	if ((intel_sdvo_connector->output_flag & response) == 0)  		ret = connector_status_disconnected; @@ -1796,7 +1864,7 @@ static void intel_sdvo_destroy(struct drm_connector *connector)  	intel_sdvo_destroy_enhance_property(connector);  	drm_sysfs_connector_remove(connector);  	drm_connector_cleanup(connector); -	kfree(connector); +	kfree(intel_sdvo_connector);  }  static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector) @@ -1828,7 +1896,7 @@ intel_sdvo_set_property(struct drm_connector *connector,  	uint8_t cmd;  	int ret; -	ret = drm_connector_property_set_value(connector, property, val); +	ret = drm_object_property_set_value(&connector->base, property, val);  	if (ret)  		return ret; @@ -1854,10 +1922,21 @@ intel_sdvo_set_property(struct drm_connector *connector,  	}  	if (property == dev_priv->broadcast_rgb_property) { -		if (val == !!intel_sdvo->color_range) -			return 0; - -		intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; +		switch (val) { +		case INTEL_BROADCAST_RGB_AUTO: +			intel_sdvo->color_range_auto = true; +			break; +		case INTEL_BROADCAST_RGB_FULL: +			intel_sdvo->color_range_auto = false; +			intel_sdvo->color_range = 0; +			break; +		case INTEL_BROADCAST_RGB_LIMITED: +			intel_sdvo->color_range_auto = false; +			intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; +			break; +		default: +			return -EINVAL; +		}  		goto done;  	} @@ -1883,7 +1962,7 @@ intel_sdvo_set_property(struct drm_connector *connector,  	} else if (IS_TV_OR_LVDS(intel_sdvo_connector)) {  		temp_value = val;  		if (intel_sdvo_connector->left == property) { -			drm_connector_property_set_value(connector, +			drm_object_property_set_value(&connector->base,  							 intel_sdvo_connector->right, val);  			if (intel_sdvo_connector->left_margin == temp_value)  				return 0; @@ -1895,7 +1974,7 @@ intel_sdvo_set_property(struct drm_connector *connector,  			cmd = SDVO_CMD_SET_OVERSCAN_H;  			goto set_value;  		} else if (intel_sdvo_connector->right == property) { -			drm_connector_property_set_value(connector, +			drm_object_property_set_value(&connector->base,  							 intel_sdvo_connector->left, val);  			if (intel_sdvo_connector->right_margin == temp_value)  				return 0; @@ -1907,7 +1986,7 @@ intel_sdvo_set_property(struct drm_connector *connector,  			cmd = SDVO_CMD_SET_OVERSCAN_H;  			goto set_value;  		} else if (intel_sdvo_connector->top == property) { -			drm_connector_property_set_value(connector, +			drm_object_property_set_value(&connector->base,  							 intel_sdvo_connector->bottom, val);  			if (intel_sdvo_connector->top_margin == temp_value)  				return 0; @@ -1919,7 +1998,7 @@ intel_sdvo_set_property(struct drm_connector *connector,  			cmd = SDVO_CMD_SET_OVERSCAN_V;  			goto set_value;  		} else if (intel_sdvo_connector->bottom == property) { -			drm_connector_property_set_value(connector, +			drm_object_property_set_value(&connector->base,  							 intel_sdvo_connector->top, val);  			if (intel_sdvo_connector->bottom_margin == temp_value)  				return 0; @@ -1954,11 +2033,8 @@ set_value:  done: -	if (intel_sdvo->base.base.crtc) { -		struct drm_crtc *crtc = intel_sdvo->base.base.crtc; -		intel_set_mode(crtc, &crtc->mode, -			       crtc->x, crtc->y, crtc->fb); -	} +	if (intel_sdvo->base.base.crtc) +		intel_crtc_restore_mode(intel_sdvo->base.base.crtc);  	return 0;  #undef CHECK_PROPERTY @@ -1967,7 +2043,6 @@ done:  static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {  	.mode_fixup = intel_sdvo_mode_fixup,  	.mode_set = intel_sdvo_mode_set, -	.disable = intel_encoder_noop,  };  static const struct drm_connector_funcs intel_sdvo_connector_funcs = { @@ -2072,17 +2147,24 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,  	else  		mapping = &dev_priv->sdvo_mappings[1]; -	pin = GMBUS_PORT_DPB; -	if (mapping->initialized) +	if (mapping->initialized && intel_gmbus_is_port_valid(mapping->i2c_pin))  		pin = mapping->i2c_pin; +	else +		pin = GMBUS_PORT_DPB; -	if (intel_gmbus_is_port_valid(pin)) { -		sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin); -		intel_gmbus_set_speed(sdvo->i2c, GMBUS_RATE_1MHZ); -		intel_gmbus_force_bit(sdvo->i2c, true); -	} else { -		sdvo->i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB); -	} +	sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin); + +	/* With gmbus we should be able to drive sdvo i2c at 2MHz, but somehow +	 * our code totally fails once we start using gmbus. Hence fall back to +	 * bit banging for now. */ +	intel_gmbus_force_bit(sdvo->i2c, true); +} + +/* undo any changes intel_sdvo_select_i2c_bus() did to sdvo->i2c */ +static void +intel_sdvo_unselect_i2c_bus(struct intel_sdvo *sdvo) +{ +	intel_gmbus_force_bit(sdvo->i2c, false);  }  static bool @@ -2150,13 +2232,16 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector,  }  static void -intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector) +intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo, +			       struct intel_sdvo_connector *connector)  {  	struct drm_device *dev = connector->base.base.dev;  	intel_attach_force_audio_property(&connector->base.base); -	if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) +	if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) {  		intel_attach_broadcast_rgb_property(&connector->base.base); +		intel_sdvo->color_range_auto = true; +	}  }  static bool @@ -2201,11 +2286,10 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)  		connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;  		intel_sdvo->is_hdmi = true;  	} -	intel_sdvo->base.cloneable = true;  	intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);  	if (intel_sdvo->is_hdmi) -		intel_sdvo_add_hdmi_properties(intel_sdvo_connector); +		intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector);  	return true;  } @@ -2232,7 +2316,6 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)  	intel_sdvo->is_tv = true;  	intel_sdvo->base.needs_tv_clock = true; -	intel_sdvo->base.cloneable = false;  	intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); @@ -2275,8 +2358,6 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)  		intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;  	} -	intel_sdvo->base.cloneable = true; -  	intel_sdvo_connector_init(intel_sdvo_connector,  				  intel_sdvo);  	return true; @@ -2307,9 +2388,6 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)  		intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;  	} -	/* SDVO LVDS is not cloneable because the input mode gets adjusted by the encoder */ -	intel_sdvo->base.cloneable = false; -  	intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);  	if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))  		goto err; @@ -2382,6 +2460,18 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags)  	return true;  } +static void intel_sdvo_output_cleanup(struct intel_sdvo *intel_sdvo) +{ +	struct drm_device *dev = intel_sdvo->base.base.dev; +	struct drm_connector *connector, *tmp; + +	list_for_each_entry_safe(connector, tmp, +				 &dev->mode_config.connector_list, head) { +		if (intel_attached_encoder(connector) == &intel_sdvo->base) +			intel_sdvo_destroy(connector); +	} +} +  static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,  					  struct intel_sdvo_connector *intel_sdvo_connector,  					  int type) @@ -2422,7 +2512,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,  				i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]);  	intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[0]; -	drm_connector_attach_property(&intel_sdvo_connector->base.base, +	drm_object_attach_property(&intel_sdvo_connector->base.base.base,  				      intel_sdvo_connector->tv_format, 0);  	return true; @@ -2438,7 +2528,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,  		intel_sdvo_connector->name = \  			drm_property_create_range(dev, 0, #name, 0, data_value[0]); \  		if (!intel_sdvo_connector->name) return false; \ -		drm_connector_attach_property(connector, \ +		drm_object_attach_property(&connector->base, \  					      intel_sdvo_connector->name, \  					      intel_sdvo_connector->cur_##name); \  		DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \ @@ -2475,7 +2565,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,  		if (!intel_sdvo_connector->left)  			return false; -		drm_connector_attach_property(connector, +		drm_object_attach_property(&connector->base,  					      intel_sdvo_connector->left,  					      intel_sdvo_connector->left_margin); @@ -2484,7 +2574,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,  		if (!intel_sdvo_connector->right)  			return false; -		drm_connector_attach_property(connector, +		drm_object_attach_property(&connector->base,  					      intel_sdvo_connector->right,  					      intel_sdvo_connector->right_margin);  		DRM_DEBUG_KMS("h_overscan: max %d, " @@ -2512,7 +2602,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,  		if (!intel_sdvo_connector->top)  			return false; -		drm_connector_attach_property(connector, +		drm_object_attach_property(&connector->base,  					      intel_sdvo_connector->top,  					      intel_sdvo_connector->top_margin); @@ -2522,7 +2612,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,  		if (!intel_sdvo_connector->bottom)  			return false; -		drm_connector_attach_property(connector, +		drm_object_attach_property(&connector->base,  					      intel_sdvo_connector->bottom,  					      intel_sdvo_connector->bottom_margin);  		DRM_DEBUG_KMS("v_overscan: max %d, " @@ -2554,7 +2644,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,  		if (!intel_sdvo_connector->dot_crawl)  			return false; -		drm_connector_attach_property(connector, +		drm_object_attach_property(&connector->base,  					      intel_sdvo_connector->dot_crawl,  					      intel_sdvo_connector->cur_dot_crawl);  		DRM_DEBUG_KMS("dot crawl: current %d\n", response); @@ -2658,10 +2748,8 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)  	intel_sdvo->is_sdvob = is_sdvob;  	intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, intel_sdvo) >> 1;  	intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg); -	if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) { -		kfree(intel_sdvo); -		return false; -	} +	if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) +		goto err_i2c_bus;  	/* encoder type will be decided later */  	intel_encoder = &intel_sdvo->base; @@ -2705,9 +2793,20 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)  				    intel_sdvo->caps.output_flags) != true) {  		DRM_DEBUG_KMS("SDVO output failed to setup on %s\n",  			      SDVO_NAME(intel_sdvo)); -		goto err; +		/* Output_setup can leave behind connectors! */ +		goto err_output;  	} +	/* +	 * Cloning SDVO with anything is often impossible, since the SDVO +	 * encoder can request a special input timing mode. And even if that's +	 * not the case we have evidence that cloning a plain unscaled mode with +	 * VGA doesn't really work. Furthermore the cloning flags are way too +	 * simplistic anyway to express such constraints, so just give up on +	 * cloning for SDVO encoders. +	 */ +	intel_sdvo->base.cloneable = false; +  	/* Only enable the hotplug irq if we need it, to work around noisy  	 * hotplug lines.  	 */ @@ -2718,12 +2817,12 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)  	/* Set the input timing to the screen. Assume always input 0. */  	if (!intel_sdvo_set_target_input(intel_sdvo)) -		goto err; +		goto err_output;  	if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,  						    &intel_sdvo->pixel_clock_min,  						    &intel_sdvo->pixel_clock_max)) -		goto err; +		goto err_output;  	DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "  			"clock range %dMHz - %dMHz, " @@ -2743,9 +2842,14 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)  			(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');  	return true; +err_output: +	intel_sdvo_output_cleanup(intel_sdvo); +  err:  	drm_encoder_cleanup(&intel_encoder->base);  	i2c_del_adapter(&intel_sdvo->ddc); +err_i2c_bus: +	intel_sdvo_unselect_i2c_bus(intel_sdvo);  	kfree(intel_sdvo);  	return false;  |