Commit fb7a46f3 authored by ling.ma@intel.com's avatar ling.ma@intel.com Committed by Eric Anholt

drm/i915: Choose real sdvo output according to result from detection

Baed on Eric's idea in order to handle multiple sdvo encoders
we implement another approach to dynamically chose real one
encoder after detection, which is contrasted with patch -
drm/i915:Construct all possible sdvo outputs for sdvo encoder.
Signed-off-by: default avatarMa Ling <ling.ma@intel.com>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent bcae2ca8
...@@ -55,6 +55,12 @@ struct intel_sdvo_priv { ...@@ -55,6 +55,12 @@ struct intel_sdvo_priv {
/* Pixel clock limitations reported by the SDVO device, in kHz */ /* Pixel clock limitations reported by the SDVO device, in kHz */
int pixel_clock_min, pixel_clock_max; int pixel_clock_min, pixel_clock_max;
/*
* For multiple function SDVO device,
* this is for current attached outputs.
*/
uint16_t attached_output;
/** /**
* This is set if we're going to treat the device as TV-out. * This is set if we're going to treat the device as TV-out.
* *
...@@ -114,6 +120,9 @@ struct intel_sdvo_priv { ...@@ -114,6 +120,9 @@ struct intel_sdvo_priv {
u32 save_SDVOX; u32 save_SDVOX;
}; };
static bool
intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags);
/** /**
* Writes the SDVOB or SDVOC with the given value, but always writes both * Writes the SDVOB or SDVOC with the given value, but always writes both
* SDVOB and SDVOC to work around apparent hardware issues (according to * SDVOB and SDVOC to work around apparent hardware issues (according to
...@@ -1435,6 +1444,39 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) ...@@ -1435,6 +1444,39 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)
intel_sdvo_read_response(intel_output, &response, 2); intel_sdvo_read_response(intel_output, &response, 2);
} }
static bool
intel_sdvo_multifunc_encoder(struct intel_output *intel_output)
{
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
int caps = 0;
if (sdvo_priv->caps.output_flags &
(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
caps++;
if (sdvo_priv->caps.output_flags &
(SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1))
caps++;
if (sdvo_priv->caps.output_flags &
(SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID0))
caps++;
if (sdvo_priv->caps.output_flags &
(SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1))
caps++;
if (sdvo_priv->caps.output_flags &
(SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_YPRPB1))
caps++;
if (sdvo_priv->caps.output_flags &
(SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1))
caps++;
if (sdvo_priv->caps.output_flags &
(SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1))
caps++;
return (caps > 1);
}
static void static void
intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
{ {
...@@ -1453,23 +1495,31 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) ...@@ -1453,23 +1495,31 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector) static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector)
{ {
u8 response[2]; uint16_t response;
u8 status; u8 status;
struct intel_output *intel_output = to_intel_output(connector); struct intel_output *intel_output = to_intel_output(connector);
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
status = intel_sdvo_read_response(intel_output, &response, 2); status = intel_sdvo_read_response(intel_output, &response, 2);
DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]); DRM_DEBUG("SDVO response %d %d\n", response & 0xff, response >> 8);
if (status != SDVO_CMD_STATUS_SUCCESS) if (status != SDVO_CMD_STATUS_SUCCESS)
return connector_status_unknown; return connector_status_unknown;
if ((response[0] != 0) || (response[1] != 0)) { if (response == 0)
intel_sdvo_hdmi_sink_detect(connector);
return connector_status_connected;
} else
return connector_status_disconnected; return connector_status_disconnected;
if (intel_sdvo_multifunc_encoder(intel_output) &&
sdvo_priv->attached_output != response) {
if (sdvo_priv->controlled_output != response &&
intel_sdvo_output_setup(intel_output, response) != true)
return connector_status_unknown;
sdvo_priv->attached_output = response;
}
intel_sdvo_hdmi_sink_detect(connector);
return connector_status_connected;
} }
static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
...@@ -1866,16 +1916,101 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device) ...@@ -1866,16 +1916,101 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
return 0x72; return 0x72;
} }
static bool
intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
{
struct drm_connector *connector = &intel_output->base;
struct drm_encoder *encoder = &intel_output->enc;
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
bool ret = true, registered = false;
sdvo_priv->is_tv = false;
intel_output->needs_tv_clock = false;
sdvo_priv->is_lvds = false;
if (device_is_registered(&connector->kdev)) {
drm_sysfs_connector_remove(connector);
registered = true;
}
if (flags &
(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) {
if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0;
else
sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1;
encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
connector->connector_type = DRM_MODE_CONNECTOR_DVID;
if (intel_sdvo_get_supp_encode(intel_output,
&sdvo_priv->encode) &&
intel_sdvo_get_digital_encoding_mode(intel_output) &&
sdvo_priv->is_hdmi) {
/* enable hdmi encoding mode if supported */
intel_sdvo_set_encode(intel_output, SDVO_ENCODE_HDMI);
intel_sdvo_set_colorimetry(intel_output,
SDVO_COLORIMETRY_RGB256);
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
}
} else if (flags & SDVO_OUTPUT_SVID0) {
sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
sdvo_priv->is_tv = true;
intel_output->needs_tv_clock = true;
} else if (flags & SDVO_OUTPUT_RGB0) {
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
encoder->encoder_type = DRM_MODE_ENCODER_DAC;
connector->connector_type = DRM_MODE_CONNECTOR_VGA;
} else if (flags & SDVO_OUTPUT_RGB1) {
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
encoder->encoder_type = DRM_MODE_ENCODER_DAC;
connector->connector_type = DRM_MODE_CONNECTOR_VGA;
} else if (flags & SDVO_OUTPUT_LVDS0) {
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
sdvo_priv->is_lvds = true;
} else if (flags & SDVO_OUTPUT_LVDS1) {
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
sdvo_priv->is_lvds = true;
} else {
unsigned char bytes[2];
sdvo_priv->controlled_output = 0;
memcpy(bytes, &sdvo_priv->caps.output_flags, 2);
DRM_DEBUG_KMS(I915_SDVO,
"%s: Unknown SDVO output type (0x%02x%02x)\n",
SDVO_NAME(sdvo_priv),
bytes[0], bytes[1]);
ret = false;
}
if (ret && registered)
ret = drm_sysfs_connector_add(connector) == 0 ? true : false;
return ret;
}
bool intel_sdvo_init(struct drm_device *dev, int output_device) bool intel_sdvo_init(struct drm_device *dev, int output_device)
{ {
struct drm_connector *connector; struct drm_connector *connector;
struct intel_output *intel_output; struct intel_output *intel_output;
struct intel_sdvo_priv *sdvo_priv; struct intel_sdvo_priv *sdvo_priv;
int connector_type;
u8 ch[0x40]; u8 ch[0x40];
int i; int i;
int encoder_type;
intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
if (!intel_output) { if (!intel_output) {
...@@ -1925,88 +2060,28 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) ...@@ -1925,88 +2060,28 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
intel_output->ddc_bus->algo = &intel_sdvo_i2c_bit_algo; intel_output->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
/* In defaut case sdvo lvds is false */ /* In defaut case sdvo lvds is false */
sdvo_priv->is_lvds = false;
intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps); intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps);
if (sdvo_priv->caps.output_flags & if (intel_sdvo_output_setup(intel_output,
(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) { sdvo_priv->caps.output_flags) != true) {
if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) DRM_DEBUG("SDVO output failed to setup on SDVO%c\n",
sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0; output_device == SDVOB ? 'B' : 'C');
else
sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1;
encoder_type = DRM_MODE_ENCODER_TMDS;
connector_type = DRM_MODE_CONNECTOR_DVID;
if (intel_sdvo_get_supp_encode(intel_output,
&sdvo_priv->encode) &&
intel_sdvo_get_digital_encoding_mode(intel_output) &&
sdvo_priv->is_hdmi) {
/* enable hdmi encoding mode if supported */
intel_sdvo_set_encode(intel_output, SDVO_ENCODE_HDMI);
intel_sdvo_set_colorimetry(intel_output,
SDVO_COLORIMETRY_RGB256);
connector_type = DRM_MODE_CONNECTOR_HDMIA;
}
}
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
{
sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
encoder_type = DRM_MODE_ENCODER_TVDAC;
connector_type = DRM_MODE_CONNECTOR_SVIDEO;
sdvo_priv->is_tv = true;
intel_output->needs_tv_clock = true;
}
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
{
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
encoder_type = DRM_MODE_ENCODER_DAC;
connector_type = DRM_MODE_CONNECTOR_VGA;
}
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
{
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
encoder_type = DRM_MODE_ENCODER_DAC;
connector_type = DRM_MODE_CONNECTOR_VGA;
}
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0)
{
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
encoder_type = DRM_MODE_ENCODER_LVDS;
connector_type = DRM_MODE_CONNECTOR_LVDS;
sdvo_priv->is_lvds = true;
}
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1)
{
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
encoder_type = DRM_MODE_ENCODER_LVDS;
connector_type = DRM_MODE_CONNECTOR_LVDS;
sdvo_priv->is_lvds = true;
}
else
{
unsigned char bytes[2];
sdvo_priv->controlled_output = 0;
memcpy (bytes, &sdvo_priv->caps.output_flags, 2);
DRM_DEBUG_KMS(I915_SDVO,
"%s: Unknown SDVO output type (0x%02x%02x)\n",
SDVO_NAME(sdvo_priv),
bytes[0], bytes[1]);
encoder_type = DRM_MODE_ENCODER_NONE;
connector_type = DRM_MODE_CONNECTOR_Unknown;
goto err_i2c; goto err_i2c;
} }
connector = &intel_output->base; connector = &intel_output->base;
drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, drm_connector_init(dev, connector, &intel_sdvo_connector_funcs,
connector_type); connector->connector_type);
drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
connector->interlace_allowed = 0; connector->interlace_allowed = 0;
connector->doublescan_allowed = 0; connector->doublescan_allowed = 0;
connector->display_info.subpixel_order = SubPixelHorizontalRGB; connector->display_info.subpixel_order = SubPixelHorizontalRGB;
drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); drm_encoder_init(dev, &intel_output->enc,
&intel_sdvo_enc_funcs, intel_output->enc.encoder_type);
drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs); drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment