From 39d9b85a4d4fa1642663ca0d208b5c246a3d6f50 Mon Sep 17 00:00:00 2001 From: Gary Wang Date: Fri, 28 Aug 2015 16:40:34 +0800 Subject: drm/i915: set CDCLK if DPLL0 enabled during resuming from S3 Since BIOS RC 1.4 it would enable CDCLK PLL during BIOS S3 resume, then driver needs to set CDCLK to avoid display corruption if DPLL0 enabled. References: https://bugs.freedesktop.org/show_bug.cgi?id=91697 Reviewed-by: Rodrigo Vivi Reviewed-by: Damien Lespiau Reviewed-by: Cooper Chiou Reviewed-by: Wei Shun Chang Tested-by: Gary Wang Cc: Daniel Vetter Cc: Gavin Hindman Cc: Chris Wilson Cc: Xiong Y Zhang Signed-off-by: Gary Wang Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 53f5476..8ea9821 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5712,16 +5712,13 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv) /* enable PG1 and Misc I/O */ intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); - /* DPLL0 already enabed !? */ - if (I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE) { - DRM_DEBUG_DRIVER("DPLL0 already running\n"); - return; + /* DPLL0 not enabled (happens on early BIOS versions) */ + if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) { + /* enable DPLL0 */ + required_vco = skl_cdclk_get_vco(dev_priv->skl_boot_cdclk); + skl_dpll0_enable(dev_priv, required_vco); } - /* enable DPLL0 */ - required_vco = skl_cdclk_get_vco(dev_priv->skl_boot_cdclk); - skl_dpll0_enable(dev_priv, required_vco); - /* set CDCLK to the frequency the BIOS chose */ skl_set_cdclk(dev_priv, dev_priv->skl_boot_cdclk); -- cgit v0.10.2 From d14e7b6d1d8747826cb900db852351c550e00fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 20 Aug 2015 19:37:29 +0300 Subject: drm/i915: Check DP link status on long hpd too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are no longer checkling the DP link status on long hpd. We used to do that from the .hot_plug() handler, but it was removed when MST got introduced. If there's no userspace we now fail to retrain the link if the sink power is toggled (or cable yanked and replugged), meaning the user is left staring at a blank screen. With the retraining put back that should be fixed. Also remove the leftover comment that referred to the old retraining from .hot_plug(). Fixes a regression introduced in: commit 0e32b39ceed665bfa4a77a4bc307b6652b991632 Author: Dave Airlie Date: Fri May 2 14:02:48 2014 +1000 drm/i915: add DP 1.2 MST support (v0.7) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89453 Tested-by: Palmer Dabbelt Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91407 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89461 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89594 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=85641 Cc: Dave Airlie Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3781cd3..94686cb 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4961,9 +4961,12 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) intel_dp_probe_oui(intel_dp); - if (!intel_dp_probe_mst(intel_dp)) + if (!intel_dp_probe_mst(intel_dp)) { + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + intel_dp_check_link_status(intel_dp); + drm_modeset_unlock(&dev->mode_config.connection_mutex); goto mst_fail; - + } } else { if (intel_dp->is_mst) { if (intel_dp_check_mst_status(intel_dp) == -EINVAL) @@ -4971,10 +4974,6 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) } if (!intel_dp->is_mst) { - /* - * we'll check the link status via the normal hot plug path later - - * but for short hpds we should check it now - */ drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); intel_dp_check_link_status(intel_dp); drm_modeset_unlock(&dev->mode_config.connection_mutex); -- cgit v0.10.2 From 54875571bbfde00fc63741715c531cbb5246c3b2 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 30 Jun 2015 17:06:47 +0300 Subject: drm/i915: apply the PCI_D0/D3 hibernation workaround everywhere on pre GEN6 commit da2bc1b9db3351addd293e5b82757efe1f77ed1d Author: Imre Deak Date: Thu Oct 23 19:23:26 2014 +0300 drm/i915: add poweroff_late handler introduced a regression on old platforms during hibernation. A workaround was added in commit ab3be73fa7b43f4c3648ce29b5fd649ea54d3adb Author: Imre Deak Date: Mon Mar 2 13:04:41 2015 +0200 drm/i915: gen4: work around hang during hibernation using an explicit blacklist for the GENs/BIOS vendors where the issue was reported. Later there we had reports of the same failure on platforms not on this list. To my best knowledge the correct thing to do is still to put the device to PCI D3 state during hibernation, see [1] and [2] for the reasons. This also aligns with our future plans to unify more the runtime and system suspend/resume paths. Since an exact blacklist seems to be impractical (multiple GENs and BIOS vendors are affected) apply the workaround on everything pre GEN6. [1] http://lists.freedesktop.org/archives/intel-gfx/2015-February/060710.html [2] https://lkml.org/lkml/2015/6/22/274 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=95061 Reported-by: Ilya Tumaykin Reported-by: Dirk Griesbach Reported-by: Pavel Machek Reported-by: Mikko Rapeli Tested-by: Mikko Rapeli Reported-by: Paul Bolle CC: stable@vger.kernel.org Signed-off-by: Imre Deak Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 1d88745..8edcec8 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -662,15 +662,18 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation) pci_disable_device(drm_dev->pdev); /* - * During hibernation on some GEN4 platforms the BIOS may try to access + * During hibernation on some platforms the BIOS may try to access * the device even though it's already in D3 and hang the machine. So * leave the device in D0 on those platforms and hope the BIOS will - * power down the device properly. Platforms where this was seen: - * Lenovo Thinkpad X301, X61s + * power down the device properly. The issue was seen on multiple old + * GENs with different BIOS vendors, so having an explicit blacklist + * is inpractical; apply the workaround on everything pre GEN6. The + * platforms where the issue was seen: + * Lenovo Thinkpad X301, X61s, X60, T60, X41 + * Fujitsu FSC S7110 + * Acer Aspire 1830T */ - if (!(hibernation && - drm_dev->pdev->subsystem_vendor == PCI_VENDOR_ID_LENOVO && - INTEL_INFO(dev_priv)->gen == 4)) + if (!(hibernation && INTEL_INFO(dev_priv)->gen < 6)) pci_set_power_state(drm_dev->pdev, PCI_D3hot); return 0; -- cgit v0.10.2 From 11c1b657c42f65c43f866b611956ef0a10bedafc Mon Sep 17 00:00:00 2001 From: Xiong Zhang Date: Mon, 17 Aug 2015 16:04:04 +0800 Subject: drm/i915: Enable HDMI on DDI-E DDI-E doesn't have the correspondent GMBUS pin. We rely on VBT to tell us which one it being used instead. The DVI/HDMI on shared port couldn't exist. This patch isn't tested without hardware wchich has HDMI on DDI-E. v2: fix trailing whitespace v3: MISSING_CASE take place of BUG() Signed-off-by: Xiong Zhang Reviewed-by: Rodrigo Vivi Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 089459b..9b9bd2e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1416,6 +1416,10 @@ enum modeset_restore { #define DP_AUX_C 0x20 #define DP_AUX_D 0x30 +#define DDC_PIN_B 0x05 +#define DDC_PIN_C 0x04 +#define DDC_PIN_D 0x06 + struct ddi_vbt_port_info { /* * This is an index in the HDMI/DVI DDI buffer translation table. @@ -1430,6 +1434,7 @@ struct ddi_vbt_port_info { uint8_t supports_dp:1; uint8_t alternate_aux_channel; + uint8_t alternate_ddc_pin; uint8_t dp_boost_level; uint8_t hdmi_boost_level; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index be83b77..313b5a7 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -905,7 +905,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, uint8_t hdmi_level_shift; int i, j; bool is_dvi, is_hdmi, is_dp, is_edp, is_crt; - uint8_t aux_channel; + uint8_t aux_channel, ddc_pin; /* Each DDI port can have more than one value on the "DVO Port" field, * so look for all the possible values for each port and abort if more * than one is found. */ @@ -939,6 +939,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, return; aux_channel = child->raw[25]; + ddc_pin = child->common.ddc_pin; is_dvi = child->common.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING; is_dp = child->common.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT; @@ -970,11 +971,27 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, DRM_DEBUG_KMS("Port %c is internal DP\n", port_name(port)); if (is_dvi) { - if (child->common.ddc_pin == 0x05 && port != PORT_B) + if (port == PORT_E) { + info->alternate_ddc_pin = ddc_pin; + /* if DDIE share ddc pin with other port, then + * dvi/hdmi couldn't exist on the shared port. + * Otherwise they share the same ddc bin and system + * couldn't communicate with them seperately. */ + if (ddc_pin == DDC_PIN_B) { + dev_priv->vbt.ddi_port_info[PORT_B].supports_dvi = 0; + dev_priv->vbt.ddi_port_info[PORT_B].supports_hdmi = 0; + } else if (ddc_pin == DDC_PIN_C) { + dev_priv->vbt.ddi_port_info[PORT_C].supports_dvi = 0; + dev_priv->vbt.ddi_port_info[PORT_C].supports_hdmi = 0; + } else if (ddc_pin == DDC_PIN_D) { + dev_priv->vbt.ddi_port_info[PORT_D].supports_dvi = 0; + dev_priv->vbt.ddi_port_info[PORT_D].supports_hdmi = 0; + } + } else if (ddc_pin == DDC_PIN_B && port != PORT_B) DRM_DEBUG_KMS("Unexpected DDC pin for port B\n"); - if (child->common.ddc_pin == 0x04 && port != PORT_C) + else if (ddc_pin == DDC_PIN_C && port != PORT_C) DRM_DEBUG_KMS("Unexpected DDC pin for port C\n"); - if (child->common.ddc_pin == 0x06 && port != PORT_D) + else if (ddc_pin == DDC_PIN_D && port != PORT_D) DRM_DEBUG_KMS("Unexpected DDC pin for port D\n"); } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 51cbea8..dcd336b 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1958,6 +1958,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_dig_port->port; + uint8_t alternate_ddc_pin; drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); @@ -1991,6 +1992,26 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, intel_hdmi->ddc_bus = GMBUS_PIN_DPD; intel_encoder->hpd_pin = HPD_PORT_D; break; + case PORT_E: + /* On SKL PORT E doesn't have seperate GMBUS pin + * We rely on VBT to set a proper alternate GMBUS pin. */ + alternate_ddc_pin = + dev_priv->vbt.ddi_port_info[PORT_E].alternate_ddc_pin; + switch (alternate_ddc_pin) { + case DDC_PIN_B: + intel_hdmi->ddc_bus = GMBUS_PIN_DPB; + break; + case DDC_PIN_C: + intel_hdmi->ddc_bus = GMBUS_PIN_DPC; + break; + case DDC_PIN_D: + intel_hdmi->ddc_bus = GMBUS_PIN_DPD; + break; + default: + MISSING_CASE(alternate_ddc_pin); + } + intel_encoder->hpd_pin = HPD_PORT_E; + break; case PORT_A: intel_encoder->hpd_pin = HPD_PORT_A; /* Internal port only for eDP. */ -- cgit v0.10.2 From 2800e4c228b8961c4da1a4925cc20c16e623851b Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 7 Aug 2015 17:35:21 -0700 Subject: drm/i915/skl: Enable DDI-E There are OEMs using DDI-E out there, so let's enable it. Unfortunately there is no detection bit for DDI-E So we need to rely on VBT for that. I also need to give credits to Xiong since before seing his approach to check info->support_* I was creating an ugly vbt->ddie_sfuse_strap in order to propagate the ddi presence info v2: Rebased as last patch in the series. since all other patches in this series are needed for anything working propperly on DDI-E. Credits-to: "Zhang, Xiong Y" Cc: "Zhang, Xiong Y" Reviewed-by: Xiong Zhang Signed-off-by: Rodrigo Vivi Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 313b5a7..b3e437b 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -909,19 +909,19 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, /* Each DDI port can have more than one value on the "DVO Port" field, * so look for all the possible values for each port and abort if more * than one is found. */ - int dvo_ports[][2] = { - {DVO_PORT_HDMIA, DVO_PORT_DPA}, - {DVO_PORT_HDMIB, DVO_PORT_DPB}, - {DVO_PORT_HDMIC, DVO_PORT_DPC}, - {DVO_PORT_HDMID, DVO_PORT_DPD}, - {DVO_PORT_CRT, -1 /* Port E can only be DVO_PORT_CRT */ }, + int dvo_ports[][3] = { + {DVO_PORT_HDMIA, DVO_PORT_DPA, -1}, + {DVO_PORT_HDMIB, DVO_PORT_DPB, -1}, + {DVO_PORT_HDMIC, DVO_PORT_DPC, -1}, + {DVO_PORT_HDMID, DVO_PORT_DPD, -1}, + {DVO_PORT_CRT, DVO_PORT_HDMIE, DVO_PORT_DPE}, }; /* Find the child device to use, abort if more than one found. */ for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { it = dev_priv->vbt.child_dev + i; - for (j = 0; j < 2; j++) { + for (j = 0; j < 3; j++) { if (dvo_ports[port][j] == -1) break; diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 06d0dbd..a591227 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -775,6 +775,8 @@ int intel_parse_bios(struct drm_device *dev); #define DVO_PORT_DPC 8 #define DVO_PORT_DPD 9 #define DVO_PORT_DPA 10 +#define DVO_PORT_DPE 11 +#define DVO_PORT_HDMIE 12 #define DVO_PORT_MIPIA 21 #define DVO_PORT_MIPIB 22 #define DVO_PORT_MIPIC 23 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8ea9821..9bae133 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13960,6 +13960,15 @@ static void intel_setup_outputs(struct drm_device *dev) intel_ddi_init(dev, PORT_C); if (found & SFUSE_STRAP_DDID_DETECTED) intel_ddi_init(dev, PORT_D); + /* + * On SKL we don't have a way to detect DDI-E so we rely on VBT. + */ + if (IS_SKYLAKE(dev) && + (dev_priv->vbt.ddi_port_info[PORT_E].supports_dp || + dev_priv->vbt.ddi_port_info[PORT_E].supports_dvi || + dev_priv->vbt.ddi_port_info[PORT_E].supports_hdmi)) + intel_ddi_init(dev, PORT_E); + } else if (HAS_PCH_SPLIT(dev)) { int found; dpd_is_edp = intel_dp_is_edp(dev, PORT_D); -- cgit v0.10.2 From 477ec3283c324d16e8da07a8d8a4a367e31b6eab Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 6 Aug 2015 15:51:39 +0800 Subject: drm/i915: eDP can be present on DDI-E Enable eDP on DDI-E. Also let's remove duplicated definitions to avoid later confusion. Signed-off-by: Rodrigo Vivi Reviewed-by: Xiong Zhang Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index a591227..46cd5c7 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -758,11 +758,6 @@ int intel_parse_bios(struct drm_device *dev); #define DVO_C 2 #define DVO_D 3 -/* define the PORT for DP output type */ -#define PORT_IDPB 7 -#define PORT_IDPC 8 -#define PORT_IDPD 9 - /* Possible values for the "DVO Port" field for versions >= 155: */ #define DVO_PORT_HDMIA 0 #define DVO_PORT_HDMIB 1 diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 94686cb..32663b19 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5015,16 +5015,17 @@ intel_trans_dp_port_sel(struct drm_crtc *crtc) return -1; } -/* check the VBT to see whether the eDP is on DP-D port */ +/* check the VBT to see whether the eDP is on another port */ bool intel_dp_is_edp(struct drm_device *dev, enum port port) { struct drm_i915_private *dev_priv = dev->dev_private; union child_device_config *p_child; int i; static const short port_mapping[] = { - [PORT_B] = PORT_IDPB, - [PORT_C] = PORT_IDPC, - [PORT_D] = PORT_IDPD, + [PORT_B] = DVO_PORT_DPB, + [PORT_C] = DVO_PORT_DPC, + [PORT_D] = DVO_PORT_DPD, + [PORT_E] = DVO_PORT_DPE, }; if (port == PORT_A) -- cgit v0.10.2 From d8e19f99d3483adb01c6269dd5775ba8ecf1870a Mon Sep 17 00:00:00 2001 From: Xiong Zhang Date: Thu, 13 Aug 2015 18:00:12 +0800 Subject: drm/i915/skl: Adding DDI_E power well domain From B spec, DDI_E port belong to PowerWell 2, but DDI_E share the powerwell_req/staus register bit with DDI_A which belong to DDI_A_E_POWER_WELL. In order to communicate with the connector on DDI-E, both DDI_A_E_POWER_WELL and POWER_WELL_2 must be enabled. Currently intel_dp_power_get(DDI_E) only enable DDI_A_E_POWER_WELL, this patch will not only enable DDI_a_E_POWER_WELL but also enable POWER_WELL_2. This patch also fix the DDI-E hotplug function. Signed-off-by: Xiong Zhang Reviewed-by: Rodrigo Vivi Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 33aabc7..e3ec904 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2562,6 +2562,8 @@ static const char *power_domain_str(enum intel_display_power_domain domain) return "PORT_DDI_D_2_LANES"; case POWER_DOMAIN_PORT_DDI_D_4_LANES: return "PORT_DDI_D_4_LANES"; + case POWER_DOMAIN_PORT_DDI_E_2_LANES: + return "PORT_DDI_E_2_LANES"; case POWER_DOMAIN_PORT_DSI: return "PORT_DSI"; case POWER_DOMAIN_PORT_CRT: diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9b9bd2e..e304d4e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -182,6 +182,7 @@ enum intel_display_power_domain { POWER_DOMAIN_PORT_DDI_C_4_LANES, POWER_DOMAIN_PORT_DDI_D_2_LANES, POWER_DOMAIN_PORT_DDI_D_4_LANES, + POWER_DOMAIN_PORT_DDI_E_2_LANES, POWER_DOMAIN_PORT_DSI, POWER_DOMAIN_PORT_CRT, POWER_DOMAIN_PORT_OTHER, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9bae133..a5cddcd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5150,7 +5150,6 @@ static enum intel_display_power_domain port_to_power_domain(enum port port) { switch (port) { case PORT_A: - case PORT_E: return POWER_DOMAIN_PORT_DDI_A_4_LANES; case PORT_B: return POWER_DOMAIN_PORT_DDI_B_4_LANES; @@ -5158,6 +5157,8 @@ static enum intel_display_power_domain port_to_power_domain(enum port port) return POWER_DOMAIN_PORT_DDI_C_4_LANES; case PORT_D: return POWER_DOMAIN_PORT_DDI_D_4_LANES; + case PORT_E: + return POWER_DOMAIN_PORT_DDI_E_2_LANES; default: WARN_ON_ONCE(1); return POWER_DOMAIN_PORT_OTHER; diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 821644d..af7fdb3 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -297,6 +297,7 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \ BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) | \ BIT(POWER_DOMAIN_AUX_B) | \ BIT(POWER_DOMAIN_AUX_C) | \ BIT(POWER_DOMAIN_AUX_D) | \ @@ -316,6 +317,7 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, #define SKL_DISPLAY_DDI_A_E_POWER_DOMAINS ( \ BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \ BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) | \ BIT(POWER_DOMAIN_INIT)) #define SKL_DISPLAY_DDI_B_POWER_DOMAINS ( \ BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ -- cgit v0.10.2 From 69f92f67b68ab7028ffe15f0eea76b59f8859383 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 15 Jul 2015 13:57:35 +0200 Subject: drm/i915: Preserve SSC earlier Commit 92122789b2d6 ("drm/i915: preserve SSC if previously set v3") added code to intel_modeset_gem_init to override the SSC status read from VBT with the SSC status set by BIOS. However, intel_modeset_gem_init is invoked *after* intel_modeset_init, which calls intel_setup_outputs, which *modifies* SSC status by way of intel_init_pch_refclk. So unlike advertised, intel_modeset_gem_init doesn't preserve the SSC status set by BIOS but whatever intel_init_pch_refclk decided on. This is a problem on dual gpu laptops such as the MacBook Pro which require either a handler to switch DDC lines, or the discrete gpu to proxy DDC/AUX communication: Both the handler and the discrete gpu may initialize after the i915 driver, and consequently, an LVDS connector may initially seem disconnected and the SSC therefore is disabled by intel_init_pch_refclk, but on reprobe the connector may turn out to be connected and the SSC must then be enabled. Due to 92122789b2d6 however, the SSC is not enabled on reprobe since it is assumed BIOS disabled it while in fact it was disabled by intel_init_pch_refclk. Also, because the SSC status is preserved so late, the preserved value only ever gets used on resume but not on panel initialization: intel_modeset_init calls intel_init_display which indirectly calls intel_panel_use_ssc via multiple subroutines, *before* the BIOS value overrides the VBT value in intel_modeset_gem_init (intel_panel_use_ssc is the sole user of dev_priv->vbt.lvds_use_ssc). Fix this by moving the code introduced by 92122789b2d6 from intel_modeset_gem_init to intel_modeset_init before the invocation of intel_setup_outputs and intel_init_display. Add a DRM_DEBUG_KMS as suggested way back by Jani: http://lists.freedesktop.org/archives/intel-gfx/2014-June/046666.html Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115 Tested-by: Paul Hordiienko [MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina] Tested-by: William Brown [MBP 8,2 2011 intel SNB + amd turks pre-retina] Tested-by: Lukas Wunner [MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina] Tested-by: Bruno Bierbaumer [MBP 11,3 2013 intel HSW + nvidia GK107 retina -- work in progress] Fixes: 92122789b2d6 ("drm/i915: preserve SSC if previously set v3") Signed-off-by: Lukas Wunner Reviewed-by: Jesse Barnes Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a5cddcd..ca9278b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14740,6 +14740,24 @@ void intel_modeset_init(struct drm_device *dev) if (INTEL_INFO(dev)->num_pipes == 0) return; + /* + * There may be no VBT; and if the BIOS enabled SSC we can + * just keep using it to avoid unnecessary flicker. Whereas if the + * BIOS isn't using it, don't assume it will work even if the VBT + * indicates as much. + */ + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { + bool bios_lvds_use_ssc = !!(I915_READ(PCH_DREF_CONTROL) & + DREF_SSC1_ENABLE); + + if (dev_priv->vbt.lvds_use_ssc != bios_lvds_use_ssc) { + DRM_DEBUG_KMS("SSC %sabled by BIOS, overriding VBT which says %sabled\n", + bios_lvds_use_ssc ? "en" : "dis", + dev_priv->vbt.lvds_use_ssc ? "en" : "dis"); + dev_priv->vbt.lvds_use_ssc = bios_lvds_use_ssc; + } + } + intel_init_display(dev); intel_init_audio(dev); @@ -15299,7 +15317,6 @@ err: void intel_modeset_gem_init(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *c; struct drm_i915_gem_object *obj; int ret; @@ -15308,16 +15325,6 @@ void intel_modeset_gem_init(struct drm_device *dev) intel_init_gt_powersave(dev); mutex_unlock(&dev->struct_mutex); - /* - * There may be no VBT; and if the BIOS enabled SSC we can - * just keep using it to avoid unnecessary flicker. Whereas if the - * BIOS isn't using it, don't assume it will work even if the VBT - * indicates as much. - */ - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) - dev_priv->vbt.lvds_use_ssc = !!(I915_READ(PCH_DREF_CONTROL) & - DREF_SSC1_ENABLE); - intel_modeset_init_hw(dev); intel_setup_overlay(dev); -- cgit v0.10.2 From 7e6313a2516dbcd168f4ae36f0abe1a9227106b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 11 Aug 2015 20:21:46 +0300 Subject: drm/i915: Don't use link_bw for PLL setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use port_clock instead of link_bw when picking the PLL parameters for DP. link_bw may be zero with an eDP 1.4 sink that supports DP_LINK_RATE_SET so we shouldn't use it for anything other than feed it to the sink appropriately. v2: Fix typo in commit message (Sivakumar) Reviewed-by: Sivakumar Thulasimani Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter [Jani: cherry-picked from future.] Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 1900455..61575f6 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1554,17 +1554,14 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, DPLL_CFGCR2_PDIV(wrpll_params.pdiv) | wrpll_params.central_freq; } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { - struct drm_encoder *encoder = &intel_encoder->base; - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - - switch (intel_dp->link_bw) { - case DP_LINK_BW_1_62: + switch (crtc_state->port_clock / 2) { + case 81000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0); break; - case DP_LINK_BW_2_7: + case 135000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0); break; - case DP_LINK_BW_5_4: + case 270000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0); break; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 32663b19..ef345d5 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -48,28 +48,28 @@ #define INTEL_DP_RESOLUTION_FAILSAFE (3 << INTEL_DP_RESOLUTION_SHIFT_MASK) struct dp_link_dpll { - int link_bw; + int clock; struct dpll dpll; }; static const struct dp_link_dpll gen4_dpll[] = { - { DP_LINK_BW_1_62, + { 162000, { .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8 } }, - { DP_LINK_BW_2_7, + { 270000, { .p1 = 1, .p2 = 10, .n = 1, .m1 = 14, .m2 = 2 } } }; static const struct dp_link_dpll pch_dpll[] = { - { DP_LINK_BW_1_62, + { 162000, { .p1 = 2, .p2 = 10, .n = 1, .m1 = 12, .m2 = 9 } }, - { DP_LINK_BW_2_7, + { 270000, { .p1 = 1, .p2 = 10, .n = 2, .m1 = 14, .m2 = 8 } } }; static const struct dp_link_dpll vlv_dpll[] = { - { DP_LINK_BW_1_62, + { 162000, { .p1 = 3, .p2 = 2, .n = 5, .m1 = 3, .m2 = 81 } }, - { DP_LINK_BW_2_7, + { 270000, { .p1 = 2, .p2 = 2, .n = 1, .m1 = 2, .m2 = 27 } } }; @@ -83,11 +83,11 @@ static const struct dp_link_dpll chv_dpll[] = { * m2 is stored in fixed point format using formula below * (m2_int << 22) | m2_fraction */ - { DP_LINK_BW_1_62, /* m2_int = 32, m2_fraction = 1677722 */ + { 162000, /* m2_int = 32, m2_fraction = 1677722 */ { .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a } }, - { DP_LINK_BW_2_7, /* m2_int = 27, m2_fraction = 0 */ + { 270000, /* m2_int = 27, m2_fraction = 0 */ { .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } }, - { DP_LINK_BW_5_4, /* m2_int = 27, m2_fraction = 0 */ + { 540000, /* m2_int = 27, m2_fraction = 0 */ { .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } } }; @@ -1130,7 +1130,7 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector) } static void -skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock) +skl_edp_set_pll_config(struct intel_crtc_state *pipe_config) { u32 ctrl1; @@ -1142,7 +1142,7 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock) pipe_config->dpll_hw_state.cfgcr2 = 0; ctrl1 = DPLL_CTRL1_OVERRIDE(SKL_DPLL0); - switch (link_clock / 2) { + switch (pipe_config->port_clock / 2) { case 81000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, SKL_DPLL0); @@ -1176,19 +1176,19 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock) } static void -hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config, int link_bw) +hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config) { memset(&pipe_config->dpll_hw_state, 0, sizeof(pipe_config->dpll_hw_state)); - switch (link_bw) { - case DP_LINK_BW_1_62: + switch (pipe_config->port_clock / 2) { + case 81000: pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_810; break; - case DP_LINK_BW_2_7: + case 135000: pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_1350; break; - case DP_LINK_BW_5_4: + case 270000: pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_2700; break; } @@ -1245,7 +1245,7 @@ intel_dp_source_rates(struct drm_device *dev, const int **source_rates) static void intel_dp_set_clock(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, int link_bw) + struct intel_crtc_state *pipe_config) { struct drm_device *dev = encoder->base.dev; const struct dp_link_dpll *divisor = NULL; @@ -1267,7 +1267,7 @@ intel_dp_set_clock(struct intel_encoder *encoder, if (divisor && count) { for (i = 0; i < count; i++) { - if (link_bw == divisor[i].link_bw) { + if (pipe_config->port_clock == divisor[i].clock) { pipe_config->dpll = divisor[i].dpll; pipe_config->clock_set = true; break; @@ -1544,13 +1544,13 @@ found: } if (IS_SKYLAKE(dev) && is_edp(intel_dp)) - skl_edp_set_pll_config(pipe_config, common_rates[clock]); + skl_edp_set_pll_config(pipe_config); else if (IS_BROXTON(dev)) /* handled in ddi */; else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) - hsw_dp_set_ddi_pll_sel(pipe_config, intel_dp->link_bw); + hsw_dp_set_ddi_pll_sel(pipe_config); else - intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw); + intel_dp_set_clock(encoder, pipe_config); return true; } -- cgit v0.10.2 From 6fa2d197936ba0b8936e813d0adecefac160062b Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 31 Aug 2015 11:23:28 +0300 Subject: i915: Set ddi_pll_sel in DP MST path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DP MST encoder config function never sets ddi_pll_sel, even though its value is programmed in its ->pre_enable() hook. That used to work because a new pipe_config was kzalloc'ed at every modeset, and the value of zero selects the highest clock for the PLL. Starting with the commit below, the value of ddi_pll_sel is preserved through modesets, and since the correct value wasn't properly setup by the MST code, it could lead to warnings and blank screens. commit 8504c74c7ae48b4b8ed1f1c0acf67482a7f45c93 Author: Ander Conselvan de Oliveira Date: Fri May 15 11:51:50 2015 +0300 drm/i915: Preserve ddi_pll_sel when allocating new pipe_config Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91628 Cc: stable@vger.kernel.org # 7e6313a2516d drm/i915: Don't use link_bw for PLL setup Cc: stable@vger.kernel.org Cc: Timo Aaltonen Cc: Luciano Coelho Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ef345d5..0a2e33f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1175,7 +1175,7 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config) pipe_config->dpll_hw_state.ctrl1 = ctrl1; } -static void +void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config) { memset(&pipe_config->dpll_hw_state, 0, diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 369f8b6..983553c 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -33,6 +33,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { + struct drm_device *dev = encoder->base.dev; struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); struct intel_digital_port *intel_dig_port = intel_mst->primary; struct intel_dp *intel_dp = &intel_dig_port->dp; @@ -97,6 +98,10 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, &pipe_config->dp_m_n); pipe_config->dp_m_n.tu = slots; + + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + hsw_dp_set_ddi_pll_sel(pipe_config); + return true; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 93008fb..2b9e6f9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1185,6 +1185,7 @@ void intel_edp_drrs_disable(struct intel_dp *intel_dp); void intel_edp_drrs_invalidate(struct drm_device *dev, unsigned frontbuffer_bits); void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits); +void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config); /* intel_dp_mst.c */ int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); -- cgit v0.10.2