|
@@ -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.
|
|
|
*
|
|
@@ -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
|
|
@@ -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)
|
|
|
{
|
|
@@ -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)
|
|
@@ -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) {
|
|
@@ -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);
|