1e3adcf8fSFrançois Tigeot /* 2e3adcf8fSFrançois Tigeot * Copyright © 2006-2007 Intel Corporation 3e3adcf8fSFrançois Tigeot * 4e3adcf8fSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 5e3adcf8fSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 6e3adcf8fSFrançois Tigeot * to deal in the Software without restriction, including without limitation 7e3adcf8fSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8e3adcf8fSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 9e3adcf8fSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 10e3adcf8fSFrançois Tigeot * 11e3adcf8fSFrançois Tigeot * The above copyright notice and this permission notice (including the next 12e3adcf8fSFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the 13e3adcf8fSFrançois Tigeot * Software. 14e3adcf8fSFrançois Tigeot * 15e3adcf8fSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16e3adcf8fSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17e3adcf8fSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18e3adcf8fSFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19e3adcf8fSFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20e3adcf8fSFrançois Tigeot * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21e3adcf8fSFrançois Tigeot * DEALINGS IN THE SOFTWARE. 22e3adcf8fSFrançois Tigeot * 23e3adcf8fSFrançois Tigeot * Authors: 24e3adcf8fSFrançois Tigeot * Eric Anholt <eric@anholt.net> 25e3adcf8fSFrançois Tigeot */ 26e3adcf8fSFrançois Tigeot 275d0b1887SFrançois Tigeot #include <linux/dmi.h> 285d0b1887SFrançois Tigeot #include <linux/i2c.h> 2918e26a6dSFrançois Tigeot #include <drm/drmP.h> 3018e26a6dSFrançois Tigeot #include <drm/drm_crtc.h> 3118e26a6dSFrançois Tigeot #include <drm/drm_crtc_helper.h> 3218e26a6dSFrançois Tigeot #include <drm/drm_edid.h> 3318e26a6dSFrançois Tigeot #include "intel_drv.h" 345c6c6f23SFrançois Tigeot #include <drm/i915_drm.h> 35e3adcf8fSFrançois Tigeot #include "i915_drv.h" 36e3adcf8fSFrançois Tigeot 37e3adcf8fSFrançois Tigeot /* Here's the desired hotplug mode */ 38e3adcf8fSFrançois Tigeot #define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 | \ 39e3adcf8fSFrançois Tigeot ADPA_CRT_HOTPLUG_WARMUP_10MS | \ 40e3adcf8fSFrançois Tigeot ADPA_CRT_HOTPLUG_SAMPLE_4S | \ 41e3adcf8fSFrançois Tigeot ADPA_CRT_HOTPLUG_VOLTAGE_50 | \ 42e3adcf8fSFrançois Tigeot ADPA_CRT_HOTPLUG_VOLREF_325MV | \ 43e3adcf8fSFrançois Tigeot ADPA_CRT_HOTPLUG_ENABLE) 44e3adcf8fSFrançois Tigeot 45e3adcf8fSFrançois Tigeot struct intel_crt { 46e3adcf8fSFrançois Tigeot struct intel_encoder base; 47e9243325SFrançois Tigeot /* DPMS state is stored in the connector, which we need in the 48e9243325SFrançois Tigeot * encoder's enable/disable callbacks */ 49e9243325SFrançois Tigeot struct intel_connector *connector; 50e3adcf8fSFrançois Tigeot bool force_hotplug_required; 51e9243325SFrançois Tigeot u32 adpa_reg; 52e3adcf8fSFrançois Tigeot }; 53e3adcf8fSFrançois Tigeot 5419df918dSFrançois Tigeot static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder) 55e3adcf8fSFrançois Tigeot { 5619df918dSFrançois Tigeot return container_of(encoder, struct intel_crt, base); 5719df918dSFrançois Tigeot } 5819df918dSFrançois Tigeot 59*9edbd4a0SFrançois Tigeot static struct intel_crt *intel_attached_crt(struct drm_connector *connector) 60*9edbd4a0SFrançois Tigeot { 61*9edbd4a0SFrançois Tigeot return intel_encoder_to_crt(intel_attached_encoder(connector)); 62*9edbd4a0SFrançois Tigeot } 63*9edbd4a0SFrançois Tigeot 6419df918dSFrançois Tigeot static bool intel_crt_get_hw_state(struct intel_encoder *encoder, 6519df918dSFrançois Tigeot enum i915_pipe *pipe) 6619df918dSFrançois Tigeot { 6719df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 68e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 6919df918dSFrançois Tigeot struct intel_crt *crt = intel_encoder_to_crt(encoder); 7019df918dSFrançois Tigeot u32 tmp; 71e3adcf8fSFrançois Tigeot 7219df918dSFrançois Tigeot tmp = I915_READ(crt->adpa_reg); 7319df918dSFrançois Tigeot 7419df918dSFrançois Tigeot if (!(tmp & ADPA_DAC_ENABLE)) 7519df918dSFrançois Tigeot return false; 7619df918dSFrançois Tigeot 7719df918dSFrançois Tigeot if (HAS_PCH_CPT(dev)) 7819df918dSFrançois Tigeot *pipe = PORT_TO_PIPE_CPT(tmp); 79e3adcf8fSFrançois Tigeot else 8019df918dSFrançois Tigeot *pipe = PORT_TO_PIPE(tmp); 81e3adcf8fSFrançois Tigeot 8219df918dSFrançois Tigeot return true; 8319df918dSFrançois Tigeot } 8419df918dSFrançois Tigeot 85*9edbd4a0SFrançois Tigeot static unsigned int intel_crt_get_flags(struct intel_encoder *encoder) 865d0b1887SFrançois Tigeot { 875d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; 885d0b1887SFrançois Tigeot struct intel_crt *crt = intel_encoder_to_crt(encoder); 895d0b1887SFrançois Tigeot u32 tmp, flags = 0; 905d0b1887SFrançois Tigeot 915d0b1887SFrançois Tigeot tmp = I915_READ(crt->adpa_reg); 925d0b1887SFrançois Tigeot 935d0b1887SFrançois Tigeot if (tmp & ADPA_HSYNC_ACTIVE_HIGH) 945d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_PHSYNC; 955d0b1887SFrançois Tigeot else 965d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_NHSYNC; 975d0b1887SFrançois Tigeot 985d0b1887SFrançois Tigeot if (tmp & ADPA_VSYNC_ACTIVE_HIGH) 995d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_PVSYNC; 1005d0b1887SFrançois Tigeot else 1015d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_NVSYNC; 1025d0b1887SFrançois Tigeot 103*9edbd4a0SFrançois Tigeot return flags; 104*9edbd4a0SFrançois Tigeot } 105*9edbd4a0SFrançois Tigeot 106*9edbd4a0SFrançois Tigeot static void intel_crt_get_config(struct intel_encoder *encoder, 107*9edbd4a0SFrançois Tigeot struct intel_crtc_config *pipe_config) 108*9edbd4a0SFrançois Tigeot { 109*9edbd4a0SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 110*9edbd4a0SFrançois Tigeot int dotclock; 111*9edbd4a0SFrançois Tigeot 112*9edbd4a0SFrançois Tigeot pipe_config->adjusted_mode.flags |= intel_crt_get_flags(encoder); 113*9edbd4a0SFrançois Tigeot 114*9edbd4a0SFrançois Tigeot dotclock = pipe_config->port_clock; 115*9edbd4a0SFrançois Tigeot 116*9edbd4a0SFrançois Tigeot if (HAS_PCH_SPLIT(dev)) 117*9edbd4a0SFrançois Tigeot ironlake_check_encoder_dotclock(pipe_config, dotclock); 118*9edbd4a0SFrançois Tigeot 119*9edbd4a0SFrançois Tigeot pipe_config->adjusted_mode.crtc_clock = dotclock; 120*9edbd4a0SFrançois Tigeot } 121*9edbd4a0SFrançois Tigeot 122*9edbd4a0SFrançois Tigeot static void hsw_crt_get_config(struct intel_encoder *encoder, 123*9edbd4a0SFrançois Tigeot struct intel_crtc_config *pipe_config) 124*9edbd4a0SFrançois Tigeot { 125*9edbd4a0SFrançois Tigeot intel_ddi_get_config(encoder, pipe_config); 126*9edbd4a0SFrançois Tigeot 127*9edbd4a0SFrançois Tigeot pipe_config->adjusted_mode.flags &= ~(DRM_MODE_FLAG_PHSYNC | 128*9edbd4a0SFrançois Tigeot DRM_MODE_FLAG_NHSYNC | 129*9edbd4a0SFrançois Tigeot DRM_MODE_FLAG_PVSYNC | 130*9edbd4a0SFrançois Tigeot DRM_MODE_FLAG_NVSYNC); 131*9edbd4a0SFrançois Tigeot pipe_config->adjusted_mode.flags |= intel_crt_get_flags(encoder); 1325d0b1887SFrançois Tigeot } 1335d0b1887SFrançois Tigeot 13419df918dSFrançois Tigeot /* Note: The caller is required to filter out dpms modes not supported by the 13519df918dSFrançois Tigeot * platform. */ 13619df918dSFrançois Tigeot static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) 13719df918dSFrançois Tigeot { 13819df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 13919df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 14019df918dSFrançois Tigeot struct intel_crt *crt = intel_encoder_to_crt(encoder); 14119df918dSFrançois Tigeot u32 temp; 14219df918dSFrançois Tigeot 14319df918dSFrançois Tigeot temp = I915_READ(crt->adpa_reg); 144e3adcf8fSFrançois Tigeot temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); 145e3adcf8fSFrançois Tigeot temp &= ~ADPA_DAC_ENABLE; 146e3adcf8fSFrançois Tigeot 147e3adcf8fSFrançois Tigeot switch (mode) { 148e3adcf8fSFrançois Tigeot case DRM_MODE_DPMS_ON: 149e3adcf8fSFrançois Tigeot temp |= ADPA_DAC_ENABLE; 150e3adcf8fSFrançois Tigeot break; 151e3adcf8fSFrançois Tigeot case DRM_MODE_DPMS_STANDBY: 152e3adcf8fSFrançois Tigeot temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; 153e3adcf8fSFrançois Tigeot break; 154e3adcf8fSFrançois Tigeot case DRM_MODE_DPMS_SUSPEND: 155e3adcf8fSFrançois Tigeot temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; 156e3adcf8fSFrançois Tigeot break; 157e3adcf8fSFrançois Tigeot case DRM_MODE_DPMS_OFF: 158e3adcf8fSFrançois Tigeot temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; 159e3adcf8fSFrançois Tigeot break; 160e3adcf8fSFrançois Tigeot } 161e3adcf8fSFrançois Tigeot 16219df918dSFrançois Tigeot I915_WRITE(crt->adpa_reg, temp); 16319df918dSFrançois Tigeot } 16419df918dSFrançois Tigeot 16519df918dSFrançois Tigeot static void intel_disable_crt(struct intel_encoder *encoder) 16619df918dSFrançois Tigeot { 16719df918dSFrançois Tigeot intel_crt_set_dpms(encoder, DRM_MODE_DPMS_OFF); 16819df918dSFrançois Tigeot } 16919df918dSFrançois Tigeot 17019df918dSFrançois Tigeot static void intel_enable_crt(struct intel_encoder *encoder) 17119df918dSFrançois Tigeot { 17219df918dSFrançois Tigeot struct intel_crt *crt = intel_encoder_to_crt(encoder); 17319df918dSFrançois Tigeot 17419df918dSFrançois Tigeot intel_crt_set_dpms(encoder, crt->connector->base.dpms); 17519df918dSFrançois Tigeot } 17619df918dSFrançois Tigeot 1775d0b1887SFrançois Tigeot /* Special dpms function to support cloning between dvo/sdvo/crt. */ 17819df918dSFrançois Tigeot static void intel_crt_dpms(struct drm_connector *connector, int mode) 17919df918dSFrançois Tigeot { 18019df918dSFrançois Tigeot struct drm_device *dev = connector->dev; 18119df918dSFrançois Tigeot struct intel_encoder *encoder = intel_attached_encoder(connector); 18219df918dSFrançois Tigeot struct drm_crtc *crtc; 18319df918dSFrançois Tigeot int old_dpms; 18419df918dSFrançois Tigeot 18519df918dSFrançois Tigeot /* PCH platforms and VLV only support on/off. */ 18619df918dSFrançois Tigeot if (INTEL_INFO(dev)->gen >= 5 && mode != DRM_MODE_DPMS_ON) 18719df918dSFrançois Tigeot mode = DRM_MODE_DPMS_OFF; 18819df918dSFrançois Tigeot 18919df918dSFrançois Tigeot if (mode == connector->dpms) 19019df918dSFrançois Tigeot return; 19119df918dSFrançois Tigeot 19219df918dSFrançois Tigeot old_dpms = connector->dpms; 19319df918dSFrançois Tigeot connector->dpms = mode; 19419df918dSFrançois Tigeot 19519df918dSFrançois Tigeot /* Only need to change hw state when actually enabled */ 19619df918dSFrançois Tigeot crtc = encoder->base.crtc; 19719df918dSFrançois Tigeot if (!crtc) { 19819df918dSFrançois Tigeot encoder->connectors_active = false; 19919df918dSFrançois Tigeot return; 20019df918dSFrançois Tigeot } 20119df918dSFrançois Tigeot 20219df918dSFrançois Tigeot /* We need the pipe to run for anything but OFF. */ 20319df918dSFrançois Tigeot if (mode == DRM_MODE_DPMS_OFF) 20419df918dSFrançois Tigeot encoder->connectors_active = false; 20519df918dSFrançois Tigeot else 20619df918dSFrançois Tigeot encoder->connectors_active = true; 20719df918dSFrançois Tigeot 2085d0b1887SFrançois Tigeot /* We call connector dpms manually below in case pipe dpms doesn't 2095d0b1887SFrançois Tigeot * change due to cloning. */ 21019df918dSFrançois Tigeot if (mode < old_dpms) { 21119df918dSFrançois Tigeot /* From off to on, enable the pipe first. */ 21219df918dSFrançois Tigeot intel_crtc_update_dpms(crtc); 21319df918dSFrançois Tigeot 21419df918dSFrançois Tigeot intel_crt_set_dpms(encoder, mode); 21519df918dSFrançois Tigeot } else { 21619df918dSFrançois Tigeot intel_crt_set_dpms(encoder, mode); 21719df918dSFrançois Tigeot 21819df918dSFrançois Tigeot intel_crtc_update_dpms(crtc); 21919df918dSFrançois Tigeot } 22019df918dSFrançois Tigeot 22119df918dSFrançois Tigeot intel_modeset_check_state(connector->dev); 222e3adcf8fSFrançois Tigeot } 223e3adcf8fSFrançois Tigeot 224*9edbd4a0SFrançois Tigeot static enum drm_mode_status 225*9edbd4a0SFrançois Tigeot intel_crt_mode_valid(struct drm_connector *connector, 226e3adcf8fSFrançois Tigeot struct drm_display_mode *mode) 227e3adcf8fSFrançois Tigeot { 228e3adcf8fSFrançois Tigeot struct drm_device *dev = connector->dev; 229e3adcf8fSFrançois Tigeot 230e3adcf8fSFrançois Tigeot int max_clock = 0; 231e3adcf8fSFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 232e3adcf8fSFrançois Tigeot return MODE_NO_DBLESCAN; 233e3adcf8fSFrançois Tigeot 234e3adcf8fSFrançois Tigeot if (mode->clock < 25000) 235e3adcf8fSFrançois Tigeot return MODE_CLOCK_LOW; 236e3adcf8fSFrançois Tigeot 237e3adcf8fSFrançois Tigeot if (IS_GEN2(dev)) 238e3adcf8fSFrançois Tigeot max_clock = 350000; 239e3adcf8fSFrançois Tigeot else 240e3adcf8fSFrançois Tigeot max_clock = 400000; 241e3adcf8fSFrançois Tigeot if (mode->clock > max_clock) 242e3adcf8fSFrançois Tigeot return MODE_CLOCK_HIGH; 243e3adcf8fSFrançois Tigeot 24419df918dSFrançois Tigeot /* The FDI receiver on LPT only supports 8bpc and only has 2 lanes. */ 24519df918dSFrançois Tigeot if (HAS_PCH_LPT(dev) && 24619df918dSFrançois Tigeot (ironlake_get_lanes_required(mode->clock, 270000, 24) > 2)) 24719df918dSFrançois Tigeot return MODE_CLOCK_HIGH; 24819df918dSFrançois Tigeot 249e3adcf8fSFrançois Tigeot return MODE_OK; 250e3adcf8fSFrançois Tigeot } 251e3adcf8fSFrançois Tigeot 2528e26cdf6SFrançois Tigeot static bool intel_crt_compute_config(struct intel_encoder *encoder, 2538e26cdf6SFrançois Tigeot struct intel_crtc_config *pipe_config) 254e3adcf8fSFrançois Tigeot { 2558e26cdf6SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 2568e26cdf6SFrançois Tigeot 2578e26cdf6SFrançois Tigeot if (HAS_PCH_SPLIT(dev)) 2588e26cdf6SFrançois Tigeot pipe_config->has_pch_encoder = true; 2598e26cdf6SFrançois Tigeot 2605d0b1887SFrançois Tigeot /* LPT FDI RX only supports 8bpc. */ 2615d0b1887SFrançois Tigeot if (HAS_PCH_LPT(dev)) 2625d0b1887SFrançois Tigeot pipe_config->pipe_bpp = 24; 2635d0b1887SFrançois Tigeot 264e3adcf8fSFrançois Tigeot return true; 265e3adcf8fSFrançois Tigeot } 266e3adcf8fSFrançois Tigeot 267*9edbd4a0SFrançois Tigeot static void intel_crt_mode_set(struct intel_encoder *encoder) 268e3adcf8fSFrançois Tigeot { 269e3adcf8fSFrançois Tigeot 270*9edbd4a0SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 271*9edbd4a0SFrançois Tigeot struct intel_crt *crt = intel_encoder_to_crt(encoder); 272*9edbd4a0SFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 273e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 274*9edbd4a0SFrançois Tigeot struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode; 27519df918dSFrançois Tigeot u32 adpa; 276e3adcf8fSFrançois Tigeot 277*9edbd4a0SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 5) 278e3adcf8fSFrançois Tigeot adpa = ADPA_HOTPLUG_BITS; 27919df918dSFrançois Tigeot else 28019df918dSFrançois Tigeot adpa = 0; 28119df918dSFrançois Tigeot 282e3adcf8fSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 283e3adcf8fSFrançois Tigeot adpa |= ADPA_HSYNC_ACTIVE_HIGH; 284e3adcf8fSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 285e3adcf8fSFrançois Tigeot adpa |= ADPA_VSYNC_ACTIVE_HIGH; 286e3adcf8fSFrançois Tigeot 287e3adcf8fSFrançois Tigeot /* For CPT allow 3 pipe config, for others just use A or B */ 28819df918dSFrançois Tigeot if (HAS_PCH_LPT(dev)) 28919df918dSFrançois Tigeot ; /* Those bits don't exist here */ 29019df918dSFrançois Tigeot else if (HAS_PCH_CPT(dev)) 291*9edbd4a0SFrançois Tigeot adpa |= PORT_TRANS_SEL_CPT(crtc->pipe); 292*9edbd4a0SFrançois Tigeot else if (crtc->pipe == 0) 293e3adcf8fSFrançois Tigeot adpa |= ADPA_PIPE_A_SELECT; 294e3adcf8fSFrançois Tigeot else 295e3adcf8fSFrançois Tigeot adpa |= ADPA_PIPE_B_SELECT; 296e3adcf8fSFrançois Tigeot 297e3adcf8fSFrançois Tigeot if (!HAS_PCH_SPLIT(dev)) 298*9edbd4a0SFrançois Tigeot I915_WRITE(BCLRPAT(crtc->pipe), 0); 299e3adcf8fSFrançois Tigeot 30019df918dSFrançois Tigeot I915_WRITE(crt->adpa_reg, adpa); 301e3adcf8fSFrançois Tigeot } 302e3adcf8fSFrançois Tigeot 303e3adcf8fSFrançois Tigeot static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) 304e3adcf8fSFrançois Tigeot { 305e3adcf8fSFrançois Tigeot struct drm_device *dev = connector->dev; 306e3adcf8fSFrançois Tigeot struct intel_crt *crt = intel_attached_crt(connector); 307e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 308e3adcf8fSFrançois Tigeot u32 adpa; 309e3adcf8fSFrançois Tigeot bool ret; 310e3adcf8fSFrançois Tigeot 311e3adcf8fSFrançois Tigeot /* The first time through, trigger an explicit detection cycle */ 312e3adcf8fSFrançois Tigeot if (crt->force_hotplug_required) { 313e3adcf8fSFrançois Tigeot bool turn_off_dac = HAS_PCH_SPLIT(dev); 314e3adcf8fSFrançois Tigeot u32 save_adpa; 315e3adcf8fSFrançois Tigeot 316e3adcf8fSFrançois Tigeot crt->force_hotplug_required = 0; 317e3adcf8fSFrançois Tigeot 318a2fdbec6SFrançois Tigeot save_adpa = adpa = I915_READ(crt->adpa_reg); 319e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); 320e3adcf8fSFrançois Tigeot 321e3adcf8fSFrançois Tigeot adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; 322e3adcf8fSFrançois Tigeot if (turn_off_dac) 323e3adcf8fSFrançois Tigeot adpa &= ~ADPA_DAC_ENABLE; 324e3adcf8fSFrançois Tigeot 325a2fdbec6SFrançois Tigeot I915_WRITE(crt->adpa_reg, adpa); 326e3adcf8fSFrançois Tigeot 327a2fdbec6SFrançois Tigeot if (wait_for((I915_READ(crt->adpa_reg) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, 32819df918dSFrançois Tigeot 1000)) 32919df918dSFrançois Tigeot DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); 330e3adcf8fSFrançois Tigeot 331e3adcf8fSFrançois Tigeot if (turn_off_dac) { 332a2fdbec6SFrançois Tigeot I915_WRITE(crt->adpa_reg, save_adpa); 333a2fdbec6SFrançois Tigeot POSTING_READ(crt->adpa_reg); 334e3adcf8fSFrançois Tigeot } 335e3adcf8fSFrançois Tigeot } 336e3adcf8fSFrançois Tigeot 337e3adcf8fSFrançois Tigeot /* Check the status to see if both blue and green are on now */ 338a2fdbec6SFrançois Tigeot adpa = I915_READ(crt->adpa_reg); 339e3adcf8fSFrançois Tigeot if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) 340e3adcf8fSFrançois Tigeot ret = true; 341e3adcf8fSFrançois Tigeot else 342e3adcf8fSFrançois Tigeot ret = false; 343e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret); 344e3adcf8fSFrançois Tigeot 345e3adcf8fSFrançois Tigeot return ret; 346e3adcf8fSFrançois Tigeot } 347e3adcf8fSFrançois Tigeot 34819df918dSFrançois Tigeot static bool valleyview_crt_detect_hotplug(struct drm_connector *connector) 34919df918dSFrançois Tigeot { 35019df918dSFrançois Tigeot struct drm_device *dev = connector->dev; 351a2fdbec6SFrançois Tigeot struct intel_crt *crt = intel_attached_crt(connector); 35219df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 35319df918dSFrançois Tigeot u32 adpa; 35419df918dSFrançois Tigeot bool ret; 35519df918dSFrançois Tigeot u32 save_adpa; 35619df918dSFrançois Tigeot 357a2fdbec6SFrançois Tigeot save_adpa = adpa = I915_READ(crt->adpa_reg); 35819df918dSFrançois Tigeot DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); 35919df918dSFrançois Tigeot 36019df918dSFrançois Tigeot adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; 36119df918dSFrançois Tigeot 362a2fdbec6SFrançois Tigeot I915_WRITE(crt->adpa_reg, adpa); 36319df918dSFrançois Tigeot 364a2fdbec6SFrançois Tigeot if (wait_for((I915_READ(crt->adpa_reg) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, 36519df918dSFrançois Tigeot 1000)) { 36619df918dSFrançois Tigeot DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); 367a2fdbec6SFrançois Tigeot I915_WRITE(crt->adpa_reg, save_adpa); 36819df918dSFrançois Tigeot } 36919df918dSFrançois Tigeot 37019df918dSFrançois Tigeot /* Check the status to see if both blue and green are on now */ 371a2fdbec6SFrançois Tigeot adpa = I915_READ(crt->adpa_reg); 37219df918dSFrançois Tigeot if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) 37319df918dSFrançois Tigeot ret = true; 37419df918dSFrançois Tigeot else 37519df918dSFrançois Tigeot ret = false; 37619df918dSFrançois Tigeot 37719df918dSFrançois Tigeot DRM_DEBUG_KMS("valleyview hotplug adpa=0x%x, result %d\n", adpa, ret); 37819df918dSFrançois Tigeot 37919df918dSFrançois Tigeot return ret; 38019df918dSFrançois Tigeot } 38119df918dSFrançois Tigeot 382e3adcf8fSFrançois Tigeot /** 383e3adcf8fSFrançois Tigeot * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. 384e3adcf8fSFrançois Tigeot * 385e3adcf8fSFrançois Tigeot * Not for i915G/i915GM 386e3adcf8fSFrançois Tigeot * 387e3adcf8fSFrançois Tigeot * \return true if CRT is connected. 388e3adcf8fSFrançois Tigeot * \return false if CRT is disconnected. 389e3adcf8fSFrançois Tigeot */ 390e3adcf8fSFrançois Tigeot static bool intel_crt_detect_hotplug(struct drm_connector *connector) 391e3adcf8fSFrançois Tigeot { 392e3adcf8fSFrançois Tigeot struct drm_device *dev = connector->dev; 393e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 394e3adcf8fSFrançois Tigeot u32 hotplug_en, orig, stat; 395e3adcf8fSFrançois Tigeot bool ret = false; 396e3adcf8fSFrançois Tigeot int i, tries = 0; 397e3adcf8fSFrançois Tigeot 398e3adcf8fSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) 399e3adcf8fSFrançois Tigeot return intel_ironlake_crt_detect_hotplug(connector); 400e3adcf8fSFrançois Tigeot 40119df918dSFrançois Tigeot if (IS_VALLEYVIEW(dev)) 40219df918dSFrançois Tigeot return valleyview_crt_detect_hotplug(connector); 40319df918dSFrançois Tigeot 404e3adcf8fSFrançois Tigeot /* 405e3adcf8fSFrançois Tigeot * On 4 series desktop, CRT detect sequence need to be done twice 406e3adcf8fSFrançois Tigeot * to get a reliable result. 407e3adcf8fSFrançois Tigeot */ 408e3adcf8fSFrançois Tigeot 409e3adcf8fSFrançois Tigeot if (IS_G4X(dev) && !IS_GM45(dev)) 410e3adcf8fSFrançois Tigeot tries = 2; 411e3adcf8fSFrançois Tigeot else 412e3adcf8fSFrançois Tigeot tries = 1; 413e3adcf8fSFrançois Tigeot hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN); 414e3adcf8fSFrançois Tigeot hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; 415e3adcf8fSFrançois Tigeot 416e3adcf8fSFrançois Tigeot for (i = 0; i < tries ; i++) { 417e3adcf8fSFrançois Tigeot /* turn on the FORCE_DETECT */ 418e3adcf8fSFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); 419e3adcf8fSFrançois Tigeot /* wait for FORCE_DETECT to go off */ 42019df918dSFrançois Tigeot if (wait_for((I915_READ(PORT_HOTPLUG_EN) & 42119df918dSFrançois Tigeot CRT_HOTPLUG_FORCE_DETECT) == 0, 42219df918dSFrançois Tigeot 1000)) 423e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off"); 424e3adcf8fSFrançois Tigeot } 425e3adcf8fSFrançois Tigeot 426e3adcf8fSFrançois Tigeot stat = I915_READ(PORT_HOTPLUG_STAT); 427e3adcf8fSFrançois Tigeot if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE) 428e3adcf8fSFrançois Tigeot ret = true; 429e3adcf8fSFrançois Tigeot 430e3adcf8fSFrançois Tigeot /* clear the interrupt we just generated, if any */ 431e3adcf8fSFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS); 432e3adcf8fSFrançois Tigeot 433e3adcf8fSFrançois Tigeot /* and put the bits back */ 434e3adcf8fSFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, orig); 435e3adcf8fSFrançois Tigeot 436e3adcf8fSFrançois Tigeot return ret; 437e3adcf8fSFrançois Tigeot } 438e3adcf8fSFrançois Tigeot 43919df918dSFrançois Tigeot static struct edid *intel_crt_get_edid(struct drm_connector *connector, 44019df918dSFrançois Tigeot struct device *i2c) 44119df918dSFrançois Tigeot { 44219df918dSFrançois Tigeot struct edid *edid; 44319df918dSFrançois Tigeot 44419df918dSFrançois Tigeot edid = drm_get_edid(connector, i2c); 44519df918dSFrançois Tigeot 44619df918dSFrançois Tigeot if (!edid && !intel_gmbus_is_forced_bit(i2c)) { 44719df918dSFrançois Tigeot DRM_DEBUG_KMS("CRT GMBUS EDID read failed, retry using GPIO bit-banging\n"); 44819df918dSFrançois Tigeot intel_gmbus_force_bit(i2c, true); 44919df918dSFrançois Tigeot edid = drm_get_edid(connector, i2c); 45019df918dSFrançois Tigeot intel_gmbus_force_bit(i2c, false); 45119df918dSFrançois Tigeot } 45219df918dSFrançois Tigeot 45319df918dSFrançois Tigeot return edid; 45419df918dSFrançois Tigeot } 45519df918dSFrançois Tigeot 45619df918dSFrançois Tigeot /* local version of intel_ddc_get_modes() to use intel_crt_get_edid() */ 45719df918dSFrançois Tigeot static int intel_crt_ddc_get_modes(struct drm_connector *connector, 45819df918dSFrançois Tigeot struct device *adapter) 45919df918dSFrançois Tigeot { 46019df918dSFrançois Tigeot struct edid *edid; 46119df918dSFrançois Tigeot int ret; 46219df918dSFrançois Tigeot 46319df918dSFrançois Tigeot edid = intel_crt_get_edid(connector, adapter); 46419df918dSFrançois Tigeot if (!edid) 46519df918dSFrançois Tigeot return 0; 46619df918dSFrançois Tigeot 46719df918dSFrançois Tigeot ret = intel_connector_update_modes(connector, edid); 468158486a6SFrançois Tigeot kfree(edid); 46919df918dSFrançois Tigeot 47019df918dSFrançois Tigeot return ret; 47119df918dSFrançois Tigeot } 47219df918dSFrançois Tigeot 473e3adcf8fSFrançois Tigeot static bool intel_crt_detect_ddc(struct drm_connector *connector) 474e3adcf8fSFrançois Tigeot { 475e3adcf8fSFrançois Tigeot struct intel_crt *crt = intel_attached_crt(connector); 476e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private; 477e3adcf8fSFrançois Tigeot struct edid *edid; 47819df918dSFrançois Tigeot struct device *i2c; 479e3adcf8fSFrançois Tigeot 48019df918dSFrançois Tigeot BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG); 48119df918dSFrançois Tigeot 4825d0b1887SFrançois Tigeot i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin); 48319df918dSFrançois Tigeot edid = intel_crt_get_edid(connector, i2c); 48419df918dSFrançois Tigeot 48519df918dSFrançois Tigeot if (edid) { 48619df918dSFrançois Tigeot bool is_digital = edid->input & DRM_EDID_INPUT_DIGITAL; 48719df918dSFrançois Tigeot 488e3adcf8fSFrançois Tigeot /* 489e3adcf8fSFrançois Tigeot * This may be a DVI-I connector with a shared DDC 490e3adcf8fSFrançois Tigeot * link between analog and digital outputs, so we 491e3adcf8fSFrançois Tigeot * have to check the EDID input spec of the attached device. 492e3adcf8fSFrançois Tigeot */ 493e3adcf8fSFrançois Tigeot if (!is_digital) { 494e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n"); 495e3adcf8fSFrançois Tigeot return true; 49619df918dSFrançois Tigeot } 49719df918dSFrançois Tigeot 498e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n"); 49919df918dSFrançois Tigeot } else { 50019df918dSFrançois Tigeot DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [no valid EDID found]\n"); 501e3adcf8fSFrançois Tigeot } 50219df918dSFrançois Tigeot 5035d0b1887SFrançois Tigeot kfree(edid); 504e3adcf8fSFrançois Tigeot 505e3adcf8fSFrançois Tigeot return false; 506e3adcf8fSFrançois Tigeot } 507e3adcf8fSFrançois Tigeot 508e3adcf8fSFrançois Tigeot static enum drm_connector_status 509e3adcf8fSFrançois Tigeot intel_crt_load_detect(struct intel_crt *crt) 510e3adcf8fSFrançois Tigeot { 511e3adcf8fSFrançois Tigeot struct drm_device *dev = crt->base.base.dev; 512e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 513e3adcf8fSFrançois Tigeot uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe; 514e3adcf8fSFrançois Tigeot uint32_t save_bclrpat; 515e3adcf8fSFrançois Tigeot uint32_t save_vtotal; 516e3adcf8fSFrançois Tigeot uint32_t vtotal, vactive; 517e3adcf8fSFrançois Tigeot uint32_t vsample; 518e3adcf8fSFrançois Tigeot uint32_t vblank, vblank_start, vblank_end; 519e3adcf8fSFrançois Tigeot uint32_t dsl; 520e3adcf8fSFrançois Tigeot uint32_t bclrpat_reg; 521e3adcf8fSFrançois Tigeot uint32_t vtotal_reg; 522e3adcf8fSFrançois Tigeot uint32_t vblank_reg; 523e3adcf8fSFrançois Tigeot uint32_t vsync_reg; 524e3adcf8fSFrançois Tigeot uint32_t pipeconf_reg; 525e3adcf8fSFrançois Tigeot uint32_t pipe_dsl_reg; 526e3adcf8fSFrançois Tigeot uint8_t st00; 527e3adcf8fSFrançois Tigeot enum drm_connector_status status; 528e3adcf8fSFrançois Tigeot 529e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("starting load-detect on CRT\n"); 530e3adcf8fSFrançois Tigeot 531e3adcf8fSFrançois Tigeot bclrpat_reg = BCLRPAT(pipe); 532e3adcf8fSFrançois Tigeot vtotal_reg = VTOTAL(pipe); 533e3adcf8fSFrançois Tigeot vblank_reg = VBLANK(pipe); 534e3adcf8fSFrançois Tigeot vsync_reg = VSYNC(pipe); 535e3adcf8fSFrançois Tigeot pipeconf_reg = PIPECONF(pipe); 536e3adcf8fSFrançois Tigeot pipe_dsl_reg = PIPEDSL(pipe); 537e3adcf8fSFrançois Tigeot 538e3adcf8fSFrançois Tigeot save_bclrpat = I915_READ(bclrpat_reg); 539e3adcf8fSFrançois Tigeot save_vtotal = I915_READ(vtotal_reg); 540e3adcf8fSFrançois Tigeot vblank = I915_READ(vblank_reg); 541e3adcf8fSFrançois Tigeot 542e3adcf8fSFrançois Tigeot vtotal = ((save_vtotal >> 16) & 0xfff) + 1; 543e3adcf8fSFrançois Tigeot vactive = (save_vtotal & 0x7ff) + 1; 544e3adcf8fSFrançois Tigeot 545e3adcf8fSFrançois Tigeot vblank_start = (vblank & 0xfff) + 1; 546e3adcf8fSFrançois Tigeot vblank_end = ((vblank >> 16) & 0xfff) + 1; 547e3adcf8fSFrançois Tigeot 548e3adcf8fSFrançois Tigeot /* Set the border color to purple. */ 549e3adcf8fSFrançois Tigeot I915_WRITE(bclrpat_reg, 0x500050); 550e3adcf8fSFrançois Tigeot 551e3adcf8fSFrançois Tigeot if (!IS_GEN2(dev)) { 552e3adcf8fSFrançois Tigeot uint32_t pipeconf = I915_READ(pipeconf_reg); 553e3adcf8fSFrançois Tigeot I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); 554e3adcf8fSFrançois Tigeot POSTING_READ(pipeconf_reg); 555e3adcf8fSFrançois Tigeot /* Wait for next Vblank to substitue 556e3adcf8fSFrançois Tigeot * border color for Color info */ 557e3adcf8fSFrançois Tigeot intel_wait_for_vblank(dev, pipe); 558e3adcf8fSFrançois Tigeot st00 = I915_READ8(VGA_MSR_WRITE); 559e3adcf8fSFrançois Tigeot status = ((st00 & (1 << 4)) != 0) ? 560e3adcf8fSFrançois Tigeot connector_status_connected : 561e3adcf8fSFrançois Tigeot connector_status_disconnected; 562e3adcf8fSFrançois Tigeot 563e3adcf8fSFrançois Tigeot I915_WRITE(pipeconf_reg, pipeconf); 564e3adcf8fSFrançois Tigeot } else { 565e3adcf8fSFrançois Tigeot bool restore_vblank = false; 566e3adcf8fSFrançois Tigeot int count, detect; 567e3adcf8fSFrançois Tigeot 568e3adcf8fSFrançois Tigeot /* 569e3adcf8fSFrançois Tigeot * If there isn't any border, add some. 570e3adcf8fSFrançois Tigeot * Yes, this will flicker 571e3adcf8fSFrançois Tigeot */ 572e3adcf8fSFrançois Tigeot if (vblank_start <= vactive && vblank_end >= vtotal) { 573e3adcf8fSFrançois Tigeot uint32_t vsync = I915_READ(vsync_reg); 574e3adcf8fSFrançois Tigeot uint32_t vsync_start = (vsync & 0xffff) + 1; 575e3adcf8fSFrançois Tigeot 576e3adcf8fSFrançois Tigeot vblank_start = vsync_start; 577e3adcf8fSFrançois Tigeot I915_WRITE(vblank_reg, 578e3adcf8fSFrançois Tigeot (vblank_start - 1) | 579e3adcf8fSFrançois Tigeot ((vblank_end - 1) << 16)); 580e3adcf8fSFrançois Tigeot restore_vblank = true; 581e3adcf8fSFrançois Tigeot } 582e3adcf8fSFrançois Tigeot /* sample in the vertical border, selecting the larger one */ 583e3adcf8fSFrançois Tigeot if (vblank_start - vactive >= vtotal - vblank_end) 584e3adcf8fSFrançois Tigeot vsample = (vblank_start + vactive) >> 1; 585e3adcf8fSFrançois Tigeot else 586e3adcf8fSFrançois Tigeot vsample = (vtotal + vblank_end) >> 1; 587e3adcf8fSFrançois Tigeot 588e3adcf8fSFrançois Tigeot /* 589e3adcf8fSFrançois Tigeot * Wait for the border to be displayed 590e3adcf8fSFrançois Tigeot */ 591e3adcf8fSFrançois Tigeot while (I915_READ(pipe_dsl_reg) >= vactive) 592e3adcf8fSFrançois Tigeot ; 593e3adcf8fSFrançois Tigeot while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample) 594e3adcf8fSFrançois Tigeot ; 595e3adcf8fSFrançois Tigeot /* 596e3adcf8fSFrançois Tigeot * Watch ST00 for an entire scanline 597e3adcf8fSFrançois Tigeot */ 598e3adcf8fSFrançois Tigeot detect = 0; 599e3adcf8fSFrançois Tigeot count = 0; 600e3adcf8fSFrançois Tigeot do { 601e3adcf8fSFrançois Tigeot count++; 602e3adcf8fSFrançois Tigeot /* Read the ST00 VGA status register */ 603e3adcf8fSFrançois Tigeot st00 = I915_READ8(VGA_MSR_WRITE); 604e3adcf8fSFrançois Tigeot if (st00 & (1 << 4)) 605e3adcf8fSFrançois Tigeot detect++; 606e3adcf8fSFrançois Tigeot } while ((I915_READ(pipe_dsl_reg) == dsl)); 607e3adcf8fSFrançois Tigeot 608e3adcf8fSFrançois Tigeot /* restore vblank if necessary */ 609e3adcf8fSFrançois Tigeot if (restore_vblank) 610e3adcf8fSFrançois Tigeot I915_WRITE(vblank_reg, vblank); 611e3adcf8fSFrançois Tigeot /* 612e3adcf8fSFrançois Tigeot * If more than 3/4 of the scanline detected a monitor, 613e3adcf8fSFrançois Tigeot * then it is assumed to be present. This works even on i830, 614e3adcf8fSFrançois Tigeot * where there isn't any way to force the border color across 615e3adcf8fSFrançois Tigeot * the screen 616e3adcf8fSFrançois Tigeot */ 617e3adcf8fSFrançois Tigeot status = detect * 4 > count * 3 ? 618e3adcf8fSFrançois Tigeot connector_status_connected : 619e3adcf8fSFrançois Tigeot connector_status_disconnected; 620e3adcf8fSFrançois Tigeot } 621e3adcf8fSFrançois Tigeot 622e3adcf8fSFrançois Tigeot /* Restore previous settings */ 623e3adcf8fSFrançois Tigeot I915_WRITE(bclrpat_reg, save_bclrpat); 624e3adcf8fSFrançois Tigeot 625e3adcf8fSFrançois Tigeot return status; 626e3adcf8fSFrançois Tigeot } 627e3adcf8fSFrançois Tigeot 628e3adcf8fSFrançois Tigeot static enum drm_connector_status 629e3adcf8fSFrançois Tigeot intel_crt_detect(struct drm_connector *connector, bool force) 630e3adcf8fSFrançois Tigeot { 631e3adcf8fSFrançois Tigeot struct drm_device *dev = connector->dev; 632e3adcf8fSFrançois Tigeot struct intel_crt *crt = intel_attached_crt(connector); 633e3adcf8fSFrançois Tigeot enum drm_connector_status status; 634e3adcf8fSFrançois Tigeot struct intel_load_detect_pipe tmp; 635e3adcf8fSFrançois Tigeot 636*9edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n", 637*9edbd4a0SFrançois Tigeot connector->base.id, drm_get_connector_name(connector), 638*9edbd4a0SFrançois Tigeot force); 639*9edbd4a0SFrançois Tigeot 640e3adcf8fSFrançois Tigeot if (I915_HAS_HOTPLUG(dev)) { 64119df918dSFrançois Tigeot /* We can not rely on the HPD pin always being correctly wired 64219df918dSFrançois Tigeot * up, for example many KVM do not pass it through, and so 64319df918dSFrançois Tigeot * only trust an assertion that the monitor is connected. 64419df918dSFrançois Tigeot */ 645e3adcf8fSFrançois Tigeot if (intel_crt_detect_hotplug(connector)) { 646e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("CRT detected via hotplug\n"); 647e3adcf8fSFrançois Tigeot return connector_status_connected; 64819df918dSFrançois Tigeot } else 649e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("CRT not detected via hotplug\n"); 650e3adcf8fSFrançois Tigeot } 651e3adcf8fSFrançois Tigeot 652e3adcf8fSFrançois Tigeot if (intel_crt_detect_ddc(connector)) 653e3adcf8fSFrançois Tigeot return connector_status_connected; 654e3adcf8fSFrançois Tigeot 65519df918dSFrançois Tigeot /* Load detection is broken on HPD capable machines. Whoever wants a 65619df918dSFrançois Tigeot * broken monitor (without edid) to work behind a broken kvm (that fails 65719df918dSFrançois Tigeot * to have the right resistors for HP detection) needs to fix this up. 65819df918dSFrançois Tigeot * For now just bail out. */ 65919df918dSFrançois Tigeot if (I915_HAS_HOTPLUG(dev)) 66019df918dSFrançois Tigeot return connector_status_disconnected; 66119df918dSFrançois Tigeot 662e3adcf8fSFrançois Tigeot if (!force) 663e3adcf8fSFrançois Tigeot return connector->status; 664e3adcf8fSFrançois Tigeot 665e3adcf8fSFrançois Tigeot /* for pre-945g platforms use load detect */ 66619df918dSFrançois Tigeot if (intel_get_load_detect_pipe(connector, NULL, &tmp)) { 667e3adcf8fSFrançois Tigeot if (intel_crt_detect_ddc(connector)) 668e3adcf8fSFrançois Tigeot status = connector_status_connected; 669e3adcf8fSFrançois Tigeot else 670e3adcf8fSFrançois Tigeot status = intel_crt_load_detect(crt); 67119df918dSFrançois Tigeot intel_release_load_detect_pipe(connector, &tmp); 672e3adcf8fSFrançois Tigeot } else 673e3adcf8fSFrançois Tigeot status = connector_status_unknown; 674e3adcf8fSFrançois Tigeot 675e3adcf8fSFrançois Tigeot return status; 676e3adcf8fSFrançois Tigeot } 677e3adcf8fSFrançois Tigeot 678e3adcf8fSFrançois Tigeot static void intel_crt_destroy(struct drm_connector *connector) 679e3adcf8fSFrançois Tigeot { 680e3adcf8fSFrançois Tigeot drm_connector_cleanup(connector); 6815d0b1887SFrançois Tigeot kfree(connector); 682e3adcf8fSFrançois Tigeot } 683e3adcf8fSFrançois Tigeot 684e3adcf8fSFrançois Tigeot static int intel_crt_get_modes(struct drm_connector *connector) 685e3adcf8fSFrançois Tigeot { 686e3adcf8fSFrançois Tigeot struct drm_device *dev = connector->dev; 687e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 688e3adcf8fSFrançois Tigeot int ret; 68919df918dSFrançois Tigeot struct device *i2c; 690e3adcf8fSFrançois Tigeot 6915d0b1887SFrançois Tigeot i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin); 69219df918dSFrançois Tigeot ret = intel_crt_ddc_get_modes(connector, i2c); 693e3adcf8fSFrançois Tigeot if (ret || !IS_G4X(dev)) 694e3adcf8fSFrançois Tigeot return ret; 695e3adcf8fSFrançois Tigeot 696e3adcf8fSFrançois Tigeot /* Try to probe digital port for output in DVI-I -> VGA mode. */ 69719df918dSFrançois Tigeot i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB); 69819df918dSFrançois Tigeot return intel_crt_ddc_get_modes(connector, i2c); 699e3adcf8fSFrançois Tigeot } 700e3adcf8fSFrançois Tigeot 701e3adcf8fSFrançois Tigeot static int intel_crt_set_property(struct drm_connector *connector, 702e3adcf8fSFrançois Tigeot struct drm_property *property, 703e3adcf8fSFrançois Tigeot uint64_t value) 704e3adcf8fSFrançois Tigeot { 705e3adcf8fSFrançois Tigeot return 0; 706e3adcf8fSFrançois Tigeot } 707e3adcf8fSFrançois Tigeot 708e3adcf8fSFrançois Tigeot static void intel_crt_reset(struct drm_connector *connector) 709e3adcf8fSFrançois Tigeot { 710e3adcf8fSFrançois Tigeot struct drm_device *dev = connector->dev; 71119df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 712e3adcf8fSFrançois Tigeot struct intel_crt *crt = intel_attached_crt(connector); 713e3adcf8fSFrançois Tigeot 714*9edbd4a0SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 5) { 71519df918dSFrançois Tigeot u32 adpa; 71619df918dSFrançois Tigeot 717a2fdbec6SFrançois Tigeot adpa = I915_READ(crt->adpa_reg); 71819df918dSFrançois Tigeot adpa &= ~ADPA_CRT_HOTPLUG_MASK; 71919df918dSFrançois Tigeot adpa |= ADPA_HOTPLUG_BITS; 720a2fdbec6SFrançois Tigeot I915_WRITE(crt->adpa_reg, adpa); 721a2fdbec6SFrançois Tigeot POSTING_READ(crt->adpa_reg); 72219df918dSFrançois Tigeot 72319df918dSFrançois Tigeot DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa); 724e3adcf8fSFrançois Tigeot crt->force_hotplug_required = 1; 725e3adcf8fSFrançois Tigeot } 726e3adcf8fSFrançois Tigeot 72719df918dSFrançois Tigeot } 72819df918dSFrançois Tigeot 729e3adcf8fSFrançois Tigeot /* 730e3adcf8fSFrançois Tigeot * Routines for controlling stuff on the analog port 731e3adcf8fSFrançois Tigeot */ 732e3adcf8fSFrançois Tigeot 733e3adcf8fSFrançois Tigeot static const struct drm_connector_funcs intel_crt_connector_funcs = { 734e3adcf8fSFrançois Tigeot .reset = intel_crt_reset, 73519df918dSFrançois Tigeot .dpms = intel_crt_dpms, 736e3adcf8fSFrançois Tigeot .detect = intel_crt_detect, 737e3adcf8fSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 738e3adcf8fSFrançois Tigeot .destroy = intel_crt_destroy, 739e3adcf8fSFrançois Tigeot .set_property = intel_crt_set_property, 740e3adcf8fSFrançois Tigeot }; 741e3adcf8fSFrançois Tigeot 742e3adcf8fSFrançois Tigeot static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { 743e3adcf8fSFrançois Tigeot .mode_valid = intel_crt_mode_valid, 744e3adcf8fSFrançois Tigeot .get_modes = intel_crt_get_modes, 745e3adcf8fSFrançois Tigeot .best_encoder = intel_best_encoder, 746e3adcf8fSFrançois Tigeot }; 747e3adcf8fSFrançois Tigeot 748e3adcf8fSFrançois Tigeot static const struct drm_encoder_funcs intel_crt_enc_funcs = { 749e3adcf8fSFrançois Tigeot .destroy = intel_encoder_destroy, 750e3adcf8fSFrançois Tigeot }; 751e3adcf8fSFrançois Tigeot 75219df918dSFrançois Tigeot static int __init intel_no_crt_dmi_callback(const struct dmi_system_id *id) 753e3adcf8fSFrançois Tigeot { 75419df918dSFrançois Tigeot DRM_INFO("Skipping CRT initialization for %s\n", id->ident); 755e3adcf8fSFrançois Tigeot return 1; 756e3adcf8fSFrançois Tigeot } 757e3adcf8fSFrançois Tigeot 758e3adcf8fSFrançois Tigeot static const struct dmi_system_id intel_no_crt[] = { 759e3adcf8fSFrançois Tigeot { 760e3adcf8fSFrançois Tigeot .callback = intel_no_crt_dmi_callback, 761e3adcf8fSFrançois Tigeot .ident = "ACER ZGB", 762e3adcf8fSFrançois Tigeot .matches = { 763e3adcf8fSFrançois Tigeot DMI_MATCH(DMI_SYS_VENDOR, "ACER"), 764e3adcf8fSFrançois Tigeot DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"), 765e3adcf8fSFrançois Tigeot }, 766e3adcf8fSFrançois Tigeot }, 767e3adcf8fSFrançois Tigeot { } 768e3adcf8fSFrançois Tigeot }; 769e3adcf8fSFrançois Tigeot 770e3adcf8fSFrançois Tigeot void intel_crt_init(struct drm_device *dev) 771e3adcf8fSFrançois Tigeot { 772e3adcf8fSFrançois Tigeot struct drm_connector *connector; 773e3adcf8fSFrançois Tigeot struct intel_crt *crt; 774e3adcf8fSFrançois Tigeot struct intel_connector *intel_connector; 775e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 776e3adcf8fSFrançois Tigeot 777e3adcf8fSFrançois Tigeot /* Skip machines without VGA that falsely report hotplug events */ 778e3adcf8fSFrançois Tigeot if (dmi_check_system(intel_no_crt)) 779e3adcf8fSFrançois Tigeot return; 780e3adcf8fSFrançois Tigeot 781159fc1d7SFrançois Tigeot crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL); 78219df918dSFrançois Tigeot if (!crt) 78319df918dSFrançois Tigeot return; 78419df918dSFrançois Tigeot 785*9edbd4a0SFrançois Tigeot intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL); 78619df918dSFrançois Tigeot if (!intel_connector) { 787158486a6SFrançois Tigeot kfree(crt); 78819df918dSFrançois Tigeot return; 78919df918dSFrançois Tigeot } 790e3adcf8fSFrançois Tigeot 791e3adcf8fSFrançois Tigeot connector = &intel_connector->base; 79219df918dSFrançois Tigeot crt->connector = intel_connector; 793e3adcf8fSFrançois Tigeot drm_connector_init(dev, &intel_connector->base, 794e3adcf8fSFrançois Tigeot &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); 795e3adcf8fSFrançois Tigeot 796e3adcf8fSFrançois Tigeot drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs, 797e3adcf8fSFrançois Tigeot DRM_MODE_ENCODER_DAC); 798e3adcf8fSFrançois Tigeot 799e3adcf8fSFrançois Tigeot intel_connector_attach_encoder(intel_connector, &crt->base); 800e3adcf8fSFrançois Tigeot 801e3adcf8fSFrançois Tigeot crt->base.type = INTEL_OUTPUT_ANALOG; 80219df918dSFrançois Tigeot crt->base.cloneable = true; 803e9243325SFrançois Tigeot if (IS_I830(dev)) 804e9243325SFrançois Tigeot crt->base.crtc_mask = (1 << 0); 805e9243325SFrançois Tigeot else 806e9243325SFrançois Tigeot crt->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); 807e9243325SFrançois Tigeot 808e3adcf8fSFrançois Tigeot if (IS_GEN2(dev)) 809e3adcf8fSFrançois Tigeot connector->interlace_allowed = 0; 810e3adcf8fSFrançois Tigeot else 811e3adcf8fSFrançois Tigeot connector->interlace_allowed = 1; 812e3adcf8fSFrançois Tigeot connector->doublescan_allowed = 0; 813e3adcf8fSFrançois Tigeot 814e9243325SFrançois Tigeot if (HAS_PCH_SPLIT(dev)) 815e9243325SFrançois Tigeot crt->adpa_reg = PCH_ADPA; 816e9243325SFrançois Tigeot else if (IS_VALLEYVIEW(dev)) 817e9243325SFrançois Tigeot crt->adpa_reg = VLV_ADPA; 818e9243325SFrançois Tigeot else 819e9243325SFrançois Tigeot crt->adpa_reg = ADPA; 820e9243325SFrançois Tigeot 8218e26cdf6SFrançois Tigeot crt->base.compute_config = intel_crt_compute_config; 822*9edbd4a0SFrançois Tigeot crt->base.mode_set = intel_crt_mode_set; 82319df918dSFrançois Tigeot crt->base.disable = intel_disable_crt; 82419df918dSFrançois Tigeot crt->base.enable = intel_enable_crt; 8258e26cdf6SFrançois Tigeot if (I915_HAS_HOTPLUG(dev)) 8268e26cdf6SFrançois Tigeot crt->base.hpd_pin = HPD_CRT; 827*9edbd4a0SFrançois Tigeot if (HAS_DDI(dev)) { 828*9edbd4a0SFrançois Tigeot crt->base.get_config = hsw_crt_get_config; 82919df918dSFrançois Tigeot crt->base.get_hw_state = intel_ddi_get_hw_state; 830*9edbd4a0SFrançois Tigeot } else { 831*9edbd4a0SFrançois Tigeot crt->base.get_config = intel_crt_get_config; 83219df918dSFrançois Tigeot crt->base.get_hw_state = intel_crt_get_hw_state; 833*9edbd4a0SFrançois Tigeot } 83419df918dSFrançois Tigeot intel_connector->get_hw_state = intel_connector_get_hw_state; 83519df918dSFrançois Tigeot 836e3adcf8fSFrançois Tigeot drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); 837e3adcf8fSFrançois Tigeot 838e3adcf8fSFrançois Tigeot drm_sysfs_connector_add(connector); 839e3adcf8fSFrançois Tigeot 8408e26cdf6SFrançois Tigeot if (!I915_HAS_HOTPLUG(dev)) 8418e26cdf6SFrançois Tigeot intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; 842e3adcf8fSFrançois Tigeot 843e3adcf8fSFrançois Tigeot /* 844e3adcf8fSFrançois Tigeot * Configure the automatic hotplug detection stuff 845e3adcf8fSFrançois Tigeot */ 846e3adcf8fSFrançois Tigeot crt->force_hotplug_required = 0; 847e3adcf8fSFrançois Tigeot 84819df918dSFrançois Tigeot /* 84919df918dSFrançois Tigeot * TODO: find a proper way to discover whether we need to set the the 85019df918dSFrançois Tigeot * polarity and link reversal bits or not, instead of relying on the 85119df918dSFrançois Tigeot * BIOS. 85219df918dSFrançois Tigeot */ 85319df918dSFrançois Tigeot if (HAS_PCH_LPT(dev)) { 85419df918dSFrançois Tigeot u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT | 85519df918dSFrançois Tigeot FDI_RX_LINK_REVERSAL_OVERRIDE; 85619df918dSFrançois Tigeot 85719df918dSFrançois Tigeot dev_priv->fdi_rx_config = I915_READ(_FDI_RXA_CTL) & fdi_config; 85819df918dSFrançois Tigeot } 859e3adcf8fSFrançois Tigeot } 860