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$"); 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 58235783Skibstatic void intel_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; 62235783Skib u32 temp, reg; 63235783Skib 64235783Skib if (HAS_PCH_SPLIT(dev)) 65235783Skib reg = PCH_ADPA; 66235783Skib else 67235783Skib reg = ADPA; 68235783Skib 69235783Skib temp = I915_READ(reg); 70235783Skib temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); 71235783Skib temp &= ~ADPA_DAC_ENABLE; 72235783Skib 73235783Skib switch (mode) { 74235783Skib case DRM_MODE_DPMS_ON: 75235783Skib temp |= ADPA_DAC_ENABLE; 76235783Skib break; 77235783Skib case DRM_MODE_DPMS_STANDBY: 78235783Skib temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; 79235783Skib break; 80235783Skib case DRM_MODE_DPMS_SUSPEND: 81235783Skib temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; 82235783Skib break; 83235783Skib case DRM_MODE_DPMS_OFF: 84235783Skib temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; 85235783Skib break; 86235783Skib } 87235783Skib 88235783Skib I915_WRITE(reg, temp); 89235783Skib} 90235783Skib 91235783Skibstatic int intel_crt_mode_valid(struct drm_connector *connector, 92235783Skib struct drm_display_mode *mode) 93235783Skib{ 94235783Skib struct drm_device *dev = connector->dev; 95235783Skib 96235783Skib int max_clock = 0; 97235783Skib if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 98235783Skib return MODE_NO_DBLESCAN; 99235783Skib 100235783Skib if (mode->clock < 25000) 101235783Skib return MODE_CLOCK_LOW; 102235783Skib 103235783Skib if (IS_GEN2(dev)) 104235783Skib max_clock = 350000; 105235783Skib else 106235783Skib max_clock = 400000; 107235783Skib if (mode->clock > max_clock) 108235783Skib return MODE_CLOCK_HIGH; 109235783Skib 110235783Skib return MODE_OK; 111235783Skib} 112235783Skib 113235783Skibstatic bool intel_crt_mode_fixup(struct drm_encoder *encoder, 114261631Sdumbbell const struct drm_display_mode *mode, 115235783Skib struct drm_display_mode *adjusted_mode) 116235783Skib{ 117235783Skib return true; 118235783Skib} 119235783Skib 120235783Skibstatic void intel_crt_mode_set(struct drm_encoder *encoder, 121235783Skib struct drm_display_mode *mode, 122235783Skib struct drm_display_mode *adjusted_mode) 123235783Skib{ 124235783Skib 125235783Skib struct drm_device *dev = encoder->dev; 126235783Skib struct drm_crtc *crtc = encoder->crtc; 127235783Skib struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 128235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 129235783Skib int dpll_md_reg; 130235783Skib u32 adpa, dpll_md; 131235783Skib u32 adpa_reg; 132235783Skib 133235783Skib dpll_md_reg = DPLL_MD(intel_crtc->pipe); 134235783Skib 135235783Skib if (HAS_PCH_SPLIT(dev)) 136235783Skib adpa_reg = PCH_ADPA; 137235783Skib else 138235783Skib adpa_reg = ADPA; 139235783Skib 140235783Skib /* 141235783Skib * Disable separate mode multiplier used when cloning SDVO to CRT 142235783Skib * XXX this needs to be adjusted when we really are cloning 143235783Skib */ 144235783Skib if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { 145235783Skib dpll_md = I915_READ(dpll_md_reg); 146235783Skib I915_WRITE(dpll_md_reg, 147235783Skib dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); 148235783Skib } 149235783Skib 150235783Skib adpa = ADPA_HOTPLUG_BITS; 151235783Skib if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 152235783Skib adpa |= ADPA_HSYNC_ACTIVE_HIGH; 153235783Skib if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 154235783Skib adpa |= ADPA_VSYNC_ACTIVE_HIGH; 155235783Skib 156235783Skib /* For CPT allow 3 pipe config, for others just use A or B */ 157235783Skib if (HAS_PCH_CPT(dev)) 158235783Skib adpa |= PORT_TRANS_SEL_CPT(intel_crtc->pipe); 159235783Skib else if (intel_crtc->pipe == 0) 160235783Skib adpa |= ADPA_PIPE_A_SELECT; 161235783Skib else 162235783Skib adpa |= ADPA_PIPE_B_SELECT; 163235783Skib 164235783Skib if (!HAS_PCH_SPLIT(dev)) 165235783Skib I915_WRITE(BCLRPAT(intel_crtc->pipe), 0); 166235783Skib 167235783Skib I915_WRITE(adpa_reg, adpa); 168235783Skib} 169235783Skib 170235783Skibstatic bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) 171235783Skib{ 172235783Skib struct drm_device *dev = connector->dev; 173235783Skib struct intel_crt *crt = intel_attached_crt(connector); 174235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 175235783Skib u32 adpa; 176235783Skib bool ret; 177235783Skib 178235783Skib /* The first time through, trigger an explicit detection cycle */ 179235783Skib if (crt->force_hotplug_required) { 180235783Skib bool turn_off_dac = HAS_PCH_SPLIT(dev); 181235783Skib u32 save_adpa; 182235783Skib 183235783Skib crt->force_hotplug_required = 0; 184235783Skib 185235783Skib save_adpa = adpa = I915_READ(PCH_ADPA); 186235783Skib DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); 187235783Skib 188235783Skib adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; 189235783Skib if (turn_off_dac) 190235783Skib adpa &= ~ADPA_DAC_ENABLE; 191235783Skib 192235783Skib I915_WRITE(PCH_ADPA, adpa); 193235783Skib 194235783Skib if (_intel_wait_for(dev, 195235783Skib (I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, 196235783Skib 1000, 1, "915crt")) 197235783Skib DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER\n"); 198235783Skib 199235783Skib if (turn_off_dac) { 200235783Skib I915_WRITE(PCH_ADPA, save_adpa); 201235783Skib POSTING_READ(PCH_ADPA); 202235783Skib } 203235783Skib } 204235783Skib 205235783Skib /* Check the status to see if both blue and green are on now */ 206235783Skib adpa = I915_READ(PCH_ADPA); 207235783Skib if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) 208235783Skib ret = true; 209235783Skib else 210235783Skib ret = false; 211235783Skib DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret); 212235783Skib 213235783Skib return ret; 214235783Skib} 215235783Skib 216235783Skib/** 217235783Skib * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. 218235783Skib * 219235783Skib * Not for i915G/i915GM 220235783Skib * 221235783Skib * \return true if CRT is connected. 222235783Skib * \return false if CRT is disconnected. 223235783Skib */ 224235783Skibstatic bool intel_crt_detect_hotplug(struct drm_connector *connector) 225235783Skib{ 226235783Skib struct drm_device *dev = connector->dev; 227235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 228235783Skib u32 hotplug_en, orig, stat; 229235783Skib bool ret = false; 230235783Skib int i, tries = 0; 231235783Skib 232235783Skib if (HAS_PCH_SPLIT(dev)) 233235783Skib return intel_ironlake_crt_detect_hotplug(connector); 234235783Skib 235235783Skib /* 236235783Skib * On 4 series desktop, CRT detect sequence need to be done twice 237235783Skib * to get a reliable result. 238235783Skib */ 239235783Skib 240235783Skib if (IS_G4X(dev) && !IS_GM45(dev)) 241235783Skib tries = 2; 242235783Skib else 243235783Skib tries = 1; 244235783Skib hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN); 245235783Skib hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; 246235783Skib 247235783Skib for (i = 0; i < tries ; i++) { 248235783Skib /* turn on the FORCE_DETECT */ 249235783Skib I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); 250235783Skib /* wait for FORCE_DETECT to go off */ 251235783Skib if (_intel_wait_for(dev, 252235783Skib (I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0, 253235783Skib 1000, 1, "915cr2")) 254235783Skib DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off"); 255235783Skib } 256235783Skib 257235783Skib stat = I915_READ(PORT_HOTPLUG_STAT); 258235783Skib if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE) 259235783Skib ret = true; 260235783Skib 261235783Skib /* clear the interrupt we just generated, if any */ 262235783Skib I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS); 263235783Skib 264235783Skib /* and put the bits back */ 265235783Skib I915_WRITE(PORT_HOTPLUG_EN, orig); 266235783Skib 267235783Skib return ret; 268235783Skib} 269235783Skib 270235783Skibstatic bool intel_crt_detect_ddc(struct drm_connector *connector) 271235783Skib{ 272235783Skib struct intel_crt *crt = intel_attached_crt(connector); 273235783Skib struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private; 274235783Skib 275235783Skib /* CRT should always be at 0, but check anyway */ 276235783Skib if (crt->base.type != INTEL_OUTPUT_ANALOG) 277235783Skib return false; 278235783Skib 279235783Skib if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) { 280235783Skib struct edid *edid; 281235783Skib bool is_digital = false; 282235783Skib 283235783Skib edid = drm_get_edid(connector, 284235783Skib dev_priv->gmbus[dev_priv->crt_ddc_pin]); 285235783Skib /* 286235783Skib * This may be a DVI-I connector with a shared DDC 287235783Skib * link between analog and digital outputs, so we 288235783Skib * have to check the EDID input spec of the attached device. 289235783Skib * 290235783Skib * On the other hand, what should we do if it is a broken EDID? 291235783Skib */ 292235783Skib if (edid != NULL) { 293235783Skib is_digital = edid->input & DRM_EDID_INPUT_DIGITAL; 294235783Skib connector->display_info.raw_edid = NULL; 295235783Skib free(edid, DRM_MEM_KMS); 296235783Skib } 297235783Skib 298235783Skib if (!is_digital) { 299235783Skib DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n"); 300235783Skib return true; 301235783Skib } else { 302235783Skib DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n"); 303235783Skib } 304235783Skib } 305235783Skib 306235783Skib return false; 307235783Skib} 308235783Skib 309235783Skibstatic enum drm_connector_status 310235783Skibintel_crt_load_detect(struct intel_crt *crt) 311235783Skib{ 312235783Skib struct drm_device *dev = crt->base.base.dev; 313235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 314235783Skib uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe; 315235783Skib uint32_t save_bclrpat; 316235783Skib uint32_t save_vtotal; 317235783Skib uint32_t vtotal, vactive; 318235783Skib uint32_t vsample; 319235783Skib uint32_t vblank, vblank_start, vblank_end; 320235783Skib uint32_t dsl; 321235783Skib uint32_t bclrpat_reg; 322235783Skib uint32_t vtotal_reg; 323235783Skib uint32_t vblank_reg; 324235783Skib uint32_t vsync_reg; 325235783Skib uint32_t pipeconf_reg; 326235783Skib uint32_t pipe_dsl_reg; 327235783Skib uint8_t st00; 328235783Skib enum drm_connector_status status; 329235783Skib 330235783Skib DRM_DEBUG_KMS("starting load-detect on CRT\n"); 331235783Skib 332235783Skib bclrpat_reg = BCLRPAT(pipe); 333235783Skib vtotal_reg = VTOTAL(pipe); 334235783Skib vblank_reg = VBLANK(pipe); 335235783Skib vsync_reg = VSYNC(pipe); 336235783Skib pipeconf_reg = PIPECONF(pipe); 337235783Skib pipe_dsl_reg = PIPEDSL(pipe); 338235783Skib 339235783Skib save_bclrpat = I915_READ(bclrpat_reg); 340235783Skib save_vtotal = I915_READ(vtotal_reg); 341235783Skib vblank = I915_READ(vblank_reg); 342235783Skib 343235783Skib vtotal = ((save_vtotal >> 16) & 0xfff) + 1; 344235783Skib vactive = (save_vtotal & 0x7ff) + 1; 345235783Skib 346235783Skib vblank_start = (vblank & 0xfff) + 1; 347235783Skib vblank_end = ((vblank >> 16) & 0xfff) + 1; 348235783Skib 349235783Skib /* Set the border color to purple. */ 350235783Skib I915_WRITE(bclrpat_reg, 0x500050); 351235783Skib 352235783Skib if (!IS_GEN2(dev)) { 353235783Skib uint32_t pipeconf = I915_READ(pipeconf_reg); 354235783Skib I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); 355235783Skib POSTING_READ(pipeconf_reg); 356235783Skib /* Wait for next Vblank to substitue 357235783Skib * border color for Color info */ 358235783Skib intel_wait_for_vblank(dev, pipe); 359235783Skib st00 = I915_READ8(VGA_MSR_WRITE); 360235783Skib status = ((st00 & (1 << 4)) != 0) ? 361235783Skib connector_status_connected : 362235783Skib connector_status_disconnected; 363235783Skib 364235783Skib I915_WRITE(pipeconf_reg, pipeconf); 365235783Skib } else { 366235783Skib bool restore_vblank = false; 367235783Skib int count, detect; 368235783Skib 369235783Skib /* 370235783Skib * If there isn't any border, add some. 371235783Skib * Yes, this will flicker 372235783Skib */ 373235783Skib if (vblank_start <= vactive && vblank_end >= vtotal) { 374235783Skib uint32_t vsync = I915_READ(vsync_reg); 375235783Skib uint32_t vsync_start = (vsync & 0xffff) + 1; 376235783Skib 377235783Skib vblank_start = vsync_start; 378235783Skib I915_WRITE(vblank_reg, 379235783Skib (vblank_start - 1) | 380235783Skib ((vblank_end - 1) << 16)); 381235783Skib restore_vblank = true; 382235783Skib } 383235783Skib /* sample in the vertical border, selecting the larger one */ 384235783Skib if (vblank_start - vactive >= vtotal - vblank_end) 385235783Skib vsample = (vblank_start + vactive) >> 1; 386235783Skib else 387235783Skib vsample = (vtotal + vblank_end) >> 1; 388235783Skib 389235783Skib /* 390235783Skib * Wait for the border to be displayed 391235783Skib */ 392235783Skib while (I915_READ(pipe_dsl_reg) >= vactive) 393235783Skib ; 394235783Skib while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample) 395235783Skib ; 396235783Skib /* 397235783Skib * Watch ST00 for an entire scanline 398235783Skib */ 399235783Skib detect = 0; 400235783Skib count = 0; 401235783Skib do { 402235783Skib count++; 403235783Skib /* Read the ST00 VGA status register */ 404235783Skib st00 = I915_READ8(VGA_MSR_WRITE); 405235783Skib if (st00 & (1 << 4)) 406235783Skib detect++; 407235783Skib } while ((I915_READ(pipe_dsl_reg) == dsl)); 408235783Skib 409235783Skib /* restore vblank if necessary */ 410235783Skib if (restore_vblank) 411235783Skib I915_WRITE(vblank_reg, vblank); 412235783Skib /* 413235783Skib * If more than 3/4 of the scanline detected a monitor, 414235783Skib * then it is assumed to be present. This works even on i830, 415235783Skib * where there isn't any way to force the border color across 416235783Skib * the screen 417235783Skib */ 418235783Skib status = detect * 4 > count * 3 ? 419235783Skib connector_status_connected : 420235783Skib connector_status_disconnected; 421235783Skib } 422235783Skib 423235783Skib /* Restore previous settings */ 424235783Skib I915_WRITE(bclrpat_reg, save_bclrpat); 425235783Skib 426235783Skib return status; 427235783Skib} 428235783Skib 429235783Skibstatic enum drm_connector_status 430235783Skibintel_crt_detect(struct drm_connector *connector, bool force) 431235783Skib{ 432235783Skib struct drm_device *dev = connector->dev; 433235783Skib struct intel_crt *crt = intel_attached_crt(connector); 434235783Skib enum drm_connector_status status; 435235783Skib struct intel_load_detect_pipe tmp; 436235783Skib 437235783Skib if (I915_HAS_HOTPLUG(dev)) { 438235783Skib if (intel_crt_detect_hotplug(connector)) { 439235783Skib DRM_DEBUG_KMS("CRT detected via hotplug\n"); 440235783Skib return connector_status_connected; 441235783Skib } else { 442235783Skib DRM_DEBUG_KMS("CRT not detected via hotplug\n"); 443235783Skib return connector_status_disconnected; 444235783Skib } 445235783Skib } 446235783Skib 447235783Skib if (intel_crt_detect_ddc(connector)) 448235783Skib return connector_status_connected; 449235783Skib 450235783Skib if (!force) 451235783Skib return connector->status; 452235783Skib 453235783Skib /* for pre-945g platforms use load detect */ 454235783Skib if (intel_get_load_detect_pipe(&crt->base, connector, NULL, 455235783Skib &tmp)) { 456235783Skib if (intel_crt_detect_ddc(connector)) 457235783Skib status = connector_status_connected; 458235783Skib else 459235783Skib status = intel_crt_load_detect(crt); 460235783Skib intel_release_load_detect_pipe(&crt->base, connector, 461235783Skib &tmp); 462235783Skib } else 463235783Skib status = connector_status_unknown; 464235783Skib 465235783Skib return status; 466235783Skib} 467235783Skib 468235783Skibstatic void intel_crt_destroy(struct drm_connector *connector) 469235783Skib{ 470235783Skib 471235783Skib#if 0 472235783Skib drm_sysfs_connector_remove(connector); 473235783Skib#endif 474235783Skib drm_connector_cleanup(connector); 475235783Skib free(connector, DRM_MEM_KMS); 476235783Skib} 477235783Skib 478235783Skibstatic int intel_crt_get_modes(struct drm_connector *connector) 479235783Skib{ 480235783Skib struct drm_device *dev = connector->dev; 481235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 482235783Skib int ret; 483235783Skib 484235783Skib ret = intel_ddc_get_modes(connector, 485235783Skib dev_priv->gmbus[dev_priv->crt_ddc_pin]); 486235783Skib if (ret || !IS_G4X(dev)) 487235783Skib return ret; 488235783Skib 489235783Skib /* Try to probe digital port for output in DVI-I -> VGA mode. */ 490235783Skib return (intel_ddc_get_modes(connector, 491235783Skib dev_priv->gmbus[GMBUS_PORT_DPB])); 492235783Skib} 493235783Skib 494235783Skibstatic int intel_crt_set_property(struct drm_connector *connector, 495235783Skib struct drm_property *property, 496235783Skib uint64_t value) 497235783Skib{ 498235783Skib return 0; 499235783Skib} 500235783Skib 501235783Skibstatic void intel_crt_reset(struct drm_connector *connector) 502235783Skib{ 503235783Skib struct drm_device *dev = connector->dev; 504235783Skib struct intel_crt *crt = intel_attached_crt(connector); 505235783Skib 506235783Skib if (HAS_PCH_SPLIT(dev)) 507235783Skib crt->force_hotplug_required = 1; 508235783Skib} 509235783Skib 510235783Skib/* 511235783Skib * Routines for controlling stuff on the analog port 512235783Skib */ 513235783Skib 514235783Skibstatic const struct drm_encoder_helper_funcs intel_crt_helper_funcs = { 515235783Skib .dpms = intel_crt_dpms, 516235783Skib .mode_fixup = intel_crt_mode_fixup, 517235783Skib .prepare = intel_encoder_prepare, 518235783Skib .commit = intel_encoder_commit, 519235783Skib .mode_set = intel_crt_mode_set, 520235783Skib}; 521235783Skib 522235783Skibstatic const struct drm_connector_funcs intel_crt_connector_funcs = { 523235783Skib .reset = intel_crt_reset, 524235783Skib .dpms = drm_helper_connector_dpms, 525235783Skib .detect = intel_crt_detect, 526235783Skib .fill_modes = drm_helper_probe_single_connector_modes, 527235783Skib .destroy = intel_crt_destroy, 528235783Skib .set_property = intel_crt_set_property, 529235783Skib}; 530235783Skib 531235783Skibstatic const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { 532235783Skib .mode_valid = intel_crt_mode_valid, 533235783Skib .get_modes = intel_crt_get_modes, 534235783Skib .best_encoder = intel_best_encoder, 535235783Skib}; 536235783Skib 537235783Skibstatic const struct drm_encoder_funcs intel_crt_enc_funcs = { 538235783Skib .destroy = intel_encoder_destroy, 539235783Skib}; 540235783Skib 541235783Skibstatic int intel_no_crt_dmi_callback(const struct dmi_system_id *id) 542235783Skib{ 543235783Skib DRM_DEBUG_KMS("Skipping CRT initialization for %s\n", id->ident); 544235783Skib return 1; 545235783Skib} 546235783Skib 547235783Skibstatic const struct dmi_system_id intel_no_crt[] = { 548235783Skib { 549235783Skib .callback = intel_no_crt_dmi_callback, 550235783Skib .ident = "ACER ZGB", 551235783Skib .matches = { 552235783Skib DMI_MATCH(DMI_SYS_VENDOR, "ACER"), 553235783Skib DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"), 554235783Skib }, 555235783Skib }, 556235783Skib { } 557235783Skib}; 558235783Skib 559235783Skibvoid intel_crt_init(struct drm_device *dev) 560235783Skib{ 561235783Skib struct drm_connector *connector; 562235783Skib struct intel_crt *crt; 563235783Skib struct intel_connector *intel_connector; 564235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 565235783Skib 566235783Skib /* Skip machines without VGA that falsely report hotplug events */ 567235783Skib if (dmi_check_system(intel_no_crt)) 568235783Skib return; 569235783Skib 570235783Skib crt = malloc(sizeof(struct intel_crt), DRM_MEM_KMS, M_WAITOK | M_ZERO); 571235783Skib intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS, 572235783Skib M_WAITOK | M_ZERO); 573235783Skib 574235783Skib connector = &intel_connector->base; 575235783Skib drm_connector_init(dev, &intel_connector->base, 576235783Skib &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); 577235783Skib 578235783Skib drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs, 579235783Skib DRM_MODE_ENCODER_DAC); 580235783Skib 581235783Skib intel_connector_attach_encoder(intel_connector, &crt->base); 582235783Skib 583235783Skib crt->base.type = INTEL_OUTPUT_ANALOG; 584235783Skib crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT | 585235783Skib 1 << INTEL_ANALOG_CLONE_BIT | 586235783Skib 1 << INTEL_SDVO_LVDS_CLONE_BIT); 587235783Skib crt->base.crtc_mask = (1 << 0) | (1 << 1); 588235783Skib if (IS_GEN2(dev)) 589235783Skib connector->interlace_allowed = 0; 590235783Skib else 591235783Skib connector->interlace_allowed = 1; 592235783Skib connector->doublescan_allowed = 0; 593235783Skib 594235783Skib drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs); 595235783Skib drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); 596235783Skib 597235783Skib#if 0 598235783Skib drm_sysfs_connector_add(connector); 599235783Skib#endif 600235783Skib 601235783Skib if (I915_HAS_HOTPLUG(dev)) 602235783Skib connector->polled = DRM_CONNECTOR_POLL_HPD; 603235783Skib else 604235783Skib connector->polled = DRM_CONNECTOR_POLL_CONNECT; 605235783Skib 606235783Skib /* 607235783Skib * Configure the automatic hotplug detection stuff 608235783Skib */ 609235783Skib crt->force_hotplug_required = 0; 610235783Skib if (HAS_PCH_SPLIT(dev)) { 611235783Skib u32 adpa; 612235783Skib 613235783Skib adpa = I915_READ(PCH_ADPA); 614235783Skib adpa &= ~ADPA_CRT_HOTPLUG_MASK; 615235783Skib adpa |= ADPA_HOTPLUG_BITS; 616235783Skib I915_WRITE(PCH_ADPA, adpa); 617235783Skib POSTING_READ(PCH_ADPA); 618235783Skib 619235783Skib DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa); 620235783Skib crt->force_hotplug_required = 1; 621235783Skib } 622235783Skib 623235783Skib dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; 624235783Skib} 625