intel_hdmi.c revision 9dff6af860d6b7f661d4360eb859837afaca0a1b
17d57382e65994ab7d01741373bd1c420370aed9fEric Anholt/* 27d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Copyright 2006 Dave Airlie <airlied@linux.ie> 37d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Copyright © 2006-2009 Intel Corporation 47d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * 57d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Permission is hereby granted, free of charge, to any person obtaining a 67d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * copy of this software and associated documentation files (the "Software"), 77d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * to deal in the Software without restriction, including without limitation 87d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 97d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * and/or sell copies of the Software, and to permit persons to whom the 107d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Software is furnished to do so, subject to the following conditions: 117d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * 127d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * The above copyright notice and this permission notice (including the next 137d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * paragraph) shall be included in all copies or substantial portions of the 147d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Software. 157d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * 167d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 177d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 187d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 197d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 207d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 217d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 227d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * DEALINGS IN THE SOFTWARE. 237d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * 247d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Authors: 257d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Eric Anholt <eric@anholt.net> 267d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Jesse Barnes <jesse.barnes@intel.com> 277d57382e65994ab7d01741373bd1c420370aed9fEric Anholt */ 287d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 297d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include <linux/i2c.h> 307d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include <linux/delay.h> 317d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include "drmP.h" 327d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include "drm.h" 337d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include "drm_crtc.h" 347d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include "intel_drv.h" 357d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include "i915_drm.h" 367d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include "i915_drv.h" 377d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 387d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstruct intel_hdmi_priv { 397d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 sdvox_reg; 407d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 save_SDVOX; 419dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling bool has_hdmi_sink; 427d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 437d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 447d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic void intel_hdmi_mode_set(struct drm_encoder *encoder, 457d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *mode, 467d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *adjusted_mode) 477d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 487d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_device *dev = encoder->dev; 497d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_i915_private *dev_priv = dev->dev_private; 507d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_crtc *crtc = encoder->crtc; 517d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 527d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_output *intel_output = enc_to_intel_output(encoder); 537d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; 547d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 sdvox; 557d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 567d57382e65994ab7d01741373bd1c420370aed9fEric Anholt sdvox = SDVO_ENCODING_HDMI | 577d57382e65994ab7d01741373bd1c420370aed9fEric Anholt SDVO_BORDER_ENABLE | 587d57382e65994ab7d01741373bd1c420370aed9fEric Anholt SDVO_VSYNC_ACTIVE_HIGH | 597d57382e65994ab7d01741373bd1c420370aed9fEric Anholt SDVO_HSYNC_ACTIVE_HIGH; 607d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 617d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (hdmi_priv->has_hdmi_sink) 627d57382e65994ab7d01741373bd1c420370aed9fEric Anholt sdvox |= SDVO_AUDIO_ENABLE; 637d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 647d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (intel_crtc->pipe == 1) 657d57382e65994ab7d01741373bd1c420370aed9fEric Anholt sdvox |= SDVO_PIPE_B_SELECT; 667d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 677d57382e65994ab7d01741373bd1c420370aed9fEric Anholt I915_WRITE(hdmi_priv->sdvox_reg, sdvox); 687d57382e65994ab7d01741373bd1c420370aed9fEric Anholt POSTING_READ(hdmi_priv->sdvox_reg); 697d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 707d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 717d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) 727d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 737d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_device *dev = encoder->dev; 747d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_i915_private *dev_priv = dev->dev_private; 757d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_output *intel_output = enc_to_intel_output(encoder); 767d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; 777d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 temp; 787d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 797d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (mode != DRM_MODE_DPMS_ON) { 807d57382e65994ab7d01741373bd1c420370aed9fEric Anholt temp = I915_READ(hdmi_priv->sdvox_reg); 817d57382e65994ab7d01741373bd1c420370aed9fEric Anholt I915_WRITE(hdmi_priv->sdvox_reg, temp & ~SDVO_ENABLE); 827d57382e65994ab7d01741373bd1c420370aed9fEric Anholt } else { 837d57382e65994ab7d01741373bd1c420370aed9fEric Anholt temp = I915_READ(hdmi_priv->sdvox_reg); 847d57382e65994ab7d01741373bd1c420370aed9fEric Anholt I915_WRITE(hdmi_priv->sdvox_reg, temp | SDVO_ENABLE); 857d57382e65994ab7d01741373bd1c420370aed9fEric Anholt } 867d57382e65994ab7d01741373bd1c420370aed9fEric Anholt POSTING_READ(hdmi_priv->sdvox_reg); 877d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 887d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 897d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic void intel_hdmi_save(struct drm_connector *connector) 907d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 917d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_device *dev = connector->dev; 927d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_i915_private *dev_priv = dev->dev_private; 937d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_output *intel_output = to_intel_output(connector); 947d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; 957d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 967d57382e65994ab7d01741373bd1c420370aed9fEric Anholt hdmi_priv->save_SDVOX = I915_READ(hdmi_priv->sdvox_reg); 977d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 987d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 997d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic void intel_hdmi_restore(struct drm_connector *connector) 1007d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 1017d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_device *dev = connector->dev; 1027d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_i915_private *dev_priv = dev->dev_private; 1037d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_output *intel_output = to_intel_output(connector); 1047d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; 1057d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1067d57382e65994ab7d01741373bd1c420370aed9fEric Anholt I915_WRITE(hdmi_priv->sdvox_reg, hdmi_priv->save_SDVOX); 1077d57382e65994ab7d01741373bd1c420370aed9fEric Anholt POSTING_READ(hdmi_priv->sdvox_reg); 1087d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 1097d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1107d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic int intel_hdmi_mode_valid(struct drm_connector *connector, 1117d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *mode) 1127d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 1137d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (mode->clock > 165000) 1147d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return MODE_CLOCK_HIGH; 1157d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (mode->clock < 20000) 1167d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return MODE_CLOCK_HIGH; 1177d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1187d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 1197d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return MODE_NO_DBLESCAN; 1207d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1217d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return MODE_OK; 1227d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 1237d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1247d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, 1257d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *mode, 1267d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *adjusted_mode) 1277d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 1287d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return true; 1297d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 1307d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1319dff6af860d6b7f661d4360eb859837afaca0a1bMa Lingstatic void 1329dff6af860d6b7f661d4360eb859837afaca0a1bMa Lingintel_hdmi_sink_detect(struct drm_connector *connector) 1339dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling{ 1349dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling struct intel_output *intel_output = to_intel_output(connector); 1359dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; 1369dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling struct edid *edid = NULL; 1379dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling 1389dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling edid = drm_get_edid(&intel_output->base, 1399dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling &intel_output->ddc_bus->adapter); 1409dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling if (edid != NULL) { 1419dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid); 1429dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling kfree(edid); 1439dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling intel_output->base.display_info.raw_edid = NULL; 1449dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling } 1459dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling} 1469dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling 1477d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic enum drm_connector_status 1487d57382e65994ab7d01741373bd1c420370aed9fEric Anholtintel_hdmi_detect(struct drm_connector *connector) 1497d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 1507d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_device *dev = connector->dev; 1517d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_i915_private *dev_priv = dev->dev_private; 1527d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_output *intel_output = to_intel_output(connector); 1537d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; 1547d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 temp, bit; 1557d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1567d57382e65994ab7d01741373bd1c420370aed9fEric Anholt temp = I915_READ(PORT_HOTPLUG_EN); 1577d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1587d57382e65994ab7d01741373bd1c420370aed9fEric Anholt I915_WRITE(PORT_HOTPLUG_EN, 1597d57382e65994ab7d01741373bd1c420370aed9fEric Anholt temp | 1607d57382e65994ab7d01741373bd1c420370aed9fEric Anholt HDMIB_HOTPLUG_INT_EN | 1617d57382e65994ab7d01741373bd1c420370aed9fEric Anholt HDMIC_HOTPLUG_INT_EN | 1627d57382e65994ab7d01741373bd1c420370aed9fEric Anholt HDMID_HOTPLUG_INT_EN); 1637d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1647d57382e65994ab7d01741373bd1c420370aed9fEric Anholt POSTING_READ(PORT_HOTPLUG_EN); 1657d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1667d57382e65994ab7d01741373bd1c420370aed9fEric Anholt switch (hdmi_priv->sdvox_reg) { 1677d57382e65994ab7d01741373bd1c420370aed9fEric Anholt case SDVOB: 1687d57382e65994ab7d01741373bd1c420370aed9fEric Anholt bit = HDMIB_HOTPLUG_INT_STATUS; 1697d57382e65994ab7d01741373bd1c420370aed9fEric Anholt break; 1707d57382e65994ab7d01741373bd1c420370aed9fEric Anholt case SDVOC: 1717d57382e65994ab7d01741373bd1c420370aed9fEric Anholt bit = HDMIC_HOTPLUG_INT_STATUS; 1727d57382e65994ab7d01741373bd1c420370aed9fEric Anholt break; 1737d57382e65994ab7d01741373bd1c420370aed9fEric Anholt default: 1747d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return connector_status_unknown; 1757d57382e65994ab7d01741373bd1c420370aed9fEric Anholt } 1767d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1779dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0) { 1789dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling intel_hdmi_sink_detect(connector); 1797d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return connector_status_connected; 1809dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling } else 1817d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return connector_status_disconnected; 1827d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 1837d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1847d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic int intel_hdmi_get_modes(struct drm_connector *connector) 1857d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 1867d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_output *intel_output = to_intel_output(connector); 1877d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1887d57382e65994ab7d01741373bd1c420370aed9fEric Anholt /* We should parse the EDID data and find out if it's an HDMI sink so 1897d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * we can send audio to it. 1907d57382e65994ab7d01741373bd1c420370aed9fEric Anholt */ 1917d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1927d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return intel_ddc_get_modes(intel_output); 1937d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 1947d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1957d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic void intel_hdmi_destroy(struct drm_connector *connector) 1967d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 1977d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_output *intel_output = to_intel_output(connector); 1987d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1997d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (intel_output->i2c_bus) 2007d57382e65994ab7d01741373bd1c420370aed9fEric Anholt intel_i2c_destroy(intel_output->i2c_bus); 2017d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_sysfs_connector_remove(connector); 2027d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_connector_cleanup(connector); 2037d57382e65994ab7d01741373bd1c420370aed9fEric Anholt kfree(intel_output); 2047d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 2057d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2067d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { 2077d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .dpms = intel_hdmi_dpms, 2087d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .mode_fixup = intel_hdmi_mode_fixup, 2097d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .prepare = intel_encoder_prepare, 2107d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .mode_set = intel_hdmi_mode_set, 2117d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .commit = intel_encoder_commit, 2127d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 2137d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2147d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic const struct drm_connector_funcs intel_hdmi_connector_funcs = { 2157d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .save = intel_hdmi_save, 2167d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .restore = intel_hdmi_restore, 2177d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .detect = intel_hdmi_detect, 2187d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .fill_modes = drm_helper_probe_single_connector_modes, 2197d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .destroy = intel_hdmi_destroy, 2207d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 2217d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2227d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = { 2237d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .get_modes = intel_hdmi_get_modes, 2247d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .mode_valid = intel_hdmi_mode_valid, 2257d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .best_encoder = intel_best_encoder, 2267d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 2277d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2287d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic void intel_hdmi_enc_destroy(struct drm_encoder *encoder) 2297d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 2307d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_encoder_cleanup(encoder); 2317d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 2327d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2337d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic const struct drm_encoder_funcs intel_hdmi_enc_funcs = { 2347d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .destroy = intel_hdmi_enc_destroy, 2357d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 2367d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2377d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2387d57382e65994ab7d01741373bd1c420370aed9fEric Anholtvoid intel_hdmi_init(struct drm_device *dev, int sdvox_reg) 2397d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 2407d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_i915_private *dev_priv = dev->dev_private; 2417d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_connector *connector; 2427d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_output *intel_output; 2437d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_hdmi_priv *hdmi_priv; 2447d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2457d57382e65994ab7d01741373bd1c420370aed9fEric Anholt intel_output = kcalloc(sizeof(struct intel_output) + 2467d57382e65994ab7d01741373bd1c420370aed9fEric Anholt sizeof(struct intel_hdmi_priv), 1, GFP_KERNEL); 2477d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (!intel_output) 2487d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return; 2497d57382e65994ab7d01741373bd1c420370aed9fEric Anholt hdmi_priv = (struct intel_hdmi_priv *)(intel_output + 1); 2507d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2517d57382e65994ab7d01741373bd1c420370aed9fEric Anholt connector = &intel_output->base; 2527d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, 2537d57382e65994ab7d01741373bd1c420370aed9fEric Anholt DRM_MODE_CONNECTOR_DVID); 2547d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); 2557d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2567d57382e65994ab7d01741373bd1c420370aed9fEric Anholt intel_output->type = INTEL_OUTPUT_HDMI; 2577d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2587d57382e65994ab7d01741373bd1c420370aed9fEric Anholt connector->interlace_allowed = 0; 2597d57382e65994ab7d01741373bd1c420370aed9fEric Anholt connector->doublescan_allowed = 0; 2607d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2617d57382e65994ab7d01741373bd1c420370aed9fEric Anholt /* Set up the DDC bus. */ 2627d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (sdvox_reg == SDVOB) 2637d57382e65994ab7d01741373bd1c420370aed9fEric Anholt intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB"); 2647d57382e65994ab7d01741373bd1c420370aed9fEric Anholt else 2657d57382e65994ab7d01741373bd1c420370aed9fEric Anholt intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC"); 2667d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2677d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (!intel_output->ddc_bus) 2687d57382e65994ab7d01741373bd1c420370aed9fEric Anholt goto err_connector; 2697d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2707d57382e65994ab7d01741373bd1c420370aed9fEric Anholt hdmi_priv->sdvox_reg = sdvox_reg; 2717d57382e65994ab7d01741373bd1c420370aed9fEric Anholt intel_output->dev_priv = hdmi_priv; 2727d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2737d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_encoder_init(dev, &intel_output->enc, &intel_hdmi_enc_funcs, 2747d57382e65994ab7d01741373bd1c420370aed9fEric Anholt DRM_MODE_ENCODER_TMDS); 2757d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_encoder_helper_add(&intel_output->enc, &intel_hdmi_helper_funcs); 2767d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2777d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_mode_connector_attach_encoder(&intel_output->base, 2787d57382e65994ab7d01741373bd1c420370aed9fEric Anholt &intel_output->enc); 2797d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_sysfs_connector_add(connector); 2807d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2817d57382e65994ab7d01741373bd1c420370aed9fEric Anholt /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written 2827d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * 0xd. Failure to do so will result in spurious interrupts being 2837d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * generated on the port when a cable is not attached. 2847d57382e65994ab7d01741373bd1c420370aed9fEric Anholt */ 2857d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (IS_G4X(dev) && !IS_GM45(dev)) { 2867d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 temp = I915_READ(PEG_BAND_GAP_DATA); 2877d57382e65994ab7d01741373bd1c420370aed9fEric Anholt I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); 2887d57382e65994ab7d01741373bd1c420370aed9fEric Anholt } 2897d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2907d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return; 2917d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2927d57382e65994ab7d01741373bd1c420370aed9fEric Anholterr_connector: 2937d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_connector_cleanup(connector); 2947d57382e65994ab7d01741373bd1c420370aed9fEric Anholt kfree(intel_output); 2957d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2967d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return; 2977d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 298