From patchwork Thu Jan 5 12:54:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089810 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 2C5F1C53210 for ; Thu, 5 Jan 2023 12:59:39 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 9C53A10E713; Thu, 5 Jan 2023 12:59:38 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 8E85710E712 for ; Thu, 5 Jan 2023 12:59:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923576; x=1704459576; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Sbtpivke+ElPIZBfkt9BpZ26tZI7oAEmb3Jnrdms8ZY=; b=ggtFsTm1VhYi7Rv/EbAPD70tHYFoc6n5HraBPuGHQ1ttKj54pEkprxky dWJEEQWxlvzCWJ0AMpxnwN9xsCR29oSZ8j20sPr1fCH6Jz/FLYA22mdvp urUVwrCLc21D9SCPc6MCwByGWptEoez+FKWoSxy2zJa3I2BNUAwsZRVIc 05MMqWU8eELUlbbjQObyqEgmXRbcja2hq426t97FsR/N8oCKslAjSPPSi Kv27Rji8AQfFedcAn98BuqiQYh7Vw8DuHm42JazMFYTccLgeHdousrmli UZSsOkBBt3BEA6asUUXZ9+jfolcfbcoBWFIoPHQW+PZ6rdtmc0UhR+eKv Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697709" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697709" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 04:59:36 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829540937" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829540937" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 04:59:34 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:26 +0200 Message-Id: <20230105125446.960504-2-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 01/21] drm/i915/mtl: Initial DDI port setup 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Clint Taylor Initialize c10 combo phy ports. TODO Type-C ports. Cc: Radhakrishna Sripada Signed-off-by: Clint Taylor Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-2-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index e75b9b2a0e01..b5618de88f03 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -7874,7 +7874,11 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) if (!HAS_DISPLAY(dev_priv)) return; - if (IS_DG2(dev_priv)) { + if (IS_METEORLAKE(dev_priv)) { + /* TODO: initialize TC ports as well */ + intel_ddi_init(dev_priv, PORT_A); + intel_ddi_init(dev_priv, PORT_B); + } else if (IS_DG2(dev_priv)) { intel_ddi_init(dev_priv, PORT_A); intel_ddi_init(dev_priv, PORT_B); intel_ddi_init(dev_priv, PORT_C); From patchwork Thu Jan 5 12:54:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089811 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 0E583C3DA7A for ; Thu, 5 Jan 2023 12:59:42 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 63EA310E712; Thu, 5 Jan 2023 12:59:41 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 8DE0410E712 for ; Thu, 5 Jan 2023 12:59:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923578; x=1704459578; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=X8VYICdqmlEpof74dUk1UUS2QNwZGu1NwZ77/ICLeMc=; b=VxF+7MiwD0lfEP2Izz3NUfYubt7uM8UYtzEhtL/m5sDO1ZtpwblTLmax 55TULPwxUg5pPS4dnCM5IP6D7ha6Qwaw7MPXTwX8nNpwmg3lqfS1//Ssd 2ecgU+Ai4vEPUh573FUFQyi+8zxcIHZdcR2PaPDDLyfGuN5rl9o3IDv0M 7uJkVQv5MM3vsvWdiVGuTfYCCB4UYxNNrbAV+zsFmEPqZ4bZv3tPl29aW i+nC+/qvaXEzDggiGjziTH/463441gm8UbGNye5CF7saReiqJB6WSl0FK mAoP1a/Inqx6NMAGVBZn0yHdM2aUvHN5Qxgr0OU/+u1hmrt3evUcXdeDn Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697718" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697718" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 04:59:38 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829540940" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829540940" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 04:59:36 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:27 +0200 Message-Id: <20230105125446.960504-3-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 02/21] drm/i915/mtl: Add DP rates 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Add DP rates for Meteorlake. Signed-off-by: Radhakrishna Sripada Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-3-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index bf80f296a8fd..0b08e9b6ea22 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -420,6 +420,11 @@ static int ehl_max_source_rate(struct intel_dp *intel_dp) return 810000; } +static int mtl_max_source_rate(struct intel_dp *intel_dp) +{ + return intel_dp_is_edp(intel_dp) ? 675000 : 810000; +} + static int vbt_max_link_rate(struct intel_dp *intel_dp) { struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; @@ -444,6 +449,10 @@ static void intel_dp_set_source_rates(struct intel_dp *intel_dp) { /* The values must be in increasing order */ + static const int mtl_rates[] = { + 162000, 216000, 243000, 270000, 324000, 432000, 540000, 675000, + 810000, + }; static const int icl_rates[] = { 162000, 216000, 270000, 324000, 432000, 540000, 648000, 810000, 1000000, 1350000, @@ -469,7 +478,11 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) drm_WARN_ON(&dev_priv->drm, intel_dp->source_rates || intel_dp->num_source_rates); - if (DISPLAY_VER(dev_priv) >= 11) { + if (DISPLAY_VER(dev_priv) >= 14) { + source_rates = mtl_rates; + size = ARRAY_SIZE(mtl_rates); + max_rate = mtl_max_source_rate(intel_dp); + } else if (DISPLAY_VER(dev_priv) >= 11) { source_rates = icl_rates; size = ARRAY_SIZE(icl_rates); if (IS_DG2(dev_priv)) From patchwork Thu Jan 5 12:54:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089812 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 6FCE8C3DA7A for ; Thu, 5 Jan 2023 12:59:44 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id BF5A710E715; Thu, 5 Jan 2023 12:59:43 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 9D9B710E712 for ; Thu, 5 Jan 2023 12:59:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923580; x=1704459580; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=w6SiyN17pHRus9hsQ6b55AISFe5Hn/BSJHFpB+fVXU8=; b=TE63HhGluvAo+u359GN1jErQ0ric8xjutUJqPz6yeYHACJqug+8rv1sr vZGZgAHlH5glA4JYmnevLn/kAibmBD6dAKFGJ9Z5a7wwqcNyWfU1No3U2 PPOoJCx+WdWKRWPX8NGfsEUSv6Kj1bjV6Ji/8ietS7kjwOpx+oIQRM/qX B39EnCKCsT4vUMPHebnCU4hPGZ/h+iB/e2R5hwL5RxM0oSTjdMGo9O3J6 tTJnmU07xb0EnTdZceX6y+BBLHKz3MUHvJPdy7d1ggBylgzfVo3OnwbWe /IcACaP1CeJri9uZlN1fkAib9aTNRaKXf84jDr9HGWYBT+e1pKN95+Gv0 w==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697722" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697722" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 04:59:40 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829540947" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829540947" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 04:59:38 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:28 +0200 Message-Id: <20230105125446.960504-4-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 03/21] drm/i915/mtl: Create separate reg file for PICA registers 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Create a separate file to store registers for PICA chips C10 and C20. v2: Rename file (Jani) Signed-off-by: Radhakrishna Sripada Signed-off-by: Mika Kahola --- .../gpu/drm/i915/display/intel_cx0_phy_regs.h | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h new file mode 100644 index 000000000000..d6b3709d3762 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright © 2022 Intel Corporation + */ + +#ifndef __INTEL_CX0_PHY_REGS_H__ +#define __INTEL_CX0_PHY_REGS_H__ + +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_A 0x64040 +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_B 0x64140 +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC1 0x16F240 +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC2 0x16F440 +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC3 0x16F640 +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC4 0x16F840 +#define _XELPDP_PORT_M2P_MSGBUS_CTL(port, lane) (_PICK(port, \ + [PORT_A] = _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_A, \ + [PORT_B] = _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_B, \ + [PORT_TC1] = _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC1, \ + [PORT_TC2] = _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC2, \ + [PORT_TC3] = _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC3, \ + [PORT_TC4] = _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC4) + ((lane) * 4)) + +#define XELPDP_PORT_M2P_MSGBUS_CTL(port, lane) _MMIO(_XELPDP_PORT_M2P_MSGBUS_CTL(port, lane)) +#define XELPDP_PORT_M2P_TRANSACTION_PENDING REG_BIT(31) +#define XELPDP_PORT_M2P_COMMAND_TYPE_MASK REG_GENMASK(30, 27) +#define XELPDP_PORT_M2P_COMMAND_WRITE_UNCOMMITTED REG_FIELD_PREP(XELPDP_PORT_M2P_COMMAND_TYPE_MASK, 0x1) +#define XELPDP_PORT_M2P_COMMAND_WRITE_COMMITTED REG_FIELD_PREP(XELPDP_PORT_M2P_COMMAND_TYPE_MASK, 0x2) +#define XELPDP_PORT_M2P_COMMAND_READ REG_FIELD_PREP(XELPDP_PORT_M2P_COMMAND_TYPE_MASK, 0x3) +#define XELPDP_PORT_M2P_DATA_MASK REG_GENMASK(23, 16) +#define XELPDP_PORT_M2P_DATA(val) REG_FIELD_PREP(XELPDP_PORT_M2P_DATA_MASK, val) +#define XELPDP_PORT_M2P_TRANSACTION_RESET REG_BIT(15) +#define XELPDP_PORT_M2P_ADDRESS_MASK REG_GENMASK(11, 0) +#define XELPDP_PORT_M2P_ADDRESS(val) REG_FIELD_PREP(XELPDP_PORT_M2P_ADDRESS_MASK, val) + +#define XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane) _MMIO(_XELPDP_PORT_M2P_MSGBUS_CTL(port, lane) + 8) +#define XELPDP_PORT_P2M_RESPONSE_READY REG_BIT(31) +#define XELPDP_PORT_P2M_COMMAND_TYPE_MASK REG_GENMASK(30, 27) +#define XELPDP_PORT_P2M_COMMAND_READ_ACK 0x4 +#define XELPDP_PORT_P2M_COMMAND_WRITE_ACK 0x5 +#define XELPDP_PORT_P2M_DATA_MASK REG_GENMASK(23, 16) +#define XELPDP_PORT_P2M_DATA(val) REG_FIELD_PREP(XELPDP_PORT_P2M_DATA_MASK, val) +#define XELPDP_PORT_P2M_ERROR_SET REG_BIT(15) +#define XELPDP_MSGBUS_TIMEOUT_SLOW 1 +#define XELPDP_MSGBUS_TIMEOUT_FAST_US 2 + +#define XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US 3200 +#define XELPDP_PCLK_PLL_DISABLE_TIMEOUT_US 20 +#define XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US 100 +#define XELPDP_PORT_RESET_START_TIMEOUT_US 5 +#define XELPDP_PORT_POWERDOWN_UPDATE_TIMEOUT_US 100 +#define XELPDP_PORT_RESET_END_TIMEOUT 15 +#define XELPDP_REFCLK_ENABLE_TIMEOUT_US 1 + +#define _XELPDP_PORT_BUF_CTL1_LN0_A 0x64004 +#define _XELPDP_PORT_BUF_CTL1_LN0_B 0x64104 +#define _XELPDP_PORT_BUF_CTL1_LN0_USBC1 0x16F200 +#define _XELPDP_PORT_BUF_CTL1_LN0_USBC2 0x16F400 +#define _XELPDP_PORT_BUF_CTL1_LN0_USBC3 0x16F600 +#define _XELPDP_PORT_BUF_CTL1_LN0_USBC4 0x16F800 +#define _XELPDP_PORT_BUF_CTL1(port) (_PICK(port, \ + [PORT_A] = _XELPDP_PORT_BUF_CTL1_LN0_A, \ + [PORT_B] = _XELPDP_PORT_BUF_CTL1_LN0_B, \ + [PORT_TC1] = _XELPDP_PORT_BUF_CTL1_LN0_USBC1, \ + [PORT_TC2] = _XELPDP_PORT_BUF_CTL1_LN0_USBC2, \ + [PORT_TC3] = _XELPDP_PORT_BUF_CTL1_LN0_USBC3, \ + [PORT_TC4] = _XELPDP_PORT_BUF_CTL1_LN0_USBC4)) + +#define XELPDP_PORT_BUF_CTL1(port) _MMIO(_XELPDP_PORT_BUF_CTL1(port)) +#define XELPDP_PORT_BUF_SOC_PHY_READY REG_BIT(24) +#define XELPDP_PORT_REVERSAL REG_BIT(16) + +#define XELPDP_TC_PHY_OWNERSHIP REG_BIT(6) +#define XELPDP_TCSS_POWER_REQUEST REG_BIT(5) +#define XELPDP_TCSS_POWER_STATE REG_BIT(4) +#define XELPDP_PORT_WIDTH_MASK REG_GENMASK(3, 1) +#define XELPDP_PORT_WIDTH(val) REG_FIELD_PREP(XELPDP_PORT_WIDTH_MASK, val) + +#define XELPDP_PORT_BUF_CTL2(port) _MMIO(_XELPDP_PORT_BUF_CTL1(port) + 4) +#define XELPDP_LANE0_PIPE_RESET REG_BIT(31) +#define XELPDP_LANE1_PIPE_RESET REG_BIT(30) +#define XELPDP_LANE0_PHY_CURRENT_STATUS REG_BIT(29) +#define XELPDP_LANE1_PHY_CURRENT_STATUS REG_BIT(28) +#define XELPDP_LANE0_POWERDOWN_UPDATE REG_BIT(25) +#define XELPDP_LANE1_POWERDOWN_UPDATE REG_BIT(24) +#define XELPDP_LANE0_POWERDOWN_NEW_STATE_MASK REG_GENMASK(23, 20) +#define XELPDP_LANE0_POWERDOWN_NEW_STATE(val) REG_FIELD_PREP(XELPDP_LANE0_POWERDOWN_NEW_STATE_MASK, val) +#define XELPDP_LANE1_POWERDOWN_NEW_STATE_MASK REG_GENMASK(19, 16) +#define XELPDP_LANE1_POWERDOWN_NEW_STATE(val) REG_FIELD_PREP(XELPDP_LANE1_POWERDOWN_NEW_STATE_MASK, val) +#define XELPDP_POWER_STATE_READY_MASK REG_GENMASK(7, 4) +#define XELPDP_POWER_STATE_READY(val) REG_FIELD_PREP(XELPDP_POWER_STATE_READY_MASK, val) + +#define XELPDP_PORT_BUF_CTL3(port) _MMIO(_XELPDP_PORT_BUF_CTL1(port) + 8) +#define XELPDP_PLL_LANE_STAGGERING_DELAY_MASK REG_GENMASK(15, 8) +#define XELPDP_PLL_LANE_STAGGERING_DELAY(val) REG_FIELD_PREP(XELPDP_PLL_LANE_STAGGERING_DELAY_MASK, val) +#define XELPDP_POWER_STATE_ACTIVE_MASK REG_GENMASK(3, 0) +#define XELPDP_POWER_STATE_ACTIVE(val) REG_FIELD_PREP(XELPDP_POWER_STATE_ACTIVE_MASK, val) + +#define _XELPDP_PORT_CLOCK_CTL_A 0x640E0 +#define _XELPDP_PORT_CLOCK_CTL_B 0x641E0 +#define _XELPDP_PORT_CLOCK_CTL_USBC1 0x16F260 +#define _XELPDP_PORT_CLOCK_CTL_USBC2 0x16F460 +#define _XELPDP_PORT_CLOCK_CTL_USBC3 0x16F660 +#define _XELPDP_PORT_CLOCK_CTL_USBC4 0x16F860 +#define XELPDP_PORT_CLOCK_CTL(port) _MMIO(_PICK(port, \ + [PORT_A] = _XELPDP_PORT_CLOCK_CTL_A, \ + [PORT_B] = _XELPDP_PORT_CLOCK_CTL_B, \ + [PORT_TC1] = _XELPDP_PORT_CLOCK_CTL_USBC1, \ + [PORT_TC2] = _XELPDP_PORT_CLOCK_CTL_USBC2, \ + [PORT_TC3] = _XELPDP_PORT_CLOCK_CTL_USBC3, \ + [PORT_TC4] = _XELPDP_PORT_CLOCK_CTL_USBC4)) + +#define XELPDP_LANE0_PCLK_PLL_REQUEST REG_BIT(31) +#define XELPDP_LANE0_PCLK_PLL_ACK REG_BIT(30) +#define XELPDP_LANE0_PCLK_REFCLK_REQUEST REG_BIT(29) +#define XELPDP_LANE0_PCLK_REFCLK_ACK REG_BIT(28) +#define XELPDP_LANE1_PCLK_PLL_REQUEST REG_BIT(27) +#define XELPDP_LANE1_PCLK_PLL_ACK REG_BIT(26) +#define XELPDP_LANE1_PCLK_REFCLK_REQUEST REG_BIT(25) +#define XELPDP_LANE1_PCLK_REFCLK_ACK REG_BIT(24) +#define XELPDP_TBT_CLOCK_REQUEST REG_BIT(19) +#define XELPDP_TBT_CLOCK_ACK REG_BIT(18) +#define XELPDP_DDI_CLOCK_SELECT_MASK REG_GENMASK(15, 12) +#define XELPDP_DDI_CLOCK_SELECT(val) REG_FIELD_PREP(XELPDP_DDI_CLOCK_SELECT_MASK, val) +#define XELPDP_DDI_CLOCK_SELECT_NONE 0x0 +#define XELPDP_DDI_CLOCK_SELECT_MAXPCLK 0x8 +#define XELPDP_DDI_CLOCK_SELECT_DIV18CLK 0x9 +#define XELPDP_DDI_CLOCK_SELECT_TBT_162 0xc +#define XELPDP_DDI_CLOCK_SELECT_TBT_270 0xd +#define XELPDP_DDI_CLOCK_SELECT_TBT_540 0xe +#define XELPDP_DDI_CLOCK_SELECT_TBT_810 0xf +#define XELPDP_FORWARD_CLOCK_UNGATE REG_BIT(10) +#define XELPDP_LANE1_PHY_CLOCK_SELECT REG_BIT(8) +#define XELPDP_SSC_ENABLE_PLLA REG_BIT(1) +#define XELPDP_SSC_ENABLE_PLLB REG_BIT(0) + +#endif /* __INTEL_CX0_PHY_REGS_H__ */ From patchwork Thu Jan 5 12:54:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089813 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 44E23C54E76 for ; Thu, 5 Jan 2023 12:59:47 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id B118010E717; Thu, 5 Jan 2023 12:59:46 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7DEB510E714 for ; Thu, 5 Jan 2023 12:59:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923583; x=1704459583; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=CvwI8Wavp2TFFyA2DAYDNZt7mMBhyk8CGTLttSx9J7s=; b=MHA1ooOQVtcn2RSdXF4+G9/LNP0uIChyBPyzU07r6QoKPt8FBEm7vFoP xC7/Q6Dt/cwXZWJwUrZpWEN1Y899+RvVVS2U/A4eMx2gIS2/xM0bH/v1d pxqR9t057Yk8FHtVroU4GIsY0TYZ19LhZNfOPd0G9xjST3eE1qBM4Tev3 nJl/o7any6HyODRItyLw6OBXmsEuFOYiXOf+Hj3D2QIEnCbbbzgMd5HPn uASxQ9cRolKVUTogwrRFJINHIOX9wwKRATmv51ifTMHzLtaP1tkl3CVGb kRj3ZF9yzTw44WFTXxW7uIDLHI3K8pRtRtr6aKImxhy9BOpCSZ0ybm9EU Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697729" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697729" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 04:59:43 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829540951" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829540951" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 04:59:40 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:29 +0200 Message-Id: <20230105125446.960504-5-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 04/21] drm/i915/mtl: Add Support for C10 PHY message bus and pll programming 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Radhakrishna Sripada XELPDP has C10 and C20 phys from Synopsys to drive displays. Each phy has a dedicated PIPE 5.2 Message bus for configuration. This message bus is used to configure the phy internal registers. XELPDP has C10 phys to drive output to the EDP and the native output from the display engine. Add structures, programming hardware state readout logic. Port clock calculations are similar to DG2. Use the DG2 formulae to calculate the port clock but use the relevant pll signals. Note: PHY lane 0 is always used for PLL programming. Add sequences for C10 phy enable/disable phy lane reset, powerdown change sequence and phy lane programming. Bspec: 64539, 64568, 64599, 65100, 65101, 65450, 65451, 67610, 67636 v2: Squash patches related to C10 phy message bus and pll programming support (Jani) Move register definitions to a new file i.e. intel_cx0_reg_defs.h (Jani) Move macro definitions (Jani) DP rates as separate patch (Jani) Spin out xelpdp register definitions into a separate file (Jani) Replace macro to select registers based on phy lane with function calls (Jani) Fix styling issues (Jani) Call XELPDP_PORT_P2M_MSGBUS_STATUS() with port instead of phy (Lucas) v3: Move clear request flag into try-loop Cc: Mika Kahola Cc: Imre Deak Cc: Uma Shankar Signed-off-by: Radhakrishna Sripada Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-5-mika.kahola@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_cx0_phy.c | 1110 +++++++++++++++++ drivers/gpu/drm/i915/display/intel_cx0_phy.h | 43 + .../gpu/drm/i915/display/intel_cx0_phy_regs.h | 34 + drivers/gpu/drm/i915/display/intel_ddi.c | 22 +- drivers/gpu/drm/i915/display/intel_display.c | 1 + .../drm/i915/display/intel_display_power.c | 3 +- .../i915/display/intel_display_power_well.c | 2 +- .../drm/i915/display/intel_display_types.h | 6 + drivers/gpu/drm/i915/display/intel_dpll.c | 22 +- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 2 +- .../drm/i915/display/intel_modeset_verify.c | 2 + drivers/gpu/drm/i915/i915_reg.h | 5 + drivers/gpu/drm/i915/i915_reg_defs.h | 57 + 14 files changed, 1305 insertions(+), 5 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_cx0_phy.c create mode 100644 drivers/gpu/drm/i915/display/intel_cx0_phy.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index f47f00b162a4..200364242c83 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -290,6 +290,7 @@ i915-y += \ display/icl_dsi.o \ display/intel_backlight.o \ display/intel_crt.o \ + display/intel_cx0_phy.o \ display/intel_ddi.o \ display/intel_ddi_buf_trans.o \ display/intel_display_trace.o \ diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c new file mode 100644 index 000000000000..1ceebbc6b650 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -0,0 +1,1110 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#include "i915_reg.h" +#include "intel_cx0_phy.h" +#include "intel_cx0_phy_regs.h" +#include "intel_de.h" +#include "intel_display_types.h" +#include "intel_dp.h" +#include "intel_panel.h" + +bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy) +{ + if (IS_METEORLAKE(dev_priv) && (phy < PHY_C)) + return true; + + return false; +} + +static void intel_cx0_bus_reset(struct drm_i915_private *i915, enum port port, int lane) +{ + enum phy phy = intel_port_to_phy(i915, port); + + /* Bring the phy to idle. */ + intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane-1), + XELPDP_PORT_M2P_TRANSACTION_RESET); + + /* Wait for Idle Clear. */ + if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane-1), + XELPDP_PORT_M2P_TRANSACTION_RESET, + XELPDP_MSGBUS_TIMEOUT_SLOW)) { + drm_err_once(&i915->drm, "Failed to bring PHY %c to idle.\n", phy_name(phy)); + return; + } + + intel_de_write(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane-1), ~0); +} + +static int intel_cx0_wait_for_ack(struct drm_i915_private *i915, enum port port, int lane, u32 *val) +{ + enum phy phy = intel_port_to_phy(i915, port); + + if (__intel_wait_for_register(&i915->uncore, + XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane-1), + XELPDP_PORT_P2M_RESPONSE_READY, + XELPDP_PORT_P2M_RESPONSE_READY, + XELPDP_MSGBUS_TIMEOUT_FAST_US, + XELPDP_MSGBUS_TIMEOUT_SLOW, val)) { + drm_dbg_kms(&i915->drm, "PHY %c Timeout waiting for message ACK. Status: 0x%x\n", phy_name(phy), *val); + return -ETIMEDOUT; + } + + return 0; +} + +static int __intel_cx0_read(struct drm_i915_private *i915, enum port port, + int lane, u16 addr, u32 *val) +{ + enum phy phy = intel_port_to_phy(i915, port); + int ack; + + /* Wait for pending transactions.*/ + if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane-1), + XELPDP_PORT_M2P_TRANSACTION_PENDING, + XELPDP_MSGBUS_TIMEOUT_SLOW)) { + drm_dbg_kms(&i915->drm, "PHY %c Timeout waiting for previous transaction to complete. Reset the bus and retry.\n", phy_name(phy)); + intel_cx0_bus_reset(i915, port, lane); + return -ETIMEDOUT; + } + + /* Issue the read command. */ + intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane-1), + XELPDP_PORT_M2P_TRANSACTION_PENDING | + XELPDP_PORT_M2P_COMMAND_READ | + XELPDP_PORT_M2P_ADDRESS(addr)); + + /* Wait for response ready. And read response.*/ + ack = intel_cx0_wait_for_ack(i915, port, lane, val); + if (ack < 0) { + intel_cx0_bus_reset(i915, port, lane); + return ack; + } + + /* Check for error. */ + if (*val & XELPDP_PORT_P2M_ERROR_SET) { + drm_dbg_kms(&i915->drm, "PHY %c Error occurred during read command. Status: 0x%x\n", phy_name(phy), *val); + intel_cx0_bus_reset(i915, port, lane); + return -EINVAL; + } + + /* Check for Read Ack. */ + if (REG_FIELD_GET(XELPDP_PORT_P2M_COMMAND_TYPE_MASK, *val) != + XELPDP_PORT_P2M_COMMAND_READ_ACK) { + drm_dbg_kms(&i915->drm, "PHY %c Not a Read response. MSGBUS Status: 0x%x.\n", phy_name(phy), *val); + intel_cx0_bus_reset(i915, port, lane); + return -EINVAL; + } + + /* Clear Response Ready flag.*/ + intel_de_write(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane-1), ~0); + + return REG_FIELD_GET(XELPDP_PORT_P2M_DATA_MASK, *val); +} + +static u8 intel_cx0_read(struct drm_i915_private *i915, enum port port, + int lane, u16 addr) +{ + enum phy phy = intel_port_to_phy(i915, port); + int i, status = 0; + u32 val; + + for (i = 0; i < 3; i++) { + status = __intel_cx0_read(i915, port, lane, addr, &val); + + if (status >= 0) + break; + } + + if (i == 3) { + drm_err_once(&i915->drm, "PHY %c Read %04x failed after %d retries.\n", phy_name(phy), addr, i); + return 0; + } + + return status; +} + +static int intel_cx0_wait_cwrite_ack(struct drm_i915_private *i915, + enum port port, int lane) +{ + enum phy phy = intel_port_to_phy(i915, port); + int ack; + u32 val = 0; + + /* Check for write ack. */ + ack = intel_cx0_wait_for_ack(i915, port, lane, &val); + if (ack < 0) + return ack; + + if ((REG_FIELD_GET(XELPDP_PORT_P2M_COMMAND_TYPE_MASK, val) != + XELPDP_PORT_P2M_COMMAND_WRITE_ACK) || val & XELPDP_PORT_P2M_ERROR_SET) { + drm_dbg_kms(&i915->drm, "PHY %c Unexpected ACK received. MSGBUS STATUS: 0x%x.\n", phy_name(phy), val); + return -EINVAL; + } + + return 0; +} + +static int __intel_cx0_write_once(struct drm_i915_private *i915, enum port port, + int lane, u16 addr, u8 data, bool committed) +{ + enum phy phy = intel_port_to_phy(i915, port); + + /* Wait for pending transactions.*/ + if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane-1), + XELPDP_PORT_M2P_TRANSACTION_PENDING, + XELPDP_MSGBUS_TIMEOUT_SLOW)) { + drm_dbg_kms(&i915->drm, "PHY %c Timeout waiting for previous transaction to complete. Reset the bus and retry.\n", phy_name(phy)); + intel_cx0_bus_reset(i915, port, lane); + return -ETIMEDOUT; + } + + /* Issue the write command. */ + intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane-1), + XELPDP_PORT_M2P_TRANSACTION_PENDING | + (committed ? XELPDP_PORT_M2P_COMMAND_WRITE_COMMITTED : + XELPDP_PORT_M2P_COMMAND_WRITE_UNCOMMITTED) | + XELPDP_PORT_M2P_DATA(data) | + XELPDP_PORT_M2P_ADDRESS(addr)); + + /* Check for error. */ + if (committed) { + if (intel_cx0_wait_cwrite_ack(i915, port, lane) < 0) { + intel_cx0_bus_reset(i915, port, lane); + return -EINVAL; + } + } else if ((intel_de_read(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane-1)) & + XELPDP_PORT_P2M_ERROR_SET)) { + drm_dbg_kms(&i915->drm, "PHY %c Error occurred during write command.\n", phy_name(phy)); + intel_cx0_bus_reset(i915, port, lane); + return -EINVAL; + } + + intel_de_write(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane-1), ~0); + + return 0; +} + +static void __intel_cx0_write(struct drm_i915_private *i915, enum port port, + int lane, u16 addr, u8 data, bool committed) +{ + enum phy phy = intel_port_to_phy(i915, port); + int i, status; + + for (i = 0; i < 3; i++) { + status = __intel_cx0_write_once(i915, port, lane, addr, data, committed); + + if (status == 0) + break; + } + + if (i == 3) { + drm_err_once(&i915->drm, "PHY %c Write %04x failed after %d retries.\n", phy_name(phy), addr, i); + return; + } +} + +static void intel_cx0_write(struct drm_i915_private *i915, enum port port, + int lane, u16 addr, u8 data, bool committed) +{ + if (lane & INTEL_CX0_BOTH_LANES) { + __intel_cx0_write(i915, port, INTEL_CX0_LANE0, addr, data, committed); + __intel_cx0_write(i915, port, INTEL_CX0_LANE1, addr, data, committed); + } else { + __intel_cx0_write(i915, port, lane, addr, data, committed); + } +} + +static void __intel_cx0_rmw(struct drm_i915_private *i915, enum port port, + int lane, u16 addr, u8 clear, u8 set, bool committed) +{ + u8 old, val; + + old = intel_cx0_read(i915, port, lane, addr); + val = (old & ~clear) | set; + + if (val != old) + intel_cx0_write(i915, port, lane, addr, val, committed); +} + +static void intel_cx0_rmw(struct drm_i915_private *i915, enum port port, + int lane, u16 addr, u8 clear, u8 set, bool committed) +{ + if (lane & INTEL_CX0_BOTH_LANES) { + __intel_cx0_rmw(i915, port, INTEL_CX0_LANE0, addr, clear, set, committed); + __intel_cx0_rmw(i915, port, INTEL_CX0_LANE1, addr, clear, set, committed); + } else { + __intel_cx0_rmw(i915, port, lane, addr, clear, set, committed); + } +} + +/* + * Basic DP link rates with 38.4 MHz reference clock. + * Note: The tables below are with SSC. In non-ssc + * registers 0xC04 to 0xC08(pll[4] to pll[8]) will be + * programmed 0. + */ + +static const struct intel_c10mpllb_state mtl_c10_dp_rbr = { + .clock = 162000, + .pll[0] = 0xB4, + .pll[1] = 0, + .pll[2] = 0x30, + .pll[3] = 0x1, + .pll[4] = 0x26, + .pll[5] = 0x0C, + .pll[6] = 0x98, + .pll[7] = 0x46, + .pll[8] = 0x1, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0xC0, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0x2, + .pll[16] = 0x84, + .pll[17] = 0x4F, + .pll[18] = 0xE5, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_edp_r216 = { + .clock = 216000, + .pll[0] = 0x4, + .pll[1] = 0, + .pll[2] = 0xA2, + .pll[3] = 0x1, + .pll[4] = 0x33, + .pll[5] = 0x10, + .pll[6] = 0x75, + .pll[7] = 0xB3, + .pll[8] = 0x1, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0x2, + .pll[16] = 0x85, + .pll[17] = 0x0F, + .pll[18] = 0xE6, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_edp_r243 = { + .clock = 243000, + .pll[0] = 0x34, + .pll[1] = 0, + .pll[2] = 0xDA, + .pll[3] = 0x1, + .pll[4] = 0x39, + .pll[5] = 0x12, + .pll[6] = 0xE3, + .pll[7] = 0xE9, + .pll[8] = 0x1, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0x20, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0x2, + .pll[16] = 0x85, + .pll[17] = 0x8F, + .pll[18] = 0xE6, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_dp_hbr1 = { + .clock = 270000, + .pll[0] = 0xF4, + .pll[1] = 0, + .pll[2] = 0xF8, + .pll[3] = 0x0, + .pll[4] = 0x20, + .pll[5] = 0x0A, + .pll[6] = 0x29, + .pll[7] = 0x10, + .pll[8] = 0x1, /* Verify */ + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0xA0, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0x1, + .pll[16] = 0x84, + .pll[17] = 0x4F, + .pll[18] = 0xE5, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_edp_r324 = { + .clock = 324000, + .pll[0] = 0xB4, + .pll[1] = 0, + .pll[2] = 0x30, + .pll[3] = 0x1, + .pll[4] = 0x26, + .pll[5] = 0x0C, + .pll[6] = 0x98, + .pll[7] = 0x46, + .pll[8] = 0x1, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0xC0, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0x1, + .pll[16] = 0x85, + .pll[17] = 0x4F, + .pll[18] = 0xE6, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_edp_r432 = { + .clock = 432000, + .pll[0] = 0x4, + .pll[1] = 0, + .pll[2] = 0xA2, + .pll[3] = 0x1, + .pll[4] = 0x33, + .pll[5] = 0x10, + .pll[6] = 0x75, + .pll[7] = 0xB3, + .pll[8] = 0x1, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0x1, + .pll[16] = 0x85, + .pll[17] = 0x0F, + .pll[18] = 0xE6, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_dp_hbr2 = { + .clock = 540000, + .pll[0] = 0xF4, + .pll[1] = 0, + .pll[2] = 0xF8, + .pll[3] = 0, + .pll[4] = 0x20, + .pll[5] = 0x0A, + .pll[6] = 0x29, + .pll[7] = 0x10, + .pll[8] = 0x1, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0xA0, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0, + .pll[16] = 0x84, + .pll[17] = 0x4F, + .pll[18] = 0xE5, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_edp_r675 = { + .clock = 675000, + .pll[0] = 0xB4, + .pll[1] = 0, + .pll[2] = 0x3E, + .pll[3] = 0x1, + .pll[4] = 0xA8, + .pll[5] = 0x0C, + .pll[6] = 0x33, + .pll[7] = 0x54, + .pll[8] = 0x1, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0xC8, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0, + .pll[16] = 0x85, + .pll[17] = 0x8F, + .pll[18] = 0xE6, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_dp_hbr3 = { + .clock = 810000, + .pll[0] = 0x34, + .pll[1] = 0, + .pll[2] = 0x84, + .pll[3] = 0x1, + .pll[4] = 0x30, + .pll[5] = 0x0F, + .pll[6] = 0x3D, + .pll[7] = 0x98, + .pll[8] = 0x1, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0xF0, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0, + .pll[16] = 0x84, + .pll[17] = 0x0F, + .pll[18] = 0xE5, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state * const mtl_c10_dp_tables[] = { + &mtl_c10_dp_rbr, + &mtl_c10_dp_hbr1, + &mtl_c10_dp_hbr2, + &mtl_c10_dp_hbr3, + NULL, +}; + +static const struct intel_c10mpllb_state * const mtl_c10_edp_tables[] = { + &mtl_c10_dp_rbr, + &mtl_c10_edp_r216, + &mtl_c10_edp_r243, + &mtl_c10_dp_hbr1, + &mtl_c10_edp_r324, + &mtl_c10_edp_r432, + &mtl_c10_dp_hbr2, + &mtl_c10_edp_r675, + &mtl_c10_dp_hbr3, + NULL, +}; + +static const struct intel_c10mpllb_state * const * +intel_c10_mpllb_tables_get(struct intel_crtc_state *crtc_state, + struct intel_encoder *encoder) +{ + if (intel_crtc_has_dp_encoder(crtc_state)) { + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return mtl_c10_edp_tables; + else + return mtl_c10_dp_tables; + } + + /* TODO: Add HDMI Support */ + MISSING_CASE(encoder->type); + return NULL; +} + +static int intel_c10mpllb_calc_state(struct intel_crtc_state *crtc_state, + struct intel_encoder *encoder) +{ + const struct intel_c10mpllb_state * const *tables; + int i; + + tables = intel_c10_mpllb_tables_get(crtc_state, encoder); + if (!tables) + return -EINVAL; + + for (i = 0; tables[i]; i++) { + if (crtc_state->port_clock <= tables[i]->clock) { + crtc_state->c10mpllb_state = *tables[i]; + return 0; + } + } + + return -EINVAL; +} + +int intel_cx0mpllb_calc_state(struct intel_crtc_state *crtc_state, + struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); + + return intel_c10mpllb_calc_state(crtc_state, encoder); +} + +void intel_c10mpllb_readout_hw_state(struct intel_encoder *encoder, + struct intel_c10mpllb_state *pll_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL; + u8 lane = lane_reversal ? INTEL_CX0_LANE1 : + INTEL_CX0_LANE0; + enum phy phy = intel_port_to_phy(i915, encoder->port); + int i; + u8 cmn, tx0; + + /* + * According to C10 VDR Register programming Sequence we need + * to do this to read PHY internal registers from MsgBus. + */ + intel_cx0_rmw(i915, encoder->port, lane, PHY_C10_VDR_CONTROL(1), 0, + C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED); + + for (i = 0; i < ARRAY_SIZE(pll_state->pll); i++) + pll_state->pll[i] = intel_cx0_read(i915, encoder->port, lane, + PHY_C10_VDR_PLL(i)); + + cmn = intel_cx0_read(i915, encoder->port, lane, PHY_C10_VDR_CMN(0)); + tx0 = intel_cx0_read(i915, encoder->port, lane, PHY_C10_VDR_TX(0)); + + if (tx0 != C10_TX0_VAL || cmn != C10_CMN0_DP_VAL) + drm_warn(&i915->drm, "Unexpected tx: %x or cmn: %x for phy: %c.\n", + tx0, cmn, phy_name(phy)); +} + +static void intel_c10_pll_program(struct drm_i915_private *i915, + const struct intel_crtc_state *crtc_state, + struct intel_encoder *encoder) +{ + const struct intel_c10mpllb_state *pll_state = &crtc_state->c10mpllb_state; + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL; + u8 master_lane = lane_reversal ? INTEL_CX0_LANE1 : + INTEL_CX0_LANE0; + u8 follower_lane = lane_reversal ? INTEL_CX0_LANE0 : + INTEL_CX0_LANE1; + + int i; + struct intel_dp *intel_dp; + bool use_ssc = false; + u8 cmn0 = 0; + + if (intel_crtc_has_dp_encoder(crtc_state)) { + intel_dp = enc_to_intel_dp(encoder); + use_ssc = (intel_dp->dpcd[DP_MAX_DOWNSPREAD] & + DP_MAX_DOWNSPREAD_0_5); + + if (!intel_panel_use_ssc(i915)) + use_ssc = false; + + cmn0 = C10_CMN0_DP_VAL; + } + + intel_cx0_write(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CONTROL(1), + C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED); + /* Custom width needs to be programmed to 0 for both the phy lanes */ + intel_cx0_rmw(i915, encoder->port, INTEL_CX0_BOTH_LANES, + PHY_C10_VDR_CUSTOM_WIDTH, 0x3, 0, MB_WRITE_COMMITTED); + intel_cx0_rmw(i915, encoder->port, follower_lane, PHY_C10_VDR_CONTROL(1), + C10_VDR_CTRL_MASTER_LANE, C10_VDR_CTRL_UPDATE_CFG, + MB_WRITE_COMMITTED); + + /* Program the pll values only for the master lane */ + for (i = 0; i < ARRAY_SIZE(pll_state->pll); i++) + /* If not using ssc pll[4] through pll[8] must be 0*/ + intel_cx0_write(i915, encoder->port, master_lane, PHY_C10_VDR_PLL(i), + (!use_ssc && (i > 3 && i < 9)) ? 0 : pll_state->pll[i], + (i % 4) ? MB_WRITE_UNCOMMITTED : MB_WRITE_COMMITTED); + + intel_cx0_write(i915, encoder->port, master_lane, PHY_C10_VDR_CMN(0), cmn0, MB_WRITE_COMMITTED); + intel_cx0_write(i915, encoder->port, master_lane, PHY_C10_VDR_TX(0), C10_TX0_VAL, MB_WRITE_COMMITTED); + intel_cx0_rmw(i915, encoder->port, master_lane, PHY_C10_VDR_CONTROL(1), + C10_VDR_CTRL_MSGBUS_ACCESS, C10_VDR_CTRL_MASTER_LANE | + C10_VDR_CTRL_UPDATE_CFG, MB_WRITE_COMMITTED); +} + +void intel_c10mpllb_dump_hw_state(struct drm_i915_private *dev_priv, + const struct intel_c10mpllb_state *hw_state) +{ + bool fracen; + int i; + unsigned int frac_quot = 0, frac_rem = 0, frac_den = 1; + unsigned int multiplier, tx_clk_div; + + fracen = hw_state->pll[0] & C10_PLL0_FRACEN; + drm_dbg_kms(&dev_priv->drm, "c10pll_hw_state: fracen: %s, ", + str_yes_no(fracen)); + + if (fracen) { + frac_quot = hw_state->pll[12] << 8 | hw_state->pll[11]; + frac_rem = hw_state->pll[14] << 8 | hw_state->pll[13]; + frac_den = hw_state->pll[10] << 8 | hw_state->pll[9]; + drm_dbg_kms(&dev_priv->drm, "quot: %u, rem: %u, den: %u,\n", + frac_quot, frac_rem, frac_den); + } + + multiplier = (REG_FIELD_GET8(C10_PLL3_MULTIPLIERH_MASK, hw_state->pll[3]) << 8 | + hw_state->pll[2]) / 2 + 16; + tx_clk_div = REG_FIELD_GET8(C10_PLL15_TXCLKDIV_MASK, hw_state->pll[15]); + drm_dbg_kms(&dev_priv->drm, + "multiplier: %u, tx_clk_div: %u.\n", multiplier, tx_clk_div); + + drm_dbg_kms(&dev_priv->drm, "c10pll_rawhw_state:"); + + for (i = 0; i < ARRAY_SIZE(hw_state->pll); i = i + 4) + drm_dbg_kms(&dev_priv->drm, "pll[%d] = 0x%x, pll[%d] = 0x%x, pll[%d] = 0x%x, pll[%d] = 0x%x\n", + i, hw_state->pll[i], i + 1, hw_state->pll[i + 1], + i + 2, hw_state->pll[i + 2], i + 3, hw_state->pll[i + 3]); +} + +int intel_c10mpllb_calc_port_clock(struct intel_encoder *encoder, + const struct intel_c10mpllb_state *pll_state) +{ + unsigned int frac_quot = 0, frac_rem = 0, frac_den = 1; + unsigned int multiplier, tx_clk_div, refclk = 38400; + + if (pll_state->pll[0] & C10_PLL0_FRACEN) { + frac_quot = pll_state->pll[12] << 8 | pll_state->pll[11]; + frac_rem = pll_state->pll[14] << 8 | pll_state->pll[13]; + frac_den = pll_state->pll[10] << 8 | pll_state->pll[9]; + } + + multiplier = (REG_FIELD_GET8(C10_PLL3_MULTIPLIERH_MASK, pll_state->pll[3]) << 8 | + pll_state->pll[2]) / 2 + 16; + + tx_clk_div = REG_FIELD_GET8(C10_PLL15_TXCLKDIV_MASK, pll_state->pll[15]); + + return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, (multiplier << 16) + frac_quot) + + DIV_ROUND_CLOSEST(refclk * frac_rem, frac_den), + 10 << (tx_clk_div + 16)); +} + +static void intel_program_port_clock_ctl(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + bool lane_reversal) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_dp *intel_dp; + bool ssc_enabled; + u32 val = 0; + + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL1(encoder->port), XELPDP_PORT_REVERSAL, + lane_reversal ? XELPDP_PORT_REVERSAL : 0); + + if (lane_reversal) + val |= XELPDP_LANE1_PHY_CLOCK_SELECT; + + val |= XELPDP_FORWARD_CLOCK_UNGATE; + val |= XELPDP_DDI_CLOCK_SELECT(XELPDP_DDI_CLOCK_SELECT_MAXPCLK); + + if (intel_crtc_has_dp_encoder(crtc_state)) { + intel_dp = enc_to_intel_dp(encoder); + ssc_enabled = intel_dp->dpcd[DP_MAX_DOWNSPREAD] & + DP_MAX_DOWNSPREAD_0_5; + + if (!intel_panel_use_ssc(i915)) + ssc_enabled = false; + + /* TODO: DP2.0 10G and 20G rates enable MPLLA*/ + val |= ssc_enabled ? XELPDP_SSC_ENABLE_PLLB : 0; + } + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + XELPDP_LANE1_PHY_CLOCK_SELECT | + XELPDP_FORWARD_CLOCK_UNGATE | + XELPDP_DDI_CLOCK_SELECT_MASK | + XELPDP_SSC_ENABLE_PLLB, val); +} + +static u32 intel_cx0_get_powerdown_update(u8 lane) +{ + if (lane & INTEL_CX0_LANE0) + return XELPDP_LANE0_POWERDOWN_UPDATE; + else if (lane & INTEL_CX0_LANE1) + return XELPDP_LANE1_POWERDOWN_UPDATE; + else + return XELPDP_LANE0_POWERDOWN_UPDATE | + XELPDP_LANE1_POWERDOWN_UPDATE; +} + +static u32 intel_cx0_get_powerdown_state(u8 lane, u8 state) +{ + if (lane & INTEL_CX0_LANE0) + return XELPDP_LANE0_POWERDOWN_NEW_STATE(state); + else if (lane & INTEL_CX0_LANE1) + return XELPDP_LANE1_POWERDOWN_NEW_STATE(state); + else + return XELPDP_LANE0_POWERDOWN_NEW_STATE(state) | + XELPDP_LANE1_POWERDOWN_NEW_STATE(state); +} + +static void intel_cx0_powerdown_change_sequence(struct drm_i915_private *i915, + enum port port, + u8 lane, u8 state) +{ + enum phy phy = intel_port_to_phy(i915, port); + + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), + XELPDP_LANE0_POWERDOWN_NEW_STATE_MASK | XELPDP_LANE1_POWERDOWN_NEW_STATE_MASK, + intel_cx0_get_powerdown_state(lane, state)); + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), + XELPDP_LANE0_POWERDOWN_UPDATE | XELPDP_LANE1_POWERDOWN_UPDATE, + intel_cx0_get_powerdown_update(lane)); + + /* Update Timeout Value */ + if (__intel_wait_for_register(&i915->uncore, XELPDP_PORT_BUF_CTL2(port), + intel_cx0_get_powerdown_update(lane), 0, + XELPDP_PORT_POWERDOWN_UPDATE_TIMEOUT_US, 0, NULL)) + drm_warn(&i915->drm, "PHY %c failed to bring out of Lane reset after %dus.\n", + phy_name(phy), XELPDP_PORT_RESET_START_TIMEOUT_US); +} + +static void intel_cx0_setup_powerdown(struct drm_i915_private *i915, enum port port) +{ + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), + XELPDP_POWER_STATE_READY_MASK, + XELPDP_POWER_STATE_READY(CX0_P2_STATE_READY)); + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL3(port), + XELPDP_POWER_STATE_ACTIVE_MASK | + XELPDP_PLL_LANE_STAGGERING_DELAY_MASK, + XELPDP_POWER_STATE_ACTIVE(CX0_P0_STATE_ACTIVE) | + XELPDP_PLL_LANE_STAGGERING_DELAY(0)); +} + +static u32 intel_cx0_get_pclk_refclk_request(u8 lane) +{ + if (lane & INTEL_CX0_LANE0) + return XELPDP_LANE0_PCLK_REFCLK_REQUEST; + else if (lane & INTEL_CX0_LANE1) + return XELPDP_LANE1_PCLK_REFCLK_REQUEST; + else + return XELPDP_LANE0_PCLK_REFCLK_REQUEST | + XELPDP_LANE1_PCLK_REFCLK_REQUEST; +} + +static u32 intel_cx0_get_pclk_refclk_ack(u8 lane) +{ + if (lane & INTEL_CX0_LANE0) + return XELPDP_LANE0_PCLK_REFCLK_ACK; + else if (lane & INTEL_CX0_LANE1) + return XELPDP_LANE1_PCLK_REFCLK_ACK; + else + return XELPDP_LANE0_PCLK_REFCLK_ACK | + XELPDP_LANE1_PCLK_REFCLK_ACK; +} + +/* FIXME: Some Type-C cases need not reset both the lanes. Handle those cases. */ +static void intel_cx0_phy_lane_reset(struct drm_i915_private *i915, enum port port, + bool lane_reversal) +{ + enum phy phy = intel_port_to_phy(i915, port); + u8 lane = lane_reversal ? INTEL_CX0_LANE1 : + INTEL_CX0_LANE0; + + if (__intel_wait_for_register(&i915->uncore, XELPDP_PORT_BUF_CTL1(port), + XELPDP_PORT_BUF_SOC_PHY_READY, + XELPDP_PORT_BUF_SOC_PHY_READY, + XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US, 0, NULL)) + drm_warn(&i915->drm, "PHY %c failed to bring out of SOC reset after %dus.\n", + phy_name(phy), XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US); + + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), + XELPDP_LANE0_PIPE_RESET | XELPDP_LANE1_PIPE_RESET, + XELPDP_LANE0_PIPE_RESET | XELPDP_LANE1_PIPE_RESET); + + if (__intel_wait_for_register(&i915->uncore, XELPDP_PORT_BUF_CTL2(port), + XELPDP_LANE0_PHY_CURRENT_STATUS | XELPDP_LANE1_PHY_CURRENT_STATUS, + XELPDP_LANE0_PHY_CURRENT_STATUS | XELPDP_LANE1_PHY_CURRENT_STATUS, + XELPDP_PORT_RESET_START_TIMEOUT_US, 0, NULL)) + drm_warn(&i915->drm, "PHY %c failed to bring out of Lane reset after %dus.\n", + phy_name(phy), XELPDP_PORT_RESET_START_TIMEOUT_US); + + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(port), + intel_cx0_get_pclk_refclk_request(INTEL_CX0_BOTH_LANES), + intel_cx0_get_pclk_refclk_request(lane)); + + if (__intel_wait_for_register(&i915->uncore, XELPDP_PORT_CLOCK_CTL(port), + intel_cx0_get_pclk_refclk_ack(INTEL_CX0_BOTH_LANES), + intel_cx0_get_pclk_refclk_ack(lane), + XELPDP_REFCLK_ENABLE_TIMEOUT_US, 0, NULL)) + drm_warn(&i915->drm, "PHY %c failed to request refclk after %dus.\n", + phy_name(phy), XELPDP_REFCLK_ENABLE_TIMEOUT_US); + + intel_cx0_powerdown_change_sequence(i915, port, INTEL_CX0_BOTH_LANES, + CX0_P2_STATE_RESET); + intel_cx0_setup_powerdown(i915, port); + + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), + XELPDP_LANE0_PIPE_RESET | XELPDP_LANE1_PIPE_RESET, 0); + + if (intel_de_wait_for_clear(i915, XELPDP_PORT_BUF_CTL2(port), + XELPDP_LANE0_PHY_CURRENT_STATUS | + XELPDP_LANE1_PHY_CURRENT_STATUS, + XELPDP_PORT_RESET_END_TIMEOUT)) + drm_warn(&i915->drm, "PHY %c failed to bring out of Lane reset after %dms.\n", + phy_name(phy), XELPDP_PORT_RESET_END_TIMEOUT); +} + +static void intel_c10_program_phy_lane(struct drm_i915_private *i915, + enum port port, int lane_count, + bool lane_reversal) +{ + u8 l0t1, l0t2, l1t1, l1t2; + + intel_cx0_rmw(i915, port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CONTROL(1), + C10_VDR_CTRL_MSGBUS_ACCESS, C10_VDR_CTRL_MSGBUS_ACCESS, + MB_WRITE_COMMITTED); + + l0t1 = intel_cx0_read(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(1, 2)); + l0t2 = intel_cx0_read(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(2, 2)); + l1t1 = intel_cx0_read(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(1, 2)); + l1t2 = intel_cx0_read(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(2, 2)); + + if (lane_reversal) { + switch (lane_count) { + case 1: + /* Disable MLs 1(lane0), 2(lane0), 3(lane1) */ + intel_cx0_write(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(1, 2), + l1t1 | CONTROL2_DISABLE_SINGLE_TX, + MB_WRITE_COMMITTED); + fallthrough; + case 2: + /* Disable MLs 1(lane0), 2(lane0) */ + intel_cx0_write(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(2, 2), + l0t2 | CONTROL2_DISABLE_SINGLE_TX, + MB_WRITE_COMMITTED); + fallthrough; + case 3: + /* Disable MLs 1(lane0) */ + intel_cx0_write(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(1, 2), + l0t1 | CONTROL2_DISABLE_SINGLE_TX, + MB_WRITE_COMMITTED); + break; + } + } else { + switch (lane_count) { + case 1: + /* Disable MLs 2(lane0), 3(lane1), 4(lane1) */ + intel_cx0_write(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(2, 2), + l0t2 | CONTROL2_DISABLE_SINGLE_TX, + MB_WRITE_COMMITTED); + fallthrough; + case 2: + /* Disable MLs 3(lane1), 4(lane1) */ + intel_cx0_write(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(1, 2), + l1t1 | CONTROL2_DISABLE_SINGLE_TX, + MB_WRITE_COMMITTED); + fallthrough; + case 3: + /* Disable MLs 4(lane1) */ + intel_cx0_write(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(2, 2), + l1t2 | CONTROL2_DISABLE_SINGLE_TX, + MB_WRITE_COMMITTED); + break; + } + } + + if (intel_is_c10phy(i915, intel_port_to_phy(i915, port))) { + intel_cx0_rmw(i915, port, INTEL_CX0_LANE1, PHY_C10_VDR_CONTROL(1), + C10_VDR_CTRL_UPDATE_CFG | C10_VDR_CTRL_MSGBUS_ACCESS, + C10_VDR_CTRL_UPDATE_CFG, MB_WRITE_COMMITTED); + intel_cx0_rmw(i915, port, INTEL_CX0_LANE0, PHY_C10_VDR_CONTROL(1), + C10_VDR_CTRL_UPDATE_CFG | C10_VDR_CTRL_MSGBUS_ACCESS, + C10_VDR_CTRL_MASTER_LANE | C10_VDR_CTRL_UPDATE_CFG, MB_WRITE_COMMITTED); + } +} + +static u32 intel_cx0_get_pclk_pll_request(u8 lane) +{ + if (lane & INTEL_CX0_LANE0) + return XELPDP_LANE0_PCLK_PLL_REQUEST; + else if (lane & INTEL_CX0_LANE1) + return XELPDP_LANE1_PCLK_PLL_REQUEST; + else + return XELPDP_LANE0_PCLK_PLL_REQUEST | + XELPDP_LANE1_PCLK_PLL_REQUEST; +} + +static u32 intel_cx0_get_pclk_pll_ack(u8 lane) +{ + if (lane & INTEL_CX0_LANE0) + return XELPDP_LANE0_PCLK_PLL_ACK; + else if (lane & INTEL_CX0_LANE1) + return XELPDP_LANE1_PCLK_PLL_ACK; + else + return XELPDP_LANE0_PCLK_PLL_ACK | + XELPDP_LANE1_PCLK_PLL_ACK; +} + +static void intel_c10pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL; + u8 maxpclk_lane = lane_reversal ? INTEL_CX0_LANE1 : + INTEL_CX0_LANE0; + + /* + * 1. Program PORT_CLOCK_CTL REGISTER to configure + * clock muxes, gating and SSC + */ + intel_program_port_clock_ctl(encoder, crtc_state, lane_reversal); + + /* 2. Bring PHY out of reset. */ + intel_cx0_phy_lane_reset(i915, encoder->port, lane_reversal); + + /* + * 3. Change Phy power state to Ready. + * TODO: For DP alt mode use only one lane. + */ + intel_cx0_powerdown_change_sequence(i915, encoder->port, INTEL_CX0_BOTH_LANES, + CX0_P2_STATE_READY); + + /* 4. Program PHY internal PLL internal registers. */ + intel_c10_pll_program(i915, crtc_state, encoder); + + /* + * 5. Program the enabled and disabled owned PHY lane + * transmitters over message bus + */ + intel_c10_program_phy_lane(i915, encoder->port, crtc_state->lane_count, lane_reversal); + + /* + * 6. Follow the Display Voltage Frequency Switching - Sequence + * Before Frequency Change. We handle this step in bxt_set_cdclk(). + */ + + /* + * 7. Program DDI_CLK_VALFREQ to match intended DDI + * clock frequency. + */ + intel_de_write(i915, DDI_CLK_VALFREQ(encoder->port), + crtc_state->port_clock); + /* + * 8. Set PORT_CLOCK_CTL register PCLK PLL Request + * LN to "1" to enable PLL. + */ + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + intel_cx0_get_pclk_pll_request(INTEL_CX0_BOTH_LANES), + intel_cx0_get_pclk_pll_request(maxpclk_lane)); + + /* 9. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN == "1". */ + if (__intel_wait_for_register(&i915->uncore, XELPDP_PORT_CLOCK_CTL(encoder->port), + intel_cx0_get_pclk_pll_ack(INTEL_CX0_BOTH_LANES), + intel_cx0_get_pclk_pll_ack(maxpclk_lane), + XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US, 0, NULL)) + drm_warn(&i915->drm, "Port %c PLL not locked after %dus.\n", + phy_name(phy), XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US); + + /* + * 10. Follow the Display Voltage Frequency Switching Sequence After + * Frequency Change. We handle this step in bxt_set_cdclk(). + */ +} + +void intel_cx0pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); + intel_c10pll_enable(encoder, crtc_state); +} + +static void intel_c10pll_disable(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + /* 1. Change owned PHY lane power to Disable state. */ + intel_cx0_powerdown_change_sequence(i915, encoder->port, INTEL_CX0_BOTH_LANES, + CX0_P2PG_STATE_DISABLE); + + /* + * 2. Follow the Display Voltage Frequency Switching Sequence Before + * Frequency Change. We handle this step in bxt_set_cdclk(). + */ + + /* + * 3. Set PORT_CLOCK_CTL register PCLK PLL Request LN + * to "0" to disable PLL. + */ + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + intel_cx0_get_pclk_pll_request(INTEL_CX0_BOTH_LANES) | + intel_cx0_get_pclk_refclk_request(INTEL_CX0_BOTH_LANES), 0); + + /* 4. Program DDI_CLK_VALFREQ to 0. */ + intel_de_write(i915, DDI_CLK_VALFREQ(encoder->port), 0); + + /* + * 5. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN == "0". + */ + if (__intel_wait_for_register(&i915->uncore, XELPDP_PORT_CLOCK_CTL(encoder->port), + intel_cx0_get_pclk_pll_ack(INTEL_CX0_BOTH_LANES) | + intel_cx0_get_pclk_refclk_ack(INTEL_CX0_BOTH_LANES), 0, + XELPDP_PCLK_PLL_DISABLE_TIMEOUT_US, 0, NULL)) + drm_warn(&i915->drm, "Port %c PLL not unlocked after %dus.\n", + phy_name(phy), XELPDP_PCLK_PLL_DISABLE_TIMEOUT_US); + + /* + * 6. Follow the Display Voltage Frequency Switching Sequence After + * Frequency Change. We handle this step in bxt_set_cdclk(). + */ + + /* 7. Program PORT_CLOCK_CTL register to disable and gate clocks. */ + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + XELPDP_DDI_CLOCK_SELECT_MASK | + XELPDP_FORWARD_CLOCK_UNGATE, 0); +} + +void intel_cx0pll_disable(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); + intel_c10pll_disable(encoder); +} + +void intel_c10mpllb_state_verify(struct intel_atomic_state *state, + struct intel_crtc_state *new_crtc_state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_c10mpllb_state mpllb_hw_state = { 0 }; + struct intel_c10mpllb_state *mpllb_sw_state = &new_crtc_state->c10mpllb_state; + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + struct intel_encoder *encoder; + struct intel_dp *intel_dp; + enum phy phy; + int i; + bool use_ssc = false; + + if (DISPLAY_VER(i915) < 14) + return; + + if (!new_crtc_state->hw.active) + return; + + encoder = intel_get_crtc_new_encoder(state, new_crtc_state); + phy = intel_port_to_phy(i915, encoder->port); + + if (intel_crtc_has_dp_encoder(new_crtc_state)) { + intel_dp = enc_to_intel_dp(encoder); + use_ssc = (intel_dp->dpcd[DP_MAX_DOWNSPREAD] & + DP_MAX_DOWNSPREAD_0_5); + + if (!intel_panel_use_ssc(i915)) + use_ssc = false; + } + + if (!intel_is_c10phy(i915, phy)) + return; + + intel_c10mpllb_readout_hw_state(encoder, &mpllb_hw_state); + + for (i = 0; i < ARRAY_SIZE(mpllb_sw_state->pll); i++) { + u8 expected; + + if (!use_ssc && i > 3 && i < 9) + expected = 0; + else + expected = mpllb_sw_state->pll[i]; + + I915_STATE_WARN(mpllb_hw_state.pll[i] != expected, + "[CRTC:%d:%s] mismatch in C10MPLLB: Register[%d] (expected 0x%02x, found 0x%02x)", + crtc->base.base.id, crtc->base.name, + i, expected, mpllb_hw_state.pll[i]); + } +} diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h new file mode 100644 index 000000000000..8cf340509097 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#ifndef __INTEL_CX0_PHY_H__ +#define __INTEL_CX0_PHY_H__ + +#include +#include +#include + +#include "i915_drv.h" +#include "intel_display_types.h" + +struct drm_i915_private; +struct intel_encoder; +struct intel_crtc_state; +enum phy; + +#define INTEL_CX0_LANE0 0x1 +#define INTEL_CX0_LANE1 0x2 +#define INTEL_CX0_BOTH_LANES 0x3 + +#define MB_WRITE_COMMITTED 1 +#define MB_WRITE_UNCOMMITTED 0 + +bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy); +void intel_cx0pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); +void intel_cx0pll_disable(struct intel_encoder *encoder); +void intel_c10mpllb_readout_hw_state(struct intel_encoder *encoder, + struct intel_c10mpllb_state *pll_state); +int intel_cx0mpllb_calc_state(struct intel_crtc_state *crtc_state, + struct intel_encoder *encoder); +void intel_c10mpllb_dump_hw_state(struct drm_i915_private *dev_priv, + const struct intel_c10mpllb_state *hw_state); +int intel_c10mpllb_calc_port_clock(struct intel_encoder *encoder, + const struct intel_c10mpllb_state *pll_state); +void intel_c10mpllb_state_verify(struct intel_atomic_state *state, + struct intel_crtc_state *new_crtc_state); + +#endif /* __INTEL_CX0_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h index d6b3709d3762..ef629f8b14cf 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h @@ -133,4 +133,38 @@ #define XELPDP_SSC_ENABLE_PLLA REG_BIT(1) #define XELPDP_SSC_ENABLE_PLLB REG_BIT(0) +/* C10 Vendor Registers */ +#define PHY_C10_VDR_PLL(idx) (0xC00 + (idx)) +#define C10_PLL0_FRACEN REG_BIT8(4) +#define C10_PLL3_MULTIPLIERH_MASK REG_GENMASK8(3, 0) +#define C10_PLL15_TXCLKDIV_MASK REG_GENMASK8(2, 0) + +#define PHY_C10_VDR_CMN(idx) (0xC20 + (idx)) +#define C10_CMN0_DP_VAL 0x21 +#define C10_CMN3_TXVBOOST_MASK REG_GENMASK8(7, 5) +#define C10_CMN3_TXVBOOST(val) REG_FIELD_PREP8(C10_CMN3_TXVBOOST_MASK, val) + +#define PHY_C10_VDR_TX(idx) (0xC30 + (idx)) +#define C10_TX0_VAL 0x10 + +#define PHY_C10_VDR_CONTROL(idx) (0xC70 + (idx) - 1) +#define C10_VDR_CTRL_MSGBUS_ACCESS REG_BIT8(2) +#define C10_VDR_CTRL_MASTER_LANE REG_BIT8(1) +#define C10_VDR_CTRL_UPDATE_CFG REG_BIT8(0) + +#define PHY_C10_VDR_CUSTOM_WIDTH 0xD02 + +#define CX0_P0_STATE_ACTIVE 0x0 +#define CX0_P2_STATE_READY 0x2 +#define CX0_P2PG_STATE_DISABLE 0x9 +#define CX0_P4PG_STATE_DISABLE 0xC +#define CX0_P2_STATE_RESET 0x2 + +/* PHY_C10_VDR_PLL0 */ +#define PLL_C10_MPLL_SSC_EN REG_BIT8(0) + +/* PIPE SPEC Defined Registers */ +#define PHY_CX0_TX_CONTROL(tx, control) (0x400 + ((tx) - 1) * 0x200 + (control)) +#define CONTROL2_DISABLE_SINGLE_TX REG_BIT(6) + #endif /* __INTEL_CX0_PHY_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 1f5a471a0adf..099776b62052 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -39,6 +39,7 @@ #include "intel_combo_phy_regs.h" #include "intel_connector.h" #include "intel_crtc.h" +#include "intel_cx0_phy.h" #include "intel_ddi.h" #include "intel_ddi_buf_trans.h" #include "intel_de.h" @@ -3520,6 +3521,21 @@ void intel_ddi_get_clock(struct intel_encoder *encoder, &crtc_state->dpll_hw_state); } +static void mtl_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); + + intel_c10mpllb_readout_hw_state(encoder, &crtc_state->c10mpllb_state); + intel_c10mpllb_dump_hw_state(i915, &crtc_state->c10mpllb_state); + crtc_state->port_clock = intel_c10mpllb_calc_port_clock(encoder, &crtc_state->c10mpllb_state); + + intel_ddi_get_config(encoder, crtc_state); +} + static void dg2_ddi_get_config(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state) { @@ -4394,7 +4410,11 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->cloneable = 0; encoder->pipe_mask = ~0; - if (IS_DG2(dev_priv)) { + if (DISPLAY_VER(dev_priv) >= 14) { + encoder->enable_clock = intel_cx0pll_enable; + encoder->disable_clock = intel_cx0pll_disable; + encoder->get_config = mtl_ddi_get_config; + } else if (IS_DG2(dev_priv)) { encoder->enable_clock = intel_mpllb_enable; encoder->disable_clock = intel_mpllb_disable; encoder->get_config = dg2_ddi_get_config; diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b5618de88f03..655e1c86a1eb 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -47,6 +47,7 @@ #include "display/intel_audio.h" #include "display/intel_crt.h" +#include "display/intel_cx0_phy.h" #include "display/intel_ddi.h" #include "display/intel_display_debugfs.h" #include "display/intel_display_power.h" diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 1a23ecd4623a..40f157208a81 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -1635,7 +1635,8 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv, return; /* 2. Initialize all combo phys */ - intel_combo_phy_init(dev_priv); + if (DISPLAY_VER(dev_priv) < 14) + intel_combo_phy_init(dev_priv); /* * 3. Enable Power Well 1 (PG1). diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index 8710dd41ffd4..5ebdaa8fce91 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -980,7 +980,7 @@ void gen9_disable_dc_states(struct drm_i915_private *dev_priv) if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) bxt_verify_ddi_phy_power_wells(dev_priv); - if (DISPLAY_VER(dev_priv) >= 11) + if (DISPLAY_VER(dev_priv) >= 11 && DISPLAY_VER(dev_priv) < 14) /* * DMC retains HW context only for port A, the other combo * PHY's HW context for port B is lost after DC transitions, diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 32e8b2fc3cc6..fdd65781ae40 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -978,6 +978,11 @@ struct intel_link_m_n { u32 link_n; }; +struct intel_c10mpllb_state { + u32 clock; /* in KHz */ + u8 pll[20]; +}; + struct intel_crtc_state { /* * uapi (drm) state. This is the software state shown to userspace. @@ -1121,6 +1126,7 @@ struct intel_crtc_state { union { struct intel_dpll_hw_state dpll_hw_state; struct intel_mpllb_state mpllb_state; + struct intel_c10mpllb_state c10mpllb_state; }; /* diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index c236aafe9be0..cd6d75a4fdd4 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -8,6 +8,7 @@ #include "i915_reg.h" #include "intel_crtc.h" +#include "intel_cx0_phy.h" #include "intel_de.h" #include "intel_display.h" #include "intel_display_types.h" @@ -995,6 +996,17 @@ static int dg2_crtc_compute_clock(struct intel_atomic_state *state, return 0; } +static int mtl_crtc_compute_clock(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + struct intel_encoder *encoder = + intel_get_crtc_new_encoder(state, crtc_state); + + return intel_cx0mpllb_calc_state(crtc_state, encoder); +} + static bool ilk_needs_fb_cb_tune(const struct dpll *dpll, int factor) { return dpll->m < factor * dpll->n; @@ -1423,6 +1435,10 @@ static int i8xx_crtc_compute_clock(struct intel_atomic_state *state, return 0; } +static const struct intel_dpll_funcs mtl_dpll_funcs = { + .crtc_compute_clock = mtl_crtc_compute_clock, +}; + static const struct intel_dpll_funcs dg2_dpll_funcs = { .crtc_compute_clock = dg2_crtc_compute_clock, }; @@ -1517,7 +1533,11 @@ int intel_dpll_crtc_get_shared_dpll(struct intel_atomic_state *state, void intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv) { - if (IS_DG2(dev_priv)) + if (DISPLAY_VER(dev_priv) >= 14) + dev_priv->display.funcs.dpll = &mtl_dpll_funcs; + else if (DISPLAY_VER(dev_priv) >= 14) + dev_priv->display.funcs.dpll = &mtl_dpll_funcs; + else if (IS_DG2(dev_priv)) dev_priv->display.funcs.dpll = &dg2_dpll_funcs; else if (DISPLAY_VER(dev_priv) >= 9 || HAS_DDI(dev_priv)) dev_priv->display.funcs.dpll = &hsw_dpll_funcs; diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 1974eb580ed1..a90d44f59ab1 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -4163,7 +4163,7 @@ void intel_shared_dpll_init(struct drm_i915_private *dev_priv) mutex_init(&dev_priv->display.dpll.lock); - if (IS_DG2(dev_priv)) + if (DISPLAY_VER(dev_priv) >= 14 || IS_DG2(dev_priv)) /* No shared DPLLs on DG2; port PLLs are part of the PHY */ dpll_mgr = NULL; else if (IS_ALDERLAKE_P(dev_priv)) diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c index 842d70f0dfd2..ec504470c2f0 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c @@ -11,6 +11,7 @@ #include "intel_atomic.h" #include "intel_crtc.h" #include "intel_crtc_state_dump.h" +#include "intel_cx0_phy.h" #include "intel_display.h" #include "intel_display_types.h" #include "intel_fdi.h" @@ -236,6 +237,7 @@ void intel_modeset_verify_crtc(struct intel_crtc *crtc, verify_crtc_state(crtc, old_crtc_state, new_crtc_state); intel_shared_dpll_state_verify(crtc, old_crtc_state, new_crtc_state); intel_mpllb_state_verify(state, new_crtc_state); + intel_c10mpllb_state_verify(state, new_crtc_state); } void intel_modeset_verify_disabled(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8b2cf980f323..8d4b626874db 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2067,6 +2067,11 @@ #define TRANS_PUSH_EN REG_BIT(31) #define TRANS_PUSH_SEND REG_BIT(30) +/* DDI Buffer Control */ +#define _DDI_CLK_VALFREQ_A 0x64030 +#define _DDI_CLK_VALFREQ_B 0x64130 +#define DDI_CLK_VALFREQ(port) _MMIO_PORT(port, _DDI_CLK_VALFREQ_A, _DDI_CLK_VALFREQ_B) + /* * HSW+ eDP PSR registers * diff --git a/drivers/gpu/drm/i915/i915_reg_defs.h b/drivers/gpu/drm/i915/i915_reg_defs.h index be43580a6979..d00ceb6c7666 100644 --- a/drivers/gpu/drm/i915/i915_reg_defs.h +++ b/drivers/gpu/drm/i915/i915_reg_defs.h @@ -22,6 +22,19 @@ BUILD_BUG_ON_ZERO(__is_constexpr(__n) && \ ((__n) < 0 || (__n) > 31)))) +/** + * REG_BIT8() - Prepare a u8 bit value + * @__n: 0-based bit number + * + * Local wrapper for BIT() to force u8, with compile time checks. + * + * @return: Value with bit @__n set. + */ +#define REG_BIT8(__n) \ + ((u8)(BIT(__n) + \ + BUILD_BUG_ON_ZERO(__is_constexpr(__n) && \ + ((__n) < 0 || (__n) > 7)))) + /** * REG_GENMASK() - Prepare a continuous u32 bitmask * @__high: 0-based high bit @@ -52,6 +65,21 @@ __is_constexpr(__low) && \ ((__low) < 0 || (__high) > 63 || (__low) > (__high))))) +/** + * REG_GENMASK8() - Prepare a continuous u8 bitmask + * @__high: 0-based high bit + * @__low: 0-based low bit + * + * Local wrapper for GENMASK() to force u8, with compile time checks. + * + * @return: Continuous bitmask from @__high to @__low, inclusive. + */ +#define REG_GENMASK8(__high, __low) \ + ((u8)(GENMASK(__high, __low) + \ + BUILD_BUG_ON_ZERO(__is_constexpr(__high) && \ + __is_constexpr(__low) && \ + ((__low) < 0 || (__high) > 7 || (__low) > (__high))))) + /* * Local integer constant expression version of is_power_of_2(). */ @@ -74,6 +102,23 @@ BUILD_BUG_ON_ZERO(!IS_POWER_OF_2((__mask) + (1ULL << __bf_shf(__mask)))) + \ BUILD_BUG_ON_ZERO(__builtin_choose_expr(__is_constexpr(__val), (~((__mask) >> __bf_shf(__mask)) & (__val)), 0)))) +/** + * REG_FIELD_PREP8() - Prepare a u8 bitfield value + * @__mask: shifted mask defining the field's length and position + * @__val: value to put in the field + * + * Local copy of FIELD_PREP8() to generate an integer constant expression, force + * u8 and for consistency with REG_FIELD_GET8(), REG_BIT8() and REG_GENMASK8(). + * + * @return: @__val masked and shifted into the field defined by @__mask. + */ +#define REG_FIELD_PREP8(__mask, __val) \ + ((u8)((((typeof(__mask))(__val) << __bf_shf(__mask)) & (__mask)) + \ + BUILD_BUG_ON_ZERO(!__is_constexpr(__mask)) + \ + BUILD_BUG_ON_ZERO((__mask) == 0 || (__mask) > U8_MAX) + \ + BUILD_BUG_ON_ZERO(!IS_POWER_OF_2((__mask) + (1ULL << __bf_shf(__mask)))) + \ + BUILD_BUG_ON_ZERO(__builtin_choose_expr(__is_constexpr(__val), (~((__mask) >> __bf_shf(__mask)) & (__val)), 0)))) + /** * REG_FIELD_GET() - Extract a u32 bitfield value * @__mask: shifted mask defining the field's length and position @@ -126,6 +171,18 @@ */ #define _PICK(__index, ...) (((const u32 []){ __VA_ARGS__ })[__index]) +/** + * REG_FIELD_GET8() - Extract a u8 bitfield value + * @__mask: shifted mask defining the field's length and position + * @__val: value to extract the bitfield value from + * + * Local wrapper for FIELD_GET() to force u8 and for consistency with + * REG_FIELD_PREP(), REG_BIT() and REG_GENMASK(). + * + * @return: Masked and shifted value of the field defined by @__mask in @__val. + */ +#define REG_FIELD_GET8(__mask, __val) ((u8)FIELD_GET(__mask, __val)) + typedef struct { u32 reg; } i915_reg_t; From patchwork Thu Jan 5 12:54:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089814 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 44F3BC3DA7A for ; Thu, 5 Jan 2023 12:59:50 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 83F6210E718; Thu, 5 Jan 2023 12:59:49 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 3620310E717 for ; Thu, 5 Jan 2023 12:59:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923586; x=1704459586; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=guaMD5VbZqH8TaVYtVZa7DXloikDsa1PJsCi4RgmvfQ=; b=LSjwC0NkQ3o9msblRkv2mYiRh4N91TQTo5dTR4fJGSBhGg7+cdDJdXUM czczGCHEAnxdTwXs4HsPydLmU9olih9tVGhQYLu4e82VsyChjyaWmTeK9 l5KsXts1r4rEBELwI+CHffpXHdTuDsw7zvzGc90/HrtsSSjJp3EbDRbJc Ct4EaSlsz/OMJbPIQItbgumICnirvDPFSZwkZy76ZAdpuuqk+TyRa/BG4 61NqExT2nqorpTeXX/2VhKfefZyBm1eV4wXINzXJNZOqC9D66x9ZtqkiV g2o/Fv3xb8is2lf6Cm2M0T07vAGtrwJiI5bhDp3FNQYrTvTa+A9TWQm/1 Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697735" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697735" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 04:59:46 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829540956" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829540956" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 04:59:43 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:30 +0200 Message-Id: <20230105125446.960504-6-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 05/21] drm/i915/mtl: Add C10 phy programming for HDMI 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Radhakrishna Sripada Like DG2, we still don't have a proper algorithm that can be used for calculating PHY settings, but we do have tables of register values for a handful of the more common link rates. Some support is better than none, so let's go ahead and add/use these tables when we can, and also add some logic to hdmi_port_clock_valid() to filter the modelist to just the modes we can actually support with these link rates. Hopefully we'll have a proper / non-encumbered algorithm to calculate these registers by the time we upstream and we'll be able to replace this patch with something more general purpose. Bspec: 64568 v2: Rebasing with Clint's HDMI C10 PLL tables (Mika) v3: Add missing use_hdmi checks from Clint's HDMI implementation changes (Ankit) Cc: Imre Deak Cc: Uma Shankar Signed-off-by: Radhakrishna Sripada Signed-off-by: Clint Taylor Signed-off-by: Mika Kahola Signed-off-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-6-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 584 +++++++++++++++++- drivers/gpu/drm/i915/display/intel_cx0_phy.h | 1 + .../gpu/drm/i915/display/intel_cx0_phy_regs.h | 2 + drivers/gpu/drm/i915/display/intel_hdmi.c | 5 +- 4 files changed, 581 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 1ceebbc6b650..746c905538a7 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -484,6 +484,546 @@ static const struct intel_c10mpllb_state * const mtl_c10_edp_tables[] = { NULL, }; +/* + * HDMI link rates with 38.4 MHz reference clock. + */ + +static const struct intel_c10mpllb_state mtl_c10_hdmi_25_2 = { + .clock = 25200, + .pll[0] = 0x4, + .pll[1] = 0, + .pll[2] = 0xB2, + .pll[3] = 0, + .pll[4] = 0, + .pll[5] = 0, + .pll[6] = 0, + .pll[7] = 0, + .pll[8] = 0x20, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0xD, + .pll[16] = 0x6, + .pll[17] = 0x8F, + .pll[18] = 0x84, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_27_0 = { + .clock = 27000, + .pll[0] = 0x34, + .pll[1] = 0, + .pll[2] = 0xC0, + .pll[3] = 0, + .pll[4] = 0, + .pll[5] = 0, + .pll[6] = 0, + .pll[7] = 0, + .pll[8] = 0x20, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0x80, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0xD, + .pll[16] = 0x6, + .pll[17] = 0xCF, + .pll[18] = 0x84, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_74_25 = { + .clock = 74250, + .pll[0] = 0xF4, + .pll[1] = 0, + .pll[2] = 0x7A, + .pll[3] = 0, + .pll[4] = 0, + .pll[5] = 0, + .pll[6] = 0, + .pll[7] = 0, + .pll[8] = 0x20, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0x58, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0xB, + .pll[16] = 0x6, + .pll[17] = 0xF, + .pll[18] = 0x85, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_148_5 = { + .clock = 148500, + .pll[0] = 0xF4, + .pll[1] = 0, + .pll[2] = 0x7A, + .pll[3] = 0, + .pll[4] = 0, + .pll[5] = 0, + .pll[6] = 0, + .pll[7] = 0, + .pll[8] = 0x20, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0x58, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0xA, + .pll[16] = 0x6, + .pll[17] = 0xF, + .pll[18] = 0x85, + .pll[19] = 0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_594 = { + .clock = 594000, + .pll[0] = 0xF4, + .pll[1] = 0, + .pll[2] = 0x7A, + .pll[3] = 0, + .pll[4] = 0, + .pll[5] = 0, + .pll[6] = 0, + .pll[7] = 0, + .pll[8] = 0x20, + .pll[9] = 0x1, + .pll[10] = 0, + .pll[11] = 0, + .pll[12] = 0x58, + .pll[13] = 0, + .pll[14] = 0, + .pll[15] = 0x8, + .pll[16] = 0x6, + .pll[17] = 0xF, + .pll[18] = 0x85, + .pll[19] = 0x23, +}; + +/* Precomputed C10 HDMI PLL tables */ +static const struct intel_c10mpllb_state mtl_c10_hdmi_25175 = { + .clock = 25175, + .pll[0]=0x34, + .pll[1]=0x00, + .pll[2]=0xB0, + .pll[3]=0x00, + .pll[4]=0x00, + .pll[5]=0x00, + .pll[6]=0x00, + .pll[7]=0x00, + .pll[8]=0x20, + .pll[9]=0xFF, + .pll[10]=0xFF, + .pll[11]=0x55, + .pll[12]=0xE5, + .pll[13]=0x55, + .pll[14]=0x55, + .pll[15]=0x0D, + .pll[16]=0x09, + .pll[17]=0x8F, + .pll[18]=0x84, + .pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_25200 = { + .clock = 25200, + .pll[0]=0x04, .pll[1]=0x00, .pll[2]=0xB2, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x00,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0D,.pll[16]=0x09,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_27027 = { + .clock = 27027, + .pll[0]=0x34, .pll[1]=0x00, .pll[2]=0xC0, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0xCC,.pll[12]=0x9C,.pll[13]=0xCB,.pll[14]=0xCC, + .pll[15]=0x0D,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_28320 = { + .clock = 28320, + .pll[0]=0x04, .pll[1]=0x00, .pll[2]=0xCC, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x00,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0D,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_30240 = { + .clock = 30240, + .pll[0]=0x04, .pll[1]=0x00, .pll[2]=0xDC, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x00,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0D,.pll[16]=0x08,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_31500 = { + .clock = 31500, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x62, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0xA0,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0C,.pll[16]=0x09,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_36000 = { + .clock = 36000, + .pll[0]=0xC4, .pll[1]=0x00, .pll[2]=0x76, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x00,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0C,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_40000 = { + .clock = 40000, + .pll[0]=0xB4, .pll[1]=0x00, .pll[2]=0x86, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x55,.pll[12]=0x55,.pll[13]=0x55,.pll[14]=0x55, + .pll[15]=0x0C,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_49500 = { + .clock = 49500, + .pll[0]=0x74, .pll[1]=0x00, .pll[2]=0xAE, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x20,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0C,.pll[16]=0x08,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_50000 = { + .clock = 50000, + .pll[0]=0x74, .pll[1]=0x00, .pll[2]=0xB0, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0xAA,.pll[12]=0x2A,.pll[13]=0xA9,.pll[14]=0xAA, + .pll[15]=0x0C,.pll[16]=0x08,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_57284 = { + .clock = 57284, + .pll[0]=0x34, .pll[1]=0x00, .pll[2]=0xCE, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x77,.pll[12]=0x57,.pll[13]=0x77,.pll[14]=0x77, + .pll[15]=0x0C,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_58000 = { + .clock = 58000, + .pll[0]=0x34, .pll[1]=0x00, .pll[2]=0xD0, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x55,.pll[12]=0xD5,.pll[13]=0x55,.pll[14]=0x55, + .pll[15]=0x0C,.pll[16]=0x08,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_65000 = { + .clock = 65000, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x66, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x55,.pll[12]=0xB5,.pll[13]=0x55,.pll[14]=0x55, + .pll[15]=0x0B,.pll[16]=0x09,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_71000 = { + .clock = 71000, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x72, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x55,.pll[12]=0xF5,.pll[13]=0x55,.pll[14]=0x55, + .pll[15]=0x0B,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_74176 = { + .clock = 74176, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x7A, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x44,.pll[12]=0x44,.pll[13]=0x44,.pll[14]=0x44, + .pll[15]=0x0B,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_75000 = { + .clock = 75000, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x7C, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x20,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0B,.pll[16]=0x08,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_78750 = { + .clock = 78750, + .pll[0]=0xB4, .pll[1]=0x00, .pll[2]=0x84, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x08,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0B,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_85500 = { + .clock = 85500, + .pll[0]=0xB4, .pll[1]=0x00, .pll[2]=0x92, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x10,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0B,.pll[16]=0x08,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_88750 = { + .clock = 88750, + .pll[0]=0x74, .pll[1]=0x00, .pll[2]=0x98, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0xAA,.pll[12]=0x72,.pll[13]=0xA9,.pll[14]=0xAA, + .pll[15]=0x0B,.pll[16]=0x09,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_106500 = { + .clock = 106500, + .pll[0]=0x34, .pll[1]=0x00, .pll[2]=0xBC, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0xF0,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0B,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_108000 = { + .clock = 108000, + .pll[0]=0x34, .pll[1]=0x00, .pll[2]=0xC0, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x80,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0B,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_115500 = { + .clock = 115500, + .pll[0]=0x34, .pll[1]=0x00, .pll[2]=0xD0, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x50,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0B,.pll[16]=0x08,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_119000 = { + .clock = 119000, + .pll[0]=0x34, .pll[1]=0x00, .pll[2]=0xD6, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x55,.pll[12]=0xF5,.pll[13]=0x55,.pll[14]=0x55, + .pll[15]=0x0B,.pll[16]=0x08,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_135000 = { + .clock = 135000, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x6C, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x50,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0A,.pll[16]=0x09,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_138500 = { + .clock = 138500, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x70, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0xAA,.pll[12]=0x22,.pll[13]=0xA9,.pll[14]=0xAA, + .pll[15]=0x0A,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_147160 = { + .clock = 147160, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x78, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x55,.pll[12]=0xA5,.pll[13]=0x55,.pll[14]=0x55, + .pll[15]=0x0A,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_148352 = { + .clock = 148352, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x7A, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x44,.pll[12]=0x44,.pll[13]=0x44,.pll[14]=0x44, + .pll[15]=0x0A,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_154000 = { + .clock = 154000, + .pll[0]=0xB4, .pll[1]=0x00, .pll[2]=0x80, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x55,.pll[12]=0x35,.pll[13]=0x55,.pll[14]=0x55, + .pll[15]=0x0A,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_162000 = { + .clock = 162000, + .pll[0]=0xB4, .pll[1]=0x00, .pll[2]=0x88, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x60,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0A,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_167000 = { + .clock = 167000, + .pll[0]=0xB4, .pll[1]=0x00, .pll[2]=0x8C, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0xAA,.pll[12]=0xFA,.pll[13]=0xA9,.pll[14]=0xAA, + .pll[15]=0x0A,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_197802 = { + .clock = 197802, + .pll[0]=0x74, .pll[1]=0x00, .pll[2]=0xAE, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x99,.pll[12]=0x05,.pll[13]=0x98,.pll[14]=0x99, + .pll[15]=0x0A,.pll[16]=0x08,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_198000 = { + .clock = 198000, + .pll[0]=0x74, .pll[1]=0x00, .pll[2]=0xAE, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x20,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0A,.pll[16]=0x08,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_209800 = { + .clock = 209800, + .pll[0]=0x34, .pll[1]=0x00, .pll[2]=0xBA, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x55,.pll[12]=0x45,.pll[13]=0x55,.pll[14]=0x55, + .pll[15]=0x0A,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_241500 = { + .clock = 241500, + .pll[0]=0x34, .pll[1]=0x00, .pll[2]=0xDA, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0xC8,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x0A,.pll[16]=0x08,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_262750 = { + .clock = 262750, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x68, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0xAA,.pll[12]=0x6C,.pll[13]=0xA9,.pll[14]=0xAA, + .pll[15]=0x09,.pll[16]=0x09,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_268500 = { + .clock = 268500, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x6A, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0xEC,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x09,.pll[16]=0x09,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_296703 = { + .clock = 296703, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x7A, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x33,.pll[12]=0x44,.pll[13]=0x33,.pll[14]=0x33, + .pll[15]=0x09,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_297000 = { + .clock = 297000, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x7A, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x00,.pll[12]=0x58,.pll[13]=0x00,.pll[14]=0x00, + .pll[15]=0x09,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_319750 = { + .clock = 319750, + .pll[0]=0xB4, .pll[1]=0x00, .pll[2]=0x86, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0xAA,.pll[12]=0x44,.pll[13]=0xA9,.pll[14]=0xAA, + .pll[15]=0x09,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_497750 = { + .clock = 497750, + .pll[0]=0x34, .pll[1]=0x00, .pll[2]=0xE2, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x55,.pll[12]=0x9F,.pll[13]=0x55,.pll[14]=0x55, + .pll[15]=0x09,.pll[16]=0x08,.pll[17]=0xCF,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_592000 = { + .clock = 592000, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x7A, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x55,.pll[12]=0x15,.pll[13]=0x55,.pll[14]=0x55, + .pll[15]=0x08,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state mtl_c10_hdmi_593407 = { + .clock = 593407, + .pll[0]=0xF4, .pll[1]=0x00, .pll[2]=0x7A, .pll[3]=0x00, .pll[4]=0x00, + .pll[5]=0x00, .pll[6]=0x00, .pll[7]=0x00, .pll[8]=0x20, .pll[9]=0xFF, + .pll[10]=0xFF,.pll[11]=0x3B,.pll[12]=0x44,.pll[13]=0xBA,.pll[14]=0xBB, + .pll[15]=0x08,.pll[16]=0x08,.pll[17]=0x8F,.pll[18]=0x84,.pll[19]=0x23, +}; + +static const struct intel_c10mpllb_state * const mtl_c10_hdmi_tables[] = { + &mtl_c10_hdmi_25175, + &mtl_c10_hdmi_25200, /* Consolidated Table */ + &mtl_c10_hdmi_27_0, /* Consolidated Table */ + &mtl_c10_hdmi_27027, + &mtl_c10_hdmi_28320, + &mtl_c10_hdmi_30240, + &mtl_c10_hdmi_31500, + &mtl_c10_hdmi_36000, + &mtl_c10_hdmi_40000, + &mtl_c10_hdmi_49500, + &mtl_c10_hdmi_50000, + &mtl_c10_hdmi_57284, + &mtl_c10_hdmi_58000, + &mtl_c10_hdmi_65000, + &mtl_c10_hdmi_71000, + &mtl_c10_hdmi_74176, + &mtl_c10_hdmi_74_25, /* Consolidated Table */ + &mtl_c10_hdmi_75000, + &mtl_c10_hdmi_78750, + &mtl_c10_hdmi_85500, + &mtl_c10_hdmi_88750, + &mtl_c10_hdmi_106500, + &mtl_c10_hdmi_108000, + &mtl_c10_hdmi_115500, + &mtl_c10_hdmi_119000, + &mtl_c10_hdmi_135000, + &mtl_c10_hdmi_138500, + &mtl_c10_hdmi_147160, + &mtl_c10_hdmi_148352, + &mtl_c10_hdmi_148_5, /* Consolidated Table */ + &mtl_c10_hdmi_154000, + &mtl_c10_hdmi_162000, + &mtl_c10_hdmi_167000, + &mtl_c10_hdmi_197802, + &mtl_c10_hdmi_198000, + &mtl_c10_hdmi_209800, + &mtl_c10_hdmi_241500, + &mtl_c10_hdmi_262750, + &mtl_c10_hdmi_268500, + &mtl_c10_hdmi_296703, + &mtl_c10_hdmi_297000, + &mtl_c10_hdmi_319750, + &mtl_c10_hdmi_497750, + &mtl_c10_hdmi_592000, + &mtl_c10_hdmi_593407, + &mtl_c10_hdmi_594, /* Consolidated Table */ + NULL, +}; + +int intel_c10_phy_check_hdmi_link_rate(int clock) +{ + const struct intel_c10mpllb_state * const *tables = mtl_c10_hdmi_tables; + int i; + + for (i = 0; tables[i]; i++) { + if (clock == tables[i]->clock) + return MODE_OK; + } + + return MODE_CLOCK_RANGE; +} + static const struct intel_c10mpllb_state * const * intel_c10_mpllb_tables_get(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) @@ -493,9 +1033,10 @@ intel_c10_mpllb_tables_get(struct intel_crtc_state *crtc_state, return mtl_c10_edp_tables; else return mtl_c10_dp_tables; + } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) { + return mtl_c10_hdmi_tables; } - /* TODO: Add HDMI Support */ MISSING_CASE(encoder->type); return NULL; } @@ -503,9 +1044,20 @@ intel_c10_mpllb_tables_get(struct intel_crtc_state *crtc_state, static int intel_c10mpllb_calc_state(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) { + struct drm_i915_private *i915 = to_i915(encoder->base.dev); const struct intel_c10mpllb_state * const *tables; + enum phy phy = intel_port_to_phy(i915, encoder->port); int i; + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) { + if (intel_c10_phy_check_hdmi_link_rate(crtc_state->port_clock) + != MODE_OK) { + drm_dbg_kms(&i915->drm, "Can't support HDMI link rate %d on phy %c.\n", + crtc_state->port_clock, phy_name(phy)); + return -EINVAL; + } + } + tables = intel_c10_mpllb_tables_get(crtc_state, encoder); if (!tables) return -EINVAL; @@ -557,9 +1109,10 @@ void intel_c10mpllb_readout_hw_state(struct intel_encoder *encoder, cmn = intel_cx0_read(i915, encoder->port, lane, PHY_C10_VDR_CMN(0)); tx0 = intel_cx0_read(i915, encoder->port, lane, PHY_C10_VDR_TX(0)); - if (tx0 != C10_TX0_VAL || cmn != C10_CMN0_DP_VAL) - drm_warn(&i915->drm, "Unexpected tx: %x or cmn: %x for phy: %c.\n", - tx0, cmn, phy_name(phy)); + if (tx0 != C10_TX0_VAL || (cmn != C10_CMN0_DP_VAL && + cmn != C10_CMN0_HDMI_VAL)) + drm_dbg_kms(&i915->drm, "Unexpected tx: %x or cmn: %x for phy: %c.\n", + tx0, cmn, phy_name(phy)); } static void intel_c10_pll_program(struct drm_i915_private *i915, @@ -573,11 +1126,11 @@ static void intel_c10_pll_program(struct drm_i915_private *i915, INTEL_CX0_LANE0; u8 follower_lane = lane_reversal ? INTEL_CX0_LANE0 : INTEL_CX0_LANE1; - int i; struct intel_dp *intel_dp; bool use_ssc = false; - u8 cmn0 = 0; + bool use_hdmi = false; + u8 cmn0; if (intel_crtc_has_dp_encoder(crtc_state)) { intel_dp = enc_to_intel_dp(encoder); @@ -588,6 +1141,9 @@ static void intel_c10_pll_program(struct drm_i915_private *i915, use_ssc = false; cmn0 = C10_CMN0_DP_VAL; + } else { + use_hdmi = true; + cmn0 = C10_CMN0_HDMI_VAL; } intel_cx0_write(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CONTROL(1), @@ -603,7 +1159,7 @@ static void intel_c10_pll_program(struct drm_i915_private *i915, for (i = 0; i < ARRAY_SIZE(pll_state->pll); i++) /* If not using ssc pll[4] through pll[8] must be 0*/ intel_cx0_write(i915, encoder->port, master_lane, PHY_C10_VDR_PLL(i), - (!use_ssc && (i > 3 && i < 9)) ? 0 : pll_state->pll[i], + (!(use_ssc || use_hdmi) && (i > 3 && i < 9)) ? 0 : pll_state->pll[i], (i % 4) ? MB_WRITE_UNCOMMITTED : MB_WRITE_COMMITTED); intel_cx0_write(i915, encoder->port, master_lane, PHY_C10_VDR_CMN(0), cmn0, MB_WRITE_COMMITTED); @@ -651,7 +1207,8 @@ int intel_c10mpllb_calc_port_clock(struct intel_encoder *encoder, const struct intel_c10mpllb_state *pll_state) { unsigned int frac_quot = 0, frac_rem = 0, frac_den = 1; - unsigned int multiplier, tx_clk_div, refclk = 38400; + unsigned int multiplier, tx_clk_div, hdmi_div, refclk = 38400; + int tmpclk = 0; if (pll_state->pll[0] & C10_PLL0_FRACEN) { frac_quot = pll_state->pll[12] << 8 | pll_state->pll[11]; @@ -663,10 +1220,14 @@ int intel_c10mpllb_calc_port_clock(struct intel_encoder *encoder, pll_state->pll[2]) / 2 + 16; tx_clk_div = REG_FIELD_GET8(C10_PLL15_TXCLKDIV_MASK, pll_state->pll[15]); + hdmi_div = REG_FIELD_GET8(C10_PLL15_HDMIDIV_MASK, pll_state->pll[15]); - return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, (multiplier << 16) + frac_quot) + + tmpclk = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, (multiplier << 16) + frac_quot) + DIV_ROUND_CLOSEST(refclk * frac_rem, frac_den), 10 << (tx_clk_div + 16)); + tmpclk *= (hdmi_div ? 2 : 1); + + return tmpclk; } static void intel_program_port_clock_ctl(struct intel_encoder *encoder, @@ -1070,6 +1631,7 @@ void intel_c10mpllb_state_verify(struct intel_atomic_state *state, enum phy phy; int i; bool use_ssc = false; + bool use_hdmi = false; if (DISPLAY_VER(i915) < 14) return; @@ -1087,6 +1649,8 @@ void intel_c10mpllb_state_verify(struct intel_atomic_state *state, if (!intel_panel_use_ssc(i915)) use_ssc = false; + } else { + use_hdmi = true; } if (!intel_is_c10phy(i915, phy)) @@ -1097,7 +1661,7 @@ void intel_c10mpllb_state_verify(struct intel_atomic_state *state, for (i = 0; i < ARRAY_SIZE(mpllb_sw_state->pll); i++) { u8 expected; - if (!use_ssc && i > 3 && i < 9) + if (!(use_ssc || use_hdmi) && i > 3 && i < 9) expected = 0; else expected = mpllb_sw_state->pll[i]; diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 8cf340509097..f8023f240727 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -39,5 +39,6 @@ int intel_c10mpllb_calc_port_clock(struct intel_encoder *encoder, const struct intel_c10mpllb_state *pll_state); void intel_c10mpllb_state_verify(struct intel_atomic_state *state, struct intel_crtc_state *new_crtc_state); +int intel_c10_phy_check_hdmi_link_rate(int clock); #endif /* __INTEL_CX0_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h index ef629f8b14cf..f6002b70ddbe 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h @@ -138,9 +138,11 @@ #define C10_PLL0_FRACEN REG_BIT8(4) #define C10_PLL3_MULTIPLIERH_MASK REG_GENMASK8(3, 0) #define C10_PLL15_TXCLKDIV_MASK REG_GENMASK8(2, 0) +#define C10_PLL15_HDMIDIV_MASK REG_GENMASK8(5, 3) #define PHY_C10_VDR_CMN(idx) (0xC20 + (idx)) #define C10_CMN0_DP_VAL 0x21 +#define C10_CMN0_HDMI_VAL 0x1 #define C10_CMN3_TXVBOOST_MASK REG_GENMASK8(7, 5) #define C10_CMN3_TXVBOOST(val) REG_FIELD_PREP8(C10_CMN3_TXVBOOST_MASK, val) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index efa2da080f62..7b81781a64b6 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -45,6 +45,7 @@ #include "i915_reg.h" #include "intel_atomic.h" #include "intel_connector.h" +#include "intel_cx0_phy.h" #include "intel_ddi.h" #include "intel_de.h" #include "intel_display_types.h" @@ -1882,7 +1883,9 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi, * FIXME: We will hopefully get an algorithmic way of programming * the MPLLB for HDMI in the future. */ - if (IS_DG2(dev_priv)) + if (IS_METEORLAKE(dev_priv)) + return intel_c10_phy_check_hdmi_link_rate(clock); + else if (IS_DG2(dev_priv)) return intel_snps_phy_check_hdmi_link_rate(clock); return MODE_OK; From patchwork Thu Jan 5 12:54:31 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089815 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id C1375C53210 for ; Thu, 5 Jan 2023 12:59:52 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 3601610E719; Thu, 5 Jan 2023 12:59:52 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id AFBC510E718 for ; Thu, 5 Jan 2023 12:59:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923588; x=1704459588; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=kwwTrdIfXy5jrqDrokepmsSzh8pLL0w8oYWW4GU/wIU=; b=BZHEWZ5zuYduKsN24qhgF7FSBwTrrfCCvk3n8ojQSJaRkh6JP+JgXZyO Ec7BqRHOnBQ/D07YEjYd4A14N4bKQFJxX6hVBVH/p4mpCc9Q4fuLHcvMV eLWXDrwuU5wizcnAMeP7QmgpP0qjsn5MIyn47GKtoL/dl7xZ4GNaZya2W yi5YU6+YOTHC9jo/d0jeS3RjkerGy6IOjFehJqZBFUEPTdpxx3EBBlnfK sHsekLkALfuW4dzNkT2i6UArOrjX0TgTlINvTuWAXOGKudZk40163Fyp/ Zgu36v52lQmDlVSX4RzuhzejXe/9/w+5AIApTGGySDeOzRsLW04Lq+gD7 Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697746" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697746" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 04:59:48 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829540959" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829540959" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 04:59:46 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:31 +0200 Message-Id: <20230105125446.960504-7-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 06/21] drm/i915/mtl: Add vswing programming for C10 phys 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Radhakrishna Sripada C10 phys uses direct mapping internally for voltage and pre-emphasis levels. Program the levels directly to the fields in the VDR Registers. Bspec: 65449 v2: From table "C10: Tx EQ settings for DP 1.4x" it shows level 1 and preemphasis 1 instead of two times of level 1 preemphasis 0. Fix this in the driver code as well. Cc: Imre Deak Cc: Uma Shankar Signed-off-by: Clint Taylor Signed-off-by: Radhakrishna Sripada Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-7-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 131 ++++++++++++++++-- drivers/gpu/drm/i915/display/intel_cx0_phy.h | 2 + .../gpu/drm/i915/display/intel_cx0_phy_regs.h | 6 + drivers/gpu/drm/i915/display/intel_ddi.c | 4 +- .../drm/i915/display/intel_ddi_buf_trans.c | 36 ++++- .../drm/i915/display/intel_ddi_buf_trans.h | 6 + .../i915/display/intel_display_power_map.c | 1 + 7 files changed, 175 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 746c905538a7..3d86b0f1c36d 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -6,10 +6,14 @@ #include "i915_reg.h" #include "intel_cx0_phy.h" #include "intel_cx0_phy_regs.h" +#include "intel_ddi.h" +#include "intel_ddi_buf_trans.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_panel.h" +#include "intel_psr.h" +#include "intel_uncore.h" bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy) { @@ -19,6 +23,15 @@ bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy) return false; } +static void +assert_dc_off(struct drm_i915_private *i915) +{ + bool enabled; + + enabled = intel_display_power_is_enabled(i915, POWER_DOMAIN_DC_OFF); + drm_WARN_ON(&i915->drm, !enabled); +} + static void intel_cx0_bus_reset(struct drm_i915_private *i915, enum port port, int lane) { enum phy phy = intel_port_to_phy(i915, port); @@ -111,6 +124,8 @@ static u8 intel_cx0_read(struct drm_i915_private *i915, enum port port, int i, status = 0; u32 val; + assert_dc_off(i915); + for (i = 0; i < 3; i++) { status = __intel_cx0_read(i915, port, lane, addr, &val); @@ -193,6 +208,8 @@ static void __intel_cx0_write(struct drm_i915_private *i915, enum port port, enum phy phy = intel_port_to_phy(i915, port); int i, status; + assert_dc_off(i915); + for (i = 0; i < 3; i++) { status = __intel_cx0_write_once(i915, port, lane, addr, data, committed); @@ -240,6 +257,80 @@ static void intel_cx0_rmw(struct drm_i915_private *i915, enum port port, } } +/* + * Prepare HW for CX0 phy transactions. + * + * It is required that PSR and DC5/6 are disabled before any CX0 message + * bus transaction is executed. + */ +static intel_wakeref_t intel_cx0_phy_transaction_begin(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + intel_psr_pause(intel_dp); + return intel_display_power_get(i915, POWER_DOMAIN_DC_OFF); +} + +static void intel_cx0_phy_transaction_end(struct intel_encoder *encoder, intel_wakeref_t wakeref) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + intel_psr_resume(intel_dp); + intel_display_power_put(i915, POWER_DOMAIN_DC_OFF, wakeref); +} + +void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL; + u8 master_lane = lane_reversal ? INTEL_CX0_LANE1 : + INTEL_CX0_LANE0; + u8 follower_lane = lane_reversal ? INTEL_CX0_LANE0 : + INTEL_CX0_LANE1; + const struct intel_ddi_buf_trans *trans; + intel_wakeref_t wakeref; + int n_entries, ln; + + wakeref = intel_cx0_phy_transaction_begin(encoder); + + trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); + if (drm_WARN_ON_ONCE(&i915->drm, !trans)) + return; + + intel_cx0_rmw(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CONTROL(1), + 0, C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED); + + for (ln = 0; ln < 4; ln++) { + int level = intel_ddi_level(encoder, crtc_state, ln); + int lane, tx; + + lane = ln / 2 + 1; + tx = ln % 2 + 1; + + intel_cx0_rmw(i915, encoder->port, lane, PHY_CX0_TX_CONTROL(tx, 2), + C10_PHY_VSWING_PREEMPH_MASK, + C10_PHY_VSWING_PREEMPH(trans->entries[level].direct.preemph), + MB_WRITE_COMMITTED); + intel_cx0_rmw(i915, encoder->port, lane, PHY_CX0_TX_CONTROL(tx, 8), + C10_PHY_VSWING_LEVEL_MASK, + C10_PHY_VSWING_LEVEL(trans->entries[level].direct.level), + MB_WRITE_COMMITTED); + } + + intel_cx0_write(i915, encoder->port, follower_lane, PHY_C10_VDR_CONTROL(1), + C10_VDR_CTRL_MSGBUS_ACCESS | C10_VDR_CTRL_UPDATE_CFG, + MB_WRITE_COMMITTED); + intel_cx0_write(i915, encoder->port, master_lane, PHY_C10_VDR_CONTROL(1), + C10_VDR_CTRL_MASTER_LANE | C10_VDR_CTRL_MSGBUS_ACCESS | + C10_VDR_CTRL_UPDATE_CFG, MB_WRITE_COMMITTED); + + intel_cx0_phy_transaction_end(encoder, wakeref); +} + /* * Basic DP link rates with 38.4 MHz reference clock. * Note: The tables below are with SSC. In non-ssc @@ -1092,9 +1183,12 @@ void intel_c10mpllb_readout_hw_state(struct intel_encoder *encoder, u8 lane = lane_reversal ? INTEL_CX0_LANE1 : INTEL_CX0_LANE0; enum phy phy = intel_port_to_phy(i915, encoder->port); + intel_wakeref_t wakeref; int i; u8 cmn, tx0; + wakeref = intel_cx0_phy_transaction_begin(encoder); + /* * According to C10 VDR Register programming Sequence we need * to do this to read PHY internal registers from MsgBus. @@ -1113,6 +1207,8 @@ void intel_c10mpllb_readout_hw_state(struct intel_encoder *encoder, cmn != C10_CMN0_HDMI_VAL)) drm_dbg_kms(&i915->drm, "Unexpected tx: %x or cmn: %x for phy: %c.\n", tx0, cmn, phy_name(phy)); + + intel_cx0_phy_transaction_end(encoder, wakeref); } static void intel_c10_pll_program(struct drm_i915_private *i915, @@ -1250,8 +1346,11 @@ static void intel_program_port_clock_ctl(struct intel_encoder *encoder, if (intel_crtc_has_dp_encoder(crtc_state)) { intel_dp = enc_to_intel_dp(encoder); - ssc_enabled = intel_dp->dpcd[DP_MAX_DOWNSPREAD] & - DP_MAX_DOWNSPREAD_0_5; + ssc_enabled = (intel_dp->dpcd[DP_MAX_DOWNSPREAD] & + DP_MAX_DOWNSPREAD_0_5); + + if (intel_dp_is_edp(intel_dp) && !intel_panel_use_ssc(i915)) + ssc_enabled = false; if (!intel_panel_use_ssc(i915)) ssc_enabled = false; @@ -1259,11 +1358,11 @@ static void intel_program_port_clock_ctl(struct intel_encoder *encoder, /* TODO: DP2.0 10G and 20G rates enable MPLLA*/ val |= ssc_enabled ? XELPDP_SSC_ENABLE_PLLB : 0; } + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), - XELPDP_LANE1_PHY_CLOCK_SELECT | - XELPDP_FORWARD_CLOCK_UNGATE | + XELPDP_LANE1_PHY_CLOCK_SELECT | XELPDP_FORWARD_CLOCK_UNGATE | XELPDP_DDI_CLOCK_SELECT_MASK | - XELPDP_SSC_ENABLE_PLLB, val); + XELPDP_SSC_ENABLE_PLLA | XELPDP_SSC_ENABLE_PLLB, val); } static u32 intel_cx0_get_powerdown_update(u8 lane) @@ -1401,9 +1500,12 @@ static void intel_c10_program_phy_lane(struct drm_i915_private *i915, { u8 l0t1, l0t2, l1t1, l1t2; - intel_cx0_rmw(i915, port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CONTROL(1), - C10_VDR_CTRL_MSGBUS_ACCESS, C10_VDR_CTRL_MSGBUS_ACCESS, - MB_WRITE_COMMITTED); + intel_cx0_rmw(i915, port, INTEL_CX0_LANE1, PHY_C10_VDR_CONTROL(1), + C10_VDR_CTRL_MSGBUS_ACCESS | C10_VDR_CTRL_UPDATE_CFG, + C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED); + intel_cx0_rmw(i915, port, INTEL_CX0_LANE0, PHY_C10_VDR_CONTROL(1), + C10_VDR_CTRL_MSGBUS_ACCESS | C10_VDR_CTRL_UPDATE_CFG, + C10_VDR_CTRL_MASTER_LANE | C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED); l0t1 = intel_cx0_read(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(1, 2)); l0t2 = intel_cx0_read(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(2, 2)); @@ -1559,9 +1661,14 @@ void intel_cx0pll_enable(struct intel_encoder *encoder, { struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(i915, encoder->port); + intel_wakeref_t wakeref; + + wakeref = intel_cx0_phy_transaction_begin(encoder); drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); intel_c10pll_enable(encoder, crtc_state); + + intel_cx0_phy_transaction_end(encoder, wakeref); } static void intel_c10pll_disable(struct intel_encoder *encoder) @@ -1606,7 +1713,8 @@ static void intel_c10pll_disable(struct intel_encoder *encoder) /* 7. Program PORT_CLOCK_CTL register to disable and gate clocks. */ intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), - XELPDP_DDI_CLOCK_SELECT_MASK | + XELPDP_DDI_CLOCK_SELECT_MASK, 0); + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), XELPDP_FORWARD_CLOCK_UNGATE, 0); } @@ -1614,9 +1722,14 @@ void intel_cx0pll_disable(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(i915, encoder->port); + intel_wakeref_t wakeref; + + wakeref = intel_cx0_phy_transaction_begin(encoder); drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); intel_c10pll_disable(encoder); + + intel_cx0_phy_transaction_end(encoder, wakeref); } void intel_c10mpllb_state_verify(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index f8023f240727..952c7deeffaa 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -40,5 +40,7 @@ int intel_c10mpllb_calc_port_clock(struct intel_encoder *encoder, void intel_c10mpllb_state_verify(struct intel_atomic_state *state, struct intel_crtc_state *new_crtc_state); int intel_c10_phy_check_hdmi_link_rate(int clock); +void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); #endif /* __INTEL_CX0_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h index f6002b70ddbe..fd48c75ee532 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h @@ -169,4 +169,10 @@ #define PHY_CX0_TX_CONTROL(tx, control) (0x400 + ((tx) - 1) * 0x200 + (control)) #define CONTROL2_DISABLE_SINGLE_TX REG_BIT(6) +/* C10 Phy VSWING Masks */ +#define C10_PHY_VSWING_LEVEL_MASK REG_GENMASK8(2, 0) +#define C10_PHY_VSWING_LEVEL(val) REG_FIELD_PREP8(C10_PHY_VSWING_LEVEL_MASK, val) +#define C10_PHY_VSWING_PREEMPH_MASK REG_GENMASK8(1, 0) +#define C10_PHY_VSWING_PREEMPH(val) REG_FIELD_PREP8(C10_PHY_VSWING_PREEMPH_MASK, val) + #endif /* __INTEL_CX0_PHY_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 099776b62052..e796e5cf10f0 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -4472,7 +4472,9 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->get_config = hsw_ddi_get_config; } - if (IS_DG2(dev_priv)) { + if (DISPLAY_VER(dev_priv) >= 14) { + encoder->set_signal_levels = intel_cx0_phy_set_signal_levels; + } else if (IS_DG2(dev_priv)) { encoder->set_signal_levels = intel_snps_phy_set_signal_levels; } else if (DISPLAY_VER(dev_priv) >= 12) { if (intel_phy_is_combo(dev_priv, phy)) diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c index 006a2e979000..ca2acaa73a64 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c @@ -1035,6 +1035,30 @@ static const struct intel_ddi_buf_trans dg2_snps_trans_uhbr = { .num_entries = ARRAY_SIZE(_dg2_snps_trans_uhbr), }; +/* + * Some platforms don't need a mapping table and only expect us to + * to program the vswing + preemphasis levels directly since the + * hardware will do its own mapping to tuning values internally. + */ +static const union intel_ddi_buf_trans_entry direct_map_trans[] = { + { .direct = { .level = 0, .preemph = 0 } }, + { .direct = { .level = 0, .preemph = 1 } }, + { .direct = { .level = 0, .preemph = 2 } }, + { .direct = { .level = 0, .preemph = 3 } }, + { .direct = { .level = 1, .preemph = 0 } }, + { .direct = { .level = 1, .preemph = 1 } }, + { .direct = { .level = 1, .preemph = 2 } }, + { .direct = { .level = 2, .preemph = 0 } }, + { .direct = { .level = 2, .preemph = 1 } }, + { .direct = { .level = 3, .preemph = 0 } }, +}; + +static const struct intel_ddi_buf_trans mtl_cx0c10_trans = { + .entries = direct_map_trans, + .num_entries = ARRAY_SIZE(direct_map_trans), + .hdmi_default_entry = ARRAY_SIZE(direct_map_trans) - 1, +}; + bool is_hobl_buf_trans(const struct intel_ddi_buf_trans *table) { return table == &tgl_combo_phy_trans_edp_hbr2_hobl; @@ -1606,12 +1630,22 @@ dg2_get_snps_buf_trans(struct intel_encoder *encoder, return intel_get_buf_trans(&dg2_snps_trans, n_entries); } +static const struct intel_ddi_buf_trans * +mtl_get_cx0_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + return intel_get_buf_trans(&mtl_cx0c10_trans, n_entries); +} + void intel_ddi_buf_trans_init(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(i915, encoder->port); - if (IS_DG2(i915)) { + if (DISPLAY_VER(i915) >= 14) { + encoder->get_buf_trans = mtl_get_cx0_buf_trans; + } else if (IS_DG2(i915)) { encoder->get_buf_trans = dg2_get_snps_buf_trans; } else if (IS_ALDERLAKE_P(i915)) { if (intel_phy_is_combo(i915, phy)) diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h index 2133984a572b..e4a857b9829d 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h @@ -51,6 +51,11 @@ struct dg2_snps_phy_buf_trans { u8 post_cursor; }; +struct direct_phy_buf_trans { + u8 level; + u8 preemph; +}; + union intel_ddi_buf_trans_entry { struct hsw_ddi_buf_trans hsw; struct bxt_ddi_buf_trans bxt; @@ -58,6 +63,7 @@ union intel_ddi_buf_trans_entry { struct icl_mg_phy_ddi_buf_trans mg; struct tgl_dkl_phy_ddi_buf_trans dkl; struct dg2_snps_phy_buf_trans snps; + struct direct_phy_buf_trans direct; }; struct intel_ddi_buf_trans { diff --git a/drivers/gpu/drm/i915/display/intel_display_power_map.c b/drivers/gpu/drm/i915/display/intel_display_power_map.c index f5d66ca85b19..f49da1c4eb22 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_map.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_map.c @@ -1426,6 +1426,7 @@ I915_DECL_PW_DOMAINS(xelpdp_pwdoms_dc_off, XELPDP_PW_2_POWER_DOMAINS, POWER_DOMAIN_AUDIO_MMIO, POWER_DOMAIN_MODESET, + POWER_DOMAIN_DC_OFF, POWER_DOMAIN_AUX_A, POWER_DOMAIN_AUX_B, POWER_DOMAIN_DC_OFF, From patchwork Thu Jan 5 12:54:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089816 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 61604C3DA7D for ; Thu, 5 Jan 2023 12:59:54 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id DFCF710E71A; Thu, 5 Jan 2023 12:59:53 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id B658210E719 for ; Thu, 5 Jan 2023 12:59:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923591; x=1704459591; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+tuYq5HvQWJMrOEm+uIxVxEnjUGhCj0dlnv1ZRjxSSo=; b=MKyUwtra8XXY2jrrbZ3PYplNF6yf8H/ejN3WNtUw/ZeBgjgQVsZtTfDt wThzzp/0afs1zk+3ZddqTLZVnfCoOKEhqAMenFzodP3J42zPOu2dc9Z61 zQIrxyAyfr50G7v57I/CeXW+cgEQR0fOBxGWQkp49yuW+LOsPwgdh48rU bWsPHmJaX5SlBvtnMNTvBuHAtNW4k+oKuCkFeQpcx116+ELRTa6+x1YBj +3HsWPLXiDCW6L43FO0ryDvS40Zjrv41XXzjG4gdpmMVw1Sv4PYTVH50x UfprWbpaiY7x4D+8MiMqfQ/S57LiEOfK/3QvzEKBA32vp2HdHgfgaP3RK g==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697759" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697759" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 04:59:51 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829540964" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829540964" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 04:59:48 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:32 +0200 Message-Id: <20230105125446.960504-8-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 07/21] drm/i915/mtl: Add support for PM DEMAND 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: jani.nikula@intel.com, Lucas De Marchi Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Display14 introduces a new way to instruct the PUnit with power and bandwidth requirements of DE. Add the functionality to program the registers and handle waits using interrupts. The current wait time for timeouts is programmed for 10 msecs to factor in the worst case scenarios. Changes made to use REG_BIT for a register that we touched(GEN8_DE_MISC_IER _MMIO). Bspec: 66451, 64636, 64602, 64603 v2: Moved pmdemand to be part of "struct intel_display" Cc: Matt Atwood Cc: Matt Roper Cc: Lucas De Marchi Signed-off-by: José Roberto de Souza Signed-off-by: Radhakrishna Sripada Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-8-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_bw.c | 4 +- drivers/gpu/drm/i915/display/intel_bw.h | 2 + drivers/gpu/drm/i915/display/intel_display.c | 14 + .../gpu/drm/i915/display/intel_display_core.h | 6 + .../drm/i915/display/intel_display_power.c | 8 + drivers/gpu/drm/i915/i915_irq.c | 22 +- drivers/gpu/drm/i915/i915_reg.h | 33 +- drivers/gpu/drm/i915/intel_pm.c | 286 ++++++++++++++++++ drivers/gpu/drm/i915/intel_pm.h | 35 +++ 9 files changed, 405 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index 1c236f02b380..179dfa0a2284 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -717,8 +717,8 @@ static unsigned int intel_bw_num_active_planes(struct drm_i915_private *dev_priv return num_active_planes; } -static unsigned int intel_bw_data_rate(struct drm_i915_private *dev_priv, - const struct intel_bw_state *bw_state) +unsigned int intel_bw_data_rate(struct drm_i915_private *dev_priv, + const struct intel_bw_state *bw_state) { unsigned int data_rate = 0; enum pipe pipe; diff --git a/drivers/gpu/drm/i915/display/intel_bw.h b/drivers/gpu/drm/i915/display/intel_bw.h index cb7ee3a24a58..b3eb82a71e6c 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.h +++ b/drivers/gpu/drm/i915/display/intel_bw.h @@ -62,6 +62,8 @@ int intel_bw_init(struct drm_i915_private *dev_priv); int intel_bw_atomic_check(struct intel_atomic_state *state); void intel_bw_crtc_update(struct intel_bw_state *bw_state, const struct intel_crtc_state *crtc_state); +unsigned int intel_bw_data_rate(struct drm_i915_private *dev_priv, + const struct intel_bw_state *bw_state); int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv, u32 points_mask); int intel_bw_calc_min_cdclk(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 655e1c86a1eb..87cd6a808938 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -1089,6 +1089,9 @@ intel_get_crtc_new_encoder(const struct intel_atomic_state *state, num_encoders++; } + if (!encoder) + return NULL; + drm_WARN(encoder->base.dev, num_encoders != 1, "%d encoders for pipe %c\n", num_encoders, pipe_name(master_crtc->pipe)); @@ -6868,6 +6871,10 @@ static int intel_atomic_check(struct drm_device *dev, ret = intel_modeset_calc_cdclk(state); if (ret) return ret; + + ret = intel_pmdemand_atomic_check(state); + if (ret) + goto fail; } ret = intel_atomic_check_crtcs(state); @@ -7484,6 +7491,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) } intel_sagv_pre_plane_update(state); + intel_pmdemand_pre_plane_update(state); /* Complete the events for pipes that have now been disabled */ for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { @@ -7596,6 +7604,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) intel_verify_planes(state); intel_sagv_post_plane_update(state); + intel_pmdemand_post_plane_update(state); drm_atomic_helper_commit_hw_done(&state->base); @@ -8327,6 +8336,7 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv) intel_color_init_hooks(dev_priv); intel_init_cdclk_hooks(dev_priv); intel_audio_hooks_init(dev_priv); + intel_init_pmdemand(dev_priv); intel_dpll_init_clock_hook(dev_priv); @@ -8667,6 +8677,10 @@ int intel_modeset_init_noirq(struct drm_i915_private *i915) if (ret) goto cleanup_vga_client_pw_domain_dmc; + ret = intel_pmdemand_init(i915); + if (ret) + goto cleanup_vga_client_pw_domain_dmc; + init_llist_head(&i915->display.atomic_helper.free_list); INIT_WORK(&i915->display.atomic_helper.free_work, intel_atomic_helper_free_state_worker); diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 57ddce3ba02b..c74bf0c5b88d 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -321,6 +321,12 @@ struct intel_display { struct intel_global_obj obj; } dbuf; + struct { + wait_queue_head_t waitqueue; + struct mutex lock; + struct intel_global_obj obj; + } pmdemand; + struct { /* * dkl.phy_lock protects against concurrent access of the diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 40f157208a81..a8da1b07fa43 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -19,6 +19,7 @@ #include "intel_mchbar_regs.h" #include "intel_pch_refclk.h" #include "intel_pcode.h" +#include "intel_pm.h" #include "intel_snps_phy.h" #include "skl_watermark.h" #include "vlv_sideband.h" @@ -1081,6 +1082,10 @@ static void gen9_dbuf_enable(struct drm_i915_private *dev_priv) dev_priv->display.dbuf.enabled_slices = intel_enabled_dbuf_slices_mask(dev_priv); + if (DISPLAY_VER(dev_priv) >= 14) + intel_program_dbuf_pmdemand(dev_priv, BIT(DBUF_S1) | + dev_priv->display.dbuf.enabled_slices); + /* * Just power up at least 1 slice, we will * figure out later which slices we have and what we need. @@ -1092,6 +1097,9 @@ static void gen9_dbuf_enable(struct drm_i915_private *dev_priv) static void gen9_dbuf_disable(struct drm_i915_private *dev_priv) { gen9_dbuf_slices_update(dev_priv, 0); + + if (DISPLAY_VER(dev_priv) >= 14) + intel_program_dbuf_pmdemand(dev_priv, 0); } static void gen12_dbuf_slices_config(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 54ea28cf8a1a..15dfef6d93a9 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2320,6 +2320,11 @@ static u32 gen8_de_pipe_fault_mask(struct drm_i915_private *dev_priv) return GEN8_DE_PIPE_IRQ_FAULT_ERRORS; } +static void intel_pmdemand_irq_handler(struct drm_i915_private *dev_priv) +{ + wake_up_all(&dev_priv->display.pmdemand.waitqueue); +} + static void gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) { @@ -2356,6 +2361,18 @@ gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) } } + if (iir & XELPDP_PMDEMAND_RSPTOUT_ERR) { + drm_dbg(&dev_priv->drm, + "Error waiting for Punit PM Demand Response\n"); + intel_pmdemand_irq_handler(dev_priv); + found = true; + } + + if (iir & XELPDP_PMDEMAND_RSP) { + intel_pmdemand_irq_handler(dev_priv); + found = true; + } + if (!found) drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n"); } @@ -3728,7 +3745,10 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) de_port_masked |= BXT_DE_PORT_GMBUS; - if (DISPLAY_VER(dev_priv) >= 11) { + if (DISPLAY_VER(dev_priv) >= 14) + de_misc_masked |= XELPDP_PMDEMAND_RSPTOUT_ERR | + XELPDP_PMDEMAND_RSP; + else if (DISPLAY_VER(dev_priv) >= 11) { enum port port; if (intel_bios_is_dsi_present(dev_priv, &port)) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8d4b626874db..065905723c09 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5516,8 +5516,10 @@ #define GEN8_DE_MISC_IMR _MMIO(0x44464) #define GEN8_DE_MISC_IIR _MMIO(0x44468) #define GEN8_DE_MISC_IER _MMIO(0x4446c) -#define GEN8_DE_MISC_GSE (1 << 27) -#define GEN8_DE_EDP_PSR (1 << 19) +#define XELPDP_PMDEMAND_RSPTOUT_ERR REG_BIT(27) +#define GEN8_DE_MISC_GSE REG_BIT(27) +#define GEN8_DE_EDP_PSR REG_BIT(19) +#define XELPDP_PMDEMAND_RSP REG_BIT(3) #define GEN8_PCU_ISR _MMIO(0x444e0) #define GEN8_PCU_IMR _MMIO(0x444e4) @@ -5580,6 +5582,33 @@ #define GEN11_HOTPLUG_CTL_SHORT_DETECT(hpd_pin) (1 << (_HPD_PIN_TC(hpd_pin) * 4)) #define GEN11_HOTPLUG_CTL_NO_DETECT(hpd_pin) (0 << (_HPD_PIN_TC(hpd_pin) * 4)) +#define XELPDP_INITIATE_PMDEMAND_REQUEST(dword) _MMIO(0x45230 + 4 * (dword)) +#define XELPDP_PMDEMAND_QCLK_GV_BW_MASK REG_GENMASK(31, 16) +#define XELPDP_PMDEMAND_QCLK_GV_BW(x) REG_FIELD_PREP(XELPDP_PMDEMAND_QCLK_GV_BW_MASK, x) +#define XELPDP_PMDEMAND_VOLTAGE_INDEX_MASK REG_GENMASK(14, 12) +#define XELPDP_PMDEMAND_VOLTAGE_INDEX(x) REG_FIELD_PREP(XELPDP_PMDEMAND_VOLTAGE_INDEX_MASK, x) +#define XELPDP_PMDEMAND_QCLK_GV_INDEX_MASK REG_GENMASK(11, 8) +#define XELPDP_PMDEMAND_QCLK_GV_INDEX(x) REG_FIELD_PREP(XELPDP_PMDEMAND_QCLK_GV_INDEX_MASK, x) +#define XELPDP_PMDEMAND_PIPES_MASK REG_GENMASK(7, 6) +#define XELPDP_PMDEMAND_PIPES(x) REG_FIELD_PREP(XELPDP_PMDEMAND_PIPES_MASK, x) +#define XELPDP_PMDEMAND_DBUFS_MASK REG_GENMASK(5, 4) +#define XELPDP_PMDEMAND_DBUFS(x) REG_FIELD_PREP(XELPDP_PMDEMAND_DBUFS_MASK, x) +#define XELPDP_PMDEMAND_PHYS_MASK REG_GENMASK(2, 0) +#define XELPDP_PMDEMAND_PHYS(x) REG_FIELD_PREP(XELPDP_PMDEMAND_PHYS_MASK, x) + +#define XELPDP_PMDEMAND_REQ_ENABLE REG_BIT(31) +#define XELPDP_PMDEMAND_CDCLK_FREQ_MASK REG_GENMASK(30, 20) +#define XELPDP_PMDEMAND_CDCLK_FREQ(x) REG_FIELD_PREP(XELPDP_PMDEMAND_CDCLK_FREQ_MASK, x) +#define XELPDP_PMDEMAND_DDICLK_FREQ_MASK REG_GENMASK(18, 8) +#define XELPDP_PMDEMAND_DDICLK_FREQ(x) REG_FIELD_PREP(XELPDP_PMDEMAND_DDICLK_FREQ_MASK, x) +#define XELPDP_PMDEMAND_SCALERS_MASK REG_GENMASK(6, 4) +#define XELPDP_PMDEMAND_SCALERS(x) REG_FIELD_PREP(XELPDP_PMDEMAND_SCALERS_MASK, x) +#define XELPDP_PMDEMAND_PLLS_MASK REG_GENMASK(2, 0) +#define XELPDP_PMDEMAND_PLLS(x) REG_FIELD_PREP(XELPDP_PMDEMAND_PLLS_MASK, x) + +#define GEN12_DCPR_STATUS_1 _MMIO(0x46440) +#define XELPDP_PMDEMAND_INFLIGHT_STATUS REG_BIT(26) + #define ILK_DISPLAY_CHICKEN2 _MMIO(0x42004) /* Required on all Ironlake and Sandybridge according to the B-Spec. */ #define ILK_ELPIN_409_SELECT (1 << 25) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 73c88b1c9545..1679ea1ea860 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -25,6 +25,11 @@ * */ +#include + +#include "display/intel_bw.h" +#include "display/intel_cdclk.h" +#include "display/intel_cx0_phy.h" #include "display/intel_de.h" #include "display/intel_display_trace.h" #include "display/skl_watermark.h" @@ -4085,6 +4090,287 @@ void ilk_wm_get_hw_state(struct drm_i915_private *dev_priv) !(intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) & DISP_FBC_WM_DIS); } +static struct intel_global_state *intel_pmdemand_duplicate_state(struct intel_global_obj *obj) +{ + struct intel_pmdemand_state *pmdmnd_state; + + pmdmnd_state = kmemdup(obj->state, sizeof(*pmdmnd_state), GFP_KERNEL); + if (!pmdmnd_state) + return NULL; + + return &pmdmnd_state->base; +} + +static void intel_pmdemand_destroy_state(struct intel_global_obj *obj, + struct intel_global_state *state) +{ + kfree(state); +} + +static const struct intel_global_state_funcs intel_pmdemand_funcs = { + .atomic_duplicate_state = intel_pmdemand_duplicate_state, + .atomic_destroy_state = intel_pmdemand_destroy_state, +}; + +struct intel_pmdemand_state * +intel_atomic_get_pmdemand_state(struct intel_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_global_state *pmdemand_state; + + pmdemand_state = intel_atomic_get_global_obj_state(state, &dev_priv->display.pmdemand.obj); + if (IS_ERR(pmdemand_state)) + return ERR_CAST(pmdemand_state); + + return to_intel_pmdemand_state(pmdemand_state); +} + +int intel_pmdemand_init(struct drm_i915_private *dev_priv) +{ + struct intel_pmdemand_state *pmdemand_state; + + pmdemand_state = kzalloc(sizeof(*pmdemand_state), GFP_KERNEL); + if (!pmdemand_state) + return -ENOMEM; + + intel_atomic_global_obj_init(dev_priv, &dev_priv->display.pmdemand.obj, + &pmdemand_state->base, &intel_pmdemand_funcs); + + return 0; +} + +void intel_init_pmdemand(struct drm_i915_private *dev_priv) +{ + mutex_init(&dev_priv->display.pmdemand.lock); + init_waitqueue_head(&dev_priv->display.pmdemand.waitqueue); +} + +int intel_pmdemand_atomic_check(struct intel_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_pmdemand_state *new_pmdemand_state = NULL; + struct intel_crtc_state *old_crtc_state, *new_crtc_state; + struct intel_crtc *crtc; + struct intel_encoder *encoder; + struct intel_bw_state *new_bw_state; + const struct intel_dbuf_state *new_dbuf_state; + const struct intel_cdclk_state *new_cdclk_state; + int port_clock = 0; + unsigned int data_rate; + enum phy phy; + int i, ret; + + if (DISPLAY_VER(dev_priv) < 14) + return 0; + + new_pmdemand_state = intel_atomic_get_pmdemand_state(state); + if (IS_ERR(new_pmdemand_state)) + return PTR_ERR(new_pmdemand_state); + + ret = intel_atomic_lock_global_state(&new_pmdemand_state->base); + if (ret) + return ret; + + /* Punit figures out the voltage index based on bandwidth*/ + new_bw_state = intel_atomic_get_bw_state(state); + if (IS_ERR(new_bw_state)) + return PTR_ERR(new_bw_state); + + /* firmware will calculate the qclck_gc_index, requirement is set to 0 */ + new_pmdemand_state->qclk_gv_index = 0; + + data_rate = intel_bw_data_rate(dev_priv, new_bw_state); + /* To MBs then to multiples of 100MBs */ + data_rate = DIV_ROUND_UP(data_rate, 1000); + data_rate = DIV_ROUND_UP(data_rate, 100); + new_pmdemand_state->qclk_gv_bw = data_rate; + + new_dbuf_state = intel_atomic_get_dbuf_state(state); + if (IS_ERR(new_dbuf_state)) + return PTR_ERR(new_dbuf_state); + + i = hweight8(new_dbuf_state->active_pipes); + new_pmdemand_state->active_pipes = min(i, 3); + + new_cdclk_state = intel_atomic_get_cdclk_state(state); + if (IS_ERR(new_cdclk_state)) + return PTR_ERR(new_cdclk_state); + + new_pmdemand_state->voltage_index = new_cdclk_state->logical.voltage_level; + /* KHz to MHz */ + new_pmdemand_state->cdclk_freq_mhz = DIV_ROUND_UP(new_cdclk_state->logical.cdclk, 1000); + + new_pmdemand_state->active_phys_plls_mask = 0; + + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + if (!new_crtc_state->hw.active) + continue; + + encoder = intel_get_crtc_new_encoder(state, new_crtc_state); + if (!encoder) + continue; + + phy = intel_port_to_phy(dev_priv, encoder->port); + + if (intel_is_c10phy(dev_priv, phy)) + new_pmdemand_state->active_phys_plls_mask |= BIT(phy); + + port_clock = max(port_clock, new_crtc_state->port_clock); + } + + /* To MHz */ + new_pmdemand_state->ddiclk_freq_mhz = DIV_ROUND_UP(port_clock, 1000); + + /* + * Setting scalers to max as it can not be calculated during flips and + * fastsets without taking global states locks. + */ + new_pmdemand_state->scalers = 7; + + return 0; +} + +static bool intel_pmdemand_check_prev_transaction(struct drm_i915_private *dev_priv) +{ + return !((intel_de_read(dev_priv, XELPDP_INITIATE_PMDEMAND_REQUEST(1)) & XELPDP_PMDEMAND_REQ_ENABLE) || + (intel_de_read(dev_priv, GEN12_DCPR_STATUS_1) & XELPDP_PMDEMAND_INFLIGHT_STATUS)); +} + +static bool intel_pmdemand_req_complete(struct drm_i915_private *dev_priv) +{ + return !(intel_de_read(dev_priv, XELPDP_INITIATE_PMDEMAND_REQUEST(1)) & XELPDP_PMDEMAND_REQ_ENABLE); +} + +static int intel_pmdemand_wait(struct drm_i915_private *dev_priv) +{ + DEFINE_WAIT(wait); + int ret; + const unsigned int timeout_ms = 10; + + add_wait_queue(&dev_priv->display.pmdemand.waitqueue, &wait); + + ret = wait_event_timeout(dev_priv->display.pmdemand.waitqueue, + intel_pmdemand_req_complete(dev_priv), + msecs_to_jiffies_timeout(timeout_ms)); + if (ret < 0) + drm_err(&dev_priv->drm, + "timed out waiting for Punit PM Demand Response\n"); + + remove_wait_queue(&dev_priv->display.pmdemand.waitqueue, &wait); + + return ret; +} + +/* Required to be programmed during Display Init Sequences. */ +void intel_program_dbuf_pmdemand(struct drm_i915_private *dev_priv, + u8 dbuf_slices) +{ + mutex_lock(&dev_priv->display.pmdemand.lock); + if (drm_WARN_ON(&dev_priv->drm, + !intel_pmdemand_check_prev_transaction(dev_priv))) + goto unlock; + + intel_de_rmw(dev_priv, XELPDP_INITIATE_PMDEMAND_REQUEST(0), + XELPDP_PMDEMAND_DBUFS_MASK, + XELPDP_PMDEMAND_DBUFS(hweight32(dbuf_slices))); + intel_de_rmw(dev_priv, XELPDP_INITIATE_PMDEMAND_REQUEST(1), 0, + XELPDP_PMDEMAND_REQ_ENABLE); + + intel_pmdemand_wait(dev_priv); +unlock: + mutex_unlock(&dev_priv->display.pmdemand.lock); +} + +static void intel_program_pmdemand(struct drm_i915_private *dev_priv, + const struct intel_pmdemand_state *new, + const struct intel_pmdemand_state *old) +{ + u32 val, tmp; + +#define UPDATE_PMDEMAND_VAL(val, F, f) do { \ + val &= (~(XELPDP_PMDEMAND_##F##_MASK)); \ + val |= (XELPDP_PMDEMAND_##F((u32)(old ? max(old->f, new->f) : new->f))); \ +} while (0) + + mutex_lock(&dev_priv->display.pmdemand.lock); + if (drm_WARN_ON(&dev_priv->drm, + !intel_pmdemand_check_prev_transaction(dev_priv))) + goto unlock; + + /* + * TODO: Update programming PM Demand for + * PHYS, PLLS, DDI_CLKFREQ, SCALARS + */ + val = intel_de_read(dev_priv, XELPDP_INITIATE_PMDEMAND_REQUEST(0)); + UPDATE_PMDEMAND_VAL(val, QCLK_GV_INDEX, qclk_gv_index); + UPDATE_PMDEMAND_VAL(val, QCLK_GV_BW, qclk_gv_bw); + UPDATE_PMDEMAND_VAL(val, VOLTAGE_INDEX, voltage_index); + UPDATE_PMDEMAND_VAL(val, PIPES, active_pipes); + UPDATE_PMDEMAND_VAL(val, DBUFS, dbufs); + tmp = hweight32(new->active_phys_plls_mask); + if (old) + tmp = max(tmp, hweight32(old->active_phys_plls_mask)); + val |= XELPDP_PMDEMAND_PHYS(tmp); + + intel_de_write(dev_priv, XELPDP_INITIATE_PMDEMAND_REQUEST(0), val); + + val = intel_de_read(dev_priv, XELPDP_INITIATE_PMDEMAND_REQUEST(1)); + UPDATE_PMDEMAND_VAL(val, CDCLK_FREQ, cdclk_freq_mhz); + UPDATE_PMDEMAND_VAL(val, DDICLK_FREQ, ddiclk_freq_mhz); + UPDATE_PMDEMAND_VAL(val, SCALERS, scalers); + /* + * Active_PLLs starts with 1 because of CDCLK PLL. + * TODO: Missing to account genlock filter when it gets used. + */ + val |= XELPDP_PMDEMAND_PLLS(tmp + 1); + + intel_de_write(dev_priv, XELPDP_INITIATE_PMDEMAND_REQUEST(1), val); + +#undef UPDATE_PM_DEMAND_VAL + + intel_de_rmw(dev_priv, XELPDP_INITIATE_PMDEMAND_REQUEST(1), 0, XELPDP_PMDEMAND_REQ_ENABLE); + + intel_pmdemand_wait(dev_priv); +unlock: + mutex_unlock(&dev_priv->display.pmdemand.lock); +} + +void intel_pmdemand_pre_plane_update(struct intel_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + const struct intel_pmdemand_state *new_pmdmnd_state = + intel_atomic_get_new_pmdemand_state(state); + const struct intel_pmdemand_state *old_pmdmnd_state = + intel_atomic_get_old_pmdemand_state(state); + + if (DISPLAY_VER(dev_priv) < 14) + return; + + if (!new_pmdmnd_state || + memcmp(new_pmdmnd_state, old_pmdmnd_state, sizeof(*new_pmdmnd_state)) == 0) + return; + + intel_program_pmdemand(dev_priv, new_pmdmnd_state, old_pmdmnd_state); +} + +void intel_pmdemand_post_plane_update(struct intel_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + const struct intel_pmdemand_state *new_pmdmnd_state = + intel_atomic_get_new_pmdemand_state(state); + const struct intel_pmdemand_state *old_pmdmnd_state = + intel_atomic_get_old_pmdemand_state(state); + + if (DISPLAY_VER(dev_priv) < 14) + return; + + if (!new_pmdmnd_state || + memcmp(new_pmdmnd_state, old_pmdmnd_state, sizeof(*new_pmdmnd_state)) == 0) + return; + + intel_program_pmdemand(dev_priv, new_pmdmnd_state, NULL); +} + static void ibx_init_clock_gating(struct drm_i915_private *dev_priv) { /* diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h index c09b872d65c8..b4392dcdc0b6 100644 --- a/drivers/gpu/drm/i915/intel_pm.h +++ b/drivers/gpu/drm/i915/intel_pm.h @@ -8,6 +8,8 @@ #include +#include "display/intel_global_state.h" + struct drm_i915_private; struct intel_crtc_state; struct intel_plane_state; @@ -15,6 +17,7 @@ struct intel_plane_state; void intel_init_clock_gating(struct drm_i915_private *dev_priv); void intel_suspend_hw(struct drm_i915_private *dev_priv); int ilk_wm_max_level(const struct drm_i915_private *dev_priv); +void intel_init_pmdemand(struct drm_i915_private *dev_priv); void intel_init_pm(struct drm_i915_private *dev_priv); void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv); void intel_pm_setup(struct drm_i915_private *dev_priv); @@ -31,4 +34,36 @@ void intel_print_wm_latency(struct drm_i915_private *dev_priv, bool intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable); +struct intel_pmdemand_state { + struct intel_global_state base; + + u16 qclk_gv_bw; + u8 voltage_index; + u8 qclk_gv_index; + u8 active_pipes; + u8 dbufs; + u8 active_phys_plls_mask; + u16 cdclk_freq_mhz; + u16 ddiclk_freq_mhz; + u8 scalers; +}; + +int intel_pmdemand_init(struct drm_i915_private *dev_priv); + +struct intel_pmdemand_state * +intel_atomic_get_pmdemand_state(struct intel_atomic_state *state); + +#define to_intel_pmdemand_state(x) container_of((x), struct intel_pmdemand_state, base) +#define intel_atomic_get_old_pmdemand_state(state) \ + to_intel_pmdemand_state(intel_atomic_get_old_global_obj_state(state, &to_i915(state->base.dev)->display.pmdemand.obj)) +#define intel_atomic_get_new_pmdemand_state(state) \ + to_intel_pmdemand_state(intel_atomic_get_new_global_obj_state(state, &to_i915(state->base.dev)->display.pmdemand.obj)) + +int intel_pmdemand_init(struct drm_i915_private *dev_priv); +void intel_program_dbuf_pmdemand(struct drm_i915_private *dev_priv, + u8 dbuf_slices); +void intel_pmdemand_pre_plane_update(struct intel_atomic_state *state); +void intel_pmdemand_post_plane_update(struct intel_atomic_state *state); +int intel_pmdemand_atomic_check(struct intel_atomic_state *state); + #endif /* __INTEL_PM_H__ */ From patchwork Thu Jan 5 12:54:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089817 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 26BEBC3DA7A for ; Thu, 5 Jan 2023 12:59:56 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A07E210E71B; Thu, 5 Jan 2023 12:59:55 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 55F2610E71B for ; Thu, 5 Jan 2023 12:59:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923594; x=1704459594; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=0k2CxAgJsNhIvQaUr+G+PjkMIqAcmxEVneiSx7slwTw=; b=jX6dSeURHzQeK2befmnBdhoxolnxCqX7YodcwRvEkhf9YLWhZx4l21Yl /Hxsj4AGtTCjcZgPN4nMdC6tDCxs6+MOF5mzGELalOfQImWmixZsFarPD zfrpjOThjhPmg0RmyPN1oV4LYVHCmeii/GJCtXZkCcRKPsVX/kaEexOWj x+RnCmO8DZw7nrTmKp+Jes7lVXf9VJYPgb89jraVibAuZ8wcZsj1nW6U1 ps7WIuDCZsByxSb5kyV3iH3D1QEGB9dVWBmOQiFu35f0gp4DQB5n75amr d/bmdfcB6oawnGa8Fc1FbXEu8QEDp7KDkQjKGkKPJTewQ9kJCUX9rogJN w==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697777" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697777" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 04:59:53 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829540968" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829540968" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 04:59:51 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:33 +0200 Message-Id: <20230105125446.960504-9-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 08/21] drm/i915/mtl: C20 PLL programming 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" C20 phy PLL programming sequence for DP, DP2.0, HDMI2.x non-FRL and HDMI2.x FRL. This enables C20 MPLLA and MPLLB programming sequence. add 4 lane support for c20. Signed-off-by: José Roberto de Souza Signed-off-by: Mika Kahola Signed-off-by: Bhanuprakash Modem Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-9-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 279 +++++++++++++++--- .../gpu/drm/i915/display/intel_cx0_phy_regs.h | 30 ++ drivers/gpu/drm/i915/display/intel_ddi.c | 11 +- .../drm/i915/display/intel_display_types.h | 19 +- drivers/gpu/drm/i915/display/intel_dp.c | 12 +- 5 files changed, 311 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 3d86b0f1c36d..022888050a68 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -14,6 +14,7 @@ #include "intel_panel.h" #include "intel_psr.h" #include "intel_uncore.h" +#include "intel_tc.h" bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy) { @@ -234,6 +235,18 @@ static void intel_cx0_write(struct drm_i915_private *i915, enum port port, } } +static void intel_c20_write(struct drm_i915_private *i915, enum port port, + int lane, u16 addr, u16 data) +{ + assert_dc_off(i915); + + intel_cx0_write(i915, port, lane, PHY_C20_WR_ADDRESS_H, (addr >> 8) & 0xff, 0); + intel_cx0_write(i915, port, lane, PHY_C20_WR_ADDRESS_L, addr & 0xff, 0); + + intel_cx0_write(i915, port, lane, PHY_C20_WR_DATA_H, (data >> 8) & 0xff, 0); + intel_cx0_write(i915, port, lane, PHY_C20_WR_DATA_L, data & 0xff, 1); +} + static void __intel_cx0_rmw(struct drm_i915_private *i915, enum port port, int lane, u16 addr, u8 clear, u8 set, bool committed) { @@ -1155,7 +1168,7 @@ static int intel_c10mpllb_calc_state(struct intel_crtc_state *crtc_state, for (i = 0; tables[i]; i++) { if (crtc_state->port_clock <= tables[i]->clock) { - crtc_state->c10mpllb_state = *tables[i]; + crtc_state->cx0pll_state.c10mpllb_state = *tables[i]; return 0; } } @@ -1215,7 +1228,7 @@ static void intel_c10_pll_program(struct drm_i915_private *i915, const struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) { - const struct intel_c10mpllb_state *pll_state = &crtc_state->c10mpllb_state; + const struct intel_c10mpllb_state *pll_state = &crtc_state->cx0pll_state.c10mpllb_state; struct intel_digital_port *dig_port = enc_to_dig_port(encoder); bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL; u8 master_lane = lane_reversal ? INTEL_CX0_LANE1 : @@ -1299,6 +1312,218 @@ void intel_c10mpllb_dump_hw_state(struct drm_i915_private *dev_priv, i + 2, hw_state->pll[i + 2], i + 3, hw_state->pll[i + 3]); } +static bool intel_c20_use_mplla(u32 clock) +{ + /* 10G and 20G rates use MPLLA */ + if (clock == 312500 || clock == 625000) + return true; + + return false; +} + +static u8 intel_c20_get_dp_rate(u32 clock) +{ + switch (clock) { + case 162000: /* 1.62 Gbps DP1.4 */ + return 0; + case 270000: /* 2.7 Gbps DP1.4 */ + return 1; + case 540000: /* 5.4 Gbps DP 1.4 */ + return 2; + case 810000: /* 8.1 Gbps DP1.4 */ + return 3; + case 216000: /* 2.16 Gbps eDP */ + return 4; + case 243000: /* 2.43 Gbps eDP */ + return 5; + case 324000: /* 3.24 Gbps eDP */ + return 6; + case 432000: /* 4.32 Gbps eDP */ + return 7; + case 312500: /* 10 Gbps DP2.0 */ + return 8; + case 421875: /* 13.5 Gbps DP2.0 */ + return 9; + case 625000: /* 20 Gbps DP2.0*/ + return 10; + default: + MISSING_CASE(clock); + return 0; + } +} + +static u8 intel_c20_get_hdmi_rate(u32 clock) +{ + switch (clock) { + case 25175: + case 27000: + case 74250: + case 148500: + case 594000: + return 0; + case 166670: /* 3 Gbps */ + case 333330: /* 6 Gbps */ + case 666670: /* 12 Gbps */ + return 1; + case 444440: /* 8 Gbps */ + return 2; + case 555560: /* 10 Gbps */ + return 3; + default: + MISSING_CASE(clock); + return 0; + } +} + +static bool is_dp2(u32 clock) +{ + /* DP2.0 clock rates */ + if (clock == 312500 || clock == 421875 || clock == 625000) + return true; + + return false; +} + +static bool is_hdmi_frl(u32 clock) +{ + switch (clock) { + case 166670: /* 3 Gbps */ + case 333330: /* 6 Gbps */ + case 444440: /* 8 Gbps */ + case 555560: /* 10 Gbps */ + case 666670: /* 12 Gbps */ + return true; + default: + return false; + } +} + +static bool intel_c20_protocol_switch_valid(struct intel_encoder *encoder) +{ + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + + /* banks should not be cleared for DPALT/USB4/TBT modes */ + /* TODO: optimize re-calibration in legacy mode */ + return intel_tc_port_in_legacy_mode(intel_dig_port); +} + +static void intel_c20_pll_program(struct drm_i915_private *i915, + const struct intel_crtc_state *crtc_state, + struct intel_encoder *encoder) +{ + const struct intel_c20pll_state *pll_state = &crtc_state->cx0pll_state.c20pll_state; + bool dp = false; + int lane_count = crtc_state->lane_count; + bool cntx; + int i; + + if (intel_crtc_has_dp_encoder(crtc_state)) + dp = true; + + /* 1. Read current context selection */ + cntx = intel_cx0_read(i915, encoder->port, INTEL_CX0_LANE0, PHY_C20_VDR_CUSTOM_SERDES_RATE) & + PHY_C20_CONTEXT_TOGGLE; + + /* 2. If there is a protocol switch from HDMI to DP or vice versa, clear + * the lane #0 MPLLB CAL_DONE_BANK DP2.0 10G and 20G rates enable MPLLA. + * Protocol switch is only applicable for MPLLA + */ + if (intel_c20_protocol_switch_valid(encoder)) { + for (i = 0; i < 4; i++) + intel_c20_write(i915, encoder->port, INTEL_CX0_LANE0, RAWLANEAONX_DIG_TX_MPLLB_CAL_DONE_BANK(i), 0); + } + + /* 3. Write SRAM configuration context. If A in use, write configuration to B context */ + /* 3.1 Tx configuration */ + for (i = 0; i < 3; i++) { + if (cntx) + intel_c20_write(i915, encoder->port, INTEL_CX0_LANE0, PHY_C20_A_TX_CNTX_CFG(i), pll_state->tx[i]); + else + intel_c20_write(i915, encoder->port, INTEL_CX0_LANE0, PHY_C20_B_TX_CNTX_CFG(i), pll_state->tx[i]); + } + + /* 3.2 common configuration */ + for (i = 0; i < 4; i++) { + if (cntx) + intel_c20_write(i915, encoder->port, INTEL_CX0_LANE0, PHY_C20_A_CMN_CNTX_CFG(i), pll_state->cmn[i]); + else + intel_c20_write(i915, encoder->port, INTEL_CX0_LANE0, PHY_C20_B_CMN_CNTX_CFG(i), pll_state->cmn[i]); + } + + /* 3.3 mpllb or mplla configuration */ + if (intel_c20_use_mplla(pll_state->clock)) { + for (i = 0; i < 10; i++) { + if (cntx) + intel_c20_write(i915, encoder->port, INTEL_CX0_LANE0, + PHY_C20_A_MPLLA_CNTX_CFG(i), + pll_state->mplla[i]); + else + intel_c20_write(i915, encoder->port, INTEL_CX0_LANE0, + PHY_C20_B_MPLLA_CNTX_CFG(i), + pll_state->mplla[i]); + } + } else { + for (i = 0; i < 11; i++) { + if (cntx) + intel_c20_write(i915, encoder->port, INTEL_CX0_LANE0, + PHY_C20_A_MPLLB_CNTX_CFG(i), + pll_state->mpllb[i]); + else + intel_c20_write(i915, encoder->port, INTEL_CX0_LANE0, + PHY_C20_B_MPLLB_CNTX_CFG(i), + pll_state->mpllb[i]); + } + } + + /* 4. Program custom width to match the link protocol */ + if (dp) { + intel_cx0_write(i915, encoder->port, INTEL_CX0_LANE0, PHY_C20_VDR_CUSTOM_WIDTH, + is_dp2(pll_state->clock) ? 2 : 0, + MB_WRITE_COMMITTED); + if (lane_count == 4) + intel_cx0_write(i915, encoder->port, INTEL_CX0_LANE1, PHY_C20_VDR_CUSTOM_WIDTH, + is_dp2(pll_state->clock) ? 2 : 0, + MB_WRITE_COMMITTED); + } else if (is_hdmi_frl(pll_state->clock)) { + intel_cx0_write(i915, encoder->port, INTEL_CX0_LANE0, PHY_C20_VDR_CUSTOM_WIDTH, + 1, MB_WRITE_COMMITTED); + if (lane_count == 4) + intel_cx0_write(i915, encoder->port, INTEL_CX0_LANE1, + PHY_C20_VDR_CUSTOM_WIDTH, 1, MB_WRITE_COMMITTED); + } else + intel_cx0_write(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C20_VDR_CUSTOM_WIDTH, + 0, MB_WRITE_COMMITTED); + + /* 5. For DP or 6. For HDMI */ + if (dp) { + intel_cx0_write(i915, encoder->port, INTEL_CX0_LANE0, PHY_C20_VDR_CUSTOM_SERDES_RATE, + BIT(6) | (intel_c20_get_dp_rate(pll_state->clock) << 1), + MB_WRITE_COMMITTED); + if (lane_count == 4) + intel_cx0_write(i915, encoder->port, INTEL_CX0_LANE1, PHY_C20_VDR_CUSTOM_SERDES_RATE, + BIT(6) | (intel_c20_get_dp_rate(pll_state->clock) << 1), + MB_WRITE_COMMITTED); + } else { + intel_cx0_write(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C20_VDR_CUSTOM_SERDES_RATE, + ((is_hdmi_frl(pll_state->clock) ? 1 : 0) << 7), + MB_WRITE_COMMITTED); + + intel_cx0_write(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C20_VDR_HDMI_RATE, + (intel_c20_get_hdmi_rate(pll_state->clock) << 0), + MB_WRITE_COMMITTED); + } + + /* + * 7. Write Vendor specific registers to toggle context setting to load + * the updated programming toggle context bit + */ + intel_cx0_write(i915, encoder->port, INTEL_CX0_LANE0, PHY_C20_VDR_CUSTOM_SERDES_RATE, + cntx ? 0 : 1, MB_WRITE_COMMITTED); + if (lane_count == 4) + intel_cx0_write(i915, encoder->port, INTEL_CX0_LANE1, PHY_C20_VDR_CUSTOM_SERDES_RATE, + cntx ? 0 : 1, MB_WRITE_COMMITTED); +} + int intel_c10mpllb_calc_port_clock(struct intel_encoder *encoder, const struct intel_c10mpllb_state *pll_state) { @@ -1342,7 +1567,11 @@ static void intel_program_port_clock_ctl(struct intel_encoder *encoder, val |= XELPDP_LANE1_PHY_CLOCK_SELECT; val |= XELPDP_FORWARD_CLOCK_UNGATE; - val |= XELPDP_DDI_CLOCK_SELECT(XELPDP_DDI_CLOCK_SELECT_MAXPCLK); + + if (is_hdmi_frl(crtc_state->port_clock)) + val |= XELPDP_DDI_CLOCK_SELECT(XELPDP_DDI_CLOCK_SELECT_DIV18CLK); + else + val |= XELPDP_DDI_CLOCK_SELECT(XELPDP_DDI_CLOCK_SELECT_MAXPCLK); if (intel_crtc_has_dp_encoder(crtc_state)) { intel_dp = enc_to_intel_dp(encoder); @@ -1588,8 +1817,8 @@ static u32 intel_cx0_get_pclk_pll_ack(u8 lane) XELPDP_LANE1_PCLK_PLL_ACK; } -static void intel_c10pll_enable(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +void intel_cx0pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(i915, encoder->port); @@ -1597,6 +1826,7 @@ static void intel_c10pll_enable(struct intel_encoder *encoder, bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL; u8 maxpclk_lane = lane_reversal ? INTEL_CX0_LANE1 : INTEL_CX0_LANE0; + intel_wakeref_t wakeref = intel_cx0_phy_transaction_begin(encoder); /* * 1. Program PORT_CLOCK_CTL REGISTER to configure @@ -1615,7 +1845,10 @@ static void intel_c10pll_enable(struct intel_encoder *encoder, CX0_P2_STATE_READY); /* 4. Program PHY internal PLL internal registers. */ - intel_c10_pll_program(i915, crtc_state, encoder); + if (intel_is_c10phy(i915, phy)) + intel_c10_pll_program(i915, crtc_state, encoder); + else + intel_c20_pll_program(i915, crtc_state, encoder); /* * 5. Program the enabled and disabled owned PHY lane @@ -1654,31 +1887,21 @@ static void intel_c10pll_enable(struct intel_encoder *encoder, * 10. Follow the Display Voltage Frequency Switching Sequence After * Frequency Change. We handle this step in bxt_set_cdclk(). */ -} - -void intel_cx0pll_enable(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(i915, encoder->port); - intel_wakeref_t wakeref; - - wakeref = intel_cx0_phy_transaction_begin(encoder); - - drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); - intel_c10pll_enable(encoder, crtc_state); intel_cx0_phy_transaction_end(encoder, wakeref); } -static void intel_c10pll_disable(struct intel_encoder *encoder) +void intel_cx0pll_disable(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(i915, encoder->port); + bool is_c10 = intel_is_c10phy(i915, phy); + intel_wakeref_t wakeref = intel_cx0_phy_transaction_begin(encoder); /* 1. Change owned PHY lane power to Disable state. */ intel_cx0_powerdown_change_sequence(i915, encoder->port, INTEL_CX0_BOTH_LANES, - CX0_P2PG_STATE_DISABLE); + is_c10 ? CX0_P2PG_STATE_DISABLE : + CX0_P4PG_STATE_DISABLE); /* * 2. Follow the Display Voltage Frequency Switching Sequence Before @@ -1716,18 +1939,6 @@ static void intel_c10pll_disable(struct intel_encoder *encoder) XELPDP_DDI_CLOCK_SELECT_MASK, 0); intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), XELPDP_FORWARD_CLOCK_UNGATE, 0); -} - -void intel_cx0pll_disable(struct intel_encoder *encoder) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(i915, encoder->port); - intel_wakeref_t wakeref; - - wakeref = intel_cx0_phy_transaction_begin(encoder); - - drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); - intel_c10pll_disable(encoder); intel_cx0_phy_transaction_end(encoder, wakeref); } @@ -1737,7 +1948,7 @@ void intel_c10mpllb_state_verify(struct intel_atomic_state *state, { struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_c10mpllb_state mpllb_hw_state = { 0 }; - struct intel_c10mpllb_state *mpllb_sw_state = &new_crtc_state->c10mpllb_state; + struct intel_c10mpllb_state *mpllb_sw_state = &new_crtc_state->cx0pll_state.c10mpllb_state; struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); struct intel_encoder *encoder; struct intel_dp *intel_dp; diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h index fd48c75ee532..794372f4798d 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h @@ -175,4 +175,34 @@ #define C10_PHY_VSWING_PREEMPH_MASK REG_GENMASK8(1, 0) #define C10_PHY_VSWING_PREEMPH(val) REG_FIELD_PREP8(C10_PHY_VSWING_PREEMPH_MASK, val) +/* C20 Registers */ +#define PHY_C20_WR_ADDRESS_L 0xC02 +#define PHY_C20_WR_ADDRESS_H 0xC03 +#define PHY_C20_WR_DATA_L 0xC04 +#define PHY_C20_WR_DATA_H 0xC05 +#define PHY_C20_RD_ADDRESS_L 0xC06 +#define PHY_C20_RD_ADDRESS_H 0xC07 +#define PHY_C20_RD_DATA_L 0xC08 +#define PHY_C20_RD_DATA_H 0xC09 +#define PHY_C20_VDR_CUSTOM_SERDES_RATE 0xD00 +#define PHY_C20_VDR_HDMI_RATE 0xD01 +#define PHY_C20_CONTEXT_TOGGLE REG_BIT8(0) +#define PHY_C20_VDR_CUSTOM_WIDTH 0xD02 +#define PHY_C20_A_TX_CNTX_CFG(idx) (0xCF2E - (idx)) +#define PHY_C20_B_TX_CNTX_CFG(idx) (0xCF2A - (idx)) +#define PHY_C20_A_CMN_CNTX_CFG(idx) (0xCDAA - (idx)) +#define PHY_C20_B_CMN_CNTX_CFG(idx) (0xCDA5 - (idx)) +#define PHY_C20_A_MPLLA_CNTX_CFG(idx) (0xCCF0 - (idx)) +#define PHY_C20_B_MPLLA_CNTX_CFG(idx) (0xCCE5 - (idx)) +#define PHY_C20_A_MPLLB_CNTX_CFG(idx) (0xCB5A - (idx)) +#define PHY_C20_B_MPLLB_CNTX_CFG(idx) (0xCB4E - (idx)) + +#define C20_MPLLB_FRACEN REG_BIT(13) +#define C20_MPLLA_FRACEN REG_BIT(14) +#define C20_MULTIPLIER_MASK REG_GENMASK(11, 0) +#define C20_MPLLB_TX_CLK_DIV_MASK REG_GENMASK(15, 13) +#define C20_MPLLA_TX_CLK_DIV_MASK REG_GENMASK(10, 8) + +#define RAWLANEAONX_DIG_TX_MPLLB_CAL_DONE_BANK(idx) (0x303D + (idx)) + #endif /* __INTEL_CX0_PHY_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index e796e5cf10f0..a5fbc4fed28d 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3078,6 +3078,11 @@ intel_ddi_update_prepare(struct intel_atomic_state *state, intel_tc_port_get_link(enc_to_dig_port(encoder), required_lanes); + + /* FIXME: Add MTL pll_mgr */ + if (DISPLAY_VER(i915) >= 14) + return; + if (crtc_state && crtc_state->hw.active) { struct intel_crtc *slave_crtc; @@ -3529,9 +3534,9 @@ static void mtl_ddi_get_config(struct intel_encoder *encoder, drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); - intel_c10mpllb_readout_hw_state(encoder, &crtc_state->c10mpllb_state); - intel_c10mpllb_dump_hw_state(i915, &crtc_state->c10mpllb_state); - crtc_state->port_clock = intel_c10mpllb_calc_port_clock(encoder, &crtc_state->c10mpllb_state); + intel_c10mpllb_readout_hw_state(encoder, &crtc_state->cx0pll_state.c10mpllb_state); + intel_c10mpllb_dump_hw_state(i915, &crtc_state->cx0pll_state.c10mpllb_state); + crtc_state->port_clock = intel_c10mpllb_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10mpllb_state); intel_ddi_get_config(encoder, crtc_state); } diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index fdd65781ae40..4a69727fbb91 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -983,6 +983,23 @@ struct intel_c10mpllb_state { u8 pll[20]; }; +struct intel_c20pll_state { + u32 clock; /* in kHz */ + u16 tx[3]; + u16 cmn[4]; + union { + u16 mplla[10]; + u16 mpllb[11]; + }; +}; + +struct intel_cx0pll_state { + union { + struct intel_c10mpllb_state c10mpllb_state; + struct intel_c20pll_state c20pll_state; + }; +}; + struct intel_crtc_state { /* * uapi (drm) state. This is the software state shown to userspace. @@ -1126,7 +1143,7 @@ struct intel_crtc_state { union { struct intel_dpll_hw_state dpll_hw_state; struct intel_mpllb_state mpllb_state; - struct intel_c10mpllb_state c10mpllb_state; + struct intel_cx0pll_state cx0pll_state; }; /* diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 0b08e9b6ea22..9e06bf10ce8d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -53,6 +53,7 @@ #include "intel_combo_phy_regs.h" #include "intel_connector.h" #include "intel_crtc.h" +#include "intel_cx0_phy.h" #include "intel_ddi.h" #include "intel_de.h" #include "intel_display_types.h" @@ -422,7 +423,14 @@ static int ehl_max_source_rate(struct intel_dp *intel_dp) static int mtl_max_source_rate(struct intel_dp *intel_dp) { - return intel_dp_is_edp(intel_dp) ? 675000 : 810000; + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + enum phy phy = intel_port_to_phy(i915, dig_port->base.port); + + if (intel_is_c10phy(i915, phy)) + return intel_dp_is_edp(intel_dp) ? 675000 : 810000; + + return 2000000; } static int vbt_max_link_rate(struct intel_dp *intel_dp) @@ -451,7 +459,7 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) /* The values must be in increasing order */ static const int mtl_rates[] = { 162000, 216000, 243000, 270000, 324000, 432000, 540000, 675000, - 810000, + 810000, 1000000, 1350000, 2000000, }; static const int icl_rates[] = { 162000, 216000, 270000, 324000, 432000, 540000, 648000, 810000, From patchwork Thu Jan 5 12:54:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089818 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 77018C3DA7A for ; Thu, 5 Jan 2023 12:59:59 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id CF83C10E71E; Thu, 5 Jan 2023 12:59:58 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 40B1410E71E for ; Thu, 5 Jan 2023 12:59:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923596; x=1704459596; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=2xu2rxqHGAps1JgKmUvJTjiWG+xH440XJB6N0Xc3yPs=; b=eo+fbT4ATbOSQtZiEKGI5mQy7mv6HWTckGH7bKU2UY14A+6KCJRwRQ/W rern5/ahlpXFUDC8EmFjJB56aq2kr/Gesiy8eCNbkHg8Kp37E46/vLHYn e0thWOevdAUCnQLBRHKv7vUy0pYJuTW57i456Z2X7p9ovyXBb86xLY9/z fH8suriVhv01i3kqaM7FKxMLaTBqcgt57fUPEXhqRb0cPb3dEFcpXRI65 7Nxxk1RYa6/guWB858ESZQvZgwEQLi6TyqGHyeyLGoLLZnzzgtJ0smmCt chO3a9vYVQhp5hIrUAWgSctzxeRdoRMx7mDmOsGHFJDpnFrlT590ctRUc w==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697789" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697789" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 04:59:56 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829540981" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829540981" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 04:59:54 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:34 +0200 Message-Id: <20230105125446.960504-10-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 09/21] drm/i915/mtl: C20 HW readout 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Create a table for C20 DP1.4, DP2.0 and HDMI2.1 rates. The PLL settings are based on table, not for algorithmic alternative. For DP 1.4 only MPLLB is in use. Once register settings are done, we read back C20 HW state. BSpec: 64568 v2: Update rbr, hbr1, hbr2, and hbr3 pll configurations 4 and 5 based on changes in BSpec consolidated table Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-10-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 495 ++++++++++++++++++- drivers/gpu/drm/i915/display/intel_cx0_phy.h | 10 +- drivers/gpu/drm/i915/display/intel_ddi.c | 9 +- drivers/gpu/drm/i915/display/intel_hdmi.c | 6 +- drivers/gpu/drm/i915/display/intel_hdmi.h | 1 + 5 files changed, 513 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 022888050a68..285e4cdd23eb 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -11,6 +11,7 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_dp.h" +#include "intel_hdmi.h" #include "intel_panel.h" #include "intel_psr.h" #include "intel_uncore.h" @@ -247,6 +248,23 @@ static void intel_c20_write(struct drm_i915_private *i915, enum port port, intel_cx0_write(i915, port, lane, PHY_C20_WR_DATA_L, data & 0xff, 1); } +static u16 intel_c20_read(struct drm_i915_private *i915, enum port port, + int lane, u16 addr) +{ + u16 val; + + assert_dc_off(i915); + + intel_cx0_write(i915, port, lane, PHY_C20_RD_ADDRESS_L, addr & 0xff, 0); + intel_cx0_write(i915, port, lane, PHY_C20_RD_ADDRESS_H, (addr >> 8) & 0xff, 1); + + val = intel_cx0_read(i915, port, lane, PHY_C20_RD_DATA_H); + val <<= 8; + val |= intel_cx0_read(i915, port, lane, PHY_C20_RD_DATA_L); + + return val; +} + static void __intel_cx0_rmw(struct drm_i915_private *i915, enum port port, int lane, u16 addr, u8 clear, u8 set, bool committed) { @@ -588,6 +606,192 @@ static const struct intel_c10mpllb_state * const mtl_c10_edp_tables[] = { NULL, }; +/* C20 basic DP 1.4 tables */ +static const struct intel_c20pll_state mtl_c20_dp_rbr = { + .clock = 162000, + .tx = { 0xbe88, /* tx cfg0 */ + 0x5800, /* tx cfg1 */ + 0x0000, /* tx cfg2 */ + }, + .cmn = {0x0500, /* cmn cfg0*/ + 0x0005, /* cmn cfg1 */ + 0x0000, /* cmn cfg2 */ + 0x0000, /* cmn cfg3 */ + }, + .mpllb = { 0x50a8, /* mpllb cfg0 */ + 0x2120, /* mpllb cfg1 */ + 0xcd9a, /* mpllb cfg2 */ + 0xbfc1, /* mpllb cfg3 */ + 0x5ab8, /* mpllb cfg4 */ + 0x4c34, /* mpllb cfg5 */ + 0x2000, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x6000, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0000, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_dp_hbr1 = { + .clock = 270000, + .tx = { 0xbe88, /* tx cfg0 */ + 0x4800, /* tx cfg1 */ + 0x0000, /* tx cfg2 */ + }, + .cmn = {0x0500, /* cmn cfg0*/ + 0x0005, /* cmn cfg1 */ + 0x0000, /* cmn cfg2 */ + 0x0000, /* cmn cfg3 */ + }, + .mpllb = { 0x308c, /* mpllb cfg0 */ + 0x2110, /* mpllb cfg1 */ + 0xcc9c, /* mpllb cfg2 */ + 0xbfc1, /* mpllb cfg3 */ + 0x489a, /* mpllb cfg4 */ + 0x3f81, /* mpllb cfg5 */ + 0x2000, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x5000, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0000, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_dp_hbr2 = { + .clock = 540000, + .tx = { 0xbe88, /* tx cfg0 */ + 0x4800, /* tx cfg1 */ + 0x0000, /* tx cfg2 */ + }, + .cmn = {0x0500, /* cmn cfg0*/ + 0x0005, /* cmn cfg1 */ + 0x0000, /* cmn cfg2 */ + 0x0000, /* cmn cfg3 */ + }, + .mpllb = { 0x108c, /* mpllb cfg0 */ + 0x2108, /* mpllb cfg1 */ + 0xcc9c, /* mpllb cfg2 */ + 0xbfc1, /* mpllb cfg3 */ + 0x489a, /* mpllb cfg4 */ + 0x3f81, /* mpllb cfg5 */ + 0x2000, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x5000, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0000, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_dp_hbr3 = { + .clock = 810000, + .tx = { 0xbe88, /* tx cfg0 */ + 0x4800, /* tx cfg1 */ + 0x0000, /* tx cfg2 */ + }, + .cmn = {0x0500, /* cmn cfg0*/ + 0x0005, /* cmn cfg1 */ + 0x0000, /* cmn cfg2 */ + 0x0000, /* cmn cfg3 */ + }, + .mpllb = { 0x10d2, /* mpllb cfg0 */ + 0x2108, /* mpllb cfg1 */ + 0x8d98, /* mpllb cfg2 */ + 0xbfc1, /* mpllb cfg3 */ + 0x7166, /* mpllb cfg4 */ + 0x5f42, /* mpllb cfg5 */ + 0x2000, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x7800, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0000, /* mpllb cfg10 */ + }, +}; + +/* C20 basic DP 2.0 tables */ +static const struct intel_c20pll_state mtl_c20_dp_uhbr10 = { + .clock = 312500, + .tx = { 0xbe21, /* tx cfg0 */ + 0x4800, /* tx cfg1 */ + 0x0000, /* tx cfg2 */ + }, + .cmn = {0x0500, /* cmn cfg0*/ + 0x0005, /* cmn cfg1 */ + 0x0000, /* cmn cfg2 */ + 0x0000, /* cmn cfg3 */ + }, + .mplla = { 0x3104, /* mplla cfg0 */ + 0xd105, /* mplla cfg1 */ + 0xc025, /* mplla cfg2 */ + 0xc025, /* mplla cfg3 */ + 0xa6ab, /* mplla cfg4 */ + 0x8c00, /* mplla cfg5 */ + 0x4000, /* mplla cfg6 */ + 0x0003, /* mplla cfg7 */ + 0x3555, /* mplla cfg8 */ + 0x0001, /* mplla cfg9 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_dp_uhbr13_5 = { + .clock = 421875, + .tx = { 0xbea0, /* tx cfg0 */ + 0x4800, /* tx cfg1 */ + 0x0000, /* tx cfg2 */ + }, + .cmn = {0x0500, /* cmn cfg0*/ + 0x0005, /* cmn cfg1 */ + 0x0000, /* cmn cfg2 */ + 0x0000, /* cmn cfg3 */ + }, + .mpllb = { 0x015f, /* mpllb cfg0 */ + 0x2205, /* mpllb cfg1 */ + 0x1b17, /* mpllb cfg2 */ + 0xffc1, /* mpllb cfg3 */ + 0xe100, /* mpllb cfg4 */ + 0xbd00, /* mpllb cfg5 */ + 0x2000, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x4800, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0000, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_dp_uhbr20 = { + .clock = 625000, + .tx = { 0xbe20, /* tx cfg0 */ + 0x4800, /* tx cfg1 */ + 0x0000, /* tx cfg2 */ + }, + .cmn = {0x0500, /* cmn cfg0*/ + 0x0005, /* cmn cfg1 */ + 0x0000, /* cmn cfg2 */ + 0x0000, /* cmn cfg3 */ + }, + .mplla = { 0x3104, /* mplla cfg0 */ + 0xd105, /* mplla cfg1 */ + 0xc025, /* mplla cfg2 */ + 0xc025, /* mplla cfg3 */ + 0xa6ab, /* mplla cfg4 */ + 0x8c00, /* mplla cfg5 */ + 0x4000, /* mplla cfg6 */ + 0x0003, /* mplla cfg7 */ + 0x3555, /* mplla cfg8 */ + 0x0001, /* mplla cfg9 */ + }, +}; + +static const struct intel_c20pll_state * const mtl_c20_dp_tables[] = { + &mtl_c20_dp_rbr, + &mtl_c20_dp_hbr1, + &mtl_c20_dp_hbr2, + &mtl_c20_dp_hbr3, + &mtl_c20_dp_uhbr10, + &mtl_c20_dp_uhbr13_5, + &mtl_c20_dp_uhbr20, + NULL, +}; + /* * HDMI link rates with 38.4 MHz reference clock. */ @@ -1115,7 +1319,181 @@ static const struct intel_c10mpllb_state * const mtl_c10_hdmi_tables[] = { NULL, }; -int intel_c10_phy_check_hdmi_link_rate(int clock) +static const struct intel_c20pll_state mtl_c20_hdmi_25_175 = { + .clock = 25175, + .mpllb = { 0xa0d2, /* mpllb cfg0 */ + 0x7d80, /* mpllb cfg1 */ + 0x0906, /* mpllb cfg2 */ + 0xbe40, /* mpllb cfg3 */ + 0x0000, /* mpllb cfg4 */ + 0x0000, /* mpllb cfg5 */ + 0x0200, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x0000, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0001, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_hdmi_27_0 = { + .clock = 27000, + .mpllb = { 0xa0e0, /* mpllb cfg0 */ + 0x7d80, /* mpllb cfg1 */ + 0x0906, /* mpllb cfg2 */ + 0xbe40, /* mpllb cfg3 */ + 0x0000, /* mpllb cfg4 */ + 0x0000, /* mpllb cfg5 */ + 0x2200, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x8000, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0001, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_hdmi_74_25 = { + .clock = 74250, + .mpllb = { 0x609a, /* mpllb cfg0 */ + 0x7d40, /* mpllb cfg1 */ + 0xca06, /* mpllb cfg2 */ + 0xbe40, /* mpllb cfg3 */ + 0x0000, /* mpllb cfg4 */ + 0x0000, /* mpllb cfg5 */ + 0x2200, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x5800, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0001, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_hdmi_148_5 = { + .clock = 148500, + .mpllb = { 0x409a, /* mpllb cfg0 */ + 0x7d20, /* mpllb cfg1 */ + 0xca06, /* mpllb cfg2 */ + 0xbe40, /* mpllb cfg3 */ + 0x0000, /* mpllb cfg4 */ + 0x0000, /* mpllb cfg5 */ + 0x2200, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x5800, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0001, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_hdmi_594 = { + .clock = 594000, + .mpllb = { 0x009a, /* mpllb cfg0 */ + 0x7d08, /* mpllb cfg1 */ + 0xca06, /* mpllb cfg2 */ + 0xbe40, /* mpllb cfg3 */ + 0x0000, /* mpllb cfg4 */ + 0x0000, /* mpllb cfg5 */ + 0x2200, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x5800, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0001, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_hdmi_300 = { + .clock = 166670, + .mpllb = { 0x209c, /* mpllb cfg0 */ + 0x7d10, /* mpllb cfg1 */ + 0xca06, /* mpllb cfg2 */ + 0xbe40, /* mpllb cfg3 */ + 0x0000, /* mpllb cfg4 */ + 0x0000, /* mpllb cfg5 */ + 0x2200, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x2000, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0004, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_hdmi_600 = { + .clock = 333330, + .mpllb = { 0x009c, /* mpllb cfg0 */ + 0x7d08, /* mpllb cfg1 */ + 0xca06, /* mpllb cfg2 */ + 0xbe40, /* mpllb cfg3 */ + 0x0000, /* mpllb cfg4 */ + 0x0000, /* mpllb cfg5 */ + 0x2200, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x2000, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0004, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_hdmi_800 = { + .clock = 444440, + .mpllb = { 0x00d0, /* mpllb cfg0 */ + 0x7d08, /* mpllb cfg1 */ + 0x4a06, /* mpllb cfg2 */ + 0xbe40, /* mpllb cfg3 */ + 0x0000, /* mpllb cfg4 */ + 0x0000, /* mpllb cfg5 */ + 0x2200, /* mpllb cfg6 */ + 0x0003, /* mpllb cfg7 */ + 0x2aaa, /* mpllb cfg8 */ + 0x0002, /* mpllb cfg9 */ + 0x0004, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_hdmi_1000 = { + .clock = 555560, + .mpllb = { 0x1104, /* mpllb cfg0 */ + 0x7d08, /* mpllb cfg1 */ + 0x0a06, /* mpllb cfg2 */ + 0xbe40, /* mpllb cfg3 */ + 0x0000, /* mpllb cfg4 */ + 0x0000, /* mpllb cfg5 */ + 0x2200, /* mpllb cfg6 */ + 0x0003, /* mpllb cfg7 */ + 0x3555, /* mpllb cfg8 */ + 0x0001, /* mpllb cfg9 */ + 0x0004, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state mtl_c20_hdmi_1200 = { + .clock = 666670, + .mpllb = { 0x0138, /* mpllb cfg0 */ + 0x7d08, /* mpllb cfg1 */ + 0x5486, /* mpllb cfg2 */ + 0xfe40, /* mpllb cfg3 */ + 0x0000, /* mpllb cfg4 */ + 0x0000, /* mpllb cfg5 */ + 0x2200, /* mpllb cfg6 */ + 0x0001, /* mpllb cfg7 */ + 0x4000, /* mpllb cfg8 */ + 0x0000, /* mpllb cfg9 */ + 0x0004, /* mpllb cfg10 */ + }, +}; + +static const struct intel_c20pll_state * const mtl_c20_hdmi_tables[] = { + &mtl_c20_hdmi_25_175, + &mtl_c20_hdmi_27_0, + &mtl_c20_hdmi_74_25, + &mtl_c20_hdmi_148_5, + &mtl_c20_hdmi_594, + &mtl_c20_hdmi_300, + &mtl_c20_hdmi_600, + &mtl_c20_hdmi_800, + &mtl_c20_hdmi_1000, + &mtl_c20_hdmi_1200, + NULL, +}; + +static int intel_c10_phy_check_hdmi_link_rate(int clock) { const struct intel_c10mpllb_state * const *tables = mtl_c10_hdmi_tables; int i; @@ -1128,6 +1506,17 @@ int intel_c10_phy_check_hdmi_link_rate(int clock) return MODE_CLOCK_RANGE; } +int intel_cx0_phy_check_hdmi_link_rate(struct intel_hdmi *hdmi, int clock) +{ + struct intel_digital_port *dig_port = hdmi_to_dig_port(hdmi); + struct drm_i915_private *i915 = intel_hdmi_to_i915(hdmi); + enum phy phy = intel_port_to_phy(i915, dig_port->base.port); + + if (intel_is_c10phy(i915, phy)) + return intel_c10_phy_check_hdmi_link_rate(clock); + return intel_c20_phy_check_hdmi_link_rate(clock); +} + static const struct intel_c10mpllb_state * const * intel_c10_mpllb_tables_get(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) @@ -1312,6 +1701,53 @@ void intel_c10mpllb_dump_hw_state(struct drm_i915_private *dev_priv, i + 2, hw_state->pll[i + 2], i + 3, hw_state->pll[i + 3]); } +int intel_c20_phy_check_hdmi_link_rate(int clock) +{ + const struct intel_c20pll_state * const *tables = mtl_c20_hdmi_tables; + int i; + + for (i = 0; tables[i]; i++) { + if (clock == tables[i]->clock) + return MODE_OK; + } + + return MODE_CLOCK_RANGE; +} + +static const struct intel_c20pll_state * const * +intel_c20_pll_tables_get(struct intel_crtc_state *crtc_state, + struct intel_encoder *encoder) +{ + if (intel_crtc_has_dp_encoder(crtc_state)) { + return mtl_c20_dp_tables; + } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) { + return mtl_c20_hdmi_tables; + } + + MISSING_CASE(encoder->type); + return NULL; +} + +int intel_c20pll_calc_state(struct intel_crtc_state *crtc_state, + struct intel_encoder *encoder) +{ + const struct intel_c20pll_state * const *tables; + int i; + + tables = intel_c20_pll_tables_get(crtc_state, encoder); + if (!tables) + return -EINVAL; + + for (i = 0; tables[i]; i++) { + if (crtc_state->port_clock <= tables[i]->clock) { + crtc_state->cx0pll_state.c20pll_state = *tables[i]; + return 0; + } + } + + return -EINVAL; +} + static bool intel_c20_use_mplla(u32 clock) { /* 10G and 20G rates use MPLLA */ @@ -1321,6 +1757,63 @@ static bool intel_c20_use_mplla(u32 clock) return false; } +void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, + struct intel_c20pll_state *pll_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + bool cntx, use_mplla; + u32 val; + int i; + + /* 1. Read current context selection */ + cntx = intel_cx0_read(i915, encoder->port, 0, PHY_C20_VDR_CUSTOM_SERDES_RATE) & PHY_C20_CONTEXT_TOGGLE; + + /* Read Tx configuration */ + for (i = 0; i < ARRAY_SIZE(pll_state->tx); i++) { + if (cntx) + pll_state->tx[i] = intel_c20_read(i915, encoder->port, 0, + PHY_C20_B_TX_CNTX_CFG(i)); + else + pll_state->tx[i] = intel_c20_read(i915, encoder->port, 0, + PHY_C20_A_TX_CNTX_CFG(i)); + } + + /* Read common configuration */ + for (i = 0; i < ARRAY_SIZE(pll_state->cmn); i++) { + if (cntx) + pll_state->cmn[i] = intel_c20_read(i915, encoder->port, 0, + PHY_C20_B_CMN_CNTX_CFG(i)); + else + pll_state->cmn[i] = intel_c20_read(i915, encoder->port, 0, + PHY_C20_A_CMN_CNTX_CFG(i)); + } + + val = intel_c20_read(i915, encoder->port, 0, PHY_C20_A_MPLLA_CNTX_CFG(6)); + use_mplla = val & C20_MPLLB_FRACEN; + + if (use_mplla) { + /* MPLLA configuration */ + for (i = 0; i < ARRAY_SIZE(pll_state->mplla); i++) { + if (cntx) + pll_state->mplla[i] = intel_c20_read(i915, encoder->port, 0, + PHY_C20_B_MPLLA_CNTX_CFG(i)); + else + pll_state->mplla[i] = intel_c20_read(i915, encoder->port, 0, + PHY_C20_A_MPLLA_CNTX_CFG(i)); + } + } else { + /* MPLLB configuration */ + for (i = 0; i < ARRAY_SIZE(pll_state->mpllb); i++) { + if (cntx) + pll_state->mpllb[i] = intel_c20_read(i915, encoder->port, 0, + PHY_C20_B_MPLLB_CNTX_CFG(i)); + else + pll_state->mpllb[i] = intel_c20_read(i915, encoder->port, 0, + PHY_C20_A_MPLLB_CNTX_CFG(i)); + } + } +} + static u8 intel_c20_get_dp_rate(u32 clock) { switch (clock) { diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 952c7deeffaa..86edbc4b1718 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -33,14 +33,22 @@ void intel_c10mpllb_readout_hw_state(struct intel_encoder *encoder, struct intel_c10mpllb_state *pll_state); int intel_cx0mpllb_calc_state(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder); +int intel_c20pll_calc_state(struct intel_crtc_state *crtc_state, + struct intel_encoder *encoder); +void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, + struct intel_c20pll_state *pll_state); void intel_c10mpllb_dump_hw_state(struct drm_i915_private *dev_priv, const struct intel_c10mpllb_state *hw_state); int intel_c10mpllb_calc_port_clock(struct intel_encoder *encoder, const struct intel_c10mpllb_state *pll_state); void intel_c10mpllb_state_verify(struct intel_atomic_state *state, struct intel_crtc_state *new_crtc_state); -int intel_c10_phy_check_hdmi_link_rate(int clock); +int intel_cx0_phy_check_hdmi_link_rate(struct intel_hdmi *hdmi, int clock); void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); +int intel_c20_phy_check_hdmi_link_rate(int clock); +void intel_cx0_phy_ddi_vswing_sequence(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + u32 level); #endif /* __INTEL_CX0_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index a5fbc4fed28d..c37f7f7d84cf 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3532,10 +3532,13 @@ static void mtl_ddi_get_config(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(i915, encoder->port); - drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); + if (intel_is_c10phy(i915, phy)) { + intel_c10mpllb_readout_hw_state(encoder, &crtc_state->cx0pll_state.c10mpllb_state); + intel_c10mpllb_dump_hw_state(i915, &crtc_state->cx0pll_state.c10mpllb_state); + } else { + intel_c20pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c20pll_state); + } - intel_c10mpllb_readout_hw_state(encoder, &crtc_state->cx0pll_state.c10mpllb_state); - intel_c10mpllb_dump_hw_state(i915, &crtc_state->cx0pll_state.c10mpllb_state); crtc_state->port_clock = intel_c10mpllb_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10mpllb_state); intel_ddi_get_config(encoder, crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 7b81781a64b6..e60fcd477091 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -58,7 +58,7 @@ #include "intel_panel.h" #include "intel_snps_phy.h" -static struct drm_i915_private *intel_hdmi_to_i915(struct intel_hdmi *intel_hdmi) +inline struct drm_i915_private *intel_hdmi_to_i915(struct intel_hdmi *intel_hdmi) { return to_i915(hdmi_to_dig_port(intel_hdmi)->base.base.dev); } @@ -1883,8 +1883,8 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi, * FIXME: We will hopefully get an algorithmic way of programming * the MPLLB for HDMI in the future. */ - if (IS_METEORLAKE(dev_priv)) - return intel_c10_phy_check_hdmi_link_rate(clock); + if (DISPLAY_VER(dev_priv) >= 14) + return intel_cx0_phy_check_hdmi_link_rate(hdmi, clock); else if (IS_DG2(dev_priv)) return intel_snps_phy_check_hdmi_link_rate(clock); diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h index 774dda2376ed..492bd3921385 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.h +++ b/drivers/gpu/drm/i915/display/intel_hdmi.h @@ -54,5 +54,6 @@ int intel_hdmi_dsc_get_num_slices(const struct intel_crtc_state *crtc_state, int src_max_slices, int src_max_slice_width, int hdmi_max_slices, int hdmi_throughput); int intel_hdmi_dsc_get_slice_height(int vactive); +struct drm_i915_private *intel_hdmi_to_i915(struct intel_hdmi *intel_hdmi); #endif /* __INTEL_HDMI_H__ */ From patchwork Thu Jan 5 12:54:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089819 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 9531CC3DA7D for ; Thu, 5 Jan 2023 13:00:00 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D812C10E720; Thu, 5 Jan 2023 12:59:59 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 4619310E71F for ; Thu, 5 Jan 2023 12:59:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923598; x=1704459598; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=HVAitgaVPU0ggfIGakSiiGjrsWgwFMKUtl0PFVrgxws=; b=aES/nzH0EA1HorRrOFNvMxHANNJwJoHFK8socepwkqpWbG7QYci2DSgD cMYnsLoBUAPn3Hc525C69yqE1cu0H6R72TLqYYlBy8+fC7OAX3gjLqNT2 EXlL21JJw6po/8SZhER595ISZR/MlqfYMJum7b5syF8SdxhRKLfA4pTtT WV2eW64ZYFRcL/BgfIwKRljWWov4D/C4DhItn/2e7XO9HtBGTDaOydBjg SyfiCnBQqe7B9TLud+vPNxQgA0A9BlRZwSF7u/p/m/or6oGplW5cSzqVY 3nmKON2aJGCZH4g6RRT4VgTsgS4FObPvwGqlXOJIzlvKgKGx32mo7Pkeh w==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697804" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697804" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 04:59:58 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829541003" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829541003" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 04:59:56 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:35 +0200 Message-Id: <20230105125446.960504-11-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 10/21] drm/i915/mtl: C20 port clock calculation 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Calculate port clock with C20 phy. Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-11-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 32 ++++++++++++++++++-- drivers/gpu/drm/i915/display/intel_cx0_phy.h | 2 ++ drivers/gpu/drm/i915/display/intel_ddi.c | 4 +-- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 285e4cdd23eb..14ea40cd0631 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -1571,9 +1571,10 @@ int intel_cx0mpllb_calc_state(struct intel_crtc_state *crtc_state, struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(i915, encoder->port); - drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); - - return intel_c10mpllb_calc_state(crtc_state, encoder); + if (intel_is_c10phy(i915, phy)) + return intel_c10mpllb_calc_state(crtc_state, encoder); + else + return intel_c20pll_calc_state(crtc_state, encoder); } void intel_c10mpllb_readout_hw_state(struct intel_encoder *encoder, @@ -2044,6 +2045,31 @@ int intel_c10mpllb_calc_port_clock(struct intel_encoder *encoder, return tmpclk; } +int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_c20pll_state *pll_state) +{ + unsigned int frac_quot = 0, frac_rem = 0, frac_den = 1; + unsigned int multiplier, tx_clk_div, refclk = 38400; + + if (pll_state->mpllb[6] & C20_MPLLB_FRACEN) { + frac_quot = pll_state->mpllb[8]; + frac_rem = pll_state->mpllb[9]; + frac_den = pll_state->mpllb[7]; + multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mpllb[0]); + tx_clk_div = REG_FIELD_GET(C20_MPLLB_TX_CLK_DIV_MASK, pll_state->mpllb[0]); + } else if (pll_state->mplla[6] & C20_MPLLA_FRACEN) { + frac_quot = pll_state->mplla[8]; + frac_rem = pll_state->mplla[9]; + frac_den = pll_state->mplla[7]; + multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mplla[0]); + tx_clk_div = REG_FIELD_GET(C20_MPLLA_TX_CLK_DIV_MASK, pll_state->mplla[1]); + } + + return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, (multiplier << 16) + frac_quot) + + DIV_ROUND_CLOSEST(refclk * frac_rem, frac_den), + 10 << (tx_clk_div + 16)); +} + static void intel_program_port_clock_ctl(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, bool lane_reversal) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 86edbc4b1718..8ca77dfea24b 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -43,6 +43,8 @@ int intel_c10mpllb_calc_port_clock(struct intel_encoder *encoder, const struct intel_c10mpllb_state *pll_state); void intel_c10mpllb_state_verify(struct intel_atomic_state *state, struct intel_crtc_state *new_crtc_state); +int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_c20pll_state *pll_state); int intel_cx0_phy_check_hdmi_link_rate(struct intel_hdmi *hdmi, int clock); void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index c37f7f7d84cf..829c90b17b08 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3535,12 +3535,12 @@ static void mtl_ddi_get_config(struct intel_encoder *encoder, if (intel_is_c10phy(i915, phy)) { intel_c10mpllb_readout_hw_state(encoder, &crtc_state->cx0pll_state.c10mpllb_state); intel_c10mpllb_dump_hw_state(i915, &crtc_state->cx0pll_state.c10mpllb_state); + crtc_state->port_clock = intel_c10mpllb_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10mpllb_state); } else { intel_c20pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c20pll_state); + crtc_state->port_clock = intel_c20pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c20pll_state); } - crtc_state->port_clock = intel_c10mpllb_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10mpllb_state); - intel_ddi_get_config(encoder, crtc_state); } From patchwork Thu Jan 5 12:54:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089820 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 0BCCCC3DA7A for ; Thu, 5 Jan 2023 13:00:05 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 23DD010E71F; Thu, 5 Jan 2023 13:00:04 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 6D24910E727 for ; Thu, 5 Jan 2023 13:00:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923600; x=1704459600; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=nTrpYyCpwykA2NKcL5x/YvhSqGUku3pLGyVbnyxDEHc=; b=ScRik3J5r5j3lBrI2yf3uL+72lxYlddFGG2AzmQ6Y1ZbL/Ws35zDdagK EPX3EO7sdiPlUCLEe+kVdcyFfKEih/b3bLTVRyAu7c/mlSdMSuZ34kKE2 gPi4JDkvyLTWx6iStJVukJIptkZSqP8MhpgX/f+y1Vghd8IXS0Uzzu4J5 f2svAMdw4w+67qm+wVt1vAXWM8Y8pfWumma+XsfzghLODKlR/QWaoeQhO lP9zxXhmwQI+xGGemep6R750DN3XKDXkwYMy1xNbVERUZGsFWJIawteQb ASzfkHPZgcNz8Fc+/6Zl/PSAjBw0jVwX2DuhS1UzVSEfFIhdrk4oMTF1h Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697822" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697822" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 05:00:00 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829541044" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829541044" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 04:59:58 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:36 +0200 Message-Id: <20230105125446.960504-12-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 11/21] drm/i915/mtl: C20 HDMI state calculations 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Add C20 HDMI state calculations and put HDMI table definitions in use. Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-12-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 14ea40cd0631..e5542fb209ab 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -1732,9 +1732,19 @@ intel_c20_pll_tables_get(struct intel_crtc_state *crtc_state, int intel_c20pll_calc_state(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) { + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); const struct intel_c20pll_state * const *tables; int i; + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) { + if (intel_c20_phy_check_hdmi_link_rate(crtc_state->port_clock) != MODE_OK) { + drm_dbg_kms(&i915->drm, "Can't support HDMI link rate %d on phy %c.\n", + crtc_state->port_clock, phy_name(phy)); + return -EINVAL; + } + } + tables = intel_c20_pll_tables_get(crtc_state, encoder); if (!tables) return -EINVAL; From patchwork Thu Jan 5 12:54:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089823 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 69EA2C53210 for ; Thu, 5 Jan 2023 13:00:10 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4B95410E721; Thu, 5 Jan 2023 13:00:09 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 97B5010E721 for ; Thu, 5 Jan 2023 13:00:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923602; x=1704459602; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=G0fLL6pbb8TRNfshLXyO0yrRHjF3k4XjJ7QPeWh0vz4=; b=YWhyRqjGY41V3qpYOGz/8WzKU0C3gWWgGtiI8zzpiLzuXHlBBKMw/rrY RG8AprN84h5m0GqFPMjYebd4IFY+Nzd5U2/7aR/xiyjYwPktl+31LPsD4 lVTG5xsAqzebjUsWWGYByhQDf4I+iBlVM3BazspYBgPN4u98PrZLPgbzg 6O3LkpVJw8j4aZ6i9Ot8OVPM626nUvIvhsaqfrXI23r56aqnD7ppqzsl/ bICDYglRd9xscOsSc8lNJy3Thf5hQI2j1Lh9IODHlzcsPZs0I+1k+nn8x 9Euv7Zy6BLTvFF4I4dJDJblFLS9Sudv72ai8aMjhMmnL4gspjV7df2cFM w==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697852" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697852" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 05:00:02 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829541102" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829541102" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 05:00:00 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:37 +0200 Message-Id: <20230105125446.960504-13-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 12/21] drm/i915/mtl: Add voltage swing sequence for C20 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" DP1.4 and DP20 voltage swing sequence for C20 phy. Bspec: 65449, 67636, 67610 v2: DP2.0 Tx Eq tables has been updated in BSpec. Update also the driver code as per BSpec 65449 Signed-off-by: Mika Kahola Signed-off-by: Radhakrishna Sripada Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-13-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 31 ++++++++++++----- .../gpu/drm/i915/display/intel_cx0_phy_regs.h | 4 +++ .../drm/i915/display/intel_ddi_buf_trans.c | 33 +++++++++++++++++-- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index e5542fb209ab..7520f50d4ffc 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -342,14 +342,29 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, lane = ln / 2 + 1; tx = ln % 2 + 1; - intel_cx0_rmw(i915, encoder->port, lane, PHY_CX0_TX_CONTROL(tx, 2), - C10_PHY_VSWING_PREEMPH_MASK, - C10_PHY_VSWING_PREEMPH(trans->entries[level].direct.preemph), - MB_WRITE_COMMITTED); - intel_cx0_rmw(i915, encoder->port, lane, PHY_CX0_TX_CONTROL(tx, 8), - C10_PHY_VSWING_LEVEL_MASK, - C10_PHY_VSWING_LEVEL(trans->entries[level].direct.level), - MB_WRITE_COMMITTED); + if (crtc_state->port_clock > 1000000) { + intel_cx0_rmw(i915, encoder->port, lane, PHY_CX0_TX_CONTROL(tx, 2), + C20_PHY_VSWING_PREEMPH_MASK, + C20_PHY_VSWING_PREEMPH(trans->entries[level].snps.pre_cursor), + MB_WRITE_COMMITTED); + intel_cx0_rmw(i915, encoder->port, lane, PHY_CX0_TX_CONTROL(tx, 3), + C20_PHY_VSWING_PREEMPH_MASK, + C20_PHY_VSWING_PREEMPH(trans->entries[level].snps.vswing), + MB_WRITE_COMMITTED); + intel_cx0_rmw(i915, encoder->port, lane, PHY_CX0_TX_CONTROL(tx, 4), + C20_PHY_VSWING_PREEMPH_MASK, + C20_PHY_VSWING_PREEMPH(trans->entries[level].snps.post_cursor), + MB_WRITE_COMMITTED); + } else { + intel_cx0_rmw(i915, encoder->port, lane, PHY_CX0_TX_CONTROL(tx, 2), + C10_PHY_VSWING_PREEMPH_MASK, + C10_PHY_VSWING_PREEMPH(trans->entries[level].direct.preemph), + MB_WRITE_COMMITTED); + intel_cx0_rmw(i915, encoder->port, lane, PHY_CX0_TX_CONTROL(tx, 8), + C10_PHY_VSWING_LEVEL_MASK, + C10_PHY_VSWING_LEVEL(trans->entries[level].direct.level), + MB_WRITE_COMMITTED); + } } intel_cx0_write(i915, encoder->port, follower_lane, PHY_C10_VDR_CONTROL(1), diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h index 794372f4798d..9c32152a3d10 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h @@ -203,6 +203,10 @@ #define C20_MPLLB_TX_CLK_DIV_MASK REG_GENMASK(15, 13) #define C20_MPLLA_TX_CLK_DIV_MASK REG_GENMASK(10, 8) +/* C20 Phy VSwing Masks */ +#define C20_PHY_VSWING_PREEMPH_MASK REG_GENMASK8(5, 0) +#define C20_PHY_VSWING_PREEMPH(val) REG_FIELD_PREP8(C20_PHY_VSWING_PREEMPH_MASK, val) + #define RAWLANEAONX_DIG_TX_MPLLB_CAL_DONE_BANK(idx) (0x303D + (idx)) #endif /* __INTEL_CX0_PHY_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c index ca2acaa73a64..4f4a8d3712a6 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c @@ -9,6 +9,7 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_dp.h" +#include "intel_cx0_phy.h" /* HDMI/DVI modes ignore everything but the last 2 items. So we share * them for both DP and FDI transports, allowing those ports to @@ -1053,12 +1054,37 @@ static const union intel_ddi_buf_trans_entry direct_map_trans[] = { { .direct = { .level = 3, .preemph = 0 } }, }; -static const struct intel_ddi_buf_trans mtl_cx0c10_trans = { +static const struct intel_ddi_buf_trans mtl_cx0_trans = { .entries = direct_map_trans, .num_entries = ARRAY_SIZE(direct_map_trans), .hdmi_default_entry = ARRAY_SIZE(direct_map_trans) - 1, }; +/* DP2.0 */ +static const union intel_ddi_buf_trans_entry _mtl_c20_trans_uhbr[] = { + { .snps = { 48, 0, 0 } }, /* preset 0 */ + { .snps = { 43, 0, 5 } }, /* preset 1 */ + { .snps = { 40, 0, 8 } }, /* preset 2 */ + { .snps = { 37, 0, 11 } }, /* preset 3 */ + { .snps = { 33, 0, 15 } }, /* preset 4 */ + { .snps = { 46, 2, 0 } }, /* preset 5 */ + { .snps = { 42, 2, 4 } }, /* preset 6 */ + { .snps = { 38, 2, 8 } }, /* preset 7 */ + { .snps = { 35, 2, 11 } }, /* preset 8 */ + { .snps = { 33, 2, 13 } }, /* preset 9 */ + { .snps = { 44, 4, 0 } }, /* preset 10 */ + { .snps = { 40, 4, 4 } }, /* preset 11 */ + { .snps = { 37, 4, 7 } }, /* preset 12 */ + { .snps = { 33, 4, 11 } }, /* preset 13 */ + { .snps = { 40, 8, 0 } }, /* preset 14 */ + { .snps = { 28, 2, 2 } }, /* preset 15 */ +}; + +static const struct intel_ddi_buf_trans mtl_c20_trans_uhbr = { + .entries = _mtl_c20_trans_uhbr, + .num_entries = ARRAY_SIZE(_mtl_c20_trans_uhbr), +}; + bool is_hobl_buf_trans(const struct intel_ddi_buf_trans *table) { return table == &tgl_combo_phy_trans_edp_hbr2_hobl; @@ -1635,7 +1661,10 @@ mtl_get_cx0_buf_trans(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, int *n_entries) { - return intel_get_buf_trans(&mtl_cx0c10_trans, n_entries); + if (crtc_state->port_clock > 1000000) + return intel_get_buf_trans(&mtl_c20_trans_uhbr, n_entries); + else + return intel_get_buf_trans(&mtl_cx0_trans, n_entries); } void intel_ddi_buf_trans_init(struct intel_encoder *encoder) From patchwork Thu Jan 5 12:54:38 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089821 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 49A69C3DA7D for ; Thu, 5 Jan 2023 13:00:08 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id B925310E71C; Thu, 5 Jan 2023 13:00:07 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 9046410E721 for ; Thu, 5 Jan 2023 13:00:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923604; x=1704459604; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ZXylVYOKH0H/n3XlhGe6kyVm+b9gUU9QZ1lPozVeESU=; b=XxWpHaJ4X/FmP3q1mzwHbdEIliMvYBkNcp2wPXp78SSWJEa48h3GD5ZQ tc3tn9So1m/YUayysfvITgKLGnrHh78sPTDFDYmwFct8HlIb/zwRv85+Z VtQHttW6hTY2McefomU6gMmlHxiV8Pizg/27Ya8tyP6EYkOedC3lgi0Lz pI/O7zmA8aU7fGd5GxkJIaf3WWqMEUabvq7c8BcIQJPv4079fWOYjxPsP daTR0Id7evsYcFXzFmnePniIkW9ZAyYTpsXRsus9bFk3bzoi9tJEpT6sw wxxF7k0eNw5+bcJfZ6uxoSYOFvU6vyAXLPgDmApdI7Jbyazhp4zU/AGDo g==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697862" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697862" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 05:00:04 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829541169" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829541169" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 05:00:02 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:38 +0200 Message-Id: <20230105125446.960504-14-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 13/21] drm/i915/mtl: For DP2.0 10G and 20G rates use MPLLA 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Use MPLLA for DP2.0 rates 20G and 20G, when ssc is enabled. Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-14-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 7520f50d4ffc..67e8889aec29 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2128,8 +2128,12 @@ static void intel_program_port_clock_ctl(struct intel_encoder *encoder, if (!intel_panel_use_ssc(i915)) ssc_enabled = false; - /* TODO: DP2.0 10G and 20G rates enable MPLLA*/ - val |= ssc_enabled ? XELPDP_SSC_ENABLE_PLLB : 0; + /* DP2.0 10G and 20G rates enable MPLLA*/ + if (crtc_state->port_clock == 1000000 || crtc_state->port_clock == 2000000) { + val |= ssc_enabled ? XELPDP_SSC_ENABLE_PLLA : 0; + } else { + val |= ssc_enabled ? XELPDP_SSC_ENABLE_PLLB : 0; + } } intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), From patchwork Thu Jan 5 12:54:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089822 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id EFF97C3DA7A for ; Thu, 5 Jan 2023 13:00:09 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4ED8A10E722; Thu, 5 Jan 2023 13:00:09 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id A446E10E721 for ; Thu, 5 Jan 2023 13:00:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923606; x=1704459606; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=q69bQI+n+y3IVdEGcjvmFoi1KpQC3n7L3besQhOApl4=; b=fDs2tuyloe7G5woavpsqcPVDLUhqNxugbPNnbfgprVhpx7NTy4w1JEJR snF1oK5rOA/Ba9K0NgnWC1zZyID8E0ONIOtBvnMuT9PGhylyKW6mrVhQh QwCLksfsftysBBdghzoiQFoTA/Me6bJ5/kJGNn2OLiYMNvTEYM0v9lgv8 qFPDQruidVQthUNsmMY3ElK+Zzhz5RUIMRrUJVcl38wIiN3shjXZabRjT hjA4qZkdEdwQS7/tZJRVsgOYn9FbV306wgKHrcXYHSVnzg4WKegPXlOUv e2vWOXJNVofNHTYHdX0L8T1kuY8HNFdZ96SJbOJDH6IpL5TRxjenv4pPq A==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697869" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697869" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 05:00:06 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829541210" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829541210" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 05:00:04 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:39 +0200 Message-Id: <20230105125446.960504-15-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 14/21] drm/i915/mtl: Enabling/disabling sequence Thunderbolt pll 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Enabling and disabling sequence for Thunderbolt PLL. Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-15-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 137 ++++++++++++++++++- drivers/gpu/drm/i915/display/intel_cx0_phy.h | 7 +- drivers/gpu/drm/i915/display/intel_ddi.c | 4 +- 3 files changed, 139 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 67e8889aec29..9218f99bca4e 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -14,8 +14,8 @@ #include "intel_hdmi.h" #include "intel_panel.h" #include "intel_psr.h" -#include "intel_uncore.h" #include "intel_tc.h" +#include "intel_uncore.h" bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy) { @@ -2365,8 +2365,8 @@ static u32 intel_cx0_get_pclk_pll_ack(u8 lane) XELPDP_LANE1_PCLK_PLL_ACK; } -void intel_cx0pll_enable(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +static void intel_cx0pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(i915, encoder->port); @@ -2439,7 +2439,86 @@ void intel_cx0pll_enable(struct intel_encoder *encoder, intel_cx0_phy_transaction_end(encoder, wakeref); } -void intel_cx0pll_disable(struct intel_encoder *encoder) +static int intel_mtl_tbt_clock_select(struct drm_i915_private *i915, int clock) +{ + switch (clock) { + case 162000: + return XELPDP_DDI_CLOCK_SELECT_TBT_162; + case 270000: + return XELPDP_DDI_CLOCK_SELECT_TBT_270; + case 540000: + return XELPDP_DDI_CLOCK_SELECT_TBT_540; + case 810000: + return XELPDP_DDI_CLOCK_SELECT_TBT_810; + default: + MISSING_CASE(clock); + return XELPDP_DDI_CLOCK_SELECT_TBT_162; + } +} + +static void intel_mtl_tbt_pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + u32 val = 0; + + /* + * 1. Program PORT_CLOCK_CTL REGISTER to configure + * clock muxes, gating and SSC + */ + val |= XELPDP_DDI_CLOCK_SELECT(intel_mtl_tbt_clock_select(i915, crtc_state->port_clock)); + val |= XELPDP_FORWARD_CLOCK_UNGATE; + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + XELPDP_DDI_CLOCK_SELECT_MASK | XELPDP_FORWARD_CLOCK_UNGATE, val); + + /* 2. Read back PORT_CLOCK_CTL REGISTER */ + val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(encoder->port)); + + /* + * 3. Follow the Display Voltage Frequency Switching - Sequence + * Before Frequency Change. We handle this step in bxt_set_cdclk(). + */ + + /* + * 4. Set PORT_CLOCK_CTL register TBT CLOCK Request to "1" to enable PLL. + */ + val |= XELPDP_TBT_CLOCK_REQUEST; + intel_de_write(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), val); + + /* 5. Poll on PORT_CLOCK_CTL TBT CLOCK Ack == "1". */ + if (__intel_wait_for_register(&i915->uncore, XELPDP_PORT_CLOCK_CTL(encoder->port), + XELPDP_TBT_CLOCK_ACK, + XELPDP_TBT_CLOCK_ACK, + 100, 0, NULL)) + drm_warn(&i915->drm, "[ENCODER:%d:%s][%c] PHY PLL not locked after 100us.\n", + encoder->base.base.id, encoder->base.name, phy_name(phy)); + + /* + * 6. Follow the Display Voltage Frequency Switching Sequence After + * Frequency Change. We handle this step in bxt_set_cdclk(). + */ + + /* + * 7. Program DDI_CLK_VALFREQ to match intended DDI + * clock frequency. + */ + intel_de_write(i915, DDI_CLK_VALFREQ(encoder->port), + crtc_state->port_clock); +} + +void intel_mtl_pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + + if (intel_tc_port_in_tbt_alt_mode(dig_port)) + intel_mtl_tbt_pll_enable(encoder, crtc_state); + else + intel_cx0pll_enable(encoder, crtc_state); +} + +static void intel_cx0pll_disable(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(i915, encoder->port); @@ -2491,6 +2570,56 @@ void intel_cx0pll_disable(struct intel_encoder *encoder) intel_cx0_phy_transaction_end(encoder, wakeref); } +static void intel_mtl_tbt_pll_disable(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + /* + * 1. Follow the Display Voltage Frequency Switching Sequence Before + * Frequency Change. We handle this step in bxt_set_cdclk(). + */ + + /* + * 2. Set PORT_CLOCK_CTL register TBT CLOCK Request to "0" to disable PLL. + */ + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + XELPDP_TBT_CLOCK_REQUEST, 0); + + /* 3. Poll on PORT_CLOCK_CTL TBT CLOCK Ack == "0". */ + if (__intel_wait_for_register(&i915->uncore, XELPDP_PORT_CLOCK_CTL(encoder->port), + XELPDP_TBT_CLOCK_ACK, + ~XELPDP_TBT_CLOCK_ACK, + 10, 0, NULL)) + drm_warn(&i915->drm, "[ENCODER:%d:%s][%c] PHY PLL not unlocked after 10us.\n", + encoder->base.base.id, encoder->base.name, phy_name(phy)); + + /* + * 4. Follow the Display Voltage Frequency Switching Sequence After + * Frequency Change. We handle this step in bxt_set_cdclk(). + */ + + /* + * 5. Program PORT CLOCK CTRL register to disable and gate clocks + */ + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + XELPDP_DDI_CLOCK_SELECT_MASK | + XELPDP_FORWARD_CLOCK_UNGATE, 0); + + /* 6. Program DDI_CLK_VALFREQ to 0. */ + intel_de_write(i915, DDI_CLK_VALFREQ(encoder->port), 0); +} + +void intel_mtl_pll_disable(struct intel_encoder *encoder) +{ + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + + if (intel_tc_port_in_tbt_alt_mode(dig_port)) + intel_mtl_tbt_pll_disable(encoder); + else + intel_cx0pll_disable(encoder); +} + void intel_c10mpllb_state_verify(struct intel_atomic_state *state, struct intel_crtc_state *new_crtc_state) { diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 8ca77dfea24b..141802038f12 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -26,9 +26,9 @@ enum phy; #define MB_WRITE_UNCOMMITTED 0 bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy); -void intel_cx0pll_enable(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state); -void intel_cx0pll_disable(struct intel_encoder *encoder); +void intel_mtl_pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); +void intel_mtl_pll_disable(struct intel_encoder *encoder); void intel_c10mpllb_readout_hw_state(struct intel_encoder *encoder, struct intel_c10mpllb_state *pll_state); int intel_cx0mpllb_calc_state(struct intel_crtc_state *crtc_state, @@ -53,4 +53,5 @@ int intel_c20_phy_check_hdmi_link_rate(int clock); void intel_cx0_phy_ddi_vswing_sequence(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, u32 level); +int intel_mtl_tbt_readout_hw_state(struct intel_encoder *encoder); #endif /* __INTEL_CX0_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 829c90b17b08..c2b9a2053732 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -4419,8 +4419,8 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->pipe_mask = ~0; if (DISPLAY_VER(dev_priv) >= 14) { - encoder->enable_clock = intel_cx0pll_enable; - encoder->disable_clock = intel_cx0pll_disable; + encoder->enable_clock = intel_mtl_pll_enable; + encoder->disable_clock = intel_mtl_pll_disable; encoder->get_config = mtl_ddi_get_config; } else if (IS_DG2(dev_priv)) { encoder->enable_clock = intel_mpllb_enable; From patchwork Thu Jan 5 12:54:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089824 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id DFBB2C3DA7D for ; Thu, 5 Jan 2023 13:00:11 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 52FED10E725; Thu, 5 Jan 2023 13:00:11 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id B9A8F10E721 for ; Thu, 5 Jan 2023 13:00:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923608; x=1704459608; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=XJf7bTpXzhSbco4ODtsqdCoKf+fV5NszNbPedPMW00w=; b=DoLuqvZDoJTupii2OGy+0+Ic5gF1I8ptElcdBo5Hj2FhFaEeye5zNjp2 Q8oaCocJikp+jyJf8MU3GzPxMVEk+Y8T6GKQAijNz0/pISST8UirTqDYE qxsT6lUimO8raigEaeJWshc8JWFrb9mkUp052+t5YjIDtywf1ulBmFhy5 v0rv6lWHFFAuRYBxxuQmb1lr9cj5PA9lFI9IhTS1s6zIwIMCN+6vshm1w EcfKuPXuMW+Y1fukNmAMmQ64cMFpLHPfAylhSuH+kCR7hUaRXe0LaRUjl 7uVlUzVA27Uu00yj3zLWNO6KhvmP8ZDXePZJzULOXhSU6xRxYOK5gtsZR A==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697879" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697879" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 05:00:08 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829541246" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829541246" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 05:00:06 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:40 +0200 Message-Id: <20230105125446.960504-16-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 15/21] drm/i915/mtl: Readout Thunderbolt HW state 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Readout hw state for Thunderbolt. Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-16-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 27 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_cx0_phy.h | 2 +- drivers/gpu/drm/i915/display/intel_ddi.c | 5 +++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 9218f99bca4e..c4905bd32900 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2439,6 +2439,33 @@ static void intel_cx0pll_enable(struct intel_encoder *encoder, intel_cx0_phy_transaction_end(encoder, wakeref); } +int intel_mtl_tbt_calc_port_clock(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + u32 clock; + u32 val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(encoder->port)); + + clock = REG_FIELD_GET(XELPDP_DDI_CLOCK_SELECT_MASK, val); + + drm_WARN_ON(&i915->drm, !(val & XELPDP_FORWARD_CLOCK_UNGATE)); + drm_WARN_ON(&i915->drm, !(val & XELPDP_TBT_CLOCK_REQUEST)); + drm_WARN_ON(&i915->drm, !(val & XELPDP_TBT_CLOCK_ACK)); + + switch (clock) { + case XELPDP_DDI_CLOCK_SELECT_TBT_162: + return 162000; + case XELPDP_DDI_CLOCK_SELECT_TBT_270: + return 270000; + case XELPDP_DDI_CLOCK_SELECT_TBT_540: + return 540000; + case XELPDP_DDI_CLOCK_SELECT_TBT_810: + return 810000; + default: + MISSING_CASE(clock); + return 162000; + } +} + static int intel_mtl_tbt_clock_select(struct drm_i915_private *i915, int clock) { switch (clock) { diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 141802038f12..aaaa971111a3 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -53,5 +53,5 @@ int intel_c20_phy_check_hdmi_link_rate(int clock); void intel_cx0_phy_ddi_vswing_sequence(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, u32 level); -int intel_mtl_tbt_readout_hw_state(struct intel_encoder *encoder); +int intel_mtl_tbt_calc_port_clock(struct intel_encoder *encoder); #endif /* __INTEL_CX0_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index c2b9a2053732..4a70e76e7328 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3531,8 +3531,11 @@ static void mtl_ddi_get_config(struct intel_encoder *encoder, { struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(i915, encoder->port); + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); - if (intel_is_c10phy(i915, phy)) { + if (intel_tc_port_in_tbt_alt_mode(dig_port)) { + crtc_state->port_clock = intel_mtl_tbt_calc_port_clock(encoder); + } else if (intel_is_c10phy(i915, phy)) { intel_c10mpllb_readout_hw_state(encoder, &crtc_state->cx0pll_state.c10mpllb_state); intel_c10mpllb_dump_hw_state(i915, &crtc_state->cx0pll_state.c10mpllb_state); crtc_state->port_clock = intel_c10mpllb_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10mpllb_state); From patchwork Thu Jan 5 12:54:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089825 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 475E0C3DA7A for ; Thu, 5 Jan 2023 13:00:14 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C493C10E723; Thu, 5 Jan 2023 13:00:13 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 37A8B10E723 for ; Thu, 5 Jan 2023 13:00:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923611; x=1704459611; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=tm6yWc9NZykWU0GAWJH7ZLMeSedmDPZut44Fv2lGS+U=; b=gBpvn0f2UYKipdZRGtahgihnXC04GG9QHkyqXdx3WCS3mux8x/tiA9PC eSm5s4bjLnU4iFOYI0Qp/cqrjp6ttIDlLim/nom0EfCMDzRA1jwG3k6M9 1vR3z7QutJB6EAAneNxrVRmHT9u8GD7rB/ySjcvQEhbU7kn+TZ3T+Oa4H 10NTCMxKkfqSCSjbHSsI9mwnuXXpxdA0SbwIaOfqG2I1wEGo/DIjv9SEa H7AprpsgMprVA4wHpEWkbSn/0xbLYfvw8geQLlsq07G9mK4sCLRGRbjks zFfx7VusykvHFoKuim5ryuws0KS8Of0qU8hm2mOtOCFXNivd8Ncw+uNQr Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697896" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697896" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 05:00:10 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829541295" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829541295" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 05:00:08 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:41 +0200 Message-Id: <20230105125446.960504-17-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 16/21] drm/i915/mtl: Enable TC ports 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Finally, we can enable TC ports for Meteorlake. Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-17-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 87cd6a808938..302c795c2e3f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -7885,9 +7885,12 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) return; if (IS_METEORLAKE(dev_priv)) { - /* TODO: initialize TC ports as well */ intel_ddi_init(dev_priv, PORT_A); intel_ddi_init(dev_priv, PORT_B); + intel_ddi_init(dev_priv, PORT_TC1); + intel_ddi_init(dev_priv, PORT_TC2); + intel_ddi_init(dev_priv, PORT_TC3); + intel_ddi_init(dev_priv, PORT_TC4); } else if (IS_DG2(dev_priv)) { intel_ddi_init(dev_priv, PORT_A); intel_ddi_init(dev_priv, PORT_B); From patchwork Thu Jan 5 12:54:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089826 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 82DB4C53210 for ; Thu, 5 Jan 2023 13:00:16 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 13CB410E726; Thu, 5 Jan 2023 13:00:16 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 1267010E726 for ; Thu, 5 Jan 2023 13:00:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923614; x=1704459614; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=VbgMHUTUG5KFUD59ODOaodcjJt5tLl1G7p9q45lGgls=; b=g5pFVldHxCXBfZ5z8LVBgfe/TQfZxAmVfJXSD1MQ7qMgC95amQwPdfaz z6YnSGTkc6KnaPiu2VZXHdPT3pvJ2eAp6vGdvbse767ZLoghhhrtQdSAf svDoKq6979GZibyIar5fTn+AZ0R3SBEdc0S4TW4gw9nxRi1tWDEMweR/+ x4pZsIHuoiaLpyDIU2VvnjuACdlxgc1n0RoN5JPu9mcbNzsxX38aKuVEL g3lmmWW2FYuGhsVvx1l+uylG3fbruLp8mzB7wDeZWrZXTZX8TPXzPk8Ky 8VHsyzGYlyNKcRS8itsvjiIgw/6O36AaAZWPJxYfbtIkN7oLSFDXIYZFL g==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697919" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697919" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 05:00:13 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829541319" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829541319" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 05:00:11 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:42 +0200 Message-Id: <20230105125446.960504-18-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 17/21] drm/i915/mtl: MTL PICA hotplug detection 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" PICA is used for DP alt mode and TBT modes. Hotplug interruption is routed from PICA chip to south display engine and from there to north display engine. This patch adds functionality to enable hotplug detection for all Type-C ports (4 ports available). Differently from HPD in south display, PICA provides a dedicated HPD control register for each supported port, so we loop over ports ourselves instead of using intel_hpd_hotplug_enables() or intel_get_hpd_pins(). BSpec: 49305, 55726, 65107, 65300 Signed-off-by: Mika Kahola Signed-off-by: Madhumitha Tolakanahalli Pradeep Signed-off-by: Gustavo Sousa Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-18-mika.kahola@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 226 +++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 31 ++++- 2 files changed, 252 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 15dfef6d93a9..66df94ae8063 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -162,6 +162,13 @@ static const u32 hpd_gen11[HPD_NUM_PINS] = { [HPD_PORT_TC6] = GEN11_TC_HOTPLUG(HPD_PORT_TC6) | GEN11_TBT_HOTPLUG(HPD_PORT_TC6), }; +static const u32 hpd_xelpdp[HPD_NUM_PINS] = { + [HPD_PORT_TC1] = XELPDP_TBT_HOTPLUG(HPD_PORT_TC1) | XELPDP_DP_ALT_HOTPLUG(HPD_PORT_TC1), + [HPD_PORT_TC2] = XELPDP_TBT_HOTPLUG(HPD_PORT_TC2) | XELPDP_DP_ALT_HOTPLUG(HPD_PORT_TC2), + [HPD_PORT_TC3] = XELPDP_TBT_HOTPLUG(HPD_PORT_TC3) | XELPDP_DP_ALT_HOTPLUG(HPD_PORT_TC3), + [HPD_PORT_TC4] = XELPDP_TBT_HOTPLUG(HPD_PORT_TC4) | XELPDP_DP_ALT_HOTPLUG(HPD_PORT_TC4), +}; + static const u32 hpd_icp[HPD_NUM_PINS] = { [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_A), [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_B), @@ -182,6 +189,16 @@ static const u32 hpd_sde_dg1[HPD_NUM_PINS] = { [HPD_PORT_TC1] = SDE_TC_HOTPLUG_DG2(HPD_PORT_TC1), }; +static const u32 hpd_mtp[HPD_NUM_PINS] = { + [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_A), + [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_B), + [HPD_PORT_TC1] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC1), + [HPD_PORT_TC2] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC2), + [HPD_PORT_TC3] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC3), + [HPD_PORT_TC4] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC4), +}; + + static void intel_hpd_init_pins(struct drm_i915_private *dev_priv) { struct intel_hotplug *hpd = &dev_priv->display.hotplug; @@ -195,7 +212,9 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv) return; } - if (DISPLAY_VER(dev_priv) >= 11) + if (DISPLAY_VER(dev_priv) >= 14) + hpd->hpd = hpd_xelpdp; + else if (DISPLAY_VER(dev_priv) >= 11) hpd->hpd = hpd_gen11; else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) hpd->hpd = hpd_bxt; @@ -212,6 +231,8 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv) if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) hpd->pch_hpd = hpd_sde_dg1; + else if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTP) + hpd->pch_hpd = hpd_mtp; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) hpd->pch_hpd = hpd_icp; else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv)) @@ -1965,6 +1986,44 @@ static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) cpt_serr_int_handler(dev_priv); } +static void xelpdp_pica_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir) +{ + enum hpd_pin pin; + u32 hotplug_trigger = iir & (XELPDP_DP_ALT_HOTPLUG_MASK | XELPDP_TBT_HOTPLUG_MASK); + u32 trigger_aux = iir & XELPDP_AUX_TC_MASK; + u32 pin_mask = 0, long_mask = 0; + + for (pin = HPD_PORT_TC1; pin <= HPD_PORT_TC4; pin++) { + u32 val; + + if (!(dev_priv->display.hotplug.hpd[pin] & hotplug_trigger)) + continue; + + pin_mask |= BIT(pin); + + val = intel_uncore_read(&dev_priv->uncore, XELPDP_PORT_HOTPLUG_CTL(pin)); + intel_uncore_write(&dev_priv->uncore, XELPDP_PORT_HOTPLUG_CTL(pin), val); + + if (val & (XELPDP_DP_ALT_HPD_LONG_DETECT | XELPDP_TBT_HPD_LONG_DETECT)) + long_mask |= BIT(pin); + } + + if (pin_mask) { + drm_dbg(&dev_priv->drm, + "pica hotplug event received, stat 0x%08x, pins 0x%08x, long 0x%08x\n", + hotplug_trigger, pin_mask, long_mask); + + intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); + } + + if (trigger_aux) + dp_aux_irq_handler(dev_priv); + + if (!pin_mask && !trigger_aux) + drm_err(&dev_priv->drm, + "Unexpected DE HPD/AUX interrupt 0x%08x\n", iir); +} + static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) { u32 ddi_hotplug_trigger = pch_iir & SDE_DDI_HOTPLUG_MASK_ICP; @@ -1996,6 +2055,15 @@ static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) icp_tc_port_hotplug_long_detect); } + if (pch_iir & SDE_PICAINTERRUPT) { + u32 iir = intel_uncore_read(&dev_priv->uncore, PICAINTERRUPT_IIR); + + if (iir) { + intel_uncore_write(&dev_priv->uncore, PICAINTERRUPT_IIR, iir); + xelpdp_pica_hpd_irq_handler(dev_priv, iir); + } + } + if (pin_mask) intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); @@ -3163,7 +3231,11 @@ static void gen11_display_irq_reset(struct drm_i915_private *dev_priv) GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); - GEN3_IRQ_RESET(uncore, GEN11_DE_HPD_); + + if (DISPLAY_VER(dev_priv) >= 14) + GEN3_IRQ_RESET(uncore, PICAINTERRUPT_); + else + GEN3_IRQ_RESET(uncore, GEN11_DE_HPD_); if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) GEN3_IRQ_RESET(uncore, SDE); @@ -3456,6 +3528,131 @@ static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv) icp_hpd_irq_setup(dev_priv); } +static u32 mtp_ddi_hotplug_enables(struct drm_i915_private *i915, + enum hpd_pin pin) +{ + switch (pin) { + case HPD_PORT_A: + case HPD_PORT_B: + return SHOTPLUG_CTL_DDI_HPD_ENABLE(pin); + default: + return 0; + } +} + +static u32 mtp_tc_hotplug_enables(struct drm_i915_private *i915, + enum hpd_pin pin) +{ + switch (pin) { + case HPD_PORT_TC1: + case HPD_PORT_TC2: + case HPD_PORT_TC3: + case HPD_PORT_TC4: + return ICP_TC_HPD_ENABLE(pin); + default: + return 0; + } +} + +static void mtp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug; + + hotplug = intel_uncore_read(&dev_priv->uncore, SHOTPLUG_CTL_DDI); + hotplug &= ~(SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_A) | + SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_B)); + hotplug |= intel_hpd_hotplug_enables(dev_priv, mtp_ddi_hotplug_enables); + intel_uncore_write(&dev_priv->uncore, SHOTPLUG_CTL_DDI, hotplug); +} + +static void mtp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug; + + hotplug = intel_uncore_read(&dev_priv->uncore, SHOTPLUG_CTL_TC); + hotplug &= ~(ICP_TC_HPD_ENABLE(HPD_PORT_TC1) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC2) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC3) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC4)); + hotplug |= intel_hpd_hotplug_enables(dev_priv, mtp_tc_hotplug_enables); + intel_uncore_write(&dev_priv->uncore, SHOTPLUG_CTL_TC, hotplug); +} + +static void mtp_hpd_invert(struct drm_i915_private *i915) +{ + u32 val = (INVERT_DDIA_HPD | + INVERT_DDIB_HPD | + INVERT_DDIC_HPD | + INVERT_TC1_HPD | + INVERT_TC2_HPD | + INVERT_TC3_HPD | + INVERT_TC4_HPD | + INVERT_DDID_HPD_MTP | + INVERT_DDIE_HPD); + intel_uncore_rmw(&i915->uncore, SOUTH_CHICKEN1, 0, val); +} + +static void mtp_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug_irqs, enabled_irqs; + + enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); + hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.pch_hpd); + + intel_uncore_write(&dev_priv->uncore, SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ); + + mtp_hpd_invert(dev_priv); + + ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); + + mtp_ddi_hpd_detection_setup(dev_priv); + mtp_tc_hpd_detection_setup(dev_priv); + +} + +static void xelpdp_pica_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + struct intel_encoder *encoder; + enum hpd_pin pin; + u32 available_pins = 0; + + BUILD_BUG_ON(BITS_PER_TYPE(available_pins) < HPD_NUM_PINS); + + for_each_intel_encoder(&dev_priv->drm, encoder) + available_pins |= BIT(encoder->hpd_pin); + + for (pin = HPD_PORT_TC1; pin <= HPD_PORT_TC4; pin++) { + u32 mask = (available_pins & BIT(pin)) ? ~(u32)0 : 0; + u32 val = XELPDP_TBT_HOTPLUG_ENABLE | + XELPDP_DP_ALT_HOTPLUG_ENABLE; + + intel_uncore_rmw(&dev_priv->uncore, + XELPDP_PORT_HOTPLUG_CTL(pin), + ~mask & val, mask & val); + } +} + +static void xelpdp_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug_irqs, enabled_irqs; + u32 val; + + enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.hpd); + hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.hpd); + + val = intel_uncore_read(&dev_priv->uncore, PICAINTERRUPT_IMR); + val &= ~hotplug_irqs; + val |= ~enabled_irqs & hotplug_irqs; + intel_uncore_write(&dev_priv->uncore, PICAINTERRUPT_IMR, val); + intel_uncore_posting_read(&dev_priv->uncore, PICAINTERRUPT_IMR); + + xelpdp_pica_hpd_detection_setup(dev_priv); + + if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTP) { + mtp_hpd_irq_setup(dev_priv); + } +} + static u32 spt_hotplug_enables(struct drm_i915_private *i915, enum hpd_pin pin) { @@ -3795,7 +3992,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) GEN3_IRQ_INIT(uncore, GEN8_DE_PORT_, ~de_port_masked, de_port_enables); GEN3_IRQ_INIT(uncore, GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked); - if (DISPLAY_VER(dev_priv) >= 11) { + if (IS_DISPLAY_VER(dev_priv, 11, 13)) { u32 de_hpd_masked = 0; u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK | GEN11_DE_TBT_HOTPLUG_MASK; @@ -3805,6 +4002,20 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) } } +static void mtp_irq_postinstall(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + u32 sde_mask = SDE_GMBUS_ICP | SDE_PICAINTERRUPT; + u32 de_hpd_mask = XELPDP_AUX_TC_MASK; + u32 de_hpd_enables = de_hpd_mask | XELPDP_DP_ALT_HOTPLUG_MASK | + XELPDP_TBT_HOTPLUG_MASK; + + GEN3_IRQ_INIT(uncore, PICAINTERRUPT_, ~de_hpd_mask, + de_hpd_enables); + + GEN3_IRQ_INIT(uncore, SDE, ~sde_mask, 0xffffffff); +} + static void icp_irq_postinstall(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -3866,7 +4077,11 @@ static void dg1_irq_postinstall(struct drm_i915_private *dev_priv) GEN3_IRQ_INIT(uncore, GEN11_GU_MISC_, ~gu_misc_masked, gu_misc_masked); if (HAS_DISPLAY(dev_priv)) { - icp_irq_postinstall(dev_priv); + if (DISPLAY_VER(dev_priv) >= 14) + mtp_irq_postinstall(dev_priv); + else + icp_irq_postinstall(dev_priv); + gen8_de_irq_postinstall(dev_priv); intel_uncore_write(&dev_priv->uncore, GEN11_DISPLAY_INT_CTL, GEN11_DISPLAY_IRQ_ENABLE); @@ -4324,6 +4539,7 @@ static const struct intel_hotplug_funcs platform##_hpd_funcs = { \ } HPD_FUNCS(i915); +HPD_FUNCS(xelpdp); HPD_FUNCS(dg1); HPD_FUNCS(gen11); HPD_FUNCS(bxt); @@ -4384,6 +4600,8 @@ void intel_irq_init(struct drm_i915_private *dev_priv) dev_priv->display.funcs.hotplug = &icp_hpd_funcs; else if (HAS_PCH_DG1(dev_priv)) dev_priv->display.funcs.hotplug = &dg1_hpd_funcs; + else if (DISPLAY_VER(dev_priv) >= 14) + dev_priv->display.funcs.hotplug = &xelpdp_hpd_funcs; else if (DISPLAY_VER(dev_priv) >= 11) dev_priv->display.funcs.hotplug = &gen11_hpd_funcs; else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 065905723c09..d561be0e35c1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5582,6 +5582,28 @@ #define GEN11_HOTPLUG_CTL_SHORT_DETECT(hpd_pin) (1 << (_HPD_PIN_TC(hpd_pin) * 4)) #define GEN11_HOTPLUG_CTL_NO_DETECT(hpd_pin) (0 << (_HPD_PIN_TC(hpd_pin) * 4)) +#define PICAINTERRUPT_ISR _MMIO(0x16FE50) +#define PICAINTERRUPT_IMR _MMIO(0x16FE54) +#define PICAINTERRUPT_IIR _MMIO(0x16FE58) +#define PICAINTERRUPT_IER _MMIO(0x16FE5C) + +#define XELPDP_DP_ALT_HOTPLUG(hpd_pin) REG_BIT(16 + _HPD_PIN_TC(hpd_pin)) +#define XELPDP_DP_ALT_HOTPLUG_MASK REG_GENMASK(19, 16) + +#define XELPDP_AUX_TC(hpd_pin) REG_BIT(8 + _HPD_PIN_TC(hpd_pin)) +#define XELPDP_AUX_TC_MASK REG_GENMASK(11, 8) + +#define XELPDP_TBT_HOTPLUG(hpd_pin) REG_BIT(_HPD_PIN_TC(hpd_pin)) +#define XELPDP_TBT_HOTPLUG_MASK REG_GENMASK(3, 0) + +#define XELPDP_PORT_HOTPLUG_CTL(hpd_pin) _MMIO(0x16F270 + (_HPD_PIN_TC(hpd_pin) * 0x200)) +#define XELPDP_TBT_HOTPLUG_ENABLE REG_BIT(6) +#define XELPDP_TBT_HPD_LONG_DETECT REG_BIT(5) +#define XELPDP_TBT_HPD_SHORT_DETECT REG_BIT(4) +#define XELPDP_DP_ALT_HOTPLUG_ENABLE REG_BIT(2) +#define XELPDP_DP_ALT_HPD_LONG_DETECT REG_BIT(1) +#define XELPDP_DP_ALT_HPD_SHORT_DETECT REG_BIT(0) + #define XELPDP_INITIATE_PMDEMAND_REQUEST(dword) _MMIO(0x45230 + 4 * (dword)) #define XELPDP_PMDEMAND_QCLK_GV_BW_MASK REG_GENMASK(31, 16) #define XELPDP_PMDEMAND_QCLK_GV_BW(x) REG_FIELD_PREP(XELPDP_PMDEMAND_QCLK_GV_BW_MASK, x) @@ -5917,7 +5939,8 @@ SDE_FDI_RXB_CPT | \ SDE_FDI_RXA_CPT) -/* south display engine interrupt: ICP/TGP */ +/* south display engine interrupt: ICP/TGP/MTP */ +#define SDE_PICAINTERRUPT REG_BIT(31) #define SDE_GMBUS_ICP (1 << 23) #define SDE_TC_HOTPLUG_ICP(hpd_pin) REG_BIT(24 + _HPD_PIN_TC(hpd_pin)) #define SDE_TC_HOTPLUG_DG2(hpd_pin) REG_BIT(25 + _HPD_PIN_TC(hpd_pin)) /* sigh */ @@ -6271,6 +6294,12 @@ #define SOUTH_CHICKEN1 _MMIO(0xc2000) #define FDIA_PHASE_SYNC_SHIFT_OVR 19 #define FDIA_PHASE_SYNC_SHIFT_EN 18 +#define INVERT_DDIE_HPD REG_BIT(28) +#define INVERT_DDID_HPD_MTP REG_BIT(27) +#define INVERT_TC4_HPD REG_BIT(26) +#define INVERT_TC3_HPD REG_BIT(25) +#define INVERT_TC2_HPD REG_BIT(24) +#define INVERT_TC1_HPD REG_BIT(23) #define INVERT_DDID_HPD (1 << 18) #define INVERT_DDIC_HPD (1 << 17) #define INVERT_DDIB_HPD (1 << 16) From patchwork Thu Jan 5 12:54:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089827 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 788ECC3DA7D for ; Thu, 5 Jan 2023 13:00:20 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C249010E728; Thu, 5 Jan 2023 13:00:18 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id F2EBB10E724 for ; Thu, 5 Jan 2023 13:00:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923615; x=1704459615; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=UI1PP51b6R4+ny4CLbHOEBIvpDjG6/PlYW/lL8GpZX0=; b=R5Lc1Ii4Qv4IpqmG+cljUVF1GSGr/j+chYY67v0CQswr8Tt2Z0ED1a7x G27Jd7J6xdyd6MJgayrp3tsPCzwr97RY1g1TuB5xKe9/AW9gYpX83FiOY rhl3xAerE7EHvnl8dUQ8IueWiD99SnqjG01gYIponugjEyNeC/v9bgmkp 45tdTqRCaKZtgmu8nd4tOvXfWr5+4vDX5LEwbbaoxMmfKzU1ZK+6uf6xk Ro1aexU9kQs+EW5ba7T82UKK1O4fh+2DMS9TmWJaucMHxjM764t+/m3/D qNb7XFhIiY3nDzBtvoYVnbfms7I+kX711a0kWEa5Ee3OW6LSwwn9YhUrM g==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697930" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697930" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 05:00:15 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829541347" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829541347" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 05:00:13 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:43 +0200 Message-Id: <20230105125446.960504-19-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 18/21] drm/i915/mtl: Define mask for DDI AUX interrupts 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Gustavo Sousa Xe_LPD+ defines interrupt bits for only DDI ports in the DE Port Interrupt registers. The bits for Type-C ports are defined in the PICA interrupt registers. BSpec: 50064 Signed-off-by: Gustavo Sousa Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-19-mika.kahola@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 66df94ae8063..11ebdbef1832 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2340,7 +2340,10 @@ static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) { u32 mask; - if (DISPLAY_VER(dev_priv) >= 13) + if (DISPLAY_VER(dev_priv) >= 14) + return TGL_DE_PORT_AUX_DDIA | + TGL_DE_PORT_AUX_DDIB; + else if (DISPLAY_VER(dev_priv) >= 13) return TGL_DE_PORT_AUX_DDIA | TGL_DE_PORT_AUX_DDIB | TGL_DE_PORT_AUX_DDIC | From patchwork Thu Jan 5 12:54:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089828 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id ED0D1C53210 for ; Thu, 5 Jan 2023 13:00:21 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 504B010E710; Thu, 5 Jan 2023 13:00:21 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id E619B10E72A for ; Thu, 5 Jan 2023 13:00:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923619; x=1704459619; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=7hJTViX3UYeKKDv3aw7TFlvNXs1URRO34ouIelenOHY=; b=iQ0yKk9qm3DWGZcvFAz3go5C6KS/SrDZBmzyUNuxcz+OPAht43au3Uvo p8O6aVBi86x679LSBzeRoaM6aFU9K7CSBYoctZa5UdF56mhaPyLObBhKf qE4eOFTJvId7SqLjnp95O248xdeM7Dhj4s/wBsuv3pQPbC61X/YLylLIR mY/EUF/AehNCfyVZOi1tykcmDoIG2s6fCmyJ32FLLn4v996phr/6vn3Pq zjwK3dS4F0IScIh3hddzTKJMAgHkSnjiazKLOLRWmjdGHFGuDRxdRa8g6 Npcy7wMlIJqkZR2bYHe5xnU8lIVcAYcI6Rt4IKLTZdQzGVpsL+wRSMYCD g==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697947" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697947" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 05:00:17 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829541385" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829541385" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 05:00:15 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:44 +0200 Message-Id: <20230105125446.960504-20-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 19/21] drm/i915/mtl: Power up TCSS 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Add register writes to enable powering up Type-C subsystem i.e. TCSS. For MeteorLake we need to request TCSS to power up and check the TCSS power state after 500 us. In addition, for PICA we need to set/clear the Type-C PHY ownnership bit when Type-C device is connected/disconnected. v2: Call tcss power request with correct parameter. Signed-off-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-20-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_tc.c | 117 ++++++++++++++++++- 2 files changed, 114 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 302c795c2e3f..75fcc0ef5ced 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2119,7 +2119,7 @@ bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy) if (IS_DG2(dev_priv)) /* DG2's "TC1" output uses a SNPS PHY */ return false; - else if (IS_ALDERLAKE_P(dev_priv)) + else if (IS_ALDERLAKE_P(dev_priv) || IS_METEORLAKE(dev_priv)) return phy >= PHY_F && phy <= PHY_I; else if (IS_TIGERLAKE(dev_priv)) return phy >= PHY_D && phy <= PHY_I; diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index f45328712bff..74d8d8e0e0df 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -5,6 +5,7 @@ #include "i915_drv.h" #include "i915_reg.h" +#include "intel_cx0_phy_regs.h" #include "intel_de.h" #include "intel_display.h" #include "intel_display_power_map.h" @@ -300,7 +301,7 @@ static u32 tc_port_live_status_mask(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - if (IS_ALDERLAKE_P(i915)) + if (DISPLAY_VER(i915) >= 13) return adl_tc_port_live_status_mask(dig_port); return icl_tc_port_live_status_mask(dig_port); @@ -354,11 +355,69 @@ static bool adl_tc_phy_status_complete(struct intel_digital_port *dig_port) return val & TCSS_DDI_STATUS_READY; } +static bool xelpdp_wait_phy_status_complete(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port); + + if (intel_wait_for_register(&i915->uncore, + TCSS_DDI_STATUS(tc_port), + TCSS_DDI_STATUS_READY, + TCSS_DDI_STATUS_READY, + 1)) { + drm_dbg_kms(&i915->drm, + "Port %s: PHY in TCCOLD, assuming not complete\n", + dig_port->tc_port_name); + return false; + } + + return true; +} + +static bool xelpdp_wait_for_tcss_power(struct intel_digital_port *dig_port, + bool enabled) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + + if (intel_wait_for_register(&i915->uncore, + XELPDP_PORT_BUF_CTL1(dig_port->base.port), + XELPDP_TCSS_POWER_STATE, + enabled ? XELPDP_TCSS_POWER_STATE : 0, + 5)) { + drm_dbg_kms(&i915->drm, + "Port %s: TCSS power state not as expected\n", + dig_port->tc_port_name); + return false; + } + + return true; +} + +static bool xelpdp_tc_power_request(struct intel_digital_port *dig_port, bool request) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + struct intel_uncore *uncore = &i915->uncore; + enum port port = dig_port->base.port; + u32 val; + + val = intel_uncore_read(uncore, XELPDP_PORT_BUF_CTL1(port)); + if (request) + val |= XELPDP_TCSS_POWER_REQUEST; + else + val &= ~XELPDP_TCSS_POWER_REQUEST; + intel_uncore_write(uncore, XELPDP_PORT_BUF_CTL1(port), val); + + return xelpdp_wait_phy_status_complete(dig_port) && + xelpdp_wait_for_tcss_power(dig_port, request); +} + static bool tc_phy_status_complete(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - if (IS_ALDERLAKE_P(i915)) + if (DISPLAY_VER(i915) >= 14) + return xelpdp_wait_phy_status_complete(dig_port); + else if (IS_ALDERLAKE_P(i915)) return adl_tc_phy_status_complete(dig_port); return icl_tc_phy_status_complete(dig_port); @@ -400,11 +459,31 @@ static bool adl_tc_phy_take_ownership(struct intel_digital_port *dig_port, return true; } +static bool xelpdp_tc_phy_take_ownership(struct intel_digital_port *dig_port, + bool take) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + struct intel_uncore *uncore = &i915->uncore; + enum port port = dig_port->base.port; + u32 val; + + val = intel_uncore_read(uncore, XELPDP_PORT_BUF_CTL1(port)); + if (take) + val |= XELPDP_TC_PHY_OWNERSHIP; + else + val &= ~XELPDP_TC_PHY_OWNERSHIP; + intel_uncore_write(uncore, XELPDP_PORT_BUF_CTL1(port), val); + + return true; +} + static bool tc_phy_take_ownership(struct intel_digital_port *dig_port, bool take) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - if (IS_ALDERLAKE_P(i915)) + if (DISPLAY_VER(i915) >= 14) + return xelpdp_tc_phy_take_ownership(dig_port, take); + else if (IS_ALDERLAKE_P(i915)) return adl_tc_phy_take_ownership(dig_port, take); return icl_tc_phy_take_ownership(dig_port, take); @@ -436,11 +515,23 @@ static bool adl_tc_phy_is_owned(struct intel_digital_port *dig_port) return val & DDI_BUF_CTL_TC_PHY_OWNERSHIP; } +static bool xelpdp_tc_phy_is_owned(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + struct intel_uncore *uncore = &i915->uncore; + enum port port = dig_port->base.port; + + return intel_uncore_read(uncore, XELPDP_PORT_BUF_CTL1(port)) & + XELPDP_TC_PHY_OWNERSHIP; +} + static bool tc_phy_is_owned(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - if (IS_ALDERLAKE_P(i915)) + if (DISPLAY_VER(i915) >= 14) + return xelpdp_tc_phy_is_owned(dig_port); + else if (IS_ALDERLAKE_P(i915)) return adl_tc_phy_is_owned(dig_port); return icl_tc_phy_is_owned(dig_port); @@ -464,6 +555,11 @@ static void icl_tc_phy_connect(struct intel_digital_port *dig_port, u32 live_status_mask; int max_lanes; + if (DISPLAY_VER(i915) >= 14) { + if (!xelpdp_tc_power_request(dig_port, true)) + goto out_release_phy; + } + if (!tc_phy_status_complete(dig_port)) { drm_dbg_kms(&i915->drm, "Port %s: PHY not ready\n", dig_port->tc_port_name); @@ -514,6 +610,10 @@ static void icl_tc_phy_connect(struct intel_digital_port *dig_port, out_release_phy: tc_phy_take_ownership(dig_port, false); + + if (DISPLAY_VER(i915) >= 14) + xelpdp_tc_power_request(dig_port, false); + out_set_tbt_alt_mode: dig_port->tc_mode = TC_PORT_TBT_ALT; } @@ -524,6 +624,8 @@ static void icl_tc_phy_connect(struct intel_digital_port *dig_port, */ static void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) { + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + switch (dig_port->tc_mode) { case TC_PORT_LEGACY: case TC_PORT_DP_ALT: @@ -537,6 +639,9 @@ static void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) default: MISSING_CASE(dig_port->tc_mode); } + + if (DISPLAY_VER(i915) >= 14) + xelpdp_tc_power_request(dig_port, false); } static bool icl_tc_phy_is_connected(struct intel_digital_port *dig_port) @@ -886,6 +991,10 @@ tc_has_modular_fia(struct drm_i915_private *i915, struct intel_digital_port *dig if (!INTEL_INFO(i915)->display.has_modular_fia) return false; + /* for MTL, FIA is always modular */ + if (DISPLAY_VER(i915) >= 14) + return true; + mutex_lock(&dig_port->tc_lock); wakeref = tc_cold_block(dig_port, &domain); val = intel_de_read(i915, PORT_TX_DFLEXDPSP(FIA1)); From patchwork Thu Jan 5 12:54:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089829 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id BBE7FC54EBE for ; Thu, 5 Jan 2023 13:00:24 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 3831D10E712; Thu, 5 Jan 2023 13:00:24 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 958B910E713 for ; Thu, 5 Jan 2023 13:00:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923621; x=1704459621; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=oqRklpR4SHBUAWK0IOqFhDuVSN8r5AQu3ooBm7Jq9vc=; b=egoMv7ddmD+HLOKdjCkZyz1KorK3zOdXkC4V2q0P02zxHfeK5xdQV+rH seZtagysDMSYs3WbW7maos26t2T9bpdDa1IuWEK+iKXFSJaviEJ/TY6yX a9hv2iILwy2id6mOwiu9jgOQY/vGYceKDIGHidGsVkuXYyXEEBDe0tAwT 4gGaAO0Ydb3SFdp5w/EUWQyKW77UHGHULNt75oesdN6uduYwZb7fDEQbV gHtDBN3CbrKgNkO/Slup0o/yPMxeccDp9mlNXkhSn3K7uQGFVuYOMUmUH Mj91y5eJMrpAtukeEFilFgvujerZQ1l5tahk0fQ9SX13RWLaDgzxrBI0a g==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697957" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697957" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 05:00:21 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829541419" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829541419" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 05:00:17 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:45 +0200 Message-Id: <20230105125446.960504-21-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 20/21] drm/i915/mtl: TypeC HPD live status query 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Imre Deak The HPD live status for MTL has to be read from different set of registers. MTL deserves a new function for this purpose and cannot reuse the existing HPD live status detection Signed-off-by: Anusha Srivatsa Signed-off-by: Imre Deak Signed-off-by: Mika Kahola --- drivers/gpu/drm/i915/display/intel_tc.c | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 74d8d8e0e0df..de851fddb255 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -297,10 +297,40 @@ static u32 adl_tc_port_live_status_mask(struct intel_digital_port *dig_port) return mask; } +static u32 xelpdp_tc_port_live_status_mask(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port); + u32 isr_bit = i915->display.hotplug.pch_hpd[dig_port->base.hpd_pin]; + struct intel_uncore *uncore = &i915->uncore; + u32 val, mask = 0; + enum hpd_pin pin; + + val = intel_uncore_read(uncore, PICAINTERRUPT_ISR); + pin = HPD_PORT_TC1 + tc_port - TC_PORT_1; + if (val & XELPDP_DP_ALT_HOTPLUG(pin)) + mask |= BIT(TC_PORT_DP_ALT); + if (val & XELPDP_TBT_HOTPLUG(pin)) + mask |= BIT(TC_PORT_TBT_ALT); + + if (dig_port->tc_legacy_port && + intel_uncore_read(uncore, SDEISR) & isr_bit) + mask |= BIT(TC_PORT_LEGACY); + + /* The sink can be connected only in a single mode. */ + if (!drm_WARN_ON(&i915->drm, hweight32(mask) > 1)) + tc_port_fixup_legacy_flag(dig_port, mask); + + return mask; +} + static u32 tc_port_live_status_mask(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + if (DISPLAY_VER(i915) >= 14) + return xelpdp_tc_port_live_status_mask(dig_port); + if (DISPLAY_VER(i915) >= 13) return adl_tc_port_live_status_mask(dig_port); From patchwork Thu Jan 5 12:54:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 13089830 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id C510EC53210 for ; Thu, 5 Jan 2023 13:00:25 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 1C9A310E713; Thu, 5 Jan 2023 13:00:25 +0000 (UTC) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 6043210E713 for ; Thu, 5 Jan 2023 13:00:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1672923623; x=1704459623; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=nNDV3hMOqpKyUTiXyAdr0/2Kf0Yre4j8uJtI5f79hFQ=; b=ePx2Wc4w6jkzc4Q8hrfGmaosOHjzffKTlSK+dbLpYXpV5zbro3FzsjMF coiqWETaFGAYs9+O4hO0LCjRhljQUrO1d6LicpLQ68HPBYChmdSEZcYXB bJA3PJ0fLXZXVSsiMz3sVU1QuJYsH6JxGmW5Dw18cvkA3n5kKxoBVE90F GZkyS372jZX+feWm9cYKVwlvyoYL5q08K69fQGCSCD+4kMZZi/lsT9ouk LFXhZzwjrB72IViAGBSB2ikdJgKBn8ZauGYCsIdj6xQc28dODBHmd6nnm +xPRNfmzI0QBYLEmdjSVWb7xK5JoBmkr6zaFIRcv7TY1/JsiMAuAqU3Rt Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="305697978" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="305697978" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jan 2023 05:00:22 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10580"; a="829541450" X-IronPort-AV: E=Sophos;i="5.96,303,1665471600"; d="scan'208";a="829541450" Received: from sorvi2.fi.intel.com ([10.237.72.194]) by orsmga005.jf.intel.com with ESMTP; 05 Jan 2023 05:00:20 -0800 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Thu, 5 Jan 2023 14:54:46 +0200 Message-Id: <20230105125446.960504-22-mika.kahola@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105125446.960504-1-mika.kahola@intel.com> References: <20230105125446.960504-1-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 21/21] drm/i915/mtl: Pin assignment for TypeC 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: jani.nikula@intel.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Anusha Srivatsa Unlike previous platforms that used PORT_TX_DFLEXDPSP for max_lane calculation, MTL uses only PORT_TX_DFLEXPA1 from which the max_lanes has to be calculated. Bspec: 50235, 65380 Cc: Mika Kahola Cc: Imre Deak Cc: Matt Roper Signed-off-by: Anusha Srivatsa Signed-off-by: Jose Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20221014124740.774835-21-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index de851fddb255..e7d5301fc35e 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -15,6 +15,10 @@ #include "intel_mg_phy_regs.h" #include "intel_tc.h" +#define DP_PIN_ASSIGNMENT_C 0x3 +#define DP_PIN_ASSIGNMENT_D 0x4 +#define DP_PIN_ASSIGNMENT_E 0x5 + static const char *tc_port_mode_name(enum tc_port_mode mode) { static const char * const names[] = { @@ -147,6 +151,29 @@ u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port) DP_PIN_ASSIGNMENT_SHIFT(dig_port->tc_phy_fia_idx); } +static int mtl_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + intel_wakeref_t wakeref; + u32 pin_mask; + + assert_tc_cold_blocked(dig_port); + + with_intel_display_power(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref) + pin_mask = intel_tc_port_get_pin_assignment_mask(dig_port); + + switch(pin_mask) { + default: + MISSING_CASE(pin_mask); + fallthrough; + case DP_PIN_ASSIGNMENT_D: + return 2; + case DP_PIN_ASSIGNMENT_C: + case DP_PIN_ASSIGNMENT_E: + return 4; + } +} + int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); @@ -156,6 +183,9 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) if (dig_port->tc_mode != TC_PORT_DP_ALT) return 4; + if (DISPLAY_VER(i915) >= 14) + return mtl_tc_port_get_pin_assignment_mask(dig_port); + assert_tc_cold_blocked(dig_port); lane_mask = 0;