From patchwork Fri Jul 10 11:57:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Matthew Auld X-Patchwork-Id: 11656355 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 97A286C1 for ; Fri, 10 Jul 2020 12:00:08 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7E69D2078D for ; Fri, 10 Jul 2020 12:00:08 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7E69D2078D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C3BC66EBFA; Fri, 10 Jul 2020 12:00:02 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by gabe.freedesktop.org (Postfix) with ESMTPS id 28A586EBF7 for ; Fri, 10 Jul 2020 12:00:01 +0000 (UTC) IronPort-SDR: QwYvcum4UQxeYAd2Y54xLinNYi5vnQ2etDifvod/N8PrWhm5PhisXYo96Tk2T6u9u8AJc0HgTz BeE7bdW7MQZw== X-IronPort-AV: E=McAfee;i="6000,8403,9677"; a="149653714" X-IronPort-AV: E=Sophos;i="5.75,335,1589266800"; d="scan'208";a="149653714" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2020 05:00:01 -0700 IronPort-SDR: oceVYPKYfG0igJAgEeMrLM4KaMSjNaKi5XvjD/i2fbTyxXF2pOfxCDVfqi93vOZPsZa2I+bURV QTqpErO7ignw== X-IronPort-AV: E=Sophos;i="5.75,335,1589266800"; d="scan'208";a="458257524" Received: from nmartino-mobl1.ger.corp.intel.com (HELO mwahaha-bdw.ger.corp.intel.com) ([10.255.207.224]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2020 04:59:58 -0700 From: Matthew Auld To: intel-gfx@lists.freedesktop.org Date: Fri, 10 Jul 2020 12:57:20 +0100 Message-Id: <20200710115757.290984-24-matthew.auld@intel.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200710115757.290984-1-matthew.auld@intel.com> References: <20200710115757.290984-1-matthew.auld@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [RFC 23/60] drm/i915/dg1: map/unmap pll clocks X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Lucas De Marchi Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Lucas De Marchi DG1 uses 2 registers for the ddi clock mapping, with PHY A and B using DPCLKA_CFGCR0 and PHY C and D using DPCLKA1_CFGCR0. Hide this behind a single macro that chooses the correct register according to the phy being accessed, use the correct bitfields for each pll/phy and implement separate functions for DG1 since it doesn't share much with ICL/TGL anymore. The previous values were correct for PHY A and B since they were using the same register as before and the bitfields were matching. Cc: José Roberto de Souza Cc: Clinton Taylor Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/i915/display/intel_ddi.c | 92 +++++++++++++++++++- drivers/gpu/drm/i915/display/intel_display.c | 25 +++++- drivers/gpu/drm/i915/i915_reg.h | 15 ++++ 3 files changed, 128 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 4a1a896098f9..b5ba02deb24b 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2848,6 +2848,38 @@ static u32 icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv, return 0; } +static void dg1_map_plls_to_ports(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_shared_dpll *pll = crtc_state->shared_dpll; + enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + u32 val; + + /* + * If we fail this, something went very wrong: first 2 PLLs should be + * used by first 2 phys and last 2 PLLs by last phys + */ + if (WARN_ON((pll->info->id < DPLL_ID_DG1_DPLL2 && phy >= PHY_C) || + (pll->info->id >= DPLL_ID_DG1_DPLL2 && phy < PHY_C))) + return; + + mutex_lock(&dev_priv->dpll.lock); + + val = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy)); + WARN_ON((val & DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)) == 0); + + val &= ~DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); + val |= DG1_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy); + intel_de_write(dev_priv, DG1_DPCLKA_CFGCR0(phy), val); + intel_de_posting_read(dev_priv, DG1_DPCLKA_CFGCR0(phy)); + + val &= ~DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy); + intel_de_write(dev_priv, DG1_DPCLKA_CFGCR0(phy), val); + + mutex_unlock(&dev_priv->dpll.lock); +} + static void icl_map_plls_to_ports(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -2885,6 +2917,19 @@ static void icl_map_plls_to_ports(struct intel_encoder *encoder, mutex_unlock(&dev_priv->dpll.lock); } +static void dg1_unmap_plls_to_ports(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + + mutex_lock(&dev_priv->dpll.lock); + + intel_de_rmw(dev_priv, DG1_DPCLKA_CFGCR0(phy), 0, + DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); + + mutex_unlock(&dev_priv->dpll.lock); +} + static void icl_unmap_plls_to_ports(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -2900,6 +2945,40 @@ static void icl_unmap_plls_to_ports(struct intel_encoder *encoder) mutex_unlock(&dev_priv->dpll.lock); } +static void dg1_sanitize_port_clk_off(struct drm_i915_private *dev_priv, + u32 port_mask, bool ddi_clk_needed) +{ + enum port port; + u32 val; + + for_each_port_masked(port, port_mask) { + enum phy phy = intel_port_to_phy(dev_priv, port); + bool ddi_clk_off; + + val = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy)); + ddi_clk_off = val & DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy); + + if (ddi_clk_needed == !ddi_clk_off) + continue; + + /* + * Punt on the case now where clock is gated, but it would + * be needed by the port. Something else is really broken then. + */ + if (ddi_clk_needed) { + WARN(1, "ddi_clk_needed=%u ddi_clk_off=%u phy=%u\n", + ddi_clk_needed, ddi_clk_off, phy); + continue; + } + + DRM_NOTE("PHY %c is disabled/in DSI mode with an ungated DDI clock, gate it\n", + phy_name(phy)); + + val |= DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy); + intel_de_write(dev_priv, DG1_DPCLKA_CFGCR0(phy), val); + } +} + static void icl_sanitize_port_clk_off(struct drm_i915_private *dev_priv, u32 port_mask, bool ddi_clk_needed) { @@ -2982,7 +3061,10 @@ void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) ddi_clk_needed = false; } - icl_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed); + if (IS_DG1(dev_priv)) + dg1_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed); + else + icl_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed); } static void intel_ddi_clk_select(struct intel_encoder *encoder, @@ -3507,7 +3589,9 @@ static void intel_ddi_pre_enable(struct intel_atomic_state *state, drm_WARN_ON(&dev_priv->drm, crtc_state->has_pch_encoder); - if (INTEL_GEN(dev_priv) >= 11) + if (IS_DG1(dev_priv)) + dg1_map_plls_to_ports(encoder, crtc_state); + else if (INTEL_GEN(dev_priv) >= 11) icl_map_plls_to_ports(encoder, crtc_state); intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); @@ -3693,7 +3777,9 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state, intel_ddi_post_disable_dp(state, encoder, old_crtc_state, old_conn_state); - if (INTEL_GEN(dev_priv) >= 11) + if (IS_DG1(dev_priv)) + dg1_unmap_plls_to_ports(encoder); + else if (INTEL_GEN(dev_priv) >= 11) icl_unmap_plls_to_ports(encoder); if (intel_crtc_has_dp_encoder(old_crtc_state) || is_tc_port) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 8b30daf7e304..8dc83b480466 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -10781,6 +10781,27 @@ static int hsw_crtc_compute_clock(struct intel_crtc *crtc, return 0; } +static void dg1_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, + struct intel_crtc_state *pipe_config) +{ + enum icl_port_dpll_id port_dpll_id = ICL_PORT_DPLL_DEFAULT; + enum phy phy = intel_port_to_phy(dev_priv, port); + enum intel_dpll_id id; + u32 val; + + val = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy)) + & DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); + id = DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_VAL_TO_ID(val, phy); + + if (WARN_ON(id > DPLL_ID_DG1_DPLL3)) + return; + + pipe_config->icl_port_dplls[port_dpll_id].pll = + intel_get_shared_dpll_by_id(dev_priv, id); + + icl_set_active_port_dpll(pipe_config, port_dpll_id); +} + static void cnl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, struct intel_crtc_state *pipe_config) { @@ -11080,7 +11101,9 @@ static void hsw_get_ddi_port_state(struct intel_crtc *crtc, port = TRANS_DDI_FUNC_CTL_VAL_TO_PORT(tmp); } - if (INTEL_GEN(dev_priv) >= 11) + if (IS_DG1(dev_priv)) + dg1_get_ddi_pll(dev_priv, port, pipe_config); + else if (INTEL_GEN(dev_priv) >= 11) icl_get_ddi_pll(dev_priv, port, pipe_config); else if (IS_CANNONLAKE(dev_priv)) cnl_get_ddi_pll(dev_priv, port, pipe_config); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1ae8d8542b66..7b963f362190 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -230,12 +230,14 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define _TRANS(tran, a, b) _PICK_EVEN(tran, a, b) #define _PORT(port, a, b) _PICK_EVEN(port, a, b) #define _PLL(pll, a, b) _PICK_EVEN(pll, a, b) +#define _PHY(phy, a, b) _PICK_EVEN(phy, a, b) #define _MMIO_PIPE(pipe, a, b) _MMIO(_PIPE(pipe, a, b)) #define _MMIO_PLANE(plane, a, b) _MMIO(_PLANE(plane, a, b)) #define _MMIO_TRANS(tran, a, b) _MMIO(_TRANS(tran, a, b)) #define _MMIO_PORT(port, a, b) _MMIO(_PORT(port, a, b)) #define _MMIO_PLL(pll, a, b) _MMIO(_PLL(pll, a, b)) +#define _MMIO_PHY(phy, a, b) _MMIO(_PHY(phy, a, b)) #define _PHY3(phy, ...) _PICK(phy, __VA_ARGS__) @@ -10291,6 +10293,7 @@ enum skl_power_gate { #define DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port) (3 << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port)) #define DPCLKA_CFGCR0_DDI_CLK_SEL(pll, port) ((pll) << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port)) +/* ICL Clocks */ #define ICL_DPCLKA_CFGCR0 _MMIO(0x164280) #define ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) (1 << _PICK(phy, 10, 11, 24)) #define ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port) (1 << ((tc_port) < PORT_TC4 ? \ @@ -10300,6 +10303,18 @@ enum skl_power_gate { #define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) (3 << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) #define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) ((pll) << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) +/* DG1 Clocks */ +#define _DG1_DPCLKA_CFGCR0 0x164280 +#define _DG1_DPCLKA1_CFGCR0 0x16C280 +#define DG1_DPCLKA_CFGCR0(phy) _MMIO_PHY((phy) / 2, \ + _DG1_DPCLKA_CFGCR0, \ + _DG1_DPCLKA1_CFGCR0) +#define DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) (1 << (10 + ((phy) % 2))) +#define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) (0x3 << (((phy) % 2) * 2)) +#define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) (((pll) % 2) << (((phy) % 2)) * 2) +#define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_VAL_TO_ID(val, phy) \ + ((((val) & DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy)) >> ((phy % 2) * 2)) + (2 * (phy / 2))) + /* CNL PLL */ #define DPLL0_ENABLE 0x46010 #define DPLL1_ENABLE 0x46014