Skip to content

Commit

Permalink
drm/i915: Choose real sdvo output according to result from detection
Browse files Browse the repository at this point in the history
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: Ma Ling <ling.ma@intel.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
  • Loading branch information
ling.ma@intel.com authored and Eric Anholt committed Jul 29, 2009
1 parent bcae2ca commit fb7a46f
Showing 1 changed file with 153 additions and 78 deletions.
231 changes: 153 additions & 78 deletions drivers/gpu/drm/i915/intel_sdvo.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ struct intel_sdvo_priv {
/* Pixel clock limitations reported by the SDVO device, in kHz */
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.
*
Expand Down Expand Up @@ -114,6 +120,9 @@ struct intel_sdvo_priv {
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
* SDVOB and SDVOC to work around apparent hardware issues (according to
Expand Down Expand Up @@ -1435,6 +1444,39 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)
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
intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
{
Expand All @@ -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)
{
u8 response[2];
uint16_t response;
u8 status;
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);
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)
return connector_status_unknown;

if ((response[0] != 0) || (response[1] != 0)) {
intel_sdvo_hdmi_sink_detect(connector);
return connector_status_connected;
} else
if (response == 0)
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)
Expand Down Expand Up @@ -1866,16 +1916,101 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
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)
{
struct drm_connector *connector;
struct intel_output *intel_output;
struct intel_sdvo_priv *sdvo_priv;

int connector_type;
u8 ch[0x40];
int i;
int encoder_type;

intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
if (!intel_output) {
Expand Down Expand Up @@ -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;

/* In defaut case sdvo lvds is false */
sdvo_priv->is_lvds = false;
intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps);

if (sdvo_priv->caps.output_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_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;
if (intel_sdvo_output_setup(intel_output,
sdvo_priv->caps.output_flags) != true) {
DRM_DEBUG("SDVO output failed to setup on SDVO%c\n",
output_device == SDVOB ? 'B' : 'C');
goto err_i2c;
}


connector = &intel_output->base;
drm_connector_init(dev, connector, &intel_sdvo_connector_funcs,
connector_type);
connector->connector_type);

drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
connector->interlace_allowed = 0;
connector->doublescan_allowed = 0;
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_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
Expand Down

0 comments on commit fb7a46f

Please sign in to comment.