1*e3adcf8fSFrançois Tigeot /* 2*e3adcf8fSFrançois Tigeot * Copyright © 2006-2007 Intel Corporation 3*e3adcf8fSFrançois Tigeot * 4*e3adcf8fSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 5*e3adcf8fSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 6*e3adcf8fSFrançois Tigeot * to deal in the Software without restriction, including without limitation 7*e3adcf8fSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8*e3adcf8fSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 9*e3adcf8fSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 10*e3adcf8fSFrançois Tigeot * 11*e3adcf8fSFrançois Tigeot * The above copyright notice and this permission notice (including the next 12*e3adcf8fSFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the 13*e3adcf8fSFrançois Tigeot * Software. 14*e3adcf8fSFrançois Tigeot * 15*e3adcf8fSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16*e3adcf8fSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17*e3adcf8fSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18*e3adcf8fSFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19*e3adcf8fSFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20*e3adcf8fSFrançois Tigeot * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21*e3adcf8fSFrançois Tigeot * DEALINGS IN THE SOFTWARE. 22*e3adcf8fSFrançois Tigeot * 23*e3adcf8fSFrançois Tigeot * Authors: 24*e3adcf8fSFrançois Tigeot * Eric Anholt <eric@anholt.net> 25*e3adcf8fSFrançois Tigeot * 26*e3adcf8fSFrançois Tigeot * $FreeBSD: src/sys/dev/drm2/i915/intel_crt.c,v 1.1 2012/05/22 11:07:44 kib Exp $ 27*e3adcf8fSFrançois Tigeot */ 28*e3adcf8fSFrançois Tigeot 29*e3adcf8fSFrançois Tigeot #include <dev/drm/drmP.h> 30*e3adcf8fSFrançois Tigeot #include <dev/drm/drm.h> 31*e3adcf8fSFrançois Tigeot #include <dev/drm/drm_crtc.h> 32*e3adcf8fSFrançois Tigeot #include <dev/drm/drm_crtc_helper.h> 33*e3adcf8fSFrançois Tigeot #include <dev/drm/drm_edid.h> 34*e3adcf8fSFrançois Tigeot #include "i915_drm.h" 35*e3adcf8fSFrançois Tigeot #include "i915_drv.h" 36*e3adcf8fSFrançois Tigeot #include "intel_drv.h" 37*e3adcf8fSFrançois Tigeot 38*e3adcf8fSFrançois Tigeot /* Here's the desired hotplug mode */ 39*e3adcf8fSFrançois Tigeot #define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 | \ 40*e3adcf8fSFrançois Tigeot ADPA_CRT_HOTPLUG_WARMUP_10MS | \ 41*e3adcf8fSFrançois Tigeot ADPA_CRT_HOTPLUG_SAMPLE_4S | \ 42*e3adcf8fSFrançois Tigeot ADPA_CRT_HOTPLUG_VOLTAGE_50 | \ 43*e3adcf8fSFrançois Tigeot ADPA_CRT_HOTPLUG_VOLREF_325MV | \ 44*e3adcf8fSFrançois Tigeot ADPA_CRT_HOTPLUG_ENABLE) 45*e3adcf8fSFrançois Tigeot 46*e3adcf8fSFrançois Tigeot struct intel_crt { 47*e3adcf8fSFrançois Tigeot struct intel_encoder base; 48*e3adcf8fSFrançois Tigeot bool force_hotplug_required; 49*e3adcf8fSFrançois Tigeot }; 50*e3adcf8fSFrançois Tigeot 51*e3adcf8fSFrançois Tigeot static struct intel_crt *intel_attached_crt(struct drm_connector *connector) 52*e3adcf8fSFrançois Tigeot { 53*e3adcf8fSFrançois Tigeot return container_of(intel_attached_encoder(connector), 54*e3adcf8fSFrançois Tigeot struct intel_crt, base); 55*e3adcf8fSFrançois Tigeot } 56*e3adcf8fSFrançois Tigeot 57*e3adcf8fSFrançois Tigeot static void intel_crt_dpms(struct drm_encoder *encoder, int mode) 58*e3adcf8fSFrançois Tigeot { 59*e3adcf8fSFrançois Tigeot struct drm_device *dev = encoder->dev; 60*e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 61*e3adcf8fSFrançois Tigeot u32 temp, reg; 62*e3adcf8fSFrançois Tigeot 63*e3adcf8fSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) 64*e3adcf8fSFrançois Tigeot reg = PCH_ADPA; 65*e3adcf8fSFrançois Tigeot else 66*e3adcf8fSFrançois Tigeot reg = ADPA; 67*e3adcf8fSFrançois Tigeot 68*e3adcf8fSFrançois Tigeot temp = I915_READ(reg); 69*e3adcf8fSFrançois Tigeot temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); 70*e3adcf8fSFrançois Tigeot temp &= ~ADPA_DAC_ENABLE; 71*e3adcf8fSFrançois Tigeot 72*e3adcf8fSFrançois Tigeot switch (mode) { 73*e3adcf8fSFrançois Tigeot case DRM_MODE_DPMS_ON: 74*e3adcf8fSFrançois Tigeot temp |= ADPA_DAC_ENABLE; 75*e3adcf8fSFrançois Tigeot break; 76*e3adcf8fSFrançois Tigeot case DRM_MODE_DPMS_STANDBY: 77*e3adcf8fSFrançois Tigeot temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; 78*e3adcf8fSFrançois Tigeot break; 79*e3adcf8fSFrançois Tigeot case DRM_MODE_DPMS_SUSPEND: 80*e3adcf8fSFrançois Tigeot temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; 81*e3adcf8fSFrançois Tigeot break; 82*e3adcf8fSFrançois Tigeot case DRM_MODE_DPMS_OFF: 83*e3adcf8fSFrançois Tigeot temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; 84*e3adcf8fSFrançois Tigeot break; 85*e3adcf8fSFrançois Tigeot } 86*e3adcf8fSFrançois Tigeot 87*e3adcf8fSFrançois Tigeot I915_WRITE(reg, temp); 88*e3adcf8fSFrançois Tigeot } 89*e3adcf8fSFrançois Tigeot 90*e3adcf8fSFrançois Tigeot static int intel_crt_mode_valid(struct drm_connector *connector, 91*e3adcf8fSFrançois Tigeot struct drm_display_mode *mode) 92*e3adcf8fSFrançois Tigeot { 93*e3adcf8fSFrançois Tigeot struct drm_device *dev = connector->dev; 94*e3adcf8fSFrançois Tigeot 95*e3adcf8fSFrançois Tigeot int max_clock = 0; 96*e3adcf8fSFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 97*e3adcf8fSFrançois Tigeot return MODE_NO_DBLESCAN; 98*e3adcf8fSFrançois Tigeot 99*e3adcf8fSFrançois Tigeot if (mode->clock < 25000) 100*e3adcf8fSFrançois Tigeot return MODE_CLOCK_LOW; 101*e3adcf8fSFrançois Tigeot 102*e3adcf8fSFrançois Tigeot if (IS_GEN2(dev)) 103*e3adcf8fSFrançois Tigeot max_clock = 350000; 104*e3adcf8fSFrançois Tigeot else 105*e3adcf8fSFrançois Tigeot max_clock = 400000; 106*e3adcf8fSFrançois Tigeot if (mode->clock > max_clock) 107*e3adcf8fSFrançois Tigeot return MODE_CLOCK_HIGH; 108*e3adcf8fSFrançois Tigeot 109*e3adcf8fSFrançois Tigeot return MODE_OK; 110*e3adcf8fSFrançois Tigeot } 111*e3adcf8fSFrançois Tigeot 112*e3adcf8fSFrançois Tigeot static bool intel_crt_mode_fixup(struct drm_encoder *encoder, 113*e3adcf8fSFrançois Tigeot struct drm_display_mode *mode, 114*e3adcf8fSFrançois Tigeot struct drm_display_mode *adjusted_mode) 115*e3adcf8fSFrançois Tigeot { 116*e3adcf8fSFrançois Tigeot return true; 117*e3adcf8fSFrançois Tigeot } 118*e3adcf8fSFrançois Tigeot 119*e3adcf8fSFrançois Tigeot static void intel_crt_mode_set(struct drm_encoder *encoder, 120*e3adcf8fSFrançois Tigeot struct drm_display_mode *mode, 121*e3adcf8fSFrançois Tigeot struct drm_display_mode *adjusted_mode) 122*e3adcf8fSFrançois Tigeot { 123*e3adcf8fSFrançois Tigeot 124*e3adcf8fSFrançois Tigeot struct drm_device *dev = encoder->dev; 125*e3adcf8fSFrançois Tigeot struct drm_crtc *crtc = encoder->crtc; 126*e3adcf8fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 127*e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 128*e3adcf8fSFrançois Tigeot int dpll_md_reg; 129*e3adcf8fSFrançois Tigeot u32 adpa, dpll_md; 130*e3adcf8fSFrançois Tigeot u32 adpa_reg; 131*e3adcf8fSFrançois Tigeot 132*e3adcf8fSFrançois Tigeot dpll_md_reg = DPLL_MD(intel_crtc->pipe); 133*e3adcf8fSFrançois Tigeot 134*e3adcf8fSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) 135*e3adcf8fSFrançois Tigeot adpa_reg = PCH_ADPA; 136*e3adcf8fSFrançois Tigeot else 137*e3adcf8fSFrançois Tigeot adpa_reg = ADPA; 138*e3adcf8fSFrançois Tigeot 139*e3adcf8fSFrançois Tigeot /* 140*e3adcf8fSFrançois Tigeot * Disable separate mode multiplier used when cloning SDVO to CRT 141*e3adcf8fSFrançois Tigeot * XXX this needs to be adjusted when we really are cloning 142*e3adcf8fSFrançois Tigeot */ 143*e3adcf8fSFrançois Tigeot if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { 144*e3adcf8fSFrançois Tigeot dpll_md = I915_READ(dpll_md_reg); 145*e3adcf8fSFrançois Tigeot I915_WRITE(dpll_md_reg, 146*e3adcf8fSFrançois Tigeot dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); 147*e3adcf8fSFrançois Tigeot } 148*e3adcf8fSFrançois Tigeot 149*e3adcf8fSFrançois Tigeot adpa = ADPA_HOTPLUG_BITS; 150*e3adcf8fSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 151*e3adcf8fSFrançois Tigeot adpa |= ADPA_HSYNC_ACTIVE_HIGH; 152*e3adcf8fSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 153*e3adcf8fSFrançois Tigeot adpa |= ADPA_VSYNC_ACTIVE_HIGH; 154*e3adcf8fSFrançois Tigeot 155*e3adcf8fSFrançois Tigeot /* For CPT allow 3 pipe config, for others just use A or B */ 156*e3adcf8fSFrançois Tigeot if (HAS_PCH_CPT(dev)) 157*e3adcf8fSFrançois Tigeot adpa |= PORT_TRANS_SEL_CPT(intel_crtc->pipe); 158*e3adcf8fSFrançois Tigeot else if (intel_crtc->pipe == 0) 159*e3adcf8fSFrançois Tigeot adpa |= ADPA_PIPE_A_SELECT; 160*e3adcf8fSFrançois Tigeot else 161*e3adcf8fSFrançois Tigeot adpa |= ADPA_PIPE_B_SELECT; 162*e3adcf8fSFrançois Tigeot 163*e3adcf8fSFrançois Tigeot if (!HAS_PCH_SPLIT(dev)) 164*e3adcf8fSFrançois Tigeot I915_WRITE(BCLRPAT(intel_crtc->pipe), 0); 165*e3adcf8fSFrançois Tigeot 166*e3adcf8fSFrançois Tigeot I915_WRITE(adpa_reg, adpa); 167*e3adcf8fSFrançois Tigeot } 168*e3adcf8fSFrançois Tigeot 169*e3adcf8fSFrançois Tigeot static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) 170*e3adcf8fSFrançois Tigeot { 171*e3adcf8fSFrançois Tigeot struct drm_device *dev = connector->dev; 172*e3adcf8fSFrançois Tigeot struct intel_crt *crt = intel_attached_crt(connector); 173*e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 174*e3adcf8fSFrançois Tigeot u32 adpa; 175*e3adcf8fSFrançois Tigeot bool ret; 176*e3adcf8fSFrançois Tigeot 177*e3adcf8fSFrançois Tigeot /* The first time through, trigger an explicit detection cycle */ 178*e3adcf8fSFrançois Tigeot if (crt->force_hotplug_required) { 179*e3adcf8fSFrançois Tigeot bool turn_off_dac = HAS_PCH_SPLIT(dev); 180*e3adcf8fSFrançois Tigeot u32 save_adpa; 181*e3adcf8fSFrançois Tigeot 182*e3adcf8fSFrançois Tigeot crt->force_hotplug_required = 0; 183*e3adcf8fSFrançois Tigeot 184*e3adcf8fSFrançois Tigeot save_adpa = adpa = I915_READ(PCH_ADPA); 185*e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); 186*e3adcf8fSFrançois Tigeot 187*e3adcf8fSFrançois Tigeot adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; 188*e3adcf8fSFrançois Tigeot if (turn_off_dac) 189*e3adcf8fSFrançois Tigeot adpa &= ~ADPA_DAC_ENABLE; 190*e3adcf8fSFrançois Tigeot 191*e3adcf8fSFrançois Tigeot I915_WRITE(PCH_ADPA, adpa); 192*e3adcf8fSFrançois Tigeot 193*e3adcf8fSFrançois Tigeot if (_intel_wait_for(dev, 194*e3adcf8fSFrançois Tigeot (I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, 195*e3adcf8fSFrançois Tigeot 1000, 1, "915crt")) 196*e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER\n"); 197*e3adcf8fSFrançois Tigeot 198*e3adcf8fSFrançois Tigeot if (turn_off_dac) { 199*e3adcf8fSFrançois Tigeot I915_WRITE(PCH_ADPA, save_adpa); 200*e3adcf8fSFrançois Tigeot POSTING_READ(PCH_ADPA); 201*e3adcf8fSFrançois Tigeot } 202*e3adcf8fSFrançois Tigeot } 203*e3adcf8fSFrançois Tigeot 204*e3adcf8fSFrançois Tigeot /* Check the status to see if both blue and green are on now */ 205*e3adcf8fSFrançois Tigeot adpa = I915_READ(PCH_ADPA); 206*e3adcf8fSFrançois Tigeot if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) 207*e3adcf8fSFrançois Tigeot ret = true; 208*e3adcf8fSFrançois Tigeot else 209*e3adcf8fSFrançois Tigeot ret = false; 210*e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret); 211*e3adcf8fSFrançois Tigeot 212*e3adcf8fSFrançois Tigeot return ret; 213*e3adcf8fSFrançois Tigeot } 214*e3adcf8fSFrançois Tigeot 215*e3adcf8fSFrançois Tigeot /** 216*e3adcf8fSFrançois Tigeot * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. 217*e3adcf8fSFrançois Tigeot * 218*e3adcf8fSFrançois Tigeot * Not for i915G/i915GM 219*e3adcf8fSFrançois Tigeot * 220*e3adcf8fSFrançois Tigeot * \return true if CRT is connected. 221*e3adcf8fSFrançois Tigeot * \return false if CRT is disconnected. 222*e3adcf8fSFrançois Tigeot */ 223*e3adcf8fSFrançois Tigeot static bool intel_crt_detect_hotplug(struct drm_connector *connector) 224*e3adcf8fSFrançois Tigeot { 225*e3adcf8fSFrançois Tigeot struct drm_device *dev = connector->dev; 226*e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 227*e3adcf8fSFrançois Tigeot u32 hotplug_en, orig, stat; 228*e3adcf8fSFrançois Tigeot bool ret = false; 229*e3adcf8fSFrançois Tigeot int i, tries = 0; 230*e3adcf8fSFrançois Tigeot 231*e3adcf8fSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) 232*e3adcf8fSFrançois Tigeot return intel_ironlake_crt_detect_hotplug(connector); 233*e3adcf8fSFrançois Tigeot 234*e3adcf8fSFrançois Tigeot /* 235*e3adcf8fSFrançois Tigeot * On 4 series desktop, CRT detect sequence need to be done twice 236*e3adcf8fSFrançois Tigeot * to get a reliable result. 237*e3adcf8fSFrançois Tigeot */ 238*e3adcf8fSFrançois Tigeot 239*e3adcf8fSFrançois Tigeot if (IS_G4X(dev) && !IS_GM45(dev)) 240*e3adcf8fSFrançois Tigeot tries = 2; 241*e3adcf8fSFrançois Tigeot else 242*e3adcf8fSFrançois Tigeot tries = 1; 243*e3adcf8fSFrançois Tigeot hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN); 244*e3adcf8fSFrançois Tigeot hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; 245*e3adcf8fSFrançois Tigeot 246*e3adcf8fSFrançois Tigeot for (i = 0; i < tries ; i++) { 247*e3adcf8fSFrançois Tigeot /* turn on the FORCE_DETECT */ 248*e3adcf8fSFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); 249*e3adcf8fSFrançois Tigeot /* wait for FORCE_DETECT to go off */ 250*e3adcf8fSFrançois Tigeot if (_intel_wait_for(dev, 251*e3adcf8fSFrançois Tigeot (I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0, 252*e3adcf8fSFrançois Tigeot 1000, 1, "915cr2")) 253*e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off"); 254*e3adcf8fSFrançois Tigeot } 255*e3adcf8fSFrançois Tigeot 256*e3adcf8fSFrançois Tigeot stat = I915_READ(PORT_HOTPLUG_STAT); 257*e3adcf8fSFrançois Tigeot if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE) 258*e3adcf8fSFrançois Tigeot ret = true; 259*e3adcf8fSFrançois Tigeot 260*e3adcf8fSFrançois Tigeot /* clear the interrupt we just generated, if any */ 261*e3adcf8fSFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS); 262*e3adcf8fSFrançois Tigeot 263*e3adcf8fSFrançois Tigeot /* and put the bits back */ 264*e3adcf8fSFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, orig); 265*e3adcf8fSFrançois Tigeot 266*e3adcf8fSFrançois Tigeot return ret; 267*e3adcf8fSFrançois Tigeot } 268*e3adcf8fSFrançois Tigeot 269*e3adcf8fSFrançois Tigeot static bool intel_crt_detect_ddc(struct drm_connector *connector) 270*e3adcf8fSFrançois Tigeot { 271*e3adcf8fSFrançois Tigeot struct intel_crt *crt = intel_attached_crt(connector); 272*e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private; 273*e3adcf8fSFrançois Tigeot 274*e3adcf8fSFrançois Tigeot /* CRT should always be at 0, but check anyway */ 275*e3adcf8fSFrançois Tigeot if (crt->base.type != INTEL_OUTPUT_ANALOG) 276*e3adcf8fSFrançois Tigeot return false; 277*e3adcf8fSFrançois Tigeot 278*e3adcf8fSFrançois Tigeot if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) { 279*e3adcf8fSFrançois Tigeot struct edid *edid; 280*e3adcf8fSFrançois Tigeot bool is_digital = false; 281*e3adcf8fSFrançois Tigeot 282*e3adcf8fSFrançois Tigeot edid = drm_get_edid(connector, 283*e3adcf8fSFrançois Tigeot dev_priv->gmbus[dev_priv->crt_ddc_pin]); 284*e3adcf8fSFrançois Tigeot /* 285*e3adcf8fSFrançois Tigeot * This may be a DVI-I connector with a shared DDC 286*e3adcf8fSFrançois Tigeot * link between analog and digital outputs, so we 287*e3adcf8fSFrançois Tigeot * have to check the EDID input spec of the attached device. 288*e3adcf8fSFrançois Tigeot * 289*e3adcf8fSFrançois Tigeot * On the other hand, what should we do if it is a broken EDID? 290*e3adcf8fSFrançois Tigeot */ 291*e3adcf8fSFrançois Tigeot if (edid != NULL) { 292*e3adcf8fSFrançois Tigeot is_digital = edid->input & DRM_EDID_INPUT_DIGITAL; 293*e3adcf8fSFrançois Tigeot connector->display_info.raw_edid = NULL; 294*e3adcf8fSFrançois Tigeot drm_free(edid, DRM_MEM_KMS); 295*e3adcf8fSFrançois Tigeot } 296*e3adcf8fSFrançois Tigeot 297*e3adcf8fSFrançois Tigeot if (!is_digital) { 298*e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n"); 299*e3adcf8fSFrançois Tigeot return true; 300*e3adcf8fSFrançois Tigeot } else { 301*e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n"); 302*e3adcf8fSFrançois Tigeot } 303*e3adcf8fSFrançois Tigeot } 304*e3adcf8fSFrançois Tigeot 305*e3adcf8fSFrançois Tigeot return false; 306*e3adcf8fSFrançois Tigeot } 307*e3adcf8fSFrançois Tigeot 308*e3adcf8fSFrançois Tigeot static enum drm_connector_status 309*e3adcf8fSFrançois Tigeot intel_crt_load_detect(struct intel_crt *crt) 310*e3adcf8fSFrançois Tigeot { 311*e3adcf8fSFrançois Tigeot struct drm_device *dev = crt->base.base.dev; 312*e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 313*e3adcf8fSFrançois Tigeot uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe; 314*e3adcf8fSFrançois Tigeot uint32_t save_bclrpat; 315*e3adcf8fSFrançois Tigeot uint32_t save_vtotal; 316*e3adcf8fSFrançois Tigeot uint32_t vtotal, vactive; 317*e3adcf8fSFrançois Tigeot uint32_t vsample; 318*e3adcf8fSFrançois Tigeot uint32_t vblank, vblank_start, vblank_end; 319*e3adcf8fSFrançois Tigeot uint32_t dsl; 320*e3adcf8fSFrançois Tigeot uint32_t bclrpat_reg; 321*e3adcf8fSFrançois Tigeot uint32_t vtotal_reg; 322*e3adcf8fSFrançois Tigeot uint32_t vblank_reg; 323*e3adcf8fSFrançois Tigeot uint32_t vsync_reg; 324*e3adcf8fSFrançois Tigeot uint32_t pipeconf_reg; 325*e3adcf8fSFrançois Tigeot uint32_t pipe_dsl_reg; 326*e3adcf8fSFrançois Tigeot uint8_t st00; 327*e3adcf8fSFrançois Tigeot enum drm_connector_status status; 328*e3adcf8fSFrançois Tigeot 329*e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("starting load-detect on CRT\n"); 330*e3adcf8fSFrançois Tigeot 331*e3adcf8fSFrançois Tigeot bclrpat_reg = BCLRPAT(pipe); 332*e3adcf8fSFrançois Tigeot vtotal_reg = VTOTAL(pipe); 333*e3adcf8fSFrançois Tigeot vblank_reg = VBLANK(pipe); 334*e3adcf8fSFrançois Tigeot vsync_reg = VSYNC(pipe); 335*e3adcf8fSFrançois Tigeot pipeconf_reg = PIPECONF(pipe); 336*e3adcf8fSFrançois Tigeot pipe_dsl_reg = PIPEDSL(pipe); 337*e3adcf8fSFrançois Tigeot 338*e3adcf8fSFrançois Tigeot save_bclrpat = I915_READ(bclrpat_reg); 339*e3adcf8fSFrançois Tigeot save_vtotal = I915_READ(vtotal_reg); 340*e3adcf8fSFrançois Tigeot vblank = I915_READ(vblank_reg); 341*e3adcf8fSFrançois Tigeot 342*e3adcf8fSFrançois Tigeot vtotal = ((save_vtotal >> 16) & 0xfff) + 1; 343*e3adcf8fSFrançois Tigeot vactive = (save_vtotal & 0x7ff) + 1; 344*e3adcf8fSFrançois Tigeot 345*e3adcf8fSFrançois Tigeot vblank_start = (vblank & 0xfff) + 1; 346*e3adcf8fSFrançois Tigeot vblank_end = ((vblank >> 16) & 0xfff) + 1; 347*e3adcf8fSFrançois Tigeot 348*e3adcf8fSFrançois Tigeot /* Set the border color to purple. */ 349*e3adcf8fSFrançois Tigeot I915_WRITE(bclrpat_reg, 0x500050); 350*e3adcf8fSFrançois Tigeot 351*e3adcf8fSFrançois Tigeot if (!IS_GEN2(dev)) { 352*e3adcf8fSFrançois Tigeot uint32_t pipeconf = I915_READ(pipeconf_reg); 353*e3adcf8fSFrançois Tigeot I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); 354*e3adcf8fSFrançois Tigeot POSTING_READ(pipeconf_reg); 355*e3adcf8fSFrançois Tigeot /* Wait for next Vblank to substitue 356*e3adcf8fSFrançois Tigeot * border color for Color info */ 357*e3adcf8fSFrançois Tigeot intel_wait_for_vblank(dev, pipe); 358*e3adcf8fSFrançois Tigeot st00 = I915_READ8(VGA_MSR_WRITE); 359*e3adcf8fSFrançois Tigeot status = ((st00 & (1 << 4)) != 0) ? 360*e3adcf8fSFrançois Tigeot connector_status_connected : 361*e3adcf8fSFrançois Tigeot connector_status_disconnected; 362*e3adcf8fSFrançois Tigeot 363*e3adcf8fSFrançois Tigeot I915_WRITE(pipeconf_reg, pipeconf); 364*e3adcf8fSFrançois Tigeot } else { 365*e3adcf8fSFrançois Tigeot bool restore_vblank = false; 366*e3adcf8fSFrançois Tigeot int count, detect; 367*e3adcf8fSFrançois Tigeot 368*e3adcf8fSFrançois Tigeot /* 369*e3adcf8fSFrançois Tigeot * If there isn't any border, add some. 370*e3adcf8fSFrançois Tigeot * Yes, this will flicker 371*e3adcf8fSFrançois Tigeot */ 372*e3adcf8fSFrançois Tigeot if (vblank_start <= vactive && vblank_end >= vtotal) { 373*e3adcf8fSFrançois Tigeot uint32_t vsync = I915_READ(vsync_reg); 374*e3adcf8fSFrançois Tigeot uint32_t vsync_start = (vsync & 0xffff) + 1; 375*e3adcf8fSFrançois Tigeot 376*e3adcf8fSFrançois Tigeot vblank_start = vsync_start; 377*e3adcf8fSFrançois Tigeot I915_WRITE(vblank_reg, 378*e3adcf8fSFrançois Tigeot (vblank_start - 1) | 379*e3adcf8fSFrançois Tigeot ((vblank_end - 1) << 16)); 380*e3adcf8fSFrançois Tigeot restore_vblank = true; 381*e3adcf8fSFrançois Tigeot } 382*e3adcf8fSFrançois Tigeot /* sample in the vertical border, selecting the larger one */ 383*e3adcf8fSFrançois Tigeot if (vblank_start - vactive >= vtotal - vblank_end) 384*e3adcf8fSFrançois Tigeot vsample = (vblank_start + vactive) >> 1; 385*e3adcf8fSFrançois Tigeot else 386*e3adcf8fSFrançois Tigeot vsample = (vtotal + vblank_end) >> 1; 387*e3adcf8fSFrançois Tigeot 388*e3adcf8fSFrançois Tigeot /* 389*e3adcf8fSFrançois Tigeot * Wait for the border to be displayed 390*e3adcf8fSFrançois Tigeot */ 391*e3adcf8fSFrançois Tigeot while (I915_READ(pipe_dsl_reg) >= vactive) 392*e3adcf8fSFrançois Tigeot ; 393*e3adcf8fSFrançois Tigeot while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample) 394*e3adcf8fSFrançois Tigeot ; 395*e3adcf8fSFrançois Tigeot /* 396*e3adcf8fSFrançois Tigeot * Watch ST00 for an entire scanline 397*e3adcf8fSFrançois Tigeot */ 398*e3adcf8fSFrançois Tigeot detect = 0; 399*e3adcf8fSFrançois Tigeot count = 0; 400*e3adcf8fSFrançois Tigeot do { 401*e3adcf8fSFrançois Tigeot count++; 402*e3adcf8fSFrançois Tigeot /* Read the ST00 VGA status register */ 403*e3adcf8fSFrançois Tigeot st00 = I915_READ8(VGA_MSR_WRITE); 404*e3adcf8fSFrançois Tigeot if (st00 & (1 << 4)) 405*e3adcf8fSFrançois Tigeot detect++; 406*e3adcf8fSFrançois Tigeot } while ((I915_READ(pipe_dsl_reg) == dsl)); 407*e3adcf8fSFrançois Tigeot 408*e3adcf8fSFrançois Tigeot /* restore vblank if necessary */ 409*e3adcf8fSFrançois Tigeot if (restore_vblank) 410*e3adcf8fSFrançois Tigeot I915_WRITE(vblank_reg, vblank); 411*e3adcf8fSFrançois Tigeot /* 412*e3adcf8fSFrançois Tigeot * If more than 3/4 of the scanline detected a monitor, 413*e3adcf8fSFrançois Tigeot * then it is assumed to be present. This works even on i830, 414*e3adcf8fSFrançois Tigeot * where there isn't any way to force the border color across 415*e3adcf8fSFrançois Tigeot * the screen 416*e3adcf8fSFrançois Tigeot */ 417*e3adcf8fSFrançois Tigeot status = detect * 4 > count * 3 ? 418*e3adcf8fSFrançois Tigeot connector_status_connected : 419*e3adcf8fSFrançois Tigeot connector_status_disconnected; 420*e3adcf8fSFrançois Tigeot } 421*e3adcf8fSFrançois Tigeot 422*e3adcf8fSFrançois Tigeot /* Restore previous settings */ 423*e3adcf8fSFrançois Tigeot I915_WRITE(bclrpat_reg, save_bclrpat); 424*e3adcf8fSFrançois Tigeot 425*e3adcf8fSFrançois Tigeot return status; 426*e3adcf8fSFrançois Tigeot } 427*e3adcf8fSFrançois Tigeot 428*e3adcf8fSFrançois Tigeot static enum drm_connector_status 429*e3adcf8fSFrançois Tigeot intel_crt_detect(struct drm_connector *connector, bool force) 430*e3adcf8fSFrançois Tigeot { 431*e3adcf8fSFrançois Tigeot struct drm_device *dev = connector->dev; 432*e3adcf8fSFrançois Tigeot struct intel_crt *crt = intel_attached_crt(connector); 433*e3adcf8fSFrançois Tigeot enum drm_connector_status status; 434*e3adcf8fSFrançois Tigeot struct intel_load_detect_pipe tmp; 435*e3adcf8fSFrançois Tigeot 436*e3adcf8fSFrançois Tigeot if (I915_HAS_HOTPLUG(dev)) { 437*e3adcf8fSFrançois Tigeot if (intel_crt_detect_hotplug(connector)) { 438*e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("CRT detected via hotplug\n"); 439*e3adcf8fSFrançois Tigeot return connector_status_connected; 440*e3adcf8fSFrançois Tigeot } else { 441*e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("CRT not detected via hotplug\n"); 442*e3adcf8fSFrançois Tigeot return connector_status_disconnected; 443*e3adcf8fSFrançois Tigeot } 444*e3adcf8fSFrançois Tigeot } 445*e3adcf8fSFrançois Tigeot 446*e3adcf8fSFrançois Tigeot if (intel_crt_detect_ddc(connector)) 447*e3adcf8fSFrançois Tigeot return connector_status_connected; 448*e3adcf8fSFrançois Tigeot 449*e3adcf8fSFrançois Tigeot if (!force) 450*e3adcf8fSFrançois Tigeot return connector->status; 451*e3adcf8fSFrançois Tigeot 452*e3adcf8fSFrançois Tigeot /* for pre-945g platforms use load detect */ 453*e3adcf8fSFrançois Tigeot if (intel_get_load_detect_pipe(&crt->base, connector, NULL, 454*e3adcf8fSFrançois Tigeot &tmp)) { 455*e3adcf8fSFrançois Tigeot if (intel_crt_detect_ddc(connector)) 456*e3adcf8fSFrançois Tigeot status = connector_status_connected; 457*e3adcf8fSFrançois Tigeot else 458*e3adcf8fSFrançois Tigeot status = intel_crt_load_detect(crt); 459*e3adcf8fSFrançois Tigeot intel_release_load_detect_pipe(&crt->base, connector, 460*e3adcf8fSFrançois Tigeot &tmp); 461*e3adcf8fSFrançois Tigeot } else 462*e3adcf8fSFrançois Tigeot status = connector_status_unknown; 463*e3adcf8fSFrançois Tigeot 464*e3adcf8fSFrançois Tigeot return status; 465*e3adcf8fSFrançois Tigeot } 466*e3adcf8fSFrançois Tigeot 467*e3adcf8fSFrançois Tigeot static void intel_crt_destroy(struct drm_connector *connector) 468*e3adcf8fSFrançois Tigeot { 469*e3adcf8fSFrançois Tigeot 470*e3adcf8fSFrançois Tigeot #if 0 471*e3adcf8fSFrançois Tigeot drm_sysfs_connector_remove(connector); 472*e3adcf8fSFrançois Tigeot #endif 473*e3adcf8fSFrançois Tigeot drm_connector_cleanup(connector); 474*e3adcf8fSFrançois Tigeot drm_free(connector, DRM_MEM_KMS); 475*e3adcf8fSFrançois Tigeot } 476*e3adcf8fSFrançois Tigeot 477*e3adcf8fSFrançois Tigeot static int intel_crt_get_modes(struct drm_connector *connector) 478*e3adcf8fSFrançois Tigeot { 479*e3adcf8fSFrançois Tigeot struct drm_device *dev = connector->dev; 480*e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 481*e3adcf8fSFrançois Tigeot int ret; 482*e3adcf8fSFrançois Tigeot 483*e3adcf8fSFrançois Tigeot ret = intel_ddc_get_modes(connector, 484*e3adcf8fSFrançois Tigeot dev_priv->gmbus[dev_priv->crt_ddc_pin]); 485*e3adcf8fSFrançois Tigeot if (ret || !IS_G4X(dev)) 486*e3adcf8fSFrançois Tigeot return ret; 487*e3adcf8fSFrançois Tigeot 488*e3adcf8fSFrançois Tigeot /* Try to probe digital port for output in DVI-I -> VGA mode. */ 489*e3adcf8fSFrançois Tigeot return (intel_ddc_get_modes(connector, 490*e3adcf8fSFrançois Tigeot dev_priv->gmbus[GMBUS_PORT_DPB])); 491*e3adcf8fSFrançois Tigeot } 492*e3adcf8fSFrançois Tigeot 493*e3adcf8fSFrançois Tigeot static int intel_crt_set_property(struct drm_connector *connector, 494*e3adcf8fSFrançois Tigeot struct drm_property *property, 495*e3adcf8fSFrançois Tigeot uint64_t value) 496*e3adcf8fSFrançois Tigeot { 497*e3adcf8fSFrançois Tigeot return 0; 498*e3adcf8fSFrançois Tigeot } 499*e3adcf8fSFrançois Tigeot 500*e3adcf8fSFrançois Tigeot static void intel_crt_reset(struct drm_connector *connector) 501*e3adcf8fSFrançois Tigeot { 502*e3adcf8fSFrançois Tigeot struct drm_device *dev = connector->dev; 503*e3adcf8fSFrançois Tigeot struct intel_crt *crt = intel_attached_crt(connector); 504*e3adcf8fSFrançois Tigeot 505*e3adcf8fSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) 506*e3adcf8fSFrançois Tigeot crt->force_hotplug_required = 1; 507*e3adcf8fSFrançois Tigeot } 508*e3adcf8fSFrançois Tigeot 509*e3adcf8fSFrançois Tigeot /* 510*e3adcf8fSFrançois Tigeot * Routines for controlling stuff on the analog port 511*e3adcf8fSFrançois Tigeot */ 512*e3adcf8fSFrançois Tigeot 513*e3adcf8fSFrançois Tigeot static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = { 514*e3adcf8fSFrançois Tigeot .dpms = intel_crt_dpms, 515*e3adcf8fSFrançois Tigeot .mode_fixup = intel_crt_mode_fixup, 516*e3adcf8fSFrançois Tigeot .prepare = intel_encoder_prepare, 517*e3adcf8fSFrançois Tigeot .commit = intel_encoder_commit, 518*e3adcf8fSFrançois Tigeot .mode_set = intel_crt_mode_set, 519*e3adcf8fSFrançois Tigeot }; 520*e3adcf8fSFrançois Tigeot 521*e3adcf8fSFrançois Tigeot static const struct drm_connector_funcs intel_crt_connector_funcs = { 522*e3adcf8fSFrançois Tigeot .reset = intel_crt_reset, 523*e3adcf8fSFrançois Tigeot .dpms = drm_helper_connector_dpms, 524*e3adcf8fSFrançois Tigeot .detect = intel_crt_detect, 525*e3adcf8fSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 526*e3adcf8fSFrançois Tigeot .destroy = intel_crt_destroy, 527*e3adcf8fSFrançois Tigeot .set_property = intel_crt_set_property, 528*e3adcf8fSFrançois Tigeot }; 529*e3adcf8fSFrançois Tigeot 530*e3adcf8fSFrançois Tigeot static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { 531*e3adcf8fSFrançois Tigeot .mode_valid = intel_crt_mode_valid, 532*e3adcf8fSFrançois Tigeot .get_modes = intel_crt_get_modes, 533*e3adcf8fSFrançois Tigeot .best_encoder = intel_best_encoder, 534*e3adcf8fSFrançois Tigeot }; 535*e3adcf8fSFrançois Tigeot 536*e3adcf8fSFrançois Tigeot static const struct drm_encoder_funcs intel_crt_enc_funcs = { 537*e3adcf8fSFrançois Tigeot .destroy = intel_encoder_destroy, 538*e3adcf8fSFrançois Tigeot }; 539*e3adcf8fSFrançois Tigeot 540*e3adcf8fSFrançois Tigeot static int intel_no_crt_dmi_callback(const struct dmi_system_id *id) 541*e3adcf8fSFrançois Tigeot { 542*e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("Skipping CRT initialization for %s\n", id->ident); 543*e3adcf8fSFrançois Tigeot return 1; 544*e3adcf8fSFrançois Tigeot } 545*e3adcf8fSFrançois Tigeot 546*e3adcf8fSFrançois Tigeot static const struct dmi_system_id intel_no_crt[] = { 547*e3adcf8fSFrançois Tigeot { 548*e3adcf8fSFrançois Tigeot .callback = intel_no_crt_dmi_callback, 549*e3adcf8fSFrançois Tigeot .ident = "ACER ZGB", 550*e3adcf8fSFrançois Tigeot .matches = { 551*e3adcf8fSFrançois Tigeot DMI_MATCH(DMI_SYS_VENDOR, "ACER"), 552*e3adcf8fSFrançois Tigeot DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"), 553*e3adcf8fSFrançois Tigeot }, 554*e3adcf8fSFrançois Tigeot }, 555*e3adcf8fSFrançois Tigeot { } 556*e3adcf8fSFrançois Tigeot }; 557*e3adcf8fSFrançois Tigeot 558*e3adcf8fSFrançois Tigeot void intel_crt_init(struct drm_device *dev) 559*e3adcf8fSFrançois Tigeot { 560*e3adcf8fSFrançois Tigeot struct drm_connector *connector; 561*e3adcf8fSFrançois Tigeot struct intel_crt *crt; 562*e3adcf8fSFrançois Tigeot struct intel_connector *intel_connector; 563*e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 564*e3adcf8fSFrançois Tigeot 565*e3adcf8fSFrançois Tigeot /* Skip machines without VGA that falsely report hotplug events */ 566*e3adcf8fSFrançois Tigeot if (dmi_check_system(intel_no_crt)) 567*e3adcf8fSFrançois Tigeot return; 568*e3adcf8fSFrançois Tigeot 569*e3adcf8fSFrançois Tigeot crt = kmalloc(sizeof(struct intel_crt), DRM_MEM_KMS, M_WAITOK | M_ZERO); 570*e3adcf8fSFrançois Tigeot intel_connector = kmalloc(sizeof(struct intel_connector), DRM_MEM_KMS, 571*e3adcf8fSFrançois Tigeot M_WAITOK | M_ZERO); 572*e3adcf8fSFrançois Tigeot 573*e3adcf8fSFrançois Tigeot connector = &intel_connector->base; 574*e3adcf8fSFrançois Tigeot drm_connector_init(dev, &intel_connector->base, 575*e3adcf8fSFrançois Tigeot &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); 576*e3adcf8fSFrançois Tigeot 577*e3adcf8fSFrançois Tigeot drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs, 578*e3adcf8fSFrançois Tigeot DRM_MODE_ENCODER_DAC); 579*e3adcf8fSFrançois Tigeot 580*e3adcf8fSFrançois Tigeot intel_connector_attach_encoder(intel_connector, &crt->base); 581*e3adcf8fSFrançois Tigeot 582*e3adcf8fSFrançois Tigeot crt->base.type = INTEL_OUTPUT_ANALOG; 583*e3adcf8fSFrançois Tigeot crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT | 584*e3adcf8fSFrançois Tigeot 1 << INTEL_ANALOG_CLONE_BIT | 585*e3adcf8fSFrançois Tigeot 1 << INTEL_SDVO_LVDS_CLONE_BIT); 586*e3adcf8fSFrançois Tigeot crt->base.crtc_mask = (1 << 0) | (1 << 1); 587*e3adcf8fSFrançois Tigeot if (IS_GEN2(dev)) 588*e3adcf8fSFrançois Tigeot connector->interlace_allowed = 0; 589*e3adcf8fSFrançois Tigeot else 590*e3adcf8fSFrançois Tigeot connector->interlace_allowed = 1; 591*e3adcf8fSFrançois Tigeot connector->doublescan_allowed = 0; 592*e3adcf8fSFrançois Tigeot 593*e3adcf8fSFrançois Tigeot drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs); 594*e3adcf8fSFrançois Tigeot drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); 595*e3adcf8fSFrançois Tigeot 596*e3adcf8fSFrançois Tigeot #if 0 597*e3adcf8fSFrançois Tigeot drm_sysfs_connector_add(connector); 598*e3adcf8fSFrançois Tigeot #endif 599*e3adcf8fSFrançois Tigeot 600*e3adcf8fSFrançois Tigeot if (I915_HAS_HOTPLUG(dev)) 601*e3adcf8fSFrançois Tigeot connector->polled = DRM_CONNECTOR_POLL_HPD; 602*e3adcf8fSFrançois Tigeot else 603*e3adcf8fSFrançois Tigeot connector->polled = DRM_CONNECTOR_POLL_CONNECT; 604*e3adcf8fSFrançois Tigeot 605*e3adcf8fSFrançois Tigeot /* 606*e3adcf8fSFrançois Tigeot * Configure the automatic hotplug detection stuff 607*e3adcf8fSFrançois Tigeot */ 608*e3adcf8fSFrançois Tigeot crt->force_hotplug_required = 0; 609*e3adcf8fSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) { 610*e3adcf8fSFrançois Tigeot u32 adpa; 611*e3adcf8fSFrançois Tigeot 612*e3adcf8fSFrançois Tigeot adpa = I915_READ(PCH_ADPA); 613*e3adcf8fSFrançois Tigeot adpa &= ~ADPA_CRT_HOTPLUG_MASK; 614*e3adcf8fSFrançois Tigeot adpa |= ADPA_HOTPLUG_BITS; 615*e3adcf8fSFrançois Tigeot I915_WRITE(PCH_ADPA, adpa); 616*e3adcf8fSFrançois Tigeot POSTING_READ(PCH_ADPA); 617*e3adcf8fSFrançois Tigeot 618*e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa); 619*e3adcf8fSFrançois Tigeot crt->force_hotplug_required = 1; 620*e3adcf8fSFrançois Tigeot } 621*e3adcf8fSFrançois Tigeot 622*e3adcf8fSFrançois Tigeot dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; 623*e3adcf8fSFrançois Tigeot } 624