1235783Skib/* 2235783Skib * Copyright 2006 Dave Airlie <airlied@linux.ie> 3235783Skib * Copyright �� 2006-2009 Intel Corporation 4235783Skib * 5235783Skib * Permission is hereby granted, free of charge, to any person obtaining a 6235783Skib * copy of this software and associated documentation files (the "Software"), 7235783Skib * to deal in the Software without restriction, including without limitation 8235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9235783Skib * and/or sell copies of the Software, and to permit persons to whom the 10235783Skib * Software is furnished to do so, subject to the following conditions: 11235783Skib * 12235783Skib * The above copyright notice and this permission notice (including the next 13235783Skib * paragraph) shall be included in all copies or substantial portions of the 14235783Skib * Software. 15235783Skib * 16235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19235783Skib * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20235783Skib * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21235783Skib * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22235783Skib * DEALINGS IN THE SOFTWARE. 23235783Skib * 24235783Skib * Authors: 25235783Skib * Eric Anholt <eric@anholt.net> 26235783Skib * Jesse Barnes <jesse.barnes@intel.com> 27235783Skib */ 28235783Skib 29235783Skib#include <sys/cdefs.h> 30235783Skib__FBSDID("$FreeBSD$"); 31235783Skib 32235783Skib#include <dev/drm2/drmP.h> 33235783Skib#include <dev/drm2/drm.h> 34235783Skib#include <dev/drm2/drm_crtc.h> 35235783Skib#include <dev/drm2/drm_edid.h> 36235783Skib#include <dev/drm2/i915/i915_drm.h> 37235783Skib#include <dev/drm2/i915/i915_drv.h> 38235783Skib#include <dev/drm2/i915/intel_drv.h> 39235783Skib 40235783Skibstruct intel_hdmi { 41235783Skib struct intel_encoder base; 42235783Skib u32 sdvox_reg; 43235783Skib int ddc_bus; 44235783Skib uint32_t color_range; 45235783Skib bool has_hdmi_sink; 46235783Skib bool has_audio; 47235783Skib enum hdmi_force_audio force_audio; 48235783Skib void (*write_infoframe)(struct drm_encoder *encoder, 49235783Skib struct dip_infoframe *frame); 50235783Skib}; 51235783Skib 52235783Skibstatic struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) 53235783Skib{ 54235783Skib return container_of(encoder, struct intel_hdmi, base.base); 55235783Skib} 56235783Skib 57235783Skibstatic struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) 58235783Skib{ 59235783Skib return container_of(intel_attached_encoder(connector), 60235783Skib struct intel_hdmi, base); 61235783Skib} 62235783Skib 63235783Skibvoid intel_dip_infoframe_csum(struct dip_infoframe *frame) 64235783Skib{ 65235783Skib uint8_t *data = (uint8_t *)frame; 66235783Skib uint8_t sum = 0; 67235783Skib unsigned i; 68235783Skib 69235783Skib frame->checksum = 0; 70235783Skib frame->ecc = 0; 71235783Skib 72235783Skib for (i = 0; i < frame->len + DIP_HEADER_SIZE; i++) 73235783Skib sum += data[i]; 74235783Skib 75235783Skib frame->checksum = 0x100 - sum; 76235783Skib} 77235783Skib 78235783Skibstatic u32 intel_infoframe_index(struct dip_infoframe *frame) 79235783Skib{ 80235783Skib u32 flags = 0; 81235783Skib 82235783Skib switch (frame->type) { 83235783Skib case DIP_TYPE_AVI: 84235783Skib flags |= VIDEO_DIP_SELECT_AVI; 85235783Skib break; 86235783Skib case DIP_TYPE_SPD: 87235783Skib flags |= VIDEO_DIP_SELECT_SPD; 88235783Skib break; 89235783Skib default: 90235783Skib DRM_DEBUG("unknown info frame type %d\n", frame->type); 91235783Skib break; 92235783Skib } 93235783Skib 94235783Skib return flags; 95235783Skib} 96235783Skib 97235783Skibstatic u32 intel_infoframe_flags(struct dip_infoframe *frame) 98235783Skib{ 99235783Skib u32 flags = 0; 100235783Skib 101235783Skib switch (frame->type) { 102235783Skib case DIP_TYPE_AVI: 103235783Skib flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC; 104235783Skib break; 105235783Skib case DIP_TYPE_SPD: 106235783Skib flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_VSYNC; 107235783Skib break; 108235783Skib default: 109235783Skib DRM_DEBUG("unknown info frame type %d\n", frame->type); 110235783Skib break; 111235783Skib } 112235783Skib 113235783Skib return flags; 114235783Skib} 115235783Skib 116235783Skibstatic void i9xx_write_infoframe(struct drm_encoder *encoder, 117235783Skib struct dip_infoframe *frame) 118235783Skib{ 119235783Skib uint32_t *data = (uint32_t *)frame; 120235783Skib struct drm_device *dev = encoder->dev; 121235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 122235783Skib struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 123235783Skib u32 port, flags, val = I915_READ(VIDEO_DIP_CTL); 124235783Skib unsigned i, len = DIP_HEADER_SIZE + frame->len; 125235783Skib 126235783Skib 127235783Skib /* XXX first guess at handling video port, is this corrent? */ 128235783Skib if (intel_hdmi->sdvox_reg == SDVOB) 129235783Skib port = VIDEO_DIP_PORT_B; 130235783Skib else if (intel_hdmi->sdvox_reg == SDVOC) 131235783Skib port = VIDEO_DIP_PORT_C; 132235783Skib else 133235783Skib return; 134235783Skib 135235783Skib flags = intel_infoframe_index(frame); 136235783Skib 137235783Skib val &= ~VIDEO_DIP_SELECT_MASK; 138235783Skib 139235783Skib I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags); 140235783Skib 141235783Skib for (i = 0; i < len; i += 4) { 142235783Skib I915_WRITE(VIDEO_DIP_DATA, *data); 143235783Skib data++; 144235783Skib } 145235783Skib 146235783Skib flags |= intel_infoframe_flags(frame); 147235783Skib 148235783Skib I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags); 149235783Skib} 150235783Skib 151235783Skibstatic void ironlake_write_infoframe(struct drm_encoder *encoder, 152235783Skib struct dip_infoframe *frame) 153235783Skib{ 154235783Skib uint32_t *data = (uint32_t *)frame; 155235783Skib struct drm_device *dev = encoder->dev; 156235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 157235783Skib struct drm_crtc *crtc = encoder->crtc; 158235783Skib struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 159235783Skib int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 160235783Skib unsigned i, len = DIP_HEADER_SIZE + frame->len; 161235783Skib u32 flags, val = I915_READ(reg); 162235783Skib 163235783Skib intel_wait_for_vblank(dev, intel_crtc->pipe); 164235783Skib 165235783Skib flags = intel_infoframe_index(frame); 166235783Skib 167235783Skib val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 168235783Skib 169235783Skib I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags); 170235783Skib 171235783Skib for (i = 0; i < len; i += 4) { 172235783Skib I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 173235783Skib data++; 174235783Skib } 175235783Skib 176235783Skib flags |= intel_infoframe_flags(frame); 177235783Skib 178235783Skib I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags); 179235783Skib} 180235783Skib 181235783Skibstatic void intel_set_infoframe(struct drm_encoder *encoder, 182235783Skib struct dip_infoframe *frame) 183235783Skib{ 184235783Skib struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 185235783Skib 186235783Skib if (!intel_hdmi->has_hdmi_sink) 187235783Skib return; 188235783Skib 189235783Skib intel_dip_infoframe_csum(frame); 190235783Skib intel_hdmi->write_infoframe(encoder, frame); 191235783Skib} 192235783Skib 193235783Skibstatic void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) 194235783Skib{ 195235783Skib struct dip_infoframe avi_if = { 196235783Skib .type = DIP_TYPE_AVI, 197235783Skib .ver = DIP_VERSION_AVI, 198235783Skib .len = DIP_LEN_AVI, 199235783Skib }; 200235783Skib 201235783Skib intel_set_infoframe(encoder, &avi_if); 202235783Skib} 203235783Skib 204235783Skibstatic void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) 205235783Skib{ 206235783Skib struct dip_infoframe spd_if; 207235783Skib 208235783Skib memset(&spd_if, 0, sizeof(spd_if)); 209235783Skib spd_if.type = DIP_TYPE_SPD; 210235783Skib spd_if.ver = DIP_VERSION_SPD; 211235783Skib spd_if.len = DIP_LEN_SPD; 212235783Skib strcpy(spd_if.body.spd.vn, "Intel"); 213235783Skib strcpy(spd_if.body.spd.pd, "Integrated gfx"); 214235783Skib spd_if.body.spd.sdi = DIP_SPD_PC; 215235783Skib 216235783Skib intel_set_infoframe(encoder, &spd_if); 217235783Skib} 218235783Skib 219235783Skibstatic void intel_hdmi_mode_set(struct drm_encoder *encoder, 220235783Skib struct drm_display_mode *mode, 221235783Skib struct drm_display_mode *adjusted_mode) 222235783Skib{ 223235783Skib struct drm_device *dev = encoder->dev; 224235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 225235783Skib struct drm_crtc *crtc = encoder->crtc; 226235783Skib struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 227235783Skib struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 228235783Skib u32 sdvox; 229235783Skib 230235783Skib sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE; 231235783Skib if (!HAS_PCH_SPLIT(dev)) 232235783Skib sdvox |= intel_hdmi->color_range; 233235783Skib if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 234235783Skib sdvox |= SDVO_VSYNC_ACTIVE_HIGH; 235235783Skib if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 236235783Skib sdvox |= SDVO_HSYNC_ACTIVE_HIGH; 237235783Skib 238235783Skib if (intel_crtc->bpp > 24) 239235783Skib sdvox |= COLOR_FORMAT_12bpc; 240235783Skib else 241235783Skib sdvox |= COLOR_FORMAT_8bpc; 242235783Skib 243235783Skib /* Required on CPT */ 244235783Skib if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) 245235783Skib sdvox |= HDMI_MODE_SELECT; 246235783Skib 247235783Skib if (intel_hdmi->has_audio) { 248235783Skib DRM_DEBUG_KMS("Enabling HDMI audio on pipe %c\n", 249235783Skib pipe_name(intel_crtc->pipe)); 250235783Skib sdvox |= SDVO_AUDIO_ENABLE; 251235783Skib sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC; 252235783Skib intel_write_eld(encoder, adjusted_mode); 253235783Skib } 254235783Skib 255235783Skib if (HAS_PCH_CPT(dev)) 256235783Skib sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe); 257235783Skib else if (intel_crtc->pipe == 1) 258235783Skib sdvox |= SDVO_PIPE_B_SELECT; 259235783Skib 260235783Skib I915_WRITE(intel_hdmi->sdvox_reg, sdvox); 261235783Skib POSTING_READ(intel_hdmi->sdvox_reg); 262235783Skib 263235783Skib intel_hdmi_set_avi_infoframe(encoder); 264235783Skib intel_hdmi_set_spd_infoframe(encoder); 265235783Skib} 266235783Skib 267235783Skibstatic void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) 268235783Skib{ 269235783Skib struct drm_device *dev = encoder->dev; 270235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 271235783Skib struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 272235783Skib u32 temp; 273235783Skib u32 enable_bits = SDVO_ENABLE; 274235783Skib 275235783Skib if (intel_hdmi->has_audio) 276235783Skib enable_bits |= SDVO_AUDIO_ENABLE; 277235783Skib 278235783Skib temp = I915_READ(intel_hdmi->sdvox_reg); 279235783Skib 280235783Skib /* HW workaround, need to toggle enable bit off and on for 12bpc, but 281235783Skib * we do this anyway which shows more stable in testing. 282235783Skib */ 283235783Skib if (HAS_PCH_SPLIT(dev)) { 284235783Skib I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); 285235783Skib POSTING_READ(intel_hdmi->sdvox_reg); 286235783Skib } 287235783Skib 288235783Skib if (mode != DRM_MODE_DPMS_ON) { 289235783Skib temp &= ~enable_bits; 290235783Skib } else { 291235783Skib temp |= enable_bits; 292235783Skib } 293235783Skib 294235783Skib I915_WRITE(intel_hdmi->sdvox_reg, temp); 295235783Skib POSTING_READ(intel_hdmi->sdvox_reg); 296235783Skib 297235783Skib /* HW workaround, need to write this twice for issue that may result 298235783Skib * in first write getting masked. 299235783Skib */ 300235783Skib if (HAS_PCH_SPLIT(dev)) { 301235783Skib I915_WRITE(intel_hdmi->sdvox_reg, temp); 302235783Skib POSTING_READ(intel_hdmi->sdvox_reg); 303235783Skib } 304235783Skib} 305235783Skib 306235783Skibstatic int intel_hdmi_mode_valid(struct drm_connector *connector, 307235783Skib struct drm_display_mode *mode) 308235783Skib{ 309235783Skib if (mode->clock > 165000) 310235783Skib return MODE_CLOCK_HIGH; 311235783Skib if (mode->clock < 20000) 312235783Skib return MODE_CLOCK_LOW; 313235783Skib 314235783Skib if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 315235783Skib return MODE_NO_DBLESCAN; 316235783Skib 317235783Skib return MODE_OK; 318235783Skib} 319235783Skib 320235783Skibstatic bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, 321254797Sdumbbell const struct drm_display_mode *mode, 322235783Skib struct drm_display_mode *adjusted_mode) 323235783Skib{ 324235783Skib return true; 325235783Skib} 326235783Skib 327235783Skibstatic enum drm_connector_status 328235783Skibintel_hdmi_detect(struct drm_connector *connector, bool force) 329235783Skib{ 330235783Skib struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 331235783Skib struct drm_i915_private *dev_priv = connector->dev->dev_private; 332235783Skib struct edid *edid; 333235783Skib enum drm_connector_status status = connector_status_disconnected; 334235783Skib 335235783Skib intel_hdmi->has_hdmi_sink = false; 336235783Skib intel_hdmi->has_audio = false; 337235783Skib edid = drm_get_edid(connector, dev_priv->gmbus[intel_hdmi->ddc_bus]); 338235783Skib 339235783Skib if (edid) { 340235783Skib if (edid->input & DRM_EDID_INPUT_DIGITAL) { 341235783Skib status = connector_status_connected; 342235783Skib if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI) 343235783Skib intel_hdmi->has_hdmi_sink = 344235783Skib drm_detect_hdmi_monitor(edid); 345235783Skib intel_hdmi->has_audio = drm_detect_monitor_audio(edid); 346235783Skib } 347235783Skib connector->display_info.raw_edid = NULL; 348235783Skib free(edid, DRM_MEM_KMS); 349235783Skib } else { 350235783Skib DRM_DEBUG_KMS("[CONNECTOR:%d:%s] got no edid, ddc port %d\n", 351235783Skib connector->base.id, drm_get_connector_name(connector), 352235783Skib intel_hdmi->ddc_bus); 353235783Skib } 354235783Skib 355235783Skib if (status == connector_status_connected) { 356235783Skib if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO) 357235783Skib intel_hdmi->has_audio = 358235783Skib (intel_hdmi->force_audio == HDMI_AUDIO_ON); 359235783Skib } 360235783Skib 361235783Skib return status; 362235783Skib} 363235783Skib 364235783Skibstatic int intel_hdmi_get_modes(struct drm_connector *connector) 365235783Skib{ 366235783Skib struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 367235783Skib struct drm_i915_private *dev_priv = connector->dev->dev_private; 368235783Skib 369235783Skib /* We should parse the EDID data and find out if it's an HDMI sink so 370235783Skib * we can send audio to it. 371235783Skib */ 372235783Skib 373235783Skib return intel_ddc_get_modes(connector, 374235783Skib dev_priv->gmbus[intel_hdmi->ddc_bus]); 375235783Skib} 376235783Skib 377235783Skibstatic bool 378235783Skibintel_hdmi_detect_audio(struct drm_connector *connector) 379235783Skib{ 380235783Skib struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 381235783Skib struct drm_i915_private *dev_priv = connector->dev->dev_private; 382235783Skib struct edid *edid; 383235783Skib bool has_audio = false; 384235783Skib 385235783Skib edid = drm_get_edid(connector, dev_priv->gmbus[intel_hdmi->ddc_bus]); 386235783Skib if (edid) { 387235783Skib if (edid->input & DRM_EDID_INPUT_DIGITAL) 388235783Skib has_audio = drm_detect_monitor_audio(edid); 389235783Skib 390235783Skib connector->display_info.raw_edid = NULL; 391235783Skib free(edid, DRM_MEM_KMS); 392235783Skib } 393235783Skib 394235783Skib return has_audio; 395235783Skib} 396235783Skib 397235783Skibstatic int 398235783Skibintel_hdmi_set_property(struct drm_connector *connector, 399235783Skib struct drm_property *property, 400235783Skib uint64_t val) 401235783Skib{ 402235783Skib struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 403235783Skib struct drm_i915_private *dev_priv = connector->dev->dev_private; 404235783Skib int ret; 405235783Skib 406235783Skib ret = drm_connector_property_set_value(connector, property, val); 407235783Skib if (ret) 408235783Skib return ret; 409235783Skib 410235783Skib if (property == dev_priv->force_audio_property) { 411235783Skib enum hdmi_force_audio i = val; 412235783Skib bool has_audio; 413235783Skib 414235783Skib if (i == intel_hdmi->force_audio) 415235783Skib return 0; 416235783Skib 417235783Skib intel_hdmi->force_audio = i; 418235783Skib 419235783Skib if (i == HDMI_AUDIO_AUTO) 420235783Skib has_audio = intel_hdmi_detect_audio(connector); 421235783Skib else 422235783Skib has_audio = (i == HDMI_AUDIO_ON); 423235783Skib 424235783Skib if (i == HDMI_AUDIO_OFF_DVI) 425235783Skib intel_hdmi->has_hdmi_sink = 0; 426235783Skib 427235783Skib intel_hdmi->has_audio = has_audio; 428235783Skib goto done; 429235783Skib } 430235783Skib 431235783Skib if (property == dev_priv->broadcast_rgb_property) { 432235783Skib if (val == !!intel_hdmi->color_range) 433235783Skib return 0; 434235783Skib 435235783Skib intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; 436235783Skib goto done; 437235783Skib } 438235783Skib 439235783Skib return -EINVAL; 440235783Skib 441235783Skibdone: 442235783Skib if (intel_hdmi->base.base.crtc) { 443235783Skib struct drm_crtc *crtc = intel_hdmi->base.base.crtc; 444235783Skib drm_crtc_helper_set_mode(crtc, &crtc->mode, 445235783Skib crtc->x, crtc->y, 446235783Skib crtc->fb); 447235783Skib } 448235783Skib 449235783Skib return 0; 450235783Skib} 451235783Skib 452235783Skibstatic void intel_hdmi_destroy(struct drm_connector *connector) 453235783Skib{ 454235783Skib#if 0 455235783Skib drm_sysfs_connector_remove(connector); 456235783Skib#endif 457235783Skib drm_connector_cleanup(connector); 458235783Skib free(connector, DRM_MEM_KMS); 459235783Skib} 460235783Skib 461235783Skibstatic const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { 462235783Skib .dpms = intel_hdmi_dpms, 463235783Skib .mode_fixup = intel_hdmi_mode_fixup, 464235783Skib .prepare = intel_encoder_prepare, 465235783Skib .mode_set = intel_hdmi_mode_set, 466235783Skib .commit = intel_encoder_commit, 467235783Skib}; 468235783Skib 469235783Skibstatic const struct drm_connector_funcs intel_hdmi_connector_funcs = { 470235783Skib .dpms = drm_helper_connector_dpms, 471235783Skib .detect = intel_hdmi_detect, 472235783Skib .fill_modes = drm_helper_probe_single_connector_modes, 473235783Skib .set_property = intel_hdmi_set_property, 474235783Skib .destroy = intel_hdmi_destroy, 475235783Skib}; 476235783Skib 477235783Skibstatic const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = { 478235783Skib .get_modes = intel_hdmi_get_modes, 479235783Skib .mode_valid = intel_hdmi_mode_valid, 480235783Skib .best_encoder = intel_best_encoder, 481235783Skib}; 482235783Skib 483235783Skibstatic const struct drm_encoder_funcs intel_hdmi_enc_funcs = { 484235783Skib .destroy = intel_encoder_destroy, 485235783Skib}; 486235783Skib 487235783Skibstatic void 488235783Skibintel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector) 489235783Skib{ 490235783Skib intel_attach_force_audio_property(connector); 491235783Skib intel_attach_broadcast_rgb_property(connector); 492235783Skib} 493235783Skib 494235783Skibvoid intel_hdmi_init(struct drm_device *dev, int sdvox_reg) 495235783Skib{ 496235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 497235783Skib struct drm_connector *connector; 498235783Skib struct intel_encoder *intel_encoder; 499235783Skib struct intel_connector *intel_connector; 500235783Skib struct intel_hdmi *intel_hdmi; 501235783Skib int i; 502235783Skib 503235783Skib intel_hdmi = malloc(sizeof(struct intel_hdmi), DRM_MEM_KMS, 504235783Skib M_WAITOK | M_ZERO); 505235783Skib intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS, 506235783Skib M_WAITOK | M_ZERO); 507235783Skib 508235783Skib intel_encoder = &intel_hdmi->base; 509235783Skib drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, 510235783Skib DRM_MODE_ENCODER_TMDS); 511235783Skib 512235783Skib connector = &intel_connector->base; 513235783Skib drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, 514235783Skib DRM_MODE_CONNECTOR_HDMIA); 515235783Skib drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); 516235783Skib 517235783Skib intel_encoder->type = INTEL_OUTPUT_HDMI; 518235783Skib 519235783Skib connector->polled = DRM_CONNECTOR_POLL_HPD; 520235783Skib connector->interlace_allowed = 1; 521235783Skib connector->doublescan_allowed = 0; 522235783Skib intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); 523235783Skib 524235783Skib /* Set up the DDC bus. */ 525235783Skib if (sdvox_reg == SDVOB) { 526235783Skib intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT); 527235783Skib intel_hdmi->ddc_bus = GMBUS_PORT_DPB; 528235783Skib dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; 529235783Skib } else if (sdvox_reg == SDVOC) { 530235783Skib intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); 531235783Skib intel_hdmi->ddc_bus = GMBUS_PORT_DPC; 532235783Skib dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; 533235783Skib } else if (sdvox_reg == HDMIB) { 534235783Skib intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); 535235783Skib intel_hdmi->ddc_bus = GMBUS_PORT_DPB; 536235783Skib dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; 537235783Skib } else if (sdvox_reg == HDMIC) { 538235783Skib intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT); 539235783Skib intel_hdmi->ddc_bus = GMBUS_PORT_DPC; 540235783Skib dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; 541235783Skib } else if (sdvox_reg == HDMID) { 542235783Skib intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT); 543235783Skib intel_hdmi->ddc_bus = GMBUS_PORT_DPD; 544235783Skib dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; 545235783Skib } 546235783Skib 547235783Skib 548235783Skib intel_hdmi->sdvox_reg = sdvox_reg; 549235783Skib 550235783Skib if (!HAS_PCH_SPLIT(dev)) { 551235783Skib intel_hdmi->write_infoframe = i9xx_write_infoframe; 552235783Skib I915_WRITE(VIDEO_DIP_CTL, 0); 553235783Skib } else { 554235783Skib intel_hdmi->write_infoframe = ironlake_write_infoframe; 555235783Skib for_each_pipe(i) 556235783Skib I915_WRITE(TVIDEO_DIP_CTL(i), 0); 557235783Skib } 558235783Skib 559235783Skib drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); 560235783Skib 561235783Skib intel_hdmi_add_properties(intel_hdmi, connector); 562235783Skib 563235783Skib intel_connector_attach_encoder(intel_connector, intel_encoder); 564235783Skib#if 0 565235783Skib drm_sysfs_connector_add(connector); 566235783Skib#endif 567235783Skib 568235783Skib /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written 569235783Skib * 0xd. Failure to do so will result in spurious interrupts being 570235783Skib * generated on the port when a cable is not attached. 571235783Skib */ 572235783Skib if (IS_G4X(dev) && !IS_GM45(dev)) { 573235783Skib u32 temp = I915_READ(PEG_BAND_GAP_DATA); 574235783Skib I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); 575235783Skib } 576235783Skib} 577