1235783Skib/* 2235783Skib * Copyright �� 2006-2007 Intel Corporation 3235783Skib * 4235783Skib * Permission is hereby granted, free of charge, to any person obtaining a 5235783Skib * copy of this software and associated documentation files (the "Software"), 6235783Skib * to deal in the Software without restriction, including without limitation 7235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8235783Skib * and/or sell copies of the Software, and to permit persons to whom the 9235783Skib * Software is furnished to do so, subject to the following conditions: 10235783Skib * 11235783Skib * The above copyright notice and this permission notice (including the next 12235783Skib * paragraph) shall be included in all copies or substantial portions of the 13235783Skib * Software. 14235783Skib * 15235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18235783Skib * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19235783Skib * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20235783Skib * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21235783Skib * DEALINGS IN THE SOFTWARE. 22235783Skib * 23235783Skib * Authors: 24235783Skib * Eric Anholt <eric@anholt.net> 25235783Skib */ 26235783Skib 27235783Skib#include <sys/cdefs.h> 28235783Skib__FBSDID("$FreeBSD: releng/10.3/sys/dev/drm2/i915/intel_crt.c 282199 2015-04-28 19:35:05Z dumbbell $"); 29235783Skib 30235783Skib#include <dev/drm2/drmP.h> 31235783Skib#include <dev/drm2/drm.h> 32235783Skib#include <dev/drm2/drm_crtc.h> 33235783Skib#include <dev/drm2/drm_crtc_helper.h> 34235783Skib#include <dev/drm2/drm_edid.h> 35235783Skib#include <dev/drm2/i915/i915_drm.h> 36235783Skib#include <dev/drm2/i915/i915_drv.h> 37235783Skib#include <dev/drm2/i915/intel_drv.h> 38235783Skib 39235783Skib/* Here's the desired hotplug mode */ 40235783Skib#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 | \ 41235783Skib ADPA_CRT_HOTPLUG_WARMUP_10MS | \ 42235783Skib ADPA_CRT_HOTPLUG_SAMPLE_4S | \ 43235783Skib ADPA_CRT_HOTPLUG_VOLTAGE_50 | \ 44235783Skib ADPA_CRT_HOTPLUG_VOLREF_325MV | \ 45235783Skib ADPA_CRT_HOTPLUG_ENABLE) 46235783Skib 47235783Skibstruct intel_crt { 48235783Skib struct intel_encoder base; 49235783Skib bool force_hotplug_required; 50235783Skib}; 51235783Skib 52235783Skibstatic struct intel_crt *intel_attached_crt(struct drm_connector *connector) 53235783Skib{ 54235783Skib return container_of(intel_attached_encoder(connector), 55235783Skib struct intel_crt, base); 56235783Skib} 57235783Skib 58280369Skibstatic void pch_crt_dpms(struct drm_encoder *encoder, int mode) 59235783Skib{ 60235783Skib struct drm_device *dev = encoder->dev; 61235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 62280369Skib u32 temp; 63235783Skib 64280369Skib temp = I915_READ(PCH_ADPA); 65280369Skib temp &= ~ADPA_DAC_ENABLE; 66235783Skib 67280369Skib switch (mode) { 68280369Skib case DRM_MODE_DPMS_ON: 69280369Skib temp |= ADPA_DAC_ENABLE; 70280369Skib break; 71280369Skib case DRM_MODE_DPMS_STANDBY: 72280369Skib case DRM_MODE_DPMS_SUSPEND: 73280369Skib case DRM_MODE_DPMS_OFF: 74280369Skib /* Just leave port enable cleared */ 75280369Skib break; 76280369Skib } 77280369Skib 78280369Skib I915_WRITE(PCH_ADPA, temp); 79280369Skib} 80280369Skib 81280369Skibstatic void gmch_crt_dpms(struct drm_encoder *encoder, int mode) 82280369Skib{ 83280369Skib struct drm_device *dev = encoder->dev; 84280369Skib struct drm_i915_private *dev_priv = dev->dev_private; 85280369Skib u32 temp; 86280369Skib 87280369Skib temp = I915_READ(ADPA); 88235783Skib temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); 89235783Skib temp &= ~ADPA_DAC_ENABLE; 90235783Skib 91235783Skib switch (mode) { 92235783Skib case DRM_MODE_DPMS_ON: 93235783Skib temp |= ADPA_DAC_ENABLE; 94235783Skib break; 95235783Skib case DRM_MODE_DPMS_STANDBY: 96235783Skib temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; 97235783Skib break; 98235783Skib case DRM_MODE_DPMS_SUSPEND: 99235783Skib temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; 100235783Skib break; 101235783Skib case DRM_MODE_DPMS_OFF: 102235783Skib temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; 103235783Skib break; 104235783Skib } 105235783Skib 106280369Skib I915_WRITE(ADPA, temp); 107235783Skib} 108235783Skib 109235783Skibstatic int intel_crt_mode_valid(struct drm_connector *connector, 110235783Skib struct drm_display_mode *mode) 111235783Skib{ 112235783Skib struct drm_device *dev = connector->dev; 113235783Skib 114235783Skib int max_clock = 0; 115235783Skib if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 116235783Skib return MODE_NO_DBLESCAN; 117235783Skib 118235783Skib if (mode->clock < 25000) 119235783Skib return MODE_CLOCK_LOW; 120235783Skib 121235783Skib if (IS_GEN2(dev)) 122235783Skib max_clock = 350000; 123235783Skib else 124235783Skib max_clock = 400000; 125235783Skib if (mode->clock > max_clock) 126235783Skib return MODE_CLOCK_HIGH; 127235783Skib 128235783Skib return MODE_OK; 129235783Skib} 130235783Skib 131235783Skibstatic bool intel_crt_mode_fixup(struct drm_encoder *encoder, 132282199Sdumbbell const struct drm_display_mode *mode, 133235783Skib struct drm_display_mode *adjusted_mode) 134235783Skib{ 135235783Skib return true; 136235783Skib} 137235783Skib 138235783Skibstatic void intel_crt_mode_set(struct drm_encoder *encoder, 139235783Skib struct drm_display_mode *mode, 140235783Skib struct drm_display_mode *adjusted_mode) 141235783Skib{ 142235783Skib 143235783Skib struct drm_device *dev = encoder->dev; 144235783Skib struct drm_crtc *crtc = encoder->crtc; 145235783Skib struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 146235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 147235783Skib int dpll_md_reg; 148235783Skib u32 adpa, dpll_md; 149235783Skib u32 adpa_reg; 150235783Skib 151235783Skib dpll_md_reg = DPLL_MD(intel_crtc->pipe); 152235783Skib 153235783Skib if (HAS_PCH_SPLIT(dev)) 154235783Skib adpa_reg = PCH_ADPA; 155235783Skib else 156235783Skib adpa_reg = ADPA; 157235783Skib 158235783Skib /* 159235783Skib * Disable separate mode multiplier used when cloning SDVO to CRT 160235783Skib * XXX this needs to be adjusted when we really are cloning 161235783Skib */ 162235783Skib if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { 163235783Skib dpll_md = I915_READ(dpll_md_reg); 164235783Skib I915_WRITE(dpll_md_reg, 165235783Skib dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); 166235783Skib } 167235783Skib 168235783Skib adpa = ADPA_HOTPLUG_BITS; 169235783Skib if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 170235783Skib adpa |= ADPA_HSYNC_ACTIVE_HIGH; 171235783Skib if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 172235783Skib adpa |= ADPA_VSYNC_ACTIVE_HIGH; 173235783Skib 174235783Skib /* For CPT allow 3 pipe config, for others just use A or B */ 175235783Skib if (HAS_PCH_CPT(dev)) 176235783Skib adpa |= PORT_TRANS_SEL_CPT(intel_crtc->pipe); 177235783Skib else if (intel_crtc->pipe == 0) 178235783Skib adpa |= ADPA_PIPE_A_SELECT; 179235783Skib else 180235783Skib adpa |= ADPA_PIPE_B_SELECT; 181235783Skib 182235783Skib if (!HAS_PCH_SPLIT(dev)) 183235783Skib I915_WRITE(BCLRPAT(intel_crtc->pipe), 0); 184235783Skib 185235783Skib I915_WRITE(adpa_reg, adpa); 186235783Skib} 187235783Skib 188235783Skibstatic bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) 189235783Skib{ 190235783Skib struct drm_device *dev = connector->dev; 191235783Skib struct intel_crt *crt = intel_attached_crt(connector); 192235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 193235783Skib u32 adpa; 194235783Skib bool ret; 195235783Skib 196235783Skib /* The first time through, trigger an explicit detection cycle */ 197235783Skib if (crt->force_hotplug_required) { 198235783Skib bool turn_off_dac = HAS_PCH_SPLIT(dev); 199235783Skib u32 save_adpa; 200235783Skib 201235783Skib crt->force_hotplug_required = 0; 202235783Skib 203235783Skib save_adpa = adpa = I915_READ(PCH_ADPA); 204235783Skib DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); 205235783Skib 206235783Skib adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; 207235783Skib if (turn_off_dac) 208235783Skib adpa &= ~ADPA_DAC_ENABLE; 209235783Skib 210235783Skib I915_WRITE(PCH_ADPA, adpa); 211235783Skib 212235783Skib if (_intel_wait_for(dev, 213235783Skib (I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, 214235783Skib 1000, 1, "915crt")) 215235783Skib DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER\n"); 216235783Skib 217235783Skib if (turn_off_dac) { 218235783Skib I915_WRITE(PCH_ADPA, save_adpa); 219235783Skib POSTING_READ(PCH_ADPA); 220235783Skib } 221235783Skib } 222235783Skib 223235783Skib /* Check the status to see if both blue and green are on now */ 224235783Skib adpa = I915_READ(PCH_ADPA); 225235783Skib if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) 226235783Skib ret = true; 227235783Skib else 228235783Skib ret = false; 229235783Skib DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret); 230235783Skib 231235783Skib return ret; 232235783Skib} 233235783Skib 234235783Skib/** 235235783Skib * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. 236235783Skib * 237235783Skib * Not for i915G/i915GM 238235783Skib * 239235783Skib * \return true if CRT is connected. 240235783Skib * \return false if CRT is disconnected. 241235783Skib */ 242235783Skibstatic bool intel_crt_detect_hotplug(struct drm_connector *connector) 243235783Skib{ 244235783Skib struct drm_device *dev = connector->dev; 245235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 246235783Skib u32 hotplug_en, orig, stat; 247235783Skib bool ret = false; 248235783Skib int i, tries = 0; 249235783Skib 250235783Skib if (HAS_PCH_SPLIT(dev)) 251235783Skib return intel_ironlake_crt_detect_hotplug(connector); 252235783Skib 253235783Skib /* 254235783Skib * On 4 series desktop, CRT detect sequence need to be done twice 255235783Skib * to get a reliable result. 256235783Skib */ 257235783Skib 258235783Skib if (IS_G4X(dev) && !IS_GM45(dev)) 259235783Skib tries = 2; 260235783Skib else 261235783Skib tries = 1; 262235783Skib hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN); 263235783Skib hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; 264235783Skib 265235783Skib for (i = 0; i < tries ; i++) { 266235783Skib /* turn on the FORCE_DETECT */ 267235783Skib I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); 268235783Skib /* wait for FORCE_DETECT to go off */ 269235783Skib if (_intel_wait_for(dev, 270235783Skib (I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0, 271235783Skib 1000, 1, "915cr2")) 272235783Skib DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off"); 273235783Skib } 274235783Skib 275235783Skib stat = I915_READ(PORT_HOTPLUG_STAT); 276235783Skib if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE) 277235783Skib ret = true; 278235783Skib 279235783Skib /* clear the interrupt we just generated, if any */ 280235783Skib I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS); 281235783Skib 282235783Skib /* and put the bits back */ 283235783Skib I915_WRITE(PORT_HOTPLUG_EN, orig); 284235783Skib 285235783Skib return ret; 286235783Skib} 287235783Skib 288235783Skibstatic bool intel_crt_detect_ddc(struct drm_connector *connector) 289235783Skib{ 290235783Skib struct intel_crt *crt = intel_attached_crt(connector); 291235783Skib struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private; 292235783Skib 293235783Skib /* CRT should always be at 0, but check anyway */ 294235783Skib if (crt->base.type != INTEL_OUTPUT_ANALOG) 295235783Skib return false; 296235783Skib 297235783Skib if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) { 298235783Skib struct edid *edid; 299235783Skib bool is_digital = false; 300280369Skib device_t iic; 301235783Skib 302280369Skib iic = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin); 303280369Skib edid = drm_get_edid(connector, iic); 304235783Skib /* 305235783Skib * This may be a DVI-I connector with a shared DDC 306235783Skib * link between analog and digital outputs, so we 307235783Skib * have to check the EDID input spec of the attached device. 308235783Skib * 309235783Skib * On the other hand, what should we do if it is a broken EDID? 310235783Skib */ 311235783Skib if (edid != NULL) { 312235783Skib is_digital = edid->input & DRM_EDID_INPUT_DIGITAL; 313235783Skib free(edid, DRM_MEM_KMS); 314235783Skib } 315235783Skib 316235783Skib if (!is_digital) { 317235783Skib DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n"); 318235783Skib return true; 319235783Skib } else { 320235783Skib DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n"); 321235783Skib } 322235783Skib } 323235783Skib 324235783Skib return false; 325235783Skib} 326235783Skib 327235783Skibstatic enum drm_connector_status 328235783Skibintel_crt_load_detect(struct intel_crt *crt) 329235783Skib{ 330235783Skib struct drm_device *dev = crt->base.base.dev; 331235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 332235783Skib uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe; 333235783Skib uint32_t save_bclrpat; 334235783Skib uint32_t save_vtotal; 335235783Skib uint32_t vtotal, vactive; 336235783Skib uint32_t vsample; 337235783Skib uint32_t vblank, vblank_start, vblank_end; 338235783Skib uint32_t dsl; 339235783Skib uint32_t bclrpat_reg; 340235783Skib uint32_t vtotal_reg; 341235783Skib uint32_t vblank_reg; 342235783Skib uint32_t vsync_reg; 343235783Skib uint32_t pipeconf_reg; 344235783Skib uint32_t pipe_dsl_reg; 345235783Skib uint8_t st00; 346235783Skib enum drm_connector_status status; 347235783Skib 348235783Skib DRM_DEBUG_KMS("starting load-detect on CRT\n"); 349235783Skib 350235783Skib bclrpat_reg = BCLRPAT(pipe); 351235783Skib vtotal_reg = VTOTAL(pipe); 352235783Skib vblank_reg = VBLANK(pipe); 353235783Skib vsync_reg = VSYNC(pipe); 354235783Skib pipeconf_reg = PIPECONF(pipe); 355235783Skib pipe_dsl_reg = PIPEDSL(pipe); 356235783Skib 357235783Skib save_bclrpat = I915_READ(bclrpat_reg); 358235783Skib save_vtotal = I915_READ(vtotal_reg); 359235783Skib vblank = I915_READ(vblank_reg); 360235783Skib 361235783Skib vtotal = ((save_vtotal >> 16) & 0xfff) + 1; 362235783Skib vactive = (save_vtotal & 0x7ff) + 1; 363235783Skib 364235783Skib vblank_start = (vblank & 0xfff) + 1; 365235783Skib vblank_end = ((vblank >> 16) & 0xfff) + 1; 366235783Skib 367235783Skib /* Set the border color to purple. */ 368235783Skib I915_WRITE(bclrpat_reg, 0x500050); 369235783Skib 370235783Skib if (!IS_GEN2(dev)) { 371235783Skib uint32_t pipeconf = I915_READ(pipeconf_reg); 372235783Skib I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); 373235783Skib POSTING_READ(pipeconf_reg); 374235783Skib /* Wait for next Vblank to substitue 375235783Skib * border color for Color info */ 376235783Skib intel_wait_for_vblank(dev, pipe); 377235783Skib st00 = I915_READ8(VGA_MSR_WRITE); 378235783Skib status = ((st00 & (1 << 4)) != 0) ? 379235783Skib connector_status_connected : 380235783Skib connector_status_disconnected; 381235783Skib 382235783Skib I915_WRITE(pipeconf_reg, pipeconf); 383235783Skib } else { 384235783Skib bool restore_vblank = false; 385235783Skib int count, detect; 386235783Skib 387235783Skib /* 388235783Skib * If there isn't any border, add some. 389235783Skib * Yes, this will flicker 390235783Skib */ 391235783Skib if (vblank_start <= vactive && vblank_end >= vtotal) { 392235783Skib uint32_t vsync = I915_READ(vsync_reg); 393235783Skib uint32_t vsync_start = (vsync & 0xffff) + 1; 394235783Skib 395235783Skib vblank_start = vsync_start; 396235783Skib I915_WRITE(vblank_reg, 397235783Skib (vblank_start - 1) | 398235783Skib ((vblank_end - 1) << 16)); 399235783Skib restore_vblank = true; 400235783Skib } 401235783Skib /* sample in the vertical border, selecting the larger one */ 402235783Skib if (vblank_start - vactive >= vtotal - vblank_end) 403235783Skib vsample = (vblank_start + vactive) >> 1; 404235783Skib else 405235783Skib vsample = (vtotal + vblank_end) >> 1; 406235783Skib 407235783Skib /* 408235783Skib * Wait for the border to be displayed 409235783Skib */ 410235783Skib while (I915_READ(pipe_dsl_reg) >= vactive) 411235783Skib ; 412235783Skib while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample) 413235783Skib ; 414235783Skib /* 415235783Skib * Watch ST00 for an entire scanline 416235783Skib */ 417235783Skib detect = 0; 418235783Skib count = 0; 419235783Skib do { 420235783Skib count++; 421235783Skib /* Read the ST00 VGA status register */ 422235783Skib st00 = I915_READ8(VGA_MSR_WRITE); 423235783Skib if (st00 & (1 << 4)) 424235783Skib detect++; 425235783Skib } while ((I915_READ(pipe_dsl_reg) == dsl)); 426235783Skib 427235783Skib /* restore vblank if necessary */ 428235783Skib if (restore_vblank) 429235783Skib I915_WRITE(vblank_reg, vblank); 430235783Skib /* 431235783Skib * If more than 3/4 of the scanline detected a monitor, 432235783Skib * then it is assumed to be present. This works even on i830, 433235783Skib * where there isn't any way to force the border color across 434235783Skib * the screen 435235783Skib */ 436235783Skib status = detect * 4 > count * 3 ? 437235783Skib connector_status_connected : 438235783Skib connector_status_disconnected; 439235783Skib } 440235783Skib 441235783Skib /* Restore previous settings */ 442235783Skib I915_WRITE(bclrpat_reg, save_bclrpat); 443235783Skib 444235783Skib return status; 445235783Skib} 446235783Skib 447235783Skibstatic enum drm_connector_status 448235783Skibintel_crt_detect(struct drm_connector *connector, bool force) 449235783Skib{ 450235783Skib struct drm_device *dev = connector->dev; 451235783Skib struct intel_crt *crt = intel_attached_crt(connector); 452235783Skib enum drm_connector_status status; 453235783Skib struct intel_load_detect_pipe tmp; 454235783Skib 455235783Skib if (I915_HAS_HOTPLUG(dev)) { 456235783Skib if (intel_crt_detect_hotplug(connector)) { 457235783Skib DRM_DEBUG_KMS("CRT detected via hotplug\n"); 458235783Skib return connector_status_connected; 459235783Skib } else { 460235783Skib DRM_DEBUG_KMS("CRT not detected via hotplug\n"); 461235783Skib return connector_status_disconnected; 462235783Skib } 463235783Skib } 464235783Skib 465235783Skib if (intel_crt_detect_ddc(connector)) 466235783Skib return connector_status_connected; 467235783Skib 468235783Skib if (!force) 469235783Skib return connector->status; 470235783Skib 471235783Skib /* for pre-945g platforms use load detect */ 472235783Skib if (intel_get_load_detect_pipe(&crt->base, connector, NULL, 473235783Skib &tmp)) { 474235783Skib if (intel_crt_detect_ddc(connector)) 475235783Skib status = connector_status_connected; 476235783Skib else 477235783Skib status = intel_crt_load_detect(crt); 478235783Skib intel_release_load_detect_pipe(&crt->base, connector, 479235783Skib &tmp); 480235783Skib } else 481235783Skib status = connector_status_unknown; 482235783Skib 483235783Skib return status; 484235783Skib} 485235783Skib 486235783Skibstatic void intel_crt_destroy(struct drm_connector *connector) 487235783Skib{ 488235783Skib 489235783Skib#if 0 490235783Skib drm_sysfs_connector_remove(connector); 491235783Skib#endif 492235783Skib drm_connector_cleanup(connector); 493235783Skib free(connector, DRM_MEM_KMS); 494235783Skib} 495235783Skib 496235783Skibstatic int intel_crt_get_modes(struct drm_connector *connector) 497235783Skib{ 498235783Skib struct drm_device *dev = connector->dev; 499235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 500235783Skib int ret; 501280369Skib device_t iic; 502235783Skib 503280369Skib iic = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin); 504280369Skib ret = intel_ddc_get_modes(connector, iic); 505235783Skib if (ret || !IS_G4X(dev)) 506235783Skib return ret; 507235783Skib 508235783Skib /* Try to probe digital port for output in DVI-I -> VGA mode. */ 509280369Skib iic = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB); 510280369Skib return intel_ddc_get_modes(connector, iic); 511235783Skib} 512235783Skib 513235783Skibstatic int intel_crt_set_property(struct drm_connector *connector, 514235783Skib struct drm_property *property, 515235783Skib uint64_t value) 516235783Skib{ 517235783Skib return 0; 518235783Skib} 519235783Skib 520235783Skibstatic void intel_crt_reset(struct drm_connector *connector) 521235783Skib{ 522235783Skib struct drm_device *dev = connector->dev; 523235783Skib struct intel_crt *crt = intel_attached_crt(connector); 524235783Skib 525235783Skib if (HAS_PCH_SPLIT(dev)) 526235783Skib crt->force_hotplug_required = 1; 527235783Skib} 528235783Skib 529235783Skib/* 530235783Skib * Routines for controlling stuff on the analog port 531235783Skib */ 532235783Skib 533280369Skibstatic const struct drm_encoder_helper_funcs pch_encoder_funcs = { 534235783Skib .mode_fixup = intel_crt_mode_fixup, 535235783Skib .prepare = intel_encoder_prepare, 536235783Skib .commit = intel_encoder_commit, 537235783Skib .mode_set = intel_crt_mode_set, 538280369Skib .dpms = pch_crt_dpms, 539235783Skib}; 540235783Skib 541280369Skibstatic const struct drm_encoder_helper_funcs gmch_encoder_funcs = { 542280369Skib .mode_fixup = intel_crt_mode_fixup, 543280369Skib .prepare = intel_encoder_prepare, 544280369Skib .commit = intel_encoder_commit, 545280369Skib .mode_set = intel_crt_mode_set, 546280369Skib .dpms = gmch_crt_dpms, 547280369Skib}; 548280369Skib 549235783Skibstatic const struct drm_connector_funcs intel_crt_connector_funcs = { 550235783Skib .reset = intel_crt_reset, 551235783Skib .dpms = drm_helper_connector_dpms, 552235783Skib .detect = intel_crt_detect, 553235783Skib .fill_modes = drm_helper_probe_single_connector_modes, 554235783Skib .destroy = intel_crt_destroy, 555235783Skib .set_property = intel_crt_set_property, 556235783Skib}; 557235783Skib 558235783Skibstatic const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { 559235783Skib .mode_valid = intel_crt_mode_valid, 560235783Skib .get_modes = intel_crt_get_modes, 561235783Skib .best_encoder = intel_best_encoder, 562235783Skib}; 563235783Skib 564235783Skibstatic const struct drm_encoder_funcs intel_crt_enc_funcs = { 565235783Skib .destroy = intel_encoder_destroy, 566235783Skib}; 567235783Skib 568235783Skibstatic int intel_no_crt_dmi_callback(const struct dmi_system_id *id) 569235783Skib{ 570280369Skib DRM_INFO("Skipping CRT initialization for %s\n", id->ident); 571235783Skib return 1; 572235783Skib} 573235783Skib 574235783Skibstatic const struct dmi_system_id intel_no_crt[] = { 575235783Skib { 576235783Skib .callback = intel_no_crt_dmi_callback, 577235783Skib .ident = "ACER ZGB", 578235783Skib .matches = { 579235783Skib DMI_MATCH(DMI_SYS_VENDOR, "ACER"), 580235783Skib DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"), 581235783Skib }, 582235783Skib }, 583235783Skib { } 584235783Skib}; 585235783Skib 586235783Skibvoid intel_crt_init(struct drm_device *dev) 587235783Skib{ 588235783Skib struct drm_connector *connector; 589235783Skib struct intel_crt *crt; 590235783Skib struct intel_connector *intel_connector; 591235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 592280369Skib const struct drm_encoder_helper_funcs *encoder_helper_funcs; 593235783Skib 594235783Skib /* Skip machines without VGA that falsely report hotplug events */ 595235783Skib if (dmi_check_system(intel_no_crt)) 596235783Skib return; 597235783Skib 598235783Skib crt = malloc(sizeof(struct intel_crt), DRM_MEM_KMS, M_WAITOK | M_ZERO); 599235783Skib intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS, 600235783Skib M_WAITOK | M_ZERO); 601235783Skib 602235783Skib connector = &intel_connector->base; 603235783Skib drm_connector_init(dev, &intel_connector->base, 604235783Skib &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); 605235783Skib 606235783Skib drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs, 607235783Skib DRM_MODE_ENCODER_DAC); 608235783Skib 609235783Skib intel_connector_attach_encoder(intel_connector, &crt->base); 610235783Skib 611235783Skib crt->base.type = INTEL_OUTPUT_ANALOG; 612235783Skib crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT | 613235783Skib 1 << INTEL_ANALOG_CLONE_BIT | 614235783Skib 1 << INTEL_SDVO_LVDS_CLONE_BIT); 615280369Skib if (IS_HASWELL(dev)) 616280369Skib crt->base.crtc_mask = (1 << 0); 617280369Skib else 618280369Skib crt->base.crtc_mask = (1 << 0) | (1 << 1); 619280369Skib 620235783Skib if (IS_GEN2(dev)) 621235783Skib connector->interlace_allowed = 0; 622235783Skib else 623235783Skib connector->interlace_allowed = 1; 624235783Skib connector->doublescan_allowed = 0; 625235783Skib 626280369Skib if (HAS_PCH_SPLIT(dev)) 627280369Skib encoder_helper_funcs = &pch_encoder_funcs; 628280369Skib else 629280369Skib encoder_helper_funcs = &gmch_encoder_funcs; 630280369Skib 631280369Skib drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs); 632235783Skib drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); 633235783Skib 634235783Skib#if 0 635235783Skib drm_sysfs_connector_add(connector); 636235783Skib#endif 637235783Skib 638235783Skib if (I915_HAS_HOTPLUG(dev)) 639235783Skib connector->polled = DRM_CONNECTOR_POLL_HPD; 640235783Skib else 641235783Skib connector->polled = DRM_CONNECTOR_POLL_CONNECT; 642235783Skib 643235783Skib /* 644235783Skib * Configure the automatic hotplug detection stuff 645235783Skib */ 646235783Skib crt->force_hotplug_required = 0; 647235783Skib if (HAS_PCH_SPLIT(dev)) { 648235783Skib u32 adpa; 649235783Skib 650235783Skib adpa = I915_READ(PCH_ADPA); 651235783Skib adpa &= ~ADPA_CRT_HOTPLUG_MASK; 652235783Skib adpa |= ADPA_HOTPLUG_BITS; 653235783Skib I915_WRITE(PCH_ADPA, adpa); 654235783Skib POSTING_READ(PCH_ADPA); 655235783Skib 656235783Skib DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa); 657235783Skib crt->force_hotplug_required = 1; 658235783Skib } 659235783Skib 660235783Skib dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; 661235783Skib} 662